feat: sticky keys with timeout

This commit is contained in:
Himadri Bhattacharjee
2026-01-10 08:55:23 +05:30
parent 2de7020ce8
commit 9dd801189d
3 changed files with 879 additions and 27 deletions

199
Cargo.lock generated
View File

@@ -41,7 +41,8 @@ dependencies = [
"bitvec",
"cfg-if",
"libc",
"nix",
"nix 0.29.0",
"tokio",
]
[[package]]
@@ -55,6 +56,8 @@ name = "kwargs"
version = "0.1.0"
dependencies = [
"evdev",
"nix 0.30.1",
"tokio",
]
[[package]]
@@ -63,6 +66,17 @@ version = "0.2.180"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
[[package]]
name = "mio"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
dependencies = [
"libc",
"wasi",
"windows-sys 0.61.2",
]
[[package]]
name = "nix"
version = "0.29.0"
@@ -75,18 +89,201 @@ dependencies = [
"libc",
]
[[package]]
name = "nix"
version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
dependencies = [
"bitflags",
"cfg-if",
"cfg_aliases",
"libc",
]
[[package]]
name = "pin-project-lite"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "proc-macro2"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
dependencies = [
"proc-macro2",
]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "socket2"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
dependencies = [
"libc",
"windows-sys 0.60.2",
]
[[package]]
name = "syn"
version = "2.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "tokio"
version = "1.49.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
dependencies = [
"libc",
"mio",
"pin-project-lite",
"socket2",
"tokio-macros",
"windows-sys 0.61.2",
]
[[package]]
name = "tokio-macros"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "wyz"
version = "0.5.1"

View File

@@ -4,4 +4,9 @@ version = "0.1.0"
edition = "2024"
[dependencies]
evdev = "0.13.2"
evdev = { version = "0.13.2", features = ["tokio"] }
nix = { version = "0.30.1", features = ["event", "ioctl"] }
[dependencies.tokio]
features = ["macros", "rt-multi-thread", "time"]
version = "1.17"

View File

