From caf9a12b34d28f1d54f120ddaad412d720e638a6 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 30 Mar 2018 00:57:02 +0530 Subject: [PATCH] Update glfw from upstream libxkbcommon based keyboard handling now works (at least the basic stuff, haven't tested compose/mapnotify etc.) --- glfw/glfw3.h | 173 +------- glfw/input.c | 187 ++++++--- glfw/internal.h | 10 +- glfw/source-info.json | 7 +- glfw/window.c | 2 +- glfw/wl_init.c | 86 +--- glfw/wl_platform.h | 7 +- glfw/wl_window.c | 9 +- glfw/x11_init.c | 404 ++---------------- glfw/x11_platform.h | 25 +- glfw/x11_window.c | 208 ++-------- glfw/xkb_glfw.c | 385 +++++++++++++++++ glfw/xkb_glfw.h | 353 ++-------------- glfw/xkb_unicode.c | 940 ------------------------------------------ glfw/xkb_unicode.h | 28 -- kitty/glfw-wrapper.c | 10 +- kitty/glfw-wrapper.h | 73 +--- 17 files changed, 664 insertions(+), 2243 deletions(-) create mode 100644 glfw/xkb_glfw.c delete mode 100644 glfw/xkb_unicode.c delete mode 100644 glfw/xkb_unicode.h diff --git a/glfw/glfw3.h b/glfw/glfw3.h index 9361ea92d..005144276 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1375,9 +1375,15 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); */ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); -/*! @brief The function signature for keyboard key callbacks. +/*! @brief The function signature for key callbacks. * - * This is the function signature for keyboard key callback functions. + * This is the function signature for key callback functions. + * The semantics of this function are that the key that is interacted with on the + * keyboard is reported, and the text, if any generated by the key is reported. + * So, for example, if on a US-ASCII keyboard the user presses Shift+= GLFW + * will report the text "+" and the key as GLFW_KEY_EQUAL. The reported key takes into + * account any current keyboard maps defined in the OS. So with a dvorak mapping, pressing + * the "q" key will generate text "d" and GLFW_KEY_D. * * @param[in] window The window that received the event. * @param[in] key The [keyboard key](@ref keys) that was pressed or released. @@ -1385,56 +1391,17 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. + * @param[in] text UTF-8 encoded text generated by this key event or empty string. + * @param[in] reserved Reserved for future use. * * @sa @ref input_key - * @sa @ref glfwSetKeyCallback + * @sa @ref glfwSetKeyboardCallback * - * @since Added in version 1.0. - * @glfw3 Added window handle, scancode and modifier mask parameters. + * @since Added in version 4.0. * * @ingroup input */ -typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); - -/*! @brief The function signature for Unicode character callbacks. - * - * This is the function signature for Unicode character callback functions. - * - * @param[in] window The window that received the event. - * @param[in] codepoint The Unicode code point of the character. - * - * @sa @ref input_char - * @sa @ref glfwSetCharCallback - * - * @since Added in version 2.4. - * @glfw3 Added window handle parameter. - * - * @ingroup input - */ -typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); - -/*! @brief The function signature for Unicode character with modifiers - * callbacks. - * - * This is the function signature for Unicode character with modifiers callback - * functions. It is called for each input character, regardless of what - * modifier keys are held down. - * - * @param[in] window The window that received the event. - * @param[in] codepoint The Unicode code point of the character. - * @param[in] mods Bit field describing which [modifier keys](@ref mods) were - * held down. - * - * @sa @ref input_char - * @sa @ref glfwSetCharModsCallback - * - * @deprecated Scheduled for removal in version 4.0. - * - * @since Added in version 3.1. - * - * @ingroup input - */ -typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); +typedef void (* GLFWkeyboardfun)(GLFWwindow*, int, int, int, int, const char*, int); /*! @brief The function signature for file drop callbacks. * @@ -4232,121 +4199,11 @@ GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor); */ GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); -/*! @brief Sets the key callback. - * - * This function sets the key callback of the specified window, which is called - * when a key is pressed, repeated or released. - * - * The key functions deal with physical keys, with layout independent - * [key tokens](@ref keys) named after their values in the standard US keyboard - * layout. If you want to input text, use the - * [character callback](@ref glfwSetCharCallback) instead. - * - * When a window loses input focus, it will generate synthetic key release - * events for all pressed keys. You can tell these events from user-generated - * events by the fact that the synthetic ones are generated after the focus - * loss event has been processed, i.e. after the - * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. - * - * The scancode of a key is specific to that platform or sometimes even to that - * machine. Scancodes are intended to allow users to bind keys that don't have - * a GLFW key token. Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their - * state is not saved and so it cannot be queried with @ref glfwGetKey. - * - * Sometimes GLFW needs to generate synthetic key events, in which case the - * scancode may be zero. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new key callback, or `NULL` to remove the currently - * set callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_key - * - * @since Added in version 1.0. - * @glfw3 Added window handle parameter and return value. +/*! @brief Sets the callback for handling keyboard events. * * @ingroup input */ -GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); - -/*! @brief Sets the Unicode character callback. - * - * This function sets the character callback of the specified window, which is - * called when a Unicode character is input. - * - * The character callback is intended for Unicode text input. As it deals with - * characters, it is keyboard layout dependent, whereas the - * [key callback](@ref glfwSetKeyCallback) is not. Characters do not map 1:1 - * to physical keys, as a key may produce zero, one or more characters. If you - * want to know whether a specific physical key was pressed or released, see - * the key callback instead. - * - * The character callback behaves as system text input normally does and will - * not be called if modifier keys are held down that would prevent normal text - * input on that platform, for example a Super (Command) key on macOS or Alt key - * on Windows. There is a - * [character with modifiers callback](@ref glfwSetCharModsCallback) that - * receives these events. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or the - * library had not been [initialized](@ref intro_init). - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_char - * - * @since Added in version 2.4. - * @glfw3 Added window handle parameter and return value. - * - * @ingroup input - */ -GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); - -/*! @brief Sets the Unicode character with modifiers callback. - * - * This function sets the character with modifiers callback of the specified - * window, which is called when a Unicode character is input regardless of what - * modifier keys are used. - * - * The character with modifiers callback is intended for implementing custom - * Unicode character input. For regular Unicode text input, see the - * [character callback](@ref glfwSetCharCallback). Like the character - * callback, the character with modifiers callback deals with characters and is - * keyboard layout dependent. Characters do not map 1:1 to physical keys, as - * a key may produce zero, one or more characters. If you want to know whether - * a specific physical key was pressed or released, see the - * [key callback](@ref glfwSetKeyCallback) instead. - * - * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set - * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * [error](@ref error_handling) occurred. - * - * @deprecated Scheduled for removal in version 4.0. - * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa @ref input_char - * - * @since Added in version 3.1. - * - * @ingroup input - */ -GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun cbfun); +GLFWAPI GLFWkeyboardfun glfwSetKeyboardCallback(GLFWwindow* window, GLFWkeyboardfun cbfun); /*! @brief Sets the mouse button callback. * diff --git a/glfw/input.c b/glfw/input.c index c4f1e3037..e78a8c126 100644 --- a/glfw/input.c +++ b/glfw/input.c @@ -255,9 +255,9 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) ////// GLFW event API ////// ////////////////////////////////////////////////////////////////////////// -// Notifies shared code of a physical key event +// Notifies shared code of a key event // -void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods) +void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action, int mods, const char* text, int state) { if (key >= 0 && key <= GLFW_KEY_LAST) { @@ -278,31 +278,10 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int m action = GLFW_REPEAT; } - if (!window->lockKeyMods) - mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); - if (window->callbacks.key) - window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods); -} - -// Notifies shared code of a Unicode codepoint input event -// The 'plain' parameter determines whether to emit a regular character event -// -void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain) -{ - if (codepoint < 32 || (codepoint > 126 && codepoint < 160)) - return; - - if (!window->lockKeyMods) - mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); - - if (window->callbacks.charmods) - window->callbacks.charmods((GLFWwindow*) window, codepoint, mods); - - if (plain) - { - if (window->callbacks.character) - window->callbacks.character((GLFWwindow*) window, codepoint); + if (window->callbacks.keyboard) { + if (!window->lockKeyMods) mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + window->callbacks.keyboard((GLFWwindow*) window, key, scancode, action, mods, text, state); } } @@ -454,6 +433,137 @@ void _glfwFreeJoystick(_GLFWjoystick* js) memset(js, 0, sizeof(_GLFWjoystick)); } +const char* _glfwGetKeyName(int key) +{ + switch (key) + { + // 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 "MINUS"; + case GLFW_KEY_EQUAL: return "EQUAL"; + case GLFW_KEY_LEFT_BRACKET: return "LEFT BRACKET"; + case GLFW_KEY_RIGHT_BRACKET: return "RIGHT BRACKET"; + case GLFW_KEY_BACKSLASH: return "BACKSLASH"; + case GLFW_KEY_SEMICOLON: return "SEMICOLON"; + case GLFW_KEY_APOSTROPHE: return "APOSTROPHE"; + case GLFW_KEY_GRAVE_ACCENT: return "GRAVE ACCENT"; + case GLFW_KEY_COMMA: return "COMMA"; + case GLFW_KEY_PERIOD: return "PERIOD"; + case GLFW_KEY_SLASH: return "SLASH"; + case GLFW_KEY_WORLD_1: return "WORLD 1"; + case GLFW_KEY_WORLD_2: return "WORLD 2"; + + // Function keys + case GLFW_KEY_ESCAPE: return "ESCAPE"; + case GLFW_KEY_F1: return "F1"; + case GLFW_KEY_F2: return "F2"; + case GLFW_KEY_F3: return "F3"; + case GLFW_KEY_F4: return "F4"; + case GLFW_KEY_F5: return "F5"; + case GLFW_KEY_F6: return "F6"; + case GLFW_KEY_F7: return "F7"; + case GLFW_KEY_F8: return "F8"; + case GLFW_KEY_F9: return "F9"; + case GLFW_KEY_F10: return "F10"; + case GLFW_KEY_F11: return "F11"; + case GLFW_KEY_F12: return "F12"; + case GLFW_KEY_F13: return "F13"; + case GLFW_KEY_F14: return "F14"; + case GLFW_KEY_F15: return "F15"; + case GLFW_KEY_F16: return "F16"; + case GLFW_KEY_F17: return "F17"; + case GLFW_KEY_F18: return "F18"; + case GLFW_KEY_F19: return "F19"; + case GLFW_KEY_F20: return "F20"; + case GLFW_KEY_F21: return "F21"; + case GLFW_KEY_F22: return "F22"; + case GLFW_KEY_F23: return "F23"; + case GLFW_KEY_F24: return "F24"; + case GLFW_KEY_F25: return "F25"; + case GLFW_KEY_UP: return "UP"; + case GLFW_KEY_DOWN: return "DOWN"; + case GLFW_KEY_LEFT: return "LEFT"; + case GLFW_KEY_RIGHT: return "RIGHT"; + 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_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"; + case GLFW_KEY_KP_1: return "KEYPAD 1"; + case GLFW_KEY_KP_2: return "KEYPAD 2"; + case GLFW_KEY_KP_3: return "KEYPAD 3"; + case GLFW_KEY_KP_4: return "KEYPAD 4"; + case GLFW_KEY_KP_5: return "KEYPAD 5"; + case GLFW_KEY_KP_6: return "KEYPAD 6"; + case GLFW_KEY_KP_7: return "KEYPAD 7"; + case GLFW_KEY_KP_8: return "KEYPAD 8"; + case GLFW_KEY_KP_9: return "KEYPAD 9"; + case GLFW_KEY_KP_DIVIDE: return "KEYPAD DIVIDE"; + case GLFW_KEY_KP_MULTIPLY: return "KEYPAD MULTPLY"; + case GLFW_KEY_KP_SUBTRACT: return "KEYPAD SUBTRACT"; + case GLFW_KEY_KP_ADD: return "KEYPAD ADD"; + 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_PRINT_SCREEN: return "PRINT SCREEN"; + 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_LEFT_SUPER: return "LEFT SUPER"; + case GLFW_KEY_RIGHT_SUPER: return "RIGHT SUPER"; + case GLFW_KEY_MENU: return "MENU"; + + default: return "UNKNOWN"; + } +} ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// @@ -791,33 +901,13 @@ GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) _glfwPlatformSetCursor(window, cursor); } -GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) +GLFWAPI GLFWkeyboardfun glfwSetKeyboardCallback(GLFWwindow* handle, GLFWkeyboardfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.key, cbfun); - return cbfun; -} - -GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) -{ - _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window != NULL); - - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.character, cbfun); - return cbfun; -} - -GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun) -{ - _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window != NULL); - - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun); + _GLFW_SWAP_POINTERS(window->callbacks.keyboard, cbfun); return cbfun; } @@ -1305,4 +1395,3 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void) _GLFW_REQUIRE_INIT_OR_RETURN(0); return _glfwPlatformGetTimerFrequency(); } - diff --git a/glfw/internal.h b/glfw/internal.h index fb6317458..5e04a2e34 100644 --- a/glfw/internal.h +++ b/glfw/internal.h @@ -407,9 +407,7 @@ struct _GLFWwindow GLFWcursorposfun cursorPos; GLFWcursorenterfun cursorEnter; GLFWscrollfun scroll; - GLFWkeyfun key; - GLFWcharfun character; - GLFWcharmodsfun charmods; + GLFWkeyboardfun keyboard; GLFWdropfun drop; } callbacks; @@ -711,10 +709,7 @@ void _glfwInputWindowDamage(_GLFWwindow* window); void _glfwInputWindowCloseRequest(_GLFWwindow* window); void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor); -void _glfwInputKey(_GLFWwindow* window, - int key, int scancode, int action, int mods); -void _glfwInputChar(_GLFWwindow* window, - unsigned int codepoint, int mods, GLFWbool plain); +void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action, int mods, const char* text, int state); void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset); void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods); void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos); @@ -763,6 +758,7 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, int buttonCount, int hatCount); void _glfwFreeJoystick(_GLFWjoystick* js); +const char* _glfwGetKeyName(int key); GLFWbool _glfwInitVulkan(int mode); void _glfwTerminateVulkan(void); diff --git a/glfw/source-info.json b/glfw/source-info.json index 00070c09b..9bb069df8 100644 --- a/glfw/source-info.json +++ b/glfw/source-info.json @@ -58,7 +58,6 @@ "posix_time.h", "posix_thread.h", "xkb_glfw.h", - "xkb_unicode.h", "egl_context.h", "osmesa_context.h", "linux_joystick.h" @@ -76,7 +75,7 @@ "wl_window.c", "posix_time.c", "posix_thread.c", - "xkb_unicode.c", + "xkb_glfw.c", "egl_context.c", "osmesa_context.c", "linux_joystick.c" @@ -109,7 +108,7 @@ "x11": { "headers": [ "x11_platform.h", - "xkb_unicode.h", + "xkb_glfw.h", "posix_time.h", "posix_thread.h", "glx_context.h", @@ -121,7 +120,7 @@ "x11_init.c", "x11_monitor.c", "x11_window.c", - "xkb_unicode.c", + "xkb_glfw.c", "posix_time.c", "posix_thread.c", "glx_context.c", diff --git a/glfw/window.c b/glfw/window.c index 6be617433..9f6b660c6 100644 --- a/glfw/window.c +++ b/glfw/window.c @@ -54,7 +54,7 @@ void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused) if (window->keys[key] == GLFW_PRESS) { const int scancode = _glfwPlatformGetKeyScancode(key); - _glfwInputKey(window, key, scancode, GLFW_RELEASE, 0); + _glfwInputKeyboard(window, key, scancode, GLFW_RELEASE, 0, "", 0); } } diff --git a/glfw/wl_init.c b/glfw/wl_init.c index f9e356774..5576b9f6d 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -362,7 +362,7 @@ static void keyboardHandleKeymap(void* data, close(fd); return; } - xkb_glfw_compile_keymap(mapStr); + glfw_xkb_compile_keymap(&_glfw.wl.xkb, mapStr); munmap(mapStr, size); close(fd); @@ -404,54 +404,6 @@ static void keyboardHandleLeave(void* data, _glfwInputWindowFocus(window, GLFW_FALSE); } -static xkb_keysym_t composeSymbol(xkb_keysym_t sym) -{ - if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState) - return sym; - if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym) - != XKB_COMPOSE_FEED_ACCEPTED) - return sym; - switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState)) - { - case XKB_COMPOSE_COMPOSED: - return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState); - case XKB_COMPOSE_COMPOSING: - case XKB_COMPOSE_CANCELLED: - return XKB_KEY_NoSymbol; - case XKB_COMPOSE_NOTHING: - default: - return sym; - } -} - -static void inputChar(_GLFWwindow* window, uint32_t key, GLFWbool *shouldRepeat) -{ - uint32_t code, numSyms; - long cp; - const xkb_keysym_t *syms; - xkb_keysym_t sym; - - code = key + 8; - numSyms = xkb_state_key_get_syms(_glfw.wl.xkb.state, code, &syms); - *shouldRepeat = xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, code); - - if (numSyms == 1) - { - sym = composeSymbol(syms[0]); - cp = _glfwKeySym2Unicode(sym); - if (cp != -1) - { - const int mods = _glfw.wl.xkb.modifiers; - const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); - if (*shouldRepeat) { - _glfw.wl.keyRepeatInfo.codepoint = cp; - _glfw.wl.keyRepeatInfo.plain = plain; - } - _glfwInputChar(window, cp, mods, plain); - } - } -} - static void keyboardHandleKey(void* data, struct wl_keyboard* keyboard, uint32_t serial, @@ -459,34 +411,18 @@ static void keyboardHandleKey(void* data, uint32_t key, uint32_t state) { - int keyCode; - int action; _GLFWwindow* window = _glfw.wl.keyboardFocus; - if (!window) return; - - keyCode = xkb_glfw_to_glfw_key_code(key); - action = state == WL_KEYBOARD_KEY_STATE_PRESSED - ? GLFW_PRESS : GLFW_RELEASE; + int action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE; + glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, key, action); _glfw.wl.keyRepeatInfo.nextRepeatAt = 0; - _glfw.wl.keyRepeatInfo.codepoint = -1; - _glfwInputKey(window, keyCode, key, action, - _glfw.wl.xkb.modifiers); - - if (action == GLFW_PRESS) + if (action == GLFW_PRESS && _glfw.wl.keyboardRepeatRate > 0 && glfw_xkb_should_repeat(&_glfw.wl.xkb, key)) { - GLFWbool shouldRepeat = GLFW_FALSE; - inputChar(window, key, &shouldRepeat); - - if (shouldRepeat && _glfw.wl.keyboardRepeatRate > 0) - { - _glfw.wl.keyRepeatInfo.glfwKeyCode = keyCode; - _glfw.wl.keyRepeatInfo.scancode = key; - _glfw.wl.keyRepeatInfo.nextRepeatAt = glfwGetTime() + (double)(_glfw.wl.keyboardRepeatDelay) / 1000.0; - _glfw.wl.keyRepeatInfo.keyboardFocus = window; - } + _glfw.wl.keyRepeatInfo.key = key; + _glfw.wl.keyRepeatInfo.nextRepeatAt = glfwGetTime() + (double)(_glfw.wl.keyboardRepeatDelay) / 1000.0; + _glfw.wl.keyRepeatInfo.keyboardFocus = window; } } @@ -498,7 +434,7 @@ static void keyboardHandleModifiers(void* data, uint32_t modsLocked, uint32_t group) { - xkb_glfw_update_modifiers(modsDepressed, modsLatched, modsLocked, group); + glfw_xkb_update_modifiers(&_glfw.wl.xkb, modsDepressed, modsLatched, modsLocked, group); } static void keyboardHandleRepeatInfo(void* data, @@ -711,8 +647,6 @@ int _glfwPlatformInit(void) _glfw.wl.egl.window_resize = (PFN_wl_egl_window_resize) _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_resize"); - load_glfw_xkb(); - _glfw.wl.display = wl_display_connect(NULL); if (!_glfw.wl.display) { @@ -724,7 +658,7 @@ int _glfwPlatformInit(void) _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display); wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL); - create_glfw_xkb_context(); + if (!glfw_xkb_create_context(&_glfw.wl.xkb)) return GLFW_FALSE; // Sync so we got all registry objects wl_display_roundtrip(_glfw.wl.display); @@ -767,7 +701,7 @@ void _glfwPlatformTerminate(void) _glfw.wl.egl.handle = NULL; } - release_glfw_xkb(); + glfw_xkb_release(&_glfw.wl.xkb); if (_glfw.wl.cursorTheme) wl_cursor_theme_destroy(_glfw.wl.cursorTheme); diff --git a/glfw/wl_platform.h b/glfw/wl_platform.h index da472af60..2da58b8b4 100644 --- a/glfw/wl_platform.h +++ b/glfw/wl_platform.h @@ -48,9 +48,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #else #include "null_joystick.h" #endif -#define GLFW_XKB_GLOBAL_NAME _glfw.wl.xkb #include "xkb_glfw.h" -#include "xkb_unicode.h" #include "egl_context.h" #include "osmesa_context.h" @@ -204,10 +202,7 @@ typedef struct _GLFWlibraryWayland int32_t keyboardRepeatRate; int32_t keyboardRepeatDelay; struct { - long codepoint; - int plain; - int glfwKeyCode; - int scancode; + uint32_t key; double nextRepeatAt; _GLFWwindow* keyboardFocus; } keyRepeatInfo; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 333fd3721..92817a61b 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -693,10 +693,8 @@ static void dispatchPendingKeyRepeats() { if (_glfw.wl.keyRepeatInfo.nextRepeatAt <= 0 || _glfw.wl.keyRepeatInfo.keyboardFocus != _glfw.wl.keyboardFocus || _glfw.wl.keyboardRepeatRate == 0) return; double now = glfwGetTime(); - const int mods = _glfw.wl.xkb.modifiers; while (_glfw.wl.keyRepeatInfo.nextRepeatAt <= now) { - _glfwInputKey(_glfw.wl.keyRepeatInfo.keyboardFocus, _glfw.wl.keyRepeatInfo.glfwKeyCode, _glfw.wl.keyRepeatInfo.scancode, GLFW_REPEAT, mods); - if (_glfw.wl.keyRepeatInfo.codepoint > -1) _glfwInputChar(_glfw.wl.keyRepeatInfo.keyboardFocus, _glfw.wl.keyRepeatInfo.codepoint, mods, _glfw.wl.keyRepeatInfo.plain); + glfw_xkb_handle_key_event(_glfw.wl.keyRepeatInfo.keyboardFocus, &_glfw.wl.xkb, _glfw.wl.keyRepeatInfo.key, GLFW_REPEAT); _glfw.wl.keyRepeatInfo.nextRepeatAt += 1.0 / _glfw.wl.keyboardRepeatRate; now = glfwGetTime(); } @@ -1244,13 +1242,12 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) const char* _glfwPlatformGetScancodeName(int scancode) { - // TODO - return NULL; + return glfw_xkb_keysym_name(scancode); } int _glfwPlatformGetKeyScancode(int key) { - return _glfw.wl.xkb.scancodes[key]; + return glfw_xkb_sym_for_key(key); } int _glfwPlatformCreateCursor(_GLFWcursor* cursor, diff --git a/glfw/x11_init.c b/glfw/x11_init.c index af4fb7ed6..cde6569d7 100644 --- a/glfw/x11_init.c +++ b/glfw/x11_init.c @@ -36,319 +36,6 @@ #include -// Translate an X11 key code to a GLFW key code. -// -static int translateKeyCode(int scancode) -{ - int keySym; - - // Valid key code range is [8,255], according to the Xlib manual - if (scancode < 8 || scancode > 255) - return GLFW_KEY_UNKNOWN; - - if (_glfw.x11.xkb.available) - { - // 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, scancode, 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 primary keysym for function keys (non-printable keys) - // These should not depend on the current keyboard layout - keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); - } - else - { - int dummy; - KeySym* keySyms; - - keySyms = XGetKeyboardMapping(_glfw.x11.display, scancode, 1, &dummy); - keySym = keySyms[0]; - XFree(keySyms); - } - - switch (keySym) - { - 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_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_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_Print: return GLFW_KEY_PRINT_SCREEN; - 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 - 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; - - // 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; - - // Last resort: Check for printable keys (should not happen if the XKB - // extension is available). 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... - 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_BRACKET; - case XK_bracketright: return GLFW_KEY_RIGHT_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 - return GLFW_KEY_UNKNOWN; -} - -// Create key code translation tables -// -static void createKeyTables(void) -{ - int scancode, key; - - memset(_glfw.x11.keycodes, -1, sizeof(_glfw.x11.keycodes)); - memset(_glfw.x11.scancodes, -1, sizeof(_glfw.x11.scancodes)); - - if (_glfw.x11.xkb.available) - { - // Use XKB to determine physical key locations independently of the - // current keyboard layout - - char name[XkbKeyNameLength + 1]; - XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd); - XkbGetNames(_glfw.x11.display, XkbKeyNamesMask, desc); - - // Find the X11 key code -> GLFW key code mapping - for (scancode = desc->min_key_code; scancode <= desc->max_key_code; scancode++) - { - memcpy(name, desc->names->keys[scancode].name, XkbKeyNameLength); - 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) key = GLFW_KEY_GRAVE_ACCENT; - else if (strcmp(name, "AE01") == 0) key = GLFW_KEY_1; - else if (strcmp(name, "AE02") == 0) key = GLFW_KEY_2; - else if (strcmp(name, "AE03") == 0) key = GLFW_KEY_3; - else if (strcmp(name, "AE04") == 0) key = GLFW_KEY_4; - else if (strcmp(name, "AE05") == 0) key = GLFW_KEY_5; - else if (strcmp(name, "AE06") == 0) key = GLFW_KEY_6; - else if (strcmp(name, "AE07") == 0) key = GLFW_KEY_7; - else if (strcmp(name, "AE08") == 0) key = GLFW_KEY_8; - else if (strcmp(name, "AE09") == 0) key = GLFW_KEY_9; - else if (strcmp(name, "AE10") == 0) key = GLFW_KEY_0; - else if (strcmp(name, "AE11") == 0) key = GLFW_KEY_MINUS; - else if (strcmp(name, "AE12") == 0) key = GLFW_KEY_EQUAL; - else if (strcmp(name, "AD01") == 0) key = GLFW_KEY_Q; - else if (strcmp(name, "AD02") == 0) key = GLFW_KEY_W; - else if (strcmp(name, "AD03") == 0) key = GLFW_KEY_E; - else if (strcmp(name, "AD04") == 0) key = GLFW_KEY_R; - else if (strcmp(name, "AD05") == 0) key = GLFW_KEY_T; - else if (strcmp(name, "AD06") == 0) key = GLFW_KEY_Y; - else if (strcmp(name, "AD07") == 0) key = GLFW_KEY_U; - else if (strcmp(name, "AD08") == 0) key = GLFW_KEY_I; - else if (strcmp(name, "AD09") == 0) key = GLFW_KEY_O; - else if (strcmp(name, "AD10") == 0) key = GLFW_KEY_P; - else if (strcmp(name, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET; - else if (strcmp(name, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET; - else if (strcmp(name, "AC01") == 0) key = GLFW_KEY_A; - else if (strcmp(name, "AC02") == 0) key = GLFW_KEY_S; - else if (strcmp(name, "AC03") == 0) key = GLFW_KEY_D; - else if (strcmp(name, "AC04") == 0) key = GLFW_KEY_F; - else if (strcmp(name, "AC05") == 0) key = GLFW_KEY_G; - else if (strcmp(name, "AC06") == 0) key = GLFW_KEY_H; - else if (strcmp(name, "AC07") == 0) key = GLFW_KEY_J; - else if (strcmp(name, "AC08") == 0) key = GLFW_KEY_K; - else if (strcmp(name, "AC09") == 0) key = GLFW_KEY_L; - else if (strcmp(name, "AC10") == 0) key = GLFW_KEY_SEMICOLON; - else if (strcmp(name, "AC11") == 0) key = GLFW_KEY_APOSTROPHE; - else if (strcmp(name, "AB01") == 0) key = GLFW_KEY_Z; - else if (strcmp(name, "AB02") == 0) key = GLFW_KEY_X; - else if (strcmp(name, "AB03") == 0) key = GLFW_KEY_C; - else if (strcmp(name, "AB04") == 0) key = GLFW_KEY_V; - else if (strcmp(name, "AB05") == 0) key = GLFW_KEY_B; - else if (strcmp(name, "AB06") == 0) key = GLFW_KEY_N; - else if (strcmp(name, "AB07") == 0) key = GLFW_KEY_M; - else if (strcmp(name, "AB08") == 0) key = GLFW_KEY_COMMA; - else if (strcmp(name, "AB09") == 0) key = GLFW_KEY_PERIOD; - else if (strcmp(name, "AB10") == 0) key = GLFW_KEY_SLASH; - else if (strcmp(name, "BKSL") == 0) key = GLFW_KEY_BACKSLASH; - else if (strcmp(name, "LSGT") == 0) key = GLFW_KEY_WORLD_1; - else key = GLFW_KEY_UNKNOWN; - - if ((scancode >= 0) && (scancode < 256)) - _glfw.x11.keycodes[scancode] = key; - } - - XkbFreeNames(desc, XkbKeyNamesMask, True); - XkbFreeKeyboard(desc, 0, True); - } - - for (scancode = 0; scancode < 256; scancode++) - { - // Translate the un-translated key codes using traditional X11 KeySym - // lookups - if (_glfw.x11.keycodes[scancode] < 0) - _glfw.x11.keycodes[scancode] = translateKeyCode(scancode); - - // Store the reverse translation for faster key name lookup - if (_glfw.x11.keycodes[scancode] > 0) - _glfw.x11.scancodes[_glfw.x11.keycodes[scancode]] = scancode; - } -} - -// Check whether the IM has a usable style -// -static GLFWbool hasUsableInputMethodStyle(void) -{ - unsigned int i; - GLFWbool found = GLFW_FALSE; - XIMStyles* styles = NULL; - - if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL) - return GLFW_FALSE; - - for (i = 0; i < styles->count_styles; i++) - { - if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) - { - found = GLFW_TRUE; - break; - } - } - - XFree(styles); - return found; -} - // Check whether the specified atom is supported // static Atom getSupportedAtom(Atom* supportedAtoms, @@ -623,33 +310,14 @@ static GLFWbool initExtensions(void) } } - _glfw.x11.xkb.major = 1; - _glfw.x11.xkb.minor = 0; - _glfw.x11.xkb.available = - XkbQueryExtension(_glfw.x11.display, - &_glfw.x11.xkb.majorOpcode, - &_glfw.x11.xkb.eventBase, - &_glfw.x11.xkb.errorBase, - &_glfw.x11.xkb.major, - &_glfw.x11.xkb.minor); - - if (_glfw.x11.xkb.available) - { - Bool supported; - - if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) - { - if (supported) - _glfw.x11.xkb.detectable = GLFW_TRUE; - } - } - _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so.1"); - if (_glfw.x11.x11xcb.handle) + if (!_glfw.x11.x11xcb.handle) { - _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection) - _glfw_dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to load libX11-xcb"); + return GLFW_FALSE; } + _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection) + _glfw_dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so.1"); if (_glfw.x11.xrender.handle) @@ -674,10 +342,31 @@ static GLFWbool initExtensions(void) } } - // Update the key code LUT - // FIXME: We should listen to XkbMapNotify events to track changes to - // the keyboard mapping. - createKeyTables(); + _glfw.x11.xkb.major = 1; + _glfw.x11.xkb.minor = 0; + _glfw.x11.xkb.available = XkbQueryExtension(_glfw.x11.display, + &_glfw.x11.xkb.majorOpcode, + &_glfw.x11.xkb.eventBase, + &_glfw.x11.xkb.errorBase, + &_glfw.x11.xkb.major, + &_glfw.x11.xkb.minor); + + if (!_glfw.x11.xkb.available) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to load Xkb extension"); + return GLFW_FALSE; + } + Bool supported; + if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) + { + if (supported) + _glfw.x11.xkb.detectable = GLFW_TRUE; + } + + if (!glfw_xkb_set_x11_events_mask()) return GLFW_FALSE; + if (!glfw_xkb_create_context(&_glfw.x11.xkb)) return GLFW_FALSE; + if (!glfw_xkb_update_x11_keyboard_id(&_glfw.x11.xkb)) return GLFW_FALSE; + if (!glfw_xkb_compile_keymap(&_glfw.x11.xkb, NULL)) return GLFW_FALSE; // Detect whether an EWMH-conformant window manager is running detectEWMH(); @@ -896,16 +585,6 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) int _glfwPlatformInit(void) { -#if !defined(X_HAVE_UTF8_STRING) - // HACK: If the current locale is "C" and the Xlib UTF-8 functions are - // unavailable, apply the environment's locale in the hope that it's - // both available and not "C" - // This is done because the "C" locale breaks wide character input, - // which is what we fall back on when UTF-8 support is missing - if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0) - setlocale(LC_CTYPE, ""); -#endif - XInitThreads(); XrmInitialize(); @@ -939,21 +618,6 @@ int _glfwPlatformInit(void) _glfw.x11.helperWindowHandle = createHelperWindow(); _glfw.x11.hiddenCursorHandle = createHiddenCursor(); - if (XSupportsLocale()) - { - XSetLocaleModifiers(""); - - _glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL); - if (_glfw.x11.im) - { - if (!hasUsableInputMethodStyle()) - { - XCloseIM(_glfw.x11.im); - _glfw.x11.im = NULL; - } - } - } - #if defined(__linux__) if (!_glfwInitJoysticksLinux()) return GLFW_FALSE; @@ -985,15 +649,10 @@ void _glfwPlatformTerminate(void) _glfw.x11.hiddenCursorHandle = (Cursor) 0; } + glfw_xkb_release(&_glfw.x11.xkb); free(_glfw.x11.primarySelectionString); free(_glfw.x11.clipboardString); - if (_glfw.x11.im) - { - XCloseIM(_glfw.x11.im); - _glfw.x11.im = NULL; - } - if (_glfw.x11.display) { XCloseDisplay(_glfw.x11.display); @@ -1050,4 +709,3 @@ const char* _glfwPlatformGetVersionString(void) #endif ; } - diff --git a/glfw/x11_platform.h b/glfw/x11_platform.h index c37c740e4..64177170e 100644 --- a/glfw/x11_platform.h +++ b/glfw/x11_platform.h @@ -47,6 +47,8 @@ // The XInput extension provides raw mouse motion input #include +#include "xkb_glfw.h" + typedef XRRCrtcGamma* (* PFN_XRRAllocGamma)(int); typedef void (* PFN_XRRFreeCrtcInfo)(XRRCrtcInfo*); typedef void (* PFN_XRRFreeGamma)(XRRCrtcGamma*); @@ -96,8 +98,6 @@ typedef XineramaScreenInfo* (* PFN_XineramaQueryScreens)(Display*,int*); #define XineramaQueryExtension _glfw.x11.xinerama.QueryExtension #define XineramaQueryScreens _glfw.x11.xinerama.QueryScreens -typedef XID xcb_window_t; -typedef XID xcb_visualid_t; typedef struct xcb_connection_t xcb_connection_t; typedef xcb_connection_t* (* PFN_XGetXCBConnection)(Display*); #define XGetXCBConnection _glfw.x11.x11xcb.GetXCBConnection @@ -151,7 +151,6 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(Vk #include "posix_thread.h" #include "posix_time.h" -#include "xkb_unicode.h" #include "glx_context.h" #include "egl_context.h" #include "osmesa_context.h" @@ -180,7 +179,6 @@ typedef struct _GLFWwindowX11 { Colormap colormap; Window handle; - XIC ic; GLFWbool overrideRedirect; GLFWbool iconified; @@ -219,20 +217,12 @@ typedef struct _GLFWlibraryX11 Cursor hiddenCursorHandle; // Context for mapping window XIDs to _GLFWwindow pointers XContext context; - // XIM input method - XIM im; // Most recent error code received by X error handler int errorCode; // Primary selection string (while the primary selection is owned) char* primarySelectionString; // Clipboard string (while the selection is owned) char* clipboardString; - // Key name string - char keyName[5]; - // X11 keycode to GLFW key LUT - short int keycodes[256]; - // GLFW key to X11 keycode LUT - short int scancodes[GLFW_KEY_LAST + 1]; // Where to place the cursor when re-enabled double restoreCursorPosX, restoreCursorPosY; // The window whose disabled cursor mode is active @@ -318,15 +308,7 @@ typedef struct _GLFWlibraryX11 PFN_XRRUpdateConfiguration UpdateConfiguration; } randr; - struct { - GLFWbool available; - GLFWbool detectable; - int majorOpcode; - int eventBase; - int errorBase; - int major; - int minor; - } xkb; + _GLFWXKBData xkb; struct { int count; @@ -441,4 +423,3 @@ void _glfwReleaseErrorHandlerX11(void); void _glfwInputErrorX11(int error, const char* message); void _glfwPushSelectionToManagerX11(void); - diff --git a/glfw/x11_window.c b/glfw/x11_window.c index 0186db8a7..560c566cd 100644 --- a/glfw/x11_window.c +++ b/glfw/x11_window.c @@ -220,17 +220,6 @@ static int translateState(int state) return mods; } -// Translates an X11 key code to a GLFW key token -// -static int translateKey(int scancode) -{ - // Use the pre-filled LUT (see createKeyTables() in x11_init.c) - if (scancode < 0 || scancode > 255) - return GLFW_KEY_UNKNOWN; - - return _glfw.x11.keycodes[scancode]; -} - // Return the GLFW window corresponding to the specified X11 window // static _GLFWwindow* findWindowByHandle(Window handle) @@ -497,31 +486,6 @@ static size_t encodeUTF8(char* s, unsigned int ch) return count; } -// Decode a Unicode code point from a UTF-8 stream -// Based on cutef8 by Jeff Bezanson (Public Domain) -// -#if defined(X_HAVE_UTF8_STRING) -static unsigned int decodeUTF8(const char** s) -{ - unsigned int ch = 0, count = 0; - static const unsigned int offsets[] = - { - 0x00000000u, 0x00003080u, 0x000e2080u, - 0x03c82080u, 0xfa082080u, 0x82082080u - }; - - do - { - ch = (ch << 6) + (unsigned char) **s; - (*s)++; - count++; - } while ((**s & 0xc0) == 0x80); - - assert(count <= 6); - return ch - offsets[count - 1]; -} -#endif /*X_HAVE_UTF8_STRING*/ - // Convert the specified Latin-1 string to UTF-8 // static char* convertLatin1toUTF8(const char* source) @@ -746,19 +710,6 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, } _glfwPlatformSetWindowTitle(window, wndconfig->title); - - if (_glfw.x11.im) - { - window->x11.ic = XCreateIC(_glfw.x11.im, - XNInputStyle, - XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, - window->x11.handle, - XNFocusWindow, - window->x11.handle, - NULL); - } - _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos); _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height); @@ -1141,16 +1092,8 @@ static void releaseMonitor(_GLFWwindow* window) static void processEvent(XEvent *event) { _GLFWwindow* window = NULL; - int keycode = 0; Bool filtered = False; - // HACK: Save scancode as some IMs clear the field in XFilterEvent - if (event->type == KeyPress || event->type == KeyRelease) - keycode = event->xkey.keycode; - - if (_glfw.x11.im) - filtered = XFilterEvent(event, None); - if (_glfw.x11.randr.available) { if (event->type == _glfw.x11.randr.eventBase + RRNotify) @@ -1208,6 +1151,27 @@ static void processEvent(XEvent *event) handleSelectionRequest(event); return; } + else if (event->type == _glfw.x11.xkb.eventBase) + { + XkbEvent *kb_event = (XkbEvent*)event; + switch(kb_event->any.xkb_type) { + case XkbNewKeyboardNotify: + if(!glfw_xkb_update_x11_keyboard_id(&_glfw.x11.xkb)) return; + /* fallthrough */ + case XkbMapNotify: + { + glfw_xkb_compile_keymap(&_glfw.x11.xkb, NULL); + return; + } + case XkbStateNotify: + { + XkbStateNotifyEvent *state_event = (XkbStateNotifyEvent*)kb_event; + glfw_xkb_update_modifiers(&_glfw.x11.xkb, state_event->base_mods, state_event->latched_mods, state_event->locked_mods, state_event->group); + return; + } + } + return; + } window = findWindowByHandle(event->xany.window); if (window == NULL) @@ -1220,105 +1184,12 @@ static void processEvent(XEvent *event) { case KeyPress: { - const int key = translateKey(keycode); - const int mods = translateState(event->xkey.state); - const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); - - if (window->x11.ic) - { - // HACK: Ignore duplicate key press events generated by ibus - // These have the same timestamp as the original event - // Corresponding release events are filtered out - // implicitly by the GLFW key repeat logic - if (window->x11.lastKeyTime < event->xkey.time) - { - if (keycode) - _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); - - window->x11.lastKeyTime = event->xkey.time; - } - - if (!filtered) - { - int count; - Status status; -#if defined(X_HAVE_UTF8_STRING) - char buffer[100]; - char* chars = buffer; - - count = Xutf8LookupString(window->x11.ic, - &event->xkey, - buffer, sizeof(buffer) - 1, - NULL, &status); - - if (status == XBufferOverflow) - { - chars = calloc(count + 1, 1); - count = Xutf8LookupString(window->x11.ic, - &event->xkey, - chars, count, - NULL, &status); - } - - if (status == XLookupChars || status == XLookupBoth) - { - const char* c = chars; - chars[count] = '\0'; - while (c - chars < count) - _glfwInputChar(window, decodeUTF8(&c), mods, plain); - } -#else /*X_HAVE_UTF8_STRING*/ - wchar_t buffer[16]; - wchar_t* chars = buffer; - - count = XwcLookupString(window->x11.ic, - &event->xkey, - buffer, - sizeof(buffer) / sizeof(wchar_t), - NULL, - &status); - - if (status == XBufferOverflow) - { - chars = calloc(count, sizeof(wchar_t)); - count = XwcLookupString(window->x11.ic, - &event->xkey, - chars, count, - NULL, &status); - } - - if (status == XLookupChars || status == XLookupBoth) - { - int i; - for (i = 0; i < count; i++) - _glfwInputChar(window, chars[i], mods, plain); - } -#endif /*X_HAVE_UTF8_STRING*/ - - if (chars != buffer) - free(chars); - } - } - else - { - KeySym keysym; - XLookupString(&event->xkey, NULL, 0, &keysym, NULL); - - _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); - - const long character = _glfwKeySym2Unicode(keysym); - if (character != -1) - _glfwInputChar(window, character, mods, plain); - } - + glfw_xkb_handle_key_event(window, &_glfw.x11.xkb, event->xkey.keycode, GLFW_PRESS); return; } case KeyRelease: { - const int key = translateKey(keycode); - const int mods = translateState(event->xkey.state); - if (!_glfw.x11.xkb.detectable) { // HACK: Key repeat events will arrive as KeyRelease/KeyPress @@ -1332,7 +1203,7 @@ static void processEvent(XEvent *event) if (next.type == KeyPress && next.xkey.window == event->xkey.window && - next.xkey.keycode == keycode) + next.xkey.keycode == event->xkey.keycode) { // HACK: The time of repeat events sometimes doesn't // match that of the press event, so add an @@ -1351,7 +1222,7 @@ static void processEvent(XEvent *event) } } - _glfwInputKey(window, key, keycode, GLFW_RELEASE, mods); + glfw_xkb_handle_key_event(window, &_glfw.x11.xkb, event->xkey.keycode, GLFW_RELEASE); return; } @@ -1735,9 +1606,6 @@ static void processEvent(XEvent *event) return; } - if (window->x11.ic) - XSetICFocus(window->x11.ic); - _glfwInputWindowFocus(window, GLFW_TRUE); return; } @@ -1755,9 +1623,6 @@ static void processEvent(XEvent *event) return; } - if (window->x11.ic) - XUnsetICFocus(window->x11.ic); - if (window->monitor && window->autoIconify) _glfwPlatformIconifyWindow(window); @@ -1989,12 +1854,6 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) if (window->monitor) releaseMonitor(window); - if (window->x11.ic) - { - XDestroyIC(window->x11.ic); - window->x11.ic = NULL; - } - if (window->context.destroy) window->context.destroy(window); @@ -2765,28 +2624,13 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) const char* _glfwPlatformGetScancodeName(int scancode) { - if (!_glfw.x11.xkb.available) - return NULL; - const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); - if (keysym == NoSymbol) - return NULL; - - const long ch = _glfwKeySym2Unicode(keysym); - if (ch == -1) - return NULL; - - const size_t count = encodeUTF8(_glfw.x11.keyName, (unsigned int) ch); - if (count == 0) - return NULL; - - _glfw.x11.keyName[count] = '\0'; - return _glfw.x11.keyName; + return glfw_xkb_keysym_name(scancode); } int _glfwPlatformGetKeyScancode(int key) { - return _glfw.x11.scancodes[key]; + return glfw_xkb_sym_for_key(key); } int _glfwPlatformCreateCursor(_GLFWcursor* cursor, diff --git a/glfw/xkb_glfw.c b/glfw/xkb_glfw.c new file mode 100644 index 000000000..7aac014e9 --- /dev/null +++ b/glfw/xkb_glfw.c @@ -0,0 +1,385 @@ +//======================================================================== +// GLFW 3.3 XKB - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2018 Kovid Goyal +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + + +#include +#include +#include "internal.h" +#include "xkb_glfw.h" + +static GLFWbool debug_keyboard = GLFW_FALSE; +#define debug(...) if (debug_keyboard) printf(__VA_ARGS__); + +#define map_key(key) { \ + switch(key) { \ + S(space, SPACE); \ + S(apostrophe, APOSTROPHE); \ + S(comma, COMMA); \ + S(minus, MINUS); \ + S(period, PERIOD); \ + S(slash, SLASH); \ + S(semicolon, SEMICOLON); \ + S(equal, EQUAL); \ + S(bracketleft, LEFT_BRACKET); \ + S(backslash, BACKSLASH); \ + S(bracketright, RIGHT_BRACKET); \ + S(grave, GRAVE_ACCENT); \ + S(Escape, ESCAPE); \ + S(Return, ENTER); \ + S(Tab, TAB); \ + S(BackSpace, BACKSPACE); \ + S(Insert, INSERT); \ + S(Delete, DELETE); \ + S(Right, RIGHT); \ + S(Left, LEFT); \ + S(Up, UP); \ + S(Down, DOWN); \ + S(Page_Up, PAGE_UP); \ + S(Page_Down, PAGE_DOWN); \ + S(Home, HOME); \ + S(End, END); \ + S(Caps_Lock, CAPS_LOCK); \ + S(Scroll_Lock, SCROLL_LOCK); \ + S(Num_Lock, NUM_LOCK); \ + S(Print, PRINT_SCREEN); \ + S(Pause, PAUSE); \ + S(KP_Decimal, KP_DECIMAL); \ + S(KP_Divide, KP_DIVIDE); \ + S(KP_Multiply, KP_MULTIPLY); \ + S(KP_Subtract, KP_SUBTRACT); \ + S(KP_Add, KP_ADD); \ + S(KP_Enter, KP_ENTER); \ + S(KP_Equal, KP_EQUAL); \ + F(KP_Home, HOME); \ + F(KP_End, END); \ + F(KP_Page_Up, PAGE_UP); \ + F(KP_Page_Down, PAGE_DOWN); \ + F(KP_Insert, INSERT); \ + F(KP_Delete, DELETE); \ + S(Shift_L, LEFT_SHIFT); \ + S(Control_L, LEFT_CONTROL); \ + S(Alt_L, LEFT_ALT); \ + S(Super_L, LEFT_SUPER); \ + S(Shift_R, RIGHT_SHIFT); \ + S(Control_R, RIGHT_CONTROL); \ + S(Alt_R, RIGHT_ALT); \ + S(Super_R, RIGHT_SUPER); \ + S(Menu, MENU); \ + R(0, 9, 0, 9); \ + R(a, z, A, Z); \ + D(A, Z, A, Z); \ + R(F1, F25, F1, F25); \ + R(KP_0, KP_9, KP_0, KP_9); \ + default: \ + break; \ + } \ +} + +static int +glfw_key_for_sym(xkb_keysym_t key) { +#define S(f, t) case XKB_KEY_##f: return GLFW_KEY_##t +#define F(f, t) S(f, t) +#define R(s, e, gs, ...) case XKB_KEY_##s ... XKB_KEY_##e: return GLFW_KEY_##gs + key - XKB_KEY_##s +#define D(s, e, gs, ...) R(s, e, gs) + map_key(key) + return GLFW_KEY_UNKNOWN; +#undef F +#undef D +#undef R +#undef S +}; + +xkb_keysym_t +glfw_xkb_sym_for_key(int key) { +#define S(f, t) case GLFW_KEY_##t: return XKB_KEY_##f +#define F(...) +#define R(s, e, gs, ge) case GLFW_KEY_##gs ... GLFW_KEY_##ge: return XKB_KEY_##s + key - GLFW_KEY_##gs +#define D(...) + map_key(key) + return GLFW_KEY_UNKNOWN; +#undef F +#undef D +#undef R +#undef S +} + +#ifdef _GLFW_X11 + +GLFWbool +glfw_xkb_set_x11_events_mask(void) { + if (!XkbSelectEvents(_glfw.x11.display, XkbUseCoreKbd, XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask, XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask)) { + _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to set XKB events mask"); + return GLFW_FALSE; + } + return GLFW_TRUE; +} + +GLFWbool +glfw_xkb_update_x11_keyboard_id(_GLFWXKBData *xkb) { + xkb->keyboard_device_id = -1; + xcb_connection_t* conn = XGetXCBConnection(_glfw.x11.display); + if (!conn) { + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to retrieve XCB connection"); + return GLFW_FALSE; + } + + xkb->keyboard_device_id = xkb_x11_get_core_keyboard_device_id(conn); + if (xkb->keyboard_device_id == -1) { + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to retrieve core keyboard device id"); + return GLFW_FALSE; + } + return GLFW_TRUE; +} + +#define xkb_glfw_load_keymap(keymap, ...) {\ + xcb_connection_t* conn = XGetXCBConnection(_glfw.x11.display); \ + if (conn) keymap = xkb_x11_keymap_new_from_device(xkb->context, conn, xkb->keyboard_device_id, XKB_KEYMAP_COMPILE_NO_FLAGS); \ +} + +#define xkb_glfw_load_state(keymap, state, ...) {\ + xcb_connection_t* conn = XGetXCBConnection(_glfw.x11.display); \ + if (conn) state = xkb_x11_state_new_from_device(keymap, conn, xkb->keyboard_device_id); \ +} + +#else + +#define xkb_glfw_load_keymap(keymap, map_str) keymap = xkb_keymap_new_from_string(xkb->context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0); +#define xkb_glfw_load_state(keymap, state, ...) state = xkb_state_new(keymap); + +#endif + +void +glfw_xkb_release(_GLFWXKBData *xkb) { + if (xkb->composeState) { + xkb_compose_state_unref(xkb->composeState); + xkb->composeState = NULL; + } + if (xkb->keymap) { + xkb_keymap_unref(xkb->keymap); + xkb->keymap = NULL; + } + if (xkb->state) { + xkb_state_unref(xkb->state); + xkb->state = NULL; + } + if (xkb->clean_state) { + xkb_state_unref(xkb->clean_state); + xkb->clean_state = NULL; + } + if (xkb->context) { + xkb_context_unref(xkb->context); + xkb->context = NULL; + } +} + +GLFWbool +glfw_xkb_create_context(_GLFWXKBData *xkb) { + xkb->context = xkb_context_new(0); + debug_keyboard = getenv("GLFW_DEBUG_KEYBOARD") != NULL; + if (!xkb->context) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Failed to initialize XKB context"); + return GLFW_FALSE; + } + return GLFW_TRUE; +} + +GLFWbool +glfw_xkb_compile_keymap(_GLFWXKBData *xkb, const char *map_str) { + const char* locale = NULL; + struct xkb_state* state = NULL, *clean_state = NULL; + struct xkb_keymap* keymap = NULL; + struct xkb_compose_table* compose_table = NULL; + struct xkb_compose_state* compose_state = NULL; + (void)(map_str); // not needed on X11 + + xkb_glfw_load_keymap(keymap, map_str); + if (!keymap) _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to compile XKB keymap"); + else { + xkb_glfw_load_state(keymap, state); + clean_state = xkb_state_new(keymap); + if (!state || ! clean_state) { + _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB state"); + xkb_keymap_unref(keymap); keymap = NULL; + } else { + /* Look up the preferred locale, falling back to "C" as default. */ + locale = getenv("LC_ALL"); + if (!locale) locale = getenv("LC_CTYPE"); + if (!locale) locale = getenv("LANG"); + if (!locale) locale = "C"; + compose_table = xkb_compose_table_new_from_locale(xkb->context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); + if (!compose_table) { + _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB compose table"); + xkb_keymap_unref(keymap); keymap = NULL; + xkb_state_unref(state); state = NULL; + } else { + compose_state = xkb_compose_state_new(compose_table, XKB_COMPOSE_STATE_NO_FLAGS); + xkb_compose_table_unref(compose_table); compose_table = NULL; + if (!compose_state) { + _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB compose state"); + xkb_keymap_unref(keymap); keymap = NULL; + xkb_state_unref(state); state = NULL; + } + } + } + } + if (keymap && state && clean_state && compose_state) { + if (xkb->composeState) xkb_compose_state_unref(xkb->composeState); + xkb->composeState = compose_state; + if (xkb->keymap) xkb_keymap_unref(xkb->keymap); + xkb->keymap = keymap; + if (xkb->state) xkb_state_unref(xkb->state); + xkb->state = state; + if (xkb->clean_state) xkb_state_unref(xkb->clean_state); + xkb->clean_state = clean_state; + } + if (xkb->keymap) { + xkb->controlMask = 1 << xkb_keymap_mod_get_index(xkb->keymap, "Control"); + xkb->altMask = 1 << xkb_keymap_mod_get_index(xkb->keymap, "Mod1"); + xkb->shiftMask = 1 << xkb_keymap_mod_get_index(xkb->keymap, "Shift"); + xkb->superMask = 1 << xkb_keymap_mod_get_index(xkb->keymap, "Mod4"); + xkb->capsLockMask = 1 << xkb_keymap_mod_get_index(xkb->keymap, "Lock"); + xkb->numLockMask = 1 << xkb_keymap_mod_get_index(xkb->keymap, "Mod2"); + } + return GLFW_TRUE; +} + +void +glfw_xkb_update_modifiers(_GLFWXKBData *xkb, unsigned int depressed, unsigned int latched, unsigned int locked, unsigned int group) { + xkb_mod_mask_t mask; + unsigned int modifiers = 0; + if (!xkb->keymap) return; + xkb_state_update_mask(xkb->state, depressed, latched, locked, 0, 0, group); + mask = xkb_state_serialize_mods(xkb->state, XKB_STATE_MODS_DEPRESSED | XKB_STATE_LAYOUT_DEPRESSED | XKB_STATE_MODS_LATCHED | XKB_STATE_LAYOUT_LATCHED); + if (mask & xkb->controlMask) modifiers |= GLFW_MOD_CONTROL; + if (mask & xkb->altMask) modifiers |= GLFW_MOD_ALT; + if (mask & xkb->shiftMask) modifiers |= GLFW_MOD_SHIFT; + if (mask & xkb->superMask) modifiers |= GLFW_MOD_SUPER; + if (mask & xkb->capsLockMask) modifiers |= GLFW_MOD_CAPS_LOCK; + if (mask & xkb->numLockMask) modifiers |= GLFW_MOD_NUM_LOCK; + xkb->modifiers = modifiers; +} + +GLFWbool +glfw_xkb_should_repeat(_GLFWXKBData *xkb, xkb_keycode_t scancode) { +#ifdef _GLFW_WAYLAND + scancode += 8; +#endif + return xkb_keymap_key_repeats(xkb->keymap, scancode); +} + + +static char text[256]; + +static inline xkb_keysym_t +compose_symbol(_GLFWXKBData *xkb, xkb_keysym_t sym) { + if (sym == XKB_KEY_NoSymbol) return sym; + if (xkb_compose_state_feed(xkb->composeState, sym) != XKB_COMPOSE_FEED_ACCEPTED) return sym; + switch (xkb_compose_state_get_status(xkb->composeState)) { + case XKB_COMPOSE_COMPOSED: + xkb_compose_state_get_utf8(xkb->composeState, text, sizeof(text)); + return xkb_compose_state_get_one_sym(xkb->composeState); + case XKB_COMPOSE_COMPOSING: + case XKB_COMPOSE_CANCELLED: + return XKB_KEY_NoSymbol; + case XKB_COMPOSE_NOTHING: + default: + return sym; + } +} + + +const char* +glfw_xkb_keysym_name(xkb_keysym_t sym) { + static char name[256]; + name[0] = 0; + xkb_keysym_get_name(sym, name, sizeof(name)); + return name; +} + + +static inline const char* +format_mods(unsigned int mods) { + static char buf[128]; + char *p = buf, *s; +#define pr(x) p += snprintf(p, sizeof(buf) - (p - buf) - 1, x) + pr("mods: "); + s = p; + if (mods & GLFW_MOD_CONTROL) pr("ctrl+"); + if (mods & GLFW_MOD_ALT) pr("alt+"); + if (mods & GLFW_MOD_SHIFT) pr("shift+"); + if (mods & GLFW_MOD_SUPER) pr("super+"); + if (mods & GLFW_MOD_CAPS_LOCK) pr("capslock+"); + if (mods & GLFW_MOD_NUM_LOCK) pr("numlock+"); + if (p == s) pr("none"); + else p--; + pr(" "); +#undef pr + return buf; +} + +void +glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t scancode, int action) { + const xkb_keysym_t *syms, *clean_syms; + xkb_keysym_t glfw_sym; + xkb_keycode_t code_for_sym = scancode; +#ifdef _GLFW_WAYLAND + code_for_sym += 8; +#endif + debug("scancode: 0x%x release: %d ", scancode, action == GLFW_RELEASE); + int num_syms = xkb_state_key_get_syms(xkb->state, code_for_sym, &syms); + int num_clean_syms = xkb_state_key_get_syms(xkb->clean_state, code_for_sym, &clean_syms); + text[0] = 0; + // According to the documentation of xkb_compose_state_feed it does not + // support multi-sym events, so we ignore them + if (num_syms != 1 || num_clean_syms != 1) { + debug("scancode: 0x%x num_syms: %d num_clean_syms: %d ignoring event\n", scancode, num_syms, num_clean_syms); + return; + } + glfw_sym = clean_syms[0]; + debug("clean_sym: %s ", glfw_xkb_keysym_name(clean_syms[0])); + if (action == GLFW_PRESS || action == GLFW_REPEAT) { + const char *text_type = "composed_text"; + glfw_sym = compose_symbol(xkb, syms[0]); + if (glfw_sym == XKB_KEY_NoSymbol) { + debug("compose not complete, ignoring.\n"); + return; + } + debug("composed_sym: %s ", glfw_xkb_keysym_name(glfw_sym)); + if (glfw_sym == syms[0]) { // composed sym is the same as non-composed sym + glfw_sym = clean_syms[0]; + // xkb returns text even if alt and/or super are pressed + if ( ((GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER) & xkb->modifiers) == 0) xkb_state_key_get_utf8(xkb->state, code_for_sym, text, sizeof(text)); + text_type = "text"; + } + if (text[0] <= 31 || text[0] == 127) text[0] = 0; // dont send text for ascii control codes + if (text[0]) { debug("%s: %s ", text_type, text); } + } + int glfw_keycode = glfw_key_for_sym(glfw_sym); + debug("%sglfw_key: %s\n", format_mods(xkb->modifiers), _glfwGetKeyName(glfw_keycode)); + _glfwInputKeyboard(window, glfw_keycode, glfw_sym, action, xkb->modifiers, text, 0); +} diff --git a/glfw/xkb_glfw.h b/glfw/xkb_glfw.h index 7afef7335..af96685da 100644 --- a/glfw/xkb_glfw.h +++ b/glfw/xkb_glfw.h @@ -1,7 +1,7 @@ //======================================================================== // GLFW 3.3 XKB - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2014 Kovid Goyal +// Copyright (c) 2018 Kovid Goyal // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -28,56 +28,16 @@ #include #include - -typedef struct xkb_context* (* PFN_xkb_context_new)(enum xkb_context_flags); -typedef void (* PFN_xkb_context_unref)(struct xkb_context*); -typedef struct xkb_keymap* (* PFN_xkb_keymap_new_from_string)(struct xkb_context*, const char*, enum xkb_keymap_format, enum xkb_keymap_compile_flags); -typedef void (* PFN_xkb_keymap_unref)(struct xkb_keymap*); -typedef xkb_mod_index_t (* PFN_xkb_keymap_mod_get_index)(struct xkb_keymap*, const char*); -typedef int (* PFN_xkb_keymap_key_repeats)(struct xkb_keymap*, xkb_keycode_t); -typedef struct xkb_state* (* PFN_xkb_state_new)(struct xkb_keymap*); -typedef void (* PFN_xkb_state_unref)(struct xkb_state*); -typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**); -typedef enum xkb_state_component (* PFN_xkb_state_update_mask)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t); -typedef xkb_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum xkb_state_component); - -#define xkb_context_new GLFW_XKB_GLOBAL_NAME.context_new -#define xkb_context_unref GLFW_XKB_GLOBAL_NAME.context_unref -#define xkb_keymap_new_from_string GLFW_XKB_GLOBAL_NAME.keymap_new_from_string -#define xkb_keymap_unref GLFW_XKB_GLOBAL_NAME.keymap_unref -#define xkb_keymap_mod_get_index GLFW_XKB_GLOBAL_NAME.keymap_mod_get_index -#define xkb_keymap_key_repeats GLFW_XKB_GLOBAL_NAME.keymap_key_repeats -#define xkb_state_new GLFW_XKB_GLOBAL_NAME.state_new -#define xkb_state_unref GLFW_XKB_GLOBAL_NAME.state_unref -#define xkb_state_key_get_syms GLFW_XKB_GLOBAL_NAME.state_key_get_syms -#define xkb_state_update_mask GLFW_XKB_GLOBAL_NAME.state_update_mask -#define xkb_state_serialize_mods GLFW_XKB_GLOBAL_NAME.state_serialize_mods - -typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags); -typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*); -typedef struct xkb_compose_state* (* PFN_xkb_compose_state_new)(struct xkb_compose_table*, enum xkb_compose_state_flags); -typedef void (* PFN_xkb_compose_state_unref)(struct xkb_compose_state*); -typedef enum xkb_compose_feed_result (* PFN_xkb_compose_state_feed)(struct xkb_compose_state*, xkb_keysym_t); -typedef enum xkb_compose_status (* PFN_xkb_compose_state_get_status)(struct xkb_compose_state*); -typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_state*); - -#define xkb_compose_table_new_from_locale GLFW_XKB_GLOBAL_NAME.compose_table_new_from_locale -#define xkb_compose_table_unref GLFW_XKB_GLOBAL_NAME.compose_table_unref -#define xkb_compose_state_new GLFW_XKB_GLOBAL_NAME.compose_state_new -#define xkb_compose_state_unref GLFW_XKB_GLOBAL_NAME.compose_state_unref -#define xkb_compose_state_feed GLFW_XKB_GLOBAL_NAME.compose_state_feed -#define xkb_compose_state_get_status GLFW_XKB_GLOBAL_NAME.compose_state_get_status -#define xkb_compose_state_get_one_sym GLFW_XKB_GLOBAL_NAME.compose_state_get_one_sym - +#ifdef _GLFW_X11 +#include +#endif typedef struct { - void* handle; struct xkb_context* context; struct xkb_keymap* keymap; struct xkb_state* state; + struct xkb_state* clean_state; struct xkb_compose_state* composeState; - short int keycodes[256]; - short int scancodes[GLFW_KEY_LAST + 1]; xkb_mod_mask_t controlMask; xkb_mod_mask_t altMask; @@ -87,288 +47,29 @@ typedef struct { xkb_mod_mask_t numLockMask; unsigned int modifiers; - PFN_xkb_context_new context_new; - PFN_xkb_context_unref context_unref; - PFN_xkb_keymap_new_from_string keymap_new_from_string; - PFN_xkb_keymap_unref keymap_unref; - PFN_xkb_keymap_mod_get_index keymap_mod_get_index; - PFN_xkb_keymap_key_repeats keymap_key_repeats; - PFN_xkb_state_new state_new; - PFN_xkb_state_unref state_unref; - PFN_xkb_state_key_get_syms state_key_get_syms; - PFN_xkb_state_update_mask state_update_mask; - PFN_xkb_state_serialize_mods state_serialize_mods; +#ifdef _GLFW_X11 + int32_t keyboard_device_id; + GLFWbool available; + GLFWbool detectable; + int majorOpcode; + int eventBase; + int errorBase; + int major; + int minor; +#endif - PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale; - PFN_xkb_compose_table_unref compose_table_unref; - PFN_xkb_compose_state_new compose_state_new; - PFN_xkb_compose_state_unref compose_state_unref; - PFN_xkb_compose_state_feed compose_state_feed; - PFN_xkb_compose_state_get_status compose_state_get_status; - PFN_xkb_compose_state_get_one_sym compose_state_get_one_sym; } _GLFWXKBData; -#define bind_xkb_sym(name) GLFW_XKB_GLOBAL_NAME.name = (PFN_xkb_##name) _glfw_dlsym(GLFW_XKB_GLOBAL_NAME.handle, "xkb_" #name) -#define load_glfw_xkb() {\ - GLFW_XKB_GLOBAL_NAME.handle = _glfw_dlopen("libxkbcommon.so.0"); \ - if (!GLFW_XKB_GLOBAL_NAME.handle) \ - { \ - _glfwInputError(GLFW_PLATFORM_ERROR, \ - "Failed to open libxkbcommon"); \ - return GLFW_FALSE; \ - } \ - bind_xkb_sym(context_new); \ - bind_xkb_sym(context_unref); \ - bind_xkb_sym(keymap_new_from_string); \ - bind_xkb_sym(keymap_unref); \ - bind_xkb_sym(keymap_mod_get_index); \ - bind_xkb_sym(keymap_key_repeats); \ - bind_xkb_sym(state_new); \ - bind_xkb_sym(state_unref); \ - bind_xkb_sym(state_key_get_syms); \ - bind_xkb_sym(state_update_mask); \ - bind_xkb_sym(state_serialize_mods); \ - bind_xkb_sym(compose_table_new_from_locale); \ - bind_xkb_sym(compose_table_unref); \ - bind_xkb_sym(compose_state_new); \ - bind_xkb_sym(compose_state_unref); \ - bind_xkb_sym(compose_state_feed); \ - bind_xkb_sym(compose_state_get_status); \ - bind_xkb_sym(compose_state_get_one_sym); \ -} +#ifdef _GLFW_X11 +GLFWbool glfw_xkb_set_x11_events_mask(void); +GLFWbool glfw_xkb_update_x11_keyboard_id(_GLFWXKBData *xkb); +#endif -#define release_glfw_xkb() {\ - if (GLFW_XKB_GLOBAL_NAME.composeState) { \ - xkb_compose_state_unref(GLFW_XKB_GLOBAL_NAME.composeState); \ - GLFW_XKB_GLOBAL_NAME.composeState = NULL; \ - } \ - if (GLFW_XKB_GLOBAL_NAME.keymap) { \ - xkb_keymap_unref(GLFW_XKB_GLOBAL_NAME.keymap); \ - GLFW_XKB_GLOBAL_NAME.keymap = NULL; \ - } \ - if (GLFW_XKB_GLOBAL_NAME.state) { \ - xkb_state_unref(GLFW_XKB_GLOBAL_NAME.state); \ - GLFW_XKB_GLOBAL_NAME.state = NULL; \ - } \ - if (GLFW_XKB_GLOBAL_NAME.context) { \ - xkb_context_unref(GLFW_XKB_GLOBAL_NAME.context); \ - GLFW_XKB_GLOBAL_NAME.context = NULL; \ - } \ - if (GLFW_XKB_GLOBAL_NAME.handle) { \ - _glfw_dlclose(GLFW_XKB_GLOBAL_NAME.handle); \ - GLFW_XKB_GLOBAL_NAME.handle = NULL; \ - } \ -} - -#define create_glfw_xkb_context() {\ - GLFW_XKB_GLOBAL_NAME.context = xkb_context_new(0); \ - if (!GLFW_XKB_GLOBAL_NAME.context) \ - { \ - _glfwInputError(GLFW_PLATFORM_ERROR, \ - "Failed to initialize XKB context"); \ - return GLFW_FALSE; \ - } \ - int scancode; \ - memset(GLFW_XKB_GLOBAL_NAME.keycodes, -1, sizeof(GLFW_XKB_GLOBAL_NAME.keycodes)); \ - memset(GLFW_XKB_GLOBAL_NAME.scancodes, -1, sizeof(GLFW_XKB_GLOBAL_NAME.scancodes)); \ -\ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_1] = GLFW_KEY_1; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_2] = GLFW_KEY_2; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_3] = GLFW_KEY_3; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_4] = GLFW_KEY_4; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_5] = GLFW_KEY_5; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_6] = GLFW_KEY_6; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_7] = GLFW_KEY_7; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_8] = GLFW_KEY_8; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_9] = GLFW_KEY_9; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_0] = GLFW_KEY_0; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_SPACE] = GLFW_KEY_SPACE; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_MINUS] = GLFW_KEY_MINUS; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_EQUAL] = GLFW_KEY_EQUAL; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_Q] = GLFW_KEY_Q; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_W] = GLFW_KEY_W; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_E] = GLFW_KEY_E; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_R] = GLFW_KEY_R; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_T] = GLFW_KEY_T; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_Y] = GLFW_KEY_Y; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_U] = GLFW_KEY_U; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_I] = GLFW_KEY_I; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_O] = GLFW_KEY_O; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_P] = GLFW_KEY_P; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_A] = GLFW_KEY_A; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_S] = GLFW_KEY_S; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_D] = GLFW_KEY_D; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F] = GLFW_KEY_F; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_G] = GLFW_KEY_G; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_H] = GLFW_KEY_H; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_J] = GLFW_KEY_J; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_K] = GLFW_KEY_K; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_L] = GLFW_KEY_L; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_Z] = GLFW_KEY_Z; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_X] = GLFW_KEY_X; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_C] = GLFW_KEY_C; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_V] = GLFW_KEY_V; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_B] = GLFW_KEY_B; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_N] = GLFW_KEY_N; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_M] = GLFW_KEY_M; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_COMMA] = GLFW_KEY_COMMA; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_DOT] = GLFW_KEY_PERIOD; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_SLASH] = GLFW_KEY_SLASH; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_ESC] = GLFW_KEY_ESCAPE; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_TAB] = GLFW_KEY_TAB; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_MENU] = GLFW_KEY_MENU; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_PAUSE] = GLFW_KEY_PAUSE; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_DELETE] = GLFW_KEY_DELETE; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_ENTER] = GLFW_KEY_ENTER; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_HOME] = GLFW_KEY_HOME; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_END] = GLFW_KEY_END; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_PAGEUP] = GLFW_KEY_PAGE_UP; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_INSERT] = GLFW_KEY_INSERT; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_LEFT] = GLFW_KEY_LEFT; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_RIGHT] = GLFW_KEY_RIGHT; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_DOWN] = GLFW_KEY_DOWN; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_UP] = GLFW_KEY_UP; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F1] = GLFW_KEY_F1; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F2] = GLFW_KEY_F2; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F3] = GLFW_KEY_F3; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F4] = GLFW_KEY_F4; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F5] = GLFW_KEY_F5; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F6] = GLFW_KEY_F6; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F7] = GLFW_KEY_F7; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F8] = GLFW_KEY_F8; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F9] = GLFW_KEY_F9; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F10] = GLFW_KEY_F10; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F11] = GLFW_KEY_F11; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F12] = GLFW_KEY_F12; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F13] = GLFW_KEY_F13; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F14] = GLFW_KEY_F14; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F15] = GLFW_KEY_F15; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F16] = GLFW_KEY_F16; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F17] = GLFW_KEY_F17; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F18] = GLFW_KEY_F18; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F19] = GLFW_KEY_F19; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F20] = GLFW_KEY_F20; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F21] = GLFW_KEY_F21; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F22] = GLFW_KEY_F22; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F23] = GLFW_KEY_F23; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F24] = GLFW_KEY_F24; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPPLUS] = GLFW_KEY_KP_ADD; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP0] = GLFW_KEY_KP_0; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP1] = GLFW_KEY_KP_1; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP2] = GLFW_KEY_KP_2; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP3] = GLFW_KEY_KP_3; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP4] = GLFW_KEY_KP_4; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP5] = GLFW_KEY_KP_5; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP6] = GLFW_KEY_KP_6; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP7] = GLFW_KEY_KP_7; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP8] = GLFW_KEY_KP_8; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP9] = GLFW_KEY_KP_9; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL; \ - GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPENTER] = GLFW_KEY_KP_ENTER; \ -\ - for (scancode = 0; scancode < 256; scancode++) \ - { \ - if (GLFW_XKB_GLOBAL_NAME.keycodes[scancode] > 0) \ - GLFW_XKB_GLOBAL_NAME.scancodes[GLFW_XKB_GLOBAL_NAME.keycodes[scancode]] = scancode; \ - } \ -\ -} - - -#define xkb_glfw_compile_keymap(map_str) { \ - const char* locale = NULL; \ - struct xkb_state* state = NULL; \ - struct xkb_keymap* keymap = NULL; \ - struct xkb_compose_table* compose_table = NULL; \ - struct xkb_compose_state* compose_state = NULL; \ -\ - keymap = xkb_keymap_new_from_string(GLFW_XKB_GLOBAL_NAME.context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0); \ - if (!keymap) _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to compile XKB keymap"); \ - else { \ - state = xkb_state_new(keymap); \ - if (!state) { \ - _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB state"); \ - xkb_keymap_unref(keymap); keymap = NULL; \ - } else { \ - /* Look up the preferred locale, falling back to "C" as default. */ \ - locale = getenv("LC_ALL"); \ - if (!locale) locale = getenv("LC_CTYPE"); \ - if (!locale) locale = getenv("LANG"); \ - if (!locale) locale = "C"; \ - compose_table = xkb_compose_table_new_from_locale(GLFW_XKB_GLOBAL_NAME.context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); \ - if (!compose_table) { \ - _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB compose table"); \ - xkb_keymap_unref(keymap); keymap = NULL; \ - xkb_state_unref(state); state = NULL; \ - } else { \ - compose_state = xkb_compose_state_new(compose_table, XKB_COMPOSE_STATE_NO_FLAGS); \ - xkb_compose_table_unref(compose_table); compose_table = NULL; \ - if (!compose_state) { \ - _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB compose state"); \ - xkb_keymap_unref(keymap); keymap = NULL; \ - xkb_state_unref(state); state = NULL; \ - }\ - } \ - } \ - } \ - if (keymap && state && compose_state) { \ - if (GLFW_XKB_GLOBAL_NAME.composeState) xkb_compose_state_unref(GLFW_XKB_GLOBAL_NAME.composeState); \ - GLFW_XKB_GLOBAL_NAME.composeState = compose_state; \ - if (GLFW_XKB_GLOBAL_NAME.keymap) xkb_keymap_unref(GLFW_XKB_GLOBAL_NAME.keymap); \ - GLFW_XKB_GLOBAL_NAME.keymap = keymap; \ - if (GLFW_XKB_GLOBAL_NAME.state) xkb_state_unref(GLFW_XKB_GLOBAL_NAME.state); \ - GLFW_XKB_GLOBAL_NAME.state = state; \ - }\ - if (GLFW_XKB_GLOBAL_NAME.keymap) { \ - GLFW_XKB_GLOBAL_NAME.controlMask = 1 << xkb_keymap_mod_get_index(GLFW_XKB_GLOBAL_NAME.keymap, "Control"); \ - GLFW_XKB_GLOBAL_NAME.altMask = 1 << xkb_keymap_mod_get_index(GLFW_XKB_GLOBAL_NAME.keymap, "Mod1"); \ - GLFW_XKB_GLOBAL_NAME.shiftMask = 1 << xkb_keymap_mod_get_index(GLFW_XKB_GLOBAL_NAME.keymap, "Shift"); \ - GLFW_XKB_GLOBAL_NAME.superMask = 1 << xkb_keymap_mod_get_index(GLFW_XKB_GLOBAL_NAME.keymap, "Mod4"); \ - GLFW_XKB_GLOBAL_NAME.capsLockMask = 1 << xkb_keymap_mod_get_index(GLFW_XKB_GLOBAL_NAME.keymap, "Lock"); \ - GLFW_XKB_GLOBAL_NAME.numLockMask = 1 << xkb_keymap_mod_get_index(GLFW_XKB_GLOBAL_NAME.keymap, "Mod2"); \ - } \ -} - - -#define xkb_glfw_update_modifiers(depressed, latched, locked, group) {\ - xkb_mod_mask_t mask; \ - unsigned int modifiers = 0; \ - if (!GLFW_XKB_GLOBAL_NAME.keymap) return; \ - xkb_state_update_mask(GLFW_XKB_GLOBAL_NAME.state, depressed, latched, locked, 0, 0, group); \ - mask = xkb_state_serialize_mods(GLFW_XKB_GLOBAL_NAME.state, XKB_STATE_MODS_DEPRESSED | XKB_STATE_LAYOUT_DEPRESSED | XKB_STATE_MODS_LATCHED | XKB_STATE_LAYOUT_LATCHED); \ - if (mask & GLFW_XKB_GLOBAL_NAME.controlMask) modifiers |= GLFW_MOD_CONTROL; \ - if (mask & GLFW_XKB_GLOBAL_NAME.altMask) modifiers |= GLFW_MOD_ALT; \ - if (mask & GLFW_XKB_GLOBAL_NAME.shiftMask) modifiers |= GLFW_MOD_SHIFT; \ - if (mask & GLFW_XKB_GLOBAL_NAME.superMask) modifiers |= GLFW_MOD_SUPER; \ - if (mask & GLFW_XKB_GLOBAL_NAME.capsLockMask) modifiers |= GLFW_MOD_CAPS_LOCK; \ - if (mask & GLFW_XKB_GLOBAL_NAME.numLockMask) modifiers |= GLFW_MOD_NUM_LOCK; \ - GLFW_XKB_GLOBAL_NAME.modifiers = modifiers; \ -} - - -#define xkb_glfw_to_glfw_key_code(key) \ - ((key < sizeof(GLFW_XKB_GLOBAL_NAME.keycodes) / sizeof(GLFW_XKB_GLOBAL_NAME.keycodes[0])) ? GLFW_XKB_GLOBAL_NAME.keycodes[key] : GLFW_KEY_UNKNOWN) +void glfw_xkb_release(_GLFWXKBData *xkb); +GLFWbool glfw_xkb_create_context(_GLFWXKBData *xkb); +GLFWbool glfw_xkb_compile_keymap(_GLFWXKBData *xkb, const char *map_str); +void glfw_xkb_update_modifiers(_GLFWXKBData *xkb, unsigned int depressed, unsigned int latched, unsigned int locked, unsigned int group); +GLFWbool glfw_xkb_should_repeat(_GLFWXKBData *xkb, xkb_keycode_t scancode); +const char* glfw_xkb_keysym_name(xkb_keysym_t sym); +xkb_keysym_t glfw_xkb_sym_for_key(int key); +void glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t scancode, int action); diff --git a/glfw/xkb_unicode.c b/glfw/xkb_unicode.c deleted file mode 100644 index ecfdc2aff..000000000 --- a/glfw/xkb_unicode.c +++ /dev/null @@ -1,940 +0,0 @@ -//======================================================================== -// GLFW 3.3 X11 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== - -#include "internal.h" - - -/* - * Marcus: This code was originally written by Markus G. Kuhn. - * I have made some slight changes (trimmed it down a bit from >60 KB to - * 20 KB), but the functionality is the same. - */ - -/* - * This module converts keysym values into the corresponding ISO 10646 - * (UCS, Unicode) values. - * - * The array keysymtab[] contains pairs of X11 keysym values for graphical - * characters and the corresponding Unicode value. The function - * _glfwKeySym2Unicode() maps a keysym onto a Unicode value using a binary - * search, therefore keysymtab[] must remain SORTED by keysym value. - * - * We allow to represent any UCS character in the range U-00000000 to - * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. - * This admittedly does not cover the entire 31-bit space of UCS, but - * it does cover all of the characters up to U-10FFFF, which can be - * represented by UTF-16, and more, and it is very unlikely that higher - * UCS codes will ever be assigned by ISO. So to get Unicode character - * U+ABCD you can directly use keysym 0x0100abcd. - * - * Original author: Markus G. Kuhn , University of - * Cambridge, April 2001 - * - * Special thanks to Richard Verhoeven for preparing - * an initial draft of the mapping table. - * - */ - - -//************************************************************************ -//**** KeySym to Unicode mapping table **** -//************************************************************************ - -static const struct codepair { - unsigned short keysym; - unsigned short ucs; -} keysymtab[] = { - { 0x01a1, 0x0104 }, - { 0x01a2, 0x02d8 }, - { 0x01a3, 0x0141 }, - { 0x01a5, 0x013d }, - { 0x01a6, 0x015a }, - { 0x01a9, 0x0160 }, - { 0x01aa, 0x015e }, - { 0x01ab, 0x0164 }, - { 0x01ac, 0x0179 }, - { 0x01ae, 0x017d }, - { 0x01af, 0x017b }, - { 0x01b1, 0x0105 }, - { 0x01b2, 0x02db }, - { 0x01b3, 0x0142 }, - { 0x01b5, 0x013e }, - { 0x01b6, 0x015b }, - { 0x01b7, 0x02c7 }, - { 0x01b9, 0x0161 }, - { 0x01ba, 0x015f }, - { 0x01bb, 0x0165 }, - { 0x01bc, 0x017a }, - { 0x01bd, 0x02dd }, - { 0x01be, 0x017e }, - { 0x01bf, 0x017c }, - { 0x01c0, 0x0154 }, - { 0x01c3, 0x0102 }, - { 0x01c5, 0x0139 }, - { 0x01c6, 0x0106 }, - { 0x01c8, 0x010c }, - { 0x01ca, 0x0118 }, - { 0x01cc, 0x011a }, - { 0x01cf, 0x010e }, - { 0x01d0, 0x0110 }, - { 0x01d1, 0x0143 }, - { 0x01d2, 0x0147 }, - { 0x01d5, 0x0150 }, - { 0x01d8, 0x0158 }, - { 0x01d9, 0x016e }, - { 0x01db, 0x0170 }, - { 0x01de, 0x0162 }, - { 0x01e0, 0x0155 }, - { 0x01e3, 0x0103 }, - { 0x01e5, 0x013a }, - { 0x01e6, 0x0107 }, - { 0x01e8, 0x010d }, - { 0x01ea, 0x0119 }, - { 0x01ec, 0x011b }, - { 0x01ef, 0x010f }, - { 0x01f0, 0x0111 }, - { 0x01f1, 0x0144 }, - { 0x01f2, 0x0148 }, - { 0x01f5, 0x0151 }, - { 0x01f8, 0x0159 }, - { 0x01f9, 0x016f }, - { 0x01fb, 0x0171 }, - { 0x01fe, 0x0163 }, - { 0x01ff, 0x02d9 }, - { 0x02a1, 0x0126 }, - { 0x02a6, 0x0124 }, - { 0x02a9, 0x0130 }, - { 0x02ab, 0x011e }, - { 0x02ac, 0x0134 }, - { 0x02b1, 0x0127 }, - { 0x02b6, 0x0125 }, - { 0x02b9, 0x0131 }, - { 0x02bb, 0x011f }, - { 0x02bc, 0x0135 }, - { 0x02c5, 0x010a }, - { 0x02c6, 0x0108 }, - { 0x02d5, 0x0120 }, - { 0x02d8, 0x011c }, - { 0x02dd, 0x016c }, - { 0x02de, 0x015c }, - { 0x02e5, 0x010b }, - { 0x02e6, 0x0109 }, - { 0x02f5, 0x0121 }, - { 0x02f8, 0x011d }, - { 0x02fd, 0x016d }, - { 0x02fe, 0x015d }, - { 0x03a2, 0x0138 }, - { 0x03a3, 0x0156 }, - { 0x03a5, 0x0128 }, - { 0x03a6, 0x013b }, - { 0x03aa, 0x0112 }, - { 0x03ab, 0x0122 }, - { 0x03ac, 0x0166 }, - { 0x03b3, 0x0157 }, - { 0x03b5, 0x0129 }, - { 0x03b6, 0x013c }, - { 0x03ba, 0x0113 }, - { 0x03bb, 0x0123 }, - { 0x03bc, 0x0167 }, - { 0x03bd, 0x014a }, - { 0x03bf, 0x014b }, - { 0x03c0, 0x0100 }, - { 0x03c7, 0x012e }, - { 0x03cc, 0x0116 }, - { 0x03cf, 0x012a }, - { 0x03d1, 0x0145 }, - { 0x03d2, 0x014c }, - { 0x03d3, 0x0136 }, - { 0x03d9, 0x0172 }, - { 0x03dd, 0x0168 }, - { 0x03de, 0x016a }, - { 0x03e0, 0x0101 }, - { 0x03e7, 0x012f }, - { 0x03ec, 0x0117 }, - { 0x03ef, 0x012b }, - { 0x03f1, 0x0146 }, - { 0x03f2, 0x014d }, - { 0x03f3, 0x0137 }, - { 0x03f9, 0x0173 }, - { 0x03fd, 0x0169 }, - { 0x03fe, 0x016b }, - { 0x047e, 0x203e }, - { 0x04a1, 0x3002 }, - { 0x04a2, 0x300c }, - { 0x04a3, 0x300d }, - { 0x04a4, 0x3001 }, - { 0x04a5, 0x30fb }, - { 0x04a6, 0x30f2 }, - { 0x04a7, 0x30a1 }, - { 0x04a8, 0x30a3 }, - { 0x04a9, 0x30a5 }, - { 0x04aa, 0x30a7 }, - { 0x04ab, 0x30a9 }, - { 0x04ac, 0x30e3 }, - { 0x04ad, 0x30e5 }, - { 0x04ae, 0x30e7 }, - { 0x04af, 0x30c3 }, - { 0x04b0, 0x30fc }, - { 0x04b1, 0x30a2 }, - { 0x04b2, 0x30a4 }, - { 0x04b3, 0x30a6 }, - { 0x04b4, 0x30a8 }, - { 0x04b5, 0x30aa }, - { 0x04b6, 0x30ab }, - { 0x04b7, 0x30ad }, - { 0x04b8, 0x30af }, - { 0x04b9, 0x30b1 }, - { 0x04ba, 0x30b3 }, - { 0x04bb, 0x30b5 }, - { 0x04bc, 0x30b7 }, - { 0x04bd, 0x30b9 }, - { 0x04be, 0x30bb }, - { 0x04bf, 0x30bd }, - { 0x04c0, 0x30bf }, - { 0x04c1, 0x30c1 }, - { 0x04c2, 0x30c4 }, - { 0x04c3, 0x30c6 }, - { 0x04c4, 0x30c8 }, - { 0x04c5, 0x30ca }, - { 0x04c6, 0x30cb }, - { 0x04c7, 0x30cc }, - { 0x04c8, 0x30cd }, - { 0x04c9, 0x30ce }, - { 0x04ca, 0x30cf }, - { 0x04cb, 0x30d2 }, - { 0x04cc, 0x30d5 }, - { 0x04cd, 0x30d8 }, - { 0x04ce, 0x30db }, - { 0x04cf, 0x30de }, - { 0x04d0, 0x30df }, - { 0x04d1, 0x30e0 }, - { 0x04d2, 0x30e1 }, - { 0x04d3, 0x30e2 }, - { 0x04d4, 0x30e4 }, - { 0x04d5, 0x30e6 }, - { 0x04d6, 0x30e8 }, - { 0x04d7, 0x30e9 }, - { 0x04d8, 0x30ea }, - { 0x04d9, 0x30eb }, - { 0x04da, 0x30ec }, - { 0x04db, 0x30ed }, - { 0x04dc, 0x30ef }, - { 0x04dd, 0x30f3 }, - { 0x04de, 0x309b }, - { 0x04df, 0x309c }, - { 0x05ac, 0x060c }, - { 0x05bb, 0x061b }, - { 0x05bf, 0x061f }, - { 0x05c1, 0x0621 }, - { 0x05c2, 0x0622 }, - { 0x05c3, 0x0623 }, - { 0x05c4, 0x0624 }, - { 0x05c5, 0x0625 }, - { 0x05c6, 0x0626 }, - { 0x05c7, 0x0627 }, - { 0x05c8, 0x0628 }, - { 0x05c9, 0x0629 }, - { 0x05ca, 0x062a }, - { 0x05cb, 0x062b }, - { 0x05cc, 0x062c }, - { 0x05cd, 0x062d }, - { 0x05ce, 0x062e }, - { 0x05cf, 0x062f }, - { 0x05d0, 0x0630 }, - { 0x05d1, 0x0631 }, - { 0x05d2, 0x0632 }, - { 0x05d3, 0x0633 }, - { 0x05d4, 0x0634 }, - { 0x05d5, 0x0635 }, - { 0x05d6, 0x0636 }, - { 0x05d7, 0x0637 }, - { 0x05d8, 0x0638 }, - { 0x05d9, 0x0639 }, - { 0x05da, 0x063a }, - { 0x05e0, 0x0640 }, - { 0x05e1, 0x0641 }, - { 0x05e2, 0x0642 }, - { 0x05e3, 0x0643 }, - { 0x05e4, 0x0644 }, - { 0x05e5, 0x0645 }, - { 0x05e6, 0x0646 }, - { 0x05e7, 0x0647 }, - { 0x05e8, 0x0648 }, - { 0x05e9, 0x0649 }, - { 0x05ea, 0x064a }, - { 0x05eb, 0x064b }, - { 0x05ec, 0x064c }, - { 0x05ed, 0x064d }, - { 0x05ee, 0x064e }, - { 0x05ef, 0x064f }, - { 0x05f0, 0x0650 }, - { 0x05f1, 0x0651 }, - { 0x05f2, 0x0652 }, - { 0x06a1, 0x0452 }, - { 0x06a2, 0x0453 }, - { 0x06a3, 0x0451 }, - { 0x06a4, 0x0454 }, - { 0x06a5, 0x0455 }, - { 0x06a6, 0x0456 }, - { 0x06a7, 0x0457 }, - { 0x06a8, 0x0458 }, - { 0x06a9, 0x0459 }, - { 0x06aa, 0x045a }, - { 0x06ab, 0x045b }, - { 0x06ac, 0x045c }, - { 0x06ae, 0x045e }, - { 0x06af, 0x045f }, - { 0x06b0, 0x2116 }, - { 0x06b1, 0x0402 }, - { 0x06b2, 0x0403 }, - { 0x06b3, 0x0401 }, - { 0x06b4, 0x0404 }, - { 0x06b5, 0x0405 }, - { 0x06b6, 0x0406 }, - { 0x06b7, 0x0407 }, - { 0x06b8, 0x0408 }, - { 0x06b9, 0x0409 }, - { 0x06ba, 0x040a }, - { 0x06bb, 0x040b }, - { 0x06bc, 0x040c }, - { 0x06be, 0x040e }, - { 0x06bf, 0x040f }, - { 0x06c0, 0x044e }, - { 0x06c1, 0x0430 }, - { 0x06c2, 0x0431 }, - { 0x06c3, 0x0446 }, - { 0x06c4, 0x0434 }, - { 0x06c5, 0x0435 }, - { 0x06c6, 0x0444 }, - { 0x06c7, 0x0433 }, - { 0x06c8, 0x0445 }, - { 0x06c9, 0x0438 }, - { 0x06ca, 0x0439 }, - { 0x06cb, 0x043a }, - { 0x06cc, 0x043b }, - { 0x06cd, 0x043c }, - { 0x06ce, 0x043d }, - { 0x06cf, 0x043e }, - { 0x06d0, 0x043f }, - { 0x06d1, 0x044f }, - { 0x06d2, 0x0440 }, - { 0x06d3, 0x0441 }, - { 0x06d4, 0x0442 }, - { 0x06d5, 0x0443 }, - { 0x06d6, 0x0436 }, - { 0x06d7, 0x0432 }, - { 0x06d8, 0x044c }, - { 0x06d9, 0x044b }, - { 0x06da, 0x0437 }, - { 0x06db, 0x0448 }, - { 0x06dc, 0x044d }, - { 0x06dd, 0x0449 }, - { 0x06de, 0x0447 }, - { 0x06df, 0x044a }, - { 0x06e0, 0x042e }, - { 0x06e1, 0x0410 }, - { 0x06e2, 0x0411 }, - { 0x06e3, 0x0426 }, - { 0x06e4, 0x0414 }, - { 0x06e5, 0x0415 }, - { 0x06e6, 0x0424 }, - { 0x06e7, 0x0413 }, - { 0x06e8, 0x0425 }, - { 0x06e9, 0x0418 }, - { 0x06ea, 0x0419 }, - { 0x06eb, 0x041a }, - { 0x06ec, 0x041b }, - { 0x06ed, 0x041c }, - { 0x06ee, 0x041d }, - { 0x06ef, 0x041e }, - { 0x06f0, 0x041f }, - { 0x06f1, 0x042f }, - { 0x06f2, 0x0420 }, - { 0x06f3, 0x0421 }, - { 0x06f4, 0x0422 }, - { 0x06f5, 0x0423 }, - { 0x06f6, 0x0416 }, - { 0x06f7, 0x0412 }, - { 0x06f8, 0x042c }, - { 0x06f9, 0x042b }, - { 0x06fa, 0x0417 }, - { 0x06fb, 0x0428 }, - { 0x06fc, 0x042d }, - { 0x06fd, 0x0429 }, - { 0x06fe, 0x0427 }, - { 0x06ff, 0x042a }, - { 0x07a1, 0x0386 }, - { 0x07a2, 0x0388 }, - { 0x07a3, 0x0389 }, - { 0x07a4, 0x038a }, - { 0x07a5, 0x03aa }, - { 0x07a7, 0x038c }, - { 0x07a8, 0x038e }, - { 0x07a9, 0x03ab }, - { 0x07ab, 0x038f }, - { 0x07ae, 0x0385 }, - { 0x07af, 0x2015 }, - { 0x07b1, 0x03ac }, - { 0x07b2, 0x03ad }, - { 0x07b3, 0x03ae }, - { 0x07b4, 0x03af }, - { 0x07b5, 0x03ca }, - { 0x07b6, 0x0390 }, - { 0x07b7, 0x03cc }, - { 0x07b8, 0x03cd }, - { 0x07b9, 0x03cb }, - { 0x07ba, 0x03b0 }, - { 0x07bb, 0x03ce }, - { 0x07c1, 0x0391 }, - { 0x07c2, 0x0392 }, - { 0x07c3, 0x0393 }, - { 0x07c4, 0x0394 }, - { 0x07c5, 0x0395 }, - { 0x07c6, 0x0396 }, - { 0x07c7, 0x0397 }, - { 0x07c8, 0x0398 }, - { 0x07c9, 0x0399 }, - { 0x07ca, 0x039a }, - { 0x07cb, 0x039b }, - { 0x07cc, 0x039c }, - { 0x07cd, 0x039d }, - { 0x07ce, 0x039e }, - { 0x07cf, 0x039f }, - { 0x07d0, 0x03a0 }, - { 0x07d1, 0x03a1 }, - { 0x07d2, 0x03a3 }, - { 0x07d4, 0x03a4 }, - { 0x07d5, 0x03a5 }, - { 0x07d6, 0x03a6 }, - { 0x07d7, 0x03a7 }, - { 0x07d8, 0x03a8 }, - { 0x07d9, 0x03a9 }, - { 0x07e1, 0x03b1 }, - { 0x07e2, 0x03b2 }, - { 0x07e3, 0x03b3 }, - { 0x07e4, 0x03b4 }, - { 0x07e5, 0x03b5 }, - { 0x07e6, 0x03b6 }, - { 0x07e7, 0x03b7 }, - { 0x07e8, 0x03b8 }, - { 0x07e9, 0x03b9 }, - { 0x07ea, 0x03ba }, - { 0x07eb, 0x03bb }, - { 0x07ec, 0x03bc }, - { 0x07ed, 0x03bd }, - { 0x07ee, 0x03be }, - { 0x07ef, 0x03bf }, - { 0x07f0, 0x03c0 }, - { 0x07f1, 0x03c1 }, - { 0x07f2, 0x03c3 }, - { 0x07f3, 0x03c2 }, - { 0x07f4, 0x03c4 }, - { 0x07f5, 0x03c5 }, - { 0x07f6, 0x03c6 }, - { 0x07f7, 0x03c7 }, - { 0x07f8, 0x03c8 }, - { 0x07f9, 0x03c9 }, - { 0x08a1, 0x23b7 }, - { 0x08a2, 0x250c }, - { 0x08a3, 0x2500 }, - { 0x08a4, 0x2320 }, - { 0x08a5, 0x2321 }, - { 0x08a6, 0x2502 }, - { 0x08a7, 0x23a1 }, - { 0x08a8, 0x23a3 }, - { 0x08a9, 0x23a4 }, - { 0x08aa, 0x23a6 }, - { 0x08ab, 0x239b }, - { 0x08ac, 0x239d }, - { 0x08ad, 0x239e }, - { 0x08ae, 0x23a0 }, - { 0x08af, 0x23a8 }, - { 0x08b0, 0x23ac }, - { 0x08bc, 0x2264 }, - { 0x08bd, 0x2260 }, - { 0x08be, 0x2265 }, - { 0x08bf, 0x222b }, - { 0x08c0, 0x2234 }, - { 0x08c1, 0x221d }, - { 0x08c2, 0x221e }, - { 0x08c5, 0x2207 }, - { 0x08c8, 0x223c }, - { 0x08c9, 0x2243 }, - { 0x08cd, 0x21d4 }, - { 0x08ce, 0x21d2 }, - { 0x08cf, 0x2261 }, - { 0x08d6, 0x221a }, - { 0x08da, 0x2282 }, - { 0x08db, 0x2283 }, - { 0x08dc, 0x2229 }, - { 0x08dd, 0x222a }, - { 0x08de, 0x2227 }, - { 0x08df, 0x2228 }, - { 0x08ef, 0x2202 }, - { 0x08f6, 0x0192 }, - { 0x08fb, 0x2190 }, - { 0x08fc, 0x2191 }, - { 0x08fd, 0x2192 }, - { 0x08fe, 0x2193 }, - { 0x09e0, 0x25c6 }, - { 0x09e1, 0x2592 }, - { 0x09e2, 0x2409 }, - { 0x09e3, 0x240c }, - { 0x09e4, 0x240d }, - { 0x09e5, 0x240a }, - { 0x09e8, 0x2424 }, - { 0x09e9, 0x240b }, - { 0x09ea, 0x2518 }, - { 0x09eb, 0x2510 }, - { 0x09ec, 0x250c }, - { 0x09ed, 0x2514 }, - { 0x09ee, 0x253c }, - { 0x09ef, 0x23ba }, - { 0x09f0, 0x23bb }, - { 0x09f1, 0x2500 }, - { 0x09f2, 0x23bc }, - { 0x09f3, 0x23bd }, - { 0x09f4, 0x251c }, - { 0x09f5, 0x2524 }, - { 0x09f6, 0x2534 }, - { 0x09f7, 0x252c }, - { 0x09f8, 0x2502 }, - { 0x0aa1, 0x2003 }, - { 0x0aa2, 0x2002 }, - { 0x0aa3, 0x2004 }, - { 0x0aa4, 0x2005 }, - { 0x0aa5, 0x2007 }, - { 0x0aa6, 0x2008 }, - { 0x0aa7, 0x2009 }, - { 0x0aa8, 0x200a }, - { 0x0aa9, 0x2014 }, - { 0x0aaa, 0x2013 }, - { 0x0aae, 0x2026 }, - { 0x0aaf, 0x2025 }, - { 0x0ab0, 0x2153 }, - { 0x0ab1, 0x2154 }, - { 0x0ab2, 0x2155 }, - { 0x0ab3, 0x2156 }, - { 0x0ab4, 0x2157 }, - { 0x0ab5, 0x2158 }, - { 0x0ab6, 0x2159 }, - { 0x0ab7, 0x215a }, - { 0x0ab8, 0x2105 }, - { 0x0abb, 0x2012 }, - { 0x0abc, 0x2329 }, - { 0x0abe, 0x232a }, - { 0x0ac3, 0x215b }, - { 0x0ac4, 0x215c }, - { 0x0ac5, 0x215d }, - { 0x0ac6, 0x215e }, - { 0x0ac9, 0x2122 }, - { 0x0aca, 0x2613 }, - { 0x0acc, 0x25c1 }, - { 0x0acd, 0x25b7 }, - { 0x0ace, 0x25cb }, - { 0x0acf, 0x25af }, - { 0x0ad0, 0x2018 }, - { 0x0ad1, 0x2019 }, - { 0x0ad2, 0x201c }, - { 0x0ad3, 0x201d }, - { 0x0ad4, 0x211e }, - { 0x0ad6, 0x2032 }, - { 0x0ad7, 0x2033 }, - { 0x0ad9, 0x271d }, - { 0x0adb, 0x25ac }, - { 0x0adc, 0x25c0 }, - { 0x0add, 0x25b6 }, - { 0x0ade, 0x25cf }, - { 0x0adf, 0x25ae }, - { 0x0ae0, 0x25e6 }, - { 0x0ae1, 0x25ab }, - { 0x0ae2, 0x25ad }, - { 0x0ae3, 0x25b3 }, - { 0x0ae4, 0x25bd }, - { 0x0ae5, 0x2606 }, - { 0x0ae6, 0x2022 }, - { 0x0ae7, 0x25aa }, - { 0x0ae8, 0x25b2 }, - { 0x0ae9, 0x25bc }, - { 0x0aea, 0x261c }, - { 0x0aeb, 0x261e }, - { 0x0aec, 0x2663 }, - { 0x0aed, 0x2666 }, - { 0x0aee, 0x2665 }, - { 0x0af0, 0x2720 }, - { 0x0af1, 0x2020 }, - { 0x0af2, 0x2021 }, - { 0x0af3, 0x2713 }, - { 0x0af4, 0x2717 }, - { 0x0af5, 0x266f }, - { 0x0af6, 0x266d }, - { 0x0af7, 0x2642 }, - { 0x0af8, 0x2640 }, - { 0x0af9, 0x260e }, - { 0x0afa, 0x2315 }, - { 0x0afb, 0x2117 }, - { 0x0afc, 0x2038 }, - { 0x0afd, 0x201a }, - { 0x0afe, 0x201e }, - { 0x0ba3, 0x003c }, - { 0x0ba6, 0x003e }, - { 0x0ba8, 0x2228 }, - { 0x0ba9, 0x2227 }, - { 0x0bc0, 0x00af }, - { 0x0bc2, 0x22a5 }, - { 0x0bc3, 0x2229 }, - { 0x0bc4, 0x230a }, - { 0x0bc6, 0x005f }, - { 0x0bca, 0x2218 }, - { 0x0bcc, 0x2395 }, - { 0x0bce, 0x22a4 }, - { 0x0bcf, 0x25cb }, - { 0x0bd3, 0x2308 }, - { 0x0bd6, 0x222a }, - { 0x0bd8, 0x2283 }, - { 0x0bda, 0x2282 }, - { 0x0bdc, 0x22a2 }, - { 0x0bfc, 0x22a3 }, - { 0x0cdf, 0x2017 }, - { 0x0ce0, 0x05d0 }, - { 0x0ce1, 0x05d1 }, - { 0x0ce2, 0x05d2 }, - { 0x0ce3, 0x05d3 }, - { 0x0ce4, 0x05d4 }, - { 0x0ce5, 0x05d5 }, - { 0x0ce6, 0x05d6 }, - { 0x0ce7, 0x05d7 }, - { 0x0ce8, 0x05d8 }, - { 0x0ce9, 0x05d9 }, - { 0x0cea, 0x05da }, - { 0x0ceb, 0x05db }, - { 0x0cec, 0x05dc }, - { 0x0ced, 0x05dd }, - { 0x0cee, 0x05de }, - { 0x0cef, 0x05df }, - { 0x0cf0, 0x05e0 }, - { 0x0cf1, 0x05e1 }, - { 0x0cf2, 0x05e2 }, - { 0x0cf3, 0x05e3 }, - { 0x0cf4, 0x05e4 }, - { 0x0cf5, 0x05e5 }, - { 0x0cf6, 0x05e6 }, - { 0x0cf7, 0x05e7 }, - { 0x0cf8, 0x05e8 }, - { 0x0cf9, 0x05e9 }, - { 0x0cfa, 0x05ea }, - { 0x0da1, 0x0e01 }, - { 0x0da2, 0x0e02 }, - { 0x0da3, 0x0e03 }, - { 0x0da4, 0x0e04 }, - { 0x0da5, 0x0e05 }, - { 0x0da6, 0x0e06 }, - { 0x0da7, 0x0e07 }, - { 0x0da8, 0x0e08 }, - { 0x0da9, 0x0e09 }, - { 0x0daa, 0x0e0a }, - { 0x0dab, 0x0e0b }, - { 0x0dac, 0x0e0c }, - { 0x0dad, 0x0e0d }, - { 0x0dae, 0x0e0e }, - { 0x0daf, 0x0e0f }, - { 0x0db0, 0x0e10 }, - { 0x0db1, 0x0e11 }, - { 0x0db2, 0x0e12 }, - { 0x0db3, 0x0e13 }, - { 0x0db4, 0x0e14 }, - { 0x0db5, 0x0e15 }, - { 0x0db6, 0x0e16 }, - { 0x0db7, 0x0e17 }, - { 0x0db8, 0x0e18 }, - { 0x0db9, 0x0e19 }, - { 0x0dba, 0x0e1a }, - { 0x0dbb, 0x0e1b }, - { 0x0dbc, 0x0e1c }, - { 0x0dbd, 0x0e1d }, - { 0x0dbe, 0x0e1e }, - { 0x0dbf, 0x0e1f }, - { 0x0dc0, 0x0e20 }, - { 0x0dc1, 0x0e21 }, - { 0x0dc2, 0x0e22 }, - { 0x0dc3, 0x0e23 }, - { 0x0dc4, 0x0e24 }, - { 0x0dc5, 0x0e25 }, - { 0x0dc6, 0x0e26 }, - { 0x0dc7, 0x0e27 }, - { 0x0dc8, 0x0e28 }, - { 0x0dc9, 0x0e29 }, - { 0x0dca, 0x0e2a }, - { 0x0dcb, 0x0e2b }, - { 0x0dcc, 0x0e2c }, - { 0x0dcd, 0x0e2d }, - { 0x0dce, 0x0e2e }, - { 0x0dcf, 0x0e2f }, - { 0x0dd0, 0x0e30 }, - { 0x0dd1, 0x0e31 }, - { 0x0dd2, 0x0e32 }, - { 0x0dd3, 0x0e33 }, - { 0x0dd4, 0x0e34 }, - { 0x0dd5, 0x0e35 }, - { 0x0dd6, 0x0e36 }, - { 0x0dd7, 0x0e37 }, - { 0x0dd8, 0x0e38 }, - { 0x0dd9, 0x0e39 }, - { 0x0dda, 0x0e3a }, - { 0x0ddf, 0x0e3f }, - { 0x0de0, 0x0e40 }, - { 0x0de1, 0x0e41 }, - { 0x0de2, 0x0e42 }, - { 0x0de3, 0x0e43 }, - { 0x0de4, 0x0e44 }, - { 0x0de5, 0x0e45 }, - { 0x0de6, 0x0e46 }, - { 0x0de7, 0x0e47 }, - { 0x0de8, 0x0e48 }, - { 0x0de9, 0x0e49 }, - { 0x0dea, 0x0e4a }, - { 0x0deb, 0x0e4b }, - { 0x0dec, 0x0e4c }, - { 0x0ded, 0x0e4d }, - { 0x0df0, 0x0e50 }, - { 0x0df1, 0x0e51 }, - { 0x0df2, 0x0e52 }, - { 0x0df3, 0x0e53 }, - { 0x0df4, 0x0e54 }, - { 0x0df5, 0x0e55 }, - { 0x0df6, 0x0e56 }, - { 0x0df7, 0x0e57 }, - { 0x0df8, 0x0e58 }, - { 0x0df9, 0x0e59 }, - { 0x0ea1, 0x3131 }, - { 0x0ea2, 0x3132 }, - { 0x0ea3, 0x3133 }, - { 0x0ea4, 0x3134 }, - { 0x0ea5, 0x3135 }, - { 0x0ea6, 0x3136 }, - { 0x0ea7, 0x3137 }, - { 0x0ea8, 0x3138 }, - { 0x0ea9, 0x3139 }, - { 0x0eaa, 0x313a }, - { 0x0eab, 0x313b }, - { 0x0eac, 0x313c }, - { 0x0ead, 0x313d }, - { 0x0eae, 0x313e }, - { 0x0eaf, 0x313f }, - { 0x0eb0, 0x3140 }, - { 0x0eb1, 0x3141 }, - { 0x0eb2, 0x3142 }, - { 0x0eb3, 0x3143 }, - { 0x0eb4, 0x3144 }, - { 0x0eb5, 0x3145 }, - { 0x0eb6, 0x3146 }, - { 0x0eb7, 0x3147 }, - { 0x0eb8, 0x3148 }, - { 0x0eb9, 0x3149 }, - { 0x0eba, 0x314a }, - { 0x0ebb, 0x314b }, - { 0x0ebc, 0x314c }, - { 0x0ebd, 0x314d }, - { 0x0ebe, 0x314e }, - { 0x0ebf, 0x314f }, - { 0x0ec0, 0x3150 }, - { 0x0ec1, 0x3151 }, - { 0x0ec2, 0x3152 }, - { 0x0ec3, 0x3153 }, - { 0x0ec4, 0x3154 }, - { 0x0ec5, 0x3155 }, - { 0x0ec6, 0x3156 }, - { 0x0ec7, 0x3157 }, - { 0x0ec8, 0x3158 }, - { 0x0ec9, 0x3159 }, - { 0x0eca, 0x315a }, - { 0x0ecb, 0x315b }, - { 0x0ecc, 0x315c }, - { 0x0ecd, 0x315d }, - { 0x0ece, 0x315e }, - { 0x0ecf, 0x315f }, - { 0x0ed0, 0x3160 }, - { 0x0ed1, 0x3161 }, - { 0x0ed2, 0x3162 }, - { 0x0ed3, 0x3163 }, - { 0x0ed4, 0x11a8 }, - { 0x0ed5, 0x11a9 }, - { 0x0ed6, 0x11aa }, - { 0x0ed7, 0x11ab }, - { 0x0ed8, 0x11ac }, - { 0x0ed9, 0x11ad }, - { 0x0eda, 0x11ae }, - { 0x0edb, 0x11af }, - { 0x0edc, 0x11b0 }, - { 0x0edd, 0x11b1 }, - { 0x0ede, 0x11b2 }, - { 0x0edf, 0x11b3 }, - { 0x0ee0, 0x11b4 }, - { 0x0ee1, 0x11b5 }, - { 0x0ee2, 0x11b6 }, - { 0x0ee3, 0x11b7 }, - { 0x0ee4, 0x11b8 }, - { 0x0ee5, 0x11b9 }, - { 0x0ee6, 0x11ba }, - { 0x0ee7, 0x11bb }, - { 0x0ee8, 0x11bc }, - { 0x0ee9, 0x11bd }, - { 0x0eea, 0x11be }, - { 0x0eeb, 0x11bf }, - { 0x0eec, 0x11c0 }, - { 0x0eed, 0x11c1 }, - { 0x0eee, 0x11c2 }, - { 0x0eef, 0x316d }, - { 0x0ef0, 0x3171 }, - { 0x0ef1, 0x3178 }, - { 0x0ef2, 0x317f }, - { 0x0ef3, 0x3181 }, - { 0x0ef4, 0x3184 }, - { 0x0ef5, 0x3186 }, - { 0x0ef6, 0x318d }, - { 0x0ef7, 0x318e }, - { 0x0ef8, 0x11eb }, - { 0x0ef9, 0x11f0 }, - { 0x0efa, 0x11f9 }, - { 0x0eff, 0x20a9 }, - { 0x13a4, 0x20ac }, - { 0x13bc, 0x0152 }, - { 0x13bd, 0x0153 }, - { 0x13be, 0x0178 }, - { 0x20ac, 0x20ac }, - { 0xfe50, '`' }, - { 0xfe51, 0x00b4 }, - { 0xfe52, '^' }, - { 0xfe53, '~' }, - { 0xfe54, 0x00af }, - { 0xfe55, 0x02d8 }, - { 0xfe56, 0x02d9 }, - { 0xfe57, 0x00a8 }, - { 0xfe58, 0x02da }, - { 0xfe59, 0x02dd }, - { 0xfe5a, 0x02c7 }, - { 0xfe5b, 0x00b8 }, - { 0xfe5c, 0x02db }, - { 0xfe5d, 0x037a }, - { 0xfe5e, 0x309b }, - { 0xfe5f, 0x309c }, - { 0xfe63, '/' }, - { 0xfe64, 0x02bc }, - { 0xfe65, 0x02bd }, - { 0xfe66, 0x02f5 }, - { 0xfe67, 0x02f3 }, - { 0xfe68, 0x02cd }, - { 0xfe69, 0xa788 }, - { 0xfe6a, 0x02f7 }, - { 0xfe6e, ',' }, - { 0xfe6f, 0x00a4 }, - { 0xfe80, 'a' }, // XK_dead_a - { 0xfe81, 'A' }, // XK_dead_A - { 0xfe82, 'e' }, // XK_dead_e - { 0xfe83, 'E' }, // XK_dead_E - { 0xfe84, 'i' }, // XK_dead_i - { 0xfe85, 'I' }, // XK_dead_I - { 0xfe86, 'o' }, // XK_dead_o - { 0xfe87, 'O' }, // XK_dead_O - { 0xfe88, 'u' }, // XK_dead_u - { 0xfe89, 'U' }, // XK_dead_U - { 0xfe8a, 0x0259 }, - { 0xfe8b, 0x018f }, - { 0xfe8c, 0x00b5 }, - { 0xfe90, '_' }, - { 0xfe91, 0x02c8 }, - { 0xfe92, 0x02cc }, - { 0xff80 /*XKB_KEY_KP_Space*/, ' ' }, - { 0xff95 /*XKB_KEY_KP_7*/, 0x0037 }, - { 0xff96 /*XKB_KEY_KP_4*/, 0x0034 }, - { 0xff97 /*XKB_KEY_KP_8*/, 0x0038 }, - { 0xff98 /*XKB_KEY_KP_6*/, 0x0036 }, - { 0xff99 /*XKB_KEY_KP_2*/, 0x0032 }, - { 0xff9a /*XKB_KEY_KP_9*/, 0x0039 }, - { 0xff9b /*XKB_KEY_KP_3*/, 0x0033 }, - { 0xff9c /*XKB_KEY_KP_1*/, 0x0031 }, - { 0xff9d /*XKB_KEY_KP_5*/, 0x0035 }, - { 0xff9e /*XKB_KEY_KP_0*/, 0x0030 }, - { 0xffaa /*XKB_KEY_KP_Multiply*/, '*' }, - { 0xffab /*XKB_KEY_KP_Add*/, '+' }, - { 0xffac /*XKB_KEY_KP_Separator*/, ',' }, - { 0xffad /*XKB_KEY_KP_Subtract*/, '-' }, - { 0xffae /*XKB_KEY_KP_Decimal*/, '.' }, - { 0xffaf /*XKB_KEY_KP_Divide*/, '/' }, - { 0xffb0 /*XKB_KEY_KP_0*/, 0x0030 }, - { 0xffb1 /*XKB_KEY_KP_1*/, 0x0031 }, - { 0xffb2 /*XKB_KEY_KP_2*/, 0x0032 }, - { 0xffb3 /*XKB_KEY_KP_3*/, 0x0033 }, - { 0xffb4 /*XKB_KEY_KP_4*/, 0x0034 }, - { 0xffb5 /*XKB_KEY_KP_5*/, 0x0035 }, - { 0xffb6 /*XKB_KEY_KP_6*/, 0x0036 }, - { 0xffb7 /*XKB_KEY_KP_7*/, 0x0037 }, - { 0xffb8 /*XKB_KEY_KP_8*/, 0x0038 }, - { 0xffb9 /*XKB_KEY_KP_9*/, 0x0039 }, - { 0xffbd /*XKB_KEY_KP_Equal*/, '=' } -}; - - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -// Convert XKB KeySym to Unicode -// -long _glfwKeySym2Unicode(unsigned int keysym) -{ - int min = 0; - int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; - int mid; - - // First check for Latin-1 characters (1:1 mapping) - if ((keysym >= 0x0020 && keysym <= 0x007e) || - (keysym >= 0x00a0 && keysym <= 0x00ff)) - { - return keysym; - } - - // Also check for directly encoded 24-bit UCS characters - if ((keysym & 0xff000000) == 0x01000000) - return keysym & 0x00ffffff; - - // Binary search in table - while (max >= min) - { - mid = (min + max) / 2; - if (keysymtab[mid].keysym < keysym) - min = mid + 1; - else if (keysymtab[mid].keysym > keysym) - max = mid - 1; - else - return keysymtab[mid].ucs; - } - - // No matching Unicode value found - return -1; -} - diff --git a/glfw/xkb_unicode.h b/glfw/xkb_unicode.h deleted file mode 100644 index f95e14f10..000000000 --- a/glfw/xkb_unicode.h +++ /dev/null @@ -1,28 +0,0 @@ -//======================================================================== -// GLFW 3.3 Linux - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2014 Jonas Ådahl -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not -// be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source -// distribution. -// -//======================================================================== - -long _glfwKeySym2Unicode(unsigned int keysym); - diff --git a/kitty/glfw-wrapper.c b/kitty/glfw-wrapper.c index 02399431e..d3a839ba4 100644 --- a/kitty/glfw-wrapper.c +++ b/kitty/glfw-wrapper.c @@ -254,14 +254,8 @@ load_glfw(const char* path) { *(void **) (&glfwSetCursor_impl) = dlsym(handle, "glfwSetCursor"); if (glfwSetCursor_impl == NULL) fail("Failed to load glfw function glfwSetCursor with error: %s", dlerror()); - *(void **) (&glfwSetKeyCallback_impl) = dlsym(handle, "glfwSetKeyCallback"); - if (glfwSetKeyCallback_impl == NULL) fail("Failed to load glfw function glfwSetKeyCallback with error: %s", dlerror()); - - *(void **) (&glfwSetCharCallback_impl) = dlsym(handle, "glfwSetCharCallback"); - if (glfwSetCharCallback_impl == NULL) fail("Failed to load glfw function glfwSetCharCallback with error: %s", dlerror()); - - *(void **) (&glfwSetCharModsCallback_impl) = dlsym(handle, "glfwSetCharModsCallback"); - if (glfwSetCharModsCallback_impl == NULL) fail("Failed to load glfw function glfwSetCharModsCallback with error: %s", dlerror()); + *(void **) (&glfwSetKeyboardCallback_impl) = dlsym(handle, "glfwSetKeyboardCallback"); + if (glfwSetKeyboardCallback_impl == NULL) fail("Failed to load glfw function glfwSetKeyboardCallback with error: %s", dlerror()); *(void **) (&glfwSetMouseButtonCallback_impl) = dlsym(handle, "glfwSetMouseButtonCallback"); if (glfwSetMouseButtonCallback_impl == NULL) fail("Failed to load glfw function glfwSetMouseButtonCallback with error: %s", dlerror()); diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index 29271c490..a709186a8 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -1133,9 +1133,15 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); */ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); -/*! @brief The function signature for keyboard key callbacks. +/*! @brief The function signature for key callbacks. * - * This is the function signature for keyboard key callback functions. + * This is the function signature for key callback functions. + * The semantics of this function are that the key that is interacted with on the + * keyboard is reported, and the text, if any generated by the key is reported. + * So, for example, if on a US-ASCII keyboard the user presses Shift+= GLFW + * will report the text "+" and the key as GLFW_KEY_EQUAL. The reported key takes into + * account any current keyboard maps defined in the OS. So with a dvorak mapping, pressing + * the "q" key will generate text "d" and GLFW_KEY_D. * * @param[in] window The window that received the event. * @param[in] key The [keyboard key](@ref keys) that was pressed or released. @@ -1143,56 +1149,17 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. + * @param[in] text UTF-8 encoded text generated by this key event or empty string. + * @param[in] reserved Reserved for future use. * * @sa @ref input_key - * @sa @ref glfwSetKeyCallback + * @sa @ref glfwSetKeyboardCallback * - * @since Added in version 1.0. - * @glfw3 Added window handle, scancode and modifier mask parameters. + * @since Added in version 4.0. * * @ingroup input */ -typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); - -/*! @brief The function signature for Unicode character callbacks. - * - * This is the function signature for Unicode character callback functions. - * - * @param[in] window The window that received the event. - * @param[in] codepoint The Unicode code point of the character. - * - * @sa @ref input_char - * @sa @ref glfwSetCharCallback - * - * @since Added in version 2.4. - * @glfw3 Added window handle parameter. - * - * @ingroup input - */ -typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); - -/*! @brief The function signature for Unicode character with modifiers - * callbacks. - * - * This is the function signature for Unicode character with modifiers callback - * functions. It is called for each input character, regardless of what - * modifier keys are held down. - * - * @param[in] window The window that received the event. - * @param[in] codepoint The Unicode code point of the character. - * @param[in] mods Bit field describing which [modifier keys](@ref mods) were - * held down. - * - * @sa @ref input_char - * @sa @ref glfwSetCharModsCallback - * - * @deprecated Scheduled for removal in version 4.0. - * - * @since Added in version 3.1. - * - * @ingroup input - */ -typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); +typedef void (* GLFWkeyboardfun)(GLFWwindow*, int, int, int, int, const char*, int); /*! @brief The function signature for file drop callbacks. * @@ -1713,17 +1680,9 @@ typedef void (*glfwSetCursor_func)(GLFWwindow*, GLFWcursor*); glfwSetCursor_func glfwSetCursor_impl; #define glfwSetCursor glfwSetCursor_impl -typedef GLFWkeyfun (*glfwSetKeyCallback_func)(GLFWwindow*, GLFWkeyfun); -glfwSetKeyCallback_func glfwSetKeyCallback_impl; -#define glfwSetKeyCallback glfwSetKeyCallback_impl - -typedef GLFWcharfun (*glfwSetCharCallback_func)(GLFWwindow*, GLFWcharfun); -glfwSetCharCallback_func glfwSetCharCallback_impl; -#define glfwSetCharCallback glfwSetCharCallback_impl - -typedef GLFWcharmodsfun (*glfwSetCharModsCallback_func)(GLFWwindow*, GLFWcharmodsfun); -glfwSetCharModsCallback_func glfwSetCharModsCallback_impl; -#define glfwSetCharModsCallback glfwSetCharModsCallback_impl +typedef GLFWkeyboardfun (*glfwSetKeyboardCallback_func)(GLFWwindow*, GLFWkeyboardfun); +glfwSetKeyboardCallback_func glfwSetKeyboardCallback_impl; +#define glfwSetKeyboardCallback glfwSetKeyboardCallback_impl typedef GLFWmousebuttonfun (*glfwSetMouseButtonCallback_func)(GLFWwindow*, GLFWmousebuttonfun); glfwSetMouseButtonCallback_func glfwSetMouseButtonCallback_impl;