fix(xim): honor reset and X11 keyboard state

This commit is contained in:
2026-08-14 22:34:37 +09:00
parent 9804c1f55c
commit a637f457f7
10 changed files with 394 additions and 258 deletions

View File

@@ -1,37 +1,38 @@
#include <stdint.h>
#include <xcb/xcb.h>
#include <xkbcommon/xkbcommon.h>
enum
{
ShiftMask = 1<<0,
LockMask = 1<<1,
GroupShift = 13,
GroupMask = 3,
};
#include <xkbcommon/xkbcommon-names.h>
uint32_t
keymaplookup(const uint32_t *syms, int nsyms, uint16_t state)
keymaplookup(struct xkb_state *state, uint8_t keycode, uint16_t corestate)
{
uint32_t lo, hi, lower, upper;
int col, group, shift;
static const char *modname[] = {
XKB_MOD_NAME_SHIFT,
XKB_MOD_NAME_CAPS,
XKB_MOD_NAME_CTRL,
XKB_MOD_NAME_MOD1,
XKB_MOD_NAME_MOD2,
XKB_MOD_NAME_MOD3,
XKB_MOD_NAME_MOD4,
XKB_MOD_NAME_MOD5,
};
struct xkb_keymap *keymap;
xkb_mod_index_t index;
xkb_mod_mask_t mods;
int i;
if(syms == NULL || nsyms <= 0)
if(state == NULL)
return XKB_KEY_NoSymbol;
group = (state >> GroupShift) & GroupMask;
col = group * 2;
if(col >= nsyms || syms[col] == XKB_KEY_NoSymbol)
col = 0;
lo = syms[col];
if(lo == XKB_KEY_NoSymbol)
return XKB_KEY_NoSymbol;
hi = col + 1 < nsyms ? syms[col + 1] : XKB_KEY_NoSymbol;
lower = xkb_keysym_to_lower(lo);
upper = xkb_keysym_to_upper(lo);
if(hi == XKB_KEY_NoSymbol)
hi = lower != upper ? upper : lo;
shift = (state & ShiftMask) != 0;
/* Lock reverses Shift only for keys with an alphabetic case pair. */
if((state & LockMask) && lower != upper)
shift = !shift;
return shift ? hi : lo;
keymap = xkb_state_get_keymap(state);
mods = 0;
for(i = 0; i < (int)(sizeof modname / sizeof modname[0]); i++){
if(!(corestate & (1U << i)))
continue;
index = xkb_keymap_mod_get_index(keymap, modname[i]);
if(index != XKB_MOD_INVALID && index < 8 * sizeof mods)
mods |= (xkb_mod_mask_t)1 << index;
}
xkb_state_update_mask(state, mods, 0, 0, 0, 0,
(corestate >> 13) & 3);
return xkb_state_key_get_one_sym(state, keycode);
}