// 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; } } } }
unsafe internal extern static IntPtr GetNames(IntPtr display, XkbNamesMask which, XkbDesc *xkb);
unsafe internal extern static void FreeKeyboard(XkbDesc *descr, int which, bool free);
unsafe public extern static IntPtr XkbGetNames(IntPtr display, XkbNamesMask which, XkbDesc *xkb);
unsafe public extern static void XkbFreeKeyboard(XkbDesc *descr, int which, bool free);
internal static extern unsafe void FreeKeyboard(XkbDesc *descr, int which, bool free);