diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 1371aedb..700b2108 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -37,6 +37,7 @@ video tutorials. - Chi-kwan Chan - Victor Chernyakin - TheChocolateOre + - Виктор Чернякин - Ali Chraghi - Joseph Chua - Ian Clarkson diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 463b898d..244a073a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,8 +52,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..dbe05dc6 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,21 @@ const char* _glfwGetScancodeNameWayland(int scancode) return NULL; } - const uint32_t codepoint = _glfwKeySym2Unicode(keysyms[0]); - if (codepoint == GLFW_INVALID_CODEPOINT) + // HACK: 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 lie to the function about the buffer + // size, because we know it won't use more than 5 bytes. + // + // See: https://github.com/xkbcommon/libxkbcommon/issues/418 + if (xkb_keysym_to_utf8(keysyms[0], _glfw.wl.keynames[key], 7) <= 0) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to retrieve codepoint for key name"); + "Wayland: Failed to encode keysym as UTF-8"); return NULL; } - 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]; }