From e621ae092021c37ea1bbb02fec45b91b68d75230 Mon Sep 17 00:00:00 2001 From: William Edwards Date: Fri, 16 Feb 2024 14:20:35 -0800 Subject: [PATCH] feat(Keyboard): add keyboard event support and support for sending keys over DBus --- Cargo.lock | 2 +- src/input/capability.rs | 163 +++++++++++++++++++++++- src/input/composite_device/mod.rs | 44 ++++++- src/input/event/evdev.rs | 172 ++++++++++++++++++++++++- src/input/target/keyboard.rs | 205 +++++++++++++++++++++++++++++- 5 files changed, 570 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2da6b9cc..5dbb28d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -604,7 +604,7 @@ dependencies = [ [[package]] name = "inputplumber" -version = "0.1.4" +version = "0.1.5" dependencies = [ "evdev", "glob-match", diff --git a/src/input/capability.rs b/src/input/capability.rs index 2d85f274..662dab9b 100644 --- a/src/input/capability.rs +++ b/src/input/capability.rs @@ -139,4 +139,165 @@ pub enum GamepadTrigger { } #[derive(Clone, Debug)] -pub enum Keyboard {} +pub enum Keyboard { + KeyEsc, + Key1, + Key2, + Key3, + Key4, + Key5, + Key6, + Key7, + Key8, + Key9, + Key0, + KeyMinus, + KeyEqual, + KeyBackspace, + KeyTab, + KeyQ, + KeyW, + KeyE, + KeyR, + KeyT, + KeyY, + KeyU, + KeyI, + KeyO, + KeyP, + KeyLeftBrace, + KeyRightBrace, + KeyEnter, + KeyLeftCtrl, + KeyA, + KeyS, + KeyD, + KeyF, + KeyG, + KeyH, + KeyJ, + KeyK, + KeyL, + KeySemicolon, + KeyApostrophe, + KeyGrave, + KeyLeftShift, + KeyBackslash, + KeyZ, + KeyX, + KeyC, + KeyV, + KeyB, + KeyN, + KeyM, + KeyComma, + KeyDot, + KeySlash, + KeyRightshift, + KeyKpasterisk, + KeyLeftAlt, + KeySpace, + KeyCapslock, + KeyF1, + KeyF2, + KeyF3, + KeyF4, + KeyF5, + KeyF6, + KeyF7, + KeyF8, + KeyF9, + KeyF10, + KeyNumlock, + KeyScrolllock, + KeyKp7, + KeyKp8, + KeyKp9, + KeyKpminus, + KeyKp4, + KeyKp5, + KeyKp6, + KeyKpplus, + KeyKp1, + KeyKp2, + KeyKp3, + KeyKp0, + KeyKpdot, + KeyZenkakuhankaku, + Key102nd, + KeyF11, + KeyF12, + KeyRo, + KeyKatakana, + KeyHiragana, + KeyHenkan, + KeyKatakanahiragana, + KeyMuhenkan, + KeyKpjpcomma, + KeyKpenter, + KeyRightctrl, + KeyKpslash, + KeySysrq, + KeyRightalt, + KeyHome, + KeyUp, + KeyPageup, + KeyLeft, + KeyRight, + KeyEnd, + KeyDown, + KeyPagedown, + KeyInsert, + KeyDelete, + KeyMute, + KeyVolumeDown, + KeyVolumeUp, + KeyPower, + KeyKpequal, + KeyPause, + KeyKpcomma, + KeyHanja, + KeyYen, + KeyLeftmeta, + KeyRightmeta, + KeyCompose, + KeyStop, + KeyAgain, + KeyProps, + KeyUndo, + KeyFront, + KeyCopy, + KeyOpen, + KeyPaste, + KeyFind, + KeyCut, + KeyHelp, + KeyCalc, + KeySleep, + KeyWww, + KeyBack, + KeyForward, + KeyEjectcd, + KeyNextsong, + KeyPlaypause, + KeyPrevioussong, + KeyStopcd, + KeyRefresh, + KeyEdit, + KeyScrollUp, + KeyScrollDown, + KeyKpleftparen, + KeyKprightparen, + KeyF13, + KeyF14, + KeyF15, + KeyF16, + KeyF17, + KeyF18, + KeyF19, + KeyF20, + KeyF21, + KeyF22, + KeyF23, + KeyF24, +} diff --git a/src/input/composite_device/mod.rs b/src/input/composite_device/mod.rs index 67bf0301..de94068e 100644 --- a/src/input/composite_device/mod.rs +++ b/src/input/composite_device/mod.rs @@ -44,6 +44,8 @@ pub enum Command { SetInterceptMode(InterceptMode), GetInterceptMode(mpsc::Sender), GetSourceDevicePaths(mpsc::Sender>), + GetTargetDevicePaths(mpsc::Sender>), + GetDBusDevicePaths(mpsc::Sender>), SourceDeviceAdded, SourceDeviceStopped(String), Stop, @@ -116,9 +118,33 @@ impl DBusInterface { Ok(()) } - /// Emitted when an input event occurs when the device is in intercept mode - #[dbus_interface(signal)] - async fn input_event(ctxt: &SignalContext<'_>, event: String, value: f64) -> zbus::Result<()>; + /// Target devices that this [CompositeDevice] is managing + #[dbus_interface(property)] + async fn target_devices(&self) -> fdo::Result> { + let (sender, mut receiver) = mpsc::channel::>(1); + self.tx + .send(Command::GetTargetDevicePaths(sender)) + .map_err(|e| fdo::Error::Failed(e.to_string()))?; + let Some(paths) = receiver.recv().await else { + return Ok(Vec::new()); + }; + + Ok(paths) + } + + /// Target dbus devices that this [CompositeDevice] is managing + #[dbus_interface(property)] + async fn dbus_devices(&self) -> fdo::Result> { + let (sender, mut receiver) = mpsc::channel::>(1); + self.tx + .send(Command::GetDBusDevicePaths(sender)) + .map_err(|e| fdo::Error::Failed(e.to_string()))?; + let Some(paths) = receiver.recv().await else { + return Ok(Vec::new()); + }; + + Ok(paths) + } } /// Defines a handle to a [CompositeDevice] for communication @@ -284,6 +310,18 @@ impl CompositeDevice { log::error!("Failed to send source device paths: {:?}", e); } } + Command::GetTargetDevicePaths(sender) => { + let paths = self.target_devices.keys().cloned().collect(); + if let Err(e) = sender.send(paths).await { + log::error!("Failed to send target device paths: {:?}", e); + } + } + Command::GetDBusDevicePaths(sender) => { + let paths = self.target_dbus_devices.keys().cloned().collect(); + if let Err(e) = sender.send(paths).await { + log::error!("Failed to send dbus device paths: {:?}", e); + } + } Command::SourceDeviceAdded => todo!(), Command::SourceDeviceStopped(device_id) => { log::debug!("Detected source device removal: {}", device_id); diff --git a/src/input/event/evdev.rs b/src/input/event/evdev.rs index bf98a7b2..4c452dfa 100644 --- a/src/input/event/evdev.rs +++ b/src/input/event/evdev.rs @@ -2,7 +2,9 @@ use std::collections::HashMap; use evdev::{AbsInfo, AbsoluteAxisCode, EventType, InputEvent, KeyCode}; -use crate::input::capability::{Capability, Gamepad, GamepadAxis, GamepadButton, GamepadTrigger}; +use crate::input::capability::{ + Capability, Gamepad, GamepadAxis, GamepadButton, GamepadTrigger, Keyboard, +}; use super::native::{InputValue, NativeEvent}; @@ -258,6 +260,7 @@ impl EvdevEvent { fn event_type_from_capability(capability: Capability) -> Option { match capability { Capability::Sync => Some(EventType::SYNCHRONIZATION), + Capability::Keyboard(_) => Some(EventType::KEY), Capability::Gamepad(gamepad) => match gamepad { Gamepad::Button(button) => match button { GamepadButton::DPadUp => Some(EventType::ABSOLUTE), @@ -370,7 +373,168 @@ fn event_codes_from_capability(capability: Capability) -> Vec { Gamepad::Gyro => vec![], }, Capability::Mouse(_) => vec![], - Capability::Keyboard(_) => vec![], + Capability::Keyboard(key) => match key { + Keyboard::KeyEsc => vec![KeyCode::KEY_ESC.0], + Keyboard::Key1 => vec![KeyCode::KEY_1.0], + Keyboard::Key2 => vec![KeyCode::KEY_2.0], + Keyboard::Key3 => vec![KeyCode::KEY_3.0], + Keyboard::Key4 => vec![KeyCode::KEY_4.0], + Keyboard::Key5 => vec![KeyCode::KEY_5.0], + Keyboard::Key6 => vec![KeyCode::KEY_6.0], + Keyboard::Key7 => vec![KeyCode::KEY_7.0], + Keyboard::Key8 => vec![KeyCode::KEY_8.0], + Keyboard::Key9 => vec![KeyCode::KEY_9.0], + Keyboard::Key0 => vec![KeyCode::KEY_0.0], + Keyboard::KeyMinus => vec![KeyCode::KEY_MINUS.0], + Keyboard::KeyEqual => vec![KeyCode::KEY_EQUAL.0], + Keyboard::KeyBackspace => vec![KeyCode::KEY_BACKSPACE.0], + Keyboard::KeyTab => vec![KeyCode::KEY_TAB.0], + Keyboard::KeyQ => vec![KeyCode::KEY_Q.0], + Keyboard::KeyW => vec![KeyCode::KEY_W.0], + Keyboard::KeyE => vec![KeyCode::KEY_E.0], + Keyboard::KeyR => vec![KeyCode::KEY_R.0], + Keyboard::KeyT => vec![KeyCode::KEY_T.0], + Keyboard::KeyY => vec![KeyCode::KEY_Y.0], + Keyboard::KeyU => vec![KeyCode::KEY_U.0], + Keyboard::KeyI => vec![KeyCode::KEY_I.0], + Keyboard::KeyO => vec![KeyCode::KEY_O.0], + Keyboard::KeyP => vec![KeyCode::KEY_P.0], + Keyboard::KeyLeftBrace => vec![KeyCode::KEY_LEFTBRACE.0], + Keyboard::KeyRightBrace => vec![KeyCode::KEY_RIGHTBRACE.0], + Keyboard::KeyEnter => vec![KeyCode::KEY_ENTER.0], + Keyboard::KeyLeftCtrl => vec![KeyCode::KEY_LEFTCTRL.0], + Keyboard::KeyA => vec![KeyCode::KEY_A.0], + Keyboard::KeyS => vec![KeyCode::KEY_S.0], + Keyboard::KeyD => vec![KeyCode::KEY_D.0], + Keyboard::KeyF => vec![KeyCode::KEY_F.0], + Keyboard::KeyG => vec![KeyCode::KEY_G.0], + Keyboard::KeyH => vec![KeyCode::KEY_H.0], + Keyboard::KeyJ => vec![KeyCode::KEY_J.0], + Keyboard::KeyK => vec![KeyCode::KEY_K.0], + Keyboard::KeyL => vec![KeyCode::KEY_L.0], + Keyboard::KeySemicolon => vec![KeyCode::KEY_SEMICOLON.0], + Keyboard::KeyApostrophe => vec![KeyCode::KEY_APOSTROPHE.0], + Keyboard::KeyGrave => vec![KeyCode::KEY_GRAVE.0], + Keyboard::KeyLeftShift => vec![KeyCode::KEY_LEFTSHIFT.0], + Keyboard::KeyBackslash => vec![KeyCode::KEY_BACKSLASH.0], + Keyboard::KeyZ => vec![KeyCode::KEY_Z.0], + Keyboard::KeyX => vec![KeyCode::KEY_X.0], + Keyboard::KeyC => vec![KeyCode::KEY_C.0], + Keyboard::KeyV => vec![KeyCode::KEY_V.0], + Keyboard::KeyB => vec![KeyCode::KEY_B.0], + Keyboard::KeyN => vec![KeyCode::KEY_N.0], + Keyboard::KeyM => vec![KeyCode::KEY_M.0], + Keyboard::KeyComma => vec![KeyCode::KEY_COMMA.0], + Keyboard::KeyDot => vec![KeyCode::KEY_DOT.0], + Keyboard::KeySlash => vec![KeyCode::KEY_SLASH.0], + Keyboard::KeyRightshift => vec![KeyCode::KEY_RIGHTSHIFT.0], + Keyboard::KeyKpasterisk => vec![KeyCode::KEY_KPASTERISK.0], + Keyboard::KeyLeftAlt => vec![KeyCode::KEY_LEFTALT.0], + Keyboard::KeySpace => vec![KeyCode::KEY_SPACE.0], + Keyboard::KeyCapslock => vec![KeyCode::KEY_CAPSLOCK.0], + Keyboard::KeyF1 => vec![KeyCode::KEY_F1.0], + Keyboard::KeyF2 => vec![KeyCode::KEY_F2.0], + Keyboard::KeyF3 => vec![KeyCode::KEY_F3.0], + Keyboard::KeyF4 => vec![KeyCode::KEY_F4.0], + Keyboard::KeyF5 => vec![KeyCode::KEY_F5.0], + Keyboard::KeyF6 => vec![KeyCode::KEY_F6.0], + Keyboard::KeyF7 => vec![KeyCode::KEY_F7.0], + Keyboard::KeyF8 => vec![KeyCode::KEY_F8.0], + Keyboard::KeyF9 => vec![KeyCode::KEY_F9.0], + Keyboard::KeyF10 => vec![KeyCode::KEY_F10.0], + Keyboard::KeyNumlock => vec![KeyCode::KEY_NUMLOCK.0], + Keyboard::KeyScrolllock => vec![KeyCode::KEY_SCROLLLOCK.0], + Keyboard::KeyKp7 => vec![KeyCode::KEY_KP7.0], + Keyboard::KeyKp8 => vec![KeyCode::KEY_KP8.0], + Keyboard::KeyKp9 => vec![KeyCode::KEY_KP9.0], + Keyboard::KeyKpminus => vec![KeyCode::KEY_KPMINUS.0], + Keyboard::KeyKp4 => vec![KeyCode::KEY_KP4.0], + Keyboard::KeyKp5 => vec![KeyCode::KEY_KP5.0], + Keyboard::KeyKp6 => vec![KeyCode::KEY_KP6.0], + Keyboard::KeyKpplus => vec![KeyCode::KEY_KPPLUS.0], + Keyboard::KeyKp1 => vec![KeyCode::KEY_KP1.0], + Keyboard::KeyKp2 => vec![KeyCode::KEY_KP2.0], + Keyboard::KeyKp3 => vec![KeyCode::KEY_KP3.0], + Keyboard::KeyKp0 => vec![KeyCode::KEY_KP0.0], + Keyboard::KeyKpdot => vec![KeyCode::KEY_KPDOT.0], + Keyboard::KeyZenkakuhankaku => vec![KeyCode::KEY_ZENKAKUHANKAKU.0], + Keyboard::Key102nd => vec![KeyCode::KEY_102ND.0], + Keyboard::KeyF11 => vec![KeyCode::KEY_F11.0], + Keyboard::KeyF12 => vec![KeyCode::KEY_F12.0], + Keyboard::KeyRo => vec![KeyCode::KEY_RO.0], + Keyboard::KeyKatakana => vec![KeyCode::KEY_KATAKANA.0], + Keyboard::KeyHiragana => vec![KeyCode::KEY_HIRAGANA.0], + Keyboard::KeyHenkan => vec![KeyCode::KEY_HENKAN.0], + Keyboard::KeyKatakanahiragana => vec![KeyCode::KEY_KATAKANAHIRAGANA.0], + Keyboard::KeyMuhenkan => vec![KeyCode::KEY_MUHENKAN.0], + Keyboard::KeyKpjpcomma => vec![KeyCode::KEY_KPJPCOMMA.0], + Keyboard::KeyKpenter => vec![KeyCode::KEY_KPENTER.0], + Keyboard::KeyRightctrl => vec![KeyCode::KEY_RIGHTCTRL.0], + Keyboard::KeyKpslash => vec![KeyCode::KEY_KPSLASH.0], + Keyboard::KeySysrq => vec![KeyCode::KEY_SYSRQ.0], + Keyboard::KeyRightalt => vec![KeyCode::KEY_RIGHTALT.0], + Keyboard::KeyHome => vec![KeyCode::KEY_HOME.0], + Keyboard::KeyUp => vec![KeyCode::KEY_UP.0], + Keyboard::KeyPageup => vec![KeyCode::KEY_PAGEUP.0], + Keyboard::KeyLeft => vec![KeyCode::KEY_LEFT.0], + Keyboard::KeyRight => vec![KeyCode::KEY_RIGHT.0], + Keyboard::KeyEnd => vec![KeyCode::KEY_END.0], + Keyboard::KeyDown => vec![KeyCode::KEY_DOWN.0], + Keyboard::KeyPagedown => vec![KeyCode::KEY_PAGEDOWN.0], + Keyboard::KeyInsert => vec![KeyCode::KEY_INSERT.0], + Keyboard::KeyDelete => vec![KeyCode::KEY_DELETE.0], + Keyboard::KeyMute => vec![KeyCode::KEY_MUTE.0], + Keyboard::KeyVolumeDown => vec![KeyCode::KEY_VOLUMEDOWN.0], + Keyboard::KeyVolumeUp => vec![KeyCode::KEY_VOLUMEUP.0], + Keyboard::KeyPower => vec![KeyCode::KEY_POWER.0], + Keyboard::KeyKpequal => vec![KeyCode::KEY_KPEQUAL.0], + Keyboard::KeyPause => vec![KeyCode::KEY_PAUSE.0], + Keyboard::KeyKpcomma => vec![KeyCode::KEY_KPCOMMA.0], + Keyboard::KeyHanja => vec![KeyCode::KEY_HANJA.0], + Keyboard::KeyYen => vec![KeyCode::KEY_YEN.0], + Keyboard::KeyLeftmeta => vec![KeyCode::KEY_LEFTMETA.0], + Keyboard::KeyRightmeta => vec![KeyCode::KEY_RIGHTMETA.0], + Keyboard::KeyCompose => vec![KeyCode::KEY_COMPOSE.0], + Keyboard::KeyStop => vec![KeyCode::KEY_STOP.0], + Keyboard::KeyAgain => vec![KeyCode::KEY_AGAIN.0], + Keyboard::KeyProps => vec![KeyCode::KEY_PROPS.0], + Keyboard::KeyUndo => vec![KeyCode::KEY_UNDO.0], + Keyboard::KeyFront => vec![KeyCode::KEY_FRONT.0], + Keyboard::KeyCopy => vec![KeyCode::KEY_COPY.0], + Keyboard::KeyOpen => vec![KeyCode::KEY_OPEN.0], + Keyboard::KeyPaste => vec![KeyCode::KEY_PASTE.0], + Keyboard::KeyFind => vec![KeyCode::KEY_FIND.0], + Keyboard::KeyCut => vec![KeyCode::KEY_CUT.0], + Keyboard::KeyHelp => vec![KeyCode::KEY_HELP.0], + Keyboard::KeyCalc => vec![KeyCode::KEY_CALC.0], + Keyboard::KeySleep => vec![KeyCode::KEY_SLEEP.0], + Keyboard::KeyWww => vec![KeyCode::KEY_WWW.0], + Keyboard::KeyBack => vec![KeyCode::KEY_BACK.0], + Keyboard::KeyForward => vec![KeyCode::KEY_FORWARD.0], + Keyboard::KeyEjectcd => vec![KeyCode::KEY_EJECTCD.0], + Keyboard::KeyNextsong => vec![KeyCode::KEY_NEXTSONG.0], + Keyboard::KeyPlaypause => vec![KeyCode::KEY_PLAYPAUSE.0], + Keyboard::KeyPrevioussong => vec![KeyCode::KEY_PREVIOUSSONG.0], + Keyboard::KeyStopcd => vec![KeyCode::KEY_STOPCD.0], + Keyboard::KeyRefresh => vec![KeyCode::KEY_REFRESH.0], + Keyboard::KeyEdit => vec![KeyCode::KEY_EDIT.0], + Keyboard::KeyScrollUp => vec![KeyCode::KEY_SCROLLUP.0], + Keyboard::KeyScrollDown => vec![KeyCode::KEY_SCROLLDOWN.0], + Keyboard::KeyKpleftparen => vec![KeyCode::KEY_KPLEFTPAREN.0], + Keyboard::KeyKprightparen => vec![KeyCode::KEY_KPRIGHTPAREN.0], + Keyboard::KeyF13 => vec![KeyCode::KEY_F13.0], + Keyboard::KeyF14 => vec![KeyCode::KEY_F14.0], + Keyboard::KeyF15 => vec![KeyCode::KEY_F15.0], + Keyboard::KeyF16 => vec![KeyCode::KEY_F16.0], + Keyboard::KeyF17 => vec![KeyCode::KEY_F17.0], + Keyboard::KeyF18 => vec![KeyCode::KEY_F18.0], + Keyboard::KeyF19 => vec![KeyCode::KEY_F19.0], + Keyboard::KeyF20 => vec![KeyCode::KEY_F20.0], + Keyboard::KeyF21 => vec![KeyCode::KEY_F21.0], + Keyboard::KeyF22 => vec![KeyCode::KEY_F22.0], + Keyboard::KeyF23 => vec![KeyCode::KEY_F23.0], + Keyboard::KeyF24 => vec![KeyCode::KEY_F24.0], + }, } } @@ -465,9 +629,7 @@ fn normalize_unsigned_value(raw_value: i32, max: i32) -> f64 { /// De-normalizes the given value from -1.0 - 1.0 into a real value based on the /// minimum and maximum axis range from the given [AbsInfo]. fn denormalize_optional_signed_value(normal_value: Option, axis_info: AbsInfo) -> Option { - if normal_value.is_none() { - return None; - } + normal_value?; let normal_value = normal_value.unwrap(); Some(denormalize_signed_value(normal_value, axis_info)) } diff --git a/src/input/target/keyboard.rs b/src/input/target/keyboard.rs index e019900b..d5f59445 100644 --- a/src/input/target/keyboard.rs +++ b/src/input/target/keyboard.rs @@ -10,8 +10,12 @@ use zbus::{fdo, Connection}; use zbus_macros::dbus_interface; use crate::input::{ + capability::{Capability, Keyboard}, composite_device, - event::{evdev::EvdevEvent, native::NativeEvent}, + event::{ + evdev::EvdevEvent, + native::{InputValue, NativeEvent}, + }, }; use super::TargetCommand; @@ -21,11 +25,13 @@ const BUFFER_SIZE: usize = 2048; /// The [DBusInterface] provides a DBus interface that can be exposed for managing /// a [KeyboardDevice]. It works by sending command messages to a channel that the /// [KeyboardDevice] is listening on. -pub struct DBusInterface {} +pub struct DBusInterface { + command_tx: mpsc::Sender, +} impl DBusInterface { - fn new() -> DBusInterface { - DBusInterface {} + fn new(command_tx: mpsc::Sender) -> DBusInterface { + DBusInterface { command_tx } } } @@ -36,6 +42,25 @@ impl DBusInterface { async fn name(&self) -> fdo::Result { Ok("Keyboard".into()) } + + /// Send the given key to the virtual keyboard + async fn send_key(&self, key: String, value: bool) -> fdo::Result<()> { + // Create a NativeEvent to send to the keyboard + let capability = capability_from_key_string(key.as_str()); + if matches!(capability, Capability::NotImplemented) { + return Err(fdo::Error::NotSupported("Invalid key code".into())); + } + let value = InputValue::Bool(value); + let event = NativeEvent::new(capability, value); + + // Write the event to the virtual device + self.command_tx + .send(TargetCommand::WriteEvent(event)) + .await + .map_err(|err| fdo::Error::Failed(err.to_string()))?; + + Ok(()) + } } #[derive(Debug)] @@ -73,8 +98,9 @@ impl KeyboardDevice { pub async fn listen_on_dbus(&mut self, path: String) -> Result<(), Box> { let conn = self.conn.clone(); self.dbus_path = Some(path.clone()); + let tx = self.tx.clone(); tokio::spawn(async move { - let iface = DBusInterface::new(); + let iface = DBusInterface::new(tx); if let Err(e) = conn.object_server().at(path, iface).await { log::error!("Failed to setup DBus interface for device: {:?}", e); } @@ -296,7 +322,7 @@ impl KeyboardDevice { keys.insert(KeyCode::KEY_F23); keys.insert(KeyCode::KEY_F24); - let mut device = VirtualDeviceBuilder::new()? + let device = VirtualDeviceBuilder::new()? .name("InputPlumber Keyboard") .with_keys(&keys)? .build()?; @@ -304,3 +330,170 @@ impl KeyboardDevice { Ok(device) } } + +/// Returns an input device capability from the given key string. +fn capability_from_key_string(key: &str) -> Capability { + match key { + "KEY_ESC" => Capability::Keyboard(Keyboard::KeyEsc), + "KEY_1" => Capability::Keyboard(Keyboard::Key1), + "KEY_2" => Capability::Keyboard(Keyboard::Key2), + "KEY_3" => Capability::Keyboard(Keyboard::Key3), + "KEY_4" => Capability::Keyboard(Keyboard::Key4), + "KEY_5" => Capability::Keyboard(Keyboard::Key5), + "KEY_6" => Capability::Keyboard(Keyboard::Key6), + "KEY_7" => Capability::Keyboard(Keyboard::Key7), + "KEY_8" => Capability::Keyboard(Keyboard::Key8), + "KEY_9" => Capability::Keyboard(Keyboard::Key9), + "KEY_0" => Capability::Keyboard(Keyboard::Key0), + "KEY_MINUS" => Capability::Keyboard(Keyboard::KeyMinus), + "KEY_EQUAL" => Capability::Keyboard(Keyboard::KeyEqual), + "KEY_BACKSPACE" => Capability::Keyboard(Keyboard::KeyBackspace), + "KEY_TAB" => Capability::Keyboard(Keyboard::KeyTab), + "KEY_Q" => Capability::Keyboard(Keyboard::KeyQ), + "KEY_W" => Capability::Keyboard(Keyboard::KeyW), + "KEY_E" => Capability::Keyboard(Keyboard::KeyE), + "KEY_R" => Capability::Keyboard(Keyboard::KeyR), + "KEY_T" => Capability::Keyboard(Keyboard::KeyT), + "KEY_Y" => Capability::Keyboard(Keyboard::KeyY), + "KEY_U" => Capability::Keyboard(Keyboard::KeyU), + "KEY_I" => Capability::Keyboard(Keyboard::KeyI), + "KEY_O" => Capability::Keyboard(Keyboard::KeyO), + "KEY_P" => Capability::Keyboard(Keyboard::KeyP), + "KEY_LEFTBRACE" => Capability::Keyboard(Keyboard::KeyLeftBrace), + "KEY_RIGHTBRACE" => Capability::Keyboard(Keyboard::KeyRightBrace), + "KEY_ENTER" => Capability::Keyboard(Keyboard::KeyEnter), + "KEY_LEFTCTRL" => Capability::Keyboard(Keyboard::KeyLeftCtrl), + "KEY_A" => Capability::Keyboard(Keyboard::KeyA), + "KEY_S" => Capability::Keyboard(Keyboard::KeyS), + "KEY_D" => Capability::Keyboard(Keyboard::KeyD), + "KEY_F" => Capability::Keyboard(Keyboard::KeyF), + "KEY_G" => Capability::Keyboard(Keyboard::KeyG), + "KEY_H" => Capability::Keyboard(Keyboard::KeyH), + "KEY_J" => Capability::Keyboard(Keyboard::KeyJ), + "KEY_K" => Capability::Keyboard(Keyboard::KeyK), + "KEY_L" => Capability::Keyboard(Keyboard::KeyL), + "KEY_SEMICOLON" => Capability::Keyboard(Keyboard::KeySemicolon), + "KEY_APOSTROPHE" => Capability::Keyboard(Keyboard::KeyApostrophe), + "KEY_GRAVE" => Capability::Keyboard(Keyboard::KeyGrave), + "KEY_LEFTSHIFT" => Capability::Keyboard(Keyboard::KeyLeftShift), + "KEY_BACKSLASH" => Capability::Keyboard(Keyboard::KeyBackslash), + "KEY_Z" => Capability::Keyboard(Keyboard::KeyZ), + "KEY_X" => Capability::Keyboard(Keyboard::KeyX), + "KEY_C" => Capability::Keyboard(Keyboard::KeyC), + "KEY_V" => Capability::Keyboard(Keyboard::KeyV), + "KEY_B" => Capability::Keyboard(Keyboard::KeyB), + "KEY_N" => Capability::Keyboard(Keyboard::KeyN), + "KEY_M" => Capability::Keyboard(Keyboard::KeyM), + "KEY_COMMA" => Capability::Keyboard(Keyboard::KeyComma), + "KEY_DOT" => Capability::Keyboard(Keyboard::KeyDot), + "KEY_SLASH" => Capability::Keyboard(Keyboard::KeySlash), + "KEY_RIGHTSHIFT" => Capability::Keyboard(Keyboard::KeyRightshift), + "KEY_KPASTERISK" => Capability::Keyboard(Keyboard::KeyKpasterisk), + "KEY_LEFTALT" => Capability::Keyboard(Keyboard::KeyLeftAlt), + "KEY_SPACE" => Capability::Keyboard(Keyboard::KeySpace), + "KEY_CAPSLOCK" => Capability::Keyboard(Keyboard::KeyCapslock), + "KEY_F1" => Capability::Keyboard(Keyboard::KeyF1), + "KEY_F2" => Capability::Keyboard(Keyboard::KeyF2), + "KEY_F3" => Capability::Keyboard(Keyboard::KeyF3), + "KEY_F4" => Capability::Keyboard(Keyboard::KeyF4), + "KEY_F5" => Capability::Keyboard(Keyboard::KeyF5), + "KEY_F6" => Capability::Keyboard(Keyboard::KeyF6), + "KEY_F7" => Capability::Keyboard(Keyboard::KeyF7), + "KEY_F8" => Capability::Keyboard(Keyboard::KeyF8), + "KEY_F9" => Capability::Keyboard(Keyboard::KeyF9), + "KEY_F10" => Capability::Keyboard(Keyboard::KeyF10), + "KEY_NUMLOCK" => Capability::Keyboard(Keyboard::KeyNumlock), + "KEY_SCROLLLOCK" => Capability::Keyboard(Keyboard::KeyScrolllock), + "KEY_KP7" => Capability::Keyboard(Keyboard::KeyKp7), + "KEY_KP8" => Capability::Keyboard(Keyboard::KeyKp8), + "KEY_KP9" => Capability::Keyboard(Keyboard::KeyKp9), + "KEY_KPMINUS" => Capability::Keyboard(Keyboard::KeyKpminus), + "KEY_KP4" => Capability::Keyboard(Keyboard::KeyKp4), + "KEY_KP5" => Capability::Keyboard(Keyboard::KeyKp5), + "KEY_KP6" => Capability::Keyboard(Keyboard::KeyKp6), + "KEY_KPPLUS" => Capability::Keyboard(Keyboard::KeyKpplus), + "KEY_KP1" => Capability::Keyboard(Keyboard::KeyKp1), + "KEY_KP2" => Capability::Keyboard(Keyboard::KeyKp2), + "KEY_KP3" => Capability::Keyboard(Keyboard::KeyKp3), + "KEY_KP0" => Capability::Keyboard(Keyboard::KeyKp0), + "KEY_KPDOT" => Capability::Keyboard(Keyboard::KeyKpdot), + "KEY_ZENKAKUHANKAKU" => Capability::Keyboard(Keyboard::KeyZenkakuhankaku), + "KEY_102ND" => Capability::Keyboard(Keyboard::Key102nd), + "KEY_F11" => Capability::Keyboard(Keyboard::KeyF11), + "KEY_F12" => Capability::Keyboard(Keyboard::KeyF12), + "KEY_RO" => Capability::Keyboard(Keyboard::KeyRo), + "KEY_KATAKANA" => Capability::Keyboard(Keyboard::KeyKatakana), + "KEY_HIRAGANA" => Capability::Keyboard(Keyboard::KeyHiragana), + "KEY_HENKAN" => Capability::Keyboard(Keyboard::KeyHenkan), + "KEY_KATAKANAHIRAGANA" => Capability::Keyboard(Keyboard::KeyKatakanahiragana), + "KEY_MUHENKAN" => Capability::Keyboard(Keyboard::KeyMuhenkan), + "KEY_KPJPCOMMA" => Capability::Keyboard(Keyboard::KeyKpjpcomma), + "KEY_KPENTER" => Capability::Keyboard(Keyboard::KeyKpenter), + "KEY_RIGHTCTRL" => Capability::Keyboard(Keyboard::KeyRightctrl), + "KEY_KPSLASH" => Capability::Keyboard(Keyboard::KeyKpslash), + "KEY_SYSRQ" => Capability::Keyboard(Keyboard::KeySysrq), + "KEY_RIGHTALT" => Capability::Keyboard(Keyboard::KeyRightalt), + "KEY_HOME" => Capability::Keyboard(Keyboard::KeyHome), + "KEY_UP" => Capability::Keyboard(Keyboard::KeyUp), + "KEY_PAGEUP" => Capability::Keyboard(Keyboard::KeyPageup), + "KEY_LEFT" => Capability::Keyboard(Keyboard::KeyLeft), + "KEY_RIGHT" => Capability::Keyboard(Keyboard::KeyRight), + "KEY_END" => Capability::Keyboard(Keyboard::KeyEnd), + "KEY_DOWN" => Capability::Keyboard(Keyboard::KeyDown), + "KEY_PAGEDOWN" => Capability::Keyboard(Keyboard::KeyPagedown), + "KEY_INSERT" => Capability::Keyboard(Keyboard::KeyInsert), + "KEY_DELETE" => Capability::Keyboard(Keyboard::KeyDelete), + "KEY_MUTE" => Capability::Keyboard(Keyboard::KeyMute), + "KEY_VOLUMEDOWN" => Capability::Keyboard(Keyboard::KeyVolumeDown), + "KEY_VOLUMEUP" => Capability::Keyboard(Keyboard::KeyVolumeUp), + "KEY_POWER" => Capability::Keyboard(Keyboard::KeyPower), + "KEY_KPEQUAL" => Capability::Keyboard(Keyboard::KeyKpequal), + "KEY_PAUSE" => Capability::Keyboard(Keyboard::KeyPause), + "KEY_KPCOMMA" => Capability::Keyboard(Keyboard::KeyKpcomma), + "KEY_HANJA" => Capability::Keyboard(Keyboard::KeyHanja), + "KEY_YEN" => Capability::Keyboard(Keyboard::KeyYen), + "KEY_LEFTMETA" => Capability::Keyboard(Keyboard::KeyLeftmeta), + "KEY_RIGHTMETA" => Capability::Keyboard(Keyboard::KeyRightmeta), + "KEY_COMPOSE" => Capability::Keyboard(Keyboard::KeyCompose), + "KEY_STOP" => Capability::Keyboard(Keyboard::KeyStop), + "KEY_AGAIN" => Capability::Keyboard(Keyboard::KeyAgain), + "KEY_PROPS" => Capability::Keyboard(Keyboard::KeyProps), + "KEY_UNDO" => Capability::Keyboard(Keyboard::KeyUndo), + "KEY_FRONT" => Capability::Keyboard(Keyboard::KeyFront), + "KEY_COPY" => Capability::Keyboard(Keyboard::KeyCopy), + "KEY_OPEN" => Capability::Keyboard(Keyboard::KeyOpen), + "KEY_PASTE" => Capability::Keyboard(Keyboard::KeyPaste), + "KEY_FIND" => Capability::Keyboard(Keyboard::KeyFind), + "KEY_CUT" => Capability::Keyboard(Keyboard::KeyCut), + "KEY_HELP" => Capability::Keyboard(Keyboard::KeyHelp), + "KEY_CALC" => Capability::Keyboard(Keyboard::KeyCalc), + "KEY_SLEEP" => Capability::Keyboard(Keyboard::KeySleep), + "KEY_WWW" => Capability::Keyboard(Keyboard::KeyWww), + "KEY_BACK" => Capability::Keyboard(Keyboard::KeyBack), + "KEY_FORWARD" => Capability::Keyboard(Keyboard::KeyForward), + "KEY_EJECTCD" => Capability::Keyboard(Keyboard::KeyEjectcd), + "KEY_NEXTSONG" => Capability::Keyboard(Keyboard::KeyNextsong), + "KEY_PLAYPAUSE" => Capability::Keyboard(Keyboard::KeyPlaypause), + "KEY_PREVIOUSSONG" => Capability::Keyboard(Keyboard::KeyPrevioussong), + "KEY_STOPCD" => Capability::Keyboard(Keyboard::KeyStopcd), + "KEY_REFRESH" => Capability::Keyboard(Keyboard::KeyRefresh), + "KEY_EDIT" => Capability::Keyboard(Keyboard::KeyEdit), + "KEY_SCROLLUP" => Capability::Keyboard(Keyboard::KeyScrollUp), + "KEY_SCROLLDOWN" => Capability::Keyboard(Keyboard::KeyScrollDown), + "KEY_KPLEFTPAREN" => Capability::Keyboard(Keyboard::KeyKpleftparen), + "KEY_KPRIGHTPAREN" => Capability::Keyboard(Keyboard::KeyKprightparen), + "KEY_F13" => Capability::Keyboard(Keyboard::KeyF13), + "KEY_F14" => Capability::Keyboard(Keyboard::KeyF14), + "KEY_F15" => Capability::Keyboard(Keyboard::KeyF15), + "KEY_F16" => Capability::Keyboard(Keyboard::KeyF16), + "KEY_F17" => Capability::Keyboard(Keyboard::KeyF17), + "KEY_F18" => Capability::Keyboard(Keyboard::KeyF18), + "KEY_F19" => Capability::Keyboard(Keyboard::KeyF19), + "KEY_F20" => Capability::Keyboard(Keyboard::KeyF20), + "KEY_F21" => Capability::Keyboard(Keyboard::KeyF21), + "KEY_F22" => Capability::Keyboard(Keyboard::KeyF22), + "KEY_F23" => Capability::Keyboard(Keyboard::KeyF23), + "KEY_F24" => Capability::Keyboard(Keyboard::KeyF24), + _ => Capability::NotImplemented, + } +}