mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-27 07:45:29 +00:00
724 lines
26 KiB
C#
724 lines
26 KiB
C#
#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.
|
||
//
|
||
#endregion
|
||
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Text;
|
||
using System.Diagnostics;
|
||
using OpenTK.Input;
|
||
|
||
namespace OpenTK.Platform.X11
|
||
{
|
||
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.PrintScreen;
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
}
|