From c0cb4c2fe1e158f45ec46d54f15c597a30b7cdcd Mon Sep 17 00:00:00 2001 From: Marcus Date: Sun, 2 Jan 2011 11:18:14 +0100 Subject: [PATCH] Implemented raw key code support for X11. --- include/GL/glfw3.h | 230 ++++++++++++++++++++++++------------ src/x11/platform.h | 13 ++ src/x11/x11_init.c | 117 ++++++++++++++++++ src/x11/x11_window.c | 274 +++++++++++++++++++++++++++---------------- tests/events.c | 83 ++++++++++--- 5 files changed, 522 insertions(+), 195 deletions(-) diff --git a/include/GL/glfw3.h b/include/GL/glfw3.h index a8e3866c..e94e49a1 100644 --- a/include/GL/glfw3.h +++ b/include/GL/glfw3.h @@ -184,83 +184,161 @@ extern "C" { #define GLFW_RELEASE 0 #define GLFW_PRESS 1 -/* Keyboard key definitions: 8-bit ISO-8859-1 (Latin 1) encoding is used - * for printable keys (such as A-Z, 0-9 etc), and values above 256 - * represent special (non-printable) keys (e.g. F1, Page Up etc). +/* Keyboard raw key codes. + * These key codes are inspired by the USB HID Usage Tables v1.12 (p. 53-60), + * but re-arranged to map to 7-bit ASCII for printable keys (function keys are + * put in the 256+ range). + * The naming of the key codes follow these rules: + * - The US keyboard layout is used. + * - Names of printable alpha-numeric characters are used (e.g. "A", "R", + * "3", etc). + * - For non-alphanumeric characters, Unicode:ish names are used (e.g. + * "COMMA", "LEFT_SQUARE_BRACKET", etc). Note that some names do not + * correspond to the Unicode standard (usually for brevity). + * - Keys that lack a clear US mapping are named "WORLD_x". + * - For non-printable keys, custom names are used (e.g. "F4", + * "BACKSPACE", etc). */ -#define GLFW_KEY_UNKNOWN -1 -#define GLFW_KEY_SPACE 32 -#define GLFW_KEY_SPECIAL 256 -#define GLFW_KEY_ESC (GLFW_KEY_SPECIAL+1) -#define GLFW_KEY_F1 (GLFW_KEY_SPECIAL+2) -#define GLFW_KEY_F2 (GLFW_KEY_SPECIAL+3) -#define GLFW_KEY_F3 (GLFW_KEY_SPECIAL+4) -#define GLFW_KEY_F4 (GLFW_KEY_SPECIAL+5) -#define GLFW_KEY_F5 (GLFW_KEY_SPECIAL+6) -#define GLFW_KEY_F6 (GLFW_KEY_SPECIAL+7) -#define GLFW_KEY_F7 (GLFW_KEY_SPECIAL+8) -#define GLFW_KEY_F8 (GLFW_KEY_SPECIAL+9) -#define GLFW_KEY_F9 (GLFW_KEY_SPECIAL+10) -#define GLFW_KEY_F10 (GLFW_KEY_SPECIAL+11) -#define GLFW_KEY_F11 (GLFW_KEY_SPECIAL+12) -#define GLFW_KEY_F12 (GLFW_KEY_SPECIAL+13) -#define GLFW_KEY_F13 (GLFW_KEY_SPECIAL+14) -#define GLFW_KEY_F14 (GLFW_KEY_SPECIAL+15) -#define GLFW_KEY_F15 (GLFW_KEY_SPECIAL+16) -#define GLFW_KEY_F16 (GLFW_KEY_SPECIAL+17) -#define GLFW_KEY_F17 (GLFW_KEY_SPECIAL+18) -#define GLFW_KEY_F18 (GLFW_KEY_SPECIAL+19) -#define GLFW_KEY_F19 (GLFW_KEY_SPECIAL+20) -#define GLFW_KEY_F20 (GLFW_KEY_SPECIAL+21) -#define GLFW_KEY_F21 (GLFW_KEY_SPECIAL+22) -#define GLFW_KEY_F22 (GLFW_KEY_SPECIAL+23) -#define GLFW_KEY_F23 (GLFW_KEY_SPECIAL+24) -#define GLFW_KEY_F24 (GLFW_KEY_SPECIAL+25) -#define GLFW_KEY_F25 (GLFW_KEY_SPECIAL+26) -#define GLFW_KEY_UP (GLFW_KEY_SPECIAL+27) -#define GLFW_KEY_DOWN (GLFW_KEY_SPECIAL+28) -#define GLFW_KEY_LEFT (GLFW_KEY_SPECIAL+29) -#define GLFW_KEY_RIGHT (GLFW_KEY_SPECIAL+30) -#define GLFW_KEY_LSHIFT (GLFW_KEY_SPECIAL+31) -#define GLFW_KEY_RSHIFT (GLFW_KEY_SPECIAL+32) -#define GLFW_KEY_LCTRL (GLFW_KEY_SPECIAL+33) -#define GLFW_KEY_RCTRL (GLFW_KEY_SPECIAL+34) -#define GLFW_KEY_LALT (GLFW_KEY_SPECIAL+35) -#define GLFW_KEY_RALT (GLFW_KEY_SPECIAL+36) -#define GLFW_KEY_TAB (GLFW_KEY_SPECIAL+37) -#define GLFW_KEY_ENTER (GLFW_KEY_SPECIAL+38) -#define GLFW_KEY_BACKSPACE (GLFW_KEY_SPECIAL+39) -#define GLFW_KEY_INSERT (GLFW_KEY_SPECIAL+40) -#define GLFW_KEY_DEL (GLFW_KEY_SPECIAL+41) -#define GLFW_KEY_PAGEUP (GLFW_KEY_SPECIAL+42) -#define GLFW_KEY_PAGEDOWN (GLFW_KEY_SPECIAL+43) -#define GLFW_KEY_HOME (GLFW_KEY_SPECIAL+44) -#define GLFW_KEY_END (GLFW_KEY_SPECIAL+45) -#define GLFW_KEY_KP_0 (GLFW_KEY_SPECIAL+46) -#define GLFW_KEY_KP_1 (GLFW_KEY_SPECIAL+47) -#define GLFW_KEY_KP_2 (GLFW_KEY_SPECIAL+48) -#define GLFW_KEY_KP_3 (GLFW_KEY_SPECIAL+49) -#define GLFW_KEY_KP_4 (GLFW_KEY_SPECIAL+50) -#define GLFW_KEY_KP_5 (GLFW_KEY_SPECIAL+51) -#define GLFW_KEY_KP_6 (GLFW_KEY_SPECIAL+52) -#define GLFW_KEY_KP_7 (GLFW_KEY_SPECIAL+53) -#define GLFW_KEY_KP_8 (GLFW_KEY_SPECIAL+54) -#define GLFW_KEY_KP_9 (GLFW_KEY_SPECIAL+55) -#define GLFW_KEY_KP_DIVIDE (GLFW_KEY_SPECIAL+56) -#define GLFW_KEY_KP_MULTIPLY (GLFW_KEY_SPECIAL+57) -#define GLFW_KEY_KP_SUBTRACT (GLFW_KEY_SPECIAL+58) -#define GLFW_KEY_KP_ADD (GLFW_KEY_SPECIAL+59) -#define GLFW_KEY_KP_DECIMAL (GLFW_KEY_SPECIAL+60) -#define GLFW_KEY_KP_EQUAL (GLFW_KEY_SPECIAL+61) -#define GLFW_KEY_KP_ENTER (GLFW_KEY_SPECIAL+62) -#define GLFW_KEY_KP_NUM_LOCK (GLFW_KEY_SPECIAL+63) -#define GLFW_KEY_CAPS_LOCK (GLFW_KEY_SPECIAL+64) -#define GLFW_KEY_SCROLL_LOCK (GLFW_KEY_SPECIAL+65) -#define GLFW_KEY_PAUSE (GLFW_KEY_SPECIAL+66) -#define GLFW_KEY_LSUPER (GLFW_KEY_SPECIAL+67) -#define GLFW_KEY_RSUPER (GLFW_KEY_SPECIAL+68) -#define GLFW_KEY_MENU (GLFW_KEY_SPECIAL+69) -#define GLFW_KEY_LAST GLFW_KEY_MENU + +/* Printable keys */ +#define GLFW_KEY_SPACE 32 +#define GLFW_KEY_APOSTROPHE 39 /* ' */ +#define GLFW_KEY_COMMA 44 /* , */ +#define GLFW_KEY_MINUS 45 /* - */ +#define GLFW_KEY_PERIOD 46 /* . */ +#define GLFW_KEY_SLASH 47 /* / */ +#define GLFW_KEY_0 48 +#define GLFW_KEY_1 49 +#define GLFW_KEY_2 50 +#define GLFW_KEY_3 51 +#define GLFW_KEY_4 52 +#define GLFW_KEY_5 53 +#define GLFW_KEY_6 54 +#define GLFW_KEY_7 55 +#define GLFW_KEY_8 56 +#define GLFW_KEY_9 57 +#define GLFW_KEY_SEMICOLON 59 /* ; */ +#define GLFW_KEY_EQUAL 61 /* = */ +#define GLFW_KEY_A 65 +#define GLFW_KEY_B 66 +#define GLFW_KEY_C 67 +#define GLFW_KEY_D 68 +#define GLFW_KEY_E 69 +#define GLFW_KEY_F 70 +#define GLFW_KEY_G 71 +#define GLFW_KEY_H 72 +#define GLFW_KEY_I 73 +#define GLFW_KEY_J 74 +#define GLFW_KEY_K 75 +#define GLFW_KEY_L 76 +#define GLFW_KEY_M 77 +#define GLFW_KEY_N 78 +#define GLFW_KEY_O 79 +#define GLFW_KEY_P 80 +#define GLFW_KEY_Q 81 +#define GLFW_KEY_R 82 +#define GLFW_KEY_S 83 +#define GLFW_KEY_T 84 +#define GLFW_KEY_U 85 +#define GLFW_KEY_V 86 +#define GLFW_KEY_W 87 +#define GLFW_KEY_X 88 +#define GLFW_KEY_Y 89 +#define GLFW_KEY_Z 90 +#define GLFW_KEY_LEFT_SQUARE_BRACKET 91 /* [ */ +#define GLFW_KEY_BACKSLASH 92 /* \ */ +#define GLFW_KEY_RIGHT_SQUARE_BRACKET 93 /* ] */ +#define GLFW_KEY_GRAVE_ACCENT 96 /* ` */ +#define GLFW_KEY_WORLD_1 161 /* non-US #1 */ +#define GLFW_KEY_WORLD_2 162 /* non-US #2 */ + +/* Function keys */ +#define GLFW_KEY_ESCAPE 256 +#define GLFW_KEY_ENTER 257 +#define GLFW_KEY_TAB 258 +#define GLFW_KEY_BACKSPACE 259 +#define GLFW_KEY_INSERT 260 +#define GLFW_KEY_DELETE 261 +#define GLFW_KEY_RIGHT 262 +#define GLFW_KEY_LEFT 263 +#define GLFW_KEY_DOWN 264 +#define GLFW_KEY_UP 265 +#define GLFW_KEY_PAGE_UP 266 +#define GLFW_KEY_PAGE_DOWN 267 +#define GLFW_KEY_HOME 268 +#define GLFW_KEY_END 269 +#define GLFW_KEY_CAPS_LOCK 280 +#define GLFW_KEY_SCROLL_LOCK 281 +#define GLFW_KEY_NUM_LOCK 282 +#define GLFW_KEY_PRINT_SCREEN 283 +#define GLFW_KEY_PAUSE 284 +#define GLFW_KEY_F1 290 +#define GLFW_KEY_F2 291 +#define GLFW_KEY_F3 292 +#define GLFW_KEY_F4 293 +#define GLFW_KEY_F5 294 +#define GLFW_KEY_F6 295 +#define GLFW_KEY_F7 296 +#define GLFW_KEY_F8 297 +#define GLFW_KEY_F9 298 +#define GLFW_KEY_F10 299 +#define GLFW_KEY_F11 300 +#define GLFW_KEY_F12 301 +#define GLFW_KEY_F13 302 +#define GLFW_KEY_F14 303 +#define GLFW_KEY_F15 304 +#define GLFW_KEY_F16 305 +#define GLFW_KEY_F17 306 +#define GLFW_KEY_F18 307 +#define GLFW_KEY_F19 308 +#define GLFW_KEY_F20 309 +#define GLFW_KEY_F21 310 +#define GLFW_KEY_F22 311 +#define GLFW_KEY_F23 312 +#define GLFW_KEY_F24 313 +#define GLFW_KEY_F25 314 +#define GLFW_KEY_KP_0 320 +#define GLFW_KEY_KP_1 321 +#define GLFW_KEY_KP_2 322 +#define GLFW_KEY_KP_3 323 +#define GLFW_KEY_KP_4 324 +#define GLFW_KEY_KP_5 325 +#define GLFW_KEY_KP_6 326 +#define GLFW_KEY_KP_7 327 +#define GLFW_KEY_KP_8 328 +#define GLFW_KEY_KP_9 329 +#define GLFW_KEY_KP_DECIMAL 330 +#define GLFW_KEY_KP_DIVIDE 331 +#define GLFW_KEY_KP_MULTIPLY 332 +#define GLFW_KEY_KP_SUBTRACT 333 +#define GLFW_KEY_KP_ADD 334 +#define GLFW_KEY_KP_ENTER 335 +#define GLFW_KEY_KP_EQUAL 336 +#define GLFW_KEY_LEFT_SHIFT 340 +#define GLFW_KEY_LEFT_CONTROL 341 +#define GLFW_KEY_LEFT_ALT 342 +#define GLFW_KEY_LEFT_SUPER 343 +#define GLFW_KEY_RIGHT_SHIFT 344 +#define GLFW_KEY_RIGHT_CONTROL 345 +#define GLFW_KEY_RIGHT_ALT 346 +#define GLFW_KEY_RIGHT_SUPER 347 +#define GLFW_KEY_MENU 348 +#define GLFW_KEY_LAST GLFW_KEY_MENU + +/* GLFW 2.x key name aliases (deprecated) */ +#define GLFW_KEY_ESC GLFW_KEY_ESCAPE +#define GLFW_KEY_DEL GLFW_KEY_DELETE +#define GLFW_KEY_PAGEUP GLFW_KEY_PAGE_UP +#define GLFW_KEY_PAGEDOWN GLFW_KEY_PAGE_DOWN +#define GLFW_KEY_KP_NUM_LOCK GLFW_KEY_NUM_LOCK +#define GLFW_KEY_LCTRL GLFW_KEY_LEFT_CONTROL +#define GLFW_KEY_LSHIFT GLFW_KEY_LEFT_SHIFT +#define GLFW_KEY_LALT GLFW_KEY_LEFT_ALT +#define GLFW_KEY_LSUPER GLFW_KEY_LEFT_SUPER +#define GLFW_KEY_RCTRL GLFW_KEY_RIGHT_CONTROL +#define GLFW_KEY_RSHIFT GLFW_KEY_RIGHT_SHIFT +#define GLFW_KEY_RALT GLFW_KEY_RIGHT_ALT +#define GLFW_KEY_RSUPER GLFW_KEY_RIGHT_SUPER /* Mouse button definitions */ #define GLFW_MOUSE_BUTTON_1 0 diff --git a/src/x11/platform.h b/src/x11/platform.h index a243bffd..a370df0b 100644 --- a/src/x11/platform.h +++ b/src/x11/platform.h @@ -66,6 +66,9 @@ #include #endif +// The Xkb extension provides improved keyboard support +#include + #ifndef GL_VERSION_3_0 @@ -173,6 +176,16 @@ typedef struct _GLFWlibraryX11 GLboolean gammaBroken; } RandR; + struct { + GLboolean available; + int majorOpcode; + int eventBase; + int errorBase; + int majorVersion; + int minorVersion; + int keyCodeLUT[256]; + } Xkb; + // Screensaver data struct { GLboolean changed; diff --git a/src/x11/x11_init.c b/src/x11/x11_init.c index ac5c3054..2f23e334 100644 --- a/src/x11/x11_init.c +++ b/src/x11/x11_init.c @@ -62,6 +62,107 @@ static void initLibraries(void) } +//======================================================================== +// Update the key code LUT +//======================================================================== + +static void updateKeyCodeLUT(void) +{ + int i, keyCode, keyCodeGLFW; + char name[XkbKeyNameLength+1]; + XkbDescPtr descr; + + // Clear the LUT + for (i = 0; i < 256; ++i) + { + _glfwLibrary.X11.Xkb.keyCodeLUT[i] = -1; + } + + // This functionality requires the Xkb extension + if (!_glfwLibrary.X11.Xkb.available) + { + return; + } + + // Get keyboard description + descr = XkbGetKeyboard(_glfwLibrary.X11.display, + XkbAllComponentsMask, + XkbUseCoreKbd); + + // Find the X11 key code -> GLFW key code mapping + for (keyCode = descr->min_key_code; keyCode <= descr->max_key_code; ++keyCode) + { + // Get the key name + for (i = 0; i < XkbKeyNameLength; ++i) + { + name[i] = descr->names->keys[keyCode].name[i]; + } + name[XkbKeyNameLength] = 0; + + // Map the key name to a GLFW key code. Note: We only map printable + // keys here, and we use the US keyboard layout. + if (strcmp(name, "TLDE") == 0) keyCodeGLFW = GLFW_KEY_GRAVE_ACCENT; + else if (strcmp(name, "AE01") == 0) keyCodeGLFW = GLFW_KEY_1; + else if (strcmp(name, "AE02") == 0) keyCodeGLFW = GLFW_KEY_2; + else if (strcmp(name, "AE03") == 0) keyCodeGLFW = GLFW_KEY_3; + else if (strcmp(name, "AE04") == 0) keyCodeGLFW = GLFW_KEY_4; + else if (strcmp(name, "AE05") == 0) keyCodeGLFW = GLFW_KEY_5; + else if (strcmp(name, "AE06") == 0) keyCodeGLFW = GLFW_KEY_6; + else if (strcmp(name, "AE07") == 0) keyCodeGLFW = GLFW_KEY_7; + else if (strcmp(name, "AE08") == 0) keyCodeGLFW = GLFW_KEY_8; + else if (strcmp(name, "AE09") == 0) keyCodeGLFW = GLFW_KEY_9; + else if (strcmp(name, "AE10") == 0) keyCodeGLFW = GLFW_KEY_0; + else if (strcmp(name, "AE11") == 0) keyCodeGLFW = GLFW_KEY_MINUS; + else if (strcmp(name, "AE12") == 0) keyCodeGLFW = GLFW_KEY_EQUAL; + else if (strcmp(name, "AD01") == 0) keyCodeGLFW = GLFW_KEY_Q; + else if (strcmp(name, "AD02") == 0) keyCodeGLFW = GLFW_KEY_W; + else if (strcmp(name, "AD03") == 0) keyCodeGLFW = GLFW_KEY_E; + else if (strcmp(name, "AD04") == 0) keyCodeGLFW = GLFW_KEY_R; + else if (strcmp(name, "AD05") == 0) keyCodeGLFW = GLFW_KEY_T; + else if (strcmp(name, "AD06") == 0) keyCodeGLFW = GLFW_KEY_Y; + else if (strcmp(name, "AD07") == 0) keyCodeGLFW = GLFW_KEY_U; + else if (strcmp(name, "AD08") == 0) keyCodeGLFW = GLFW_KEY_I; + else if (strcmp(name, "AD09") == 0) keyCodeGLFW = GLFW_KEY_O; + else if (strcmp(name, "AD10") == 0) keyCodeGLFW = GLFW_KEY_P; + else if (strcmp(name, "AD11") == 0) keyCodeGLFW = GLFW_KEY_LEFT_SQUARE_BRACKET; + else if (strcmp(name, "AD12") == 0) keyCodeGLFW = GLFW_KEY_RIGHT_SQUARE_BRACKET; + else if (strcmp(name, "AC01") == 0) keyCodeGLFW = GLFW_KEY_A; + else if (strcmp(name, "AC02") == 0) keyCodeGLFW = GLFW_KEY_S; + else if (strcmp(name, "AC03") == 0) keyCodeGLFW = GLFW_KEY_D; + else if (strcmp(name, "AC04") == 0) keyCodeGLFW = GLFW_KEY_F; + else if (strcmp(name, "AC05") == 0) keyCodeGLFW = GLFW_KEY_G; + else if (strcmp(name, "AC06") == 0) keyCodeGLFW = GLFW_KEY_H; + else if (strcmp(name, "AC07") == 0) keyCodeGLFW = GLFW_KEY_J; + else if (strcmp(name, "AC08") == 0) keyCodeGLFW = GLFW_KEY_K; + else if (strcmp(name, "AC09") == 0) keyCodeGLFW = GLFW_KEY_L; + else if (strcmp(name, "AC10") == 0) keyCodeGLFW = GLFW_KEY_SEMICOLON; + else if (strcmp(name, "AC11") == 0) keyCodeGLFW = GLFW_KEY_APOSTROPHE; + else if (strcmp(name, "AB01") == 0) keyCodeGLFW = GLFW_KEY_Z; + else if (strcmp(name, "AB02") == 0) keyCodeGLFW = GLFW_KEY_X; + else if (strcmp(name, "AB03") == 0) keyCodeGLFW = GLFW_KEY_C; + else if (strcmp(name, "AB04") == 0) keyCodeGLFW = GLFW_KEY_V; + else if (strcmp(name, "AB05") == 0) keyCodeGLFW = GLFW_KEY_B; + else if (strcmp(name, "AB06") == 0) keyCodeGLFW = GLFW_KEY_N; + else if (strcmp(name, "AB07") == 0) keyCodeGLFW = GLFW_KEY_M; + else if (strcmp(name, "AB08") == 0) keyCodeGLFW = GLFW_KEY_COMMA; + else if (strcmp(name, "AB09") == 0) keyCodeGLFW = GLFW_KEY_PERIOD; + else if (strcmp(name, "AB10") == 0) keyCodeGLFW = GLFW_KEY_SLASH; + else if (strcmp(name, "BKSL") == 0) keyCodeGLFW = GLFW_KEY_BACKSLASH; + else if (strcmp(name, "LSGT") == 0) keyCodeGLFW = GLFW_KEY_WORLD_1; + else keyCodeGLFW = -1; + + // Update the key code LUT + if ((keyCode >= 0) && (keyCode < 256)) + { + _glfwLibrary.X11.Xkb.keyCodeLUT[keyCode] = keyCodeGLFW; + } + } + + // Free the keyboard description + XkbFreeKeyboard(descr, 0, True); +} + + //======================================================================== // Initialize X11 display and look for supported X11 extensions //======================================================================== @@ -126,6 +227,22 @@ static GLboolean initDisplay(void) return GL_FALSE; } + // Check if Xkb is supported on this display + _glfwLibrary.X11.Xkb.majorVersion = 1; + _glfwLibrary.X11.Xkb.minorVersion = 0; + _glfwLibrary.X11.Xkb.available = + XkbQueryExtension(_glfwLibrary.X11.display, + &_glfwLibrary.X11.Xkb.majorOpcode, + &_glfwLibrary.X11.Xkb.eventBase, + &_glfwLibrary.X11.Xkb.errorBase, + &_glfwLibrary.X11.Xkb.majorVersion, + &_glfwLibrary.X11.Xkb.minorVersion); + + // Update the key code LUT + // FIXME: We should listen to XkbMapNotify events to track changes to + // the keyboard mapping. + updateKeyCodeLUT(); + return GL_TRUE; } diff --git a/src/x11/x11_window.c b/src/x11/x11_window.c index 0b026b16..2879ecb0 100644 --- a/src/x11/x11_window.c +++ b/src/x11/x11_window.c @@ -35,6 +35,12 @@ #include #include +#ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB + #define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 +#endif +#ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT + #define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#endif // Action for EWMH client messages #define _NET_WM_STATE_REMOVE 0 @@ -213,124 +219,188 @@ static GLboolean checkForEWMH(_GLFWwindow* window) static int translateKey(int keycode) { - KeySym key, key_lc, key_uc; + KeySym key; // Try secondary keysym, for numeric keypad keys - // Note: This way we always force "NumLock = ON", which at least - // enables GLFW users to detect numeric keypad keys + // Note: This way we always force "NumLock = ON", which is intentional + // since the returned key code should correspond to a physical + // location. key = XKeycodeToKeysym(_glfwLibrary.X11.display, keycode, 1); switch (key) { - // Numeric keypad - case XK_KP_0: return GLFW_KEY_KP_0; - case XK_KP_1: return GLFW_KEY_KP_1; - case XK_KP_2: return GLFW_KEY_KP_2; - case XK_KP_3: return GLFW_KEY_KP_3; - case XK_KP_4: return GLFW_KEY_KP_4; - case XK_KP_5: return GLFW_KEY_KP_5; - case XK_KP_6: return GLFW_KEY_KP_6; - case XK_KP_7: return GLFW_KEY_KP_7; - case XK_KP_8: return GLFW_KEY_KP_8; - case XK_KP_9: return GLFW_KEY_KP_9; + case XK_KP_0: return GLFW_KEY_KP_0; + case XK_KP_1: return GLFW_KEY_KP_1; + case XK_KP_2: return GLFW_KEY_KP_2; + case XK_KP_3: return GLFW_KEY_KP_3; + case XK_KP_4: return GLFW_KEY_KP_4; + case XK_KP_5: return GLFW_KEY_KP_5; + case XK_KP_6: return GLFW_KEY_KP_6; + case XK_KP_7: return GLFW_KEY_KP_7; + case XK_KP_8: return GLFW_KEY_KP_8; + case XK_KP_9: return GLFW_KEY_KP_9; case XK_KP_Separator: - case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; - case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; - case XK_KP_Enter: return GLFW_KEY_KP_ENTER; - default: break; + case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + default: break; } - // Now try pimary keysym + // Now try pimary keysym for function keys (non-printable keys). These + // should not be layout dependent (i.e. US layout and international + // layouts should give the same result). key = XKeycodeToKeysym(_glfwLibrary.X11.display, keycode, 0); switch (key) { - // Special keys (non character keys) - case XK_Escape: return GLFW_KEY_ESC; - case XK_Tab: return GLFW_KEY_TAB; - case XK_Shift_L: return GLFW_KEY_LSHIFT; - case XK_Shift_R: return GLFW_KEY_RSHIFT; - case XK_Control_L: return GLFW_KEY_LCTRL; - case XK_Control_R: return GLFW_KEY_RCTRL; + case XK_Escape: return GLFW_KEY_ESCAPE; + case XK_Tab: return GLFW_KEY_TAB; + case XK_Shift_L: return GLFW_KEY_LEFT_SHIFT; + case XK_Shift_R: return GLFW_KEY_RIGHT_SHIFT; + case XK_Control_L: return GLFW_KEY_LEFT_CONTROL; + case XK_Control_R: return GLFW_KEY_RIGHT_CONTROL; case XK_Meta_L: - case XK_Alt_L: return GLFW_KEY_LALT; - case XK_Mode_switch: // Mapped to Alt_R on many keyboards - case XK_Meta_R: + case XK_Alt_L: return GLFW_KEY_LEFT_ALT; + case XK_Mode_switch: // Mapped to Alt_R on many keyboards case XK_ISO_Level3_Shift: // AltGr on at least some machines - case XK_Alt_R: return GLFW_KEY_RALT; - case XK_Super_L: return GLFW_KEY_LSUPER; - case XK_Super_R: return GLFW_KEY_RSUPER; - case XK_Menu: return GLFW_KEY_MENU; - case XK_Num_Lock: return GLFW_KEY_KP_NUM_LOCK; - case XK_Caps_Lock: return GLFW_KEY_CAPS_LOCK; - case XK_Scroll_Lock: return GLFW_KEY_SCROLL_LOCK; - case XK_Pause: return GLFW_KEY_PAUSE; - case XK_KP_Delete: - case XK_Delete: return GLFW_KEY_DEL; - case XK_BackSpace: return GLFW_KEY_BACKSPACE; - case XK_Return: return GLFW_KEY_ENTER; - case XK_KP_Home: - case XK_Home: return GLFW_KEY_HOME; - case XK_KP_End: - case XK_End: return GLFW_KEY_END; - case XK_KP_Page_Up: - case XK_Page_Up: return GLFW_KEY_PAGEUP; - case XK_KP_Page_Down: - case XK_Page_Down: return GLFW_KEY_PAGEDOWN; - case XK_KP_Insert: - case XK_Insert: return GLFW_KEY_INSERT; - case XK_KP_Left: - case XK_Left: return GLFW_KEY_LEFT; - case XK_KP_Right: - case XK_Right: return GLFW_KEY_RIGHT; - case XK_KP_Down: - case XK_Down: return GLFW_KEY_DOWN; - case XK_KP_Up: - case XK_Up: return GLFW_KEY_UP; - case XK_F1: return GLFW_KEY_F1; - case XK_F2: return GLFW_KEY_F2; - case XK_F3: return GLFW_KEY_F3; - case XK_F4: return GLFW_KEY_F4; - case XK_F5: return GLFW_KEY_F5; - case XK_F6: return GLFW_KEY_F6; - case XK_F7: return GLFW_KEY_F7; - case XK_F8: return GLFW_KEY_F8; - case XK_F9: return GLFW_KEY_F9; - case XK_F10: return GLFW_KEY_F10; - case XK_F11: return GLFW_KEY_F11; - case XK_F12: return GLFW_KEY_F12; - case XK_F13: return GLFW_KEY_F13; - case XK_F14: return GLFW_KEY_F14; - case XK_F15: return GLFW_KEY_F15; - case XK_F16: return GLFW_KEY_F16; - case XK_F17: return GLFW_KEY_F17; - case XK_F18: return GLFW_KEY_F18; - case XK_F19: return GLFW_KEY_F19; - case XK_F20: return GLFW_KEY_F20; - case XK_F21: return GLFW_KEY_F21; - case XK_F22: return GLFW_KEY_F22; - case XK_F23: return GLFW_KEY_F23; - case XK_F24: return GLFW_KEY_F24; - case XK_F25: return GLFW_KEY_F25; + case XK_Meta_R: + case XK_Alt_R: return GLFW_KEY_RIGHT_ALT; + case XK_Super_L: return GLFW_KEY_LEFT_SUPER; + case XK_Super_R: return GLFW_KEY_RIGHT_SUPER; + case XK_Menu: return GLFW_KEY_MENU; + case XK_Num_Lock: return GLFW_KEY_NUM_LOCK; + case XK_Caps_Lock: return GLFW_KEY_CAPS_LOCK; + case XK_Scroll_Lock: return GLFW_KEY_SCROLL_LOCK; + case XK_Pause: return GLFW_KEY_PAUSE; + case XK_Delete: return GLFW_KEY_DELETE; + case XK_BackSpace: return GLFW_KEY_BACKSPACE; + case XK_Return: return GLFW_KEY_ENTER; + case XK_Home: return GLFW_KEY_HOME; + case XK_End: return GLFW_KEY_END; + case XK_Page_Up: return GLFW_KEY_PAGE_UP; + case XK_Page_Down: return GLFW_KEY_PAGE_DOWN; + case XK_Insert: return GLFW_KEY_INSERT; + case XK_Left: return GLFW_KEY_LEFT; + case XK_Right: return GLFW_KEY_RIGHT; + case XK_Down: return GLFW_KEY_DOWN; + case XK_Up: return GLFW_KEY_UP; + case XK_F1: return GLFW_KEY_F1; + case XK_F2: return GLFW_KEY_F2; + case XK_F3: return GLFW_KEY_F3; + case XK_F4: return GLFW_KEY_F4; + case XK_F5: return GLFW_KEY_F5; + case XK_F6: return GLFW_KEY_F6; + case XK_F7: return GLFW_KEY_F7; + case XK_F8: return GLFW_KEY_F8; + case XK_F9: return GLFW_KEY_F9; + case XK_F10: return GLFW_KEY_F10; + case XK_F11: return GLFW_KEY_F11; + case XK_F12: return GLFW_KEY_F12; + case XK_F13: return GLFW_KEY_F13; + case XK_F14: return GLFW_KEY_F14; + case XK_F15: return GLFW_KEY_F15; + case XK_F16: return GLFW_KEY_F16; + case XK_F17: return GLFW_KEY_F17; + case XK_F18: return GLFW_KEY_F18; + case XK_F19: return GLFW_KEY_F19; + case XK_F20: return GLFW_KEY_F20; + case XK_F21: return GLFW_KEY_F21; + case XK_F22: return GLFW_KEY_F22; + case XK_F23: return GLFW_KEY_F23; + case XK_F24: return GLFW_KEY_F24; + case XK_F25: return GLFW_KEY_F25; - // Numeric keypad (should have been detected in secondary keysym!) - case XK_KP_Divide: return GLFW_KEY_KP_DIVIDE; - case XK_KP_Multiply: return GLFW_KEY_KP_MULTIPLY; - case XK_KP_Subtract: return GLFW_KEY_KP_SUBTRACT; - case XK_KP_Add: return GLFW_KEY_KP_ADD; - case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; - case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + // Numeric keypad + case XK_KP_Divide: return GLFW_KEY_KP_DIVIDE; + case XK_KP_Multiply: return GLFW_KEY_KP_MULTIPLY; + case XK_KP_Subtract: return GLFW_KEY_KP_SUBTRACT; + case XK_KP_Add: return GLFW_KEY_KP_ADD; - // The rest (should be printable keys) - default: - // Make uppercase - XConvertCase(key, &key_lc, &key_uc); - key = key_uc; - - // Valid ISO 8859-1 character? - if ((key >= 32 && key <= 126) || (key >= 160 && key <= 255)) - return (int) key; - - return GLFW_KEY_UNKNOWN; + // These should have been detected in secondary keysym test above! + case XK_KP_Insert: return GLFW_KEY_KP_0; + case XK_KP_End: return GLFW_KEY_KP_1; + case XK_KP_Down: return GLFW_KEY_KP_2; + case XK_KP_Page_Down: return GLFW_KEY_KP_3; + case XK_KP_Left: return GLFW_KEY_KP_4; + case XK_KP_Right: return GLFW_KEY_KP_6; + case XK_KP_Home: return GLFW_KEY_KP_7; + case XK_KP_Up: return GLFW_KEY_KP_8; + case XK_KP_Page_Up: return GLFW_KEY_KP_9; + case XK_KP_Delete: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + default: break; } + + // At this point we should only have printable keys left. We try the + // pre-filled LUT first (which is layout independent), which should give + // a positive result if we have the Xkb extension. + if ((keycode >= 0) && (keycode < 256)) + { + int result = _glfwLibrary.X11.Xkb.keyCodeLUT[keycode]; + if (result >= 0) + { + return result; + } + } + + // Last resort: Check the pimary keysym for printable keys. This will + // give a layout dependent mapping (which is wrong, and we may miss some + // keys, especially on non-US keyboards), but it's better than nothing... + switch (key) + { + case XK_a: return GLFW_KEY_A; + case XK_b: return GLFW_KEY_B; + case XK_c: return GLFW_KEY_C; + case XK_d: return GLFW_KEY_D; + case XK_e: return GLFW_KEY_E; + case XK_f: return GLFW_KEY_F; + case XK_g: return GLFW_KEY_G; + case XK_h: return GLFW_KEY_H; + case XK_i: return GLFW_KEY_I; + case XK_j: return GLFW_KEY_J; + case XK_k: return GLFW_KEY_K; + case XK_l: return GLFW_KEY_L; + case XK_m: return GLFW_KEY_M; + case XK_n: return GLFW_KEY_N; + case XK_o: return GLFW_KEY_O; + case XK_p: return GLFW_KEY_P; + case XK_q: return GLFW_KEY_Q; + case XK_r: return GLFW_KEY_R; + case XK_s: return GLFW_KEY_S; + case XK_t: return GLFW_KEY_T; + case XK_u: return GLFW_KEY_U; + case XK_v: return GLFW_KEY_V; + case XK_w: return GLFW_KEY_W; + case XK_x: return GLFW_KEY_X; + case XK_y: return GLFW_KEY_Y; + case XK_z: return GLFW_KEY_Z; + case XK_1: return GLFW_KEY_1; + case XK_2: return GLFW_KEY_2; + case XK_3: return GLFW_KEY_3; + case XK_4: return GLFW_KEY_4; + case XK_5: return GLFW_KEY_5; + case XK_6: return GLFW_KEY_6; + case XK_7: return GLFW_KEY_7; + case XK_8: return GLFW_KEY_8; + case XK_9: return GLFW_KEY_9; + case XK_0: return GLFW_KEY_0; + case XK_space: return GLFW_KEY_SPACE; + case XK_minus: return GLFW_KEY_MINUS; + case XK_equal: return GLFW_KEY_EQUAL; + case XK_bracketleft: return GLFW_KEY_LEFT_SQUARE_BRACKET; + case XK_bracketright: return GLFW_KEY_RIGHT_SQUARE_BRACKET; + case XK_backslash: return GLFW_KEY_BACKSLASH; + case XK_semicolon: return GLFW_KEY_SEMICOLON; + case XK_apostrophe: return GLFW_KEY_APOSTROPHE; + case XK_grave: return GLFW_KEY_GRAVE_ACCENT; + case XK_comma: return GLFW_KEY_COMMA; + case XK_period: return GLFW_KEY_PERIOD; + case XK_slash: return GLFW_KEY_SLASH; + case XK_less: return GLFW_KEY_WORLD_1; // At least in some layouts... + default: break; + } + + // No matching translation was found, so return -1 + return -1; } diff --git a/tests/events.c b/tests/events.c index e6fda25e..2998027d 100644 --- a/tests/events.c +++ b/tests/events.c @@ -46,8 +46,59 @@ static const char* get_key_name(int key) { switch (key) { - case GLFW_KEY_UNKNOWN: return "unknown"; + // Printable keys + case GLFW_KEY_A: return "a"; + case GLFW_KEY_B: return "b"; + case GLFW_KEY_C: return "c"; + case GLFW_KEY_D: return "d"; + case GLFW_KEY_E: return "e"; + case GLFW_KEY_F: return "f"; + case GLFW_KEY_G: return "g"; + case GLFW_KEY_H: return "h"; + case GLFW_KEY_I: return "i"; + case GLFW_KEY_J: return "j"; + case GLFW_KEY_K: return "k"; + case GLFW_KEY_L: return "l"; + case GLFW_KEY_M: return "m"; + case GLFW_KEY_N: return "n"; + case GLFW_KEY_O: return "o"; + case GLFW_KEY_P: return "p"; + case GLFW_KEY_Q: return "q"; + case GLFW_KEY_R: return "r"; + case GLFW_KEY_S: return "s"; + case GLFW_KEY_T: return "t"; + case GLFW_KEY_U: return "u"; + case GLFW_KEY_V: return "v"; + case GLFW_KEY_W: return "w"; + case GLFW_KEY_X: return "x"; + case GLFW_KEY_Y: return "y"; + case GLFW_KEY_Z: return "z"; + case GLFW_KEY_1: return "1"; + case GLFW_KEY_2: return "2"; + case GLFW_KEY_3: return "3"; + case GLFW_KEY_4: return "4"; + case GLFW_KEY_5: return "5"; + case GLFW_KEY_6: return "6"; + case GLFW_KEY_7: return "7"; + case GLFW_KEY_8: return "8"; + case GLFW_KEY_9: return "9"; + case GLFW_KEY_0: return "0"; case GLFW_KEY_SPACE: return "space"; + case GLFW_KEY_MINUS: return "-"; + case GLFW_KEY_EQUAL: return "="; + case GLFW_KEY_LEFT_SQUARE_BRACKET: return "["; + case GLFW_KEY_RIGHT_SQUARE_BRACKET: return "]"; + case GLFW_KEY_BACKSLASH: return "\\"; + case GLFW_KEY_SEMICOLON: return ";"; + case GLFW_KEY_APOSTROPHE: return "'"; + case GLFW_KEY_GRAVE_ACCENT: return "`"; + case GLFW_KEY_COMMA: return ","; + case GLFW_KEY_PERIOD: return "."; + case GLFW_KEY_SLASH: return "/"; + case GLFW_KEY_WORLD_1: return "world 1"; + case GLFW_KEY_WORLD_2: return "world 2"; + + // Special keys case GLFW_KEY_ESC: return "escape"; case GLFW_KEY_F1: return "F1"; case GLFW_KEY_F2: return "F2"; @@ -78,19 +129,19 @@ static const char* get_key_name(int key) case GLFW_KEY_DOWN: return "down"; case GLFW_KEY_LEFT: return "left"; case GLFW_KEY_RIGHT: return "right"; - case GLFW_KEY_LSHIFT: return "left shift"; - case GLFW_KEY_RSHIFT: return "right shift"; - case GLFW_KEY_LCTRL: return "left control"; - case GLFW_KEY_RCTRL: return "right control"; - case GLFW_KEY_LALT: return "left alt"; - case GLFW_KEY_RALT: return "right alt"; + case GLFW_KEY_LEFT_SHIFT: return "left shift"; + case GLFW_KEY_RIGHT_SHIFT: return "right shift"; + case GLFW_KEY_LEFT_CONTROL: return "left control"; + case GLFW_KEY_RIGHT_CONTROL: return "right control"; + case GLFW_KEY_LEFT_ALT: return "left alt"; + case GLFW_KEY_RIGHT_ALT: return "right alt"; case GLFW_KEY_TAB: return "tab"; case GLFW_KEY_ENTER: return "enter"; case GLFW_KEY_BACKSPACE: return "backspace"; case GLFW_KEY_INSERT: return "insert"; - case GLFW_KEY_DEL: return "delete"; - case GLFW_KEY_PAGEUP: return "page up"; - case GLFW_KEY_PAGEDOWN: return "page down"; + case GLFW_KEY_DELETE: return "delete"; + case GLFW_KEY_PAGE_UP: return "page up"; + case GLFW_KEY_PAGE_DOWN: return "page down"; case GLFW_KEY_HOME: return "home"; case GLFW_KEY_END: return "end"; case GLFW_KEY_KP_0: return "keypad 0"; @@ -110,12 +161,12 @@ static const char* get_key_name(int key) case GLFW_KEY_KP_DECIMAL: return "keypad decimal"; case GLFW_KEY_KP_EQUAL: return "keypad equal"; case GLFW_KEY_KP_ENTER: return "keypad enter"; - case GLFW_KEY_KP_NUM_LOCK: return "keypad num lock"; + case GLFW_KEY_NUM_LOCK: return "num lock"; case GLFW_KEY_CAPS_LOCK: return "caps lock"; case GLFW_KEY_SCROLL_LOCK: return "scroll lock"; case GLFW_KEY_PAUSE: return "pause"; - case GLFW_KEY_LSUPER: return "left super"; - case GLFW_KEY_RSUPER: return "right super"; + case GLFW_KEY_LEFT_SUPER: return "left super"; + case GLFW_KEY_RIGHT_SUPER: return "right super"; case GLFW_KEY_MENU: return "menu"; } @@ -231,8 +282,6 @@ static void key_callback(GLFWwindow window, int key, int action) if (name) printf(" (%s) was %s\n", name, get_action_name(action)); - else if (isgraph(key)) - printf(" (%c) was %s\n", key, get_action_name(action)); else printf(" was %s\n", get_action_name(action)); @@ -241,7 +290,7 @@ static void key_callback(GLFWwindow window, int key, int action) switch (key) { - case 'R': + case GLFW_KEY_R: { keyrepeat = !keyrepeat; if (keyrepeat) @@ -253,7 +302,7 @@ static void key_callback(GLFWwindow window, int key, int action) break; } - case 'S': + case GLFW_KEY_S: { systemkeys = !systemkeys; if (systemkeys)