import { CanonicalKey } from '@/types/generated' export const keys = { KeyA: CanonicalKey.KeyA, KeyB: CanonicalKey.KeyB, KeyC: CanonicalKey.KeyC, KeyD: CanonicalKey.KeyD, KeyE: CanonicalKey.KeyE, KeyF: CanonicalKey.KeyF, KeyG: CanonicalKey.KeyG, KeyH: CanonicalKey.KeyH, KeyI: CanonicalKey.KeyI, KeyJ: CanonicalKey.KeyJ, KeyK: CanonicalKey.KeyK, KeyL: CanonicalKey.KeyL, KeyM: CanonicalKey.KeyM, KeyN: CanonicalKey.KeyN, KeyO: CanonicalKey.KeyO, KeyP: CanonicalKey.KeyP, KeyQ: CanonicalKey.KeyQ, KeyR: CanonicalKey.KeyR, KeyS: CanonicalKey.KeyS, KeyT: CanonicalKey.KeyT, KeyU: CanonicalKey.KeyU, KeyV: CanonicalKey.KeyV, KeyW: CanonicalKey.KeyW, KeyX: CanonicalKey.KeyX, KeyY: CanonicalKey.KeyY, KeyZ: CanonicalKey.KeyZ, Digit1: CanonicalKey.Digit1, Digit2: CanonicalKey.Digit2, Digit3: CanonicalKey.Digit3, Digit4: CanonicalKey.Digit4, Digit5: CanonicalKey.Digit5, Digit6: CanonicalKey.Digit6, Digit7: CanonicalKey.Digit7, Digit8: CanonicalKey.Digit8, Digit9: CanonicalKey.Digit9, Digit0: CanonicalKey.Digit0, Enter: CanonicalKey.Enter, Escape: CanonicalKey.Escape, Backspace: CanonicalKey.Backspace, Tab: CanonicalKey.Tab, Space: CanonicalKey.Space, Minus: CanonicalKey.Minus, Equal: CanonicalKey.Equal, BracketLeft: CanonicalKey.BracketLeft, BracketRight: CanonicalKey.BracketRight, Backslash: CanonicalKey.Backslash, Semicolon: CanonicalKey.Semicolon, Quote: CanonicalKey.Quote, Backquote: CanonicalKey.Backquote, Comma: CanonicalKey.Comma, Period: CanonicalKey.Period, Slash: CanonicalKey.Slash, CapsLock: CanonicalKey.CapsLock, F1: CanonicalKey.F1, F2: CanonicalKey.F2, F3: CanonicalKey.F3, F4: CanonicalKey.F4, F5: CanonicalKey.F5, F6: CanonicalKey.F6, F7: CanonicalKey.F7, F8: CanonicalKey.F8, F9: CanonicalKey.F9, F10: CanonicalKey.F10, F11: CanonicalKey.F11, F12: CanonicalKey.F12, PrintScreen: CanonicalKey.PrintScreen, ScrollLock: CanonicalKey.ScrollLock, Pause: CanonicalKey.Pause, Insert: CanonicalKey.Insert, Home: CanonicalKey.Home, PageUp: CanonicalKey.PageUp, Delete: CanonicalKey.Delete, End: CanonicalKey.End, PageDown: CanonicalKey.PageDown, ArrowRight: CanonicalKey.ArrowRight, ArrowLeft: CanonicalKey.ArrowLeft, ArrowDown: CanonicalKey.ArrowDown, ArrowUp: CanonicalKey.ArrowUp, NumLock: CanonicalKey.NumLock, NumpadDivide: CanonicalKey.NumpadDivide, NumpadMultiply: CanonicalKey.NumpadMultiply, NumpadSubtract: CanonicalKey.NumpadSubtract, NumpadAdd: CanonicalKey.NumpadAdd, NumpadEnter: CanonicalKey.NumpadEnter, Numpad1: CanonicalKey.Numpad1, Numpad2: CanonicalKey.Numpad2, Numpad3: CanonicalKey.Numpad3, Numpad4: CanonicalKey.Numpad4, Numpad5: CanonicalKey.Numpad5, Numpad6: CanonicalKey.Numpad6, Numpad7: CanonicalKey.Numpad7, Numpad8: CanonicalKey.Numpad8, Numpad9: CanonicalKey.Numpad9, Numpad0: CanonicalKey.Numpad0, NumpadDecimal: CanonicalKey.NumpadDecimal, IntlBackslash: CanonicalKey.IntlBackslash, ContextMenu: CanonicalKey.ContextMenu, F13: CanonicalKey.F13, F14: CanonicalKey.F14, F15: CanonicalKey.F15, F16: CanonicalKey.F16, F17: CanonicalKey.F17, F18: CanonicalKey.F18, F19: CanonicalKey.F19, F20: CanonicalKey.F20, F21: CanonicalKey.F21, F22: CanonicalKey.F22, F23: CanonicalKey.F23, F24: CanonicalKey.F24, ControlLeft: CanonicalKey.ControlLeft, ShiftLeft: CanonicalKey.ShiftLeft, AltLeft: CanonicalKey.AltLeft, MetaLeft: CanonicalKey.MetaLeft, ControlRight: CanonicalKey.ControlRight, ShiftRight: CanonicalKey.ShiftRight, AltRight: CanonicalKey.AltRight, MetaRight: CanonicalKey.MetaRight, } as const export type KeyName = keyof typeof keys // Consumer Control Usage codes (for multimedia keys) export const consumerKeys = { PlayPause: 0x00cd, Stop: 0x00b7, NextTrack: 0x00b5, PrevTrack: 0x00b6, Mute: 0x00e2, VolumeUp: 0x00e9, VolumeDown: 0x00ea, } as const export type ConsumerKeyName = keyof typeof consumerKeys export const modifiers: Partial> = { [CanonicalKey.ControlLeft]: 0x01, [CanonicalKey.ShiftLeft]: 0x02, [CanonicalKey.AltLeft]: 0x04, [CanonicalKey.MetaLeft]: 0x08, [CanonicalKey.ControlRight]: 0x10, [CanonicalKey.ShiftRight]: 0x20, [CanonicalKey.AltRight]: 0x40, [CanonicalKey.MetaRight]: 0x80, } export const keyToHidUsage = { [CanonicalKey.KeyA]: 0x04, [CanonicalKey.KeyB]: 0x05, [CanonicalKey.KeyC]: 0x06, [CanonicalKey.KeyD]: 0x07, [CanonicalKey.KeyE]: 0x08, [CanonicalKey.KeyF]: 0x09, [CanonicalKey.KeyG]: 0x0a, [CanonicalKey.KeyH]: 0x0b, [CanonicalKey.KeyI]: 0x0c, [CanonicalKey.KeyJ]: 0x0d, [CanonicalKey.KeyK]: 0x0e, [CanonicalKey.KeyL]: 0x0f, [CanonicalKey.KeyM]: 0x10, [CanonicalKey.KeyN]: 0x11, [CanonicalKey.KeyO]: 0x12, [CanonicalKey.KeyP]: 0x13, [CanonicalKey.KeyQ]: 0x14, [CanonicalKey.KeyR]: 0x15, [CanonicalKey.KeyS]: 0x16, [CanonicalKey.KeyT]: 0x17, [CanonicalKey.KeyU]: 0x18, [CanonicalKey.KeyV]: 0x19, [CanonicalKey.KeyW]: 0x1a, [CanonicalKey.KeyX]: 0x1b, [CanonicalKey.KeyY]: 0x1c, [CanonicalKey.KeyZ]: 0x1d, [CanonicalKey.Digit1]: 0x1e, [CanonicalKey.Digit2]: 0x1f, [CanonicalKey.Digit3]: 0x20, [CanonicalKey.Digit4]: 0x21, [CanonicalKey.Digit5]: 0x22, [CanonicalKey.Digit6]: 0x23, [CanonicalKey.Digit7]: 0x24, [CanonicalKey.Digit8]: 0x25, [CanonicalKey.Digit9]: 0x26, [CanonicalKey.Digit0]: 0x27, [CanonicalKey.Enter]: 0x28, [CanonicalKey.Escape]: 0x29, [CanonicalKey.Backspace]: 0x2a, [CanonicalKey.Tab]: 0x2b, [CanonicalKey.Space]: 0x2c, [CanonicalKey.Minus]: 0x2d, [CanonicalKey.Equal]: 0x2e, [CanonicalKey.BracketLeft]: 0x2f, [CanonicalKey.BracketRight]: 0x30, [CanonicalKey.Backslash]: 0x31, [CanonicalKey.Semicolon]: 0x33, [CanonicalKey.Quote]: 0x34, [CanonicalKey.Backquote]: 0x35, [CanonicalKey.Comma]: 0x36, [CanonicalKey.Period]: 0x37, [CanonicalKey.Slash]: 0x38, [CanonicalKey.CapsLock]: 0x39, [CanonicalKey.F1]: 0x3a, [CanonicalKey.F2]: 0x3b, [CanonicalKey.F3]: 0x3c, [CanonicalKey.F4]: 0x3d, [CanonicalKey.F5]: 0x3e, [CanonicalKey.F6]: 0x3f, [CanonicalKey.F7]: 0x40, [CanonicalKey.F8]: 0x41, [CanonicalKey.F9]: 0x42, [CanonicalKey.F10]: 0x43, [CanonicalKey.F11]: 0x44, [CanonicalKey.F12]: 0x45, [CanonicalKey.PrintScreen]: 0x46, [CanonicalKey.ScrollLock]: 0x47, [CanonicalKey.Pause]: 0x48, [CanonicalKey.Insert]: 0x49, [CanonicalKey.Home]: 0x4a, [CanonicalKey.PageUp]: 0x4b, [CanonicalKey.Delete]: 0x4c, [CanonicalKey.End]: 0x4d, [CanonicalKey.PageDown]: 0x4e, [CanonicalKey.ArrowRight]: 0x4f, [CanonicalKey.ArrowLeft]: 0x50, [CanonicalKey.ArrowDown]: 0x51, [CanonicalKey.ArrowUp]: 0x52, [CanonicalKey.NumLock]: 0x53, [CanonicalKey.NumpadDivide]: 0x54, [CanonicalKey.NumpadMultiply]: 0x55, [CanonicalKey.NumpadSubtract]: 0x56, [CanonicalKey.NumpadAdd]: 0x57, [CanonicalKey.NumpadEnter]: 0x58, [CanonicalKey.Numpad1]: 0x59, [CanonicalKey.Numpad2]: 0x5a, [CanonicalKey.Numpad3]: 0x5b, [CanonicalKey.Numpad4]: 0x5c, [CanonicalKey.Numpad5]: 0x5d, [CanonicalKey.Numpad6]: 0x5e, [CanonicalKey.Numpad7]: 0x5f, [CanonicalKey.Numpad8]: 0x60, [CanonicalKey.Numpad9]: 0x61, [CanonicalKey.Numpad0]: 0x62, [CanonicalKey.NumpadDecimal]: 0x63, [CanonicalKey.IntlBackslash]: 0x64, [CanonicalKey.ContextMenu]: 0x65, [CanonicalKey.F13]: 0x68, [CanonicalKey.F14]: 0x69, [CanonicalKey.F15]: 0x6a, [CanonicalKey.F16]: 0x6b, [CanonicalKey.F17]: 0x6c, [CanonicalKey.F18]: 0x6d, [CanonicalKey.F19]: 0x6e, [CanonicalKey.F20]: 0x6f, [CanonicalKey.F21]: 0x70, [CanonicalKey.F22]: 0x71, [CanonicalKey.F23]: 0x72, [CanonicalKey.F24]: 0x73, [CanonicalKey.ControlLeft]: 0xe0, [CanonicalKey.ShiftLeft]: 0xe1, [CanonicalKey.AltLeft]: 0xe2, [CanonicalKey.MetaLeft]: 0xe3, [CanonicalKey.ControlRight]: 0xe4, [CanonicalKey.ShiftRight]: 0xe5, [CanonicalKey.AltRight]: 0xe6, [CanonicalKey.MetaRight]: 0xe7, } as const satisfies Record export function canonicalKeyToHidUsage(key: CanonicalKey): number { return keyToHidUsage[key] } export function updateModifierMaskForKey(mask: number, key: CanonicalKey, press: boolean): number { const bit = modifiers[key] ?? 0 if (bit === 0) return mask return press ? (mask | bit) : (mask & ~bit) } export const latchingKeys = [ CanonicalKey.CapsLock, CanonicalKey.ScrollLock, CanonicalKey.NumLock, ] as const // Normalize browser-specific KeyboardEvent.code variants. export function normalizeKeyboardCode(code: string, key: string): string { if (code === 'IntlBackslash' && (key === '`' || key === '~')) return 'Backquote' if (code === 'Backquote' && (key === '§' || key === '±')) return 'IntlBackslash' if (code === 'IntlYen') return 'IntlBackslash' if (code === 'OSLeft') return 'MetaLeft' if (code === 'OSRight') return 'MetaRight' if (code === '' && key === 'Shift') return 'ShiftRight' return code } export function keyboardEventToCanonicalKey(code: string, key: string): CanonicalKey | undefined { const normalizedCode = normalizeKeyboardCode(code, key) if (normalizedCode in keys) { return keys[normalizedCode as KeyName] } return undefined }