Possible fix for handling unknown modifiers on Xkb systems

This commit is contained in:
Kovid Goyal 2018-03-30 23:43:07 +05:30
parent b59d7dda11
commit 677c47b9dd
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 65 additions and 18 deletions

75
glfw/xkb_glfw.c vendored
View File

@ -258,30 +258,44 @@ glfw_xkb_compile_keymap(_GLFWXKBData *xkb, const char *map_str) {
xkb->clean_state = clean_state; xkb->clean_state = clean_state;
} }
if (xkb->keymap) { if (xkb->keymap) {
xkb->controlMask = 1 << xkb_keymap_mod_get_index(xkb->keymap, "Control"); #define S(a, n) xkb->a##Idx = xkb_keymap_mod_get_index(xkb->keymap, n); xkb->a##Mask = 1 << xkb->a##Idx;
xkb->altMask = 1 << xkb_keymap_mod_get_index(xkb->keymap, "Mod1"); S(control, XKB_MOD_NAME_CTRL);
xkb->shiftMask = 1 << xkb_keymap_mod_get_index(xkb->keymap, "Shift"); S(alt, XKB_MOD_NAME_ALT);
xkb->superMask = 1 << xkb_keymap_mod_get_index(xkb->keymap, "Mod4"); S(shift, XKB_MOD_NAME_SHIFT);
xkb->capsLockMask = 1 << xkb_keymap_mod_get_index(xkb->keymap, "Lock"); S(super, XKB_MOD_NAME_LOGO);
xkb->numLockMask = 1 << xkb_keymap_mod_get_index(xkb->keymap, "Mod2"); S(capsLock, XKB_MOD_NAME_CAPS);
S(numLock, XKB_MOD_NAME_NUM);
size_t capacity = sizeof(xkb->unknownModifiers)/sizeof(xkb->unknownModifiers[0]), j = 0;
for (xkb_mod_index_t i = 0; i < capacity; i++) xkb->unknownModifiers[i] = XKB_MOD_INVALID;
for (xkb_mod_index_t i = 0; i < xkb_keymap_num_mods(xkb->keymap) && j < capacity - 1; i++) {
if (i != xkb->controlIdx && i != xkb->altIdx && i != xkb->shiftIdx && i != xkb->superIdx && i != xkb->capsLockIdx && i != xkb->numLockIdx) xkb->unknownModifiers[j++] = i;
}
#undef S
} }
return GLFW_TRUE; return GLFW_TRUE;
} }
static inline xkb_mod_mask_t
active_unknown_modifiers(_GLFWXKBData *xkb) {
size_t i = 0;
xkb_mod_mask_t ans = 0;
while (xkb->unknownModifiers[i] != XKB_MOD_INVALID) {
if (xkb_state_mod_index_is_active(xkb->state, xkb->unknownModifiers[i], XKB_STATE_MODS_EFFECTIVE)) ans |= (1 << xkb->unknownModifiers[i]);
i++;
}
return ans;
}
void void
glfw_xkb_update_modifiers(_GLFWXKBData *xkb, unsigned int depressed, unsigned int latched, unsigned int locked, unsigned int group) { glfw_xkb_update_modifiers(_GLFWXKBData *xkb, unsigned int depressed, unsigned int latched, unsigned int locked, unsigned int group) {
xkb_mod_mask_t mask;
unsigned int modifiers = 0;
if (!xkb->keymap) return; if (!xkb->keymap) return;
xkb->modifiers = 0;
xkb_state_update_mask(xkb->state, depressed, latched, locked, 0, 0, group); xkb_state_update_mask(xkb->state, depressed, latched, locked, 0, 0, group);
mask = xkb_state_serialize_mods(xkb->state, XKB_STATE_MODS_DEPRESSED | XKB_STATE_LAYOUT_DEPRESSED | XKB_STATE_MODS_LATCHED | XKB_STATE_LAYOUT_LATCHED); #define S(attr, name) if (xkb_state_mod_index_is_active(xkb->state, xkb->attr##Idx, XKB_STATE_MODS_EFFECTIVE)) xkb->modifiers |= GLFW_MOD_##name
if (mask & xkb->controlMask) modifiers |= GLFW_MOD_CONTROL; S(control, CONTROL); S(alt, ALT); S(shift, SHIFT); S(super, SUPER); S(capsLock, CAPS_LOCK); S(numLock, NUM_LOCK);
if (mask & xkb->altMask) modifiers |= GLFW_MOD_ALT; #undef S
if (mask & xkb->shiftMask) modifiers |= GLFW_MOD_SHIFT; xkb->activeUnknownModifiers = active_unknown_modifiers(xkb);
if (mask & xkb->superMask) modifiers |= GLFW_MOD_SUPER;
if (mask & xkb->capsLockMask) modifiers |= GLFW_MOD_CAPS_LOCK;
if (mask & xkb->numLockMask) modifiers |= GLFW_MOD_NUM_LOCK;
xkb->modifiers = modifiers;
} }
GLFWbool GLFWbool
@ -326,7 +340,7 @@ static inline const char*
format_mods(unsigned int mods) { format_mods(unsigned int mods) {
static char buf[128]; static char buf[128];
char *p = buf, *s; char *p = buf, *s;
#define pr(x) p += snprintf(p, sizeof(buf) - (p - buf) - 1, x) #define pr(x) p += snprintf(p, sizeof(buf) - (p - buf) - 1, "%s", x)
pr("mods: "); pr("mods: ");
s = p; s = p;
if (mods & GLFW_MOD_CONTROL) pr("ctrl+"); if (mods & GLFW_MOD_CONTROL) pr("ctrl+");
@ -342,6 +356,24 @@ format_mods(unsigned int mods) {
return buf; return buf;
} }
static inline const char*
format_xkb_mods(_GLFWXKBData *xkb, const char* name, xkb_mod_mask_t mods) {
static char buf[512];
char *p = buf, *s;
#define pr(x) p += snprintf(p, sizeof(buf) - (p - buf) - 1, "%s", x)
pr(name); pr(": ");
s = p;
for (xkb_mod_index_t i = 0; i < xkb_keymap_num_mods(xkb->keymap); i++) {
xkb_mod_mask_t m = 1 << i;
if (m & mods) { pr(xkb_keymap_mod_get_name(xkb->keymap, i)); pr("+"); }
}
if (p == s) pr("none");
else p--;
pr(" ");
#undef pr
return buf;
}
void void
glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t scancode, int action) { glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t scancode, int action) {
const xkb_keysym_t *syms, *clean_syms; const xkb_keysym_t *syms, *clean_syms;
@ -371,7 +403,14 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
} }
debug("composed_sym: %s ", glfw_xkb_keysym_name(glfw_sym)); debug("composed_sym: %s ", glfw_xkb_keysym_name(glfw_sym));
if (glfw_sym == syms[0]) { // composed sym is the same as non-composed sym if (glfw_sym == syms[0]) { // composed sym is the same as non-composed sym
glfw_sym = clean_syms[0]; // Only use the clean_sym if the mods other than the mods we report
// are active (for example if ISO_Shift_Level_* mods are pressed
// they are not reported by GLFW so the key should be the shifted
// key). See https://github.com/kovidgoyal/kitty/issues/171#issuecomment-377557053
xkb_mod_mask_t consumed_unknown_mods = xkb_state_key_get_consumed_mods(xkb->state, code_for_sym) & xkb->activeUnknownModifiers;
if (xkb->activeUnknownModifiers) debug("%s", format_xkb_mods(xkb, "active_unknown_mods", xkb->activeUnknownModifiers));
if (consumed_unknown_mods) { debug("%s", format_xkb_mods(xkb, "consumed_unknown_mods", consumed_unknown_mods)); }
else glfw_sym = clean_syms[0];
// xkb returns text even if alt and/or super are pressed // xkb returns text even if alt and/or super are pressed
if ( ((GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER) & xkb->modifiers) == 0) xkb_state_key_get_utf8(xkb->state, code_for_sym, text, sizeof(text)); if ( ((GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER) & xkb->modifiers) == 0) xkb_state_key_get_utf8(xkb->state, code_for_sym, text, sizeof(text));
text_type = "text"; text_type = "text";

8
glfw/xkb_glfw.h vendored
View File

@ -39,13 +39,21 @@ typedef struct {
struct xkb_state* clean_state; struct xkb_state* clean_state;
struct xkb_compose_state* composeState; struct xkb_compose_state* composeState;
xkb_mod_index_t controlIdx;
xkb_mod_index_t altIdx;
xkb_mod_index_t shiftIdx;
xkb_mod_index_t superIdx;
xkb_mod_index_t capsLockIdx;
xkb_mod_index_t numLockIdx;
xkb_mod_mask_t controlMask; xkb_mod_mask_t controlMask;
xkb_mod_mask_t altMask; xkb_mod_mask_t altMask;
xkb_mod_mask_t shiftMask; xkb_mod_mask_t shiftMask;
xkb_mod_mask_t superMask; xkb_mod_mask_t superMask;
xkb_mod_mask_t capsLockMask; xkb_mod_mask_t capsLockMask;
xkb_mod_mask_t numLockMask; xkb_mod_mask_t numLockMask;
xkb_mod_mask_t activeUnknownModifiers;
unsigned int modifiers; unsigned int modifiers;
xkb_mod_index_t unknownModifiers[256];
#ifdef _GLFW_X11 #ifdef _GLFW_X11
int32_t keyboard_device_id; int32_t keyboard_device_id;