Files
lollipop/src/main.rs
Himadri Bhattacharjee eb8d3db6e3 feat: ini config parsing
2026-01-10 17:21:05 +05:30

749 lines
20 KiB
Rust

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