From c99fe1d450911b0df89d1ef70f4c3d10388b1789 Mon Sep 17 00:00:00 2001 From: CJ Pais Date: Thu, 3 Jul 2025 14:26:02 -0700 Subject: [PATCH] Fix the keycode bug. --- bun.lockb | Bin 67231 -> 67590 bytes package.json | 1 - src/components/settings/KeyboardShortcuts.tsx | 6 +- src/lib/utils/keyboard.ts | 131 ++++++++++++++++++ 4 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 src/lib/utils/keyboard.ts diff --git a/bun.lockb b/bun.lockb index ecaab7a13cd58e3d15cd6a279d01469a218a6e7f..53f8db28f90449d3e86b2890e7282cbb4d50f93f 100755 GIT binary patch delta 8572 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 V|LKjp-zzh3DAF>+aV&1C?q7mq3uyoV diff --git a/package.json b/package.json index 14dba8a..048c45c 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "@tauri-apps/plugin-stronghold": "~2", "@tauri-apps/plugin-updater": "~2", "@tauri-apps/plugin-upload": "~2", - "keycode": "^2.2.1", "react": "^18.3.1", "react-dom": "^18.3.1", "tailwindcss": "^4.0.2", diff --git a/src/components/settings/KeyboardShortcuts.tsx b/src/components/settings/KeyboardShortcuts.tsx index 6018431..c1f6a45 100644 --- a/src/components/settings/KeyboardShortcuts.tsx +++ b/src/components/settings/KeyboardShortcuts.tsx @@ -8,7 +8,7 @@ import { } from "../../lib/types"; import { invoke } from "@tauri-apps/api/core"; import { type } from "@tauri-apps/plugin-os"; -import keycode from "keycode"; +import { getKeyName } from "../../lib/utils/keyboard"; import ResetIcon from "../icons/ResetIcon"; export const KeyboardShortcuts: React.FC = () => { @@ -95,7 +95,7 @@ export const KeyboardShortcuts: React.FC = () => { e.preventDefault(); // Get the key and normalize it (unify left/right modifiers) - const rawKey = keycode(e).toLowerCase(); + const rawKey = getKeyName(e); const key = normalizeKey(rawKey); console.log("You pressed", rawKey, "normalized to", key); @@ -113,7 +113,7 @@ export const KeyboardShortcuts: React.FC = () => { e.preventDefault(); // Get the key and normalize it - const rawKey = keycode(e).toLowerCase(); + const rawKey = getKeyName(e); const key = normalizeKey(rawKey); // Remove from currently pressed keys diff --git a/src/lib/utils/keyboard.ts b/src/lib/utils/keyboard.ts new file mode 100644 index 0000000..f109714 --- /dev/null +++ b/src/lib/utils/keyboard.ts @@ -0,0 +1,131 @@ +/** + * Keyboard utility functions for handling keyboard events + */ + +/** + * Extract a consistent key name from a KeyboardEvent + * This function replaces the keycode library and provides better support + * for extended function keys (F14+) and cross-platform compatibility + */ +export const getKeyName = (e: KeyboardEvent): string => { + // Handle special cases first + if (e.code) { + const code = e.code; + + // Handle function keys (F1-F24) + if (code.match(/^F\d+$/)) { + return code.toLowerCase(); // F1, F2, ..., F14, F15, etc. + } + + // Handle regular letter keys (KeyA -> a) + if (code.match(/^Key[A-Z]$/)) { + return code.replace("Key", "").toLowerCase(); + } + + // Handle digit keys (Digit0 -> 0) + if (code.match(/^Digit\d$/)) { + return code.replace("Digit", ""); + } + + // Handle numpad digit keys (Numpad0 -> numpad 0) + if (code.match(/^Numpad\d$/)) { + return code.replace("Numpad", "numpad ").toLowerCase(); + } + + // Handle modifier keys - normalize left/right variants + const modifierMap: Record = { + ShiftLeft: "shift", + ShiftRight: "shift", + ControlLeft: "ctrl", + ControlRight: "ctrl", + AltLeft: "alt", + AltRight: "alt", + MetaLeft: "command", + MetaRight: "command", + OSLeft: "command", + OSRight: "command", + CapsLock: "caps lock", + Tab: "tab", + Enter: "enter", + Space: "space", + Backspace: "backspace", + Delete: "delete", + Escape: "esc", + ArrowUp: "up", + ArrowDown: "down", + ArrowLeft: "left", + ArrowRight: "right", + Home: "home", + End: "end", + PageUp: "page up", + PageDown: "page down", + Insert: "insert", + PrintScreen: "print screen", + ScrollLock: "scroll lock", + Pause: "pause", + ContextMenu: "menu", + NumpadMultiply: "numpad *", + NumpadAdd: "numpad +", + NumpadSubtract: "numpad -", + NumpadDecimal: "numpad .", + NumpadDivide: "numpad /", + NumLock: "num lock", + }; + + if (modifierMap[code]) { + return modifierMap[code]; + } + + // Handle punctuation and special characters + const punctuationMap: Record = { + Semicolon: ";", + Equal: "=", + Comma: ",", + Minus: "-", + Period: ".", + Slash: "/", + Backquote: "`", + BracketLeft: "[", + Backslash: "\\", + BracketRight: "]", + Quote: "'", + }; + + if (punctuationMap[code]) { + return punctuationMap[code]; + } + + // For any other codes, try to convert to a reasonable format + return code.toLowerCase().replace(/([a-z])([A-Z])/g, "$1 $2"); + } + + // Fallback to e.key if e.code is not available + if (e.key) { + const key = e.key; + + // Handle special key names + const keyMap: Record = { + Control: "ctrl", + Alt: "alt", + Shift: "shift", + Meta: "command", + OS: "command", + CapsLock: "caps lock", + ArrowUp: "up", + ArrowDown: "down", + ArrowLeft: "left", + ArrowRight: "right", + Escape: "esc", + " ": "space", + }; + + if (keyMap[key]) { + return keyMap[key]; + } + + return key.toLowerCase(); + } + + // Last resort fallback + return `unknown-${e.keyCode || e.which || 0}`; +};