diff options
author | Gatis Paeglis <gatis.paeglis@digia.com> | 2014-03-28 16:22:14 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-04-03 14:20:19 +0200 |
commit | bd40a7cc446cafb8c9922d7d19845da580868859 (patch) | |
tree | 966292563ebe2541ee6129c0d9ce42409f4a24fe /src/3rdparty/xkbcommon/src/state.c | |
parent | 151cf2047aa36ac395a841a3ced8b2142a997aec (diff) |
Update bundled libxkbcommon version to 0.4.1
This is the latest version, released on Mar 27 2014. It includes:
https://bugs.freedesktop.org/show_bug.cgi?id=75798
https://bugs.freedesktop.org/show_bug.cgi?id=75892
Required for fixing input when running Qt application on Mac OS X
with XQuartz and for fixing QTBUG-36281.
Change-Id: Idc4d3c99a4008a10b91ab51c8910b36909974703
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/3rdparty/xkbcommon/src/state.c')
-rw-r--r-- | src/3rdparty/xkbcommon/src/state.c | 308 |
1 files changed, 252 insertions, 56 deletions
diff --git a/src/3rdparty/xkbcommon/src/state.c b/src/3rdparty/xkbcommon/src/state.c index 768d47c182..0f9ea79264 100644 --- a/src/3rdparty/xkbcommon/src/state.c +++ b/src/3rdparty/xkbcommon/src/state.c @@ -61,6 +61,7 @@ #include "keymap.h" #include "keysym.h" +#include "utf8.h" struct xkb_filter { union xkb_action action; @@ -108,7 +109,7 @@ struct xkb_state { * < Left Shift down, Right Shift down, Left Shift Up > * the modifier should still be set. This keeps the count. */ - int16_t mod_key_count[sizeof(xkb_mod_mask_t) * 8]; + int16_t mod_key_count[XKB_MAX_MODS]; int refcnt; darray(struct xkb_filter) filters; @@ -121,9 +122,8 @@ get_entry_for_key_state(struct xkb_state *state, const struct xkb_key *key, { const struct xkb_key_type *type = key->groups[group].type; xkb_mod_mask_t active_mods = state->components.mods & type->mods.mask; - unsigned int i; - for (i = 0; i < type->num_entries; i++) { + for (unsigned i = 0; i < type->num_entries; i++) { /* * If the virtual modifiers are not bound to anything, we're * supposed to skip the entry (xserver does this with cached @@ -170,7 +170,7 @@ wrap_group_into_range(int32_t group, if (num_groups == 0) return XKB_LAYOUT_INVALID; - if (group < num_groups) + if (group >= 0 && (xkb_layout_index_t) group < num_groups) return group; switch (out_of_range_group_action) { @@ -623,30 +623,42 @@ xkb_state_led_update_all(struct xkb_state *state) xkb_mod_mask_t mod_mask = 0; xkb_layout_mask_t group_mask = 0; - if (led->which_mods & XKB_STATE_MODS_EFFECTIVE) - mod_mask |= state->components.mods; - if (led->which_mods & XKB_STATE_MODS_DEPRESSED) - mod_mask |= state->components.base_mods; - if (led->which_mods & XKB_STATE_MODS_LATCHED) - mod_mask |= state->components.latched_mods; - if (led->which_mods & XKB_STATE_MODS_LOCKED) - mod_mask |= state->components.locked_mods; - if (led->mods.mask & mod_mask) - state->components.leds |= (1 << idx); - - if (led->which_groups & XKB_STATE_LAYOUT_EFFECTIVE) - group_mask |= (1 << state->components.group); - if (led->which_groups & XKB_STATE_LAYOUT_DEPRESSED) - group_mask |= (1 << state->components.base_group); - if (led->which_groups & XKB_STATE_LAYOUT_LATCHED) - group_mask |= (1 << state->components.latched_group); - if (led->which_groups & XKB_STATE_LAYOUT_LOCKED) - group_mask |= (1 << state->components.locked_group); - if (led->groups & group_mask) - state->components.leds |= (1 << idx); - - if (led->ctrls & state->keymap->enabled_ctrls) - state->components.leds |= (1 << idx); + if (led->which_mods != 0 && led->mods.mask != 0) { + if (led->which_mods & XKB_STATE_MODS_EFFECTIVE) + mod_mask |= state->components.mods; + if (led->which_mods & XKB_STATE_MODS_DEPRESSED) + mod_mask |= state->components.base_mods; + if (led->which_mods & XKB_STATE_MODS_LATCHED) + mod_mask |= state->components.latched_mods; + if (led->which_mods & XKB_STATE_MODS_LOCKED) + mod_mask |= state->components.locked_mods; + + if (led->mods.mask & mod_mask) { + state->components.leds |= (1u << idx); + continue; + } + } + + if (led->which_groups != 0 && led->groups != 0) { + if (led->which_groups & XKB_STATE_LAYOUT_EFFECTIVE) + group_mask |= (1u << state->components.group); + if (led->which_groups & XKB_STATE_LAYOUT_DEPRESSED) + group_mask |= (1u << state->components.base_group); + if (led->which_groups & XKB_STATE_LAYOUT_LATCHED) + group_mask |= (1u << state->components.latched_group); + if (led->which_groups & XKB_STATE_LAYOUT_LOCKED) + group_mask |= (1u << state->components.locked_group); + + if (led->groups & group_mask) { + state->components.leds |= (1u << idx); + continue; + } + } + + if (led->ctrls & state->keymap->enabled_ctrls) { + state->components.leds |= (1u << idx); + continue; + } } } @@ -657,23 +669,27 @@ xkb_state_led_update_all(struct xkb_state *state) static void xkb_state_update_derived(struct xkb_state *state) { + xkb_layout_index_t wrapped; + state->components.mods = (state->components.base_mods | state->components.latched_mods | state->components.locked_mods); /* TODO: Use groups_wrap control instead of always RANGE_WRAP. */ + wrapped = wrap_group_into_range(state->components.locked_group, + state->keymap->num_groups, + RANGE_WRAP, 0); state->components.locked_group = - wrap_group_into_range(state->components.locked_group, - state->keymap->num_groups, - RANGE_WRAP, 0); + (wrapped == XKB_LAYOUT_INVALID ? 0 : wrapped); + wrapped = wrap_group_into_range(state->components.base_group + + state->components.latched_group + + state->components.locked_group, + state->keymap->num_groups, + RANGE_WRAP, 0); state->components.group = - wrap_group_into_range(state->components.base_group + - state->components.latched_group + - state->components.locked_group, - state->keymap->num_groups, - RANGE_WRAP, 0); + (wrapped == XKB_LAYOUT_INVALID ? 0 : wrapped); xkb_state_led_update_all(state); } @@ -781,7 +797,7 @@ xkb_state_update_mask(struct xkb_state *state, num_mods = xkb_keymap_num_mods(state->keymap); for (idx = 0; idx < num_mods; idx++) { - xkb_mod_mask_t mod = (1 << idx); + xkb_mod_mask_t mod = (1u << idx); if (base_mods & mod) state->components.base_mods |= mod; if (latched_mods & mod) @@ -826,6 +842,53 @@ err: return 0; } +/* + * http://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Lock_Modifier + */ +static bool +should_do_caps_transformation(struct xkb_state *state, xkb_keycode_t kc) +{ + xkb_mod_index_t caps = + xkb_keymap_mod_get_index(state->keymap, XKB_MOD_NAME_CAPS); + + return + xkb_state_mod_index_is_active(state, caps, XKB_STATE_MODS_EFFECTIVE) > 0 && + xkb_state_mod_index_is_consumed(state, kc, caps) == 0; +} + +/* + * http://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Control_Modifier + */ +static bool +should_do_ctrl_transformation(struct xkb_state *state, xkb_keycode_t kc) +{ + xkb_mod_index_t ctrl = + xkb_keymap_mod_get_index(state->keymap, XKB_MOD_NAME_CTRL); + + return + xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_EFFECTIVE) > 0 && + xkb_state_mod_index_is_consumed(state, kc, ctrl) == 0; +} + +/* Verbatim from libX11:src/xkb/XKBBind.c */ +static char +XkbToControl(char ch) +{ + char c = ch; + + if ((c >= '@' && c < '\177') || c == ' ') + c &= 0x1F; + else if (c == '2') + c = '\000'; + else if (c >= '3' && c <= '7') + c -= ('3' - '\033'); + else if (c == '8') + c = '\177'; + else if (c == '/') + c = '_' & 0x1F; + return c; +} + /** * Provides either exactly one symbol, or XKB_KEY_NoSymbol. */ @@ -835,7 +898,6 @@ xkb_state_key_get_one_sym(struct xkb_state *state, xkb_keycode_t kc) const xkb_keysym_t *syms; xkb_keysym_t sym; int num_syms; - xkb_mod_index_t caps; num_syms = xkb_state_key_get_syms(state, kc, &syms); if (num_syms != 1) @@ -843,18 +905,135 @@ xkb_state_key_get_one_sym(struct xkb_state *state, xkb_keycode_t kc) sym = syms[0]; - /* - * Perform capitalization transformation, see: - * http://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Lock_Modifier - */ - caps = xkb_keymap_mod_get_index(state->keymap, XKB_MOD_NAME_CAPS); - if (xkb_state_mod_index_is_active(state, caps, XKB_STATE_MODS_EFFECTIVE) > 0 && - xkb_state_mod_index_is_consumed(state, kc, caps) == 0) + if (should_do_caps_transformation(state, kc)) + sym = xkb_keysym_to_upper(sym); + + return sym; +} + +/* + * The caps and ctrl transformations require some special handling, + * so we cannot simply use xkb_state_get_one_sym() for them. + * In particular, if Control is set, we must try very hard to find + * some layout in which the keysym is ASCII and thus can be (maybe) + * converted to a control character. libX11 allows to disable this + * behavior with the XkbLC_ControlFallback (see XkbSetXlibControls(3)), + * but it is enabled by default, yippee. + */ +static xkb_keysym_t +get_one_sym_for_string(struct xkb_state *state, xkb_keycode_t kc) +{ + xkb_level_index_t level; + xkb_layout_index_t layout, num_layouts; + const xkb_keysym_t *syms; + int nsyms; + xkb_keysym_t sym; + + layout = xkb_state_key_get_layout(state, kc); + num_layouts = xkb_keymap_num_layouts_for_key(state->keymap, kc); + level = xkb_state_key_get_level(state, kc, layout); + if (layout == XKB_LAYOUT_INVALID || num_layouts == 0 || + level == XKB_LEVEL_INVALID) + return XKB_KEY_NoSymbol; + + nsyms = xkb_keymap_key_get_syms_by_level(state->keymap, kc, + layout, level, &syms); + if (nsyms != 1) + return XKB_KEY_NoSymbol; + sym = syms[0]; + + if (should_do_ctrl_transformation(state, kc) && sym > 127u) { + for (xkb_layout_index_t i = 0; i < num_layouts; i++) { + level = xkb_state_key_get_level(state, kc, i); + if (level == XKB_LEVEL_INVALID) + continue; + + nsyms = xkb_keymap_key_get_syms_by_level(state->keymap, kc, + i, level, &syms); + if (nsyms == 1 && syms[0] <= 127u) { + sym = syms[0]; + break; + } + } + } + + if (should_do_caps_transformation(state, kc)) { sym = xkb_keysym_to_upper(sym); + } return sym; } +XKB_EXPORT int +xkb_state_key_get_utf8(struct xkb_state *state, xkb_keycode_t kc, + char *buffer, size_t size) +{ + xkb_keysym_t sym; + const xkb_keysym_t *syms; + int nsyms; + int offset; + char tmp[7]; + + sym = get_one_sym_for_string(state, kc); + if (sym != XKB_KEY_NoSymbol) { + nsyms = 1; syms = &sym; + } + else { + nsyms = xkb_state_key_get_syms(state, kc, &syms); + } + + /* Make sure not to truncate in the middle of a UTF-8 sequence. */ + offset = 0; + for (int i = 0; i < nsyms; i++) { + int ret = xkb_keysym_to_utf8(syms[i], tmp, sizeof(tmp)); + if (ret <= 0) + goto err_bad; + + ret--; + if ((size_t) (offset + ret) <= size) + memcpy(buffer + offset, tmp, ret); + offset += ret; + } + + if ((size_t) offset >= size) + goto err_trunc; + buffer[offset] = '\0'; + + if (!is_valid_utf8(buffer, offset)) + goto err_bad; + + if (offset == 1 && (unsigned int) buffer[0] <= 127u && + should_do_ctrl_transformation(state, kc)) + buffer[0] = XkbToControl(buffer[0]); + + return offset; + +err_trunc: + if (size > 0) + buffer[size - 1] = '\0'; + return offset; + +err_bad: + if (size > 0) + buffer[0] = '\0'; + return 0; +} + +XKB_EXPORT uint32_t +xkb_state_key_get_utf32(struct xkb_state *state, xkb_keycode_t kc) +{ + xkb_keysym_t sym; + uint32_t cp; + + sym = get_one_sym_for_string(state, kc); + cp = xkb_keysym_to_utf32(sym); + + if (cp <= 127u && should_do_ctrl_transformation(state, kc)) + cp = (uint32_t) XkbToControl((char) cp); + + return cp; +} + /** * Serialises the requested modifier state into an xkb_mod_mask_t, with all * the same disclaimers as in xkb_state_update_mask. @@ -913,7 +1092,7 @@ xkb_state_mod_index_is_active(struct xkb_state *state, if (idx >= xkb_keymap_num_mods(state->keymap)) return -1; - return !!(xkb_state_serialize_mods(state, type) & (1 << idx)); + return !!(xkb_state_serialize_mods(state, type) & (1u << idx)); } /** @@ -964,7 +1143,7 @@ xkb_state_mod_indices_are_active(struct xkb_state *state, ret = -1; break; } - wanted |= (1 << idx); + wanted |= (1u << idx); } va_end(ap); @@ -1015,7 +1194,7 @@ xkb_state_mod_names_are_active(struct xkb_state *state, ret = -1; break; } - wanted |= (1 << idx); + wanted |= (1u << idx); } va_end(ap); @@ -1042,11 +1221,11 @@ xkb_state_layout_index_is_active(struct xkb_state *state, if (type & XKB_STATE_LAYOUT_EFFECTIVE) ret |= (state->components.group == idx); if (type & XKB_STATE_LAYOUT_DEPRESSED) - ret |= (state->components.base_group == idx); + ret |= (state->components.base_group == (int32_t) idx); if (type & XKB_STATE_LAYOUT_LATCHED) - ret |= (state->components.latched_group == idx); + ret |= (state->components.latched_group == (int32_t) idx); if (type & XKB_STATE_LAYOUT_LOCKED) - ret |= (state->components.locked_group == idx); + ret |= (state->components.locked_group == (int32_t) idx); return ret; } @@ -1077,7 +1256,7 @@ xkb_state_led_index_is_active(struct xkb_state *state, xkb_led_index_t idx) darray_item(state->keymap->leds, idx).name == XKB_ATOM_NONE) return -1; - return !!(state->components.leds & (1 << idx)); + return !!(state->components.leds & (1u << idx)); } /** @@ -1097,18 +1276,24 @@ xkb_state_led_name_is_active(struct xkb_state *state, const char *name) static xkb_mod_mask_t key_get_consumed(struct xkb_state *state, const struct xkb_key *key) { + const struct xkb_key_type *type; const struct xkb_key_type_entry *entry; + xkb_mod_mask_t preserve; xkb_layout_index_t group; group = xkb_state_key_get_layout(state, key->keycode); if (group == XKB_LAYOUT_INVALID) return 0; + type = key->groups[group].type; + entry = get_entry_for_key_state(state, key, group); - if (!entry) - return 0; + if (entry) + preserve = entry->preserve.mask; + else + preserve = 0; - return entry->mods.mask & ~entry->preserve.mask; + return type->mods.mask & ~preserve; } /** @@ -1132,7 +1317,7 @@ xkb_state_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t kc, if (!key || idx >= xkb_keymap_num_mods(state->keymap)) return -1; - return !!((1 << idx) & key_get_consumed(state, key)); + return !!((1u << idx) & key_get_consumed(state, key)); } /** @@ -1154,3 +1339,14 @@ xkb_state_mod_mask_remove_consumed(struct xkb_state *state, xkb_keycode_t kc, return mask & ~key_get_consumed(state, key); } + +XKB_EXPORT xkb_mod_mask_t +xkb_state_key_get_consumed_mods(struct xkb_state *state, xkb_keycode_t kc) +{ + const struct xkb_key *key = XkbKey(state->keymap, kc); + + if (!key) + return 0; + + return key_get_consumed(state, key); +} |