diff options
Diffstat (limited to 'CrowX/X11/X11KeyMap.cs')
| -rw-r--r-- | CrowX/X11/X11KeyMap.cs | 726 |
1 files changed, 726 insertions, 0 deletions
diff --git a/CrowX/X11/X11KeyMap.cs b/CrowX/X11/X11KeyMap.cs new file mode 100644 index 00000000..15a05ecc --- /dev/null +++ b/CrowX/X11/X11KeyMap.cs @@ -0,0 +1,726 @@ +#region License +// +// X11KeyMap.cs +// +// Author: +// Stefanos Apostolopoulos <stapostol@gmail.com> +// +// Copyright (c) 2006-2014 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +using Crow; + + +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; +using OpenTK.Input; + +namespace X11Sharp +{ + class X11KeyMap + { + // Keycode lookup table for current layout + readonly Key[] keycodes = new Key[256]; + readonly bool xkb_supported; + + internal X11KeyMap(IntPtr display) + { + xkb_supported = Xkb.IsSupported(display); + if (xkb_supported) + { + RefreshKeycodes(display); + } + } + + // 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; + } + } + } + } + + static Key TranslateXKey(XKey key) + { + switch (key) + { + case XKey.Escape: + return Key.Escape; + case XKey.Return: + return Key.Enter; + case XKey.space: + return Key.Space; + case XKey.BackSpace: + return Key.BackSpace; + + case XKey.Shift_L: + return Key.ShiftLeft; + case XKey.Shift_R: + return Key.ShiftRight; + case XKey.Alt_L: + return Key.AltLeft; + case XKey.Alt_R: + return Key.AltRight; + case XKey.Control_L: + return Key.ControlLeft; + case XKey.Control_R: + return Key.ControlRight; + case XKey.Super_L: + return Key.WinLeft; + case XKey.Super_R: + return Key.WinRight; + case XKey.Meta_L: + return Key.WinLeft; + case XKey.Meta_R: + return Key.WinRight; + case XKey.ISO_Level3_Shift: + return Key.AltRight; // Normally AltGr + + case XKey.Menu: + return Key.Menu; + case XKey.Tab: + return Key.Tab; + case XKey.minus: + return Key.Minus; + case XKey.plus: + return Key.Plus; + case XKey.equal: + return Key.Plus; + + case XKey.Caps_Lock: + return Key.CapsLock; + case XKey.Num_Lock: + return Key.NumLock; + + case XKey.F1: + return Key.F1; + case XKey.F2: + return Key.F2; + case XKey.F3: + return Key.F3; + case XKey.F4: + return Key.F4; + case XKey.F5: + return Key.F5; + case XKey.F6: + return Key.F6; + case XKey.F7: + return Key.F7; + case XKey.F8: + return Key.F8; + case XKey.F9: + return Key.F9; + case XKey.F10: + return Key.F10; + case XKey.F11: + return Key.F11; + case XKey.F12: + return Key.F12; + case XKey.F13: + return Key.F13; + case XKey.F14: + return Key.F14; + case XKey.F15: + return Key.F15; + case XKey.F16: + return Key.F16; + case XKey.F17: + return Key.F17; + case XKey.F18: + return Key.F18; + case XKey.F19: + return Key.F19; + case XKey.F20: + return Key.F20; + case XKey.F21: + return Key.F21; + case XKey.F22: + return Key.F22; + case XKey.F23: + return Key.F23; + case XKey.F24: + return Key.F24; + case XKey.F25: + return Key.F25; + case XKey.F26: + return Key.F26; + case XKey.F27: + return Key.F27; + case XKey.F28: + return Key.F28; + case XKey.F29: + return Key.F29; + case XKey.F30: + return Key.F30; + case XKey.F31: + return Key.F31; + case XKey.F32: + return Key.F32; + case XKey.F33: + return Key.F33; + case XKey.F34: + return Key.F34; + case XKey.F35: + return Key.F35; + + case XKey.a: + case XKey.A: + return Key.A; + case XKey.b: + case XKey.B: + return Key.B; + case XKey.c: + case XKey.C: + return Key.C; + case XKey.d: + case XKey.D: + return Key.D; + case XKey.e: + case XKey.E: + return Key.E; + case XKey.f: + case XKey.F: + return Key.F; + case XKey.g: + case XKey.G: + return Key.G; + case XKey.h: + case XKey.H: + return Key.H; + case XKey.i: + case XKey.I: + return Key.I; + case XKey.j: + case XKey.J: + return Key.J; + case XKey.k: + case XKey.K: + return Key.K; + case XKey.l: + case XKey.L: + return Key.L; + case XKey.m: + case XKey.M: + return Key.M; + case XKey.n: + case XKey.N: + return Key.N; + case XKey.o: + case XKey.O: + return Key.O; + case XKey.p: + case XKey.P: + return Key.P; + case XKey.q: + case XKey.Q: + return Key.Q; + case XKey.r: + case XKey.R: + return Key.R; + case XKey.s: + case XKey.S: + return Key.S; + case XKey.t: + case XKey.T: + return Key.T; + case XKey.u: + case XKey.U: + return Key.U; + case XKey.v: + case XKey.V: + return Key.V; + case XKey.w: + case XKey.W: + return Key.W; + case XKey.x: + case XKey.X: + return Key.X; + case XKey.y: + case XKey.Y: + return Key.Y; + case XKey.z: + case XKey.Z: + return Key.Z; + + case XKey.Number0: + return Key.Number0; + case XKey.Number1: + return Key.Number1; + case XKey.Number2: + return Key.Number2; + case XKey.Number3: + return Key.Number3; + case XKey.Number4: + return Key.Number4; + case XKey.Number5: + return Key.Number5; + case XKey.Number6: + return Key.Number6; + case XKey.Number7: + return Key.Number7; + case XKey.Number8: + return Key.Number8; + case XKey.Number9: + return Key.Number9; + + case XKey.KP_0: + return Key.Keypad0; + case XKey.KP_1: + return Key.Keypad1; + case XKey.KP_2: + return Key.Keypad2; + case XKey.KP_3: + return Key.Keypad3; + case XKey.KP_4: + return Key.Keypad4; + case XKey.KP_5: + return Key.Keypad5; + case XKey.KP_6: + return Key.Keypad6; + case XKey.KP_7: + return Key.Keypad7; + case XKey.KP_8: + return Key.Keypad8; + case XKey.KP_9: + return Key.Keypad9; + + case XKey.Pause: + return Key.Pause; + case XKey.Break: + return Key.Pause; + case XKey.Scroll_Lock: + return Key.Pause; + case XKey.Insert: + return Key.Insert; + case XKey.Print: + return Key.PrintScreen; + case XKey.Sys_Req: + return Key.PrintScreen; + + case XKey.backslash: + return Key.BackSlash; + case XKey.bar: + return Key.BackSlash; + case XKey.braceleft: + return Key.BracketLeft; + case XKey.bracketleft: + return Key.BracketLeft; + case XKey.braceright: + return Key.BracketRight; + case XKey.bracketright: + return Key.BracketRight; + case XKey.colon: + return Key.Semicolon; + case XKey.semicolon: + return Key.Semicolon; + case XKey.quoteright: + return Key.Quote; + case XKey.quotedbl: + return Key.Quote; + case XKey.quoteleft: + return Key.Tilde; + case XKey.asciitilde: + return Key.Tilde; + + case XKey.comma: + return Key.Comma; + case XKey.less: + return Key.Comma; + case XKey.period: + return Key.Period; + case XKey.greater: + return Key.Period; + case XKey.slash: + return Key.Slash; + case XKey.question: + return Key.Slash; + + case XKey.Left: + return Key.Left; + case XKey.Down: + return Key.Down; + case XKey.Right: + return Key.Right; + case XKey.Up: + return Key.Up; + + case XKey.Delete: + return Key.Delete; + case XKey.Home: + return Key.Home; + case XKey.End: + return Key.End; + //case XKey.Prior: return Key.PageUp; // XKey.Prior == XKey.Page_Up + case XKey.Page_Up: + return Key.PageUp; + case XKey.Page_Down: + return Key.PageDown; + //case XKey.Next: return Key.PageDown; // XKey.Next == XKey.Page_Down + + case XKey.KP_Add: + return Key.KeypadAdd; + case XKey.KP_Subtract: + return Key.KeypadSubtract; + case XKey.KP_Multiply: + return Key.KeypadMultiply; + case XKey.KP_Divide: + return Key.KeypadDivide; + case XKey.KP_Decimal: + return Key.KeypadDecimal; + case XKey.KP_Insert: + return Key.Keypad0; + case XKey.KP_End: + return Key.Keypad1; + case XKey.KP_Down: + return Key.Keypad2; + case XKey.KP_Page_Down: + return Key.Keypad3; + case XKey.KP_Left: + return Key.Keypad4; + case XKey.KP_Right: + return Key.Keypad6; + case XKey.KP_Home: + return Key.Keypad7; + case XKey.KP_Up: + return Key.Keypad8; + case XKey.KP_Page_Up: + return Key.Keypad9; + case XKey.KP_Delete: + return Key.KeypadDecimal; + case XKey.KP_Enter: + return Key.KeypadEnter; + + default: + return Key.Unknown; + } + } + + bool TranslateKeyEvent(ref XKeyEvent e, out Key key) + { + if (xkb_supported) + { + return TranslateKeyXkb(e.display, e.keycode, out key); + } + else + { + return TranslateKeyX11(ref e, out key); + } + } + + bool TranslateKeyX11(ref XKeyEvent e, out Key key) + { + XKey keysym = (XKey)API.LookupKeysym(ref e, 0); + XKey keysym2 = (XKey)API.LookupKeysym(ref e, 1); + key = X11KeyMap.TranslateXKey(keysym); + if (key == Key.Unknown) + { + key = X11KeyMap.TranslateXKey(keysym2); + } + if (key == Key.Unknown) + { + Debug.Print("KeyCode {0} (Keysym: {1}, {2}) not mapped.", e.keycode, (XKey)keysym, (XKey)keysym2); + } + + return key != Key.Unknown; + } + + 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; + } + + internal bool TranslateKey(int keycode, out Key key) + { + if (keycode < 0 || keycode > 255) + { + key = Key.Unknown; + } + else + { + key = keycodes[keycode]; + } + return key != Key.Unknown; + } + + internal bool TranslateKey(ref XKeyEvent e, out Key key) + { + return TranslateKey(e.keycode, out key); + } + + internal static MouseButton TranslateButton(int button, out float wheelx, out float wheely) + { + wheelx = 0; + wheely = 0; + + switch (button) + { + case 1: return MouseButton.Left; + case 2: return MouseButton.Middle; + case 3: return MouseButton.Right; + case 4: wheely = +1; return MouseButton.LastButton; + case 5: wheely = -1; return MouseButton.LastButton; + case 6: wheelx = +1; return MouseButton.LastButton; + case 7: wheelx = -1; return MouseButton.LastButton; + case 8: return MouseButton.Button1; + case 9: return MouseButton.Button2; + case 10: return MouseButton.Button3; + case 11: return MouseButton.Button4; + case 12: return MouseButton.Button5; + case 13: return MouseButton.Button6; + case 14: return MouseButton.Button7; + default: return MouseButton.LastButton; + } + } + } +} |