This commit is contained in:
Andrew Corrigan 2014-05-18 10:03:33 +00:00
commit f3f8d9ddc6
4 changed files with 157 additions and 124 deletions

View File

@ -261,11 +261,12 @@ if (_GLFW_X11)
# Check for Xkb (X keyboard extension) # Check for Xkb (X keyboard extension)
if (NOT X11_Xkb_FOUND) 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() endif()
list(APPEND glfw_INCLUDE_DIR ${X11_Xkb_INCLUDE_PATH})
find_library(RT_LIBRARY rt) find_library(RT_LIBRARY rt)
mark_as_advanced(RT_LIBRARY) mark_as_advanced(RT_LIBRARY)
if (RT_LIBRARY) if (RT_LIBRARY)

View File

@ -70,6 +70,8 @@
#cmakedefine _GLFW_HAS_GLXGETPROCADDRESSEXT #cmakedefine _GLFW_HAS_GLXGETPROCADDRESSEXT
// Define this to 1 if dlopen is available // Define this to 1 if dlopen is available
#cmakedefine _GLFW_HAS_DLOPEN #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 // Define this to 1 if glfwInit should change the current directory
#cmakedefine _GLFW_USE_CHDIR #cmakedefine _GLFW_USE_CHDIR

View File

@ -40,39 +40,57 @@
static int translateKey(int keyCode) static int translateKey(int keyCode)
{ {
int keySym; int keySym;
int keysyms_per_keycode_return;
KeySym *keysyms;
// Valid key code range is [8,255], according to the XLib manual // Valid key code range is [8,255], according to the XLib manual
if (keyCode < 8 || keyCode > 255) if (keyCode < 8 || keyCode > 255)
return GLFW_KEY_UNKNOWN; return GLFW_KEY_UNKNOWN;
// Try secondary keysym, for numeric keypad keys #if defined(_GLFW_HAS_XKB)
// Note: This way we always force "NumLock = ON", which is intentional if(_glfw.x11.xkb.available)
// 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; // Try secondary keysym, for numeric keypad keys
case XK_KP_1: return GLFW_KEY_KP_1; // Note: This way we always force "NumLock = ON", which is intentional
case XK_KP_2: return GLFW_KEY_KP_2; // since the returned key code should correspond to a physical
case XK_KP_3: return GLFW_KEY_KP_3; // location.
case XK_KP_4: return GLFW_KEY_KP_4; keySym = XkbKeycodeToKeysym(_glfw.x11.display, keyCode, 0, 1);
case XK_KP_5: return GLFW_KEY_KP_5; switch (keySym)
case XK_KP_6: return GLFW_KEY_KP_6; {
case XK_KP_7: return GLFW_KEY_KP_7; case XK_KP_0: return GLFW_KEY_KP_0;
case XK_KP_8: return GLFW_KEY_KP_8; case XK_KP_1: return GLFW_KEY_KP_1;
case XK_KP_9: return GLFW_KEY_KP_9; case XK_KP_2: return GLFW_KEY_KP_2;
case XK_KP_Separator: case XK_KP_3: return GLFW_KEY_KP_3;
case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; case XK_KP_4: return GLFW_KEY_KP_4;
case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; case XK_KP_5: return GLFW_KEY_KP_5;
case XK_KP_Enter: return GLFW_KEY_KP_ENTER; case XK_KP_6: return GLFW_KEY_KP_6;
default: break; 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) switch (keySym)
{ {
case XK_Escape: return GLFW_KEY_ESCAPE; case XK_Escape: return GLFW_KEY_ESCAPE;
@ -217,92 +235,100 @@ static int translateKey(int keyCode)
// //
static void updateKeyCodeLUT(void) static void updateKeyCodeLUT(void)
{ {
int i, keyCode, keyCodeGLFW; int keyCode;
#if defined(_GLFW_HAS_XKB)
int keyCodeGLFW, i;
char name[XkbKeyNameLength + 1]; char name[XkbKeyNameLength + 1];
XkbDescPtr descr; XkbDescPtr descr;
#endif
// Clear the LUT // Clear the LUT
for (keyCode = 0; keyCode < 256; keyCode++) for (keyCode = 0; keyCode < 256; keyCode++)
_glfw.x11.keyCodeLUT[keyCode] = GLFW_KEY_UNKNOWN; _glfw.x11.keyCodeLUT[keyCode] = GLFW_KEY_UNKNOWN;
// Use XKB to determine physical key locations independently of the current #if defined(_GLFW_HAS_XKB)
// keyboard layout if(_glfw.x11.xkb.available)
// 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)
{ {
// Get the key name // Use XKB to determine physical key locations independently of the current
for (i = 0; i < XkbKeyNameLength; i++) // keyboard layout
name[i] = descr->names->keys[keyCode].name[i];
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 // Find the X11 key code -> GLFW key code mapping
// keys here, and we use the US keyboard layout. The rest of the for (keyCode = descr->min_key_code; keyCode <= descr->max_key_code; ++keyCode)
// keys (function keys) are mapped using traditional KeySym {
// translations. // Get the key name
if (strcmp(name, "TLDE") == 0) keyCodeGLFW = GLFW_KEY_GRAVE_ACCENT; for (i = 0; i < XkbKeyNameLength; i++)
else if (strcmp(name, "AE01") == 0) keyCodeGLFW = GLFW_KEY_1; name[i] = descr->names->keys[keyCode].name[i];
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 name[XkbKeyNameLength] = 0;
if ((keyCode >= 0) && (keyCode < 256))
_glfw.x11.keyCodeLUT[keyCode] = keyCodeGLFW; // 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);
} }
#endif
// Free the keyboard description
XkbFreeKeyboard(descr, 0, True);
// Translate the un-translated key codes using traditional X11 KeySym // Translate the un-translated key codes using traditional X11 KeySym
// lookups // lookups
@ -431,7 +457,9 @@ static void detectEWMH(void)
// //
static GLboolean initExtensions(void) static GLboolean initExtensions(void)
{ {
#if defined(_GLFW_HAS_XKB) // suppress unused variable warning
Bool supported; Bool supported;
#endif
// Find or create window manager atoms // Find or create window manager atoms
_glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display, _glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display,
@ -494,33 +522,32 @@ static GLboolean initExtensions(void)
} }
// Check if Xkb is supported on this display // Check if Xkb is supported on this display
#if defined(_GLFW_HAS_XKB)
_glfw.x11.xkb.versionMajor = 1; _glfw.x11.xkb.versionMajor = 1;
_glfw.x11.xkb.versionMinor = 0; _glfw.x11.xkb.versionMinor = 0;
if (!XkbQueryExtension(_glfw.x11.display, _glfw.x11.xkb.available =
&_glfw.x11.xkb.majorOpcode, XkbQueryExtension(_glfw.x11.display,
&_glfw.x11.xkb.eventBase, &_glfw.x11.xkb.majorOpcode,
&_glfw.x11.xkb.errorBase, &_glfw.x11.xkb.eventBase,
&_glfw.x11.xkb.versionMajor, &_glfw.x11.xkb.errorBase,
&_glfw.x11.xkb.versionMinor)) &_glfw.x11.xkb.versionMajor,
{ &_glfw.x11.xkb.versionMinor);
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: The keyboard extension is not available");
return GL_FALSE;
}
if (!XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) if (_glfw.x11.xkb.available)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, if (!XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported))
"X11: Failed to set detectable key repeat"); {
return GL_FALSE; // X11: Failed to set detectable key repeat
} _glfw.x11.xkb.available = GL_FALSE;
}
if (!supported) if (!supported)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, // X11: Detectable key repeat is not supported
"X11: Detectable key repeat is not supported"); _glfw.x11.xkb.available = GL_FALSE;
return GL_FALSE; }
} }
#endif
// Update the key code LUT // Update the key code LUT
// FIXME: We should listen to XkbMapNotify events to track changes to // FIXME: We should listen to XkbMapNotify events to track changes to

View File

@ -46,7 +46,9 @@
#include <X11/extensions/XInput2.h> #include <X11/extensions/XInput2.h>
// The Xkb extension provides improved keyboard support // The Xkb extension provides improved keyboard support
#include <X11/XKBlib.h> #if defined(_GLFW_HAS_XKB)
#include <X11/XKBlib.h>
#endif
#include "posix_tls.h" #include "posix_tls.h"
@ -175,6 +177,7 @@ typedef struct _GLFWlibraryX11
} randr; } randr;
struct { struct {
GLboolean available;
int majorOpcode; int majorOpcode;
int eventBase; int eventBase;
int errorBase; int errorBase;