2
0
Эх сурвалжийг харах

Wayland: Implement compose key for character input

This commit has been copied almost verbatim from Bryce Harrington’s
patch against Weston’s toytoolkit[1].  He gave his agreement to
relicense it under zlib[2].

[1] https://patchwork.freedesktop.org/patch/114661/
[2] https://github.com/glfw/glfw/pull/879#issuecomment-252988257
Emmanuel Gil Peyrot 9 жил өмнө
parent
commit
046d281abc
2 өөрчлөгдсөн 58 нэмэгдсэн , 1 устгасан
  1. 56 1
      src/wl_init.c
  2. 2 0
      src/wl_platform.h

+ 56 - 1
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);

+ 2 - 0
src/wl_platform.h

@@ -29,6 +29,7 @@
 
 #include <wayland-client.h>
 #include <xkbcommon/xkbcommon.h>
+#include <xkbcommon/xkbcommon-compose.h>
 #include <dlfcn.h>
 
 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;