case XKB_CONSUMED_MODE_XKB:
consumed = type->mods.mask;
break;
+
+ case XKB_CONSUMED_MODE_GTK: {
+ const struct xkb_key_type_entry *no_mods_entry;
+ xkb_level_index_t no_mods_leveli;
+ const struct xkb_level *no_mods_level, *level;
+
+ no_mods_entry = get_entry_for_mods(type, 0);
+ no_mods_leveli = no_mods_entry ? no_mods_entry->level : 0;
+ no_mods_level = &key->groups[group].levels[no_mods_leveli];
+
+ for (unsigned i = 0; i < type->num_entries; i++) {
+ const struct xkb_key_type_entry *entry = &type->entries[i];
+ if (!entry_is_active(entry))
+ continue;
+
+ level = &key->groups[group].levels[entry->level];
+ if (XkbLevelsSameSyms(level, no_mods_level))
+ continue;
+
+ if (entry == matching_entry || popcount(entry->mods.mask) == 1)
+ consumed |= entry->mods.mask & ~entry->preserve.mask;
+ }
+ break;
+ }
}
return consumed & ~preserve;
switch (mode) {
case XKB_CONSUMED_MODE_XKB:
+ case XKB_CONSUMED_MODE_GTK:
break;
default:
log_err_func(state->keymap->ctx,
static int evdev_offset = 8;
static bool report_state_changes;
static bool with_compose;
+static enum xkb_consumed_mode consumed_mode = XKB_CONSUMED_MODE_XKB;
#define NLONGS(n) (((n) + LONG_BIT - 1) / LONG_BIT)
if (value != KEY_STATE_RELEASE)
test_print_keycode_state(kbd->state, kbd->compose_state, keycode,
- XKB_CONSUMED_MODE_XKB);
+ consumed_mode);
if (with_compose) {
status = xkb_compose_state_get_status(kbd->compose_state);
setlocale(LC_ALL, "");
- while ((opt = getopt(argc, argv, "r:m:l:v:o:k:n:cd")) != -1) {
+ while ((opt = getopt(argc, argv, "r:m:l:v:o:k:n:cdg")) != -1) {
switch (opt) {
case 'r':
rules = optarg;
case 'd':
with_compose = true;
break;
+ case 'g':
+ consumed_mode = XKB_CONSUMED_MODE_GTK;
+ break;
case '?':
fprintf(stderr, " Usage: %s [-r <rules>] [-m <model>] "
"[-l <layout>] [-v <variant>] [-o <options>]\n",
argv[0]);
fprintf(stderr, "For both: -n <evdev keycode offset>\n"
" -c (to report changes to the state)\n"
- " -d (to enable compose)\n");
+ " -d (to enable compose)\n"
+ " -g (to use GTK consumed mode)\n");
exit(2);
}
}
assert(mask == ((1U << shift) | (1U << alt) | (1U << ctrl) | (1U << mod5)));
xkb_state_unref(state);
+
+ /* Test XKB_CONSUMED_MODE_GTK, CTRL+ALT */
+ state = xkb_state_new(keymap);
+ assert(state);
+
+ mask = xkb_state_key_get_consumed_mods2(state, KEY_F1 + EVDEV_OFFSET,
+ XKB_CONSUMED_MODE_GTK);
+ assert(mask == 0);
+
+ xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_DOWN);
+ mask = xkb_state_key_get_consumed_mods2(state, KEY_F1 + EVDEV_OFFSET,
+ XKB_CONSUMED_MODE_GTK);
+ assert(mask == 0);
+
+ xkb_state_update_key(state, KEY_LEFTALT + EVDEV_OFFSET, XKB_KEY_DOWN);
+ mask = xkb_state_key_get_consumed_mods2(state, KEY_F1 + EVDEV_OFFSET,
+ XKB_CONSUMED_MODE_GTK);
+ assert(mask == ((1U << alt) | (1U << ctrl)));
+
+ xkb_state_unref(state);
+
+ /* Test XKB_CONSUMED_MODE_GTK, Simple Shift */
+ state = xkb_state_new(keymap);
+ assert(state);
+
+ mask = xkb_state_key_get_consumed_mods2(state, KEY_A + EVDEV_OFFSET,
+ XKB_CONSUMED_MODE_GTK);
+ assert(mask == ((1U << shift) | (1U << caps)));
+
+ xkb_state_update_key(state, KEY_LEFTALT + EVDEV_OFFSET, XKB_KEY_DOWN);
+ mask = xkb_state_key_get_consumed_mods2(state, KEY_A + EVDEV_OFFSET,
+ XKB_CONSUMED_MODE_GTK);
+ assert(mask == ((1U << shift) | (1U << caps)));
+
+ xkb_state_unref(state);
}
static void
* even though they are not active, since if they *were* active they would
* have affected key translation.
*/
- XKB_CONSUMED_MODE_XKB
+ XKB_CONSUMED_MODE_XKB,
+ /**
+ * This is the mode used by the GTK+ toolkit.
+ *
+ * The mode consists of the following two heuristics:
+ *
+ * - The active set of modifiers, excluding modifiers which do not affect
+ * the key (as described above), are considered consumed, if they result
+ * in different keysyms being produced than when no modifiers are active.
+ *
+ * - Additionally, a single modifier is considered consumed if, were it the
+ * only active modifier affecting the key (as described above), it would
+ * result in different keysyms being produced than when no modifiers are
+ * active.
+ */
+ XKB_CONSUMED_MODE_GTK
};
/**