refactor: improve keybind saving logic and error handling

This commit is contained in:
PandaDEV 2025-01-02 17:05:02 +10:00
parent 6656af8ab1
commit 0c28a5b0db
No known key found for this signature in database
GPG key ID: 13EFF9BAF70EE75C
8 changed files with 478 additions and 154 deletions

View file

@ -12,7 +12,7 @@ All the data of Qopy is stored inside of a SQLite database.
## Disable Windows+V for default clipboard manager ## Disable Windows+V for default clipboard manager
https://github.com/user-attachments/assets/723f9e07-3190-46ec-9bb7-15dfc112f620 <video src="https://github.com/user-attachments/assets/723f9e07-3190-46ec-9bb7-15dfc112f620" controls title="Disable Windows+V for default clipboard manager"></video>
To disable the default clipboard manager popup from windows open Command prompt and run this command To disable the default clipboard manager popup from windows open Command prompt and run this command

View file

@ -33,7 +33,6 @@
<div <div
@blur="onBlur" @blur="onBlur"
@focus="onFocus" @focus="onFocus"
@keydown="onKeyDown"
class="keybind-input" class="keybind-input"
ref="keybindInput" ref="keybindInput"
tabindex="0"> tabindex="0">
@ -44,7 +43,7 @@
class="key" class="key"
:class="{ modifier: isModifier(key) }" :class="{ modifier: isModifier(key) }"
v-for="(key, index) in keybind"> v-for="(key, index) in keybind">
{{ keyToDisplay(key) }} {{ keyToLabel(key) }}
</span> </span>
</template> </template>
</div> </div>
@ -58,10 +57,11 @@ import { onMounted, onUnmounted, reactive, ref } from "vue";
import { platform } from "@tauri-apps/plugin-os"; import { platform } from "@tauri-apps/plugin-os";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { Key } from "wrdu-keyboard/key"; import { Key } from "wrdu-keyboard/key";
import { KeyValues, KeyLabels } from "../types/keys";
const activeModifiers = reactive<Set<string>>(new Set()); const activeModifiers = reactive<Set<KeyValues>>(new Set());
const isKeybindInputFocused = ref(false); const isKeybindInputFocused = ref(false);
const keybind = ref<string[]>([]); const keybind = ref<KeyValues[]>([]);
const keybindInput = ref<HTMLElement | null>(null); const keybindInput = ref<HTMLElement | null>(null);
const lastBlurTime = ref(0); const lastBlurTime = ref(0);
const os = ref(""); const os = ref("");
@ -69,52 +69,27 @@ const router = useRouter();
const keyboard = useKeyboard(); const keyboard = useKeyboard();
const showEmptyKeybindError = ref(false); const showEmptyKeybindError = ref(false);
const keyToDisplayMap: Record<string, string> = {
" ": "Space",
Alt: "Alt",
AltLeft: "Alt L",
AltRight: "Alt R",
ArrowDown: "↓",
ArrowLeft: "←",
ArrowRight: "→",
ArrowUp: "↑",
Control: "Ctrl",
ControlLeft: "Ctrl L",
ControlRight: "Ctrl R",
Enter: "↵",
Meta: "Meta",
MetaLeft: "Meta L",
MetaRight: "Meta R",
Shift: "⇧",
ShiftLeft: "⇧ L",
ShiftRight: "⇧ R",
};
const modifierKeySet = new Set([ const modifierKeySet = new Set([
"Alt", KeyValues.AltLeft,
"AltLeft", KeyValues.AltRight,
"AltRight", KeyValues.ControlLeft,
"Control", KeyValues.ControlRight,
"ControlLeft", KeyValues.MetaLeft,
"ControlRight", KeyValues.MetaRight,
"Meta", KeyValues.ShiftLeft,
"MetaLeft", KeyValues.ShiftRight,
"MetaRight",
"Shift",
"ShiftLeft",
"ShiftRight",
]); ]);
const isModifier = (key: string): boolean => { const isModifier = (key: KeyValues): boolean => {
return modifierKeySet.has(key); return modifierKeySet.has(key);
}; };
const keyToDisplay = (key: string): string => { const keyToLabel = (key: KeyValues): string => {
return keyToDisplayMap[key] || key; return KeyLabels[key] || key;
}; };
const updateKeybind = () => { const updateKeybind = () => {
const modifiers = Array.from(activeModifiers).sort(); const modifiers = Array.from(activeModifiers);
const nonModifiers = keybind.value.filter((key) => !isModifier(key)); const nonModifiers = keybind.value.filter((key) => !isModifier(key));
keybind.value = [...modifiers, ...nonModifiers]; keybind.value = [...modifiers, ...nonModifiers];
}; };
@ -133,9 +108,9 @@ const onFocus = () => {
}; };
const onKeyDown = (event: KeyboardEvent) => { const onKeyDown = (event: KeyboardEvent) => {
const key = event.code; const key = event.code as KeyValues;
if (key === "Escape") { if (key === KeyValues.Escape) {
if (keybindInput.value) { if (keybindInput.value) {
keybindInput.value.blur(); keybindInput.value.blur();
} }
@ -155,8 +130,7 @@ const onKeyDown = (event: KeyboardEvent) => {
const saveKeybind = async () => { const saveKeybind = async () => {
if (keybind.value.length > 0) { if (keybind.value.length > 0) {
console.log("Saving keybind", keybind.value); await invoke("save_keybind", { keybind: keybind.value });
await invoke("save_keybind", { keybind: keybind });
} else { } else {
showEmptyKeybindError.value = true; showEmptyKeybindError.value = true;
} }
@ -165,8 +139,13 @@ const saveKeybind = async () => {
os.value = platform(); os.value = platform();
onMounted(() => { onMounted(() => {
keyboard.down([Key.All], (event) => {
if (isKeybindInputFocused.value) {
onKeyDown(event);
}
});
keyboard.down([Key.Escape], (event) => { keyboard.down([Key.Escape], (event) => {
console.log("Escape key pressed");
if (isKeybindInputFocused.value) { if (isKeybindInputFocused.value) {
keybindInput.value?.blur(); keybindInput.value?.blur();
} else { } else {

View file

@ -1,6 +1,6 @@
diff --git a/node_modules/wrdu-keyboard/.DS_Store b/.DS_Store diff --git a/node_modules/wrdu-keyboard/.DS_Store b/.DS_Store
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..fabbd951c2d14c46fd10fa167b8836d116bc0db6 index 0000000000000000000000000000000000000000..4b7e9446f3580fab3e4feaba097bcdaf98c5833c
Binary files /dev/null and b/.DS_Store differ Binary files /dev/null and b/.DS_Store differ
diff --git a/dist/runtime/keyboard.d.ts b/dist/runtime/keyboard.d.ts diff --git a/dist/runtime/keyboard.d.ts b/dist/runtime/keyboard.d.ts
index aeae40f3d2bc3efd459cce04c29c21c43884154d..6131bab4895ebb3048a5225f366430d23c5f1f13 100644 index aeae40f3d2bc3efd459cce04c29c21c43884154d..6131bab4895ebb3048a5225f366430d23c5f1f13 100644
@ -27,10 +27,10 @@ index aeae40f3d2bc3efd459cce04c29c21c43884154d..6131bab4895ebb3048a5225f366430d2
up: New; up: New;
prevent: { prevent: {
diff --git a/dist/runtime/keyboard.js b/dist/runtime/keyboard.js diff --git a/dist/runtime/keyboard.js b/dist/runtime/keyboard.js
index e16f600258cee90d185ffc52777bed95c14bd93e..e4ce2678db649ec82e5a67fcdb74f5cdb37820aa 100644 index e16f600258cee90d185ffc52777bed95c14bd93e..5ddec447a5dc66ffe063eb9f9dd765c9045bdaf7 100644
--- a/dist/runtime/keyboard.js --- a/dist/runtime/keyboard.js
+++ b/dist/runtime/keyboard.js +++ b/dist/runtime/keyboard.js
@@ -1,13 +1,14 @@ @@ -1,45 +1,54 @@
import { Key } from "./types/keys.js"; import { Key } from "./types/keys.js";
import { defineNuxtPlugin } from "#app"; import { defineNuxtPlugin } from "#app";
-const getKeyString = (keys) => keys[0] == Key.All ? keys.sort().join("+") : "All"; -const getKeyString = (keys) => keys[0] == Key.All ? keys.sort().join("+") : "All";
@ -45,18 +45,31 @@ index e16f600258cee90d185ffc52777bed95c14bd93e..e4ce2678db649ec82e5a67fcdb74f5cd
+ const key = event.code; + const key = event.code;
+ pressedKeys.add(key); + pressedKeys.add(key);
const pressedArray = Array.from(pressedKeys); const pressedArray = Array.from(pressedKeys);
const keyString = getKeyString(pressedArray); - const keyString = getKeyString(pressedArray);
if (handlers.down[keyString]) { - if (handlers.down[keyString]) {
@@ -17,13 +18,16 @@ const onKeydown = (event) => { - handlers.down[keyString].forEach((eventHandler) => {
} - if (eventHandler.prevent) {
eventHandler.handler(event); - event.preventDefault();
if (eventHandler.once) { - }
- eventHandler.handler(event);
- if (eventHandler.once) {
- handlers.down[keyString] = handlers.down[keyString].filter((h) => h !== eventHandler); - handlers.down[keyString] = handlers.down[keyString].filter((h) => h !== eventHandler);
- }
- });
+ for (const keyString of [getKeyString(pressedArray), "All"]) {
+ if (handlers.down[keyString]) {
+ handlers.down[keyString].forEach((eventHandler) => {
+ if (eventHandler.prevent) {
+ event.preventDefault();
+ }
+ eventHandler.handler(event);
+ if (eventHandler.once) {
+ handlers.down[keyString] = handlers.down[keyString].filter( + handlers.down[keyString] = handlers.down[keyString].filter(
+ (h) => h !== eventHandler + (h) => h !== eventHandler
+ ); + );
} + }
}); + });
+ }
} }
}; };
const onKeyup = (event) => { const onKeyup = (event) => {
@ -64,18 +77,31 @@ index e16f600258cee90d185ffc52777bed95c14bd93e..e4ce2678db649ec82e5a67fcdb74f5cd
+ const key = event.code; + const key = event.code;
+ pressedKeys.delete(key); + pressedKeys.delete(key);
const releasedArray = Array.from(pressedKeys); const releasedArray = Array.from(pressedKeys);
const keyString = getKeyString(releasedArray); - const keyString = getKeyString(releasedArray);
if (handlers.up[keyString]) { - if (handlers.up[keyString]) {
@@ -33,13 +37,16 @@ const onKeyup = (event) => { - handlers.up[keyString].forEach((eventHandler) => {
} - if (eventHandler.prevent) {
eventHandler.handler(event); - event.preventDefault();
if (eventHandler.once) { - }
- eventHandler.handler(event);
- if (eventHandler.once) {
- handlers.up[keyString] = handlers.up[keyString].filter((h) => h !== eventHandler); - handlers.up[keyString] = handlers.up[keyString].filter((h) => h !== eventHandler);
- }
- });
+ for (const keyString of [getKeyString(releasedArray), "All"]) {
+ if (handlers.up[keyString]) {
+ handlers.up[keyString].forEach((eventHandler) => {
+ if (eventHandler.prevent) {
+ event.preventDefault();
+ }
+ eventHandler.handler(event);
+ if (eventHandler.once) {
+ handlers.up[keyString] = handlers.up[keyString].filter( + handlers.up[keyString] = handlers.up[keyString].filter(
+ (h) => h !== eventHandler + (h) => h !== eventHandler
+ ); + );
} + }
}); + });
+ }
} }
}; };
const init = () => { const init = () => {
@ -84,36 +110,18 @@ index e16f600258cee90d185ffc52777bed95c14bd93e..e4ce2678db649ec82e5a67fcdb74f5cd
window.addEventListener("keydown", onKeydown); window.addEventListener("keydown", onKeydown);
window.addEventListener("keyup", onKeyup); window.addEventListener("keyup", onKeyup);
}; };
@@ -47,6 +54,20 @@ const stop = () => { @@ -47,6 +56,10 @@ const stop = () => {
window.removeEventListener("keydown", onKeydown); window.removeEventListener("keydown", onKeydown);
window.removeEventListener("keyup", onKeyup); window.removeEventListener("keyup", onKeyup);
}; };
+const unregisterAll = () => { +const unregisterAll = () => {
+ Object.keys(handlers.down).forEach((key) => {
+ handlers.down[key].forEach((handler) => {
+ console.log(`Unregistering ${key} ${handler.handler.toString()}`);
+ });
+ });
+ Object.keys(handlers.up).forEach((key) => {
+ handlers.up[key].forEach((handler) => {
+ console.log(`Unregistering ${key} ${handler.handler.toString()}`);
+ });
+ });
+ handlers.down = {}; + handlers.down = {};
+ handlers.up = {}; + handlers.up = {};
+}; +};
const down = (keys, handler, config = {}) => { const down = (keys, handler, config = {}) => {
if (keys.includes(Key.All)) { if (keys.includes(Key.All)) {
keys = [Key.All]; keys = [Key.All];
@@ -59,6 +80,7 @@ const down = (keys, handler, config = {}) => { @@ -84,6 +97,7 @@ const keyboard = defineNuxtPlugin((nuxtApp) => {
handlers.down[key] = [];
}
const { once = false, prevent = false } = config;
+ console.log(key, handler.toString());
handlers.down[key].push({ handler, prevent, once });
};
const up = (keys, handler, config = {}) => {
@@ -84,6 +106,7 @@ const keyboard = defineNuxtPlugin((nuxtApp) => {
keyboard: { keyboard: {
init, init,
stop, stop,

View file

@ -1,48 +1,61 @@
use tauri_plugin_aptabase::EventTracker;
use crate::utils::commands::center_window_on_current_monitor; use crate::utils::commands::center_window_on_current_monitor;
use crate::utils::keys::KeyCode;
use global_hotkey::{ use global_hotkey::{
hotkey::{Code, HotKey, Modifiers}, hotkey::{Code, HotKey, Modifiers},
GlobalHotKeyEvent, GlobalHotKeyManager, HotKeyState, GlobalHotKeyEvent, GlobalHotKeyManager, HotKeyState,
}; };
use std::cell::RefCell; use lazy_static::lazy_static;
use std::str::FromStr; use std::str::FromStr;
use std::sync::Mutex;
use tauri::{AppHandle, Listener, Manager}; use tauri::{AppHandle, Listener, Manager};
use tauri_plugin_aptabase::EventTracker;
thread_local! { lazy_static! {
static HOTKEY_MANAGER: RefCell<Option<GlobalHotKeyManager>> = RefCell::new(None); static ref HOTKEY_MANAGER: Mutex<Option<GlobalHotKeyManager>> = Mutex::new(None);
static ref REGISTERED_HOTKEYS: Mutex<Vec<HotKey>> = Mutex::new(Vec::new());
} }
pub fn setup(app_handle: tauri::AppHandle) { pub fn setup(app_handle: tauri::AppHandle) {
let app_handle_clone = app_handle.clone(); let app_handle_clone = app_handle.clone();
let manager = GlobalHotKeyManager::new().expect("Failed to initialize hotkey manager"); let manager = match GlobalHotKeyManager::new() {
HOTKEY_MANAGER.with(|m| *m.borrow_mut() = Some(manager)); Ok(manager) => manager,
Err(err) => {
eprintln!("Failed to initialize hotkey manager: {:?}", err);
return;
}
};
{
let mut manager_guard = HOTKEY_MANAGER.lock().unwrap();
*manager_guard = Some(manager);
}
let rt = app_handle.state::<tokio::runtime::Runtime>(); let rt = app_handle.state::<tokio::runtime::Runtime>();
let initial_keybind = rt let initial_keybind = rt
.block_on(crate::db::settings::get_keybind(app_handle_clone.clone())) .block_on(crate::db::settings::get_keybind(app_handle_clone.clone()))
.expect("Failed to get initial keybind"); .expect("Failed to get initial keybind");
let initial_shortcut = initial_keybind.join("+");
let initial_shortcut_for_update = initial_shortcut.clone(); let initial_shortcut_for_update = initial_keybind.clone();
let initial_shortcut_for_save = initial_shortcut.clone(); let initial_shortcut_for_save = initial_keybind.clone();
if let Err(e) = register_shortcut(&initial_shortcut) { if let Err(e) = register_shortcut(&initial_keybind) {
eprintln!("Error registering initial shortcut: {:?}", e); eprintln!("Error registering initial shortcut: {:?}", e);
} }
app_handle.listen("update-shortcut", move |event| { app_handle.listen("update-shortcut", move |event| {
let payload_str = event.payload().to_string(); let payload_str = event.payload();
if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut_for_update) { if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut_for_update) {
HOTKEY_MANAGER.with(|manager| { let manager_guard = HOTKEY_MANAGER.lock().unwrap();
if let Some(manager) = manager.borrow().as_ref() { if let Some(manager) = manager_guard.as_ref() {
let _ = manager.unregister(old_hotkey); let _ = manager.unregister(old_hotkey);
} }
});
} }
if let Err(e) = register_shortcut(&payload_str) { let payload: Vec<String> = serde_json::from_str(payload_str).unwrap_or_default();
if let Err(e) = register_shortcut(&payload) {
eprintln!("Error re-registering shortcut: {:?}", e); eprintln!("Error re-registering shortcut: {:?}", e);
} }
}); });
@ -51,14 +64,14 @@ pub fn setup(app_handle: tauri::AppHandle) {
let payload_str = event.payload().to_string(); let payload_str = event.payload().to_string();
if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut_for_save) { if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut_for_save) {
HOTKEY_MANAGER.with(|manager| { let manager_guard = HOTKEY_MANAGER.lock().unwrap();
if let Some(manager) = manager.borrow().as_ref() { if let Some(manager) = manager_guard.as_ref() {
let _ = manager.unregister(old_hotkey); let _ = manager.unregister(old_hotkey);
} }
});
} }
if let Err(e) = register_shortcut(&payload_str) { let payload: Vec<String> = serde_json::from_str(&payload_str).unwrap_or_default();
if let Err(e) = register_shortcut(&payload) {
eprintln!("Error registering saved shortcut: {:?}", e); eprintln!("Error registering saved shortcut: {:?}", e);
} }
}); });
@ -81,48 +94,36 @@ pub fn setup(app_handle: tauri::AppHandle) {
}); });
} }
fn register_shortcut(shortcut: &str) -> Result<(), Box<dyn std::error::Error>> { fn register_shortcut(shortcut: &[String]) -> Result<(), Box<dyn std::error::Error>> {
let hotkey = parse_hotkey(shortcut)?; let hotkey = parse_hotkey(shortcut)?;
HOTKEY_MANAGER.with(|manager| {
if let Some(manager) = manager.borrow().as_ref() { let manager_guard = HOTKEY_MANAGER.lock().unwrap();
manager.register(hotkey)?; if let Some(manager) = manager_guard.as_ref() {
} manager.register(hotkey.clone())?;
REGISTERED_HOTKEYS.lock().unwrap().push(hotkey);
Ok(()) Ok(())
}) } else {
Err("Hotkey manager not initialized".into())
}
} }
fn parse_hotkey(shortcut: &str) -> Result<HotKey, Box<dyn std::error::Error>> { fn parse_hotkey(shortcut: &[String]) -> Result<HotKey, Box<dyn std::error::Error>> {
let mut modifiers = Modifiers::empty(); let mut modifiers = Modifiers::empty();
let mut code = None; let mut code = None;
let shortcut = shortcut.replace("\"", ""); for part in shortcut {
for part in shortcut.split('+') {
let part = part.trim().to_lowercase();
match part.as_str() { match part.as_str() {
"ctrl" | "control" | "controlleft" => modifiers |= Modifiers::CONTROL, "ControlLeft" => modifiers |= Modifiers::CONTROL,
"alt" | "altleft" | "optionleft" => modifiers |= Modifiers::ALT, "AltLeft" => modifiers |= Modifiers::ALT,
"shift" | "shiftleft" => modifiers |= Modifiers::SHIFT, "ShiftLeft" => modifiers |= Modifiers::SHIFT,
"super" | "meta" | "cmd" | "metaleft" => modifiers |= Modifiers::META, "MetaLeft" => modifiers |= Modifiers::META,
key => { key => {
let key_code = if key.starts_with("key") { code = Some(Code::from(KeyCode::from_str(key)?));
"Key".to_string() + &key[3..].to_uppercase()
} else if key.len() == 1 && key.chars().next().unwrap().is_alphabetic() {
"Key".to_string() + &key.to_uppercase()
} else {
key.to_string()
};
code = Some(
Code::from_str(&key_code)
.map_err(|_| format!("Invalid key code: {}", key_code))?,
);
} }
} }
} }
let key_code = let key_code = code.ok_or_else(|| "No valid key code found".to_string())?;
code.ok_or_else(|| format!("No valid key code found in shortcut: {}", shortcut))?;
Ok(HotKey::new(Some(modifiers), key_code)) Ok(HotKey::new(Some(modifiers), key_code))
} }
@ -144,7 +145,10 @@ fn handle_hotkey_event(app_handle: &AppHandle) {
center_window_on_current_monitor(&window); center_window_on_current_monitor(&window);
} }
let _ = app_handle.track_event("hotkey_triggered", Some(serde_json::json!({ let _ = app_handle.track_event(
"hotkey_triggered",
Some(serde_json::json!({
"action": if window.is_visible().unwrap() { "hide" } else { "show" } "action": if window.is_visible().unwrap() { "hide" } else { "show" }
}))); })),
);
} }

View file

@ -30,11 +30,8 @@ pub async fn save_keybind(
pool: tauri::State<'_, SqlitePool>, pool: tauri::State<'_, SqlitePool>,
keybind: Vec<String>, keybind: Vec<String>,
) -> Result<(), String> { ) -> Result<(), String> {
let keybind_str = keybind.join("+");
let keybind_clone = keybind_str.clone();
app_handle app_handle
.emit("update-shortcut", &keybind_str) .emit("update-shortcut", &keybind)
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
let json = serde_json::to_string(&keybind).map_err(|e| e.to_string())?; let json = serde_json::to_string(&keybind).map_err(|e| e.to_string())?;
@ -46,7 +43,7 @@ pub async fn save_keybind(
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
let _ = app_handle.track_event("keybind_saved", Some(serde_json::json!({ let _ = app_handle.track_event("keybind_saved", Some(serde_json::json!({
"keybind": keybind_clone "keybind": keybind
}))); })));
Ok(()) Ok(())
@ -97,7 +94,7 @@ pub async fn get_keybind(app_handle: tauri::AppHandle) -> Result<Vec<String>, St
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
let json = row.map(|r| r.get::<String, _>("value")).unwrap_or_else(|| { let json = row.map(|r| r.get::<String, _>("value")).unwrap_or_else(|| {
serde_json::to_string(&vec!["Meta".to_string(), "V".to_string()]) serde_json::to_string(&vec!["MetaLeft".to_string(), "KeyV".to_string()])
.expect("Failed to serialize default keybind") .expect("Failed to serialize default keybind")
}); });

118
src-tauri/src/utils/keys.rs Normal file
View file

@ -0,0 +1,118 @@
use global_hotkey::hotkey::Code;
use std::str::FromStr;
pub struct KeyCode(Code);
impl FromStr for KeyCode {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let code = match s {
"Backquote" => Code::Backquote,
"Backslash" => Code::Backslash,
"BracketLeft" => Code::BracketLeft,
"BracketRight" => Code::BracketRight,
"Comma" => Code::Comma,
"Digit0" => Code::Digit0,
"Digit1" => Code::Digit1,
"Digit2" => Code::Digit2,
"Digit3" => Code::Digit3,
"Digit4" => Code::Digit4,
"Digit5" => Code::Digit5,
"Digit6" => Code::Digit6,
"Digit7" => Code::Digit7,
"Digit8" => Code::Digit8,
"Digit9" => Code::Digit9,
"Equal" => Code::Equal,
"KeyA" => Code::KeyA,
"KeyB" => Code::KeyB,
"KeyC" => Code::KeyC,
"KeyD" => Code::KeyD,
"KeyE" => Code::KeyE,
"KeyF" => Code::KeyF,
"KeyG" => Code::KeyG,
"KeyH" => Code::KeyH,
"KeyI" => Code::KeyI,
"KeyJ" => Code::KeyJ,
"KeyK" => Code::KeyK,
"KeyL" => Code::KeyL,
"KeyM" => Code::KeyM,
"KeyN" => Code::KeyN,
"KeyO" => Code::KeyO,
"KeyP" => Code::KeyP,
"KeyQ" => Code::KeyQ,
"KeyR" => Code::KeyR,
"KeyS" => Code::KeyS,
"KeyT" => Code::KeyT,
"KeyU" => Code::KeyU,
"KeyV" => Code::KeyV,
"KeyW" => Code::KeyW,
"KeyX" => Code::KeyX,
"KeyY" => Code::KeyY,
"KeyZ" => Code::KeyZ,
"Minus" => Code::Minus,
"Period" => Code::Period,
"Quote" => Code::Quote,
"Semicolon" => Code::Semicolon,
"Slash" => Code::Slash,
"Backspace" => Code::Backspace,
"CapsLock" => Code::CapsLock,
"Delete" => Code::Delete,
"Enter" => Code::Enter,
"Space" => Code::Space,
"Tab" => Code::Tab,
"End" => Code::End,
"Home" => Code::Home,
"Insert" => Code::Insert,
"PageDown" => Code::PageDown,
"PageUp" => Code::PageUp,
"ArrowDown" => Code::ArrowDown,
"ArrowLeft" => Code::ArrowLeft,
"ArrowRight" => Code::ArrowRight,
"ArrowUp" => Code::ArrowUp,
"NumLock" => Code::NumLock,
"Numpad0" => Code::Numpad0,
"Numpad1" => Code::Numpad1,
"Numpad2" => Code::Numpad2,
"Numpad3" => Code::Numpad3,
"Numpad4" => Code::Numpad4,
"Numpad5" => Code::Numpad5,
"Numpad6" => Code::Numpad6,
"Numpad7" => Code::Numpad7,
"Numpad8" => Code::Numpad8,
"Numpad9" => Code::Numpad9,
"NumpadAdd" => Code::NumpadAdd,
"NumpadDecimal" => Code::NumpadDecimal,
"NumpadDivide" => Code::NumpadDivide,
"NumpadMultiply" => Code::NumpadMultiply,
"NumpadSubtract" => Code::NumpadSubtract,
"Escape" => Code::Escape,
"PrintScreen" => Code::PrintScreen,
"ScrollLock" => Code::ScrollLock,
"Pause" => Code::Pause,
"AudioVolumeDown" => Code::AudioVolumeDown,
"AudioVolumeMute" => Code::AudioVolumeMute,
"AudioVolumeUp" => Code::AudioVolumeUp,
"F1" => Code::F1,
"F2" => Code::F2,
"F3" => Code::F3,
"F4" => Code::F4,
"F5" => Code::F5,
"F6" => Code::F6,
"F7" => Code::F7,
"F8" => Code::F8,
"F9" => Code::F9,
"F10" => Code::F10,
"F11" => Code::F11,
"F12" => Code::F12,
_ => return Err(format!("Unknown key code: {}", s)),
};
Ok(KeyCode(code))
}
}
impl From<KeyCode> for Code {
fn from(key_code: KeyCode) -> Self {
key_code.0
}
}

View file

@ -2,3 +2,4 @@ pub mod commands;
pub mod favicon; pub mod favicon;
pub mod types; pub mod types;
pub mod logger; pub mod logger;
pub mod keys;

217
types/keys.ts Normal file
View file

@ -0,0 +1,217 @@
export enum KeyValues {
Backquote = 'Backquote',
Backslash = 'Backslash',
BracketLeft = 'BracketLeft',
BracketRight = 'BracketRight',
Comma = 'Comma',
Digit0 = 'Digit0',
Digit1 = 'Digit1',
Digit2 = 'Digit2',
Digit3 = 'Digit3',
Digit4 = 'Digit4',
Digit5 = 'Digit5',
Digit6 = 'Digit6',
Digit7 = 'Digit7',
Digit8 = 'Digit8',
Digit9 = 'Digit9',
Equal = 'Equal',
KeyA = 'KeyA',
KeyB = 'KeyB',
KeyC = 'KeyC',
KeyD = 'KeyD',
KeyE = 'KeyE',
KeyF = 'KeyF',
KeyG = 'KeyG',
KeyH = 'KeyH',
KeyI = 'KeyI',
KeyJ = 'KeyJ',
KeyK = 'KeyK',
KeyL = 'KeyL',
KeyM = 'KeyM',
KeyN = 'KeyN',
KeyO = 'KeyO',
KeyP = 'KeyP',
KeyQ = 'KeyQ',
KeyR = 'KeyR',
KeyS = 'KeyS',
KeyT = 'KeyT',
KeyU = 'KeyU',
KeyV = 'KeyV',
KeyW = 'KeyW',
KeyX = 'KeyX',
KeyY = 'KeyY',
KeyZ = 'KeyZ',
Minus = 'Minus',
Period = 'Period',
Quote = 'Quote',
Semicolon = 'Semicolon',
Slash = 'Slash',
AltLeft = 'AltLeft',
AltRight = 'AltRight',
Backspace = 'Backspace',
CapsLock = 'CapsLock',
ContextMenu = 'ContextMenu',
ControlLeft = 'ControlLeft',
ControlRight = 'ControlRight',
Enter = 'Enter',
MetaLeft = 'MetaLeft',
MetaRight = 'MetaRight',
ShiftLeft = 'ShiftLeft',
ShiftRight = 'ShiftRight',
Space = 'Space',
Tab = 'Tab',
Delete = 'Delete',
End = 'End',
Home = 'Home',
Insert = 'Insert',
PageDown = 'PageDown',
PageUp = 'PageUp',
ArrowDown = 'ArrowDown',
ArrowLeft = 'ArrowLeft',
ArrowRight = 'ArrowRight',
ArrowUp = 'ArrowUp',
NumLock = 'NumLock',
Numpad0 = 'Numpad0',
Numpad1 = 'Numpad1',
Numpad2 = 'Numpad2',
Numpad3 = 'Numpad3',
Numpad4 = 'Numpad4',
Numpad5 = 'Numpad5',
Numpad6 = 'Numpad6',
Numpad7 = 'Numpad7',
Numpad8 = 'Numpad8',
Numpad9 = 'Numpad9',
NumpadAdd = 'NumpadAdd',
NumpadDecimal = 'NumpadDecimal',
NumpadDivide = 'NumpadDivide',
NumpadMultiply = 'NumpadMultiply',
NumpadSubtract = 'NumpadSubtract',
Escape = 'Escape',
PrintScreen = 'PrintScreen',
ScrollLock = 'ScrollLock',
Pause = 'Pause',
AudioVolumeDown = 'AudioVolumeDown',
AudioVolumeMute = 'AudioVolumeMute',
AudioVolumeUp = 'AudioVolumeUp',
F1 = 'F1',
F2 = 'F2',
F3 = 'F3',
F4 = 'F4',
F5 = 'F5',
F6 = 'F6',
F7 = 'F7',
F8 = 'F8',
F9 = 'F9',
F10 = 'F10',
F11 = 'F11',
F12 = 'F12',
}
export enum KeyLabels {
Backquote = '`',
Backslash = '\\',
BracketLeft = '[',
BracketRight = ']',
Comma = ',',
Digit0 = '0',
Digit1 = '1',
Digit2 = '2',
Digit3 = '3',
Digit4 = '4',
Digit5 = '5',
Digit6 = '6',
Digit7 = '7',
Digit8 = '8',
Digit9 = '9',
Equal = '=',
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',
Minus = '-',
Period = '.',
Quote = "'",
Semicolon = ';',
Slash = '/',
AltLeft = 'Alt',
AltRight = 'Alt (Right)',
Backspace = 'Backspace',
CapsLock = 'Caps Lock',
ContextMenu = 'Context Menu',
ControlLeft = 'Ctrl',
ControlRight = 'Ctrl (Right)',
Enter = 'Enter',
MetaLeft = 'Meta',
MetaRight = 'Meta (Right)',
ShiftLeft = 'Shift',
ShiftRight = 'Shift (Right)',
Space = 'Space',
Tab = 'Tab',
Delete = 'Delete',
End = 'End',
Home = 'Home',
Insert = 'Insert',
PageDown = 'Page Down',
PageUp = 'Page Up',
ArrowDown = '↓',
ArrowLeft = '←',
ArrowRight = '→',
ArrowUp = '↑',
NumLock = 'Num Lock',
Numpad0 = 'Numpad 0',
Numpad1 = 'Numpad 1',
Numpad2 = 'Numpad 2',
Numpad3 = 'Numpad 3',
Numpad4 = 'Numpad 4',
Numpad5 = 'Numpad 5',
Numpad6 = 'Numpad 6',
Numpad7 = 'Numpad 7',
Numpad8 = 'Numpad 8',
Numpad9 = 'Numpad 9',
NumpadAdd = 'Numpad +',
NumpadDecimal = 'Numpad .',
NumpadDivide = 'Numpad /',
NumpadMultiply = 'Numpad *',
NumpadSubtract = 'Numpad -',
Escape = 'Esc',
PrintScreen = 'Print Screen',
ScrollLock = 'Scroll Lock',
Pause = 'Pause',
AudioVolumeDown = 'Volume Down',
AudioVolumeMute = 'Volume Mute',
AudioVolumeUp = 'Volume Up',
F1 = 'F1',
F2 = 'F2',
F3 = 'F3',
F4 = 'F4',
F5 = 'F5',
F6 = 'F6',
F7 = 'F7',
F8 = 'F8',
F9 = 'F9',
F10 = 'F10',
F11 = 'F11',
F12 = 'F12',
}