1
0
mirror of https://github.com/laurent22/joplin.git synced 2026-04-14 11:22:36 +02:00

Compare commits

...

1 Commits

Author SHA1 Message Date
Laurent Cozic
07f8fe3966 update 2026-03-18 14:45:48 +00:00
2 changed files with 79 additions and 10 deletions

View File

@@ -13,34 +13,72 @@ const dispatchWheel = (options: WheelEventInit) => {
document.dispatchEvent(new WheelEvent('wheel', { bubbles: true, ...options }));
};
const dispatchKeyDown = (key: string) => {
document.dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true }));
};
const dispatchKeyUp = (key: string) => {
document.dispatchEvent(new KeyboardEvent('keyup', { key, bubbles: true }));
};
describe('useCtrlWheelZoom', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test('should zoom on Ctrl/Meta+Wheel', () => {
test('should zoom when Ctrl key is pressed and wheel is scrolled', () => {
renderHook(() => useCtrlWheelZoom());
dispatchWheel({ deltaY: -100, ctrlKey: true });
dispatchKeyDown('Control');
dispatchWheel({ deltaY: -100 });
expect(Setting.incValue).toHaveBeenCalledWith('windowContentZoomFactor', 10);
jest.clearAllMocks();
dispatchWheel({ deltaY: 100, ctrlKey: true });
dispatchWheel({ deltaY: 100 });
expect(Setting.incValue).toHaveBeenCalledWith('windowContentZoomFactor', -10);
jest.clearAllMocks();
dispatchWheel({ deltaY: -100, metaKey: true });
expect(Setting.incValue).toHaveBeenCalledWith('windowContentZoomFactor', 10);
dispatchKeyUp('Control');
});
test('should not zoom on wheel without modifier', () => {
test('should zoom when Meta key is pressed and wheel is scrolled', () => {
renderHook(() => useCtrlWheelZoom());
dispatchKeyDown('Meta');
dispatchWheel({ deltaY: -100 });
expect(Setting.incValue).toHaveBeenCalledWith('windowContentZoomFactor', 10);
dispatchKeyUp('Meta');
});
test('should not zoom on wheel without modifier key pressed', () => {
renderHook(() => useCtrlWheelZoom());
dispatchWheel({ deltaY: -100 });
expect(Setting.incValue).not.toHaveBeenCalled();
});
test('should not zoom when only ctrlKey flag is set on wheel event (trackpad pinch)', () => {
// On macOS, trackpad pinch gestures send wheel events with ctrlKey=true
// but without actually pressing the Ctrl key
renderHook(() => useCtrlWheelZoom());
dispatchWheel({ deltaY: -100, ctrlKey: true });
expect(Setting.incValue).not.toHaveBeenCalled();
});
test('should stop zooming after key is released', () => {
renderHook(() => useCtrlWheelZoom());
dispatchKeyDown('Control');
dispatchWheel({ deltaY: -100 });
expect(Setting.incValue).toHaveBeenCalledTimes(1);
jest.clearAllMocks();
dispatchKeyUp('Control');
dispatchWheel({ deltaY: -100 });
expect(Setting.incValue).not.toHaveBeenCalled();
});
});

View File

@@ -3,14 +3,45 @@ import Setting from '@joplin/lib/models/Setting';
const useCtrlWheelZoom = () => {
useEffect(() => {
// Track whether modifier keys are actually pressed via keyboard events.
// This is needed because on macOS, trackpad pinch-to-zoom gestures are
// reported as wheel events with ctrlKey=true, even though Ctrl isn't pressed.
let ctrlPressed = false;
let metaPressed = false;
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Control') ctrlPressed = true;
if (e.key === 'Meta') metaPressed = true;
};
const handleKeyUp = (e: KeyboardEvent) => {
if (e.key === 'Control') ctrlPressed = false;
if (e.key === 'Meta') metaPressed = false;
};
const handleBlur = () => {
ctrlPressed = false;
metaPressed = false;
};
const handleWheel = (e: WheelEvent) => {
if (e.ctrlKey || e.metaKey) {
if (ctrlPressed || metaPressed) {
e.preventDefault();
Setting.incValue('windowContentZoomFactor', e.deltaY < 0 ? 10 : -10);
}
};
document.addEventListener('keydown', handleKeyDown);
document.addEventListener('keyup', handleKeyUp);
window.addEventListener('blur', handleBlur);
document.addEventListener('wheel', handleWheel, { passive: false });
return () => document.removeEventListener('wheel', handleWheel);
return () => {
document.removeEventListener('keydown', handleKeyDown);
document.removeEventListener('keyup', handleKeyUp);
window.removeEventListener('blur', handleBlur);
document.removeEventListener('wheel', handleWheel);
};
}, []);
};