Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions static/app/utils/useHotkeys.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('useHotkeys', () => {

function makeKeyEventFixture(keyCode: any, options: any) {
return {
key: keyCode,
keyCode: getKeyCode(keyCode),
preventDefault: jest.fn(),
...options,
Expand Down Expand Up @@ -170,4 +171,49 @@ describe('useHotkeys', () => {
expect(evt.preventDefault).not.toHaveBeenCalled();
expect(callback).toHaveBeenCalled();
});

it('handles slash key on different keyboard layouts using key property', () => {
const callback = jest.fn();

renderHook(p => useHotkeys(p), {
initialProps: [{match: 'command+/', callback}],
});

// Simulate German keyboard where "/" has a different keyCode but evt.key is still "/"
const evt = {
key: '/',
keyCode: 55, // German keyboard: the "7" key
metaKey: true,
shiftKey: false,
ctrlKey: false,
altKey: false,
preventDefault: jest.fn(),
} as any;
events.keydown!(evt);

expect(callback).toHaveBeenCalled();
expect(evt.preventDefault).toHaveBeenCalled();
});

it('still works with keyCode fallback for special keys', () => {
const callback = jest.fn();

renderHook(p => useHotkeys(p), {
initialProps: [{match: 'escape', callback}],
});

// Simulate escape key with both key and keyCode
const evt = {
key: 'Escape',
keyCode: 27,
metaKey: false,
shiftKey: false,
ctrlKey: false,
altKey: false,
preventDefault: jest.fn(),
} as any;
events.keydown!(evt);

expect(callback).toHaveBeenCalled();
});
});
29 changes: 22 additions & 7 deletions static/app/utils/useHotkeys.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,33 @@ import toArray from 'sentry/utils/array/toArray';
import {getKeyCode} from './getKeyCode';

const isKeyPressed = (key: string, evt: KeyboardEvent): boolean => {
const keyCode = getKeyCode(key);
switch (keyCode) {
case getKeyCode('command'):
const normalizedKey = key.toLowerCase();

switch (normalizedKey) {
case 'command':
case 'cmd':
case '⌘':
return evt.metaKey;
case getKeyCode('shift'):
case 'shift':
case '⇧':
return evt.shiftKey;
case getKeyCode('ctrl'):
case 'ctrl':
case 'control':
case '⌃':
return evt.ctrlKey;
case getKeyCode('alt'):
case 'alt':
case 'option':
case '⌥':
return evt.altKey;
default:
default: {
// Use evt.key for better keyboard layout support (works with German keyboards, etc.)
// Fall back to keyCode for backwards compatibility with special keys
if (evt.key && evt.key.toLowerCase() === normalizedKey) {
return true;
}
const keyCode = getKeyCode(key);
return keyCode === evt.keyCode;
}
}
};

Expand Down
Loading