atom: describe how this odd data structure works
[platform/upstream/libxkbcommon.git] / src / state.c
1 /************************************************************
2  * Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3  *
4  * Permission to use, copy, modify, and distribute this
5  * software and its documentation for any purpose and without
6  * fee is hereby granted, provided that the above copyright
7  * notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting
9  * documentation, and that the name of Silicon Graphics not be
10  * used in advertising or publicity pertaining to distribution
11  * of the software without specific prior written permission.
12  * Silicon Graphics makes no representation about the suitability
13  * of this software for any purpose. It is provided "as is"
14  * without any express or implied warranty.
15  *
16  * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18  * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19  * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23  * THE USE OR PERFORMANCE OF THIS SOFTWARE.
24  *
25  ********************************************************/
26
27 /*
28  * Copyright © 2012 Intel Corporation
29  * Copyright © 2012 Ran Benita <ran234@gmail.com>
30  *
31  * Permission is hereby granted, free of charge, to any person obtaining a
32  * copy of this software and associated documentation files (the "Software"),
33  * to deal in the Software without restriction, including without limitation
34  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
35  * and/or sell copies of the Software, and to permit persons to whom the
36  * Software is furnished to do so, subject to the following conditions:
37  *
38  * The above copyright notice and this permission notice (including the next
39  * paragraph) shall be included in all copies or substantial portions of the
40  * Software.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
45  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
47  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
48  * DEALINGS IN THE SOFTWARE.
49  *
50  * Author: Daniel Stone <daniel@fooishbar.org>
51  */
52
53 /*
54  * This is a bastardised version of xkbActions.c from the X server which
55  * does not support, for the moment:
56  *   - AccessX sticky/debounce/etc (will come later)
57  *   - pointer keys (may come later)
58  *   - key redirects (unlikely)
59  *   - messages (very unlikely)
60  */
61
62 #include "keymap.h"
63 #include "keysym.h"
64 #include "utf8.h"
65
66 struct xkb_filter {
67     union xkb_action action;
68     const struct xkb_key *key;
69     uint32_t priv;
70     bool (*func)(struct xkb_state *state,
71                  struct xkb_filter *filter,
72                  const struct xkb_key *key,
73                  enum xkb_key_direction direction);
74     int refcnt;
75 };
76
77 struct state_components {
78     /* These may be negative, because of -1 group actions. */
79     int32_t base_group; /**< depressed */
80     int32_t latched_group;
81     int32_t locked_group;
82     xkb_layout_index_t group; /**< effective */
83
84     xkb_mod_mask_t base_mods; /**< depressed */
85     xkb_mod_mask_t latched_mods;
86     xkb_mod_mask_t locked_mods;
87     xkb_mod_mask_t mods; /**< effective */
88
89     xkb_led_mask_t leds;
90 };
91
92 struct xkb_state {
93     /*
94      * Before updating the state, we keep a copy of just this struct. This
95      * allows us to report which components of the state have changed.
96      */
97     struct state_components components;
98
99     /*
100      * At each event, we accumulate all the needed modifications to the base
101      * modifiers, and apply them at the end. These keep track of this state.
102      */
103     xkb_mod_mask_t set_mods;
104     xkb_mod_mask_t clear_mods;
105
106     /*
107      * We mustn't clear a base modifier if there's another depressed key
108      * which affects it, e.g. given this sequence
109      * < Left Shift down, Right Shift down, Left Shift Up >
110      * the modifier should still be set. This keeps the count.
111      */
112     int16_t mod_key_count[XKB_MAX_MODS];
113
114     int refcnt;
115     darray(struct xkb_filter) filters;
116     struct xkb_keymap *keymap;
117 };
118
119 /*
120  * If the virtual modifiers are not bound to anything, the entry
121  * is not active and should be skipped. xserver does this with
122  * cached entry->active field.
123  */
124 static bool
125 entry_is_active(const struct xkb_key_type_entry *entry)
126 {
127     return entry->mods.mods == 0 || entry->mods.mask != 0;
128 }
129
130 static const struct xkb_key_type_entry *
131 get_entry_for_mods(const struct xkb_key_type *type, xkb_mod_mask_t mods)
132 {
133     for (unsigned i = 0; i < type->num_entries; i++)
134         if (entry_is_active(&type->entries[i]) &&
135             type->entries[i].mods.mask == mods)
136             return &type->entries[i];
137     return NULL;
138 }
139
140 static const struct xkb_key_type_entry *
141 get_entry_for_key_state(struct xkb_state *state, const struct xkb_key *key,
142                         xkb_layout_index_t group)
143 {
144     const struct xkb_key_type *type = key->groups[group].type;
145     xkb_mod_mask_t active_mods = state->components.mods & type->mods.mask;
146     return get_entry_for_mods(type, active_mods);
147 }
148
149 /**
150  * Returns the level to use for the given key and state, or
151  * XKB_LEVEL_INVALID.
152  */
153 XKB_EXPORT xkb_level_index_t
154 xkb_state_key_get_level(struct xkb_state *state, xkb_keycode_t kc,
155                         xkb_layout_index_t layout)
156 {
157     const struct xkb_key *key = XkbKey(state->keymap, kc);
158     const struct xkb_key_type_entry *entry;
159
160     if (!key || layout >= key->num_groups)
161         return XKB_LEVEL_INVALID;
162
163     /* If we don't find an explicit match the default is 0. */
164     entry = get_entry_for_key_state(state, key, layout);
165     if (!entry)
166         return 0;
167
168     return entry->level;
169 }
170
171 xkb_layout_index_t
172 XkbWrapGroupIntoRange(int32_t group,
173                       xkb_layout_index_t num_groups,
174                       enum xkb_range_exceed_type out_of_range_group_action,
175                       xkb_layout_index_t out_of_range_group_number)
176 {
177     if (num_groups == 0)
178         return XKB_LAYOUT_INVALID;
179
180     if (group >= 0 && (xkb_layout_index_t) group < num_groups)
181         return group;
182
183     switch (out_of_range_group_action) {
184     case RANGE_REDIRECT:
185         if (out_of_range_group_number >= num_groups)
186             return 0;
187         return out_of_range_group_number;
188
189     case RANGE_SATURATE:
190         if (group < 0)
191             return 0;
192         else
193             return num_groups - 1;
194
195     case RANGE_WRAP:
196     default:
197         /*
198          * C99 says a negative dividend in a modulo operation always
199          * gives a negative result.
200          */
201         if (group < 0)
202             return ((int) num_groups + (group % (int) num_groups));
203         else
204             return group % num_groups;
205     }
206 }
207
208 /**
209  * Returns the layout to use for the given key and state, taking
210  * wrapping/clamping/etc into account, or XKB_LAYOUT_INVALID.
211  */
212 XKB_EXPORT xkb_layout_index_t
213 xkb_state_key_get_layout(struct xkb_state *state, xkb_keycode_t kc)
214 {
215     const struct xkb_key *key = XkbKey(state->keymap, kc);
216
217     if (!key)
218         return XKB_LAYOUT_INVALID;
219
220     return XkbWrapGroupIntoRange(state->components.group, key->num_groups,
221                                  key->out_of_range_group_action,
222                                  key->out_of_range_group_number);
223 }
224
225 static const union xkb_action *
226 xkb_key_get_action(struct xkb_state *state, const struct xkb_key *key)
227 {
228     static const union xkb_action dummy = { .type = ACTION_TYPE_NONE };
229
230     xkb_layout_index_t layout;
231     xkb_level_index_t level;
232
233     layout = xkb_state_key_get_layout(state, key->keycode);
234     if (layout == XKB_LAYOUT_INVALID)
235         return &dummy;
236
237     level = xkb_state_key_get_level(state, key->keycode, layout);
238     if (level == XKB_LEVEL_INVALID)
239         return &dummy;
240
241     return &key->groups[layout].levels[level].action;
242 }
243
244 static struct xkb_filter *
245 xkb_filter_new(struct xkb_state *state)
246 {
247     struct xkb_filter *filter = NULL, *iter;
248
249     darray_foreach(iter, state->filters) {
250         if (iter->func)
251             continue;
252         filter = iter;
253         break;
254     }
255
256     if (!filter) {
257         darray_resize0(state->filters, darray_size(state->filters) + 1);
258         filter = &darray_item(state->filters, darray_size(state->filters) -1);
259     }
260
261     filter->refcnt = 1;
262     return filter;
263 }
264
265 /***====================================================================***/
266
267 enum xkb_filter_result {
268     /*
269      * The event is consumed by the filters.
270      *
271      * An event is always processed by all filters, but any filter can
272      * prevent it from being processed further by consuming it.
273      */
274     XKB_FILTER_CONSUME,
275     /*
276      * The event may continue to be processed as far as this filter is
277      * concerned.
278      */
279     XKB_FILTER_CONTINUE,
280 };
281
282 static void
283 xkb_filter_group_set_new(struct xkb_state *state, struct xkb_filter *filter)
284 {
285     filter->priv = state->components.base_group;
286     if (filter->action.group.flags & ACTION_ABSOLUTE_SWITCH)
287         state->components.base_group = filter->action.group.group;
288     else
289         state->components.base_group += filter->action.group.group;
290 }
291
292 static bool
293 xkb_filter_group_set_func(struct xkb_state *state,
294                           struct xkb_filter *filter,
295                           const struct xkb_key *key,
296                           enum xkb_key_direction direction)
297 {
298     if (key != filter->key) {
299         filter->action.group.flags &= ~ACTION_LOCK_CLEAR;
300         return XKB_FILTER_CONTINUE;
301     }
302
303     if (direction == XKB_KEY_DOWN) {
304         filter->refcnt++;
305         return XKB_FILTER_CONSUME;
306     }
307     else if (--filter->refcnt > 0) {
308         return XKB_FILTER_CONSUME;
309     }
310
311     state->components.base_group = filter->priv;
312
313     if (filter->action.group.flags & ACTION_LOCK_CLEAR)
314         state->components.locked_group = 0;
315
316     filter->func = NULL;
317     return XKB_FILTER_CONTINUE;
318 }
319
320 static void
321 xkb_filter_group_lock_new(struct xkb_state *state, struct xkb_filter *filter)
322 {
323     if (filter->action.group.flags & ACTION_ABSOLUTE_SWITCH)
324         state->components.locked_group = filter->action.group.group;
325     else
326         state->components.locked_group += filter->action.group.group;
327 }
328
329 static bool
330 xkb_filter_group_lock_func(struct xkb_state *state,
331                            struct xkb_filter *filter,
332                            const struct xkb_key *key,
333                            enum xkb_key_direction direction)
334 {
335     if (key != filter->key)
336         return XKB_FILTER_CONTINUE;
337
338     if (direction == XKB_KEY_DOWN) {
339         filter->refcnt++;
340         return XKB_FILTER_CONSUME;
341     }
342     if (--filter->refcnt > 0)
343         return XKB_FILTER_CONSUME;
344
345     filter->func = NULL;
346     return XKB_FILTER_CONTINUE;
347 }
348
349 static void
350 xkb_filter_mod_set_new(struct xkb_state *state, struct xkb_filter *filter)
351 {
352     state->set_mods = filter->action.mods.mods.mask;
353 }
354
355 static bool
356 xkb_filter_mod_set_func(struct xkb_state *state,
357                         struct xkb_filter *filter,
358                         const struct xkb_key *key,
359                         enum xkb_key_direction direction)
360 {
361     if (key != filter->key) {
362         filter->action.mods.flags &= ~ACTION_LOCK_CLEAR;
363         return XKB_FILTER_CONTINUE;
364     }
365
366     if (direction == XKB_KEY_DOWN) {
367         filter->refcnt++;
368         return XKB_FILTER_CONSUME;
369     }
370     else if (--filter->refcnt > 0) {
371         return XKB_FILTER_CONSUME;
372     }
373
374     state->clear_mods = filter->action.mods.mods.mask;
375     if (filter->action.mods.flags & ACTION_LOCK_CLEAR)
376         state->components.locked_mods &= ~filter->action.mods.mods.mask;
377
378     filter->func = NULL;
379     return XKB_FILTER_CONTINUE;
380 }
381
382 static void
383 xkb_filter_mod_lock_new(struct xkb_state *state, struct xkb_filter *filter)
384 {
385     filter->priv = (state->components.locked_mods &
386                     filter->action.mods.mods.mask);
387     state->set_mods |= filter->action.mods.mods.mask;
388     if (!(filter->action.mods.flags & ACTION_LOCK_NO_LOCK))
389         state->components.locked_mods |= filter->action.mods.mods.mask;
390 }
391
392 static bool
393 xkb_filter_mod_lock_func(struct xkb_state *state,
394                          struct xkb_filter *filter,
395                          const struct xkb_key *key,
396                          enum xkb_key_direction direction)
397 {
398     if (key != filter->key)
399         return XKB_FILTER_CONTINUE;
400
401     if (direction == XKB_KEY_DOWN) {
402         filter->refcnt++;
403         return XKB_FILTER_CONSUME;
404     }
405     if (--filter->refcnt > 0)
406         return XKB_FILTER_CONSUME;
407
408     state->clear_mods |= filter->action.mods.mods.mask;
409     if (!(filter->action.mods.flags & ACTION_LOCK_NO_UNLOCK))
410         state->components.locked_mods &= ~filter->priv;
411
412     filter->func = NULL;
413     return XKB_FILTER_CONTINUE;
414 }
415
416 enum xkb_key_latch_state {
417     NO_LATCH,
418     LATCH_KEY_DOWN,
419     LATCH_PENDING,
420 };
421
422 static bool
423 xkb_action_breaks_latch(const union xkb_action *action)
424 {
425     switch (action->type) {
426     case ACTION_TYPE_NONE:
427     case ACTION_TYPE_PTR_BUTTON:
428     case ACTION_TYPE_PTR_LOCK:
429     case ACTION_TYPE_CTRL_SET:
430     case ACTION_TYPE_CTRL_LOCK:
431     case ACTION_TYPE_SWITCH_VT:
432     case ACTION_TYPE_TERMINATE:
433         return true;
434     default:
435         return false;
436     }
437 }
438
439 static void
440 xkb_filter_mod_latch_new(struct xkb_state *state, struct xkb_filter *filter)
441 {
442     filter->priv = LATCH_KEY_DOWN;
443     state->set_mods = filter->action.mods.mods.mask;
444 }
445
446 static bool
447 xkb_filter_mod_latch_func(struct xkb_state *state,
448                           struct xkb_filter *filter,
449                           const struct xkb_key *key,
450                           enum xkb_key_direction direction)
451 {
452     enum xkb_key_latch_state latch = filter->priv;
453
454     if (direction == XKB_KEY_DOWN && latch == LATCH_PENDING) {
455         /* If this is a new keypress and we're awaiting our single latched
456          * keypress, then either break the latch if any random key is pressed,
457          * or promote it to a lock or plain base set if it's the same
458          * modifier. */
459         const union xkb_action *action = xkb_key_get_action(state, key);
460         if (action->type == ACTION_TYPE_MOD_LATCH &&
461             action->mods.flags == filter->action.mods.flags &&
462             action->mods.mods.mask == filter->action.mods.mods.mask) {
463             filter->action = *action;
464             if (filter->action.mods.flags & ACTION_LATCH_TO_LOCK) {
465                 filter->action.type = ACTION_TYPE_MOD_LOCK;
466                 filter->func = xkb_filter_mod_lock_func;
467                 state->components.locked_mods |= filter->action.mods.mods.mask;
468             }
469             else {
470                 filter->action.type = ACTION_TYPE_MOD_SET;
471                 filter->func = xkb_filter_mod_set_func;
472                 state->set_mods = filter->action.mods.mods.mask;
473             }
474             filter->key = key;
475             state->components.latched_mods &= ~filter->action.mods.mods.mask;
476             /* XXX beep beep! */
477             return XKB_FILTER_CONSUME;
478         }
479         else if (xkb_action_breaks_latch(action)) {
480             /* XXX: This may be totally broken, we might need to break the
481              *      latch in the next run after this press? */
482             state->components.latched_mods &= ~filter->action.mods.mods.mask;
483             filter->func = NULL;
484             return XKB_FILTER_CONTINUE;
485         }
486     }
487     else if (direction == XKB_KEY_UP && key == filter->key) {
488         /* Our key got released.  If we've set it to clear locks, and we
489          * currently have the same modifiers locked, then release them and
490          * don't actually latch.  Else we've actually hit the latching
491          * stage, so set PENDING and move our modifier from base to
492          * latched. */
493         if (latch == NO_LATCH ||
494             ((filter->action.mods.flags & ACTION_LOCK_CLEAR) &&
495              (state->components.locked_mods & filter->action.mods.mods.mask) ==
496              filter->action.mods.mods.mask)) {
497             /* XXX: We might be a bit overenthusiastic about clearing
498              *      mods other filters have set here? */
499             if (latch == LATCH_PENDING)
500                 state->components.latched_mods &=
501                     ~filter->action.mods.mods.mask;
502             else
503                 state->clear_mods = filter->action.mods.mods.mask;
504             state->components.locked_mods &= ~filter->action.mods.mods.mask;
505             filter->func = NULL;
506         }
507         else {
508             latch = LATCH_PENDING;
509             state->clear_mods = filter->action.mods.mods.mask;
510             state->components.latched_mods |= filter->action.mods.mods.mask;
511             /* XXX beep beep! */
512         }
513     }
514     else if (direction == XKB_KEY_DOWN && latch == LATCH_KEY_DOWN) {
515         /* Someone's pressed another key while we've still got the latching
516          * key held down, so keep the base modifier state active (from
517          * xkb_filter_mod_latch_new), but don't trip the latch, just clear
518          * it as soon as the modifier gets released. */
519         latch = NO_LATCH;
520     }
521
522     filter->priv = latch;
523
524     return XKB_FILTER_CONTINUE;
525 }
526
527 static const struct {
528     void (*new)(struct xkb_state *state, struct xkb_filter *filter);
529     bool (*func)(struct xkb_state *state, struct xkb_filter *filter,
530                  const struct xkb_key *key, enum xkb_key_direction direction);
531 } filter_action_funcs[_ACTION_TYPE_NUM_ENTRIES] = {
532     [ACTION_TYPE_MOD_SET]    = { xkb_filter_mod_set_new,
533                                  xkb_filter_mod_set_func },
534     [ACTION_TYPE_MOD_LATCH]  = { xkb_filter_mod_latch_new,
535                                  xkb_filter_mod_latch_func },
536     [ACTION_TYPE_MOD_LOCK]   = { xkb_filter_mod_lock_new,
537                                  xkb_filter_mod_lock_func },
538     [ACTION_TYPE_GROUP_SET]  = { xkb_filter_group_set_new,
539                                  xkb_filter_group_set_func },
540     [ACTION_TYPE_GROUP_LOCK] = { xkb_filter_group_lock_new,
541                                  xkb_filter_group_lock_func },
542 };
543
544 /**
545  * Applies any relevant filters to the key, first from the list of filters
546  * that are currently active, then if no filter has claimed the key, possibly
547  * apply a new filter from the key action.
548  */
549 static void
550 xkb_filter_apply_all(struct xkb_state *state,
551                      const struct xkb_key *key,
552                      enum xkb_key_direction direction)
553 {
554     struct xkb_filter *filter;
555     const union xkb_action *action;
556     bool consumed;
557
558     /* First run through all the currently active filters and see if any of
559      * them have consumed this event. */
560     consumed = false;
561     darray_foreach(filter, state->filters) {
562         if (!filter->func)
563             continue;
564
565         if (filter->func(state, filter, key, direction) == XKB_FILTER_CONSUME)
566             consumed = true;
567     }
568     if (consumed || direction == XKB_KEY_UP)
569         return;
570
571     action = xkb_key_get_action(state, key);
572
573     /*
574      * It's possible for the keymap to set action->type explicitly, like so:
575      *     interpret XF86_Next_VMode {
576      *         action = Private(type=0x86, data="+VMode");
577      *     };
578      * We don't handle those.
579      */
580     if (action->type >= _ACTION_TYPE_NUM_ENTRIES)
581         return;
582
583     if (!filter_action_funcs[action->type].new)
584         return;
585
586     filter = xkb_filter_new(state);
587     filter->key = key;
588     filter->func = filter_action_funcs[action->type].func;
589     filter->action = *action;
590     filter_action_funcs[action->type].new(state, filter);
591 }
592
593 XKB_EXPORT struct xkb_state *
594 xkb_state_new(struct xkb_keymap *keymap)
595 {
596     struct xkb_state *ret;
597
598     ret = calloc(sizeof(*ret), 1);
599     if (!ret)
600         return NULL;
601
602     ret->refcnt = 1;
603     ret->keymap = xkb_keymap_ref(keymap);
604
605     return ret;
606 }
607
608 XKB_EXPORT struct xkb_state *
609 xkb_state_ref(struct xkb_state *state)
610 {
611     state->refcnt++;
612     return state;
613 }
614
615 XKB_EXPORT void
616 xkb_state_unref(struct xkb_state *state)
617 {
618     if (!state || --state->refcnt > 0)
619         return;
620
621     xkb_keymap_unref(state->keymap);
622     darray_free(state->filters);
623     free(state);
624 }
625
626 XKB_EXPORT struct xkb_keymap *
627 xkb_state_get_keymap(struct xkb_state *state)
628 {
629     return state->keymap;
630 }
631
632 /**
633  * Update the LED state to match the rest of the xkb_state.
634  */
635 static void
636 xkb_state_led_update_all(struct xkb_state *state)
637 {
638     xkb_led_index_t idx;
639     const struct xkb_led *led;
640
641     state->components.leds = 0;
642
643     xkb_leds_enumerate(idx, led, state->keymap) {
644         xkb_mod_mask_t mod_mask = 0;
645         xkb_layout_mask_t group_mask = 0;
646
647         if (led->which_mods != 0 && led->mods.mask != 0) {
648             if (led->which_mods & XKB_STATE_MODS_EFFECTIVE)
649                 mod_mask |= state->components.mods;
650             if (led->which_mods & XKB_STATE_MODS_DEPRESSED)
651                 mod_mask |= state->components.base_mods;
652             if (led->which_mods & XKB_STATE_MODS_LATCHED)
653                 mod_mask |= state->components.latched_mods;
654             if (led->which_mods & XKB_STATE_MODS_LOCKED)
655                 mod_mask |= state->components.locked_mods;
656
657             if (led->mods.mask & mod_mask) {
658                 state->components.leds |= (1u << idx);
659                 continue;
660             }
661         }
662
663         if (led->which_groups != 0 && led->groups != 0) {
664             if (led->which_groups & XKB_STATE_LAYOUT_EFFECTIVE)
665                 group_mask |= (1u << state->components.group);
666             if (led->which_groups & XKB_STATE_LAYOUT_DEPRESSED)
667                 group_mask |= (1u << state->components.base_group);
668             if (led->which_groups & XKB_STATE_LAYOUT_LATCHED)
669                 group_mask |= (1u << state->components.latched_group);
670             if (led->which_groups & XKB_STATE_LAYOUT_LOCKED)
671                 group_mask |= (1u << state->components.locked_group);
672
673             if (led->groups & group_mask) {
674                 state->components.leds |= (1u << idx);
675                 continue;
676             }
677         }
678
679         if (led->ctrls & state->keymap->enabled_ctrls) {
680             state->components.leds |= (1u << idx);
681             continue;
682         }
683     }
684 }
685
686 /**
687  * Calculates the derived state (effective mods/group and LEDs) from an
688  * up-to-date xkb_state.
689  */
690 static void
691 xkb_state_update_derived(struct xkb_state *state)
692 {
693     xkb_layout_index_t wrapped;
694
695     state->components.mods = (state->components.base_mods |
696                               state->components.latched_mods |
697                               state->components.locked_mods);
698
699     /* TODO: Use groups_wrap control instead of always RANGE_WRAP. */
700
701     wrapped = XkbWrapGroupIntoRange(state->components.locked_group,
702                                     state->keymap->num_groups,
703                                     RANGE_WRAP, 0);
704     state->components.locked_group =
705         (wrapped == XKB_LAYOUT_INVALID ? 0 : wrapped);
706
707     wrapped = XkbWrapGroupIntoRange(state->components.base_group +
708                                     state->components.latched_group +
709                                     state->components.locked_group,
710                                     state->keymap->num_groups,
711                                     RANGE_WRAP, 0);
712     state->components.group =
713         (wrapped == XKB_LAYOUT_INVALID ? 0 : wrapped);
714
715     xkb_state_led_update_all(state);
716 }
717
718 static enum xkb_state_component
719 get_state_component_changes(const struct state_components *a,
720                             const struct state_components *b)
721 {
722     xkb_mod_mask_t mask = 0;
723
724     if (a->group != b->group)
725         mask |= XKB_STATE_LAYOUT_EFFECTIVE;
726     if (a->base_group != b->base_group)
727         mask |= XKB_STATE_LAYOUT_DEPRESSED;
728     if (a->latched_group != b->latched_group)
729         mask |= XKB_STATE_LAYOUT_LATCHED;
730     if (a->locked_group != b->locked_group)
731         mask |= XKB_STATE_LAYOUT_LOCKED;
732     if (a->mods != b->mods)
733         mask |= XKB_STATE_MODS_EFFECTIVE;
734     if (a->base_mods != b->base_mods)
735         mask |= XKB_STATE_MODS_DEPRESSED;
736     if (a->latched_mods != b->latched_mods)
737         mask |= XKB_STATE_MODS_LATCHED;
738     if (a->locked_mods != b->locked_mods)
739         mask |= XKB_STATE_MODS_LOCKED;
740     if (a->leds != b->leds)
741         mask |= XKB_STATE_LEDS;
742
743     return mask;
744 }
745
746 /**
747  * Given a particular key event, updates the state structure to reflect the
748  * new modifiers.
749  */
750 XKB_EXPORT enum xkb_state_component
751 xkb_state_update_key(struct xkb_state *state, xkb_keycode_t kc,
752                      enum xkb_key_direction direction)
753 {
754     xkb_mod_index_t i;
755     xkb_mod_mask_t bit;
756     struct state_components prev_components;
757     const struct xkb_key *key = XkbKey(state->keymap, kc);
758
759     if (!key)
760         return 0;
761
762     prev_components = state->components;
763
764     state->set_mods = 0;
765     state->clear_mods = 0;
766
767     xkb_filter_apply_all(state, key, direction);
768
769     for (i = 0, bit = 1; state->set_mods; i++, bit <<= 1) {
770         if (state->set_mods & bit) {
771             state->mod_key_count[i]++;
772             state->components.base_mods |= bit;
773             state->set_mods &= ~bit;
774         }
775     }
776
777     for (i = 0, bit = 1; state->clear_mods; i++, bit <<= 1) {
778         if (state->clear_mods & bit) {
779             state->mod_key_count[i]--;
780             if (state->mod_key_count[i] <= 0) {
781                 state->components.base_mods &= ~bit;
782                 state->mod_key_count[i] = 0;
783             }
784             state->clear_mods &= ~bit;
785         }
786     }
787
788     xkb_state_update_derived(state);
789
790     return get_state_component_changes(&prev_components, &state->components);
791 }
792
793 /**
794  * Updates the state from a set of explicit masks as gained from
795  * xkb_state_serialize_mods and xkb_state_serialize_groups.  As noted in the
796  * documentation for these functions in xkbcommon.h, this round-trip is
797  * lossy, and should only be used to update a slave state mirroring the
798  * master, e.g. in a client/server window system.
799  */
800 XKB_EXPORT enum xkb_state_component
801 xkb_state_update_mask(struct xkb_state *state,
802                       xkb_mod_mask_t base_mods,
803                       xkb_mod_mask_t latched_mods,
804                       xkb_mod_mask_t locked_mods,
805                       xkb_layout_index_t base_group,
806                       xkb_layout_index_t latched_group,
807                       xkb_layout_index_t locked_group)
808 {
809     struct state_components prev_components;
810     xkb_mod_mask_t mask;
811
812     prev_components = state->components;
813
814     /* Only include modifiers which exist in the keymap. */
815     mask = (xkb_mod_mask_t) ((1ull << xkb_keymap_num_mods(state->keymap)) - 1u);
816
817     state->components.base_mods = base_mods & mask;
818     state->components.latched_mods = latched_mods & mask;
819     state->components.locked_mods = locked_mods & mask;
820
821     /* Make sure the mods are fully resolved - since we get arbitrary
822      * input, they might not be.
823      *
824      * It might seem more reasonable to do this only for components.mods
825      * in xkb_state_update_derived(), rather than for each component
826      * seperately.  That would allow to distinguish between "really"
827      * depressed mods (would be in MODS_DEPRESSED) and indirectly
828      * depressed to to a mapping (would only be in MODS_EFFECTIVE).
829      * However, the traditional behavior of xkb_state_update_key() is that
830      * if a vmod is depressed, its mappings are depressed with it; so we're
831      * expected to do the same here.  Also, LEDs (usually) look if a real
832      * mod is locked, not just effective; otherwise it won't be lit.
833      *
834      * We OR here because mod_mask_get_effective() drops vmods. */
835     state->components.base_mods |=
836         mod_mask_get_effective(state->keymap, state->components.base_mods);
837     state->components.latched_mods |=
838         mod_mask_get_effective(state->keymap, state->components.latched_mods);
839     state->components.locked_mods |=
840         mod_mask_get_effective(state->keymap, state->components.locked_mods);
841
842     state->components.base_group = base_group;
843     state->components.latched_group = latched_group;
844     state->components.locked_group = locked_group;
845
846     xkb_state_update_derived(state);
847
848     return get_state_component_changes(&prev_components, &state->components);
849 }
850
851 /**
852  * Provides the symbols to use for the given key and state.  Returns the
853  * number of symbols pointed to in syms_out.
854  */
855 XKB_EXPORT int
856 xkb_state_key_get_syms(struct xkb_state *state, xkb_keycode_t kc,
857                        const xkb_keysym_t **syms_out)
858 {
859     xkb_layout_index_t layout;
860     xkb_level_index_t level;
861
862     layout = xkb_state_key_get_layout(state, kc);
863     if (layout == XKB_LAYOUT_INVALID)
864         goto err;
865
866     level = xkb_state_key_get_level(state, kc, layout);
867     if (level == XKB_LEVEL_INVALID)
868         goto err;
869
870     return xkb_keymap_key_get_syms_by_level(state->keymap, kc, layout, level,
871                                             syms_out);
872
873 err:
874     *syms_out = NULL;
875     return 0;
876 }
877
878 /*
879  * https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Lock_Modifier
880  */
881 static bool
882 should_do_caps_transformation(struct xkb_state *state, xkb_keycode_t kc)
883 {
884     xkb_mod_index_t caps =
885         xkb_keymap_mod_get_index(state->keymap, XKB_MOD_NAME_CAPS);
886
887     return
888         xkb_state_mod_index_is_active(state, caps, XKB_STATE_MODS_EFFECTIVE) > 0 &&
889         xkb_state_mod_index_is_consumed(state, kc, caps) == 0;
890 }
891
892 /*
893  * https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Control_Modifier
894  */
895 static bool
896 should_do_ctrl_transformation(struct xkb_state *state, xkb_keycode_t kc)
897 {
898     xkb_mod_index_t ctrl =
899         xkb_keymap_mod_get_index(state->keymap, XKB_MOD_NAME_CTRL);
900
901     return
902         xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_EFFECTIVE) > 0 &&
903         xkb_state_mod_index_is_consumed(state, kc, ctrl) == 0;
904 }
905
906 /* Verbatim from libX11:src/xkb/XKBBind.c */
907 static char
908 XkbToControl(char ch)
909 {
910     char c = ch;
911
912     if ((c >= '@' && c < '\177') || c == ' ')
913         c &= 0x1F;
914     else if (c == '2')
915         c = '\000';
916     else if (c >= '3' && c <= '7')
917         c -= ('3' - '\033');
918     else if (c == '8')
919         c = '\177';
920     else if (c == '/')
921         c = '_' & 0x1F;
922     return c;
923 }
924
925 /**
926  * Provides either exactly one symbol, or XKB_KEY_NoSymbol.
927  */
928 XKB_EXPORT xkb_keysym_t
929 xkb_state_key_get_one_sym(struct xkb_state *state, xkb_keycode_t kc)
930 {
931     const xkb_keysym_t *syms;
932     xkb_keysym_t sym;
933     int num_syms;
934
935     num_syms = xkb_state_key_get_syms(state, kc, &syms);
936     if (num_syms != 1)
937         return XKB_KEY_NoSymbol;
938
939     sym = syms[0];
940
941     if (should_do_caps_transformation(state, kc))
942         sym = xkb_keysym_to_upper(sym);
943
944     return sym;
945 }
946
947 /*
948  * The caps and ctrl transformations require some special handling,
949  * so we cannot simply use xkb_state_get_one_sym() for them.
950  * In particular, if Control is set, we must try very hard to find
951  * some layout in which the keysym is ASCII and thus can be (maybe)
952  * converted to a control character. libX11 allows to disable this
953  * behavior with the XkbLC_ControlFallback (see XkbSetXlibControls(3)),
954  * but it is enabled by default, yippee.
955  */
956 static xkb_keysym_t
957 get_one_sym_for_string(struct xkb_state *state, xkb_keycode_t kc)
958 {
959     xkb_level_index_t level;
960     xkb_layout_index_t layout, num_layouts;
961     const xkb_keysym_t *syms;
962     int nsyms;
963     xkb_keysym_t sym;
964
965     layout = xkb_state_key_get_layout(state, kc);
966     num_layouts = xkb_keymap_num_layouts_for_key(state->keymap, kc);
967     level = xkb_state_key_get_level(state, kc, layout);
968     if (layout == XKB_LAYOUT_INVALID || num_layouts == 0 ||
969         level == XKB_LEVEL_INVALID)
970         return XKB_KEY_NoSymbol;
971
972     nsyms = xkb_keymap_key_get_syms_by_level(state->keymap, kc,
973                                              layout, level, &syms);
974     if (nsyms != 1)
975         return XKB_KEY_NoSymbol;
976     sym = syms[0];
977
978     if (should_do_ctrl_transformation(state, kc) && sym > 127u) {
979         for (xkb_layout_index_t i = 0; i < num_layouts; i++) {
980             level = xkb_state_key_get_level(state, kc, i);
981             if (level == XKB_LEVEL_INVALID)
982                 continue;
983
984             nsyms = xkb_keymap_key_get_syms_by_level(state->keymap, kc,
985                                                      i, level, &syms);
986             if (nsyms == 1 && syms[0] <= 127u) {
987                 sym = syms[0];
988                 break;
989             }
990         }
991     }
992
993     if (should_do_caps_transformation(state, kc)) {
994         sym = xkb_keysym_to_upper(sym);
995     }
996
997     return sym;
998 }
999
1000 XKB_EXPORT int
1001 xkb_state_key_get_utf8(struct xkb_state *state, xkb_keycode_t kc,
1002                        char *buffer, size_t size)
1003 {
1004     xkb_keysym_t sym;
1005     const xkb_keysym_t *syms;
1006     int nsyms;
1007     int offset;
1008     char tmp[7];
1009
1010     sym = get_one_sym_for_string(state, kc);
1011     if (sym != XKB_KEY_NoSymbol) {
1012         nsyms = 1; syms = &sym;
1013     }
1014     else {
1015         nsyms = xkb_state_key_get_syms(state, kc, &syms);
1016     }
1017
1018     /* Make sure not to truncate in the middle of a UTF-8 sequence. */
1019     offset = 0;
1020     for (int i = 0; i < nsyms; i++) {
1021         int ret = xkb_keysym_to_utf8(syms[i], tmp, sizeof(tmp));
1022         if (ret <= 0)
1023             goto err_bad;
1024
1025         ret--;
1026         if ((size_t) (offset + ret) <= size)
1027             memcpy(buffer + offset, tmp, ret);
1028         offset += ret;
1029     }
1030
1031     if ((size_t) offset >= size)
1032         goto err_trunc;
1033     buffer[offset] = '\0';
1034
1035     if (!is_valid_utf8(buffer, offset))
1036         goto err_bad;
1037
1038     if (offset == 1 && (unsigned int) buffer[0] <= 127u &&
1039         should_do_ctrl_transformation(state, kc))
1040         buffer[0] = XkbToControl(buffer[0]);
1041
1042     return offset;
1043
1044 err_trunc:
1045     if (size > 0)
1046         buffer[size - 1] = '\0';
1047     return offset;
1048
1049 err_bad:
1050     if (size > 0)
1051         buffer[0] = '\0';
1052     return 0;
1053 }
1054
1055 XKB_EXPORT uint32_t
1056 xkb_state_key_get_utf32(struct xkb_state *state, xkb_keycode_t kc)
1057 {
1058     xkb_keysym_t sym;
1059     uint32_t cp;
1060
1061     sym = get_one_sym_for_string(state, kc);
1062     cp = xkb_keysym_to_utf32(sym);
1063
1064     if (cp <= 127u && should_do_ctrl_transformation(state, kc))
1065         cp = (uint32_t) XkbToControl((char) cp);
1066
1067     return cp;
1068 }
1069
1070 /**
1071  * Serialises the requested modifier state into an xkb_mod_mask_t, with all
1072  * the same disclaimers as in xkb_state_update_mask.
1073  */
1074 XKB_EXPORT xkb_mod_mask_t
1075 xkb_state_serialize_mods(struct xkb_state *state,
1076                          enum xkb_state_component type)
1077 {
1078     xkb_mod_mask_t ret = 0;
1079
1080     if (type & XKB_STATE_MODS_EFFECTIVE)
1081         return state->components.mods;
1082
1083     if (type & XKB_STATE_MODS_DEPRESSED)
1084         ret |= state->components.base_mods;
1085     if (type & XKB_STATE_MODS_LATCHED)
1086         ret |= state->components.latched_mods;
1087     if (type & XKB_STATE_MODS_LOCKED)
1088         ret |= state->components.locked_mods;
1089
1090     return ret;
1091 }
1092
1093 /**
1094  * Serialises the requested group state, with all the same disclaimers as
1095  * in xkb_state_update_mask.
1096  */
1097 XKB_EXPORT xkb_layout_index_t
1098 xkb_state_serialize_layout(struct xkb_state *state,
1099                            enum xkb_state_component type)
1100 {
1101     xkb_layout_index_t ret = 0;
1102
1103     if (type & XKB_STATE_LAYOUT_EFFECTIVE)
1104         return state->components.group;
1105
1106     if (type & XKB_STATE_LAYOUT_DEPRESSED)
1107         ret += state->components.base_group;
1108     if (type & XKB_STATE_LAYOUT_LATCHED)
1109         ret += state->components.latched_group;
1110     if (type & XKB_STATE_LAYOUT_LOCKED)
1111         ret += state->components.locked_group;
1112
1113     return ret;
1114 }
1115
1116 /**
1117  * Gets a modifier mask and returns the resolved effective mask; this
1118  * is needed because some modifiers can also map to other modifiers, e.g.
1119  * the "NumLock" modifier usually also sets the "Mod2" modifier.
1120  */
1121 xkb_mod_mask_t
1122 mod_mask_get_effective(struct xkb_keymap *keymap, xkb_mod_mask_t mods)
1123 {
1124     const struct xkb_mod *mod;
1125     xkb_mod_index_t i;
1126     xkb_mod_mask_t mask;
1127
1128     /* The effective mask is only real mods for now. */
1129     mask = mods & MOD_REAL_MASK_ALL;
1130
1131     xkb_mods_enumerate(i, mod, &keymap->mods)
1132         if (mods & (1u << i))
1133             mask |= mod->mapping;
1134
1135     return mask;
1136 }
1137
1138 /**
1139  * Returns 1 if the given modifier is active with the specified type(s), 0 if
1140  * not, or -1 if the modifier is invalid.
1141  */
1142 XKB_EXPORT int
1143 xkb_state_mod_index_is_active(struct xkb_state *state,
1144                               xkb_mod_index_t idx,
1145                               enum xkb_state_component type)
1146 {
1147     if (idx >= xkb_keymap_num_mods(state->keymap))
1148         return -1;
1149
1150     return !!(xkb_state_serialize_mods(state, type) & (1u << idx));
1151 }
1152
1153 /**
1154  * Helper function for xkb_state_mod_indices_are_active and
1155  * xkb_state_mod_names_are_active.
1156  */
1157 static bool
1158 match_mod_masks(struct xkb_state *state,
1159                 enum xkb_state_component type,
1160                 enum xkb_state_match match,
1161                 xkb_mod_mask_t wanted)
1162 {
1163     xkb_mod_mask_t active = xkb_state_serialize_mods(state, type);
1164
1165     if (!(match & XKB_STATE_MATCH_NON_EXCLUSIVE) && (active & ~wanted))
1166         return false;
1167
1168     if (match & XKB_STATE_MATCH_ANY)
1169         return active & wanted;
1170
1171     return (active & wanted) == wanted;
1172 }
1173
1174 /**
1175  * Returns 1 if the modifiers are active with the specified type(s), 0 if
1176  * not, or -1 if any of the modifiers are invalid.
1177  */
1178 XKB_EXPORT int
1179 xkb_state_mod_indices_are_active(struct xkb_state *state,
1180                                  enum xkb_state_component type,
1181                                  enum xkb_state_match match,
1182                                  ...)
1183 {
1184     va_list ap;
1185     xkb_mod_mask_t wanted = 0;
1186     int ret = 0;
1187     xkb_mod_index_t num_mods = xkb_keymap_num_mods(state->keymap);
1188
1189     va_start(ap, match);
1190     while (1) {
1191         xkb_mod_index_t idx = va_arg(ap, xkb_mod_index_t);
1192         if (idx == XKB_MOD_INVALID)
1193             break;
1194         if (idx >= num_mods) {
1195             ret = -1;
1196             break;
1197         }
1198         wanted |= (1u << idx);
1199     }
1200     va_end(ap);
1201
1202     if (ret == -1)
1203         return ret;
1204
1205     return match_mod_masks(state, type, match, wanted);
1206 }
1207
1208 /**
1209  * Returns 1 if the given modifier is active with the specified type(s), 0 if
1210  * not, or -1 if the modifier is invalid.
1211  */
1212 XKB_EXPORT int
1213 xkb_state_mod_name_is_active(struct xkb_state *state, const char *name,
1214                              enum xkb_state_component type)
1215 {
1216     xkb_mod_index_t idx = xkb_keymap_mod_get_index(state->keymap, name);
1217
1218     if (idx == XKB_MOD_INVALID)
1219         return -1;
1220
1221     return xkb_state_mod_index_is_active(state, idx, type);
1222 }
1223
1224 /**
1225  * Returns 1 if the modifiers are active with the specified type(s), 0 if
1226  * not, or -1 if any of the modifiers are invalid.
1227  */
1228 XKB_EXPORT ATTR_NULL_SENTINEL int
1229 xkb_state_mod_names_are_active(struct xkb_state *state,
1230                                enum xkb_state_component type,
1231                                enum xkb_state_match match,
1232                                ...)
1233 {
1234     va_list ap;
1235     xkb_mod_mask_t wanted = 0;
1236     int ret = 0;
1237
1238     va_start(ap, match);
1239     while (1) {
1240         xkb_mod_index_t idx;
1241         const char *str = va_arg(ap, const char *);
1242         if (str == NULL)
1243             break;
1244         idx = xkb_keymap_mod_get_index(state->keymap, str);
1245         if (idx == XKB_MOD_INVALID) {
1246             ret = -1;
1247             break;
1248         }
1249         wanted |= (1u << idx);
1250     }
1251     va_end(ap);
1252
1253     if (ret == -1)
1254         return ret;
1255
1256     return match_mod_masks(state, type, match, wanted);
1257 }
1258
1259 /**
1260  * Returns 1 if the given group is active with the specified type(s), 0 if
1261  * not, or -1 if the group is invalid.
1262  */
1263 XKB_EXPORT int
1264 xkb_state_layout_index_is_active(struct xkb_state *state,
1265                                 xkb_layout_index_t idx,
1266                                 enum xkb_state_component type)
1267 {
1268     int ret = 0;
1269
1270     if (idx >= state->keymap->num_groups)
1271         return -1;
1272
1273     if (type & XKB_STATE_LAYOUT_EFFECTIVE)
1274         ret |= (state->components.group == idx);
1275     if (type & XKB_STATE_LAYOUT_DEPRESSED)
1276         ret |= (state->components.base_group == (int32_t) idx);
1277     if (type & XKB_STATE_LAYOUT_LATCHED)
1278         ret |= (state->components.latched_group == (int32_t) idx);
1279     if (type & XKB_STATE_LAYOUT_LOCKED)
1280         ret |= (state->components.locked_group == (int32_t) idx);
1281
1282     return ret;
1283 }
1284
1285 /**
1286  * Returns 1 if the given modifier is active with the specified type(s), 0 if
1287  * not, or -1 if the modifier is invalid.
1288  */
1289 XKB_EXPORT int
1290 xkb_state_layout_name_is_active(struct xkb_state *state, const char *name,
1291                                 enum xkb_state_component type)
1292 {
1293     xkb_layout_index_t idx = xkb_keymap_layout_get_index(state->keymap, name);
1294
1295     if (idx == XKB_LAYOUT_INVALID)
1296         return -1;
1297
1298     return xkb_state_layout_index_is_active(state, idx, type);
1299 }
1300
1301 /**
1302  * Returns 1 if the given LED is active, 0 if not, or -1 if the LED is invalid.
1303  */
1304 XKB_EXPORT int
1305 xkb_state_led_index_is_active(struct xkb_state *state, xkb_led_index_t idx)
1306 {
1307     if (idx >= state->keymap->num_leds ||
1308         state->keymap->leds[idx].name == XKB_ATOM_NONE)
1309         return -1;
1310
1311     return !!(state->components.leds & (1u << idx));
1312 }
1313
1314 /**
1315  * Returns 1 if the given LED is active, 0 if not, or -1 if the LED is invalid.
1316  */
1317 XKB_EXPORT int
1318 xkb_state_led_name_is_active(struct xkb_state *state, const char *name)
1319 {
1320     xkb_led_index_t idx = xkb_keymap_led_get_index(state->keymap, name);
1321
1322     if (idx == XKB_LED_INVALID)
1323         return -1;
1324
1325     return xkb_state_led_index_is_active(state, idx);
1326 }
1327
1328 /**
1329  * See:
1330  * - XkbTranslateKeyCode(3), mod_rtrn return value, from libX11.
1331  * - MyEnhancedXkbTranslateKeyCode(), a modification of the above, from GTK+.
1332  */
1333 static xkb_mod_mask_t
1334 key_get_consumed(struct xkb_state *state, const struct xkb_key *key,
1335                  enum xkb_consumed_mode mode)
1336 {
1337     const struct xkb_key_type *type;
1338     const struct xkb_key_type_entry *matching_entry;
1339     xkb_mod_mask_t preserve = 0;
1340     xkb_layout_index_t group;
1341     xkb_mod_mask_t consumed = 0;
1342
1343     group = xkb_state_key_get_layout(state, key->keycode);
1344     if (group == XKB_LAYOUT_INVALID)
1345         return 0;
1346
1347     type = key->groups[group].type;
1348
1349     matching_entry = get_entry_for_key_state(state, key, group);
1350     if (matching_entry)
1351         preserve = matching_entry->preserve.mask;
1352
1353     switch (mode) {
1354     case XKB_CONSUMED_MODE_XKB:
1355         consumed = type->mods.mask;
1356         break;
1357
1358     case XKB_CONSUMED_MODE_GTK: {
1359         const struct xkb_key_type_entry *no_mods_entry;
1360         xkb_level_index_t no_mods_leveli;
1361         const struct xkb_level *no_mods_level, *level;
1362
1363         no_mods_entry = get_entry_for_mods(type, 0);
1364         no_mods_leveli = no_mods_entry ? no_mods_entry->level : 0;
1365         no_mods_level = &key->groups[group].levels[no_mods_leveli];
1366
1367         for (unsigned i = 0; i < type->num_entries; i++) {
1368             const struct xkb_key_type_entry *entry = &type->entries[i];
1369             if (!entry_is_active(entry))
1370                 continue;
1371
1372             level = &key->groups[group].levels[entry->level];
1373             if (XkbLevelsSameSyms(level, no_mods_level))
1374                 continue;
1375
1376             if (entry == matching_entry || one_bit_set(entry->mods.mask))
1377                 consumed |= entry->mods.mask & ~entry->preserve.mask;
1378         }
1379         break;
1380     }
1381     }
1382
1383     return consumed & ~preserve;
1384 }
1385
1386 XKB_EXPORT int
1387 xkb_state_mod_index_is_consumed2(struct xkb_state *state, xkb_keycode_t kc,
1388                                  xkb_mod_index_t idx,
1389                                  enum xkb_consumed_mode mode)
1390 {
1391     const struct xkb_key *key = XkbKey(state->keymap, kc);
1392
1393     if (!key || idx >= xkb_keymap_num_mods(state->keymap))
1394         return -1;
1395
1396     return !!((1u << idx) & key_get_consumed(state, key, mode));
1397 }
1398
1399 XKB_EXPORT int
1400 xkb_state_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t kc,
1401                                 xkb_mod_index_t idx)
1402 {
1403     return xkb_state_mod_index_is_consumed2(state, kc, idx,
1404                                             XKB_CONSUMED_MODE_XKB);
1405 }
1406
1407 XKB_EXPORT xkb_mod_mask_t
1408 xkb_state_mod_mask_remove_consumed(struct xkb_state *state, xkb_keycode_t kc,
1409                                    xkb_mod_mask_t mask)
1410 {
1411     const struct xkb_key *key = XkbKey(state->keymap, kc);
1412
1413     if (!key)
1414         return 0;
1415
1416     return mask & ~key_get_consumed(state, key, XKB_CONSUMED_MODE_XKB);
1417 }
1418
1419 XKB_EXPORT xkb_mod_mask_t
1420 xkb_state_key_get_consumed_mods2(struct xkb_state *state, xkb_keycode_t kc,
1421                                  enum xkb_consumed_mode mode)
1422 {
1423     const struct xkb_key *key;
1424
1425     switch (mode) {
1426     case XKB_CONSUMED_MODE_XKB:
1427     case XKB_CONSUMED_MODE_GTK:
1428         break;
1429     default:
1430         log_err_func(state->keymap->ctx,
1431                      "unrecognized consumed modifiers mode: %d\n", mode);
1432         return 0;
1433     }
1434
1435     key = XkbKey(state->keymap, kc);
1436     if (!key)
1437         return 0;
1438
1439     return key_get_consumed(state, key, mode);
1440 }
1441
1442 XKB_EXPORT xkb_mod_mask_t
1443 xkb_state_key_get_consumed_mods(struct xkb_state *state, xkb_keycode_t kc)
1444 {
1445     return xkb_state_key_get_consumed_mods2(state, kc, XKB_CONSUMED_MODE_XKB);
1446 }