From 48e4dcfa43ac6b7270af526290862e662780766d Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Thu, 13 Apr 2017 20:15:04 +0200 Subject: [PATCH] Implement Hotkeys for Linux --- hotkey/Cargo.toml | 7 + hotkey/src/lib.rs | 18 +- hotkey/src/linux/key_code.rs | 1590 ++++++++++++++++++++++++++++++++ hotkey/src/linux/mod.rs | 230 +++++ hotkey/src/other/mod.rs | 27 +- hotkey/src/windows/key_code.rs | 174 ++++ hotkey/src/windows/mod.rs | 336 +++---- src/hotkey_config.rs | 14 +- src/hotkey_system.rs | 127 ++- src/lib.rs | 2 +- 10 files changed, 2240 insertions(+), 285 deletions(-) create mode 100644 hotkey/src/linux/key_code.rs create mode 100644 hotkey/src/linux/mod.rs create mode 100644 hotkey/src/windows/key_code.rs diff --git a/hotkey/Cargo.toml b/hotkey/Cargo.toml index 01a6a184..59a7bd21 100644 --- a/hotkey/Cargo.toml +++ b/hotkey/Cargo.toml @@ -12,5 +12,12 @@ keywords = ["speedrun", "timer", "livesplit", "hotkey", "keyboard"] winapi = "0.2.8" user32-sys = "0.2.0" kernel32-sys = "0.2.2" +parking_lot = "0.4.0" + +[target.'cfg(target_os = "linux")'.dependencies] +x11-dl = "2.13.0" +mio = "0.6.6" +promising-future = "0.2.4" [dependencies] +quick-error = "1.1.0" diff --git a/hotkey/src/lib.rs b/hotkey/src/lib.rs index 7cbc09e6..2098ff12 100644 --- a/hotkey/src/lib.rs +++ b/hotkey/src/lib.rs @@ -1,15 +1,17 @@ +#[macro_use] +extern crate quick_error; + #[cfg(windows)] pub mod windows; #[cfg(windows)] pub use windows::*; -#[cfg(not(any(windows)))] +#[cfg(target_os = "linux")] +pub mod linux; +#[cfg(target_os = "linux")] +pub use linux::*; + +#[cfg(not(any(windows, target_os = "linux")))] pub mod other; -#[cfg(not(any(windows)))] +#[cfg(not(any(windows, target_os = "linux")))] pub use other::*; - -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub enum KeyEvent { - KeyUp(KeyCode), - KeyDown(KeyCode), -} diff --git a/hotkey/src/linux/key_code.rs b/hotkey/src/linux/key_code.rs new file mode 100644 index 00000000..913e2de3 --- /dev/null +++ b/hotkey/src/linux/key_code.rs @@ -0,0 +1,1590 @@ +#[repr(u32)] +#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)] +pub enum KeyCode { + BackSpace = 0xFF08, + Tab = 0xFF09, + Linefeed = 0xFF0A, + Clear = 0xFF0B, + Return = 0xFF0D, + Pause = 0xFF13, + ScrollLock = 0xFF14, + SysReq = 0xFF15, + Escape = 0xFF1B, + Delete = 0xFFFF, + MultiKey = 0xFF20, + Kanji = 0xFF21, + Muhenkan = 0xFF22, + Henkan = 0xFF23, + Romaji = 0xFF24, + Hiragana = 0xFF25, + Katakana = 0xFF26, + HiraganaKatakana = 0xFF27, + Zenkaku = 0xFF28, + Hankaku = 0xFF29, + ZenkakuHankaku = 0xFF2A, + Touroku = 0xFF2B, + Massyo = 0xFF2C, + KanaLock = 0xFF2D, + KanaShift = 0xFF2E, + EisuShift = 0xFF2F, + EisuToggle = 0xFF30, + Home = 0xFF50, + Left = 0xFF51, + Up = 0xFF52, + Right = 0xFF53, + Down = 0xFF54, + PageUp = 0xFF55, + PageDown = 0xFF56, + End = 0xFF57, + Begin = 0xFF58, + WinL = 0xFF5B, + WinR = 0xFF5C, + App = 0xFF5D, + Select = 0xFF60, + Print = 0xFF61, + Execute = 0xFF62, + Insert = 0xFF63, + Undo = 0xFF65, + Redo = 0xFF66, + Menu = 0xFF67, + Find = 0xFF68, + Cancel = 0xFF69, + Help = 0xFF6A, + Break = 0xFF6B, + ModeSwitch = 0xFF7E, + NumLock = 0xFF7F, + NumPadSpace = 0xFF80, + NumPadTab = 0xFF89, + NumPadEnter = 0xFF8D, + NumPadF1 = 0xFF91, + NumPadF2 = 0xFF92, + NumPadF3 = 0xFF93, + NumPadF4 = 0xFF94, + NumPadHome = 0xFF95, + NumPadLeft = 0xFF96, + NumPadUp = 0xFF97, + NumPadRight = 0xFF98, + NumPadDown = 0xFF99, + NumPadPageUp = 0xFF9A, + NumPadPageDown = 0xFF9B, + NumPadEnd = 0xFF9C, + NumPadBegin = 0xFF9D, + NumPadInsert = 0xFF9E, + NumPadDelete = 0xFF9F, + NumPadEqual = 0xFFBD, + NumPadMultiply = 0xFFAA, + NumPadAdd = 0xFFAB, + NumPadSeparator = 0xFFAC, + NumPadSubtract = 0xFFAD, + NumPadDecimal = 0xFFAE, + NumPadDivide = 0xFFAF, + NumPad0 = 0xFFB0, + NumPad1 = 0xFFB1, + NumPad2 = 0xFFB2, + NumPad3 = 0xFFB3, + NumPad4 = 0xFFB4, + NumPad5 = 0xFFB5, + NumPad6 = 0xFFB6, + NumPad7 = 0xFFB7, + NumPad8 = 0xFFB8, + NumPad9 = 0xFFB9, + F1 = 0xFFBE, + F2 = 0xFFBF, + F3 = 0xFFC0, + F4 = 0xFFC1, + F5 = 0xFFC2, + F6 = 0xFFC3, + F7 = 0xFFC4, + F8 = 0xFFC5, + F9 = 0xFFC6, + F10 = 0xFFC7, + F11 = 0xFFC8, + F12 = 0xFFC9, + F13 = 0xFFCA, + F14 = 0xFFCB, + F15 = 0xFFCC, + F16 = 0xFFCD, + F17 = 0xFFCE, + F18 = 0xFFCF, + F19 = 0xFFD0, + F20 = 0xFFD1, + F21 = 0xFFD2, + F22 = 0xFFD3, + F23 = 0xFFD4, + F24 = 0xFFD5, + F25 = 0xFFD6, + F26 = 0xFFD7, + F27 = 0xFFD8, + F28 = 0xFFD9, + F29 = 0xFFDA, + F30 = 0xFFDB, + F31 = 0xFFDC, + F32 = 0xFFDD, + F33 = 0xFFDE, + F34 = 0xFFDF, + F35 = 0xFFE0, + ShiftL = 0xFFE1, + ShiftR = 0xFFE2, + ControlL = 0xFFE3, + ControlR = 0xFFE4, + CapsLock = 0xFFE5, + ShiftLock = 0xFFE6, + MetaL = 0xFFE7, + MetaR = 0xFFE8, + AltL = 0xFFE9, + AltR = 0xFFEA, + SuperL = 0xFFEB, + SuperR = 0xFFEC, + HyperL = 0xFFED, + HyperR = 0xFFEE, + Space = 0x020, + Exclam = 0x021, + Quotedbl = 0x022, + NumberSign = 0x023, + Dollar = 0x024, + Percent = 0x025, + Ampersand = 0x026, + Apostrophe = 0x027, + ParenLeft = 0x028, + ParenRight = 0x029, + Asterisk = 0x02a, + Plus = 0x02b, + Comma = 0x02c, + Minus = 0x02d, + Period = 0x02e, + Slash = 0x02f, + D0 = 0x030, + D1 = 0x031, + D2 = 0x032, + D3 = 0x033, + D4 = 0x034, + D5 = 0x035, + D6 = 0x036, + D7 = 0x037, + D8 = 0x038, + D9 = 0x039, + Colon = 0x03a, + Semicolon = 0x03b, + Less = 0x03c, + Equal = 0x03d, + Greater = 0x03e, + Question = 0x03f, + At = 0x040, + LowercaseA = 0x041, + LowercaseB = 0x042, + LowercaseC = 0x043, + LowercaseD = 0x044, + LowercaseE = 0x045, + LowercaseF = 0x046, + LowercaseG = 0x047, + LowercaseH = 0x048, + LowercaseI = 0x049, + LowercaseJ = 0x04a, + LowercaseK = 0x04b, + LowercaseL = 0x04c, + LowercaseM = 0x04d, + LowercaseN = 0x04e, + LowercaseO = 0x04f, + LowercaseP = 0x050, + LowercaseQ = 0x051, + LowercaseR = 0x052, + LowercaseS = 0x053, + LowercaseT = 0x054, + LowercaseU = 0x055, + LowercaseV = 0x056, + LowercaseW = 0x057, + LowercaseX = 0x058, + LowercaseY = 0x059, + LowercaseZ = 0x05a, + BracketLeft = 0x05b, + Backslash = 0x05c, + BracketRight = 0x05d, + AsciiCircum = 0x05e, + Underscore = 0x05f, + Grave = 0x060, + A = 0x061, + B = 0x062, + C = 0x063, + D = 0x064, + E = 0x065, + F = 0x066, + G = 0x067, + H = 0x068, + I = 0x069, + J = 0x06a, + K = 0x06b, + L = 0x06c, + M = 0x06d, + N = 0x06e, + O = 0x06f, + P = 0x070, + Q = 0x071, + R = 0x072, + S = 0x073, + T = 0x074, + U = 0x075, + V = 0x076, + W = 0x077, + X = 0x078, + Y = 0x079, + Z = 0x07a, + BraceLeft = 0x07b, + Bar = 0x07c, + BraceRight = 0x07d, + AsciiTilde = 0x07e, + NobreakSpace = 0x0a0, + ExclamDown = 0x0a1, + Cent = 0x0a2, + Sterling = 0x0a3, + Currency = 0x0a4, + Yen = 0x0a5, + Brokenbar = 0x0a6, + Section = 0x0a7, + Diaeresis = 0x0a8, + Copyright = 0x0a9, + Ordfeminine = 0x0aa, + GuillemotLeft = 0x0ab, + NotSign = 0x0ac, + Hyphen = 0x0ad, + Registered = 0x0ae, + Macron = 0x0af, + Degree = 0x0b0, + Plusminus = 0x0b1, + Twosuperior = 0x0b2, + Threesuperior = 0x0b3, + Acute = 0x0b4, + Mu = 0x0b5, + Paragraph = 0x0b6, + PeriodCentered = 0x0b7, + Cedilla = 0x0b8, + Onesuperior = 0x0b9, + Masculine = 0x0ba, + GuillemotRight = 0x0bb, + Onequarter = 0x0bc, + Onehalf = 0x0bd, + Threequarters = 0x0be, + QuestionDown = 0x0bf, + Agrave = 0x0c0, + AAcute = 0x0c1, + ACircumflex = 0x0c2, + ATilde = 0x0c3, + Adiaeresis = 0x0c4, + Aring = 0x0c5, + Ae = 0x0c6, + Ccedilla = 0x0c7, + Egrave = 0x0c8, + EAcute = 0x0c9, + ECircumflex = 0x0ca, + Ediaeresis = 0x0cb, + Igrave = 0x0cc, + IAcute = 0x0cd, + ICircumflex = 0x0ce, + Idiaeresis = 0x0cf, + Eth = 0x0d0, + NTilde = 0x0d1, + Ograve = 0x0d2, + OAcute = 0x0d3, + OCircumflex = 0x0d4, + OTilde = 0x0d5, + Odiaeresis = 0x0d6, + Multiply = 0x0d7, + Ooblique = 0x0d8, + Ugrave = 0x0d9, + UAcute = 0x0da, + UCircumflex = 0x0db, + Udiaeresis = 0x0dc, + YAcute = 0x0dd, + Thorn = 0x0de, + Ssharp = 0x0df, +} + + +// pub enum Bla { +// BackSpace = 0xFF08, +// Tab = 0xFF09, +// Linefeed = 0xFF0A, +// Clear = 0xFF0B, +// Return = 0xFF0D, +// Pause = 0xFF13, +// ScrollLock = 0xFF14, +// SysReq = 0xFF15, +// Escape = 0xFF1B, +// Delete = 0xFFFF, +// MultiKey = 0xFF20, +// Kanji = 0xFF21, +// Muhenkan = 0xFF22, +// Henkan = 0xFF23, +// Romaji = 0xFF24, +// Hiragana = 0xFF25, +// Katakana = 0xFF26, +// HiraganaKatakana = 0xFF27, +// Zenkaku = 0xFF28, +// Hankaku = 0xFF29, +// ZenkakuHankaku = 0xFF2A, +// Touroku = 0xFF2B, +// Massyo = 0xFF2C, +// KanaLock = 0xFF2D, +// KanaShift = 0xFF2E, +// EisuShift = 0xFF2F, +// EisuToggle = 0xFF30, +// Home = 0xFF50, +// Left = 0xFF51, +// Up = 0xFF52, +// Right = 0xFF53, +// Down = 0xFF54, +// PageUp = 0xFF55, +// PageDown = 0xFF56, +// End = 0xFF57, +// Begin = 0xFF58, +// WinL = 0xFF5B, +// WinR = 0xFF5C, +// App = 0xFF5D, +// Select = 0xFF60, +// Print = 0xFF61, +// Execute = 0xFF62, +// Insert = 0xFF63, +// Undo = 0xFF65, +// Redo = 0xFF66, +// Menu = 0xFF67, +// Find = 0xFF68, +// Cancel = 0xFF69, +// Help = 0xFF6A, +// Break = 0xFF6B, +// ModeSwitch = 0xFF7E, +// NumLock = 0xFF7F, +// NumPadSpace = 0xFF80, +// NumPadTab = 0xFF89, +// NumPadEnter = 0xFF8D, +// NumPadF1 = 0xFF91, +// NumPadF2 = 0xFF92, +// NumPadF3 = 0xFF93, +// NumPadF4 = 0xFF94, +// NumPadHome = 0xFF95, +// NumPadLeft = 0xFF96, +// NumPadUp = 0xFF97, +// NumPadRight = 0xFF98, +// NumPadDown = 0xFF99, +// NumPadPageUp = 0xFF9A, +// NumPadPageDown = 0xFF9B, +// NumPadEnd = 0xFF9C, +// NumPadBegin = 0xFF9D, +// NumPadInsert = 0xFF9E, +// NumPadDelete = 0xFF9F, +// NumPadEqual = 0xFFBD, +// NumPadMultiply = 0xFFAA, +// NumPadAdd = 0xFFAB, +// NumPadSeparator = 0xFFAC, +// NumPadSubtract = 0xFFAD, +// NumPadDecimal = 0xFFAE, +// NumPadDivide = 0xFFAF, +// NumPad0 = 0xFFB0, +// NumPad1 = 0xFFB1, +// NumPad2 = 0xFFB2, +// NumPad3 = 0xFFB3, +// NumPad4 = 0xFFB4, +// NumPad5 = 0xFFB5, +// NumPad6 = 0xFFB6, +// NumPad7 = 0xFFB7, +// NumPad8 = 0xFFB8, +// NumPad9 = 0xFFB9, +// F1 = 0xFFBE, +// F2 = 0xFFBF, +// F3 = 0xFFC0, +// F4 = 0xFFC1, +// F5 = 0xFFC2, +// F6 = 0xFFC3, +// F7 = 0xFFC4, +// F8 = 0xFFC5, +// F9 = 0xFFC6, +// F10 = 0xFFC7, +// F11 = 0xFFC8, +// F12 = 0xFFC9, +// F13 = 0xFFCA, +// F14 = 0xFFCB, +// F15 = 0xFFCC, +// F16 = 0xFFCD, +// F17 = 0xFFCE, +// F18 = 0xFFCF, +// F19 = 0xFFD0, +// F20 = 0xFFD1, +// F21 = 0xFFD2, +// F22 = 0xFFD3, +// F23 = 0xFFD4, +// F24 = 0xFFD5, +// F25 = 0xFFD6, +// F26 = 0xFFD7, +// F27 = 0xFFD8, +// F28 = 0xFFD9, +// F29 = 0xFFDA, +// F30 = 0xFFDB, +// F31 = 0xFFDC, +// F32 = 0xFFDD, +// F33 = 0xFFDE, +// F34 = 0xFFDF, +// F35 = 0xFFE0, +// ShiftL = 0xFFE1, +// ShiftR = 0xFFE2, +// ControlL = 0xFFE3, +// ControlR = 0xFFE4, +// CapsLock = 0xFFE5, +// ShiftLock = 0xFFE6, +// MetaL = 0xFFE7, +// MetaR = 0xFFE8, +// AltL = 0xFFE9, +// AltR = 0xFFEA, +// SuperL = 0xFFEB, +// SuperR = 0xFFEC, +// HyperL = 0xFFED, +// HyperR = 0xFFEE, +// Space = 0x020, +// Exclam = 0x021, +// Quotedbl = 0x022, +// NumberSign = 0x023, +// Dollar = 0x024, +// Percent = 0x025, +// Ampersand = 0x026, +// Apostrophe = 0x027, +// ParenLeft = 0x028, +// ParenRight = 0x029, +// Asterisk = 0x02a, +// Plus = 0x02b, +// Comma = 0x02c, +// Minus = 0x02d, +// Period = 0x02e, +// Slash = 0x02f, +// D0 = 0x030, +// D1 = 0x031, +// D2 = 0x032, +// D3 = 0x033, +// D4 = 0x034, +// D5 = 0x035, +// D6 = 0x036, +// D7 = 0x037, +// D8 = 0x038, +// D9 = 0x039, +// Colon = 0x03a, +// Semicolon = 0x03b, +// Less = 0x03c, +// Equal = 0x03d, +// Greater = 0x03e, +// Question = 0x03f, +// At = 0x040, +// LowercaseA = 0x041, +// LowercaseB = 0x042, +// LowercaseC = 0x043, +// LowercaseD = 0x044, +// LowercaseE = 0x045, +// LowercaseF = 0x046, +// LowercaseG = 0x047, +// LowercaseH = 0x048, +// LowercaseI = 0x049, +// LowercaseJ = 0x04a, +// LowercaseK = 0x04b, +// LowercaseL = 0x04c, +// LowercaseM = 0x04d, +// LowercaseN = 0x04e, +// LowercaseO = 0x04f, +// LowercaseP = 0x050, +// LowercaseQ = 0x051, +// LowercaseR = 0x052, +// LowercaseS = 0x053, +// LowercaseT = 0x054, +// LowercaseU = 0x055, +// LowercaseV = 0x056, +// LowercaseW = 0x057, +// LowercaseX = 0x058, +// LowercaseY = 0x059, +// LowercaseZ = 0x05a, +// BracketLeft = 0x05b, +// Backslash = 0x05c, +// BracketRight = 0x05d, +// AsciiCircum = 0x05e, +// Underscore = 0x05f, +// Grave = 0x060, +// A = 0x061, +// B = 0x062, +// C = 0x063, +// D = 0x064, +// E = 0x065, +// F = 0x066, +// G = 0x067, +// H = 0x068, +// I = 0x069, +// J = 0x06a, +// K = 0x06b, +// L = 0x06c, +// M = 0x06d, +// N = 0x06e, +// O = 0x06f, +// P = 0x070, +// Q = 0x071, +// R = 0x072, +// S = 0x073, +// T = 0x074, +// U = 0x075, +// V = 0x076, +// W = 0x077, +// X = 0x078, +// Y = 0x079, +// Z = 0x07a, +// BraceLeft = 0x07b, +// Bar = 0x07c, +// BraceRight = 0x07d, +// AsciiTilde = 0x07e, +// NobreakSpace = 0x0a0, +// ExclamDown = 0x0a1, +// Cent = 0x0a2, +// Sterling = 0x0a3, +// Currency = 0x0a4, +// Yen = 0x0a5, +// Brokenbar = 0x0a6, +// Section = 0x0a7, +// Diaeresis = 0x0a8, +// Copyright = 0x0a9, +// Ordfeminine = 0x0aa, +// GuillemotLeft = 0x0ab, +// NotSign = 0x0ac, +// Hyphen = 0x0ad, +// Registered = 0x0ae, +// Macron = 0x0af, +// Degree = 0x0b0, +// Plusminus = 0x0b1, +// Twosuperior = 0x0b2, +// Threesuperior = 0x0b3, +// Acute = 0x0b4, +// Mu = 0x0b5, +// Paragraph = 0x0b6, +// PeriodCentered = 0x0b7, +// Cedilla = 0x0b8, +// Onesuperior = 0x0b9, +// Masculine = 0x0ba, +// GuillemotRight = 0x0bb, +// Onequarter = 0x0bc, +// Onehalf = 0x0bd, +// Threequarters = 0x0be, +// QuestionDown = 0x0bf, +// Agrave = 0x0c0, +// AAcute = 0x0c1, +// ACircumflex = 0x0c2, +// ATilde = 0x0c3, +// Adiaeresis = 0x0c4, +// Aring = 0x0c5, +// Ae = 0x0c6, +// Ccedilla = 0x0c7, +// Egrave = 0x0c8, +// EAcute = 0x0c9, +// ECircumflex = 0x0ca, +// Ediaeresis = 0x0cb, +// Igrave = 0x0cc, +// IAcute = 0x0cd, +// ICircumflex = 0x0ce, +// Idiaeresis = 0x0cf, +// Eth = 0x0d0, +// NTilde = 0x0d1, +// Ograve = 0x0d2, +// OAcute = 0x0d3, +// OCircumflex = 0x0d4, +// OTilde = 0x0d5, +// Odiaeresis = 0x0d6, +// Multiply = 0x0d7, +// Ooblique = 0x0d8, +// Ugrave = 0x0d9, +// UAcute = 0x0da, +// UCircumflex = 0x0db, +// Udiaeresis = 0x0dc, +// YAcute = 0x0dd, +// Thorn = 0x0de, +// Ssharp = 0x0df, +// Agrave = 0x0e0, +// AAcute = 0x0e1, +// ACircumflex = 0x0e2, +// ATilde = 0x0e3, +// Adiaeresis = 0x0e4, +// Aring = 0x0e5, +// Ae = 0x0e6, +// Ccedilla = 0x0e7, +// Egrave = 0x0e8, +// EAcute = 0x0e9, +// ECircumflex = 0x0ea, +// Ediaeresis = 0x0eb, +// Igrave = 0x0ec, +// IAcute = 0x0ed, +// ICircumflex = 0x0ee, +// Idiaeresis = 0x0ef, +// Eth = 0x0f0, +// NTilde = 0x0f1, +// Ograve = 0x0f2, +// OAcute = 0x0f3, +// OCircumflex = 0x0f4, +// OTilde = 0x0f5, +// Odiaeresis = 0x0f6, +// Division = 0x0f7, +// OSlash = 0x0f8, +// Ugrave = 0x0f9, +// UAcute = 0x0fa, +// UCircumflex = 0x0fb, +// Udiaeresis = 0x0fc, +// YAcute = 0x0fd, +// Thorn = 0x0fe, +// Ydiaeresis = 0x0ff, +// Aogonek = 0x1a1, +// Breve = 0x1a2, +// LStroke = 0x1a3, +// LCaron = 0x1a5, +// SAcute = 0x1a6, +// SCaron = 0x1a9, +// Scedilla = 0x1aa, +// TCaron = 0x1ab, +// ZAcute = 0x1ac, +// ZCaron = 0x1ae, +// ZAboveDot = 0x1af, +// Aogonek = 0x1b1, +// Ogonek = 0x1b2, +// LStroke = 0x1b3, +// LCaron = 0x1b5, +// SAcute = 0x1b6, +// Caron = 0x1b7, +// SCaron = 0x1b9, +// Scedilla = 0x1ba, +// TCaron = 0x1bb, +// ZAcute = 0x1bc, +// DoubleAcute = 0x1bd, +// ZCaron = 0x1be, +// ZAboveDot = 0x1bf, +// RAcute = 0x1c0, +// Abreve = 0x1c3, +// LAcute = 0x1c5, +// CAcute = 0x1c6, +// CCaron = 0x1c8, +// Eogonek = 0x1ca, +// ECaron = 0x1cc, +// DCaron = 0x1cf, +// DStroke = 0x1d0, +// NAcute = 0x1d1, +// NCaron = 0x1d2, +// ODoubleAcute = 0x1d5, +// RCaron = 0x1d8, +// Uring = 0x1d9, +// UDoubleAcute = 0x1db, +// Tcedilla = 0x1de, +// RAcute = 0x1e0, +// Abreve = 0x1e3, +// LAcute = 0x1e5, +// CAcute = 0x1e6, +// CCaron = 0x1e8, +// Eogonek = 0x1ea, +// ECaron = 0x1ec, +// DCaron = 0x1ef, +// DStroke = 0x1f0, +// NAcute = 0x1f1, +// NCaron = 0x1f2, +// ODoubleAcute = 0x1f5, +// UDoubleAcute = 0x1fb, +// RCaron = 0x1f8, +// Uring = 0x1f9, +// Tcedilla = 0x1fe, +// AboveDot = 0x1ff, +// HStroke = 0x2a1, +// HCircumflex = 0x2a6, +// IAboveDot = 0x2a9, +// Gbreve = 0x2ab, +// JCircumflex = 0x2ac, +// HStroke = 0x2b1, +// HCircumflex = 0x2b6, +// IDotless = 0x2b9, +// Gbreve = 0x2bb, +// JCircumflex = 0x2bc, +// CAboveDot = 0x2c5, +// CCircumflex = 0x2c6, +// GAboveDot = 0x2d5, +// GCircumflex = 0x2d8, +// Ubreve = 0x2dd, +// SCircumflex = 0x2de, +// CAboveDot = 0x2e5, +// CCircumflex = 0x2e6, +// GAboveDot = 0x2f5, +// GCircumflex = 0x2f8, +// Ubreve = 0x2fd, +// SCircumflex = 0x2fe, +// Kra = 0x3a2, +// Kappa = 0x3a2, +// Rcedilla = 0x3a3, +// ITilde = 0x3a5, +// Lcedilla = 0x3a6, +// Emacron = 0x3aa, +// Gcedilla = 0x3ab, +// TSlash = 0x3ac, +// Rcedilla = 0x3b3, +// ITilde = 0x3b5, +// Lcedilla = 0x3b6, +// Emacron = 0x3ba, +// Gcedilla = 0x3bb, +// TSlash = 0x3bc, +// Eng = 0x3bd, +// Eng = 0x3bf, +// Amacron = 0x3c0, +// Iogonek = 0x3c7, +// EAboveDot = 0x3cc, +// Imacron = 0x3cf, +// Ncedilla = 0x3d1, +// Omacron = 0x3d2, +// Kcedilla = 0x3d3, +// Uogonek = 0x3d9, +// UTilde = 0x3dd, +// Umacron = 0x3de, +// Amacron = 0x3e0, +// Iogonek = 0x3e7, +// EAboveDot = 0x3ec, +// Imacron = 0x3ef, +// Ncedilla = 0x3f1, +// Omacron = 0x3f2, +// Kcedilla = 0x3f3, +// Uogonek = 0x3f9, +// UTilde = 0x3fd, +// Umacron = 0x3fe, +// Overline = 0x47e, +// KanaFullstop = 0x4a1, +// KanaOpeningBracket = 0x4a2, +// KanaClosingBracket = 0x4a3, +// KanaComma = 0x4a4, +// KanaConjunctive = 0x4a5, +// KanaMiddleDot = 0x4a5, +// KanaWo = 0x4a6, +// KanaA = 0x4a7, +// KanaI = 0x4a8, +// KanaU = 0x4a9, +// KanaE = 0x4aa, +// KanaO = 0x4ab, +// KanaYa = 0x4ac, +// KanaYu = 0x4ad, +// KanaYo = 0x4ae, +// KanaTsu = 0x4af, +// ProlongedSound = 0x4b0, +// KanaA = 0x4b1, +// KanaI = 0x4b2, +// KanaU = 0x4b3, +// KanaE = 0x4b4, +// KanaO = 0x4b5, +// KanaKa = 0x4b6, +// KanaKi = 0x4b7, +// KanaKu = 0x4b8, +// KanaKe = 0x4b9, +// KanaKo = 0x4ba, +// KanaSa = 0x4bb, +// KanaShi = 0x4bc, +// KanaSu = 0x4bd, +// KanaSe = 0x4be, +// KanaSo = 0x4bf, +// KanaTa = 0x4c0, +// KanaChi = 0x4c1, +// KanaTsu = 0x4c2, +// KanaTu = 0x4c2, +// KanaTe = 0x4c3, +// KanaTo = 0x4c4, +// KanaNa = 0x4c5, +// KanaNi = 0x4c6, +// KanaNu = 0x4c7, +// KanaNe = 0x4c8, +// KanaNo = 0x4c9, +// KanaHa = 0x4ca, +// KanaHi = 0x4cb, +// KanaFu = 0x4cc, +// KanaHe = 0x4cd, +// KanaHo = 0x4ce, +// KanaMa = 0x4cf, +// KanaMi = 0x4d0, +// KanaMu = 0x4d1, +// KanaMe = 0x4d2, +// KanaMo = 0x4d3, +// KanaYa = 0x4d4, +// KanaYu = 0x4d5, +// KanaYo = 0x4d6, +// KanaRa = 0x4d7, +// KanaRi = 0x4d8, +// KanaRu = 0x4d9, +// KanaRe = 0x4da, +// KanaRo = 0x4db, +// KanaWa = 0x4dc, +// KanaN = 0x4dd, +// VoicedSound = 0x4de, +// SemivoicedSound = 0x4df, +// KanaSwitch = 0xFF7E, +// ArabicComma = 0x5ac, +// ArabicSemicolon = 0x5bb, +// ArabicQuestionMark = 0x5bf, +// ArabicHamza = 0x5c1, +// ArabicMaddaonalef = 0x5c2, +// ArabicHamzaonalef = 0x5c3, +// ArabicHamzaonwaw = 0x5c4, +// ArabicHamzaunderalef = 0x5c5, +// ArabicHamzaonyeh = 0x5c6, +// ArabicAlef = 0x5c7, +// ArabicBeh = 0x5c8, +// ArabicTehmarbuta = 0x5c9, +// ArabicTeh = 0x5ca, +// ArabicTheh = 0x5cb, +// ArabicJeem = 0x5cc, +// ArabicHah = 0x5cd, +// ArabicKhah = 0x5ce, +// ArabicDal = 0x5cf, +// ArabicThal = 0x5d0, +// ArabicRa = 0x5d1, +// ArabicZain = 0x5d2, +// ArabicSeen = 0x5d3, +// ArabicSheen = 0x5d4, +// ArabicSad = 0x5d5, +// ArabicDad = 0x5d6, +// ArabicTah = 0x5d7, +// ArabicZah = 0x5d8, +// ArabicAin = 0x5d9, +// ArabicGhain = 0x5da, +// ArabicTatweel = 0x5e0, +// ArabicFeh = 0x5e1, +// ArabicQaf = 0x5e2, +// ArabicKaf = 0x5e3, +// ArabicLam = 0x5e4, +// ArabicMeem = 0x5e5, +// ArabicNoon = 0x5e6, +// ArabicHa = 0x5e7, +// ArabicHeh = 0x5e7, +// ArabicWaw = 0x5e8, +// ArabicAlefmaksura = 0x5e9, +// ArabicYeh = 0x5ea, +// ArabicFathatan = 0x5eb, +// ArabicDammatan = 0x5ec, +// ArabicKasratan = 0x5ed, +// ArabicFatha = 0x5ee, +// ArabicDamma = 0x5ef, +// ArabicKasra = 0x5f0, +// ArabicShadda = 0x5f1, +// ArabicSukun = 0x5f2, +// ArabicSwitch = 0xFF7E, +// SerbianDje = 0x6a1, +// MacedoniaGje = 0x6a2, +// CyrillicIo = 0x6a3, +// UkrainianIe = 0x6a4, +// UkranianJe = 0x6a4, +// MacedoniaDse = 0x6a5, +// UkrainianI = 0x6a6, +// UkranianI = 0x6a6, +// UkrainianYi = 0x6a7, +// UkranianYi = 0x6a7, +// CyrillicJe = 0x6a8, +// SerbianJe = 0x6a8, +// CyrillicLje = 0x6a9, +// SerbianLje = 0x6a9, +// CyrillicNje = 0x6aa, +// SerbianNje = 0x6aa, +// SerbianTshe = 0x6ab, +// MacedoniaKje = 0x6ac, +// ByelorussianShortu = 0x6ae, +// CyrillicDzhe = 0x6af, +// SerbianDze = 0x6af, +// NumeroSign = 0x6b0, +// SerbianDje = 0x6b1, +// MacedoniaGje = 0x6b2, +// CyrillicIo = 0x6b3, +// UkrainianIe = 0x6b4, +// UkranianJe = 0x6b4, +// MacedoniaDse = 0x6b5, +// UkrainianI = 0x6b6, +// UkranianI = 0x6b6, +// UkrainianYi = 0x6b7, +// UkranianYi = 0x6b7, +// CyrillicJe = 0x6b8, +// SerbianJe = 0x6b8, +// CyrillicLje = 0x6b9, +// SerbianLje = 0x6b9, +// CyrillicNje = 0x6ba, +// SerbianNje = 0x6ba, +// SerbianTshe = 0x6bb, +// MacedoniaKje = 0x6bc, +// ByelorussianShortu = 0x6be, +// CyrillicDzhe = 0x6bf, +// SerbianDze = 0x6bf, +// CyrillicYu = 0x6c0, +// CyrillicA = 0x6c1, +// CyrillicBe = 0x6c2, +// CyrillicTse = 0x6c3, +// CyrillicDe = 0x6c4, +// CyrillicIe = 0x6c5, +// CyrillicEf = 0x6c6, +// CyrillicGhe = 0x6c7, +// CyrillicHa = 0x6c8, +// CyrillicI = 0x6c9, +// CyrillicShorti = 0x6ca, +// CyrillicKa = 0x6cb, +// CyrillicEl = 0x6cc, +// CyrillicEm = 0x6cd, +// CyrillicEn = 0x6ce, +// CyrillicO = 0x6cf, +// CyrillicPe = 0x6d0, +// CyrillicYa = 0x6d1, +// CyrillicEr = 0x6d2, +// CyrillicEs = 0x6d3, +// CyrillicTe = 0x6d4, +// CyrillicU = 0x6d5, +// CyrillicZhe = 0x6d6, +// CyrillicVe = 0x6d7, +// CyrillicSoftSign = 0x6d8, +// CyrillicYeru = 0x6d9, +// CyrillicZe = 0x6da, +// CyrillicSha = 0x6db, +// CyrillicE = 0x6dc, +// CyrillicShcha = 0x6dd, +// CyrillicChe = 0x6de, +// CyrillicHardSign = 0x6df, +// CyrillicYu = 0x6e0, +// CyrillicA = 0x6e1, +// CyrillicBe = 0x6e2, +// CyrillicTse = 0x6e3, +// CyrillicDe = 0x6e4, +// CyrillicIe = 0x6e5, +// CyrillicEf = 0x6e6, +// CyrillicGhe = 0x6e7, +// CyrillicHa = 0x6e8, +// CyrillicI = 0x6e9, +// CyrillicShorti = 0x6ea, +// CyrillicKa = 0x6eb, +// CyrillicEl = 0x6ec, +// CyrillicEm = 0x6ed, +// CyrillicEn = 0x6ee, +// CyrillicO = 0x6ef, +// CyrillicPe = 0x6f0, +// CyrillicYa = 0x6f1, +// CyrillicEr = 0x6f2, +// CyrillicEs = 0x6f3, +// CyrillicTe = 0x6f4, +// CyrillicU = 0x6f5, +// CyrillicZhe = 0x6f6, +// CyrillicVe = 0x6f7, +// CyrillicSoftSign = 0x6f8, +// CyrillicYeru = 0x6f9, +// CyrillicZe = 0x6fa, +// CyrillicSha = 0x6fb, +// CyrillicE = 0x6fc, +// CyrillicShcha = 0x6fd, +// CyrillicChe = 0x6fe, +// CyrillicHardSign = 0x6ff, +// GreekAlphAAccent = 0x7a1, +// GreekEpsiloNAccent = 0x7a2, +// GreekEtAAccent = 0x7a3, +// GreekIotAAccent = 0x7a4, +// GreekIotAdiaeresis = 0x7a5, +// GreekOmicroNAccent = 0x7a7, +// GreekUpsiloNAccent = 0x7a8, +// GreekUpsiloNdieresis = 0x7a9, +// GreekOmegAAccent = 0x7ab, +// GreekAccentdieresis = 0x7ae, +// GreekHorizbar = 0x7af, +// GreekAlphaAccent = 0x7b1, +// GreekEpsilonAccent = 0x7b2, +// GreekEtaAccent = 0x7b3, +// GreekIotaAccent = 0x7b4, +// GreekIotadieresis = 0x7b5, +// GreekIotaAccentdieresis = 0x7b6, +// GreekOmicronAccent = 0x7b7, +// GreekUpsilonAccent = 0x7b8, +// GreekUpsilondieresis = 0x7b9, +// GreekUpsilonAccentdieresis = 0x7ba, +// GreekOmegaAccent = 0x7bb, +// GreekAlpha = 0x7c1, +// GreekBeta = 0x7c2, +// GreekGamma = 0x7c3, +// GreekDelta = 0x7c4, +// GreekEpsilon = 0x7c5, +// GreekZeta = 0x7c6, +// GreekEta = 0x7c7, +// GreekTheta = 0x7c8, +// GreekIota = 0x7c9, +// GreekKappa = 0x7ca, +// GreekLamda = 0x7cb, +// GreekLambda = 0x7cb, +// GreekMu = 0x7cc, +// GreekNu = 0x7cd, +// GreekXi = 0x7ce, +// GreekOmicron = 0x7cf, +// GreekPi = 0x7d0, +// GreekRho = 0x7d1, +// GreekSigma = 0x7d2, +// GreekTau = 0x7d4, +// GreekUpsilon = 0x7d5, +// GreekPhi = 0x7d6, +// GreekChi = 0x7d7, +// GreekPsi = 0x7d8, +// GreekOmega = 0x7d9, +// GreekAlpha = 0x7e1, +// GreekBeta = 0x7e2, +// GreekGamma = 0x7e3, +// GreekDelta = 0x7e4, +// GreekEpsilon = 0x7e5, +// GreekZeta = 0x7e6, +// GreekEta = 0x7e7, +// GreekTheta = 0x7e8, +// GreekIota = 0x7e9, +// GreekKappa = 0x7ea, +// GreekLamda = 0x7eb, +// GreekLambda = 0x7eb, +// GreekMu = 0x7ec, +// GreekNu = 0x7ed, +// GreekXi = 0x7ee, +// GreekOmicron = 0x7ef, +// GreekPi = 0x7f0, +// GreekRho = 0x7f1, +// GreekSigma = 0x7f2, +// GreekFinalSmallSigma = 0x7f3, +// GreekTau = 0x7f4, +// GreekUpsilon = 0x7f5, +// GreekPhi = 0x7f6, +// GreekChi = 0x7f7, +// GreekPsi = 0x7f8, +// GreekOmega = 0x7f9, +// GreekSwitch = 0xFF7E, +// Leftradical = 0x8a1, +// TopLeftradical = 0x8a2, +// HorizConnector = 0x8a3, +// TopIntegral = 0x8a4, +// BotIntegral = 0x8a5, +// VertConnector = 0x8a6, +// TopLeftsqBracket = 0x8a7, +// BotLeftsqBracket = 0x8a8, +// TopRightsqBracket = 0x8a9, +// BotRightsqBracket = 0x8aa, +// TopLeftParens = 0x8ab, +// BotLeftParens = 0x8ac, +// TopRightParens = 0x8ad, +// BotRightParens = 0x8ae, +// LeftMiddleCurlyBrace = 0x8af, +// RightMiddleCurlyBrace = 0x8b0, +// TopLeftSummation = 0x8b1, +// BotLeftSummation = 0x8b2, +// TopvertSummationConnector = 0x8b3, +// BotvertSummationConnector = 0x8b4, +// TopRightSummation = 0x8b5, +// BotRightSummation = 0x8b6, +// RightMiddleSummation = 0x8b7, +// LessThanEqual = 0x8bc, +// NotEqual = 0x8bd, +// GreaterThanEqual = 0x8be, +// Integral = 0x8bf, +// Therefore = 0x8c0, +// Variation = 0x8c1, +// Infinity = 0x8c2, +// Nabla = 0x8c5, +// Approximate = 0x8c8, +// SimilarEqual = 0x8c9, +// Ifonlyif = 0x8cd, +// Implies = 0x8ce, +// Identical = 0x8cf, +// Radical = 0x8d6, +// Includedin = 0x8da, +// Includes = 0x8db, +// Intersection = 0x8dc, +// Union = 0x8dd, +// Logicaland = 0x8de, +// Logicalor = 0x8df, +// PartialDerivative = 0x8ef, +// Function = 0x8f6, +// Leftarrow = 0x8fb, +// Uparrow = 0x8fc, +// Rightarrow = 0x8fd, +// Downarrow = 0x8fe, +// Blank = 0x9df, +// SolidDiamond = 0x9e0, +// Checkerboard = 0x9e1, +// Ht = 0x9e2, +// Ff = 0x9e3, +// Cr = 0x9e4, +// Lf = 0x9e5, +// Nl = 0x9e8, +// Vt = 0x9e9, +// LowRightCorner = 0x9ea, +// UpRightCorner = 0x9eb, +// UpLeftCorner = 0x9ec, +// LowLeftCorner = 0x9ed, +// CrossingLines = 0x9ee, +// HorizLineScan1 = 0x9ef, +// HorizLineScan3 = 0x9f0, +// HorizLineScan5 = 0x9f1, +// HorizLineScan7 = 0x9f2, +// HorizLineScan9 = 0x9f3, +// Leftt = 0x9f4, +// Rightt = 0x9f5, +// Bott = 0x9f6, +// Topt = 0x9f7, +// Vertbar = 0x9f8, +// EmSpace = 0xaa1, +// EnSpace = 0xaa2, +// Em3Space = 0xaa3, +// Em4Space = 0xaa4, +// DigitSpace = 0xaa5, +// PunctSpace = 0xaa6, +// ThinSpace = 0xaa7, +// HairSpace = 0xaa8, +// Emdash = 0xaa9, +// Endash = 0xaaa, +// Signifblank = 0xaac, +// Ellipsis = 0xaae, +// DoubbaseLineDot = 0xaaf, +// Onethird = 0xab0, +// Twothirds = 0xab1, +// Onefifth = 0xab2, +// Twofifths = 0xab3, +// Threefifths = 0xab4, +// Fourfifths = 0xab5, +// Onesixth = 0xab6, +// Fivesixths = 0xab7, +// Careof = 0xab8, +// Figdash = 0xabb, +// LeftangleBracket = 0xabc, +// Decimalpoint = 0xabd, +// RightangleBracket = 0xabe, +// Marker = 0xabf, +// Oneeighth = 0xac3, +// Threeeighths = 0xac4, +// Fiveeighths = 0xac5, +// Seveneighths = 0xac6, +// Trademark = 0xac9, +// Signaturemark = 0xaca, +// TrademarkinCircle = 0xacb, +// LeftOpenTriangle = 0xacc, +// RightOpenTriangle = 0xacd, +// EmOpenCircle = 0xace, +// EmOpenrectangle = 0xacf, +// LeftsingleQuotemark = 0xad0, +// RightsingleQuotemark = 0xad1, +// LeftDoubleQuotemark = 0xad2, +// RightDoubleQuotemark = 0xad3, +// Prescription = 0xad4, +// Minutes = 0xad6, +// Seconds = 0xad7, +// Latincross = 0xad9, +// Hexagram = 0xada, +// FilledrectBullet = 0xadb, +// FilledLefttriBullet = 0xadc, +// FilledRighttriBullet = 0xadd, +// EmfilledCircle = 0xade, +// Emfilledrect = 0xadf, +// EnOpenCircBullet = 0xae0, +// EnOpensquareBullet = 0xae1, +// OpenrectBullet = 0xae2, +// OpentriBulletUp = 0xae3, +// OpentriBulletDown = 0xae4, +// Openstar = 0xae5, +// EnfilledCircBullet = 0xae6, +// EnfilledsqBullet = 0xae7, +// FilledtriBulletUp = 0xae8, +// FilledtriBulletDown = 0xae9, +// Leftpointer = 0xaea, +// Rightpointer = 0xaeb, +// Club = 0xaec, +// Diamond = 0xaed, +// Heart = 0xaee, +// Maltesecross = 0xaf0, +// Dagger = 0xaf1, +// Doubledagger = 0xaf2, +// Checkmark = 0xaf3, +// Ballotcross = 0xaf4, +// Musicalsharp = 0xaf5, +// Musicalflat = 0xaf6, +// Malesymbol = 0xaf7, +// Femalesymbol = 0xaf8, +// Telephone = 0xaf9, +// Telephonerecorder = 0xafa, +// Phonographcopyright = 0xafb, +// Caret = 0xafc, +// SinglelowQuotemark = 0xafd, +// DoublelowQuotemark = 0xafe, +// Cursor = 0xaff, +// Leftcaret = 0xba3, +// Rightcaret = 0xba6, +// Downcaret = 0xba8, +// Upcaret = 0xba9, +// Overbar = 0xbc0, +// Downtack = 0xbc2, +// Upshoe = 0xbc3, +// Downstile = 0xbc4, +// Underbar = 0xbc6, +// Jot = 0xbca, +// Quad = 0xbcc, +// Uptack = 0xbce, +// Circle = 0xbcf, +// Upstile = 0xbd3, +// Downshoe = 0xbd6, +// Rightshoe = 0xbd8, +// Leftshoe = 0xbda, +// Lefttack = 0xbdc, +// Righttack = 0xbfc, +// HebrewDoublelowLine = 0xcdf, +// HebrewAleph = 0xce0, +// HebrewBet = 0xce1, +// HebrewBeth = 0xce1, +// HebrewGimel = 0xce2, +// HebrewGimmel = 0xce2, +// HebrewDalet = 0xce3, +// HebrewDaleth = 0xce3, +// HebrewHe = 0xce4, +// HebrewWaw = 0xce5, +// HebrewZain = 0xce6, +// HebrewZayin = 0xce6, +// HebrewChet = 0xce7, +// HebrewHet = 0xce7, +// HebrewTet = 0xce8, +// HebrewTeth = 0xce8, +// HebrewYod = 0xce9, +// HebrewFinalkaph = 0xcea, +// HebrewKaph = 0xceb, +// HebrewLamed = 0xcec, +// HebrewFinalmem = 0xced, +// HebrewMem = 0xcee, +// HebrewFinalnun = 0xcef, +// HebrewNun = 0xcf0, +// HebrewSamech = 0xcf1, +// HebrewSamekh = 0xcf1, +// HebrewAyin = 0xcf2, +// HebrewFinalpe = 0xcf3, +// HebrewPe = 0xcf4, +// HebrewFinalzade = 0xcf5, +// HebrewFinalzadi = 0xcf5, +// HebrewZade = 0xcf6, +// HebrewZadi = 0xcf6, +// HebrewQoph = 0xcf7, +// HebrewKuf = 0xcf7, +// HebrewResh = 0xcf8, +// HebrewShin = 0xcf9, +// HebrewTaw = 0xcfa, +// HebrewTaf = 0xcfa, +// HebrewSwitch = 0xFF7E, + +// ModeLock = 0x1008FF01, +// MonBrightnessUp = 0x1008FF02, +// MonBrightnessDown = 0x1008FF03, +// KbdLightOnOff = 0x1008FF04, +// KbdBrightnessUp = 0x1008FF05, +// KbdBrightnessDown = 0x1008FF06, +// Standby = 0x1008FF10, +// AudioLowerVolume = 0x1008FF11, +// AudioMute = 0x1008FF12, +// AudioRaiseVolume = 0x1008FF13, +// AudioPlay = 0x1008FF14, +// AudioStop = 0x1008FF15, +// AudioPrev = 0x1008FF16, +// AudioNext = 0x1008FF17, +// HomePage = 0x1008FF18, +// Mail = 0x1008FF19, +// Start = 0x1008FF1A, +// Search = 0x1008FF1B, +// AudioRecord = 0x1008FF1C, +// Calculator = 0x1008FF1D, +// Memo = 0x1008FF1E, +// ToDoList = 0x1008FF1F, +// Calendar = 0x1008FF20, +// PowerDown = 0x1008FF21, +// ContrastAdjust = 0x1008FF22, +// RockerUp = 0x1008FF23, +// RockerDown = 0x1008FF24, +// RockerEnter = 0x1008FF25, +// Back = 0x1008FF26, +// Forward = 0x1008FF27, +// Stop = 0x1008FF28, +// Refresh = 0x1008FF29, +// PowerOff = 0x1008FF2A, +// WakeUp = 0x1008FF2B, +// Eject = 0x1008FF2C, +// ScreenSaver = 0x1008FF2D, +// Www = 0x1008FF2E, +// Sleep = 0x1008FF2F, +// Favorites = 0x1008FF30, +// AudioPause = 0x1008FF31, +// AudioMedia = 0x1008FF32, +// MyComputer = 0x1008FF33, +// VendorHome = 0x1008FF34, +// LightBulb = 0x1008FF35, +// Shop = 0x1008FF36, +// History = 0x1008FF37, +// OpenUrl = 0x1008FF38, +// AddFavorite = 0x1008FF39, +// HotLinks = 0x1008FF3A, +// BrightnessAdjust = 0x1008FF3B, +// Finance = 0x1008FF3C, +// Community = 0x1008FF3D, +// AudioRewind = 0x1008FF3E, +// BackForward = 0x1008FF3F, +// Launch0 = 0x1008FF40, +// Launch1 = 0x1008FF41, +// Launch2 = 0x1008FF42, +// Launch3 = 0x1008FF43, +// Launch4 = 0x1008FF44, +// Launch5 = 0x1008FF45, +// Launch6 = 0x1008FF46, +// Launch7 = 0x1008FF47, +// Launch8 = 0x1008FF48, +// Launch9 = 0x1008FF49, +// LaunchA = 0x1008FF4A, +// LaunchB = 0x1008FF4B, +// LaunchC = 0x1008FF4C, +// LaunchD = 0x1008FF4D, +// LaunchE = 0x1008FF4E, +// LaunchF = 0x1008FF4F, +// ApplicationLeft = 0x1008FF50, +// ApplicationRight = 0x1008FF51, +// Book = 0x1008FF52, +// Cd = 0x1008FF53, +// Calculater = 0x1008FF54, +// Clear = 0x1008FF55, +// Close = 0x1008FF56, +// Copy = 0x1008FF57, +// Cut = 0x1008FF58, +// Display = 0x1008FF59, +// Dos = 0x1008FF5A, +// Documents = 0x1008FF5B, +// Excel = 0x1008FF5C, +// Explorer = 0x1008FF5D, +// Game = 0x1008FF5E, +// Go = 0x1008FF5F, +// ITouch = 0x1008FF60, +// LogOff = 0x1008FF61, +// Market = 0x1008FF62, +// Meeting = 0x1008FF63, +// MenuKb = 0x1008FF65, +// MenuPb = 0x1008FF66, +// MySites = 0x1008FF67, +// New = 0x1008FF68, +// News = 0x1008FF69, +// OfficeHome = 0x1008FF6A, +// Open = 0x1008FF6B, +// Option = 0x1008FF6C, +// Paste = 0x1008FF6D, +// Phone = 0x1008FF6E, +// Q = 0x1008FF70, +// Reply = 0x1008FF72, +// Reload = 0x1008FF73, +// RotateWindows = 0x1008FF74, +// RotationPb = 0x1008FF75, +// RotationKb = 0x1008FF76, +// Save = 0x1008FF77, +// ScrollUp = 0x1008FF78, +// ScrollDown = 0x1008FF79, +// ScrollClick = 0x1008FF7A, +// Send = 0x1008FF7B, +// Spell = 0x1008FF7C, +// SplitScreen = 0x1008FF7D, +// Support = 0x1008FF7E, +// TasNumPadane = 0x1008FF7F, +// Terminal = 0x1008FF80, +// Tools = 0x1008FF81, +// Travel = 0x1008FF82, +// UserPb = 0x1008FF84, +// User1Kb = 0x1008FF85, +// User2Kb = 0x1008FF86, +// Video = 0x1008FF87, +// WheelButton = 0x1008FF88, +// Word = 0x1008FF89, +// Xfer = 0x1008FF8A, +// ZoomIn = 0x1008FF8B, +// ZoomOut = 0x1008FF8C, +// Away = 0x1008FF8D, +// Messenger = 0x1008FF8E, +// WebCam = 0x1008FF8F, +// MailForward = 0x1008FF90, +// Pictures = 0x1008FF91, +// Music = 0x1008FF92, +// Battery = 0x1008FF93, +// Bluetooth = 0x1008FF94, +// Wlan = 0x1008FF95, +// Uwb = 0x1008FF96, +// AudioForward = 0x1008FF97, +// AudioRepeat = 0x1008FF98, +// AudioRandomPlay = 0x1008FF99, +// Subtitle = 0x1008FF9A, +// AudioCycleTrack = 0x1008FF9B, +// CycleAngle = 0x1008FF9C, +// FrameBack = 0x1008FF9D, +// FrameForward = 0x1008FF9E, +// Time = 0x1008FF9F, +// Select = 0x1008FFA0, +// View = 0x1008FFA1, +// TopMenu = 0x1008FFA2, +// Red = 0x1008FFA3, +// Green = 0x1008FFA4, +// Yellow = 0x1008FFA5, +// Blue = 0x1008FFA6, +// Suspend = 0x1008FFA7, +// Hibernate = 0x1008FFA8, +// TouchpadToggle = 0x1008FFA9, +// TouchpadOn = 0x1008FFB0, +// TouchpadOff = 0x1008FFB1, +// AudioMicMute = 0x1008FFB2, +// SwitchVt1 = 0x1008FE01, +// SwitchVt2 = 0x1008FE02, +// SwitchVt3 = 0x1008FE03, +// SwitchVt4 = 0x1008FE04, +// SwitchVt5 = 0x1008FE05, +// SwitchVt6 = 0x1008FE06, +// SwitchVt7 = 0x1008FE07, +// SwitchVt8 = 0x1008FE08, +// SwitchVt9 = 0x1008FE09, +// SwitchVt10 = 0x1008FE0A, +// SwitchVt11 = 0x1008FE0B, +// SwitchVt12 = 0x1008FE0C, +// Ungrab = 0x1008FE20, +// ClearGrab = 0x1008FE21, +// NextVMode = 0x1008FE22, +// PrevVMode = 0x1008FE23, +// LogWindowTree = 0x1008FE24, +// LogGrabInfo = 0x1008FE25, + +// IsoLock = 0xfe01, +// IsoLevel2Latch = 0xfe02, +// IsoLevel3Shift = 0xfe03, +// IsoLevel3Latch = 0xfe04, +// IsoLevel3Lock = 0xfe05, +// IsoLevel5Shift = 0xfe11, +// IsoLevel5Latch = 0xfe12, +// IsoLevel5Lock = 0xfe13, +// IsoGroupShift = 0xff7e, +// IsoGroupLatch = 0xfe06, +// IsoGroupLock = 0xfe07, +// IsoNextGroup = 0xfe08, +// IsoNextGroupLock = 0xfe09, +// IsoPrevGroup = 0xfe0a, +// IsoPrevGroupLock = 0xfe0b, +// IsoFirstGroup = 0xfe0c, +// IsoFirstGroupLock = 0xfe0d, +// IsoLastGroup = 0xfe0e, +// IsoLastGroupLock = 0xfe0f, + +// IsoLeftTab = 0xfe20, +// IsoMoveLineUp = 0xfe21, +// IsoMoveLineDown = 0xfe22, +// IsoPartialLineUp = 0xfe23, +// IsoPartialLineDown = 0xfe24, +// IsoPartialSpaceLeft = 0xfe25, +// IsoPartialSpaceRight = 0xfe26, +// IsoSetMarginLeft = 0xfe27, +// IsoSetMarginRight = 0xfe28, +// IsoReleaseMarginLeft = 0xfe29, +// IsoReleaseMarginRight = 0xfe2a, +// IsoReleaseBothMargins = 0xfe2b, +// IsoFastCursorLeft = 0xfe2c, +// IsoFastCursorRight = 0xfe2d, +// IsoFastCursorUp = 0xfe2e, +// IsoFastCursorDown = 0xfe2f, +// IsoContinuousUnderline = 0xfe30, +// IsoDiscontinuousUnderline = 0xfe31, +// IsoEmphasize = 0xfe32, +// IsoCenterObject = 0xfe33, +// IsoEnter = 0xfe34, + +// DeadGrave = 0xfe50, +// DeadAcute = 0xfe51, +// DeadCircumflex = 0xfe52, +// DeadTilde = 0xfe53, +// DeadPerispomeni = 0xfe53, +// DeadMacron = 0xfe54, +// DeadBreve = 0xfe55, +// DeadAboveDot = 0xfe56, +// DeadDiaeresis = 0xfe57, +// DeadAbovering = 0xfe58, +// DeadDoubleAcute = 0xfe59, +// DeadCaron = 0xfe5a, +// DeadCedilla = 0xfe5b, +// DeadOgonek = 0xfe5c, +// DeadIota = 0xfe5d, +// DeadVoicedSound = 0xfe5e, +// DeadSemivoicedSound = 0xfe5f, +// DeadBelowDot = 0xfe60, +// DeadHook = 0xfe61, +// DeadHorn = 0xfe62, +// DeadStroke = 0xfe63, +// DeadAboveComma = 0xfe64, +// DeadPsili = 0xfe64, +// DeadAbovereversedComma = 0xfe65, +// DeadDoublegrave = 0xfe66, +// DeadBelowring = 0xfe67, +// DeadBelowmacron = 0xfe68, +// DeadBelowCircumflex = 0xfe69, +// DeadBelowTilde = 0xfe6a, +// DeadBelowbreve = 0xfe6b, +// DeadBelowdiaeresis = 0xfe6c, +// DeadInvertedbreve = 0xfe6d, +// DeadBelowComma = 0xfe6e, +// DeadCurrency = 0xfe6f, + +// DeadLowLine = 0xfe90, +// DeadAboveVerticalLine = 0xfe91, +// DeadBelowVerticalLine = 0xfe92, +// DeadLongsolidusoverlay = 0xfe93, + +// DeadA = 0xfe80, +// DeadA = 0xfe81, +// DeadE = 0xfe82, +// DeadE = 0xfe83, +// DeadI = 0xfe84, +// DeadI = 0xfe85, +// DeadO = 0xfe86, +// DeadO = 0xfe87, +// DeadU = 0xfe88, +// DeadU = 0xfe89, +// DeadSmallSchwa = 0xfe8a, +// DeadCapitalSchwa = 0xfe8b, + +// DeadGreek = 0xfe8c, + +// FirstVirtualScreen = 0xfed0, +// PrevVirtualScreen = 0xfed1, +// NextVirtualScreen = 0xfed2, +// LastVirtualScreen = 0xfed4, +// TerminateServer = 0xfed5, + +// AccessXEnable = 0xfe70, +// AccessXFeedbackEnable = 0xfe71, +// RepeatKeysEnable = 0xfe72, +// SlowKeysEnable = 0xfe73, +// BounceKeysEnable = 0xfe74, +// StickyKeysEnable = 0xfe75, +// MouseKeysEnable = 0xfe76, +// MouseKeysAccelEnable = 0xfe77, +// Overlay1Enable = 0xfe78, +// Overlay2Enable = 0xfe79, +// AudibleBellEnable = 0xfe7a, + +// PointerLeft = 0xfee0, +// PointerRight = 0xfee1, +// PointerUp = 0xfee2, +// PointerDown = 0xfee3, +// PointerUpLeft = 0xfee4, +// PointerUpRight = 0xfee5, +// PointerDownLeft = 0xfee6, +// PointerDownRight = 0xfee7, +// PointerButtonDflt = 0xfee8, +// PointerButton1 = 0xfee9, +// PointerButton2 = 0xfeea, +// PointerButton3 = 0xfeeb, +// PointerButton4 = 0xfeec, +// PointerButton5 = 0xfeed, +// PointerDblClickDflt = 0xfeee, +// PointerDblClick1 = 0xfeef, +// PointerDblClick2 = 0xfef0, +// PointerDblClick3 = 0xfef1, +// PointerDblClick4 = 0xfef2, +// PointerDblClick5 = 0xfef3, +// PointerDragDflt = 0xfef4, +// PointerDrag1 = 0xfef5, +// PointerDrag2 = 0xfef6, +// PointerDrag3 = 0xfef7, +// PointerDrag4 = 0xfef8, +// PointerDrag5 = 0xfefd, + +// PointerEnableKeys = 0xfef9, +// PointerAccelerate = 0xfefa, +// PointerDfltBtnNext = 0xfefb, +// PointerDfltBtnPrev = 0xfefc, + +// Ch0 = 0xfea0, +// Ch1 = 0xfea1, +// Ch2 = 0xfea2, +// Ch3 = 0xfea3, +// Ch4 = 0xfea4, +// Ch5 = 0xfea5, +// } diff --git a/hotkey/src/linux/mod.rs b/hotkey/src/linux/mod.rs new file mode 100644 index 00000000..562d5353 --- /dev/null +++ b/hotkey/src/linux/mod.rs @@ -0,0 +1,230 @@ +extern crate x11_dl; +extern crate mio; +extern crate promising_future; + +mod key_code; +pub use self::key_code::KeyCode; + +use self::x11_dl::xlib::{Xlib, XKeyEvent, Display, GrabModeAsync, KeyPressMask, KeyPress, Mod2Mask, + XErrorEvent}; +use std::{ptr, mem}; +use std::collections::hash_map::{Entry, HashMap}; +use std::sync::mpsc::{channel, Sender}; +use self::mio::{Events, Poll, Token, PollOpt, Ready, Registration, SetReadiness}; +use self::mio::unix::EventedFd; +use std::thread::{self, JoinHandle}; +use std::os::raw::{c_ulong, c_int, c_uint}; +use self::promising_future::{Promise, future_promise}; + +quick_error! { + #[derive(Debug)] + pub enum Error { + NoXLib {} + OpenXServerConnection {} + EPoll {} + ThreadStopped {} + AlreadyRegistered {} + NotRegistered {} + } +} + +pub type Result = ::std::result::Result; + +enum Message { + Register(KeyCode, Box, Promise>), + Unregister(KeyCode, Promise>), + End, +} + +pub struct Hook { + sender: Sender, + ping: SetReadiness, + _registration: Registration, + join_handle: Option>>, +} + +impl Drop for Hook { + fn drop(&mut self) { + self.sender.send(Message::End).ok(); + self.ping.set_readiness(Ready::readable()).ok(); + if let Some(handle) = self.join_handle.take() { + handle.join().ok(); + } + } +} + +unsafe fn unregister(xlib: &Xlib, display: *mut Display, window: c_ulong, code: c_uint) { + (xlib.XUngrabKey)(display, code as _, 0, window); + (xlib.XUngrabKey)(display, code as _, Mod2Mask, window); +} + +unsafe extern "C" fn handle_error(_: *mut Display, _: *mut XErrorEvent) -> c_int { + 0 +} + +impl Hook { + pub fn new() -> Result { + unsafe { + let (sender, receiver) = channel(); + + let xlib = Xlib::open().map_err(|_| Error::NoXLib)?; + (xlib.XSetErrorHandler)(Some(handle_error)); + + let display = (xlib.XOpenDisplay)(ptr::null()); + if display.is_null() { + return Err(Error::OpenXServerConnection); + } + + let window = (xlib.XDefaultRootWindow)(display); + (xlib.XSelectInput)(display, window, KeyPressMask); + + let fd = (xlib.XConnectionNumber)(display); + let poll = Poll::new().map_err(|_| Error::EPoll)?; + + let (registration, ping) = Registration::new2(); + + const X_TOKEN: Token = Token(0); + const PING_TOKEN: Token = Token(1); + + poll.register(&EventedFd(&fd), + X_TOKEN, + Ready::readable() | Ready::writable(), + PollOpt::edge()) + .map_err(|_| Error::EPoll)?; + + poll.register(®istration, + PING_TOKEN, + Ready::readable(), + PollOpt::edge()) + .map_err(|_| Error::EPoll)?; + + struct XData(Xlib, *mut Display, c_ulong); + unsafe impl Send for XData {} + let xdata = XData(xlib, display, window); + + let join_handle = thread::spawn(move || -> Result<()> { + let XData(xlib, display, window) = xdata; + + let mut result = Ok(()); + let mut events = Events::with_capacity(1024); + let mut event = mem::uninitialized(); + let mut hotkeys = HashMap::new(); + + 'event_loop: loop { + if poll.poll(&mut events, None).is_err() { + result = Err(Error::EPoll); + break 'event_loop; + } + + for mio_event in &events { + if mio_event.token() == PING_TOKEN { + for message in receiver.try_iter() { + match message { + Message::Register(key, callback, promise) => { + let code = (xlib.XKeysymToKeycode)(display, key as _) as + c_uint; + + if let Entry::Vacant(vacant) = hotkeys.entry(code) { + (xlib.XGrabKey)(display, + code as _, + 0, + window, + false as _, + GrabModeAsync, + GrabModeAsync); + + (xlib.XGrabKey)(display, + code as _, + Mod2Mask, + window, + false as _, + GrabModeAsync, + GrabModeAsync); + + vacant.insert(callback); + promise.set(Ok(())); + } else { + promise.set(Err(Error::AlreadyRegistered)); + } + } + Message::Unregister(key, promise) => { + let code = (xlib.XKeysymToKeycode)(display, key as _) as + c_uint; + + if hotkeys.remove(&code).is_some() { + unregister(&xlib, display, window, code); + promise.set(Ok(())); + } else { + promise.set(Err(Error::NotRegistered)); + } + } + Message::End => { + break 'event_loop; + } + } + } + } else if mio_event.token() == X_TOKEN { + while (xlib.XPending)(display) != 0 { + (xlib.XNextEvent)(display, &mut event); + if event.get_type() == KeyPress { + let event: &XKeyEvent = event.as_ref(); + if let Some(callback) = hotkeys.get_mut(&event.keycode) { + callback(); + } + } + } + } + } + } + + for (code, _) in hotkeys { + unregister(&xlib, display, window, code); + } + + (xlib.XCloseDisplay)(display); + + result + }); + + Ok(Hook { + sender: sender, + ping: ping, + _registration: registration, + join_handle: Some(join_handle), + }) + } + } + + pub fn register(&self, hotkey: KeyCode, callback: F) -> Result<()> + where F: FnMut() + Send + 'static + { + let (future, promise) = future_promise(); + + self.sender + .send(Message::Register(hotkey, Box::new(callback), promise)) + .map_err(|_| Error::ThreadStopped)?; + + self.ping.set_readiness(Ready::readable()).map_err(|_| Error::ThreadStopped)?; + + future.value().ok_or(Error::ThreadStopped)? + } + + pub fn unregister(&self, hotkey: KeyCode) -> Result<()> { + let (future, promise) = future_promise(); + + self.sender.send(Message::Unregister(hotkey, promise)).map_err(|_| Error::ThreadStopped)?; + self.ping.set_readiness(Ready::readable()).map_err(|_| Error::ThreadStopped)?; + + future.value().ok_or(Error::ThreadStopped)? + } +} + +#[test] +fn test() { + let hook = Hook::new().unwrap(); + hook.register(KeyCode::NumPad0, || println!("A")).unwrap(); + thread::sleep(::std::time::Duration::from_secs(5)); + hook.unregister(KeyCode::NumPad0).unwrap(); + hook.register(KeyCode::NumPad1, || println!("B")).unwrap(); + thread::sleep(::std::time::Duration::from_secs(5)); +} diff --git a/hotkey/src/other/mod.rs b/hotkey/src/other/mod.rs index d1bf004f..3fbf132c 100644 --- a/hotkey/src/other/mod.rs +++ b/hotkey/src/other/mod.rs @@ -1,13 +1,28 @@ -use KeyEvent; +quick_error! { + #[derive(Debug)] + pub enum Error { + } +} + +pub type Result = ::std::result::Result; #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)] pub struct KeyCode; pub struct Hook; -pub fn register_hook(callback: F) -> Result - where F: FnMut(KeyEvent) + Send + 'static -{ - drop(callback); - Ok(Hook) +impl Hook { + pub fn new() -> Result { + Ok(Hook) + } + + pub fn register(&self, _: KeyCode, _: F) -> Result<()> + where F: FnMut() + Send + 'static + { + Ok(()) + } + + pub fn unregister(&self, _: KeyCode) -> Result<()> { + Ok(()) + } } diff --git a/hotkey/src/windows/key_code.rs b/hotkey/src/windows/key_code.rs new file mode 100644 index 00000000..231f1abc --- /dev/null +++ b/hotkey/src/windows/key_code.rs @@ -0,0 +1,174 @@ +#[repr(u8)] +#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)] +pub enum KeyCode { + LButton = 0x01, + RButton = 0x02, + Cancel = 0x03, + MButton = 0x04, + XButton1 = 0x05, + XButton2 = 0x06, + Back = 0x08, + Tab = 0x09, + Clear = 0x0C, + Return = 0x0D, + Shift = 0x10, + Control = 0x11, + Menu = 0x12, + Pause = 0x13, + Capital = 0x14, + Kana = 0x15, + Junja = 0x17, + Final = 0x18, + Kanji = 0x19, + Escape = 0x1B, + Convert = 0x1C, + NonConvert = 0x1D, + Accept = 0x1E, + ModeChange = 0x1F, + Space = 0x20, + Prior = 0x21, + Next = 0x22, + End = 0x23, + Home = 0x24, + Left = 0x25, + Up = 0x26, + Right = 0x27, + Down = 0x28, + Select = 0x29, + Print = 0x2A, + Execute = 0x2B, + Snapshot = 0x2C, + Insert = 0x2D, + Delete = 0x2E, + Help = 0x2F, + D0 = 0x30, + D1 = 0x31, + D2 = 0x32, + D3 = 0x33, + D4 = 0x34, + D5 = 0x35, + D6 = 0x36, + D7 = 0x37, + D8 = 0x38, + D9 = 0x39, + A = 0x41, + B = 0x42, + C = 0x43, + D = 0x44, + E = 0x45, + F = 0x46, + G = 0x47, + H = 0x48, + I = 0x49, + J = 0x4A, + K = 0x4B, + L = 0x4C, + M = 0x4D, + N = 0x4E, + O = 0x4F, + P = 0x50, + Q = 0x51, + R = 0x52, + S = 0x53, + T = 0x54, + U = 0x55, + V = 0x56, + W = 0x57, + X = 0x58, + Y = 0x59, + Z = 0x5A, + LeftWin = 0x5B, + RightWin = 0x5C, + Apps = 0x5D, + Sleep = 0x5F, + NumPad0 = 0x60, + NumPad1 = 0x61, + NumPad2 = 0x62, + NumPad3 = 0x63, + NumPad4 = 0x64, + NumPad5 = 0x65, + NumPad6 = 0x66, + NumPad7 = 0x67, + NumPad8 = 0x68, + NumPad9 = 0x69, + Multiply = 0x6A, + Add = 0x6B, + Separator = 0x6C, + Subtract = 0x6D, + Decimal = 0x6E, + Divide = 0x6F, + F1 = 0x70, + F2 = 0x71, + F3 = 0x72, + F4 = 0x73, + F5 = 0x74, + F6 = 0x75, + F7 = 0x76, + F8 = 0x77, + F9 = 0x78, + F10 = 0x79, + F11 = 0x7A, + F12 = 0x7B, + F13 = 0x7C, + F14 = 0x7D, + F15 = 0x7E, + F16 = 0x7F, + F17 = 0x80, + F18 = 0x81, + F19 = 0x82, + F20 = 0x83, + F21 = 0x84, + F22 = 0x85, + F23 = 0x86, + F24 = 0x87, + NumLock = 0x90, + Scroll = 0x91, + LeftShift = 0xA0, + RightShift = 0xA1, + LeftControl = 0xA2, + RightControl = 0xA3, + LeftMenu = 0xA4, + RightMenu = 0xA5, + BrowserBack = 0xA6, + BrowserForward = 0xA7, + BrowserRefresh = 0xA8, + BrowserStop = 0xA9, + BrowserSearch = 0xAA, + BrowserFavorites = 0xAB, + BrowserHome = 0xAC, + VolumeMute = 0xAD, + VolumeDown = 0xAE, + VolumeUp = 0xAF, + MediaNextTrack = 0xB0, + MediaPrevTrack = 0xB1, + MediaStop = 0xB2, + MediaPlayPause = 0xB3, + LaunchMail = 0xB4, + LaunchMediaSelect = 0xB5, + LaunchApp1 = 0xB6, + LaunchApp2 = 0xB7, + Oem1 = 0xBA, + OemPlus = 0xBB, + OemComma = 0xBC, + OemMinus = 0xBD, + OemPeriod = 0xBE, + Oem2 = 0xBF, + Oem3 = 0xC0, + Oem4 = 0xDB, + Oem5 = 0xDC, + Oem6 = 0xDD, + Oem7 = 0xDE, + Oem8 = 0xDF, + Oem102 = 0xE2, + ProcessKey = 0xE5, + Packet = 0xE7, + Attn = 0xF6, + CrSel = 0xF7, + ExSel = 0xF8, + ErEof = 0xF9, + Play = 0xFA, + Zoom = 0xFB, + NoName = 0xFC, + Pa1 = 0xFD, + OemClear = 0xFE, +} diff --git a/hotkey/src/windows/mod.rs b/hotkey/src/windows/mod.rs index 284f0508..318774ba 100644 --- a/hotkey/src/windows/mod.rs +++ b/hotkey/src/windows/mod.rs @@ -1,196 +1,41 @@ extern crate winapi; extern crate kernel32; extern crate user32; +extern crate parking_lot; + +mod key_code; +pub use self::key_code::KeyCode; use std::cell::RefCell; use std::{ptr, mem, thread}; use std::sync::mpsc::{channel, Sender}; -use self::winapi::{c_int, WPARAM, LPARAM, LRESULT, WH_KEYBOARD_LL, HHOOK, WM_KEYDOWN, WM_KEYUP, +use self::winapi::{c_int, WPARAM, LPARAM, LRESULT, WH_KEYBOARD_LL, HHOOK, WM_KEYDOWN, KBDLLHOOKSTRUCT, UINT, DWORD}; use self::user32::{CallNextHookEx, UnhookWindowsHookEx, SetWindowsHookExW, GetMessageW, PostThreadMessageW}; use self::kernel32::{GetModuleHandleW, GetCurrentThreadId}; -use KeyEvent; +use std::sync::Arc; +use std::collections::hash_map::{Entry, HashMap}; +use self::parking_lot::Mutex; const MSG_EXIT: UINT = 0x400; -#[repr(u8)] -#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)] -pub enum KeyCode { - LButton = 0x01, - RButton = 0x02, - Cancel = 0x03, - MButton = 0x04, - XButton1 = 0x05, - XButton2 = 0x06, - Back = 0x08, - Tab = 0x09, - Clear = 0x0C, - Return = 0x0D, - Shift = 0x10, - Control = 0x11, - Menu = 0x12, - Pause = 0x13, - Capital = 0x14, - Kana = 0x15, - Junja = 0x17, - Final = 0x18, - Kanji = 0x19, - Escape = 0x1B, - Convert = 0x1C, - NonConvert = 0x1D, - Accept = 0x1E, - ModeChange = 0x1F, - Space = 0x20, - Prior = 0x21, - Next = 0x22, - End = 0x23, - Home = 0x24, - Left = 0x25, - Up = 0x26, - Right = 0x27, - Down = 0x28, - Select = 0x29, - Print = 0x2A, - Execute = 0x2B, - Snapshot = 0x2C, - Insert = 0x2D, - Delete = 0x2E, - Help = 0x2F, - Num0 = 0x30, - Num1 = 0x31, - Num2 = 0x32, - Num3 = 0x33, - Num4 = 0x34, - Num5 = 0x35, - Num6 = 0x36, - Num7 = 0x37, - Num8 = 0x38, - Num9 = 0x39, - A = 0x41, - B = 0x42, - C = 0x43, - D = 0x44, - E = 0x45, - F = 0x46, - G = 0x47, - H = 0x48, - I = 0x49, - J = 0x4A, - K = 0x4B, - L = 0x4C, - M = 0x4D, - N = 0x4E, - O = 0x4F, - P = 0x50, - Q = 0x51, - R = 0x52, - S = 0x53, - T = 0x54, - U = 0x55, - V = 0x56, - W = 0x57, - X = 0x58, - Y = 0x59, - Z = 0x5A, - LWin = 0x5B, - RWin = 0x5C, - Apps = 0x5D, - Sleep = 0x5F, - NumPad0 = 0x60, - NumPad1 = 0x61, - NumPad2 = 0x62, - NumPad3 = 0x63, - NumPad4 = 0x64, - NumPad5 = 0x65, - NumPad6 = 0x66, - NumPad7 = 0x67, - NumPad8 = 0x68, - NumPad9 = 0x69, - Multiply = 0x6A, - Add = 0x6B, - Separator = 0x6C, - Subtract = 0x6D, - Decimal = 0x6E, - Divide = 0x6F, - F1 = 0x70, - F2 = 0x71, - F3 = 0x72, - F4 = 0x73, - F5 = 0x74, - F6 = 0x75, - F7 = 0x76, - F8 = 0x77, - F9 = 0x78, - F10 = 0x79, - F11 = 0x7A, - F12 = 0x7B, - F13 = 0x7C, - F14 = 0x7D, - F15 = 0x7E, - F16 = 0x7F, - F17 = 0x80, - F18 = 0x81, - F19 = 0x82, - F20 = 0x83, - F21 = 0x84, - F22 = 0x85, - F23 = 0x86, - F24 = 0x87, - NumLock = 0x90, - Scroll = 0x91, - LShift = 0xA0, - RShift = 0xA1, - LControl = 0xA2, - RControl = 0xA3, - LMenu = 0xA4, - RMenu = 0xA5, - BrowserBack = 0xA6, - BrowserForward = 0xA7, - BrowserRefresh = 0xA8, - BrowserStop = 0xA9, - BrowserSearch = 0xAA, - BrowserFavorites = 0xAB, - BrowserHome = 0xAC, - VolumeMute = 0xAD, - VolumeDown = 0xAE, - VolumeUp = 0xAF, - MediaNextTrack = 0xB0, - MediaPrevTrack = 0xB1, - MediaStop = 0xB2, - MediaPlayPause = 0xB3, - LaunchMail = 0xB4, - LaunchMediaSelect = 0xB5, - LaunchApp1 = 0xB6, - LaunchApp2 = 0xB7, - Oem1 = 0xBA, - OemPlus = 0xBB, - OemComma = 0xBC, - OemMinus = 0xBD, - OemPeriod = 0xBE, - Oem2 = 0xBF, - Oem3 = 0xC0, - Oem4 = 0xDB, - Oem5 = 0xDC, - Oem6 = 0xDD, - Oem7 = 0xDE, - Oem8 = 0xDF, - Oem102 = 0xE2, - ProcessKey = 0xE5, - Packet = 0xE7, - Attn = 0xF6, - CrSel = 0xF7, - ExSel = 0xF8, - ErEof = 0xF9, - Play = 0xFA, - Zoom = 0xFB, - NoName = 0xFC, - Pa1 = 0xFD, - OemClear = 0xFE, +quick_error! { + #[derive(Debug)] + pub enum Error { + AlreadyRegistered {} + NotRegistered {} + WindowsHook {} + ThreadStopped {} + MessageLoop {} + } } +pub type Result = ::std::result::Result; + pub struct Hook { thread_id: DWORD, + hotkeys: Arc>>>, } impl Drop for Hook { @@ -203,7 +48,7 @@ impl Drop for Hook { struct State { hook: HHOOK, - events: Sender, + events: Sender, } thread_local! { @@ -220,10 +65,8 @@ unsafe extern "system" fn callback_proc(code: c_int, wparam: WPARAM, lparam: LPA let event = wparam as UINT; if event == WM_KEYDOWN { state.events - .send(KeyEvent::KeyDown(key_code)) + .send(key_code) .expect("Callback Thread disconnected"); - } else if event == WM_KEYUP { - state.events.send(KeyEvent::KeyUp(key_code)).expect("Callback Thread disconnected"); } } @@ -231,64 +74,103 @@ unsafe extern "system" fn callback_proc(code: c_int, wparam: WPARAM, lparam: LPA }) } -pub fn register_hook(mut callback: F) -> Result - where F: FnMut(KeyEvent) + Send + 'static -{ - let (initialized_tx, initialized_rx) = channel(); - let (events_tx, events_rx) = channel(); - - thread::spawn(move || { - let mut hook = ptr::null_mut(); - - STATE.with(|state| { - hook = unsafe { - SetWindowsHookExW(WH_KEYBOARD_LL, - Some(callback_proc), - GetModuleHandleW(ptr::null()), - 0) - }; - - if hook != ptr::null_mut() { - initialized_tx.send(Ok(unsafe { GetCurrentThreadId() })) - .map_err(|_| ())?; +impl Hook { + pub fn new() -> Result { + let hotkeys = + Arc::new(Mutex::new(HashMap::>::new())); + + let (initialized_tx, initialized_rx) = channel(); + let (events_tx, events_rx) = channel(); + + thread::spawn(move || { + let mut hook = ptr::null_mut(); + + STATE.with(|state| { + hook = unsafe { + SetWindowsHookExW(WH_KEYBOARD_LL, + Some(callback_proc), + GetModuleHandleW(ptr::null()), + 0) + }; + + if hook != ptr::null_mut() { + initialized_tx.send(Ok(unsafe { GetCurrentThreadId() })) + .map_err(|_| Error::ThreadStopped)?; + } else { + initialized_tx.send(Err(Error::WindowsHook)) + .map_err(|_| Error::ThreadStopped)?; + } + + *state.borrow_mut() = Some(State { + hook: hook, + events: events_tx, + }); + + Ok(()) + })?; + + let mut msg = unsafe { mem::uninitialized() }; + loop { + let ret = unsafe { GetMessageW(&mut msg, ptr::null_mut(), 0, 0) }; + + if msg.message == MSG_EXIT { + break; + } else if ret < 0 { + return Err(Error::MessageLoop); } else { - initialized_tx.send(Err(())).map_err(|_| ())?; + break; } + } - *state.borrow_mut() = Some(State { - hook: hook, - events: events_tx, - }); + unsafe { + UnhookWindowsHookEx(hook); + } - Ok(()) - })?; + Ok(()) + }); - let mut msg = unsafe { mem::uninitialized() }; - loop { - let ret = unsafe { GetMessageW(&mut msg, ptr::null_mut(), 0, 0) }; + let hotkey_map = hotkeys.clone(); - if msg.message == MSG_EXIT { - break; - } else if ret < 0 { - return Err(()); - } else { - break; + thread::spawn(move || while let Ok(key) = events_rx.recv() { + if let Some(callback) = hotkey_map.lock().get_mut(&key) { + callback(); } - } + }); - unsafe { - UnhookWindowsHookEx(hook); - } - - Ok(()) - }); + let thread_id = initialized_rx.recv().map_err(|_| Error::ThreadStopped)??; + Ok(Hook { + thread_id: thread_id, + hotkeys: hotkeys, + }) + } - thread::spawn(move || while let Ok(event) = events_rx.recv() { - callback(event); - }); + pub fn register(&self, hotkey: KeyCode, callback: F) -> Result<()> + where F: FnMut() + Send + 'static + { + if let Entry::Vacant(vacant) = self.hotkeys.lock().entry(hotkey) { + vacant.insert(Box::new(callback)); + Ok(()) + } else { + Err(Error::AlreadyRegistered) + } + } - let thread_id = initialized_rx.recv().map_err(|_| ())??; + pub fn unregister(&self, hotkey: KeyCode) -> Result<()> { + if self.hotkeys.lock().remove(&hotkey).is_some() { + Ok(()) + } else { + Err(Error::NotRegistered) + } + } +} - Ok(Hook { thread_id: thread_id }) +#[test] +fn test() { + let hook = Hook::new().unwrap(); + hook.register(KeyCode::NumPad0, || println!("A")).unwrap(); + thread::sleep(::std::time::Duration::from_secs(5)); + hook.unregister(KeyCode::NumPad0).unwrap(); + hook.register(KeyCode::NumPad1, || println!("B")).unwrap(); + thread::sleep(::std::time::Duration::from_secs(5)); } diff --git a/src/hotkey_config.rs b/src/hotkey_config.rs index c605795c..5ab9fee5 100644 --- a/src/hotkey_config.rs +++ b/src/hotkey_config.rs @@ -1,6 +1,4 @@ use hotkey::KeyCode; -use std::sync::Arc; -use parking_lot::RwLock; #[derive(Debug, Eq, PartialEq, Hash)] pub struct HotkeyConfig { @@ -13,15 +11,7 @@ pub struct HotkeyConfig { pub next_comparison: KeyCode, } -pub type SharedHotkeyConfig = Arc>; - -impl HotkeyConfig { - pub fn into_shared(self) -> SharedHotkeyConfig { - Arc::new(RwLock::new(self)) - } -} - -#[cfg(windows)] +#[cfg(any(windows, target_os = "linux"))] impl Default for HotkeyConfig { fn default() -> Self { use hotkey::KeyCode::*; @@ -37,7 +27,7 @@ impl Default for HotkeyConfig { } } -#[cfg(not(any(windows)))] +#[cfg(not(any(windows, target_os = "linux")))] impl Default for HotkeyConfig { fn default() -> Self { Self { diff --git a/src/hotkey_system.rs b/src/hotkey_system.rs index 49808974..86e966e3 100644 --- a/src/hotkey_system.rs +++ b/src/hotkey_system.rs @@ -1,48 +1,113 @@ -use {SharedTimer, HotkeyConfig, SharedHotkeyConfig}; -use hotkey::{register_hook, Hook, KeyEvent}; -use parking_lot::{RwLockReadGuard, RwLockWriteGuard}; +use {SharedTimer, HotkeyConfig}; +use hotkey::{Hook, KeyCode}; +pub use hotkey::{Result, Error}; pub struct HotkeySystem { - config: SharedHotkeyConfig, - _hook: Hook, + config: HotkeyConfig, + hook: Hook, + timer: SharedTimer, } impl HotkeySystem { - pub fn new(timer: SharedTimer) -> Result { + pub fn new(timer: SharedTimer) -> Result { Self::with_config(timer, Default::default()) } - pub fn with_config(timer: SharedTimer, config: HotkeyConfig) -> Result { - let config = config.into_shared(); + pub fn with_config(timer: SharedTimer, config: HotkeyConfig) -> Result { + let hook = Hook::new()?; + + let inner = timer.clone(); + hook.register(config.split, move || { inner.write().split(); })?; + + let inner = timer.clone(); + hook.register(config.reset, move || { inner.write().reset(true); })?; + + let inner = timer.clone(); + hook.register(config.undo, move || { inner.write().undo_split(); })?; + + let inner = timer.clone(); + hook.register(config.skip, move || { inner.write().skip_split(); })?; + + let inner = timer.clone(); + hook.register(config.pause, move || { inner.write().pause(); })?; + + let inner = timer.clone(); + hook.register(config.previous_comparison, + move || { inner.write().switch_to_previous_comparison(); })?; + + let inner = timer.clone(); + hook.register(config.next_comparison, + move || { inner.write().switch_to_next_comparison(); })?; Ok(Self { - config: config.clone(), - _hook: register_hook(move |k| if let KeyEvent::KeyDown(k) = k { - let config = config.read(); - if k == config.split { - timer.write().split(); - } else if k == config.reset { - timer.write().reset(true); - } else if k == config.undo { - timer.write().undo_split(); - } else if k == config.skip { - timer.write().skip_split(); - } else if k == config.pause { - timer.write().pause(); - } else if k == config.previous_comparison { - timer.write().switch_to_previous_comparison(); - } else if k == config.next_comparison { - timer.write().switch_to_next_comparison(); - } - })?, + config: config, + hook: hook, + timer: timer, }) } - pub fn read_config(&self) -> RwLockReadGuard { - self.config.read() + // TODO Ignore errors in a lot of situations + // If unregister works and register fails for example, + // you won't be able to register again, as unregistering will fail forever. + // Also in initial start up code ignore partially failed registers. + + pub fn set_split(&mut self, hotkey: KeyCode) -> Result<()> { + self.hook.unregister(self.config.split)?; + let inner = self.timer.clone(); + self.hook.register(hotkey, move || { inner.write().split(); })?; + self.config.split = hotkey; + Ok(()) + } + + pub fn set_reset(&mut self, hotkey: KeyCode) -> Result<()> { + self.hook.unregister(self.config.reset)?; + let inner = self.timer.clone(); + self.hook.register(hotkey, move || { inner.write().reset(true); })?; + self.config.reset = hotkey; + Ok(()) + } + + pub fn set_pause(&mut self, hotkey: KeyCode) -> Result<()> { + self.hook.unregister(self.config.pause)?; + let inner = self.timer.clone(); + self.hook.register(hotkey, move || { inner.write().pause(); })?; + self.config.pause = hotkey; + Ok(()) + } + + pub fn set_skip(&mut self, hotkey: KeyCode) -> Result<()> { + self.hook.unregister(self.config.skip)?; + let inner = self.timer.clone(); + self.hook.register(hotkey, move || { inner.write().skip_split(); })?; + self.config.skip = hotkey; + Ok(()) + } + + pub fn set_undo(&mut self, hotkey: KeyCode) -> Result<()> { + self.hook.unregister(self.config.undo)?; + let inner = self.timer.clone(); + self.hook.register(hotkey, move || { inner.write().undo_split(); })?; + self.config.undo = hotkey; + Ok(()) + } + + pub fn set_previous_comparison(&mut self, hotkey: KeyCode) -> Result<()> { + self.hook.unregister(self.config.previous_comparison)?; + let inner = self.timer.clone(); + self.hook + .register(hotkey, + move || { inner.write().switch_to_previous_comparison(); })?; + self.config.previous_comparison = hotkey; + Ok(()) } - pub fn write_config(&self) -> RwLockWriteGuard { - self.config.write() + pub fn set_next_comparison(&mut self, hotkey: KeyCode) -> Result<()> { + self.hook.unregister(self.config.next_comparison)?; + let inner = self.timer.clone(); + self.hook + .register(hotkey, + move || { inner.write().switch_to_next_comparison(); })?; + self.config.next_comparison = hotkey; + Ok(()) } } diff --git a/src/lib.rs b/src/lib.rs index 18ed1ff4..66a88af7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,5 +61,5 @@ pub use self::time_stamp::TimeStamp; pub use self::timer::{Timer, SharedTimer}; pub use self::timer_phase::TimerPhase; pub use self::timing_method::TimingMethod; -pub use self::hotkey_config::{HotkeyConfig, SharedHotkeyConfig}; +pub use self::hotkey_config::HotkeyConfig; pub use self::hotkey_system::HotkeySystem;