From 8de6c9bb87fd0bc53ec04c64186d84b5e6354e56 Mon Sep 17 00:00:00 2001 From: Ferdinand Schober Date: Mon, 18 Dec 2023 18:08:10 +0100 Subject: [PATCH] Implement keycode translation for windows (#54) closes #48 closes #16 --- .gitignore | 2 + src/backend/consumer/dummy.rs | 6 +- src/backend/consumer/macos.rs | 2 +- src/backend/consumer/windows.rs | 44 +- src/backend/consumer/wlroots.rs | 9 +- src/backend/consumer/x11.rs | 47 +- src/backend/consumer/xdg_desktop_portal.rs | 9 +- src/backend/producer/dummy.rs | 7 +- src/backend/producer/windows.rs | 10 +- src/consumer.rs | 5 +- src/lib.rs | 1 + src/producer.rs | 5 +- src/scancode.rs | 698 +++++++++++++++++++++ src/server.rs | 25 +- 14 files changed, 828 insertions(+), 42 deletions(-) create mode 100644 src/scancode.rs diff --git a/.gitignore b/.gitignore index 25e41ad..d673c4f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target .gdbinit +.idea/ +.vs/ \ No newline at end of file diff --git a/src/backend/consumer/dummy.rs b/src/backend/consumer/dummy.rs index 7101a2b..85cef2f 100644 --- a/src/backend/consumer/dummy.rs +++ b/src/backend/consumer/dummy.rs @@ -1,5 +1,9 @@ +use crate::{ + client::{ClientEvent, ClientHandle}, + consumer::EventConsumer, + event::Event, +}; use async_trait::async_trait; -use crate::{consumer::EventConsumer, event::Event, client::{ClientHandle, ClientEvent}}; pub struct DummyConsumer; diff --git a/src/backend/consumer/macos.rs b/src/backend/consumer/macos.rs index 2bec546..a4dbfc2 100644 --- a/src/backend/consumer/macos.rs +++ b/src/backend/consumer/macos.rs @@ -209,7 +209,7 @@ impl EventConsumer for MacOSConsumer { } KeyboardEvent::Modifiers { .. } => {} }, - _ => () + _ => (), } } diff --git a/src/backend/consumer/windows.rs b/src/backend/consumer/windows.rs index a664943..7562c2e 100644 --- a/src/backend/consumer/windows.rs +++ b/src/backend/consumer/windows.rs @@ -1,8 +1,7 @@ -use crate::{ - consumer::EventConsumer, - event::{KeyboardEvent, PointerEvent}, -}; +use anyhow::Result; +use crate::{consumer::EventConsumer, event::{KeyboardEvent, PointerEvent}, scancode}; use async_trait::async_trait; +use winapi::um::winuser::{KEYEVENTF_EXTENDEDKEY, SendInput}; use winapi::{ self, um::winuser::{ @@ -21,8 +20,8 @@ use crate::{ pub struct WindowsConsumer {} impl WindowsConsumer { - pub fn new() -> Self { - Self {} + pub fn new() -> Result { + Ok(Self {}) } } @@ -76,7 +75,7 @@ fn send_mouse_input(mi: MOUSEINPUT) { u: std::mem::transmute(mi), }; - winapi::um::winuser::SendInput( + SendInput( 1 as u32, &mut input as LPINPUT, std::mem::size_of::() as i32, @@ -141,10 +140,17 @@ fn scroll(axis: u8, value: f64) { } fn key_event(key: u32, state: u8) { + let scancode = match linux_keycode_to_windows_scancode(key) { + Some(code) => code, + None => return, + }; + let extended = scancode > 0xff; + let scancode = scancode & 0xff; let ki = KEYBDINPUT { wVk: 0, - wScan: key as u16, + wScan: scancode, dwFlags: KEYEVENTF_SCANCODE + | if extended { KEYEVENTF_EXTENDEDKEY } else { 0 } | match state { 0 => KEYEVENTF_KEYUP, 1 => 0u32, @@ -163,6 +169,26 @@ fn send_keyboard_input(ki: KEYBDINPUT) { u: std::mem::zeroed(), }; *input.u.ki_mut() = ki; - winapi::um::winuser::SendInput(1 as u32, &mut input, std::mem::size_of::() as i32); + SendInput(1 as u32, &mut input, std::mem::size_of::() as i32); } } + +fn linux_keycode_to_windows_scancode(linux_keycode: u32) -> Option { + let linux_scancode = match scancode::Linux::try_from(linux_keycode) { + Ok(s) => s, + Err(_) => { + log::warn!("unknown keycode: {linux_keycode}"); + return None; + }, + }; + log::trace!("linux code: {linux_scancode:?}"); + let windows_scancode = match scancode::Windows::try_from(linux_scancode) { + Ok(s) => s, + Err(_) => { + log::warn!("failed to translate linux code into windows scancode: {linux_scancode:?}"); + return None; + } + }; + log::trace!("windows code: {windows_scancode:?}"); + Some(windows_scancode as u16) +} diff --git a/src/backend/consumer/wlroots.rs b/src/backend/consumer/wlroots.rs index da1d24d..f5f27db 100644 --- a/src/backend/consumer/wlroots.rs +++ b/src/backend/consumer/wlroots.rs @@ -100,7 +100,7 @@ impl State { panic!("no keymap"); } - let vinput = VirtualInput{ pointer, keyboard }; + let vinput = VirtualInput { pointer, keyboard }; self.input_for_client.insert(client, vinput); } @@ -191,15 +191,16 @@ impl VirtualInput { Event::Keyboard(e) => match e { KeyboardEvent::Key { time, key, state } => { self.keyboard.key(time, key, state as u32); - }, + } KeyboardEvent::Modifiers { mods_depressed, mods_latched, mods_locked, group, } => { - self.keyboard.modifiers(mods_depressed, mods_latched, mods_locked, group); - }, + self.keyboard + .modifiers(mods_depressed, mods_latched, mods_locked, group); + } }, _ => {} } diff --git a/src/backend/consumer/x11.rs b/src/backend/consumer/x11.rs index a892495..68438f2 100644 --- a/src/backend/consumer/x11.rs +++ b/src/backend/consumer/x11.rs @@ -1,9 +1,18 @@ use anyhow::{anyhow, Result}; use async_trait::async_trait; use std::ptr; -use x11::{xlib::{self, XCloseDisplay}, xtest}; +use x11::{ + xlib::{self, XCloseDisplay}, + xtest, +}; -use crate::{client::ClientHandle, consumer::EventConsumer, event::{Event, PointerEvent, BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, BTN_FORWARD, BTN_BACK, KeyboardEvent}}; +use crate::{ + client::ClientHandle, + consumer::EventConsumer, + event::{ + Event, KeyboardEvent, PointerEvent, BTN_BACK, BTN_FORWARD, BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, + }, +}; pub struct X11Consumer { display: *mut xlib::Display, @@ -50,8 +59,20 @@ impl X11Consumer { fn emulate_scroll(&self, axis: u8, value: f64) { let direction = match axis { - 1 => if value < 0.0 { Self::SCROLL_LEFT } else { Self::SCROLL_RIGHT }, - _ => if value < 0.0 { Self::SCROLL_UP } else { Self::SCROLL_DOWN }, + 1 => { + if value < 0.0 { + Self::SCROLL_LEFT + } else { + Self::SCROLL_RIGHT + } + } + _ => { + if value < 0.0 { + Self::SCROLL_UP + } else { + Self::SCROLL_DOWN + } + } }; unsafe { @@ -89,15 +110,27 @@ impl EventConsumer for X11Consumer { } => { self.relative_motion(relative_x as i32, relative_y as i32); } - PointerEvent::Button { time: _, button, state } => { + PointerEvent::Button { + time: _, + button, + state, + } => { self.emulate_mouse_button(button, state); } - PointerEvent::Axis { time: _, axis, value } => { + PointerEvent::Axis { + time: _, + axis, + value, + } => { self.emulate_scroll(axis, value); } PointerEvent::Frame {} => {} }, - Event::Keyboard(KeyboardEvent::Key { time: _, key, state }) => { + Event::Keyboard(KeyboardEvent::Key { + time: _, + key, + state, + }) => { self.emulate_key(key, state); } _ => {} diff --git a/src/backend/consumer/xdg_desktop_portal.rs b/src/backend/consumer/xdg_desktop_portal.rs index 881bd4c..6690e33 100644 --- a/src/backend/consumer/xdg_desktop_portal.rs +++ b/src/backend/consumer/xdg_desktop_portal.rs @@ -8,7 +8,14 @@ use ashpd::{ }; use async_trait::async_trait; -use crate::{consumer::EventConsumer, event::{Event::{Keyboard, Pointer}, PointerEvent, KeyboardEvent}, client::ClientEvent}; +use crate::{ + client::ClientEvent, + consumer::EventConsumer, + event::{ + Event::{Keyboard, Pointer}, + KeyboardEvent, PointerEvent, + }, +}; pub struct DesktopPortalConsumer<'a> { proxy: RemoteDesktop<'a>, diff --git a/src/backend/producer/dummy.rs b/src/backend/producer/dummy.rs index dc802b4..25317ca 100644 --- a/src/backend/producer/dummy.rs +++ b/src/backend/producer/dummy.rs @@ -1,6 +1,6 @@ use std::io; use std::pin::Pin; -use std::task::{Poll, Context}; +use std::task::{Context, Poll}; use futures_core::Stream; @@ -32,10 +32,7 @@ impl EventProducer for DummyProducer { impl Stream for DummyProducer { type Item = io::Result<(ClientHandle, Event)>; - fn poll_next( - self: Pin<&mut Self>, - _cx: &mut Context<'_>, - ) -> Poll> { + fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { Poll::Pending } } diff --git a/src/backend/producer/windows.rs b/src/backend/producer/windows.rs index 998572b..592018c 100644 --- a/src/backend/producer/windows.rs +++ b/src/backend/producer/windows.rs @@ -1,7 +1,7 @@ +use anyhow::{anyhow, Result}; use core::task::{Context, Poll}; use futures::Stream; -use std::io::Result; -use std::pin::Pin; +use std::{io, pin::Pin}; use crate::{ client::{ClientEvent, ClientHandle}, @@ -18,13 +18,13 @@ impl EventProducer for WindowsProducer { } impl WindowsProducer { - pub(crate) fn new() -> Self { - Self {} + pub(crate) fn new() -> Result { + Err(anyhow!("not implemented")) } } impl Stream for WindowsProducer { - type Item = Result<(ClientHandle, Event)>; + type Item = io::Result<(ClientHandle, Event)>; fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { Poll::Pending } diff --git a/src/consumer.rs b/src/consumer.rs index b4320d3..78eba21 100644 --- a/src/consumer.rs +++ b/src/consumer.rs @@ -23,7 +23,10 @@ pub trait EventConsumer: Send { pub async fn create() -> Box { #[cfg(windows)] - return Box::new(consumer::windows::WindowsConsumer::new()); + match consumer::windows::WindowsConsumer::new() { + Ok(c) => return Box::new(c), + Err(e) => log::warn!("windows event consumer unavailable: {e}"), + } #[cfg(target_os = "macos")] match consumer::macos::MacOSConsumer::new() { diff --git a/src/lib.rs b/src/lib.rs index 3115236..0d833f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,3 +10,4 @@ pub mod producer; pub mod backend; pub mod frontend; pub mod ioutils; +pub mod scancode; diff --git a/src/producer.rs b/src/producer.rs index bdd9975..def6fef 100644 --- a/src/producer.rs +++ b/src/producer.rs @@ -13,7 +13,10 @@ pub async fn create() -> Box { return Box::new(producer::macos::MacOSProducer::new()); #[cfg(windows)] - return Box::new(producer::windows::WindowsProducer::new()); + match producer::windows::WindowsProducer::new() { + Ok(p) => return Box::new(p), + Err(e) => log::info!("windows event producer not available: {e}"), + } #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] match producer::libei::LibeiProducer::new() { diff --git a/src/scancode.rs b/src/scancode.rs new file mode 100644 index 0000000..89ba311 --- /dev/null +++ b/src/scancode.rs @@ -0,0 +1,698 @@ +/* + * https://learn.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input + */ +#[repr(u32)] +#[derive(Debug, Clone, Copy)] +pub enum Windows { + Shutdown = 0xE05E, + SystemSleep = 0xE05F, + SystemWakeUp = 0xE063, + ErrorRollOver = 0x00FF, + KeyA = 0x001E, + KeyB = 0x0030, + KeyC = 0x002E, + KeyD = 0x0020, + KeyE = 0x0012, + KeyF = 0x0021, + KeyG = 0x0022, + KeyH = 0x0023, + KeyI = 0x0017, + KeyJ = 0x0024, + KeyK = 0x0025, + KeyL = 0x0026, + KeyM = 0x0032, + KeyN = 0x0031, + KeyO = 0x0018, + KeyP = 0x0019, + KeyQ = 0x0010, + KeyR = 0x0013, + KeyS = 0x001F, + KeyT = 0x0014, + KeyU = 0x0016, + KeyV = 0x002F, + KeyW = 0x0011, + KeyX = 0x002D, + KeyY = 0x0015, + KeyZ = 0x002C, + Key1 = 0x0002, + Key2 = 0x0003, + Key3 = 0x0004, + Key4 = 0x0005, + Key5 = 0x0006, + Key6 = 0x0007, + Key7 = 0x0008, + Key8 = 0x0009, + Key9 = 0x000A, + Key0 = 0x000B, + KeyEnter = 0x001C, + KeyEsc = 0x0001, + KeyDelete = 0x000E, + KeyTab = 0x000F, + KeySpace = 0x0039, + KeyMinus = 0x000C, + KeyEqual = 0x000D, + KeyLeftBrace = 0x001A, + KeyRightBrace = 0x001B, + KeyBackslash = 0x002B, + KeySemiColon = 0x0027, + KeyApostrophe = 0x0028, + KeyGrave = 0x0029, + KeyComma = 0x0033, + KeyDot = 0x0034, + KeySlash = 0x0035, + KeyCapsLock = 0x003A, + KeyF1 = 0x003B, + KeyF2 = 0x003C, + KeyF3 = 0x003D, + KeyF4 = 0x003E, + KeyF5 = 0x003F, + KeyF6 = 0x0040, + KeyF7 = 0x0041, + KeyF8 = 0x0042, + KeyF9 = 0x0043, + KeyF10 = 0x0044, + KeyF11 = 0x0057, + KeyF12 = 0x0058, + KeyPrintScreen = 0xE037, + KeyScrollLock = 0x0046, + KeyPause = 0xE11D45, + KeyInsert = 0xE052, + KeyHome = 0xE047, + KeyPageUp = 0xE049, + KeyDeleteForward = 0xE053, + KeyEnd = 0xE04F, + KeyPageDown = 0xE051, + KeyRight = 0xE04D, + KeyLeft = 0xE04B, + KeyDown = 0xE050, + KeyUp = 0xE048, + KeypadNumLock = 0x0045, + KeypadSlash = 0xE035, + KeypadStar = 0x0037, + KeypadDash = 0x004A, + KeypadPlus = 0x004E, + KeypadEnter = 0xE01C, + Keypad1End = 0x004F, + Keypad2DownArrow = 0x0050, + Keypad3PageDn = 0x0051, + Keypad4LeftArrow = 0x004B, + Keypad5 = 0x004C, + Keypad6RightArrow = 0x004D, + Keypad7Home = 0x0047, + Keypad8UpArrow = 0x0048, + Keypad9PageUp = 0x0049, + Keypad0Insert = 0x0052, + KeypadDot = 0x0053, + KeyNonUSSlashBar = 0x0056, + KeyApplication = 0xE05D, + KeypadEquals = 0x0059, + KeyF13 = 0x0064, + KeyF14 = 0x0065, + KeyF15 = 0x0066, + KeyF16 = 0x0067, + KeyF17 = 0x0068, + KeyF18 = 0x0069, + KeyF19 = 0x006A, + KeyF20 = 0x006B, + KeyF21 = 0x006C, + KeyF22 = 0x006D, + KeyF23 = 0x006E, + KeyF24 = 0x0076, + KeypadComma = 0x007E, + KeyInternational1 = 0x0073, + KeyInternational2 = 0x0070, + KeyInternational3 = 0x007D, + #[allow(dead_code)] + KeyInternational4 = 0x0079, // FIXME unused + #[allow(dead_code)] + KeyInternational5 = 0x007B, // FIXME unused + // KeyInternational6 = 0x005C, + KeyLANG1 = 0x0072, + KeyLANG2 = 0x0071, + KeyLANG3 = 0x0078, + KeyLANG4 = 0x0077, + // KeyLANG5 = 0x0076, + KeyLeftCtrl = 0x001D, + KeyLeftShift = 0x002A, + KeyLeftAlt = 0x0038, + KeyLeftGUI = 0xE05B, + KeyRightCtrl = 0xE01D, + KeyRightShift = 0x0036, + KeyRightAlt = 0xE038, + KeyRightGUI = 0xE05C, + KeyScanNextTrack = 0xE019, + KeyScanPreviousTrack = 0xE010, + KeyStop = 0xE024, + KeyPlayPause = 0xE022, + KeyMute = 0xE020, + KeyVolumeUp = 0xE030, + KeyVolumeDown = 0xE02E, + #[allow(dead_code)] + ALConsumerControlConfiguration = 0xE06D, // TODO Unused + ALEmailReader = 0xE06C, + ALCalculator = 0xE021, + ALLocalMachineBrowser = 0xE06B, + ACSearch = 0xE065, + ACHome = 0xE032, + ACBack = 0xE06A, + ACForward = 0xE069, + ACStop = 0xE068, + ACRefresh = 0xE067, + ACBookmarks = 0xE066, +} + +/* + * https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h + */ +#[repr(u32)] +#[derive(Debug, Clone, Copy)] +#[allow(dead_code)] +pub enum Linux { + KeyReserved = 0, + KeyEsc = 1, + Key1 = 2, + Key2 = 3, + Key3 = 4, + Key4 = 5, + Key5 = 6, + Key6 = 7, + Key7 = 8, + Key8 = 9, + Key9 = 10, + Key0 = 11, + KeyMinus = 12, + KeyEqual = 13, + KeyBackspace = 14, + KeyTab = 15, + KeyQ = 16, + KeyW = 17, + KeyE = 18, + KeyR = 19, + KeyT = 20, + KeyY = 21, + KeyU = 22, + KeyI = 23, + KeyO = 24, + KeyP = 25, + KeyLeftbrace = 26, + KeyRightbrace = 27, + KeyEnter = 28, + KeyLeftCtrl = 29, + KeyA = 30, + KeyS = 31, + KeyD = 32, + KeyF = 33, + KeyG = 34, + KeyH = 35, + KeyJ = 36, + KeyK = 37, + KeyL = 38, + KeySemicolon = 39, + KeyApostrophe = 40, + KeyGrave = 41, + KeyLeftshift = 42, + KeyBackslash = 43, + KeyZ = 44, + KeyX = 45, + KeyC = 46, + KeyV = 47, + KeyB = 48, + KeyN = 49, + KeyM = 50, + KeyComma = 51, + KeyDot = 52, + KeySlash = 53, + KeyRightShift = 54, + KeyKpAsterisk = 55, + KeyLeftalt = 56, + KeySpace = 57, + KeyCapsLock = 58, + KeyF1 = 59, + KeyF2 = 60, + KeyF3 = 61, + KeyF4 = 62, + KeyF5 = 63, + KeyF6 = 64, + KeyF7 = 65, + KeyF8 = 66, + KeyF9 = 67, + KeyF10 = 68, + KeyNumlock = 69, + KeyScrollLock = 70, + KeyKp7 = 71, + KeyKp8 = 72, + KeyKp9 = 73, + KeyKpMinus = 74, + KeyKp4 = 75, + KeyKp5 = 76, + KeyKp6 = 77, + KeyKpplus = 78, + KeyKp1 = 79, + KeyKp2 = 80, + KeyKp3 = 81, + KeyKp0 = 82, + KeyKpDot = 83, + Invalid = 84, + KeyZenkakuhankaku = 85, + Key102nd = 86, + KeyF11 = 87, + KeyF12 = 88, + KeyRo = 89, + KeyKatakana = 90, + KeyHiragana = 91, + KeyHenkan = 92, + KeyKatakanahiragana = 93, + KeyMuhenkan = 94, + KeyKpJpComma = 95, + KeyKpEnter = 96, + KeyRightCtrl = 97, + KeyKpslash = 98, + KeySysrq = 99, + KeyRightalt = 100, + KeyLinefeed = 101, + KeyHome = 102, + KeyUp = 103, + KeyPageup = 104, + KeyLeft = 105, + KeyRight = 106, + KeyEnd = 107, + KeyDown = 108, + KeyPagedown = 109, + KeyInsert = 110, + KeyDelete = 111, + KeyMacro = 112, + KeyMute = 113, + KeyVolumeDown = 114, + KeyVolumeUp = 115, + KeyPower = 116, /* SC System Power Down */ + KeyKpequal = 117, + KeyKpplusminus = 118, + KeyPause = 119, + KeyScale = 120, /* AL Compiz Scale (Expose) */ + KeyKpcomma = 121, + KeyHangeul = 122, + // KEY_HANGUEL = KeyHangeul, + KeyHanja = 123, + KeyYen = 124, + KeyLeftmeta = 125, + KeyRightmeta = 126, + KeyCompose = 127, + KeyStop = 128, /* AC Stop */ + KeyAgain = 129, + KeyProps = 130, /* AC Properties */ + KeyUndo = 131, /* AC Undo */ + KeyFront = 132, + KeyCopy = 133, /* AC Copy */ + KeyOpen = 134, /* AC Open */ + KeyPaste = 135, /* AC Paste */ + KeyFind = 136, /* AC Search */ + KeyCut = 137, /* AC Cut */ + KeyHelp = 138, /* AL Integrated Help Center */ + KeyMenu = 139, /* Menu (show menu) */ + KeyCalc = 140, /* AL Calculator */ + KeySetup = 141, + KeySleep = 142, /* SC System Sleep */ + KeyWakeup = 143, /* System Wake Up */ + KeyFile = 144, /* AL Local Machine Browser */ + KeySendfile = 145, + KeyDeletefile = 146, + KeyXfer = 147, + KeyProg1 = 148, + KeyProg2 = 149, + KeyWww = 150, /* AL Internet Browser */ + KeyMsdos = 151, + KeyCoffee = 152, /* AL Terminal Lock/Screensaver */ + // KEY_SCREENLOCK = KeyCoffee, + KeyRotateDisplay = 153, /* Display orientation for e.g. tablets */ + // KEY_DIRECTION = KeyRotateDisplay, + KeyCyclewindows = 154, + KeyMail = 155, + KeyBookmarks = 156, /* AC Bookmarks */ + KeyComputer = 157, + KeyBack = 158, /* AC Back */ + KeyForward = 159, /* AC Forward */ + KeyClosecd = 160, + KeyEjectcd = 161, + KeyEjectclosecd = 162, + KeyNextsong = 163, + KeyPlaypause = 164, + KeyPrevioussong = 165, + KeyStopcd = 166, + KeyRecord = 167, + KeyRewind = 168, + KeyPhone = 169, /* Media Select Telephone */ + KeyIso = 170, + KeyConfig = 171, /* AL Consumer Control Configuration */ + KeyHomepage = 172, /* AC Home */ + KeyRefresh = 173, /* AC Refresh */ + KeyExit = 174, /* AC Exit */ + KeyMove = 175, + KeyEdit = 176, + KeyScrollup = 177, + KeyScrolldown = 178, + KeyKpleftparen = 179, + KeyKprightparen = 180, + KeyNew = 181, /* AC New */ + KeyRedo = 182, /* AC Redo/Repeat */ + KeyF13 = 183, + KeyF14 = 184, + KeyF15 = 185, + KeyF16 = 186, + KeyF17 = 187, + KeyF18 = 188, + KeyF19 = 189, + KeyF20 = 190, + KeyF21 = 191, + KeyF22 = 192, + KeyF23 = 193, + KeyF24 = 194, + Invalid1 = 195, + Invalid2 = 196, + Invalid3 = 197, + Invalid4 = 198, + Invalid5 = 199, + KeyPlaycd = 200, + KeyPausecd = 201, + KeyProg3 = 202, + KeyProg4 = 203, + KeyAllApplications = 204, /* AC Desktop Show All Applications */ + // KEY_DASHBOARD = KeyAllApplications, + KeySuspend = 205, + KeyClose = 206, /* AC Close */ + KeyPlay = 207, + KeyFastforward = 208, + KeyBassboost = 209, + KeyPrint = 210, /* AC Print */ + KeyHp = 211, + KeyCamera = 212, + KeySound = 213, + KeyQuestion = 214, + KeyEmail = 215, + KeyChat = 216, + KeySearch = 217, + KeyConnect = 218, + KeyFinance = 219, /* AL Checkbook/Finance */ + KeySport = 220, + KeyShop = 221, + KeyAlterase = 222, + KeyCancel = 223, /* AC Cancel */ + KeyBrightnessdown = 224, + KeyBrightnessup = 225, + KeyMedia = 226, + KeySwitchvideomode = 227, /* Cycle between available video, outputs (Monitor/LCD/TV-out/etc) */ + KeyKbdillumtoggle = 228, + KeyKbdillumdown = 229, + KeyKbdillumup = 230, + KeySend = 231, /* AC Send */ + KeyReply = 232, /* AC Reply */ + KeyForwardmail = 233, /* AC Forward Msg */ + KeySave = 234, /* AC Save */ + KeyDocuments = 235, + KeyBattery = 236, + KeyBluetooth = 237, + KeyWlan = 238, + KeyUwb = 239, + KeyUnknown = 240, + KeyVideoNext = 241, /* drive next video source */ + KeyVideoPrev = 242, /* drive previous video source */ + KeyBrightnessCycle = 243, /* brightness up, after max is min */ + KeyBrightnessAuto = 244, /* Set Auto Brightness: manual, brightness control is off, rely on ambient */ + // KEY_BRIGHTNESS_ZERO=KeyBrightnessAuto, + KeyDisplayOff = 245, /* display device to off state */ + KeyWwan = 246, /* Wireless WAN (LTE, UMTS, GSM, etc.) */ + // KEY_WIMAX = KeyWwan, + KeyRfkill = 247, /* Key that controls all radios */ + KeyMicmute = 248, /* Mute / unmute the microphone */ + KeyCount = 249, +} + +impl TryFrom for Linux { + type Error = (); + + fn try_from(value: u32) -> Result { + if value >= Self::KeyCount as u32 { + return Err(()); + } + let code: Linux = unsafe { std::mem::transmute(value) }; + Ok(code) + } +} + +impl TryFrom for Windows { + type Error = (); + + fn try_from(value: Linux) -> Result { + match value { + Linux::KeyReserved => Err(()), + Linux::KeyEsc => Ok(Self::KeyEsc), + Linux::Key1 => Ok(Self::Key1), + Linux::Key2 => Ok(Self::Key2), + Linux::Key3 => Ok(Self::Key3), + Linux::Key4 => Ok(Self::Key4), + Linux::Key5 => Ok(Self::Key5), + Linux::Key6 => Ok(Self::Key6), + Linux::Key7 => Ok(Self::Key7), + Linux::Key8 => Ok(Self::Key8), + Linux::Key9 => Ok(Self::Key9), + Linux::Key0 => Ok(Self::Key0), + Linux::KeyMinus => Ok(Self::KeyMinus), + Linux::KeyEqual => Ok(Self::KeyEqual), + Linux::KeyBackspace => Ok(Self::KeyDelete), + Linux::KeyTab => Ok(Self::KeyTab), + Linux::KeyQ => Ok(Self::KeyQ), + Linux::KeyW => Ok(Self::KeyW), + Linux::KeyE => Ok(Self::KeyE), + Linux::KeyR => Ok(Self::KeyR), + Linux::KeyT => Ok(Self::KeyT), + Linux::KeyY => Ok(Self::KeyY), + Linux::KeyU => Ok(Self::KeyU), + Linux::KeyI => Ok(Self::KeyI), + Linux::KeyO => Ok(Self::KeyO), + Linux::KeyP => Ok(Self::KeyP), + Linux::KeyLeftbrace => Ok(Self::KeyLeftBrace), + Linux::KeyRightbrace => Ok(Self::KeyRightBrace), + Linux::KeyEnter => Ok(Self::KeyEnter), + Linux::KeyLeftCtrl => Ok(Self::KeyLeftCtrl), + Linux::KeyA => Ok(Self::KeyA), + Linux::KeyS => Ok(Self::KeyS), + Linux::KeyD => Ok(Self::KeyD), + Linux::KeyF => Ok(Self::KeyF), + Linux::KeyG => Ok(Self::KeyG), + Linux::KeyH => Ok(Self::KeyH), + Linux::KeyJ => Ok(Self::KeyJ), + Linux::KeyK => Ok(Self::KeyK), + Linux::KeyL => Ok(Self::KeyL), + Linux::KeySemicolon => Ok(Self::KeySemiColon), + Linux::KeyApostrophe => Ok(Self::KeyApostrophe), + Linux::KeyGrave => Ok(Self::KeyGrave), + Linux::KeyLeftshift => Ok(Self::KeyLeftShift), + Linux::KeyBackslash => Ok(Self::KeyBackslash), + Linux::KeyZ => Ok(Self::KeyZ), + Linux::KeyX => Ok(Self::KeyX), + Linux::KeyC => Ok(Self::KeyC), + Linux::KeyV => Ok(Self::KeyV), + Linux::KeyB => Ok(Self::KeyB), + Linux::KeyN => Ok(Self::KeyN), + Linux::KeyM => Ok(Self::KeyM), + Linux::KeyComma => Ok(Self::KeyComma), + Linux::KeyDot => Ok(Self::KeyDot), + Linux::KeySlash => Ok(Self::KeySlash), + Linux::KeyRightShift => Ok(Self::KeyRightShift), + Linux::KeyKpAsterisk => Ok(Self::KeypadStar), + Linux::KeyLeftalt => Ok(Self::KeyLeftAlt), + Linux::KeySpace => Ok(Self::KeySpace), + Linux::KeyCapsLock => Ok(Self::KeyCapsLock), + Linux::KeyF1 => Ok(Self::KeyF1), + Linux::KeyF2 => Ok(Self::KeyF2), + Linux::KeyF3 => Ok(Self::KeyF3), + Linux::KeyF4 => Ok(Self::KeyF4), + Linux::KeyF5 => Ok(Self::KeyF5), + Linux::KeyF6 => Ok(Self::KeyF6), + Linux::KeyF7 => Ok(Self::KeyF7), + Linux::KeyF8 => Ok(Self::KeyF8), + Linux::KeyF9 => Ok(Self::KeyF9), + Linux::KeyF10 => Ok(Self::KeyF10), + Linux::KeyNumlock => Ok(Self::KeypadNumLock), + Linux::KeyScrollLock => Ok(Self::KeyScrollLock), + Linux::KeyKp7 => Ok(Self::Keypad7Home), + Linux::KeyKp8 => Ok(Self::Keypad8UpArrow), + Linux::KeyKp9 => Ok(Self::Keypad9PageUp), + Linux::KeyKpMinus => Ok(Self::KeypadDash), + Linux::KeyKp4 => Ok(Self::Keypad4LeftArrow), + Linux::KeyKp5 => Ok(Self::Keypad5), + Linux::KeyKp6 => Ok(Self::Keypad6RightArrow), + Linux::KeyKpplus => Ok(Self::KeypadPlus), + Linux::KeyKp1 => Ok(Self::Keypad1End), + Linux::KeyKp2 => Ok(Self::Keypad2DownArrow), + Linux::KeyKp3 => Ok(Self::Keypad3PageDn), + Linux::KeyKp0 => Ok(Self::Keypad0Insert), + Linux::KeyKpDot => Ok(Self::KeypadDot), + Linux::KeyZenkakuhankaku => Ok(Self::KeyLANG1), // TODO unsure + Linux::Key102nd => Ok(Self::KeyNonUSSlashBar), // TODO unsure + Linux::KeyF11 => Ok(Self::KeyF11), + Linux::KeyF12 => Ok(Self::KeyF12), + Linux::KeyRo => Ok(Self::ErrorRollOver), // TODO unsure + Linux::KeyKatakana => Ok(Self::KeyLANG1), // TODO unsure + Linux::KeyHiragana => Ok(Self::KeyLANG2), // TODO unsure + Linux::KeyHenkan => Ok(Self::KeyLANG3), // TODO unsure + Linux::KeyKatakanahiragana => Ok(Self::KeyLANG4), // TODO unsure + Linux::KeyMuhenkan => Ok(Self::KeyLANG4), // TODO unsure + Linux::KeyKpJpComma => Ok(Self::KeypadComma), + Linux::KeyKpEnter => Ok(Self::KeypadEnter), + Linux::KeyRightCtrl => Ok(Self::KeyRightCtrl), + Linux::KeyKpslash => Ok(Self::KeypadSlash), + Linux::KeySysrq => Ok(Self::KeyPrintScreen), // TODO Windows does not have Sysrq, right? + Linux::KeyRightalt => Ok(Self::KeyRightAlt), + Linux::KeyLinefeed => Ok(Self::KeyEnter), // TODO unsure + Linux::KeyHome => Ok(Self::KeyHome), + Linux::KeyUp => Ok(Self::KeyUp), + Linux::KeyPageup => Ok(Self::KeyPageUp), + Linux::KeyLeft => Ok(Self::KeyLeft), + Linux::KeyRight => Ok(Self::KeyRight), + Linux::KeyEnd => Ok(Self::KeyEnd), + Linux::KeyDown => Ok(Self::KeyDown), + Linux::KeyPagedown => Ok(Self::KeyPageDown), + Linux::KeyInsert => Ok(Self::KeyInsert), + Linux::KeyDelete => Ok(Self::KeyDeleteForward), + Linux::KeyMacro => Err(()), // TODO + Linux::KeyMute => Ok(Self::KeyMute), + Linux::KeyVolumeDown => Ok(Self::KeyVolumeDown), + Linux::KeyVolumeUp => Ok(Self::KeyVolumeUp), + Linux::KeyPower => Ok(Self::Shutdown), + Linux::KeyKpequal => Ok(Self::KeypadEquals), + Linux::KeyKpplusminus => Ok(Self::KeypadPlus), + Linux::KeyPause => Ok(Self::KeyPause), + Linux::KeyScale => Err(()), // TODO + Linux::KeyKpcomma => Ok(Self::KeypadComma), + Linux::KeyHangeul => Ok(Self::KeyInternational1), // TODO unsure + Linux::KeyHanja => Ok(Self::KeyInternational2), // TODO unsure + Linux::KeyYen => Ok(Self::KeyInternational3), // TODO unsure + Linux::KeyLeftmeta => Ok(Self::KeyLeftGUI), + Linux::KeyRightmeta => Ok(Self::KeyRightGUI), + Linux::KeyCompose => Ok(Self::KeyApplication), + Linux::KeyStop => Ok(Self::ACStop), + Linux::KeyAgain => Err(()), + Linux::KeyProps => Err(()), + Linux::KeyUndo => Err(()), + Linux::KeyFront => Err(()), + Linux::KeyCopy => Err(()), + Linux::KeyOpen => Err(()), + Linux::KeyPaste => Err(()), + Linux::KeyFind => Ok(Self::ACSearch), + Linux::KeyCut => Err(()), + Linux::KeyHelp => Ok(Self::KeyF1), // AL Integrated Help Center? + Linux::KeyMenu => Ok(Self::KeyApplication), + Linux::KeyCalc => Ok(Self::ALCalculator), + Linux::KeySetup => Err(()), + Linux::KeySleep => Ok(Self::SystemSleep), + Linux::KeyWakeup => Ok(Self::SystemWakeUp), + Linux::KeyFile => Ok(Self::ALLocalMachineBrowser), + Linux::KeySendfile => Err(()), + Linux::KeyDeletefile => Err(()), + Linux::KeyXfer => Err(()), + Linux::KeyProg1 => Err(()), + Linux::KeyProg2 => Err(()), + Linux::KeyWww => Ok(Self::ACSearch), // TODO unsure + Linux::KeyMsdos => Err(()), + Linux::KeyCoffee => Err(()), + Linux::KeyRotateDisplay => Err(()), + Linux::KeyCyclewindows => Err(()), + Linux::KeyMail => Ok(Self::ALEmailReader), + Linux::KeyBookmarks => Ok(Self::ACBookmarks), + Linux::KeyComputer => Ok(Self::ACHome), + Linux::KeyBack => Ok(Self::ACBack), + Linux::KeyForward => Ok(Self::ACForward), + Linux::KeyClosecd => Err(()), + Linux::KeyEjectcd => Err(()), + Linux::KeyEjectclosecd => Err(()), + Linux::KeyNextsong => Ok(Self::KeyScanNextTrack), + Linux::KeyPlaypause => Ok(Self::KeyPlayPause), + Linux::KeyPrevioussong => Ok(Self::KeyScanPreviousTrack), + Linux::KeyStopcd => Ok(Self::KeyStop), + Linux::KeyRecord => Err(()), + Linux::KeyRewind => Err(()), + Linux::KeyPhone => Err(()), + Linux::KeyIso => Err(()), + Linux::KeyConfig => Err(()), + Linux::KeyHomepage => Ok(Self::ACHome), + Linux::KeyRefresh => Ok(Self::ACRefresh), + Linux::KeyExit => Err(()), + Linux::KeyMove => Err(()), + Linux::KeyEdit => Err(()), + Linux::KeyScrollup => Err(()), + Linux::KeyScrolldown => Err(()), + Linux::KeyKpleftparen => Err(()), + Linux::KeyKprightparen => Err(()), + Linux::KeyNew => Err(()), + Linux::KeyRedo => Err(()), + Linux::KeyF13 => Ok(Self::KeyF13), + Linux::KeyF14 => Ok(Self::KeyF14), + Linux::KeyF15 => Ok(Self::KeyF15), + Linux::KeyF16 => Ok(Self::KeyF16), + Linux::KeyF17 => Ok(Self::KeyF17), + Linux::KeyF18 => Ok(Self::KeyF18), + Linux::KeyF19 => Ok(Self::KeyF19), + Linux::KeyF20 => Ok(Self::KeyF20), + Linux::KeyF21 => Ok(Self::KeyF21), + Linux::KeyF22 => Ok(Self::KeyF22), + Linux::KeyF23 => Ok(Self::KeyF23), + Linux::KeyF24 => Ok(Self::KeyF24), + Linux::KeyPlaycd => Err(()), + Linux::KeyPausecd => Err(()), + Linux::KeyProg3 => Err(()), + Linux::KeyProg4 => Err(()), + Linux::KeyAllApplications => Err(()), + Linux::KeySuspend => Err(()), + Linux::KeyClose => Err(()), + Linux::KeyPlay => Err(()), + Linux::KeyFastforward => Err(()), + Linux::KeyBassboost => Err(()), + Linux::KeyPrint => Err(()), + Linux::KeyHp => Err(()), + Linux::KeyCamera => Err(()), + Linux::KeySound => Err(()), + Linux::KeyQuestion => Err(()), + Linux::KeyEmail => Err(()), + Linux::KeyChat => Err(()), + Linux::KeySearch => Err(()), + Linux::KeyConnect => Err(()), + Linux::KeyFinance => Err(()), + Linux::KeySport => Err(()), + Linux::KeyShop => Err(()), + Linux::KeyAlterase => Err(()), + Linux::KeyCancel => Err(()), + Linux::KeyBrightnessdown => Err(()), + Linux::KeyBrightnessup => Err(()), + Linux::KeyMedia => Err(()), + Linux::KeySwitchvideomode => Err(()), + Linux::KeyKbdillumtoggle => Err(()), + Linux::KeyKbdillumdown => Err(()), + Linux::KeyKbdillumup => Err(()), + Linux::KeySend => Err(()), + Linux::KeyReply => Err(()), + Linux::KeyForwardmail => Err(()), + Linux::KeySave => Err(()), + Linux::KeyDocuments => Err(()), + Linux::KeyBattery => Err(()), + Linux::KeyBluetooth => Err(()), + Linux::KeyWlan => Err(()), + Linux::KeyUwb => Err(()), + Linux::KeyUnknown => Err(()), + Linux::KeyVideoNext => Err(()), + Linux::KeyVideoPrev => Err(()), + Linux::KeyBrightnessCycle => Err(()), + Linux::KeyBrightnessAuto => Err(()), + Linux::KeyDisplayOff => Err(()), + Linux::KeyWwan => Err(()), + Linux::KeyRfkill => Err(()), + Linux::KeyMicmute => Err(()), + Linux::KeyCount => Err(()), + Linux::Invalid => Err(()), + Linux::Invalid1 => Err(()), + Linux::Invalid2 => Err(()), + Linux::Invalid3 => Err(()), + Linux::Invalid4 => Err(()), + Linux::Invalid5 => Err(()), + } + } +} \ No newline at end of file diff --git a/src/server.rs b/src/server.rs index 0fad1d6..f430200 100644 --- a/src/server.rs +++ b/src/server.rs @@ -332,12 +332,12 @@ impl Server { self.producer.release(); self.state = State::Receiving; } - }, + } State::Receiving => { // consume event self.consumer.consume(event, handle).await; log::trace!("{event:?} => consumer"); - }, + } State::AwaitingLeave => { // we just entered the deadzone of a client, so // we need to ignore events that may still @@ -352,9 +352,9 @@ impl Server { if let Event::Enter() = event { self.state = State::Receiving; } - }, + } } - }, + } } // let the server know we are still alive once every second if state.last_replied.is_none() @@ -373,13 +373,23 @@ impl Server { async fn handle_producer_event(&mut self, c: ClientHandle, mut e: Event) { log::trace!("producer: ({c}) {e:?}"); - if let Event::Keyboard(crate::event::KeyboardEvent::Modifiers { mods_depressed, mods_latched: _, mods_locked: _, group: _ }) = e { + if let Event::Keyboard(crate::event::KeyboardEvent::Modifiers { + mods_depressed, + mods_latched: _, + mods_locked: _, + group: _, + }) = e + { if mods_depressed == Self::RELEASE_MODIFIERDS { self.producer.release(); self.state = State::Receiving; // send an event to release all the modifiers e = Event::Keyboard(KeyboardEvent::Modifiers { - mods_depressed: 0, mods_latched: 0, mods_locked: 0, group: 0 }); + mods_depressed: 0, + mods_latched: 0, + mods_locked: 0, + group: 0, + }); } } @@ -562,7 +572,8 @@ impl Server { } async fn enumerate(&mut self) { - let clients = self.client_manager + let clients = self + .client_manager .get_client_states() .map(|s| (s.client.clone(), s.active)) .collect();