Trimmed monorepo checkout (fluxer_desktop + packages/voice_engine_v2 + tools/ci) with a "Connect to a Different Server" menu item and popout that lets the desktop app switch to any self-hosted Fluxer instance, plus fixes for well-known discovery on single-domain self-hosted deployments and a false-positive ERR_ABORTED on same-origin client redirects during the switch. Defaults to chat.fluxr.chat and uses an isolated userData directory from the official build.
219 lines
5.7 KiB
Rust
219 lines
5.7 KiB
Rust
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
pub const KEYSYM_TABLE: &[(u32, &str)] = &[
|
|
(0xff1b, "Escape"),
|
|
(0xffbe, "F1"),
|
|
(0xffbf, "F2"),
|
|
(0xffc0, "F3"),
|
|
(0xffc1, "F4"),
|
|
(0xffc2, "F5"),
|
|
(0xffc3, "F6"),
|
|
(0xffc4, "F7"),
|
|
(0xffc5, "F8"),
|
|
(0xffc6, "F9"),
|
|
(0xffc7, "F10"),
|
|
(0xffc8, "F11"),
|
|
(0xffc9, "F12"),
|
|
(0xffca, "F13"),
|
|
(0xffcb, "F14"),
|
|
(0xffcc, "F15"),
|
|
(0xffcd, "F16"),
|
|
(0xffce, "F17"),
|
|
(0xffcf, "F18"),
|
|
(0xffd0, "F19"),
|
|
(0xffd1, "F20"),
|
|
(0xffd2, "F21"),
|
|
(0xffd3, "F22"),
|
|
(0xffd4, "F23"),
|
|
(0xffd5, "F24"),
|
|
(0xff61, "PrintScreen"),
|
|
(0xff14, "ScrollLock"),
|
|
(0xff13, "Pause"),
|
|
(0xff7f, "NumLock"),
|
|
(0xff67, "ContextMenu"),
|
|
(0x0060, "Backquote"),
|
|
(0x007e, "Backquote"),
|
|
(0x0031, "1"),
|
|
(0x0032, "2"),
|
|
(0x0033, "3"),
|
|
(0x0034, "4"),
|
|
(0x0035, "5"),
|
|
(0x0036, "6"),
|
|
(0x0037, "7"),
|
|
(0x0038, "8"),
|
|
(0x0039, "9"),
|
|
(0x0030, "0"),
|
|
(0x002d, "Minus"),
|
|
(0x003d, "Equal"),
|
|
(0xff08, "Backspace"),
|
|
(0xff09, "Tab"),
|
|
(0x0071, "Q"),
|
|
(0x0077, "W"),
|
|
(0x0065, "E"),
|
|
(0x0072, "R"),
|
|
(0x0074, "T"),
|
|
(0x0079, "Y"),
|
|
(0x0075, "U"),
|
|
(0x0069, "I"),
|
|
(0x006f, "O"),
|
|
(0x0070, "P"),
|
|
(0x005b, "BracketLeft"),
|
|
(0x005d, "BracketRight"),
|
|
(0x005c, "Backslash"),
|
|
(0xffe5, "CapsLock"),
|
|
(0x0061, "A"),
|
|
(0x0073, "S"),
|
|
(0x0064, "D"),
|
|
(0x0066, "F"),
|
|
(0x0067, "G"),
|
|
(0x0068, "H"),
|
|
(0x006a, "J"),
|
|
(0x006b, "K"),
|
|
(0x006c, "L"),
|
|
(0x003b, "Semicolon"),
|
|
(0x0027, "Quote"),
|
|
(0xff0d, "Enter"),
|
|
(0xffe1, "ShiftLeft"),
|
|
(0x007a, "Z"),
|
|
(0x0078, "X"),
|
|
(0x0063, "C"),
|
|
(0x0076, "V"),
|
|
(0x0062, "B"),
|
|
(0x006e, "N"),
|
|
(0x006d, "M"),
|
|
(0x002c, "Comma"),
|
|
(0x002e, "Period"),
|
|
(0x002f, "Slash"),
|
|
(0xffe2, "ShiftRight"),
|
|
(0xffe3, "ControlLeft"),
|
|
(0xffeb, "MetaLeft"),
|
|
(0xffe9, "AltLeft"),
|
|
(0x0020, "Space"),
|
|
(0xffea, "AltRight"),
|
|
(0xffec, "MetaRight"),
|
|
(0xffe4, "ControlRight"),
|
|
(0xff80, "Space"),
|
|
(0xff89, "Tab"),
|
|
(0xff8d, "NumpadEnter"),
|
|
(0xffbd, "NumpadEqual"),
|
|
(0xffaa, "NumpadMultiply"),
|
|
(0xffab, "NumpadAdd"),
|
|
(0xffac, "NumpadComma"),
|
|
(0xffad, "NumpadSubtract"),
|
|
(0xffae, "NumpadDecimal"),
|
|
(0xffaf, "NumpadDivide"),
|
|
(0xffb0, "Numpad0"),
|
|
(0xffb1, "Numpad1"),
|
|
(0xffb2, "Numpad2"),
|
|
(0xffb3, "Numpad3"),
|
|
(0xffb4, "Numpad4"),
|
|
(0xffb5, "Numpad5"),
|
|
(0xffb6, "Numpad6"),
|
|
(0xffb7, "Numpad7"),
|
|
(0xffb8, "Numpad8"),
|
|
(0xffb9, "Numpad9"),
|
|
(0xff51, "ArrowLeft"),
|
|
(0xff52, "ArrowUp"),
|
|
(0xff53, "ArrowRight"),
|
|
(0xff54, "ArrowDown"),
|
|
(0xff63, "Insert"),
|
|
(0xffff, "Delete"),
|
|
(0xff50, "Home"),
|
|
(0xff57, "End"),
|
|
(0xff55, "PageUp"),
|
|
(0xff56, "PageDown"),
|
|
(0x1008ff12, "AudioVolumeMute"),
|
|
(0x1008ff11, "AudioVolumeDown"),
|
|
(0x1008ff13, "AudioVolumeUp"),
|
|
(0x1008ff17, "MediaTrackNext"),
|
|
(0x1008ff16, "MediaTrackPrevious"),
|
|
(0x1008ff15, "MediaStop"),
|
|
(0x1008ff14, "MediaPlayPause"),
|
|
(0x1008ff26, "BrowserBack"),
|
|
(0x1008ff27, "BrowserForward"),
|
|
(0x1008ff29, "BrowserRefresh"),
|
|
(0x1008ff28, "BrowserStop"),
|
|
(0x1008ff1b, "BrowserSearch"),
|
|
(0x1008ff30, "BrowserFavorites"),
|
|
(0x1008ff18, "BrowserHome"),
|
|
(0x1008ff19, "LaunchMail"),
|
|
(0x1008ff32, "LaunchMediaPlayer"),
|
|
(0x1008ff41, "LaunchApp1"),
|
|
(0x1008ff42, "LaunchApp2"),
|
|
(0x1008ff2a, "Power"),
|
|
(0x1008ff2f, "Sleep"),
|
|
(0x1008ff2b, "WakeUp"),
|
|
(0xff23, "Convert"),
|
|
(0xff22, "NonConvert"),
|
|
(0xff2d, "KanaMode"),
|
|
(0xff31, "Lang1"),
|
|
(0xff34, "Lang2"),
|
|
];
|
|
|
|
pub fn keysym_to_name(keysym: u32) -> Option<&'static str> {
|
|
KEYSYM_TABLE
|
|
.iter()
|
|
.find(|(sym, _)| *sym == keysym)
|
|
.map(|(_, name)| *name)
|
|
}
|
|
|
|
pub fn fallback_name(keysym: u32) -> String {
|
|
format!("Key{keysym}")
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn common_letters_map_to_single_letter_names() {
|
|
assert_eq!(keysym_to_name(0x0061), Some("A"));
|
|
assert_eq!(keysym_to_name(0x006d), Some("M"));
|
|
assert_eq!(keysym_to_name(0x007a), Some("Z"));
|
|
}
|
|
|
|
#[test]
|
|
fn modifier_keysyms_produce_side_distinguished_names() {
|
|
assert_eq!(keysym_to_name(0xffe1), Some("ShiftLeft"));
|
|
assert_eq!(keysym_to_name(0xffe2), Some("ShiftRight"));
|
|
assert_eq!(keysym_to_name(0xffe3), Some("ControlLeft"));
|
|
assert_eq!(keysym_to_name(0xffe9), Some("AltLeft"));
|
|
assert_eq!(keysym_to_name(0xffeb), Some("MetaLeft"));
|
|
}
|
|
|
|
#[test]
|
|
fn function_keys_f1_through_f12() {
|
|
assert_eq!(keysym_to_name(0xffbe), Some("F1"));
|
|
assert_eq!(keysym_to_name(0xffc9), Some("F12"));
|
|
assert_eq!(keysym_to_name(0xff13), Some("Pause"));
|
|
assert_eq!(keysym_to_name(0xffca), Some("F13"));
|
|
assert_eq!(keysym_to_name(0xffb0), Some("Numpad0"));
|
|
assert_eq!(keysym_to_name(0x1008ff12), Some("AudioVolumeMute"));
|
|
assert_eq!(keysym_to_name(0x1008ff41), Some("LaunchApp1"));
|
|
}
|
|
|
|
#[test]
|
|
fn arrows_and_editing_keys_round_trip() {
|
|
assert_eq!(keysym_to_name(0xff51), Some("ArrowLeft"));
|
|
assert_eq!(keysym_to_name(0xff56), Some("PageDown"));
|
|
assert_eq!(keysym_to_name(0xffff), Some("Delete"));
|
|
}
|
|
|
|
#[test]
|
|
fn unknown_keysym_falls_back_to_key_n() {
|
|
assert!(keysym_to_name(0x12345).is_none());
|
|
assert_eq!(fallback_name(0x12345), "Key74565");
|
|
}
|
|
|
|
#[test]
|
|
fn no_distinct_names_share_a_keysym() {
|
|
for (i, (sym_i, name_i)) in KEYSYM_TABLE.iter().enumerate() {
|
|
for (sym_j, name_j) in &KEYSYM_TABLE[i + 1..] {
|
|
if sym_i == sym_j {
|
|
assert_eq!(name_i, name_j, "duplicate keysym {sym_i:#x}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|