From c961b72966850f332e1399aba66823089fe1d5a5 Mon Sep 17 00:00:00 2001 From: Marc Brooks Date: Wed, 20 Aug 2025 03:13:18 -0500 Subject: [PATCH] Pull in the localization checkpoint --- ui/src/components/VirtualKeyboard.tsx | 8 +- ui/src/keyboardLayouts.ts | 8 +- ui/src/keyboardLayouts/en_US.ts | 200 +++++++++++++++++++++++-- ui/src/keyboardMappings.ts | 202 +++++++++++++++++++++----- 4 files changed, 361 insertions(+), 57 deletions(-) diff --git a/ui/src/components/VirtualKeyboard.tsx b/ui/src/components/VirtualKeyboard.tsx index 16ccb9b..2c66dd8 100644 --- a/ui/src/components/VirtualKeyboard.tsx +++ b/ui/src/components/VirtualKeyboard.tsx @@ -262,7 +262,7 @@ function KeyboardWrapper() { "Tab KeyQ KeyW KeyE KeyR KeyT KeyY KeyU KeyI KeyO KeyP BracketLeft BracketRight Backslash", "CapsLock KeyA KeyS KeyD KeyF KeyG KeyH KeyJ KeyK KeyL Semicolon Quote Enter", "ShiftLeft KeyZ KeyX KeyC KeyV KeyB KeyN KeyM Comma Period Slash ShiftRight", - "ControlLeft AltLeft MetaLeft Space MetaRight AltRight", + "ControlLeft MetaLeft AltLeft Space AltRight MetaRight CtrlRight", ], shift: [ "CtrlAltDelete AltMetaEscape CtrlAltBackspace", @@ -271,7 +271,7 @@ function KeyboardWrapper() { "Tab (KeyQ) (KeyW) (KeyE) (KeyR) (KeyT) (KeyY) (KeyU) (KeyI) (KeyO) (KeyP) (BracketLeft) (BracketRight) (Backslash)", "CapsLock (KeyA) (KeyS) (KeyD) (KeyF) (KeyG) (KeyH) (KeyJ) (KeyK) (KeyL) (Semicolon) (Quote) Enter", "ShiftLeft (KeyZ) (KeyX) (KeyC) (KeyV) (KeyB) (KeyN) (KeyM) (Comma) (Period) (Slash) ShiftRight", - "ControlLeft AltLeft MetaLeft Space MetaRight AltRight", + "ControlLeft MetaLeft AltLeft Space AltRight MetaRight CtrlRight", ], }} disableButtonHold={true} @@ -287,8 +287,8 @@ function KeyboardWrapper() { onKeyPress={onKeyDown} display={keyDisplayMap} layout={{ - default: ["PrintScreen ScrollLock Pause", "Insert Home Pageup", "Delete End Pagedown"], - shift: ["(PrintScreen) ScrollLock (Pause)", "Insert Home Pageup", "Delete End Pagedown"], + default: ["PrintScreen ScrollLock Pause", "Insert Home PageUp", "Delete End PageDown"], + shift: ["(PrintScreen) ScrollLock (Pause)", "Insert Home PageUp", "Delete End PageDown"], }} syncInstanceInputs={true} debug={false} diff --git a/ui/src/keyboardLayouts.ts b/ui/src/keyboardLayouts.ts index 4ae3ad9..7a095fb 100644 --- a/ui/src/keyboardLayouts.ts +++ b/ui/src/keyboardLayouts.ts @@ -1,7 +1,13 @@ export interface KeyStroke { modifier: number; keys: number[]; } export interface KeyInfo { key: string | number; shift?: boolean, altRight?: boolean } export interface KeyCombo extends KeyInfo { deadKey?: boolean, accentKey?: KeyInfo } -export interface KeyboardLayout { isoCode: string, name: string, chars: Record } +export interface KeyboardLayout { + isoCode: string, + name: string, + chars: Record, + keyDisplayMap: Record, + virtualKeyboard: { main: { default: string[], shift: string[] }, control?: { default: string[], shift?: string[] }, controlSection?: { default: string[], shift?: string[] } } +} // to add a new layout, create a file like the above and add it to the list import { cs_CZ } from "@/keyboardLayouts/cs_CZ" diff --git a/ui/src/keyboardLayouts/en_US.ts b/ui/src/keyboardLayouts/en_US.ts index cd7aaf6..5a085ff 100644 --- a/ui/src/keyboardLayouts/en_US.ts +++ b/ui/src/keyboardLayouts/en_US.ts @@ -1,8 +1,16 @@ import { KeyboardLayout, KeyCombo } from "../keyboardLayouts" const name = "English (US)"; +const isoCode = "en-US"; -const chars = { +// dead keys +const keyAcute = { key: "Quote", control: true, menu: true, mark: "´" } // acute accent +const keyCedilla = { key: ".", shift: true, alt: true, mark: "¸" } // cedilla accent +const keyComma = { key: "BracketRight", shift: true, altRight: true, mark: "," } // comma accent +const keyDiaeresis = { key: "Quote", shift: true, control: true, menu: true, mark: "¨" } // diaeresis accent +const keyDegree = { key: "Semicolon", shift: true, control: true, menu: true, mark: "°" } // degree accent + +export const chars = { A: { key: "KeyA", shift: true }, B: { key: "KeyB", shift: true }, C: { key: "KeyC", shift: true }, @@ -89,31 +97,197 @@ const chars = { ">": { key: "Period", shift: true }, ";": { key: "Semicolon" }, ":": { key: "Semicolon", shift: true }, + "¶": { key: "Semicolon", altRight: true }, // pilcrow sign "[": { key: "BracketLeft" }, "{": { key: "BracketLeft", shift: true }, + "«": { key: "BracketLeft", altRight: true }, // double left quote sign "]": { key: "BracketRight" }, "}": { key: "BracketRight", shift: true }, + "»": { key: "BracketRight", altRight: true }, // double right quote sign "\\": { key: "Backslash" }, "|": { key: "Backslash", shift: true }, + "¬": { key: "Backslash", altRight: true }, // not sign "`": { key: "Backquote" }, "~": { key: "Backquote", shift: true }, "§": { key: "IntlBackslash" }, "±": { key: "IntlBackslash", shift: true }, - " ": { key: "Space", shift: false }, - "\n": { key: "Enter", shift: false }, - Enter: { key: "Enter", shift: false }, - Tab: { key: "Tab", shift: false }, - PrintScreen: { key: "Prt Sc", shift: false }, + " ": { key: "Space" }, + "\n": { key: "Enter" }, + Enter: { key: "Enter" }, + Escape: { key: "Escape" }, + Tab: { key: "Tab" }, + PrintScreen: { key: "Prt Sc" }, SystemRequest: { key: "Prt Sc", shift: true }, - ScrollLock: { key: "ScrollLock", shift: false}, - Pause: { key: "Pause", shift: false }, + ScrollLock: { key: "ScrollLock" }, + Pause: { key: "Pause" }, Break: { key: "Pause", shift: true }, - Insert: { key: "Insert", shift: false }, - Delete: { key: "Delete", shift: false }, + Insert: { key: "Insert" }, + Delete: { key: "Delete" }, } as Record +export const keyDisplayMap: Record = { + CtrlAltDelete: "Ctrl + Alt + Delete", + AltMetaEscape: "Alt + Meta + Escape", + CtrlAltBackspace: "Ctrl + Alt + Backspace", + Escape: "Esc", + Tab: "Tab", + Backspace: "Backspace", + "(Backspace)": "Backspace", + Enter: "Enter", + CapsLock: "Caps Lock", + ShiftLeft: "Shift", + ShiftRight: "Shift", + ControlLeft: "Ctrl", + AltLeft: "Alt", + AltRight: "Alt", + AltGraph: "AltGr", + MetaLeft: "Meta", + MetaRight: "Meta", + Space: " ", + Insert: "Insert", + Home: "Home", + PageUp: "PgUp", + Delete: "Delete", + End: "End", + PageDown: "PgDn", + Clear: "Clear", + ArrowLeft: "←", + ArrowRight: "→", + ArrowUp: "↑", + ArrowDown: "↓", + + // Letters + KeyA: "a", KeyB: "b", KeyC: "c", KeyD: "d", KeyE: "e", + KeyF: "f", KeyG: "g", KeyH: "h", KeyI: "i", KeyJ: "j", + KeyK: "k", KeyL: "l", KeyM: "m", KeyN: "n", KeyO: "o", + KeyP: "p", KeyQ: "q", KeyR: "r", KeyS: "s", KeyT: "t", + KeyU: "u", KeyV: "v", KeyW: "w", KeyX: "x", KeyY: "y", + KeyZ: "z", + + // Capital letters + "(KeyA)": "A", "(KeyB)": "B", "(KeyC)": "C", "(KeyD)": "D", "(KeyE)": "E", + "(KeyF)": "F", "(KeyG)": "G", "(KeyH)": "H", "(KeyI)": "I", "(KeyJ)": "J", + "(KeyK)": "K", "(KeyL)": "L", "(KeyM)": "M", "(KeyN)": "N", "(KeyO)": "O", + "(KeyP)": "P", "(KeyQ)": "Q", "(KeyR)": "R", "(KeyS)": "S", "(KeyT)": "T", + "(KeyU)": "U", "(KeyV)": "V", "(KeyW)": "W", "(KeyX)": "X", "(KeyY)": "Y", + "(KeyZ)": "Z", + + // Numbers + Digit1: "1", Digit2: "2", Digit3: "3", Digit4: "4", Digit5: "5", + Digit6: "6", Digit7: "7", Digit8: "8", Digit9: "9", Digit0: "0", + + // Shifted Numbers + "(Digit1)": "!", "(Digit2)": "@", "(Digit3)": "#", "(Digit4)": "$", "(Digit5)": "%", + "(Digit6)": "^", "(Digit7)": "&", "(Digit8)": "*", "(Digit9)": "(", "(Digit0)": ")", + + // Symbols + Minus: "-", + "(Minus)": "_", + Equal: "=", + "(Equal)": "+", + BracketLeft: "[", + "(BracketLeft)": "{", + BracketRight: "]", + "(BracketRight)": "}", + Backslash: "\\", + "(Backslash)": "|", + Semicolon: ";", + "(Semicolon)": ":", + Quote: "'", + "(Quote)": "\"", + Comma: ",", + "(Comma)": "<", + Period: ".", + "(Period)": ">", + Slash: "/", + "(Slash)": "?", + Backquote: "`", + "(Backquote)": "~", + IntlBackslash: "\\", + + // Function keys + F1: "F1", F2: "F2", F3: "F3", F4: "F4", + F5: "F5", F6: "F6", F7: "F7", F8: "F8", + F9: "F9", F10: "F10", F11: "F11", F12: "F12", + + // Numpad + Numpad0: "Num 0", Numpad1: "Num 1", Numpad2: "Num 2", + Numpad3: "Num 3", Numpad4: "Num 4", Numpad5: "Num 5", + Numpad6: "Num 6", Numpad7: "Num 7", Numpad8: "Num 8", + Numpad9: "Num 9", NumpadAdd: "Num +", NumpadSubtract: "Num -", + NumpadMultiply: "Num *", NumpadDivide: "Num /", NumpadDecimal: "Num .", + NumpadEqual: "Num =", NumpadEnter: "Num Enter", NumpadInsert: "Ins", + NumpadDelete: "Del", NumLock: "Num Lock", + + // Modals + PrintScreen: "PrtSc", ScrollLock: "Scroll Lock", Pause: "Pause", + "(PrintScreen)": "SysRq", "(Pause)": "Break", + SystemRequest: "SysRq", Break: "Break" +}; + +export const virtualKeyboard = { + main: { + default: [ + "CtrlAltDelete AltMetaEscape CtrlAltBackspace", + "Escape F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12", + "Backquote Digit1 Digit2 Digit3 Digit4 Digit5 Digit6 Digit7 Digit8 Digit9 Digit0 Minus Equal Backspace", + "Tab KeyQ KeyW KeyE KeyR KeyT KeyY KeyU KeyI KeyO KeyP BracketLeft BracketRight Backslash", + "CapsLock KeyA KeyS KeyD KeyF KeyG KeyH KeyJ KeyK KeyL Semicolon Quote Enter", + "ShiftLeft KeyZ KeyX KeyC KeyV KeyB KeyN KeyM Comma Period Slash ShiftRight", + "ControlLeft MetaLeft AltLeft Space AltGr MetaRight Menu ControlRight", + ], + shift: [ + "CtrlAltDelete AltMetaEscape CtrlAltBackspace", + "Escape F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12", + "(Backquote) (Digit1) (Digit2) (Digit3) (Digit4) (Digit5) (Digit6) (Digit7) (Digit8) (Digit9) (Digit0) (Minus) (Equal) (Backspace)", + "Tab (KeyQ) (KeyW) (KeyE) (KeyR) (KeyT) (KeyY) (KeyU) (KeyI) (KeyO) (KeyP) (BracketLeft) (BracketRight) (Backslash)", + "CapsLock (KeyA) (KeyS) (KeyD) (KeyF) (KeyG) (KeyH) (KeyJ) (KeyK) (KeyL) (Semicolon) (Quote) Enter", + "ShiftLeft (KeyZ) (KeyX) (KeyC) (KeyV) (KeyB) (KeyN) (KeyM) (Comma) (Period) (Slash) ShiftRight", + "ControlLeft MetaLeft AltLeft Space AltGr MetaRight Menu ControlRight", + ] + }, + controlSection: { + default: [ + "PrintScreen ScrollLock Pause", + "Insert Home PageUp", + "Delete End PageDown" + ], + shift: [ + "(PrintScreen) ScrollLock (Pause)", + "Insert Home PageUp", + "Delete End PageDown" + ], + }, + + simpleArrows: { + default: [ + "ArrowUp", + "ArrowLeft ArrowDown ArrowRight"], + }, + + numpad: { + numlocked: [ + "NumLock NumpadDivide NumpadMultiply NumpadSubtract", + "Numpad7 Numpad8 Numpad9 NumpadAdd", + "Numpad4 Numpad5 Numpad6", + "Numpad1 Numpad2 Numpad3 NumpadEnter", + "Numpad0 NumpadDecimal", + ], + default: [ + "NumLock NumpadDivide NumpadMultiply NumpadSubtract", + "Home ArrowUp PageUp NumpadAdd", + "ArrowLeft Clear ArrowRight", + "End ArrowDown PageDown NumpadEnter", + "NumpadInsert NumpadDelete", + ], + } +} + export const en_US: KeyboardLayout = { - isoCode: "en-US", - name: name, - chars: chars + isoCode, + name, + chars, + keyDisplayMap, + modifierDisplayMap, + virtualKeyboard }; \ No newline at end of file diff --git a/ui/src/keyboardMappings.ts b/ui/src/keyboardMappings.ts index 7dddd88..b862701 100644 --- a/ui/src/keyboardMappings.ts +++ b/ui/src/keyboardMappings.ts @@ -1,20 +1,39 @@ // Key codes and modifiers correspond to definitions in the // [Linux USB HID gadget driver](https://www.kernel.org/doc/Documentation/usb/gadget_hid.txt) -// [Section 10. Keyboard/Keypad Page 0x07](https://usb.org/sites/default/files/hut1_21.pdf) +// [Universal Serial Bus HID Usage Tables: Section 10](https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf) +// These are all the key codes (not scan codes) that an 85/101/102 keyboard might have on it export const keys = { + Again: 0x79, + AlternateErase: 0x9d, + AltGraph: 0xe5, + AltLeft: 0xe2, + AltRight: 0xe6, + Application: 0x65, ArrowDown: 0x51, ArrowLeft: 0x50, ArrowRight: 0x4f, ArrowUp: 0x52, + Attention: 0x9a, Backquote: 0x35, // aka Grave Backslash: 0x31, Backspace: 0x2a, BracketLeft: 0x2f, // aka LeftBrace BracketRight: 0x30, // aka RightBrace + Cancel: 0x9b, CapsLock: 0x39, + Clear: 0x9c, + ClearAgain: 0xa2, Comma: 0x36, - Compose: 0x65, - ContextMenu: 0x65, // same as Compose + Compose: 0xe3, + ContextMenu: 0x65, + ControlLeft: 0xe0, + ControlRight: 0xe4, + Copy: 0x7c, + CrSel: 0xa3, + CurrencySubunit: 0xb5, + CurrencyUnit: 0xb4, + Cut: 0x7b, + DecimalSeparator: 0xb3, Delete: 0x4c, Digit0: 0x27, Digit1: 0x1e, @@ -30,6 +49,8 @@ export const keys = { Enter: 0x28, Equal: 0x2e, Escape: 0x29, + Execute: 0x74, + ExSel: 0xa4, F1: 0x3a, F2: 0x3b, F3: 0x3c, @@ -54,9 +75,21 @@ export const keys = { F22: 0x71, F23: 0x72, F24: 0x73, - Home: 0x4a, + Find: 0x7e, + Grave: 0x35, HashTilde: 0x32, // non-US # and ~ + Help: 0x75, + Home: 0x4a, Insert: 0x49, + International1: 0x87, + International2: 0x88, + International3: 0x89, + International4: 0x8a, + International5: 0x8b, + International6: 0x8c, + International7: 0x8d, + International8: 0x8e, + International9: 0x8f, IntlBackslash: 0x64, // non-US \ and | KeyA: 0x04, KeyB: 0x05, @@ -84,10 +117,27 @@ export const keys = { KeyX: 0x1b, KeyY: 0x1c, KeyZ: 0x1d, - KeypadExclamation: 0xcf, + LockingCapsLock: 0x82, + LockingNumLock: 0x83, + LockingScrollLock: 0x84, + Lang1: 0x90, // Hangul/English toggle on Korean keyboards + Lang2: 0x91, // Hanja conversion on Korean keyboards + Lang3: 0x92, // Katakana on Japanese keyboards + Lang4: 0x93, // Hiragana on Japanese keyboards + Lang5: 0x94, // Zenkaku/Hankaku toggle on Japanese keyboards + Lang6: 0x95, + Lang7: 0x96, + Lang8: 0x97, + Lang9: 0x98, + Menu: 0x76, + MetaLeft: 0xe3, + MetaRight: 0xe7, Minus: 0x2d, + Mute: 0x7f, NumLock: 0x53, // and Clear Numpad0: 0x62, // and Insert + Numpad00: 0xb0, + Numpad000: 0xb1, Numpad1: 0x59, // and End Numpad2: 0x5a, // and Down Arrow Numpad3: 0x5b, // and Page Down @@ -98,38 +148,109 @@ export const keys = { Numpad8: 0x60, // and Up Arrow Numpad9: 0x61, // and Page Up NumpadAdd: 0x57, + NumpadAnd: 0xc7, + NumpadAt: 0xce, + NumpadBackspace: 0xbb, + NumpadBinary: 0xda, + NumpadCircumflex: 0xc3, + NumpadClear: 0xd8, + NumpadClearEntry: 0xd9, + NumpadColon: 0xcb, NumpadComma: 0x85, NumpadDecimal: 0x63, + NumpadDecimalBase: 0xdc, + NumpadDelete: 0x63, NumpadDivide: 0x54, + NumpadDownArrow: 0x5a, + NumpadEnd: 0x59, NumpadEnter: 0x58, NumpadEqual: 0x67, + NumpadExclamation: 0xcf, + NumpadGreaterThan: 0xc6, + NumpadHexadecimal: 0xdd, + NumpadHome: 0x5f, + NumpadKeyA: 0xbc, + NumpadKeyB: 0xbd, + NumpadKeyC: 0xbe, + NumpadKeyD: 0xbf, + NumpadKeyE: 0xc0, + NumpadKeyF: 0xc1, + NumpadLeftArrow: 0x5c, + NumpadLeftBrace: 0xb8, NumpadLeftParen: 0xb6, + NumpadLessThan: 0xc5, + NumpadLogicalAnd: 0xc8, + NumpadLogicalOr: 0xca, + NumpadMemoryAdd: 0xd3, + NumpadMemoryClear: 0xd2, + NumpadMemoryDivide: 0xd6, + NumpadMemoryMultiply: 0xd5, + NumpadMemoryRecall: 0xd1, + NumpadMemoryStore: 0xd0, + NumpadMemorySubtract: 0xd4, NumpadMultiply: 0x55, + NumpadOctal: 0xdb, + NumpadOctathorpe: 0xcc, + NumpadOr: 0xc9, + NumpadPageDown: 0x5b, + NumpadPageUp: 0x61, + NumpadPercent: 0xc4, + NumpadPlusMinus: 0xd7, + NumpadRightArrow: 0x5e, + NumpadRightBrace: 0xb9, NumpadRightParen: 0xb7, + NumpadSpace: 0xcd, NumpadSubtract: 0x56, + NumpadTab: 0xba, + NumpadUpArrow: 0x60, + NumpadXOR: 0xc2, + Octothorpe: 0x32, // non-US # and ~ + Operation: 0xa1, + Out: 0xa0, PageDown: 0x4e, PageUp: 0x4b, - Period: 0x37, - PrintScreen: 0x46, + Paste: 0x7d, Pause: 0x48, + Period: 0x37, Power: 0x66, + PrintScreen: 0x46, + Prior: 0x9d, Quote: 0x34, // aka Single Quote or Apostrophe + Return: 0x9e, ScrollLock: 0x47, + Select: 0x77, Semicolon: 0x33, - Slash: 0x38, - Space: 0x2c, - SystemRequest: 0x9a, - Tab: 0x2b, - ControlLeft: 0xe0, - ControlRight: 0xe4, + Separator: 0x9f, ShiftLeft: 0xe1, ShiftRight: 0xe5, - AltLeft: 0xe2, - AltRight: 0xe6, - MetaLeft: 0xe3, - MetaRight: 0xe7, + Slash: 0x38, + Space: 0x2c, + Stop: 0x78, + SystemRequest: 0x9a, + Tab: 0x2b, + ThousandsSeparator: 0xb2, + Tilde: 0x35, + Undo: 0x7a, + VolumeDown: 0x81, + VolumeUp: 0x80, } as Record; +export const deadKeys = { + 0x005e: "Circumflex", + 0x02c7: "Caron", + 0x00b7: "Dot", + 0x02d8: "Breve", + 0x002c: "Comma", + 0x00b0: "Kreis", + 0x00b4: "Acute", + 0x00a8: "Umlaut", + 0x0060: "Grave", + 0x007e: "Tilde", + 0x02dd: "DoubleAcute", + 0x02db: "Ogonek", + 0x00b8: "Cedilla", +} as Record + export const modifiers = { ControlLeft: 0x01, ControlRight: 0x10, @@ -161,37 +282,40 @@ export const modifierDisplayMap: Record = { AltRight: "Right Alt", MetaLeft: "Left Meta", MetaRight: "Right Meta", + AltGr: "AltGr", } as Record; export const keyDisplayMap: Record = { - CtrlAltDelete: "Ctrl + Alt + Delete", AltMetaEscape: "Alt + Meta + Escape", CtrlAltBackspace: "Ctrl + Alt + Backspace", - Escape: "esc", - Tab: "tab", - Backspace: "backspace", - "(Backspace)": "backspace", - Enter: "enter", - CapsLock: "caps lock", - ShiftLeft: "shift", - ShiftRight: "shift", - ControlLeft: "ctrl", + CtrlAltDelete: "Ctrl + Alt + Delete", + + AltGraph: "alt gr", AltLeft: "alt", AltRight: "alt", - MetaLeft: "meta", - MetaRight: "meta", - Space: " ", - Insert: "insert", - Home: "home", - PageUp: "page up", - Delete: "delete", - End: "end", - PageDown: "page down", + ArrowDown: "↓", ArrowLeft: "←", ArrowRight: "→", ArrowUp: "↑", - ArrowDown: "↓", - + Backspace: "backspace", + "(Backspace)": "backspace", + CapsLock: "caps lock", + ControlLeft: "ctrl", + Delete: "delete", + End: "end", + Enter: "enter", + Escape: "esc", + Home: "home", + Insert: "insert", + MetaLeft: "meta", + MetaRight: "meta", + PageDown: "page down", + PageUp: "page up", + ShiftLeft: "shift", + ShiftRight: "shift", + Space: " ", + Tab: "tab", + // Letters KeyA: "a", KeyB: "b", KeyC: "c", KeyD: "d", KeyE: "e", KeyF: "f", KeyG: "g", KeyH: "h", KeyI: "i", KeyJ: "j", @@ -222,7 +346,7 @@ export const keyDisplayMap: Record = { Equal: "=", "(Equal)": "+", BracketLeft: "[", - "(BracketLeft)": "{", + "(BracketLeft)": "{", BracketRight: "]", "(BracketRight)": "}", Backslash: "\\",