@@ -1,17 +1,110 @@
use evdev::uinput::VirtualDevice;
use evdev::{AttributeSet, EventType, InputEvent, KeyCode, KeyEvent};
use std::thread::sleep;
use std::time::Duration;
use evdev::{Device, InputEvent, KeyEvent};
use std::collections::BTreeMap;
use std::fmt::Debug;
use std::time::{Duration, SystemTime};
use evdev::uinput::VirtualDevice;
use evdev::{AttributeSet, KeyCode};
#[derive(Clone, Copy)]
pub enum KeyState {
Latched(),
Latched(SystemTime),
Locked,
None,
}
fn main() -> std::io::Result<()> {
let mut keys = AttributeSet::<KeyCode>::default();
keys.insert(KeyCode::KEY_A);
impl Debug for KeyState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Latched(arg0) => write!(
f,
"Latched {}s",
arg0.elapsed().unwrap_or_default().as_secs()
),
Self::Locked => write!(f, "Locked"),
Self::None => write!(f, "None"),
}
}
}
impl KeyState {
fn morph(&self, time: SystemTime) -> KeyState {
match self {
KeyState::Latched(last_press) => {
if time.duration_since(*last_press).unwrap() < Duration::from_millis(500) {
KeyState::Locked
} else {
KeyState::None
}
}
KeyState::Locked => KeyState::None,
KeyState::None => KeyState::Latched(time),
}
}
}
#[derive(Debug)]
pub struct InternalState {
map: BTreeMap<KeyCode, KeyState>,
}
impl InternalState {
fn morph(
&mut self,
key: KeyCode,
pressed: i32,
timestamp: SystemTime,
) -> Option<Vec<InputEvent>> {
if let Some(v) = self.map.get(&key) {
if pressed == 0 {
return None;
}
let morphed = v.morph(timestamp);
self.map.insert(key, morphed);
return match morphed {
KeyState::None => Some(vec![*KeyEvent::new(key, 0)]),
KeyState::Latched(_) => Some(vec![*KeyEvent::new(key, 1)]),
_ => None,
};
};
let mut events = vec![*KeyEvent::new(key, pressed)];
let mut empty = Vec::new();
for key in self.map.keys() {
if let Some(KeyState::Latched(_)) = self.map.get(key) {
events.push(*KeyEvent::new(*key, 0));
empty.push(*key);
}
}
for key in empty {
self.map.insert(key, KeyState::None);
}
Some(events)
}
}
fn pick_device() -> Option<Device> {
evdev::enumerate()
.map(|(_, device)| device)
.filter(|d| d.name().is_some_and(|name| name.contains("keyboard")))
.next()
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let Some(mut d) = pick_device() else {
return Ok(());
};
while !d.is_grabbed() {
println!("trying to grab");
let _ = d.grab();
}
println!("{}", d.name().unwrap_or("some keyboard ig"));
let mut events = d.into_event_stream()?;
let keys: AttributeSet<KeyCode> = get_all_keys().into_iter().collect();
let mut device = VirtualDevice::builder()?
.name("lollipop")
@@ -23,24 +116,581 @@ fn main() -> std::io::Result<()> {
println!("Available as {}", path.display());
}
sleep(Duration::from_secs(2));
let mut state = InternalState {
map: BTreeMap::default(),
};
let code = KeyCode::KEY_A.code();
loop {
// this guarantees a key event
let down_event = *KeyEvent::new(KeyCode(code), 1);
device.emit(&[down_event]).unwrap();
println!("Pressed.");
sleep(Duration::from_secs(2));
// alternativeley we can create a InputEvent, which will be any variant of InputEvent
// depending on the type_ value
let up_event = InputEvent::new(EventType::KEY.0, code, 0);
device.emit(&[up_event]).unwrap();
println!("Released.");
sleep(Duration::from_secs(2));
for key in [
KeyCode::KEY_LEFTSHIFT,
KeyCode::KEY_LEFTMETA,
KeyCode::KEY_LEFTCTRL,
KeyCode::KEY_LEFTALT,
] {
state.map.insert(key, KeyState::None);
}
Ok(())
loop {
match events.next_event().await?.destructure() {
evdev::EventSummary::Key(key_event, key_code, pressed) => {
if let Some(events) = state.morph(key_code, pressed, key_event.timestamp()) {
println!("{state:#?}");
device.emit(&events)?;
};
}
_ => {}
}
}
}
pub fn get_all_keys() -> &'static [KeyCode] {
&[
evdev::KeyCode::KEY_RESERVED,
evdev::KeyCode::KEY_ESC,
evdev::KeyCode::KEY_1,
evdev::KeyCode::KEY_2,
evdev::KeyCode::KEY_3,
evdev::KeyCode::KEY_4,
evdev::KeyCode::KEY_5,
evdev::KeyCode::KEY_6,
evdev::KeyCode::KEY_7,
evdev::KeyCode::KEY_8,
evdev::KeyCode::KEY_9,
evdev::KeyCode::KEY_0,
evdev::KeyCode::KEY_MINUS,
evdev::KeyCode::KEY_EQUAL,
evdev::KeyCode::KEY_BACKSPACE,
evdev::KeyCode::KEY_TAB,
evdev::KeyCode::KEY_Q,
evdev::KeyCode::KEY_W,
evdev::KeyCode::KEY_E,
evdev::KeyCode::KEY_R,
evdev::KeyCode::KEY_T,
evdev::KeyCode::KEY_Y,
evdev::KeyCode::KEY_U,
evdev::KeyCode::KEY_I,
evdev::KeyCode::KEY_O,
evdev::KeyCode::KEY_P,
evdev::KeyCode::KEY_LEFTBRACE,
evdev::KeyCode::KEY_RIGHTBRACE,
evdev::KeyCode::KEY_ENTER,
evdev::KeyCode::KEY_LEFTCTRL,
evdev::KeyCode::KEY_A,
evdev::KeyCode::KEY_S,
evdev::KeyCode::KEY_D,
evdev::KeyCode::KEY_F,
evdev::KeyCode::KEY_G,
evdev::KeyCode::KEY_H,
evdev::KeyCode::KEY_J,
evdev::KeyCode::KEY_K,
evdev::KeyCode::KEY_L,
evdev::KeyCode::KEY_SEMICOLON,
evdev::KeyCode::KEY_APOSTROPHE,
evdev::KeyCode::KEY_GRAVE,
evdev::KeyCode::KEY_LEFTSHIFT,
evdev::KeyCode::KEY_BACKSLASH,
evdev::KeyCode::KEY_Z,
evdev::KeyCode::KEY_X,
evdev::KeyCode::KEY_C,
evdev::KeyCode::KEY_V,
evdev::KeyCode::KEY_B,
evdev::KeyCode::KEY_N,
evdev::KeyCode::KEY_M,
evdev::KeyCode::KEY_COMMA,
evdev::KeyCode::KEY_DOT,
evdev::KeyCode::KEY_SLASH,
evdev::KeyCode::KEY_RIGHTSHIFT,
evdev::KeyCode::KEY_KPASTERISK,
evdev::KeyCode::KEY_LEFTALT,
evdev::KeyCode::KEY_SPACE,
evdev::KeyCode::KEY_CAPSLOCK,
evdev::KeyCode::KEY_F1,
evdev::KeyCode::KEY_F2,
evdev::KeyCode::KEY_F3,
evdev::KeyCode::KEY_F4,
evdev::KeyCode::KEY_F5,
evdev::KeyCode::KEY_F6,
evdev::KeyCode::KEY_F7,
evdev::KeyCode::KEY_F8,
evdev::KeyCode::KEY_F9,
evdev::KeyCode::KEY_F10,
evdev::KeyCode::KEY_NUMLOCK,
evdev::KeyCode::KEY_SCROLLLOCK,
evdev::KeyCode::KEY_KP7,
evdev::KeyCode::KEY_KP8,
evdev::KeyCode::KEY_KP9,
evdev::KeyCode::KEY_KPMINUS,
evdev::KeyCode::KEY_KP4,
evdev::KeyCode::KEY_KP5,
evdev::KeyCode::KEY_KP6,
evdev::KeyCode::KEY_KPPLUS,
evdev::KeyCode::KEY_KP1,
evdev::KeyCode::KEY_KP2,
evdev::KeyCode::KEY_KP3,
evdev::KeyCode::KEY_KP0,
evdev::KeyCode::KEY_KPDOT,
evdev::KeyCode::KEY_ZENKAKUHANKAKU,
evdev::KeyCode::KEY_102ND,
evdev::KeyCode::KEY_F11,
evdev::KeyCode::KEY_F12,
evdev::KeyCode::KEY_RO,
evdev::KeyCode::KEY_KATAKANA,
evdev::KeyCode::KEY_HIRAGANA,
evdev::KeyCode::KEY_HENKAN,
evdev::KeyCode::KEY_KATAKANAHIRAGANA,
evdev::KeyCode::KEY_MUHENKAN,
evdev::KeyCode::KEY_KPJPCOMMA,
evdev::KeyCode::KEY_KPENTER,
evdev::KeyCode::KEY_RIGHTCTRL,
evdev::KeyCode::KEY_KPSLASH,
evdev::KeyCode::KEY_SYSRQ,
evdev::KeyCode::KEY_RIGHTALT,
evdev::KeyCode::KEY_LINEFEED,
evdev::KeyCode::KEY_HOME,
evdev::KeyCode::KEY_UP,
evdev::KeyCode::KEY_PAGEUP,
evdev::KeyCode::KEY_LEFT,
evdev::KeyCode::KEY_RIGHT,
evdev::KeyCode::KEY_END,
evdev::KeyCode::KEY_DOWN,
evdev::KeyCode::KEY_PAGEDOWN,
evdev::KeyCode::KEY_INSERT,
evdev::KeyCode::KEY_DELETE,
evdev::KeyCode::KEY_MACRO,
evdev::KeyCode::KEY_MUTE,
evdev::KeyCode::KEY_VOLUMEDOWN,
evdev::KeyCode::KEY_VOLUMEUP,
evdev::KeyCode::KEY_POWER,
evdev::KeyCode::KEY_KPEQUAL,
evdev::KeyCode::KEY_KPPLUSMINUS,
evdev::KeyCode::KEY_PAUSE,
evdev::KeyCode::KEY_SCALE,
evdev::KeyCode::KEY_KPCOMMA,
evdev::KeyCode::KEY_HANGEUL,
evdev::KeyCode::KEY_HANJA,
evdev::KeyCode::KEY_YEN,
evdev::KeyCode::KEY_LEFTMETA,
evdev::KeyCode::KEY_RIGHTMETA,
evdev::KeyCode::KEY_COMPOSE,
evdev::KeyCode::KEY_STOP,
evdev::KeyCode::KEY_AGAIN,
evdev::KeyCode::KEY_PROPS,
evdev::KeyCode::KEY_UNDO,
evdev::KeyCode::KEY_FRONT,
evdev::KeyCode::KEY_COPY,
evdev::KeyCode::KEY_OPEN,
evdev::KeyCode::KEY_PASTE,
evdev::KeyCode::KEY_FIND,
evdev::KeyCode::KEY_CUT,
evdev::KeyCode::KEY_HELP,
evdev::KeyCode::KEY_MENU,
evdev::KeyCode::KEY_CALC,
evdev::KeyCode::KEY_SETUP,
evdev::KeyCode::KEY_SLEEP,
evdev::KeyCode::KEY_WAKEUP,
evdev::KeyCode::KEY_FILE,
evdev::KeyCode::KEY_SENDFILE,
evdev::KeyCode::KEY_DELETEFILE,
evdev::KeyCode::KEY_XFER,
evdev::KeyCode::KEY_PROG1,
evdev::KeyCode::KEY_PROG2,
evdev::KeyCode::KEY_WWW,
evdev::KeyCode::KEY_MSDOS,
evdev::KeyCode::KEY_COFFEE,
evdev::KeyCode::KEY_DIRECTION,
evdev::KeyCode::KEY_ROTATE_DISPLAY,
evdev::KeyCode::KEY_CYCLEWINDOWS,
evdev::KeyCode::KEY_MAIL,
evdev::KeyCode::KEY_BOOKMARKS,
evdev::KeyCode::KEY_COMPUTER,
evdev::KeyCode::KEY_BACK,
evdev::KeyCode::KEY_FORWARD,
evdev::KeyCode::KEY_CLOSECD,
evdev::KeyCode::KEY_EJECTCD,
evdev::KeyCode::KEY_EJECTCLOSECD,
evdev::KeyCode::KEY_NEXTSONG,
evdev::KeyCode::KEY_PLAYPAUSE,
evdev::KeyCode::KEY_PREVIOUSSONG,
evdev::KeyCode::KEY_STOPCD,
evdev::KeyCode::KEY_RECORD,
evdev::KeyCode::KEY_REWIND,
evdev::KeyCode::KEY_PHONE,
evdev::KeyCode::KEY_ISO,
evdev::KeyCode::KEY_CONFIG,
evdev::KeyCode::KEY_HOMEPAGE,
evdev::KeyCode::KEY_REFRESH,
evdev::KeyCode::KEY_EXIT,
evdev::KeyCode::KEY_MOVE,
evdev::KeyCode::KEY_EDIT,
evdev::KeyCode::KEY_SCROLLUP,
evdev::KeyCode::KEY_SCROLLDOWN,
evdev::KeyCode::KEY_KPLEFTPAREN,
evdev::KeyCode::KEY_KPRIGHTPAREN,
evdev::KeyCode::KEY_NEW,
evdev::KeyCode::KEY_REDO,
evdev::KeyCode::KEY_F13,
evdev::KeyCode::KEY_F14,
evdev::KeyCode::KEY_F15,
evdev::KeyCode::KEY_F16,
evdev::KeyCode::KEY_F17,
evdev::KeyCode::KEY_F18,
evdev::KeyCode::KEY_F19,
evdev::KeyCode::KEY_F20,
evdev::KeyCode::KEY_F21,
evdev::KeyCode::KEY_F22,
evdev::KeyCode::KEY_F23,
evdev::KeyCode::KEY_F24,
evdev::KeyCode::KEY_PLAYCD,
evdev::KeyCode::KEY_PAUSECD,
evdev::KeyCode::KEY_PROG3,
evdev::KeyCode::KEY_PROG4,
evdev::KeyCode::KEY_DASHBOARD,
evdev::KeyCode::KEY_SUSPEND,
evdev::KeyCode::KEY_CLOSE,
evdev::KeyCode::KEY_PLAY,
evdev::KeyCode::KEY_FASTFORWARD,
evdev::KeyCode::KEY_BASSBOOST,
evdev::KeyCode::KEY_PRINT,
evdev::KeyCode::KEY_HP,
evdev::KeyCode::KEY_CAMERA,
evdev::KeyCode::KEY_SOUND,
evdev::KeyCode::KEY_QUESTION,
evdev::KeyCode::KEY_EMAIL,
evdev::KeyCode::KEY_CHAT,
evdev::KeyCode::KEY_SEARCH,
evdev::KeyCode::KEY_CONNECT,
evdev::KeyCode::KEY_FINANCE,
evdev::KeyCode::KEY_SPORT,
evdev::KeyCode::KEY_SHOP,
evdev::KeyCode::KEY_ALTERASE,
evdev::KeyCode::KEY_CANCEL,
evdev::KeyCode::KEY_BRIGHTNESSDOWN,
evdev::KeyCode::KEY_BRIGHTNESSUP,
evdev::KeyCode::KEY_MEDIA,
evdev::KeyCode::KEY_SWITCHVIDEOMODE,
evdev::KeyCode::KEY_KBDILLUMTOGGLE,
evdev::KeyCode::KEY_KBDILLUMDOWN,
evdev::KeyCode::KEY_KBDILLUMUP,
evdev::KeyCode::KEY_SEND,
evdev::KeyCode::KEY_REPLY,
evdev::KeyCode::KEY_FORWARDMAIL,
evdev::KeyCode::KEY_SAVE,
evdev::KeyCode::KEY_DOCUMENTS,
evdev::KeyCode::KEY_BATTERY,
evdev::KeyCode::KEY_BLUETOOTH,
evdev::KeyCode::KEY_WLAN,
evdev::KeyCode::KEY_UWB,
evdev::KeyCode::KEY_UNKNOWN,
evdev::KeyCode::KEY_VIDEO_NEXT,
evdev::KeyCode::KEY_VIDEO_PREV,
evdev::KeyCode::KEY_BRIGHTNESS_CYCLE,
evdev::KeyCode::KEY_BRIGHTNESS_AUTO,
evdev::KeyCode::KEY_DISPLAY_OFF,
evdev::KeyCode::KEY_WWAN,
evdev::KeyCode::KEY_RFKILL,
evdev::KeyCode::KEY_MICMUTE,
evdev::KeyCode::BTN_0,
evdev::KeyCode::BTN_1,
evdev::KeyCode::BTN_2,
evdev::KeyCode::BTN_3,
evdev::KeyCode::BTN_4,
evdev::KeyCode::BTN_5,
evdev::KeyCode::BTN_6,
evdev::KeyCode::BTN_7,
evdev::KeyCode::BTN_8,
evdev::KeyCode::BTN_9,
evdev::KeyCode::BTN_LEFT,
evdev::KeyCode::BTN_RIGHT,
evdev::KeyCode::BTN_MIDDLE,
evdev::KeyCode::BTN_SIDE,
evdev::KeyCode::BTN_EXTRA,
evdev::KeyCode::BTN_FORWARD,
evdev::KeyCode::BTN_BACK,
evdev::KeyCode::BTN_TASK,
evdev::KeyCode::BTN_TRIGGER,
evdev::KeyCode::BTN_THUMB,
evdev::KeyCode::BTN_THUMB2,
evdev::KeyCode::BTN_TOP,
evdev::KeyCode::BTN_TOP2,
evdev::KeyCode::BTN_PINKIE,
evdev::KeyCode::BTN_BASE,
evdev::KeyCode::BTN_BASE2,
evdev::KeyCode::BTN_BASE3,
evdev::KeyCode::BTN_BASE4,
evdev::KeyCode::BTN_BASE5,
evdev::KeyCode::BTN_BASE6,
evdev::KeyCode::BTN_DEAD,
evdev::KeyCode::BTN_SOUTH,
evdev::KeyCode::BTN_EAST,
evdev::KeyCode::BTN_C,
evdev::KeyCode::BTN_NORTH,
evdev::KeyCode::BTN_WEST,
evdev::KeyCode::BTN_Z,
evdev::KeyCode::BTN_TL,
evdev::KeyCode::BTN_TR,
evdev::KeyCode::BTN_TL2,
evdev::KeyCode::BTN_TR2,
evdev::KeyCode::BTN_SELECT,
evdev::KeyCode::BTN_START,
evdev::KeyCode::BTN_MODE,
evdev::KeyCode::BTN_THUMBL,
evdev::KeyCode::BTN_THUMBR,
evdev::KeyCode::BTN_TOOL_PEN,
evdev::KeyCode::BTN_TOOL_RUBBER,
evdev::KeyCode::BTN_TOOL_BRUSH,
evdev::KeyCode::BTN_TOOL_PENCIL,
evdev::KeyCode::BTN_TOOL_AIRBRUSH,
evdev::KeyCode::BTN_TOOL_FINGER,
evdev::KeyCode::BTN_TOOL_MOUSE,
evdev::KeyCode::BTN_TOOL_LENS,
evdev::KeyCode::BTN_TOOL_QUINTTAP,
evdev::KeyCode::BTN_TOUCH,
evdev::KeyCode::BTN_STYLUS,
evdev::KeyCode::BTN_STYLUS2,
evdev::KeyCode::BTN_TOOL_DOUBLETAP,
evdev::KeyCode::BTN_TOOL_TRIPLETAP,
evdev::KeyCode::BTN_TOOL_QUADTAP,
evdev::KeyCode::BTN_GEAR_DOWN,
evdev::KeyCode::BTN_GEAR_UP,
evdev::KeyCode::KEY_OK,
evdev::KeyCode::KEY_SELECT,
evdev::KeyCode::KEY_GOTO,
evdev::KeyCode::KEY_CLEAR,
evdev::KeyCode::KEY_POWER2,
evdev::KeyCode::KEY_OPTION,
evdev::KeyCode::KEY_INFO,
evdev::KeyCode::KEY_TIME,
evdev::KeyCode::KEY_VENDOR,
evdev::KeyCode::KEY_ARCHIVE,
evdev::KeyCode::KEY_PROGRAM,
evdev::KeyCode::KEY_CHANNEL,
evdev::KeyCode::KEY_FAVORITES,
evdev::KeyCode::KEY_EPG,
evdev::KeyCode::KEY_PVR,
evdev::KeyCode::KEY_MHP,
evdev::KeyCode::KEY_LANGUAGE,
evdev::KeyCode::KEY_TITLE,
evdev::KeyCode::KEY_SUBTITLE,
evdev::KeyCode::KEY_ANGLE,
evdev::KeyCode::KEY_ZOOM,
evdev::KeyCode::KEY_FULL_SCREEN,
evdev::KeyCode::KEY_MODE,
evdev::KeyCode::KEY_KEYBOARD,
evdev::KeyCode::KEY_SCREEN,
evdev::KeyCode::KEY_PC,
evdev::KeyCode::KEY_TV,
evdev::KeyCode::KEY_TV2,
evdev::KeyCode::KEY_VCR,
evdev::KeyCode::KEY_VCR2,
evdev::KeyCode::KEY_SAT,
evdev::KeyCode::KEY_SAT2,
evdev::KeyCode::KEY_CD,
evdev::KeyCode::KEY_TAPE,
evdev::KeyCode::KEY_RADIO,
evdev::KeyCode::KEY_TUNER,
evdev::KeyCode::KEY_PLAYER,
evdev::KeyCode::KEY_TEXT,
evdev::KeyCode::KEY_DVD,
evdev::KeyCode::KEY_AUX,
evdev::KeyCode::KEY_MP3,
evdev::KeyCode::KEY_AUDIO,
evdev::KeyCode::KEY_VIDEO,
evdev::KeyCode::KEY_DIRECTORY,
evdev::KeyCode::KEY_LIST,
evdev::KeyCode::KEY_MEMO,
evdev::KeyCode::KEY_CALENDAR,
evdev::KeyCode::KEY_RED,
evdev::KeyCode::KEY_GREEN,
evdev::KeyCode::KEY_YELLOW,
evdev::KeyCode::KEY_BLUE,
evdev::KeyCode::KEY_CHANNELUP,
evdev::KeyCode::KEY_CHANNELDOWN,
evdev::KeyCode::KEY_FIRST,
evdev::KeyCode::KEY_LAST,
evdev::KeyCode::KEY_AB,
evdev::KeyCode::KEY_NEXT,
evdev::KeyCode::KEY_RESTART,
evdev::KeyCode::KEY_SLOW,
evdev::KeyCode::KEY_SHUFFLE,
evdev::KeyCode::KEY_BREAK,
evdev::KeyCode::KEY_PREVIOUS,
evdev::KeyCode::KEY_DIGITS,
evdev::KeyCode::KEY_TEEN,
evdev::KeyCode::KEY_TWEN,
evdev::KeyCode::KEY_VIDEOPHONE,
evdev::KeyCode::KEY_GAMES,
evdev::KeyCode::KEY_ZOOMIN,
evdev::KeyCode::KEY_ZOOMOUT,
evdev::KeyCode::KEY_ZOOMRESET,
evdev::KeyCode::KEY_WORDPROCESSOR,
evdev::KeyCode::KEY_EDITOR,
evdev::KeyCode::KEY_SPREADSHEET,
evdev::KeyCode::KEY_GRAPHICSEDITOR,
evdev::KeyCode::KEY_PRESENTATION,
evdev::KeyCode::KEY_DATABASE,
evdev::KeyCode::KEY_NEWS,
evdev::KeyCode::KEY_VOICEMAIL,
evdev::KeyCode::KEY_ADDRESSBOOK,
evdev::KeyCode::KEY_MESSENGER,
evdev::KeyCode::KEY_DISPLAYTOGGLE,
evdev::KeyCode::KEY_SPELLCHECK,
evdev::KeyCode::KEY_LOGOFF,
evdev::KeyCode::KEY_DOLLAR,
evdev::KeyCode::KEY_EURO,
evdev::KeyCode::KEY_FRAMEBACK,
evdev::KeyCode::KEY_FRAMEFORWARD,
evdev::KeyCode::KEY_CONTEXT_MENU,
evdev::KeyCode::KEY_MEDIA_REPEAT,
evdev::KeyCode::KEY_10CHANNELSUP,
evdev::KeyCode::KEY_10CHANNELSDOWN,
evdev::KeyCode::KEY_IMAGES,
evdev::KeyCode::KEY_DEL_EOL,
evdev::KeyCode::KEY_DEL_EOS,
evdev::KeyCode::KEY_INS_LINE,
evdev::KeyCode::KEY_DEL_LINE,
evdev::KeyCode::KEY_FN,
evdev::KeyCode::KEY_FN_ESC,
evdev::KeyCode::KEY_FN_F1,
evdev::KeyCode::KEY_FN_F2,
evdev::KeyCode::KEY_FN_F3,
evdev::KeyCode::KEY_FN_F4,
evdev::KeyCode::KEY_FN_F5,
evdev::KeyCode::KEY_FN_F6,
evdev::KeyCode::KEY_FN_F7,
evdev::KeyCode::KEY_FN_F8,
evdev::KeyCode::KEY_FN_F9,
evdev::KeyCode::KEY_FN_F10,
evdev::KeyCode::KEY_FN_F11,
evdev::KeyCode::KEY_FN_F12,
evdev::KeyCode::KEY_FN_1,
evdev::KeyCode::KEY_FN_2,
evdev::KeyCode::KEY_FN_D,
evdev::KeyCode::KEY_FN_E,
evdev::KeyCode::KEY_FN_F,
evdev::KeyCode::KEY_FN_S,
evdev::KeyCode::KEY_FN_B,
evdev::KeyCode::KEY_BRL_DOT1,
evdev::KeyCode::KEY_BRL_DOT2,
evdev::KeyCode::KEY_BRL_DOT3,
evdev::KeyCode::KEY_BRL_DOT4,
evdev::KeyCode::KEY_BRL_DOT5,
evdev::KeyCode::KEY_BRL_DOT6,
evdev::KeyCode::KEY_BRL_DOT7,
evdev::KeyCode::KEY_BRL_DOT8,
evdev::KeyCode::KEY_BRL_DOT9,
evdev::KeyCode::KEY_BRL_DOT10,
evdev::KeyCode::KEY_NUMERIC_0,
evdev::KeyCode::KEY_NUMERIC_1,
evdev::KeyCode::KEY_NUMERIC_2,
evdev::KeyCode::KEY_NUMERIC_3,
evdev::KeyCode::KEY_NUMERIC_4,
evdev::KeyCode::KEY_NUMERIC_5,
evdev::KeyCode::KEY_NUMERIC_6,
evdev::KeyCode::KEY_NUMERIC_7,
evdev::KeyCode::KEY_NUMERIC_8,
evdev::KeyCode::KEY_NUMERIC_9,
evdev::KeyCode::KEY_NUMERIC_STAR,
evdev::KeyCode::KEY_NUMERIC_POUND,
evdev::KeyCode::KEY_NUMERIC_A,
evdev::KeyCode::KEY_NUMERIC_B,
evdev::KeyCode::KEY_NUMERIC_C,
evdev::KeyCode::KEY_NUMERIC_D,
evdev::KeyCode::KEY_CAMERA_FOCUS,
evdev::KeyCode::KEY_WPS_BUTTON,
evdev::KeyCode::KEY_TOUCHPAD_TOGGLE,
evdev::KeyCode::KEY_TOUCHPAD_ON,
evdev::KeyCode::KEY_TOUCHPAD_OFF,
evdev::KeyCode::KEY_CAMERA_ZOOMIN,
evdev::KeyCode::KEY_CAMERA_ZOOMOUT,
evdev::KeyCode::KEY_CAMERA_UP,
evdev::KeyCode::KEY_CAMERA_DOWN,
evdev::KeyCode::KEY_CAMERA_LEFT,
evdev::KeyCode::KEY_CAMERA_RIGHT,
evdev::KeyCode::KEY_ATTENDANT_ON,
evdev::KeyCode::KEY_ATTENDANT_OFF,
evdev::KeyCode::KEY_ATTENDANT_TOGGLE,
evdev::KeyCode::KEY_LIGHTS_TOGGLE,
evdev::KeyCode::BTN_DPAD_UP,
evdev::KeyCode::BTN_DPAD_DOWN,
evdev::KeyCode::BTN_DPAD_LEFT,
evdev::KeyCode::BTN_DPAD_RIGHT,
evdev::KeyCode::KEY_ALS_TOGGLE,
evdev::KeyCode::KEY_BUTTONCONFIG,
evdev::KeyCode::KEY_TASKMANAGER,
evdev::KeyCode::KEY_JOURNAL,
evdev::KeyCode::KEY_CONTROLPANEL,
evdev::KeyCode::KEY_APPSELECT,
evdev::KeyCode::KEY_SCREENSAVER,
evdev::KeyCode::KEY_VOICECOMMAND,
evdev::KeyCode::KEY_ASSISTANT,
evdev::KeyCode::KEY_KBD_LAYOUT_NEXT,
evdev::KeyCode::KEY_BRIGHTNESS_MIN,
evdev::KeyCode::KEY_BRIGHTNESS_MAX,
evdev::KeyCode::KEY_KBDINPUTASSIST_PREV,
evdev::KeyCode::KEY_KBDINPUTASSIST_NEXT,
evdev::KeyCode::KEY_KBDINPUTASSIST_PREVGROUP,
evdev::KeyCode::KEY_KBDINPUTASSIST_NEXTGROUP,
evdev::KeyCode::KEY_KBDINPUTASSIST_ACCEPT,
evdev::KeyCode::KEY_KBDINPUTASSIST_CANCEL,
evdev::KeyCode::KEY_RIGHT_UP,
evdev::KeyCode::KEY_RIGHT_DOWN,
evdev::KeyCode::KEY_LEFT_UP,
evdev::KeyCode::KEY_LEFT_DOWN,
evdev::KeyCode::KEY_ROOT_MENU,
evdev::KeyCode::KEY_MEDIA_TOP_MENU,
evdev::KeyCode::KEY_NUMERIC_11,
evdev::KeyCode::KEY_NUMERIC_12,
evdev::KeyCode::KEY_AUDIO_DESC,
evdev::KeyCode::KEY_3D_MODE,
evdev::KeyCode::KEY_NEXT_FAVORITE,
evdev::KeyCode::KEY_STOP_RECORD,
evdev::KeyCode::KEY_PAUSE_RECORD,
evdev::KeyCode::KEY_VOD,
evdev::KeyCode::KEY_UNMUTE,
evdev::KeyCode::KEY_FASTREVERSE,
evdev::KeyCode::KEY_SLOWREVERSE,
evdev::KeyCode::KEY_DATA,
evdev::KeyCode::KEY_ONSCREEN_KEYBOARD,
evdev::KeyCode::KEY_PRIVACY_SCREEN_TOGGLE,
evdev::KeyCode::KEY_SELECTIVE_SCREENSHOT,
evdev::KeyCode::BTN_TRIGGER_HAPPY1,
evdev::KeyCode::BTN_TRIGGER_HAPPY2,
evdev::KeyCode::BTN_TRIGGER_HAPPY3,
evdev::KeyCode::BTN_TRIGGER_HAPPY4,
evdev::KeyCode::BTN_TRIGGER_HAPPY5,
evdev::KeyCode::BTN_TRIGGER_HAPPY6,
evdev::KeyCode::BTN_TRIGGER_HAPPY7,
evdev::KeyCode::BTN_TRIGGER_HAPPY8,
evdev::KeyCode::BTN_TRIGGER_HAPPY9,
evdev::KeyCode::BTN_TRIGGER_HAPPY10,
evdev::KeyCode::BTN_TRIGGER_HAPPY11,
evdev::KeyCode::BTN_TRIGGER_HAPPY12,
evdev::KeyCode::BTN_TRIGGER_HAPPY13,
evdev::KeyCode::BTN_TRIGGER_HAPPY14,
evdev::KeyCode::BTN_TRIGGER_HAPPY15,
evdev::KeyCode::BTN_TRIGGER_HAPPY16,
evdev::KeyCode::BTN_TRIGGER_HAPPY17,
evdev::KeyCode::BTN_TRIGGER_HAPPY18,
evdev::KeyCode::BTN_TRIGGER_HAPPY19,
evdev::KeyCode::BTN_TRIGGER_HAPPY20,
evdev::KeyCode::BTN_TRIGGER_HAPPY21,
evdev::KeyCode::BTN_TRIGGER_HAPPY22,
evdev::KeyCode::BTN_TRIGGER_HAPPY23,
evdev::KeyCode::BTN_TRIGGER_HAPPY24,
evdev::KeyCode::BTN_TRIGGER_HAPPY25,
evdev::KeyCode::BTN_TRIGGER_HAPPY26,
evdev::KeyCode::BTN_TRIGGER_HAPPY27,
evdev::KeyCode::BTN_TRIGGER_HAPPY28,
evdev::KeyCode::BTN_TRIGGER_HAPPY29,
evdev::KeyCode::BTN_TRIGGER_HAPPY30,
evdev::KeyCode::BTN_TRIGGER_HAPPY31,
evdev::KeyCode::BTN_TRIGGER_HAPPY32,
evdev::KeyCode::BTN_TRIGGER_HAPPY33,
evdev::KeyCode::BTN_TRIGGER_HAPPY34,
evdev::KeyCode::BTN_TRIGGER_HAPPY35,
evdev::KeyCode::BTN_TRIGGER_HAPPY36,
evdev::KeyCode::BTN_TRIGGER_HAPPY37,
evdev::KeyCode::BTN_TRIGGER_HAPPY38,
evdev::KeyCode::BTN_TRIGGER_HAPPY39,
evdev::KeyCode::BTN_TRIGGER_HAPPY40,
]
}