summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/xkbcommon/src/state.c
diff options
context:
space:
mode:
authorGatis Paeglis <gatis.paeglis@digia.com>2014-03-28 16:22:14 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-04-03 14:20:19 +0200
commitbd40a7cc446cafb8c9922d7d19845da580868859 (patch)
tree966292563ebe2541ee6129c0d9ce42409f4a24fe /src/3rdparty/xkbcommon/src/state.c
parent151cf2047aa36ac395a841a3ced8b2142a997aec (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.c308
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);
+}