public X11Keyboard() { Debug.WriteLine("Using X11Keyboard."); state.IsConnected = true; var display = API.DefaultDisplay; using (new XLock(display)) { // Find the number of keysyms per keycode. int first = 0, last = 0; API.DisplayKeycodes(display, ref first, ref last); var keysym_ptr = API.GetKeyboardMapping(display, (byte)first, last - first + 1, ref KeysymsPerKeycode); Functions.XFree(keysym_ptr); if (Xkb.IsSupported(display)) { // Request that auto-repeat is only set on devices that support it physically. // This typically means that it's turned off for keyboards what we want). // We prefer this method over XAutoRepeatOff/On, because the latter needs to // be reset before the program exits. bool supported; Xkb.SetDetectableAutoRepeat(display, true, out supported); KeyMap = new X11KeyMap(display); } } }
internal X11KeyMap(IntPtr display) { xkb_supported = Xkb.IsSupported(display); if (xkb_supported) { RefreshKeycodes(display); } }
bool TranslateKeyXkb(IntPtr display, int keycode, out Key key) { if (keycode < 8 || keycode > 255) { key = Key.Unknown; return(false); } // Translate the numeric keypad using the secondary group // (equivalent to NumLock = on) XKey keysym = Xkb.KeycodeToKeysym(display, keycode, 0, 1); switch (keysym) { case XKey.KP_0: key = Key.Keypad0; return(true); case XKey.KP_1: key = Key.Keypad1; return(true); case XKey.KP_2: key = Key.Keypad2; return(true); case XKey.KP_3: key = Key.Keypad3; return(true); case XKey.KP_4: key = Key.Keypad4; return(true); case XKey.KP_5: key = Key.Keypad5; return(true); case XKey.KP_6: key = Key.Keypad6; return(true); case XKey.KP_7: key = Key.Keypad7; return(true); case XKey.KP_8: key = Key.Keypad8; return(true); case XKey.KP_9: key = Key.Keypad9; return(true); case XKey.KP_Separator: case XKey.KP_Decimal: key = Key.KeypadDecimal; return(true); case XKey.KP_Equal: key = Key.Unknown; return(false); // Todo: fixme case XKey.KP_Enter: key = Key.KeypadEnter; return(true); } // Translate non-alphanumeric keys using the primary group keysym = Xkb.KeycodeToKeysym(display, keycode, 0, 0); key = TranslateXKey(keysym); return(key != Key.Unknown); }
// Refreshes the keycodes lookup table based // on the current keyboard layout. internal void RefreshKeycodes(IntPtr display) { // Approach inspired by GLFW: http://www.glfw.org/ // Huge props to the GLFW team! if (xkb_supported) { unsafe { // Xkb.GetKeyboard appears to be broken (multiple bug reports across distros) // so use Xkb.AllocKeyboard with Xkb.GetNames instead. XkbDesc *keyboard = Xkb.AllocKeyboard(display); if (keyboard != null) { Xkb.GetNames(display, XkbNamesMask.All, keyboard); for (int i = 0; i < keycodes.Length; i++) { keycodes[i] = Key.Unknown; } // Map all alphanumeric keys of this layout // Symbols are handled in GetKey() instead. for (int i = keyboard->min_key_code; i <= keyboard->max_key_code; ++i) { string name = new string((sbyte *)keyboard->names->keys[i].name, 0, Xkb.KeyNameLength); Key key = Key.Unknown; switch (name) { case "TLDE": key = Key.Tilde; break; case "AE01": key = Key.Number1; break; case "AE02": key = Key.Number2; break; case "AE03": key = Key.Number3; break; case "AE04": key = Key.Number4; break; case "AE05": key = Key.Number5; break; case "AE06": key = Key.Number6; break; case "AE07": key = Key.Number7; break; case "AE08": key = Key.Number8; break; case "AE09": key = Key.Number9; break; case "AE10": key = Key.Number0; break; case "AE11": key = Key.Minus; break; case "AE12": key = Key.Plus; break; case "AD01": key = Key.Q; break; case "AD02": key = Key.W; break; case "AD03": key = Key.E; break; case "AD04": key = Key.R; break; case "AD05": key = Key.T; break; case "AD06": key = Key.Y; break; case "AD07": key = Key.U; break; case "AD08": key = Key.I; break; case "AD09": key = Key.O; break; case "AD10": key = Key.P; break; case "AD11": key = Key.BracketLeft; break; case "AD12": key = Key.BracketRight; break; case "AC01": key = Key.A; break; case "AC02": key = Key.S; break; case "AC03": key = Key.D; break; case "AC04": key = Key.F; break; case "AC05": key = Key.G; break; case "AC06": key = Key.H; break; case "AC07": key = Key.J; break; case "AC08": key = Key.K; break; case "AC09": key = Key.L; break; case "AC10": key = Key.Semicolon; break; case "AC11": key = Key.Quote; break; case "AB01": key = Key.Z; break; case "AB02": key = Key.X; break; case "AB03": key = Key.C; break; case "AB04": key = Key.V; break; case "AB05": key = Key.B; break; case "AB06": key = Key.N; break; case "AB07": key = Key.M; break; case "AB08": key = Key.Comma; break; case "AB09": key = Key.Period; break; case "AB10": key = Key.Slash; break; case "BKSL": key = Key.BackSlash; break; case "LSGT": key = Key.Unknown; break; default: key = Key.Unknown; break; } keycodes[i] = key; } Xkb.FreeKeyboard(keyboard, 0, true); } } } // Translate unknown keys (and symbols) using // regular layout-dependent GetKey() for (int i = 0; i < 256; i++) { if (keycodes[i] == Key.Unknown) { // TranslateKeyCode expects a XKeyEvent structure // Make one up XKeyEvent e = new XKeyEvent(); e.display = display; e.keycode = i; Key key = Key.Unknown; if (TranslateKeyEvent(ref e, out key)) { keycodes[i] = key; } } } }