From d2a2d1ff571e6f55d5c165104b06cfb11c44bc51 Mon Sep 17 00:00:00 2001 From: Andrew Corrigan Date: Thu, 24 Apr 2014 01:10:58 -0400 Subject: [PATCH] Automatically disables Xkb at either run-time or compile-time. Uses XGetKeyboardMapping as a fallback. --- CMakeLists.txt | 7 +- src/glfw_config.h.in | 2 + src/x11_init.c | 267 ++++++++++++++++++++++++------------------- src/x11_platform.h | 5 +- 4 files changed, 157 insertions(+), 124 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 743e72d16..a15860184 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -261,11 +261,12 @@ if (_GLFW_X11) # Check for Xkb (X keyboard extension) if (NOT X11_Xkb_FOUND) - message(FATAL_ERROR "The X keyboard extension headers were not found") + message("The X keyboard extension headers were not found") + else() + list(APPEND glfw_INCLUDE_DIR ${X11_Xkb_INCLUDE_PATH}) + set(_GLFW_HAS_XKB 1) endif() - list(APPEND glfw_INCLUDE_DIR ${X11_Xkb_INCLUDE_PATH}) - find_library(RT_LIBRARY rt) mark_as_advanced(RT_LIBRARY) if (RT_LIBRARY) diff --git a/src/glfw_config.h.in b/src/glfw_config.h.in index 676bf380e..d52af6bc9 100644 --- a/src/glfw_config.h.in +++ b/src/glfw_config.h.in @@ -70,6 +70,8 @@ #cmakedefine _GLFW_HAS_GLXGETPROCADDRESSEXT // Define this to 1 if dlopen is available #cmakedefine _GLFW_HAS_DLOPEN +// Define this to 1 if Xkb is available +#cmakedefine _GLFW_HAS_XKB // Define this to 1 if glfwInit should change the current directory #cmakedefine _GLFW_USE_CHDIR diff --git a/src/x11_init.c b/src/x11_init.c index ab07fe323..fdc81d1dc 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -40,39 +40,57 @@ static int translateKey(int keyCode) { int keySym; + int keysyms_per_keycode_return; + KeySym *keysyms; // Valid key code range is [8,255], according to the XLib manual if (keyCode < 8 || keyCode > 255) return GLFW_KEY_UNKNOWN; - // Try secondary keysym, for 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. - keySym = XkbKeycodeToKeysym(_glfw.x11.display, keyCode, 0, 1); - switch (keySym) +#if defined(_GLFW_HAS_XKB) + if(_glfw.x11.xkb.available) { - 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; + // Try secondary keysym, for 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. + keySym = XkbKeycodeToKeysym(_glfw.x11.display, keyCode, 0, 1); + switch (keySym) + { + 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; + } + + // 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). + keySym = XkbKeycodeToKeysym(_glfw.x11.display, keyCode, 0, 0); + } + else +#endif + { + keysyms = + XGetKeyboardMapping(_glfw.x11.display, + keyCode, + 1, + &keysyms_per_keycode_return); + keySym = keysyms[0]; + XFree(keysyms); } - // 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). - keySym = XkbKeycodeToKeysym(_glfw.x11.display, keyCode, 0, 0); switch (keySym) { case XK_Escape: return GLFW_KEY_ESCAPE; @@ -217,92 +235,100 @@ static int translateKey(int keyCode) // static void updateKeyCodeLUT(void) { - int i, keyCode, keyCodeGLFW; + int keyCode; +#if defined(_GLFW_HAS_XKB) + int keyCodeGLFW, i; char name[XkbKeyNameLength + 1]; XkbDescPtr descr; +#endif // Clear the LUT for (keyCode = 0; keyCode < 256; keyCode++) _glfw.x11.keyCodeLUT[keyCode] = GLFW_KEY_UNKNOWN; - // Use XKB to determine physical key locations independently of the current - // keyboard layout - - // Get keyboard description - descr = XkbGetKeyboard(_glfw.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) +#if defined(_GLFW_HAS_XKB) + if(_glfw.x11.xkb.available) { - // Get the key name - for (i = 0; i < XkbKeyNameLength; i++) - name[i] = descr->names->keys[keyCode].name[i]; + // Use XKB to determine physical key locations independently of the current + // keyboard layout - name[XkbKeyNameLength] = 0; + // Get keyboard description + descr = XkbGetKeyboard(_glfw.x11.display, + XkbAllComponentsMask, + XkbUseCoreKbd); - // Map the key name to a GLFW key code. Note: We only map printable - // keys here, and we use the US keyboard layout. The rest of the - // keys (function keys) are mapped using traditional KeySym - // translations. - 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_BRACKET; - else if (strcmp(name, "AD12") == 0) keyCodeGLFW = GLFW_KEY_RIGHT_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 = GLFW_KEY_UNKNOWN; + // 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]; - // Update the key code LUT - if ((keyCode >= 0) && (keyCode < 256)) - _glfw.x11.keyCodeLUT[keyCode] = keyCodeGLFW; + 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. The rest of the + // keys (function keys) are mapped using traditional KeySym + // translations. + 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_BRACKET; + else if (strcmp(name, "AD12") == 0) keyCodeGLFW = GLFW_KEY_RIGHT_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 = GLFW_KEY_UNKNOWN; + + // Update the key code LUT + if ((keyCode >= 0) && (keyCode < 256)) + _glfw.x11.keyCodeLUT[keyCode] = keyCodeGLFW; + } + + // Free the keyboard description + XkbFreeKeyboard(descr, 0, True); } - - // Free the keyboard description - XkbFreeKeyboard(descr, 0, True); +#endif // Translate the un-translated key codes using traditional X11 KeySym // lookups @@ -431,7 +457,9 @@ static void detectEWMH(void) // static GLboolean initExtensions(void) { +#if defined(_GLFW_HAS_XKB) // suppress unused variable warning Bool supported; +#endif // Find or create window manager atoms _glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display, @@ -494,33 +522,32 @@ static GLboolean initExtensions(void) } // Check if Xkb is supported on this display +#if defined(_GLFW_HAS_XKB) _glfw.x11.xkb.versionMajor = 1; _glfw.x11.xkb.versionMinor = 0; - if (!XkbQueryExtension(_glfw.x11.display, - &_glfw.x11.xkb.majorOpcode, - &_glfw.x11.xkb.eventBase, - &_glfw.x11.xkb.errorBase, - &_glfw.x11.xkb.versionMajor, - &_glfw.x11.xkb.versionMinor)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: The keyboard extension is not available"); - return GL_FALSE; - } + _glfw.x11.xkb.available = + XkbQueryExtension(_glfw.x11.display, + &_glfw.x11.xkb.majorOpcode, + &_glfw.x11.xkb.eventBase, + &_glfw.x11.xkb.errorBase, + &_glfw.x11.xkb.versionMajor, + &_glfw.x11.xkb.versionMinor); - if (!XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) + if (_glfw.x11.xkb.available) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Failed to set detectable key repeat"); - return GL_FALSE; - } + if (!XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) + { + // X11: Failed to set detectable key repeat + _glfw.x11.xkb.available = GL_FALSE; + } - if (!supported) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Detectable key repeat is not supported"); - return GL_FALSE; + if (!supported) + { + // X11: Detectable key repeat is not supported + _glfw.x11.xkb.available = GL_FALSE; + } } +#endif // Update the key code LUT // FIXME: We should listen to XkbMapNotify events to track changes to diff --git a/src/x11_platform.h b/src/x11_platform.h index 785b2eadd..cdd91fb6b 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -46,7 +46,9 @@ #include // The Xkb extension provides improved keyboard support -#include +#if defined(_GLFW_HAS_XKB) + #include +#endif #include "posix_tls.h" @@ -175,6 +177,7 @@ typedef struct _GLFWlibraryX11 } randr; struct { + GLboolean available; int majorOpcode; int eventBase; int errorBase;