diff --git a/src/wl_init.c b/src/wl_init.c index 57ebfe1a..fa2d4ba1 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -691,7 +691,13 @@ int _glfwInitWayland(void) _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref) _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_unref"); _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index) - _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index"); + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index"); + _glfw.wl.xkb.keymap_mod_get_mask2 = (PFN_xkb_keymap_mod_get_mask2) + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_mask2"); + _glfw.wl.xkb.keymap_key_get_mods_for_level = (PFN_xkb_keymap_key_get_mods_for_level) + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_key_get_mods_for_level"); + _glfw.wl.xkb.keymap_num_levels_for_key = (PFN_xkb_keymap_num_levels_for_key) + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_num_levels_for_key"); _glfw.wl.xkb.keymap_key_repeats = (PFN_xkb_keymap_key_repeats) _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_key_repeats"); _glfw.wl.xkb.keymap_key_get_syms_by_level = (PFN_xkb_keymap_key_get_syms_by_level) diff --git a/src/wl_platform.h b/src/wl_platform.h index a77cc336..81f4db64 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -185,6 +185,9 @@ 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 xkb_mod_mask_t (* PFN_xkb_keymap_mod_get_mask2)(struct xkb_keymap*, const xkb_mod_index_t); +typedef xkb_level_index_t (* PFN_xkb_keymap_num_levels_for_key)(struct xkb_keymap*, const xkb_keycode_t, const xkb_layout_index_t); +typedef size_t (* PFN_xkb_keymap_key_get_mods_for_level)(struct xkb_keymap*, const xkb_keycode_t, const xkb_layout_index_t, const xkb_level_index_t, xkb_mod_mask_t *, const size_t); typedef int (* PFN_xkb_keymap_key_repeats)(struct xkb_keymap*, xkb_keycode_t); typedef int (* PFN_xkb_keymap_key_get_syms_by_level)(struct xkb_keymap*,xkb_keycode_t,xkb_layout_index_t,xkb_level_index_t,const xkb_keysym_t**); typedef struct xkb_state* (* PFN_xkb_state_new)(struct xkb_keymap*); @@ -200,6 +203,9 @@ typedef int (* PFN_xkb_keysym_to_utf8)(xkb_keysym_t, char*, size_t); #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_mod_get_mask2 _glfw.wl.xkb.keymap_mod_get_mask2 +#define xkb_keymap_num_levels_for_key _glfw.wl.xkb.keymap_num_levels_for_key +#define xkb_keymap_key_get_mods_for_level _glfw.wl.xkb.keymap_key_get_mods_for_level #define xkb_keymap_key_repeats _glfw.wl.xkb.keymap_key_repeats #define xkb_keymap_key_get_syms_by_level _glfw.wl.xkb.keymap_key_get_syms_by_level #define xkb_state_new _glfw.wl.xkb.state_new @@ -524,8 +530,11 @@ typedef struct _GLFWlibraryWayland 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_mod_get_mask2 keymap_mod_get_mask2; PFN_xkb_keymap_key_repeats keymap_key_repeats; PFN_xkb_keymap_key_get_syms_by_level keymap_key_get_syms_by_level; + PFN_xkb_keymap_num_levels_for_key keymap_num_levels_for_key; + PFN_xkb_keymap_key_get_mods_for_level keymap_key_get_mods_for_level; PFN_xkb_state_new state_new; PFN_xkb_state_unref state_unref; PFN_xkb_state_key_get_syms state_key_get_syms; diff --git a/src/wl_window.c b/src/wl_window.c index e4beec68..9f809d44 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -2978,6 +2978,28 @@ void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode) _glfwSetCursorWayland(window, window->cursor); } +// Translates an xkb modifier state mask +// +static xkb_mod_mask_t translateStateInverse(int mods) +{ + xkb_mod_mask_t mask = 0; + + if (mods & GLFW_MOD_SHIFT) + mask |= xkb_keymap_mod_get_mask2(_glfw.wl.xkb.keymap, _glfw.wl.xkb.shiftIndex); + if (mods & GLFW_MOD_CONTROL) + mask |= xkb_keymap_mod_get_mask2(_glfw.wl.xkb.keymap, _glfw.wl.xkb.controlIndex); + if (mods & GLFW_MOD_ALT) + mask |= xkb_keymap_mod_get_mask2(_glfw.wl.xkb.keymap, _glfw.wl.xkb.altIndex); + if (mods & GLFW_MOD_SUPER) + mask |= xkb_keymap_mod_get_mask2(_glfw.wl.xkb.keymap, _glfw.wl.xkb.superIndex); + if (mods & GLFW_MOD_CAPS_LOCK) + mask |= xkb_keymap_mod_get_mask2(_glfw.wl.xkb.keymap, _glfw.wl.xkb.capsLockIndex); + if (mods & GLFW_MOD_NUM_LOCK) + mask |= xkb_keymap_mod_get_mask2(_glfw.wl.xkb.keymap, _glfw.wl.xkb.numLockIndex); + + return mask; +} + const char* _glfwGetScancodeNameWayland(int scancode, int modifiers) { if (scancode < 0 || scancode > 255) @@ -3002,14 +3024,44 @@ const char* _glfwGetScancodeNameWayland(int scancode, int modifiers) return NULL; } - // FIXME: can't seem to find any way in libxkbcommon to translate an xkb_mod_mask_t into - // a xkb_level_index_t . Sigh. - int level = (modifiers & GLFW_MOD_SHIFT)? 1 : 0; + xkb_level_index_t found_level = 0; + if (0 < modifiers) + { + // Figure out the corresponding level set for the modifier set + // that the user requested. This involves a relatively annoying + // loop of trying things out. Could cache this information if + // lookup speed is of concern. + xkb_mod_mask_t mask = translateStateInverse(modifiers); + const int num_levels = xkb_keymap_num_levels_for_key(_glfw.wl.xkb.keymap, + keycode, + layout); + xkb_level_index_t level; + for (level = 0; level < num_levels && found_level == 0; ++level) + { + size_t num_masks; + xkb_mod_mask_t masks[128]; + num_masks = xkb_keymap_key_get_mods_for_level(_glfw.wl.xkb.keymap, + keycode, + layout, + level, + masks, + 128); + for (int i=0; i < num_masks; ++i) + { + if ((masks[i] & mask) == mask) + { + found_level = level; + break; + } + } + } + } + const xkb_keysym_t* keysyms = NULL; xkb_keymap_key_get_syms_by_level(_glfw.wl.xkb.keymap, keycode, layout, - level, + found_level, &keysyms); if (keysyms == NULL) {