From 21fea01161e0d6b70c0c5c1f52dc8e7a7df14a50 Mon Sep 17 00:00:00 2001 From: LocalSpook Date: Sun, 10 Dec 2023 05:54:11 -0700 Subject: [PATCH] Wayland: Replace _glfwKeySym2Unicode with xkbcommon libxkbcommon already provides functions to convert keysyms to codepoints and UTF-8. The library has offered these functions since 0.5.0[1], so using them won't cause any compatibility problems. [1] https://xkbcommon.org/doc/0.5.0/group__keysyms.html Closes #2444 --- src/CMakeLists.txt | 4 ++-- src/wl_init.c | 4 ++++ src/wl_platform.h | 7 ++++++- src/wl_window.c | 28 ++++++++++++++-------------- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fc4e17cf..1a085b2b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,8 +53,8 @@ endif() if (GLFW_BUILD_WAYLAND) target_compile_definitions(glfw PRIVATE _GLFW_WAYLAND) - target_sources(glfw PRIVATE wl_platform.h xkb_unicode.h wl_init.c - wl_monitor.c wl_window.c xkb_unicode.c) + target_sources(glfw PRIVATE wl_platform.h wl_init.c + wl_monitor.c wl_window.c) endif() if (GLFW_BUILD_X11 OR GLFW_BUILD_WAYLAND) diff --git a/src/wl_init.c b/src/wl_init.c index 76054bc6..ef9e4503 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -711,6 +711,10 @@ int _glfwInitWayland(void) _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_get_status"); _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym) _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); + _glfw.wl.xkb.keysym_to_utf32 = (PFN_xkb_keysym_to_utf32) + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keysym_to_utf32"); + _glfw.wl.xkb.keysym_to_utf8 = (PFN_xkb_keysym_to_utf8) + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keysym_to_utf8"); if (!_glfw.wl.xkb.context_new || !_glfw.wl.xkb.context_unref || diff --git a/src/wl_platform.h b/src/wl_platform.h index f3e8cba2..afa6f50a 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -42,7 +42,6 @@ typedef struct VkWaylandSurfaceCreateInfoKHR typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWaylandSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*); -#include "xkb_unicode.h" #include "posix_poll.h" typedef int (* PFN_wl_display_flush)(struct wl_display* display); @@ -178,6 +177,8 @@ typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, con 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_layout_index_t (* PFN_xkb_state_key_get_layout)(struct xkb_state*,xkb_keycode_t); typedef int (* PFN_xkb_state_mod_index_is_active)(struct xkb_state*,xkb_mod_index_t,enum xkb_state_component); +typedef uint32_t (* PFN_xkb_keysym_to_utf32)(xkb_keysym_t); +typedef int (* PFN_xkb_keysym_to_utf8)(xkb_keysym_t, char*, size_t); #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 @@ -191,6 +192,8 @@ typedef int (* PFN_xkb_state_mod_index_is_active)(struct xkb_state*,xkb_mod_inde #define xkb_state_update_mask _glfw.wl.xkb.state_update_mask #define xkb_state_key_get_layout _glfw.wl.xkb.state_key_get_layout #define xkb_state_mod_index_is_active _glfw.wl.xkb.state_mod_index_is_active +#define xkb_keysym_to_utf32 _glfw.wl.xkb.keysym_to_utf32 +#define xkb_keysym_to_utf8 _glfw.wl.xkb.keysym_to_utf8 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*); @@ -495,6 +498,8 @@ typedef struct _GLFWlibraryWayland PFN_xkb_state_update_mask state_update_mask; PFN_xkb_state_key_get_layout state_key_get_layout; PFN_xkb_state_mod_index_is_active state_mod_index_is_active; + PFN_xkb_keysym_to_utf32 keysym_to_utf32; + PFN_xkb_keysym_to_utf8 keysym_to_utf8; PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale; PFN_xkb_compose_table_unref compose_table_unref; diff --git a/src/wl_window.c b/src/wl_window.c index 2e842aaa..72c1a402 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1192,8 +1192,8 @@ static void inputText(_GLFWwindow* window, uint32_t scancode) if (xkb_state_key_get_syms(_glfw.wl.xkb.state, keycode, &keysyms) == 1) { const xkb_keysym_t keysym = composeSymbol(keysyms[0]); - const uint32_t codepoint = _glfwKeySym2Unicode(keysym); - if (codepoint != GLFW_INVALID_CODEPOINT) + const uint32_t codepoint = xkb_keysym_to_utf32(keysym); + if (codepoint != 0) { const int mods = _glfw.wl.xkb.modifiers; const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); @@ -2721,23 +2721,23 @@ const char* _glfwGetScancodeNameWayland(int scancode) return NULL; } - const uint32_t codepoint = _glfwKeySym2Unicode(keysyms[0]); - if (codepoint == GLFW_INVALID_CODEPOINT) + // WORKAROUND: xkb_keysym_to_utf8() requires the third parameter (size of the output buffer) + // to be at least 7 (6 bytes + a null terminator), because it was written when UTF-8 + // sequences could be up to 6 bytes long. The _glfw.wl.keynames buffers are only 5 bytes + // long, because UTF-8 sequences are now limited to 4 bytes and no codepoints were ever assigned + // that needed more than that. To work around this, we first copy to a temporary buffer. + // + // See: https://github.com/xkbcommon/libxkbcommon/issues/418 + char temp_buffer[7]; + const int bytes_written = xkb_keysym_to_utf8(keysyms[0], temp_buffer, sizeof(temp_buffer)); + if (bytes_written <= 0 || bytes_written > 5) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to retrieve codepoint for key name"); + "Wayland: Failed to encode keysym as UTF-8"); return NULL; } + memcpy(_glfw.wl.keynames[key], temp_buffer, bytes_written); - const size_t count = _glfwEncodeUTF8(_glfw.wl.keynames[key], codepoint); - if (count == 0) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to encode codepoint for key name"); - return NULL; - } - - _glfw.wl.keynames[key][count] = '\0'; return _glfw.wl.keynames[key]; }