diff --git a/glfw/glfw.py b/glfw/glfw.py index e6460fa5b..7f847b504 100755 --- a/glfw/glfw.py +++ b/glfw/glfw.py @@ -22,20 +22,6 @@ def wayland_protocol_file_name(base, ext='c'): return 'wayland-{}-client-protocol.{}'.format(base, ext) -def find_epoll_shim(): - cflags, ldflags, libs = [], [], [] - for candidate in '/usr/local/include/libepoll-shim /usr/include/libepoll-shim /usr/local/include /usr/include'.split(): - if os.path.exists(os.path.join(candidate, 'sys/timerfd.h')): - cflags.append('-I' + candidate) - break - for candidate in '/usr/local/lib /usr/lib'.split(): - if os.path.exists(os.path.join(candidate, 'libepoll-shim.so')): - ldflags.append('-L' + candidate) - libs.append('-lepoll-shim') - break - return cflags, ldflags, libs - - def init_env(env, pkg_config, at_least_version, module='x11'): ans = env.copy() ans.cflags = [ @@ -77,12 +63,6 @@ def init_env(env, pkg_config, at_least_version, module='x11'): for p in ans.wayland_protocols: ans.sources.append(wayland_protocol_file_name(p)) ans.all_headers.append(wayland_protocol_file_name(p, 'h')) - if is_bsd: - epoll_cflags, epoll_libdirs, epoll_libs = find_epoll_shim() - if not epoll_cflags + epoll_libdirs: - raise Exception('Failed to find the epoll-shim package, needed to build the GLFW Wayland backend') - ans.cflags.extend(epoll_cflags) - ans.ldpaths.extend(epoll_libdirs + epoll_libs) for dep in 'wayland-egl wayland-client wayland-cursor xkbcommon'.split(): ans.cflags.extend(pkg_config(dep, '--cflags-only-I')) ans.ldpaths.extend(pkg_config(dep, '--libs')) diff --git a/glfw/source-info.json b/glfw/source-info.json index 8b205fdbd..00070c09b 100644 --- a/glfw/source-info.json +++ b/glfw/source-info.json @@ -57,6 +57,7 @@ "wl_platform.h", "posix_time.h", "posix_thread.h", + "xkb_glfw.h", "xkb_unicode.h", "egl_context.h", "osmesa_context.h", diff --git a/glfw/wl_init.c b/glfw/wl_init.c index c19184d0d..b35efb4b9 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -350,16 +349,7 @@ static void keyboardHandleKeymap(void* data, int fd, uint32_t size) { - struct xkb_keymap* keymap; - struct xkb_state* state; - -#ifdef HAVE_XKBCOMMON_COMPOSE_H - struct xkb_compose_table* composeTable; - struct xkb_compose_state* composeState; -#endif - char* mapStr; - const char* locale; if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { @@ -372,78 +362,10 @@ static void keyboardHandleKeymap(void* data, close(fd); return; } - - keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context, - mapStr, - XKB_KEYMAP_FORMAT_TEXT_V1, - 0); + xkb_glfw_compile_keymap(mapStr); munmap(mapStr, size); close(fd); - if (!keymap) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to compile keymap"); - return; - } - - state = xkb_state_new(keymap); - if (!state) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create XKB state"); - xkb_keymap_unref(keymap); - return; - } - - // 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"; - -#ifdef HAVE_XKBCOMMON_COMPOSE_H - composeTable = - xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale, - XKB_COMPOSE_COMPILE_NO_FLAGS); - if (composeTable) - { - composeState = - xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS); - xkb_compose_table_unref(composeTable); - if (composeState) - _glfw.wl.xkb.composeState = composeState; - else - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create XKB compose state"); - } - else - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to create XKB compose table"); - } -#endif - - xkb_keymap_unref(_glfw.wl.xkb.keymap); - xkb_state_unref(_glfw.wl.xkb.state); - _glfw.wl.xkb.keymap = keymap; - _glfw.wl.xkb.state = state; - - _glfw.wl.xkb.controlMask = - 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control"); - _glfw.wl.xkb.altMask = - 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1"); - _glfw.wl.xkb.shiftMask = - 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); - _glfw.wl.xkb.superMask = - 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); - _glfw.wl.xkb.capsLockMask = - 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock"); - _glfw.wl.xkb.numLockMask = - 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2"); } static void keyboardHandleEnter(void* data, @@ -482,15 +404,6 @@ static void keyboardHandleLeave(void* data, _glfwInputWindowFocus(window, GLFW_FALSE); } -static int toGLFWKeyCode(uint32_t key) -{ - if (key < sizeof(_glfw.wl.keycodes) / sizeof(_glfw.wl.keycodes[0])) - return _glfw.wl.keycodes[key]; - - return GLFW_KEY_UNKNOWN; -} - -#ifdef HAVE_XKBCOMMON_COMPOSE_H static xkb_keysym_t composeSymbol(xkb_keysym_t sym) { if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState) @@ -510,9 +423,8 @@ static xkb_keysym_t composeSymbol(xkb_keysym_t sym) return sym; } } -#endif -static GLFWbool inputChar(_GLFWwindow* window, uint32_t key) +static void inputChar(_GLFWwindow* window, uint32_t key, GLFWbool *shouldRepeat) { uint32_t code, numSyms; long cp; @@ -521,24 +433,23 @@ static GLFWbool inputChar(_GLFWwindow* window, uint32_t key) 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) { -#ifdef HAVE_XKBCOMMON_COMPOSE_H sym = composeSymbol(syms[0]); -#else - sym = syms[0]; -#endif 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); } } - - return xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, syms[0]); } static void keyboardHandleKey(void* data, @@ -551,34 +462,33 @@ static void keyboardHandleKey(void* data, int keyCode; int action; _GLFWwindow* window = _glfw.wl.keyboardFocus; - GLFWbool shouldRepeat; - struct itimerspec timer = {}; if (!window) return; - keyCode = toGLFWKeyCode(key); + keyCode = xkb_glfw_to_glfw_key_code(key); action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE; + _glfw.wl.keyRepeatInfo.nextRepeatAt = 0; + _glfw.wl.keyRepeatInfo.codepoint = -1; _glfwInputKey(window, keyCode, key, action, _glfw.wl.xkb.modifiers); if (action == GLFW_PRESS) { - shouldRepeat = inputChar(window, key); + GLFWbool shouldRepeat = GLFW_FALSE; + inputChar(window, key, &shouldRepeat); if (shouldRepeat && _glfw.wl.keyboardRepeatRate > 0) { - _glfw.wl.keyboardLastKey = keyCode; - _glfw.wl.keyboardLastScancode = key; - timer.it_interval.tv_sec = _glfw.wl.keyboardRepeatRate / 1000; - timer.it_interval.tv_nsec = (_glfw.wl.keyboardRepeatRate % 1000) * 1000000; - timer.it_value.tv_sec = _glfw.wl.keyboardRepeatDelay / 1000; - timer.it_value.tv_nsec = (_glfw.wl.keyboardRepeatDelay % 1000) * 1000000; + _glfw.wl.keyRepeatInfo.glfwKeyCode = keyCode; + _glfw.wl.keyRepeatInfo.scancode = key; + _glfw.wl.keyRepeatInfo.isFirstRepeat = GLFW_TRUE; + _glfw.wl.keyRepeatInfo.nextRepeatAt = glfwGetTime() + (double)(_glfw.wl.keyboardRepeatDelay) / 1000.0; + _glfw.wl.keyRepeatInfo.keyboardFocus = window; } } - timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL); } static void keyboardHandleModifiers(void* data, @@ -589,41 +499,9 @@ static void keyboardHandleModifiers(void* data, uint32_t modsLocked, uint32_t group) { - xkb_mod_mask_t mask; - unsigned int modifiers = 0; - - if (!_glfw.wl.xkb.keymap) - return; - - xkb_state_update_mask(_glfw.wl.xkb.state, - modsDepressed, - modsLatched, - modsLocked, - 0, - 0, - group); - - mask = xkb_state_serialize_mods(_glfw.wl.xkb.state, - XKB_STATE_MODS_DEPRESSED | - XKB_STATE_LAYOUT_DEPRESSED | - XKB_STATE_MODS_LATCHED | - XKB_STATE_LAYOUT_LATCHED); - if (mask & _glfw.wl.xkb.controlMask) - modifiers |= GLFW_MOD_CONTROL; - if (mask & _glfw.wl.xkb.altMask) - modifiers |= GLFW_MOD_ALT; - if (mask & _glfw.wl.xkb.shiftMask) - modifiers |= GLFW_MOD_SHIFT; - if (mask & _glfw.wl.xkb.superMask) - modifiers |= GLFW_MOD_SUPER; - if (mask & _glfw.wl.xkb.capsLockMask) - modifiers |= GLFW_MOD_CAPS_LOCK; - if (mask & _glfw.wl.xkb.numLockMask) - modifiers |= GLFW_MOD_NUM_LOCK; - _glfw.wl.xkb.modifiers = modifiers; + xkb_glfw_update_modifiers(modsDepressed, modsLatched, modsLocked); } -#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION static void keyboardHandleRepeatInfo(void* data, struct wl_keyboard* keyboard, int32_t rate, @@ -635,7 +513,6 @@ static void keyboardHandleRepeatInfo(void* data, _glfw.wl.keyboardRepeatRate = rate; _glfw.wl.keyboardRepeatDelay = delay; } -#endif static const struct wl_keyboard_listener keyboardListener = { keyboardHandleKeymap, @@ -643,9 +520,7 @@ static const struct wl_keyboard_listener keyboardListener = { keyboardHandleLeave, keyboardHandleKey, keyboardHandleModifiers, -#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION keyboardHandleRepeatInfo, -#endif }; static void seatHandleCapabilities(void* data, @@ -798,140 +673,6 @@ static const struct wl_registry_listener registryListener = { registryHandleGlobalRemove }; -// Create key code translation tables -// -static void createKeyTables(void) -{ - int scancode; - - memset(_glfw.wl.keycodes, -1, sizeof(_glfw.wl.keycodes)); - memset(_glfw.wl.scancodes, -1, sizeof(_glfw.wl.scancodes)); - - _glfw.wl.keycodes[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT; - _glfw.wl.keycodes[KEY_1] = GLFW_KEY_1; - _glfw.wl.keycodes[KEY_2] = GLFW_KEY_2; - _glfw.wl.keycodes[KEY_3] = GLFW_KEY_3; - _glfw.wl.keycodes[KEY_4] = GLFW_KEY_4; - _glfw.wl.keycodes[KEY_5] = GLFW_KEY_5; - _glfw.wl.keycodes[KEY_6] = GLFW_KEY_6; - _glfw.wl.keycodes[KEY_7] = GLFW_KEY_7; - _glfw.wl.keycodes[KEY_8] = GLFW_KEY_8; - _glfw.wl.keycodes[KEY_9] = GLFW_KEY_9; - _glfw.wl.keycodes[KEY_0] = GLFW_KEY_0; - _glfw.wl.keycodes[KEY_SPACE] = GLFW_KEY_SPACE; - _glfw.wl.keycodes[KEY_MINUS] = GLFW_KEY_MINUS; - _glfw.wl.keycodes[KEY_EQUAL] = GLFW_KEY_EQUAL; - _glfw.wl.keycodes[KEY_Q] = GLFW_KEY_Q; - _glfw.wl.keycodes[KEY_W] = GLFW_KEY_W; - _glfw.wl.keycodes[KEY_E] = GLFW_KEY_E; - _glfw.wl.keycodes[KEY_R] = GLFW_KEY_R; - _glfw.wl.keycodes[KEY_T] = GLFW_KEY_T; - _glfw.wl.keycodes[KEY_Y] = GLFW_KEY_Y; - _glfw.wl.keycodes[KEY_U] = GLFW_KEY_U; - _glfw.wl.keycodes[KEY_I] = GLFW_KEY_I; - _glfw.wl.keycodes[KEY_O] = GLFW_KEY_O; - _glfw.wl.keycodes[KEY_P] = GLFW_KEY_P; - _glfw.wl.keycodes[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET; - _glfw.wl.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET; - _glfw.wl.keycodes[KEY_A] = GLFW_KEY_A; - _glfw.wl.keycodes[KEY_S] = GLFW_KEY_S; - _glfw.wl.keycodes[KEY_D] = GLFW_KEY_D; - _glfw.wl.keycodes[KEY_F] = GLFW_KEY_F; - _glfw.wl.keycodes[KEY_G] = GLFW_KEY_G; - _glfw.wl.keycodes[KEY_H] = GLFW_KEY_H; - _glfw.wl.keycodes[KEY_J] = GLFW_KEY_J; - _glfw.wl.keycodes[KEY_K] = GLFW_KEY_K; - _glfw.wl.keycodes[KEY_L] = GLFW_KEY_L; - _glfw.wl.keycodes[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON; - _glfw.wl.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE; - _glfw.wl.keycodes[KEY_Z] = GLFW_KEY_Z; - _glfw.wl.keycodes[KEY_X] = GLFW_KEY_X; - _glfw.wl.keycodes[KEY_C] = GLFW_KEY_C; - _glfw.wl.keycodes[KEY_V] = GLFW_KEY_V; - _glfw.wl.keycodes[KEY_B] = GLFW_KEY_B; - _glfw.wl.keycodes[KEY_N] = GLFW_KEY_N; - _glfw.wl.keycodes[KEY_M] = GLFW_KEY_M; - _glfw.wl.keycodes[KEY_COMMA] = GLFW_KEY_COMMA; - _glfw.wl.keycodes[KEY_DOT] = GLFW_KEY_PERIOD; - _glfw.wl.keycodes[KEY_SLASH] = GLFW_KEY_SLASH; - _glfw.wl.keycodes[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH; - _glfw.wl.keycodes[KEY_ESC] = GLFW_KEY_ESCAPE; - _glfw.wl.keycodes[KEY_TAB] = GLFW_KEY_TAB; - _glfw.wl.keycodes[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT; - _glfw.wl.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT; - _glfw.wl.keycodes[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL; - _glfw.wl.keycodes[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL; - _glfw.wl.keycodes[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT; - _glfw.wl.keycodes[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT; - _glfw.wl.keycodes[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER; - _glfw.wl.keycodes[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER; - _glfw.wl.keycodes[KEY_MENU] = GLFW_KEY_MENU; - _glfw.wl.keycodes[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK; - _glfw.wl.keycodes[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK; - _glfw.wl.keycodes[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN; - _glfw.wl.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK; - _glfw.wl.keycodes[KEY_PAUSE] = GLFW_KEY_PAUSE; - _glfw.wl.keycodes[KEY_DELETE] = GLFW_KEY_DELETE; - _glfw.wl.keycodes[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE; - _glfw.wl.keycodes[KEY_ENTER] = GLFW_KEY_ENTER; - _glfw.wl.keycodes[KEY_HOME] = GLFW_KEY_HOME; - _glfw.wl.keycodes[KEY_END] = GLFW_KEY_END; - _glfw.wl.keycodes[KEY_PAGEUP] = GLFW_KEY_PAGE_UP; - _glfw.wl.keycodes[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN; - _glfw.wl.keycodes[KEY_INSERT] = GLFW_KEY_INSERT; - _glfw.wl.keycodes[KEY_LEFT] = GLFW_KEY_LEFT; - _glfw.wl.keycodes[KEY_RIGHT] = GLFW_KEY_RIGHT; - _glfw.wl.keycodes[KEY_DOWN] = GLFW_KEY_DOWN; - _glfw.wl.keycodes[KEY_UP] = GLFW_KEY_UP; - _glfw.wl.keycodes[KEY_F1] = GLFW_KEY_F1; - _glfw.wl.keycodes[KEY_F2] = GLFW_KEY_F2; - _glfw.wl.keycodes[KEY_F3] = GLFW_KEY_F3; - _glfw.wl.keycodes[KEY_F4] = GLFW_KEY_F4; - _glfw.wl.keycodes[KEY_F5] = GLFW_KEY_F5; - _glfw.wl.keycodes[KEY_F6] = GLFW_KEY_F6; - _glfw.wl.keycodes[KEY_F7] = GLFW_KEY_F7; - _glfw.wl.keycodes[KEY_F8] = GLFW_KEY_F8; - _glfw.wl.keycodes[KEY_F9] = GLFW_KEY_F9; - _glfw.wl.keycodes[KEY_F10] = GLFW_KEY_F10; - _glfw.wl.keycodes[KEY_F11] = GLFW_KEY_F11; - _glfw.wl.keycodes[KEY_F12] = GLFW_KEY_F12; - _glfw.wl.keycodes[KEY_F13] = GLFW_KEY_F13; - _glfw.wl.keycodes[KEY_F14] = GLFW_KEY_F14; - _glfw.wl.keycodes[KEY_F15] = GLFW_KEY_F15; - _glfw.wl.keycodes[KEY_F16] = GLFW_KEY_F16; - _glfw.wl.keycodes[KEY_F17] = GLFW_KEY_F17; - _glfw.wl.keycodes[KEY_F18] = GLFW_KEY_F18; - _glfw.wl.keycodes[KEY_F19] = GLFW_KEY_F19; - _glfw.wl.keycodes[KEY_F20] = GLFW_KEY_F20; - _glfw.wl.keycodes[KEY_F21] = GLFW_KEY_F21; - _glfw.wl.keycodes[KEY_F22] = GLFW_KEY_F22; - _glfw.wl.keycodes[KEY_F23] = GLFW_KEY_F23; - _glfw.wl.keycodes[KEY_F24] = GLFW_KEY_F24; - _glfw.wl.keycodes[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE; - _glfw.wl.keycodes[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY; - _glfw.wl.keycodes[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT; - _glfw.wl.keycodes[KEY_KPPLUS] = GLFW_KEY_KP_ADD; - _glfw.wl.keycodes[KEY_KP0] = GLFW_KEY_KP_0; - _glfw.wl.keycodes[KEY_KP1] = GLFW_KEY_KP_1; - _glfw.wl.keycodes[KEY_KP2] = GLFW_KEY_KP_2; - _glfw.wl.keycodes[KEY_KP3] = GLFW_KEY_KP_3; - _glfw.wl.keycodes[KEY_KP4] = GLFW_KEY_KP_4; - _glfw.wl.keycodes[KEY_KP5] = GLFW_KEY_KP_5; - _glfw.wl.keycodes[KEY_KP6] = GLFW_KEY_KP_6; - _glfw.wl.keycodes[KEY_KP7] = GLFW_KEY_KP_7; - _glfw.wl.keycodes[KEY_KP8] = GLFW_KEY_KP_8; - _glfw.wl.keycodes[KEY_KP9] = GLFW_KEY_KP_9; - _glfw.wl.keycodes[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL; - _glfw.wl.keycodes[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL; - _glfw.wl.keycodes[KEY_KPENTER] = GLFW_KEY_KP_ENTER; - - for (scancode = 0; scancode < 256; scancode++) - { - if (_glfw.wl.keycodes[scancode] > 0) - _glfw.wl.scancodes[_glfw.wl.keycodes[scancode]] = scancode; - } -} - ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// @@ -971,53 +712,7 @@ int _glfwPlatformInit(void) _glfw.wl.egl.window_resize = (PFN_wl_egl_window_resize) _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_resize"); - _glfw.wl.xkb.handle = _glfw_dlopen("libxkbcommon.so.0"); - if (!_glfw.wl.xkb.handle) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to open libxkbcommon"); - return GLFW_FALSE; - } - - _glfw.wl.xkb.context_new = (PFN_xkb_context_new) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_new"); - _glfw.wl.xkb.context_unref = (PFN_xkb_context_unref) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_unref"); - _glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string"); - _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref"); - _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index"); - _glfw.wl.xkb.keymap_key_repeats = (PFN_xkb_keymap_key_repeats) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_key_repeats"); - _glfw.wl.xkb.state_new = (PFN_xkb_state_new) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_new"); - _glfw.wl.xkb.state_unref = (PFN_xkb_state_unref) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_unref"); - _glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms"); - _glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask"); - _glfw.wl.xkb.state_serialize_mods = (PFN_xkb_state_serialize_mods) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods"); - -#ifdef HAVE_XKBCOMMON_COMPOSE_H - _glfw.wl.xkb.compose_table_new_from_locale = (PFN_xkb_compose_table_new_from_locale) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale"); - _glfw.wl.xkb.compose_table_unref = (PFN_xkb_compose_table_unref) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref"); - _glfw.wl.xkb.compose_state_new = (PFN_xkb_compose_state_new) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_new"); - _glfw.wl.xkb.compose_state_unref = (PFN_xkb_compose_state_unref) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_unref"); - _glfw.wl.xkb.compose_state_feed = (PFN_xkb_compose_state_feed) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_feed"); - _glfw.wl.xkb.compose_state_get_status = (PFN_xkb_compose_state_get_status) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status"); - _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); -#endif + load_glfw_xkb(); _glfw.wl.display = wl_display_connect(NULL); if (!_glfw.wl.display) @@ -1030,15 +725,7 @@ int _glfwPlatformInit(void) _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display); wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL); - createKeyTables(); - - _glfw.wl.xkb.context = xkb_context_new(0); - if (!_glfw.wl.xkb.context) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to initialize xkb context"); - return GLFW_FALSE; - } + create_glfw_xkb_context(); // Sync so we got all registry objects wl_display_roundtrip(_glfw.wl.display); @@ -1053,10 +740,6 @@ int _glfwPlatformInit(void) _glfwInitTimerPOSIX(); - _glfw.wl.timerfd = -1; - if (_glfw.wl.seatVersion >= 4) - _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); - if (_glfw.wl.pointer && _glfw.wl.shm) { _glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm); @@ -1085,21 +768,7 @@ void _glfwPlatformTerminate(void) _glfw.wl.egl.handle = NULL; } -#ifdef HAVE_XKBCOMMON_COMPOSE_H - if (_glfw.wl.xkb.composeState) - xkb_compose_state_unref(_glfw.wl.xkb.composeState); -#endif - if (_glfw.wl.xkb.keymap) - xkb_keymap_unref(_glfw.wl.xkb.keymap); - if (_glfw.wl.xkb.state) - xkb_state_unref(_glfw.wl.xkb.state); - if (_glfw.wl.xkb.context) - xkb_context_unref(_glfw.wl.xkb.context); - if (_glfw.wl.xkb.handle) - { - _glfw_dlclose(_glfw.wl.xkb.handle); - _glfw.wl.xkb.handle = NULL; - } + release_glfw_xkb(); if (_glfw.wl.cursorTheme) wl_cursor_theme_destroy(_glfw.wl.cursorTheme); @@ -1158,4 +827,3 @@ const char* _glfwPlatformGetVersionString(void) #endif ; } - diff --git a/glfw/wl_platform.h b/glfw/wl_platform.h index ef8419e7b..776196277 100644 --- a/glfw/wl_platform.h +++ b/glfw/wl_platform.h @@ -25,10 +25,6 @@ //======================================================================== #include -#include -#ifdef HAVE_XKBCOMMON_COMPOSE_H -#include -#endif #include typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; @@ -52,6 +48,8 @@ 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" @@ -105,46 +103,6 @@ typedef void (* PFN_wl_egl_window_resize)(struct wl_egl_window*, int, int, int, #define wl_egl_window_destroy _glfw.wl.egl.window_destroy #define wl_egl_window_resize _glfw.wl.egl.window_resize -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.wl.xkb.context_new -#define xkb_context_unref _glfw.wl.xkb.context_unref -#define xkb_keymap_new_from_string _glfw.wl.xkb.keymap_new_from_string -#define xkb_keymap_unref _glfw.wl.xkb.keymap_unref -#define xkb_keymap_mod_get_index _glfw.wl.xkb.keymap_mod_get_index -#define xkb_keymap_key_repeats _glfw.wl.xkb.keymap_key_repeats -#define xkb_state_new _glfw.wl.xkb.state_new -#define xkb_state_unref _glfw.wl.xkb.state_unref -#define xkb_state_key_get_syms _glfw.wl.xkb.state_key_get_syms -#define xkb_state_update_mask _glfw.wl.xkb.state_update_mask -#define xkb_state_serialize_mods _glfw.wl.xkb.state_serialize_mods - -#ifdef HAVE_XKBCOMMON_COMPOSE_H -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.wl.xkb.compose_table_new_from_locale -#define xkb_compose_table_unref _glfw.wl.xkb.compose_table_unref -#define xkb_compose_state_new _glfw.wl.xkb.compose_state_new -#define xkb_compose_state_unref _glfw.wl.xkb.compose_state_unref -#define xkb_compose_state_feed _glfw.wl.xkb.compose_state_feed -#define xkb_compose_state_get_status _glfw.wl.xkb.compose_state_get_status -#define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym -#endif - #define _GLFW_DECORATION_WIDTH 4 #define _GLFW_DECORATION_TOP 24 #define _GLFW_DECORATION_VERTICAL (_GLFW_DECORATION_TOP + _GLFW_DECORATION_WIDTH) @@ -245,52 +203,16 @@ typedef struct _GLFWlibraryWayland int32_t keyboardRepeatRate; int32_t keyboardRepeatDelay; - int keyboardLastKey; - int keyboardLastScancode; - int timerfd; - short int keycodes[256]; - short int scancodes[GLFW_KEY_LAST + 1]; - struct { - void* handle; - struct xkb_context* context; - struct xkb_keymap* keymap; - struct xkb_state* state; - -#ifdef HAVE_XKBCOMMON_COMPOSE_H - struct xkb_compose_state* composeState; -#endif - - xkb_mod_mask_t controlMask; - xkb_mod_mask_t altMask; - xkb_mod_mask_t shiftMask; - xkb_mod_mask_t superMask; - xkb_mod_mask_t capsLockMask; - 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 HAVE_XKBCOMMON_COMPOSE_H - 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; -#endif - } xkb; + long codepoint; + int plain; + int glfwKeyCode; + int scancode; + GLFWbool isFirstRepeat; + double nextRepeatAt; + _GLFWwindow* keyboardFocus; + } keyRepeatInfo; + _GLFWXKBData xkb; _GLFWwindow* pointerFocus; _GLFWwindow* keyboardFocus; @@ -340,4 +262,3 @@ typedef struct _GLFWcursorWayland void _glfwAddOutputWayland(uint32_t name, uint32_t version); - diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 8201560c5..cf1b24e77 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -35,7 +35,6 @@ #include #include #include -#include #include @@ -690,16 +689,35 @@ static GLFWbool createXdgSurface(_GLFWwindow* window) return GLFW_TRUE; } +static void +dispatchPendingKeyRepeats() { + if (_glfw.wl.keyRepeatInfo.nextRepeatAt <= 0 || _glfw.wl.keyRepeatInfo.keyboardFocus != _glfw.wl.keyboardFocus || _glfw.wl.keyboardRepeatRate == 0) return; + double now = glfwGetTime(); + while (_glfw.wl.keyRepeatInfo.nextRepeatAt <= now) { + const int mods = _glfw.wl.xkb.modifiers; + _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); + now = glfwGetTime(); + _glfw.wl.keyRepeatInfo.nextRepeatAt = now + (1.0 / _glfw.wl.keyboardRepeatRate); + _glfw.wl.keyRepeatInfo.isFirstRepeat = GLFW_FALSE; + } +} + +static int +adjustTimeoutForKeyRepeat(int timeout) { + if (_glfw.wl.keyRepeatInfo.nextRepeatAt <= 0 || _glfw.wl.keyRepeatInfo.keyboardFocus != _glfw.wl.keyboardFocus || _glfw.wl.keyboardRepeatRate == 0) return timeout; + double now = glfwGetTime(); + if (timeout < 0 || now + timeout / 1000. > _glfw.wl.keyRepeatInfo.nextRepeatAt) { + timeout = _glfw.wl.keyRepeatInfo.nextRepeatAt <= now ? 0 : ( (_glfw.wl.keyRepeatInfo.nextRepeatAt - now) * 1000 + 1 ); + } + return timeout; +} + static void handleEvents(int timeout) { struct wl_display* display = _glfw.wl.display; - struct pollfd fds[] = { - { wl_display_get_fd(display), POLLIN }, - { _glfw.wl.timerfd, POLLIN }, - }; - ssize_t read_ret; - uint64_t repeats, i; + struct pollfd pfd = { wl_display_get_fd(display), POLLIN }; while (wl_display_prepare_read(display) != 0) wl_display_dispatch_pending(display); @@ -719,9 +737,12 @@ handleEvents(int timeout) return; } - if (poll(fds, 2, timeout) > 0) + dispatchPendingKeyRepeats(); + timeout = adjustTimeoutForKeyRepeat(timeout); + + if (poll(&pfd, 1, timeout) > 0) { - if (fds[0].revents & POLLIN) + if (pfd.revents & POLLIN) { wl_display_read_events(display); wl_display_dispatch_pending(display); @@ -731,22 +752,12 @@ handleEvents(int timeout) wl_display_cancel_read(display); } - if (fds[1].revents & POLLIN) - { - read_ret = read(_glfw.wl.timerfd, &repeats, sizeof(repeats)); - if (read_ret != 8) - return; - - for (i = 0; i < repeats; ++i) - _glfwInputKey(_glfw.wl.keyboardFocus, _glfw.wl.keyboardLastKey, - _glfw.wl.keyboardLastScancode, GLFW_REPEAT, - _glfw.wl.xkb.modifiers); - } } else { wl_display_cancel_read(display); } + dispatchPendingKeyRepeats(); } // Translates a GLFW standard cursor to a theme cursor name @@ -1240,7 +1251,7 @@ const char* _glfwPlatformGetScancodeName(int scancode) int _glfwPlatformGetKeyScancode(int key) { - return _glfw.wl.scancodes[key]; + return _glfw.wl.xkb.scancodes[key]; } int _glfwPlatformCreateCursor(_GLFWcursor* cursor, diff --git a/glfw/xkb_glfw.h b/glfw/xkb_glfw.h new file mode 100644 index 000000000..ac9882322 --- /dev/null +++ b/glfw/xkb_glfw.h @@ -0,0 +1,374 @@ +//======================================================================== +// GLFW 3.3 XKB - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 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. +// +//======================================================================== + +#pragma once + +#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 + + +typedef struct { + void* handle; + struct xkb_context* context; + struct xkb_keymap* keymap; + struct xkb_state* 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; + xkb_mod_mask_t shiftMask; + xkb_mod_mask_t superMask; + xkb_mod_mask_t capsLockMask; + 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; + + 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); \ +} + +#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) {\ + 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)