diff --git a/src/wl_init.c b/src/wl_init.c index 4627c599..e61f72f7 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -172,7 +172,10 @@ static void keyboardHandleKeymap(void* data, { struct xkb_keymap* keymap; struct xkb_state* state; + struct xkb_compose_table* composeTable; + struct xkb_compose_state* composeState; char* mapStr; + const char* locale; if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { @@ -209,6 +212,35 @@ static void keyboardHandleKeymap(void* data, 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"; + + 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"); + } + xkb_keymap_unref(_glfw.wl.xkb.keymap); xkb_state_unref(_glfw.wl.xkb.state); _glfw.wl.xkb.keymap = keymap; @@ -258,18 +290,40 @@ static int toGLFWKeyCode(uint32_t key) return GLFW_KEY_UNKNOWN; } +static xkb_keysym_t composeSymbol(xkb_keysym_t sym) +{ + if (sym == XKB_KEY_NoSymbol) + 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) { 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); if (numSyms == 1) { - cp = _glfwKeySym2Unicode(syms[0]); + sym = composeSymbol(syms[0]); + cp = _glfwKeySym2Unicode(sym); if (cp != -1) { const int mods = _glfw.wl.xkb.modifiers; @@ -645,6 +699,7 @@ void _glfwPlatformTerminate(void) _glfwTerminateJoysticksLinux(); _glfwTerminateThreadLocalStoragePOSIX(); + xkb_compose_state_unref(_glfw.wl.xkb.composeState); xkb_keymap_unref(_glfw.wl.xkb.keymap); xkb_state_unref(_glfw.wl.xkb.state); xkb_context_unref(_glfw.wl.xkb.context); diff --git a/src/wl_platform.h b/src/wl_platform.h index f60626e2..209f7bca 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -29,6 +29,7 @@ #include #include +#include #include typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; @@ -136,6 +137,7 @@ typedef struct _GLFWlibraryWayland struct xkb_context* context; struct xkb_keymap* keymap; struct xkb_state* state; + struct xkb_compose_state* composeState; xkb_mod_mask_t controlMask; xkb_mod_mask_t altMask; xkb_mod_mask_t shiftMask;