Organize src/ and test/ headers
[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 "map.h"
63
64 struct xkb_filter {
65     union xkb_action action;
66     const struct xkb_key *key;
67     uint32_t priv;
68     int (*func)(struct xkb_state *state,
69                 struct xkb_filter *filter,
70                 const struct xkb_key *key,
71                 enum xkb_key_direction direction);
72     int refcnt;
73 };
74
75 struct xkb_state {
76     xkb_group_index_t base_group; /**< depressed */
77     xkb_group_index_t latched_group;
78     xkb_group_index_t locked_group;
79     xkb_group_index_t group; /**< effective */
80
81     xkb_mod_mask_t base_mods; /**< depressed */
82     xkb_mod_mask_t latched_mods;
83     xkb_mod_mask_t locked_mods;
84     xkb_mod_mask_t mods; /**< effective */
85
86     /*
87      * At each event, we accumulate all the needed modifications to the base
88      * modifiers, and apply them at the end. These keep track of this state.
89      */
90     xkb_mod_mask_t set_mods;
91     xkb_mod_mask_t clear_mods;
92     /*
93      * We mustn't clear a base modifier if there's another depressed key
94      * which affects it, e.g. given this sequence
95      * < Left Shift down, Right Shift down, Left Shift Up >
96      * the modifier should still be set. This keeps the count.
97      */
98     int16_t mod_key_count[sizeof(xkb_mod_mask_t) * 8];
99
100     uint32_t leds;
101
102     int refcnt;
103     darray(struct xkb_filter) filters;
104     struct xkb_keymap *keymap;
105 };
106
107 static const union xkb_action fake = { .type = ACTION_TYPE_NONE };
108
109 static const union xkb_action *
110 xkb_key_get_action(struct xkb_state *state, const struct xkb_key *key)
111 {
112     xkb_group_index_t group;
113     xkb_level_index_t level;
114
115     if (!key->actions)
116         return &fake;
117
118     group = xkb_key_get_group(state, key);
119     if (group == XKB_GROUP_INVALID)
120         return &fake;
121
122     level = xkb_key_get_level(state, key, group);
123     if (level == XKB_LEVEL_INVALID)
124         return &fake;
125
126     return XkbKeyActionEntry(key, group, level);
127 }
128
129 static struct xkb_filter *
130 xkb_filter_new(struct xkb_state *state)
131 {
132     struct xkb_filter *filter = NULL, *iter;
133
134     darray_foreach(iter, state->filters) {
135         if (iter->func)
136             continue;
137         filter = iter;
138         break;
139     }
140
141     if (!filter) {
142         darray_resize0(state->filters, darray_size(state->filters) + 1);
143         filter = &darray_item(state->filters, darray_size(state->filters) -1);
144     }
145
146     filter->refcnt = 1;
147     return filter;
148 }
149
150 /***====================================================================***/
151
152 static int
153 xkb_filter_group_set_func(struct xkb_state *state,
154                           struct xkb_filter *filter,
155                           const struct xkb_key *key,
156                           enum xkb_key_direction direction)
157 {
158     if (key != filter->key) {
159         filter->action.group.flags &= ~ACTION_LOCK_CLEAR;
160         return 1;
161     }
162
163     if (direction == XKB_KEY_DOWN) {
164         filter->refcnt++;
165         return 0;
166     }
167     else if (--filter->refcnt > 0) {
168         return 0;
169     }
170
171     state->base_group = filter->priv;
172
173     if (filter->action.group.flags & ACTION_LOCK_CLEAR)
174         state->locked_group = 0;
175
176     filter->func = NULL;
177     return 1;
178 }
179
180 static void
181 xkb_filter_group_set_new(struct xkb_state *state, struct xkb_filter *filter)
182 {
183     filter->priv = state->base_group;
184     if (filter->action.group.flags & ACTION_ABSOLUTE_SWITCH)
185         state->base_group = filter->action.group.group;
186     else
187         state->base_group += filter->action.group.group;
188 }
189
190 static int
191 xkb_filter_group_lock_func(struct xkb_state *state,
192                            struct xkb_filter *filter,
193                            const struct xkb_key *key,
194                            enum xkb_key_direction direction)
195 {
196     if (key != filter->key)
197         return 1;
198
199     if (direction == XKB_KEY_DOWN) {
200         filter->refcnt++;
201         return 0;
202     }
203     if (--filter->refcnt > 0)
204         return 0;
205
206     filter->func = NULL;
207     return 1;
208 }
209
210 static void
211 xkb_filter_group_lock_new(struct xkb_state *state, struct xkb_filter *filter)
212 {
213     if (filter->action.group.flags & ACTION_ABSOLUTE_SWITCH)
214         state->locked_group = filter->action.group.group;
215     else
216         state->locked_group += filter->action.group.group;
217 }
218
219 static int
220 xkb_filter_mod_set_func(struct xkb_state *state,
221                         struct xkb_filter *filter,
222                         const struct xkb_key *key,
223                         enum xkb_key_direction direction)
224 {
225     if (key != filter->key) {
226         filter->action.mods.flags &= ~ACTION_LOCK_CLEAR;
227         return 1;
228     }
229
230     if (direction == XKB_KEY_DOWN) {
231         filter->refcnt++;
232         return 0;
233     }
234     else if (--filter->refcnt > 0) {
235         return 0;
236     }
237
238     state->clear_mods = filter->action.mods.mods.mask;
239     if (filter->action.mods.flags & ACTION_LOCK_CLEAR)
240         state->locked_mods &= ~filter->action.mods.mods.mask;
241
242     filter->func = NULL;
243     return 1;
244 }
245
246 static void
247 xkb_filter_mod_set_new(struct xkb_state *state, struct xkb_filter *filter)
248 {
249     state->set_mods = filter->action.mods.mods.mask;
250 }
251
252 static int
253 xkb_filter_mod_lock_func(struct xkb_state *state,
254                          struct xkb_filter *filter,
255                          const struct xkb_key *key,
256                          enum xkb_key_direction direction)
257 {
258     if (key != filter->key)
259         return 1;
260
261     if (direction == XKB_KEY_DOWN) {
262         filter->refcnt++;
263         return 0;
264     }
265     if (--filter->refcnt > 0)
266         return 0;
267
268     state->locked_mods &= ~filter->priv;
269
270     filter->func = NULL;
271     return 1;
272 }
273
274 static void
275 xkb_filter_mod_lock_new(struct xkb_state *state, struct xkb_filter *filter)
276 {
277     filter->priv = state->locked_mods & filter->action.mods.mods.mask;
278     state->locked_mods |= filter->action.mods.mods.mask;
279 }
280
281 enum xkb_key_latch_state {
282     NO_LATCH,
283     LATCH_KEY_DOWN,
284     LATCH_PENDING,
285 };
286
287 static bool
288 xkb_action_breaks_latch(const union xkb_action *action)
289 {
290     switch (action->type) {
291     case ACTION_TYPE_NONE:
292     case ACTION_TYPE_PTR_BUTTON:
293     case ACTION_TYPE_PTR_LOCK:
294     case ACTION_TYPE_CTRL_SET:
295     case ACTION_TYPE_CTRL_LOCK:
296     case ACTION_TYPE_KEY_REDIRECT:
297     case ACTION_TYPE_SWITCH_VT:
298     case ACTION_TYPE_TERMINATE:
299         return true;
300     default:
301         return false;
302     }
303 }
304
305 static int
306 xkb_filter_mod_latch_func(struct xkb_state *state,
307                           struct xkb_filter *filter,
308                           const struct xkb_key *key,
309                           enum xkb_key_direction direction)
310 {
311     enum xkb_key_latch_state latch = filter->priv;
312
313     if (direction == XKB_KEY_DOWN && latch == LATCH_PENDING) {
314         /* If this is a new keypress and we're awaiting our single latched
315          * keypress, then either break the latch if any random key is pressed,
316          * or promote it to a lock or plain base set if it's the same
317          * modifier. */
318         const union xkb_action *action = xkb_key_get_action(state, key);
319         if (action->type == ACTION_TYPE_MOD_LATCH &&
320             action->mods.flags == filter->action.mods.flags &&
321             action->mods.mods.mask == filter->action.mods.mods.mask) {
322             filter->action = *action;
323             if (filter->action.mods.flags & ACTION_LATCH_TO_LOCK) {
324                 filter->action.type = ACTION_TYPE_MOD_LOCK;
325                 filter->func = xkb_filter_mod_lock_func;
326                 state->locked_mods |= filter->action.mods.mods.mask;
327             }
328             else {
329                 filter->action.type = ACTION_TYPE_MOD_SET;
330                 filter->func = xkb_filter_mod_set_func;
331                 state->set_mods = filter->action.mods.mods.mask;
332             }
333             filter->key = key;
334             state->latched_mods &= ~filter->action.mods.mods.mask;
335             /* XXX beep beep! */
336             return 0;
337         }
338         else if (xkb_action_breaks_latch(action)) {
339             /* XXX: This may be totally broken, we might need to break the
340              *      latch in the next run after this press? */
341             state->latched_mods &= ~filter->action.mods.mods.mask;
342             filter->func = NULL;
343             return 1;
344         }
345     }
346     else if (direction == XKB_KEY_UP && key == filter->key) {
347         /* Our key got released.  If we've set it to clear locks, and we
348          * currently have the same modifiers locked, then release them and
349          * don't actually latch.  Else we've actually hit the latching
350          * stage, so set PENDING and move our modifier from base to
351          * latched. */
352         if (latch == NO_LATCH ||
353             ((filter->action.mods.flags & ACTION_LOCK_CLEAR) &&
354              (state->locked_mods & filter->action.mods.mods.mask) ==
355              filter->action.mods.mods.mask)) {
356             /* XXX: We might be a bit overenthusiastic about clearing
357              *      mods other filters have set here? */
358             if (latch == LATCH_PENDING)
359                 state->latched_mods &= ~filter->action.mods.mods.mask;
360             else
361                 state->clear_mods = filter->action.mods.mods.mask;
362             state->locked_mods &= ~filter->action.mods.mods.mask;
363             filter->func = NULL;
364         }
365         else {
366             latch = LATCH_PENDING;
367             state->clear_mods = filter->action.mods.mods.mask;
368             state->latched_mods |= filter->action.mods.mods.mask;
369             /* XXX beep beep! */
370         }
371     }
372     else if (direction == XKB_KEY_DOWN && latch == LATCH_KEY_DOWN) {
373         /* Someone's pressed another key while we've still got the latching
374          * key held down, so keep the base modifier state active (from
375          * xkb_filter_mod_latch_new), but don't trip the latch, just clear
376          * it as soon as the modifier gets released. */
377         latch = NO_LATCH;
378     }
379
380     filter->priv = latch;
381
382     return 1;
383 }
384
385 static void
386 xkb_filter_mod_latch_new(struct xkb_state *state, struct xkb_filter *filter)
387 {
388     filter->priv = LATCH_KEY_DOWN;
389     state->set_mods = filter->action.mods.mods.mask;
390 }
391
392 static const struct {
393     void (*new)(struct xkb_state *state, struct xkb_filter *filter);
394     int (*func)(struct xkb_state *state, struct xkb_filter *filter,
395                 const struct xkb_key *key, enum xkb_key_direction direction);
396 } filter_action_funcs[_ACTION_TYPE_NUM_ENTRIES] = {
397     [ACTION_TYPE_MOD_SET]    = { xkb_filter_mod_set_new,
398                                  xkb_filter_mod_set_func },
399     [ACTION_TYPE_MOD_LATCH]  = { xkb_filter_mod_latch_new,
400                                  xkb_filter_mod_latch_func },
401     [ACTION_TYPE_MOD_LOCK]   = { xkb_filter_mod_lock_new,
402                                  xkb_filter_mod_lock_func },
403     [ACTION_TYPE_GROUP_SET]  = { xkb_filter_group_set_new,
404                                  xkb_filter_group_set_func },
405     [ACTION_TYPE_GROUP_LOCK] = { xkb_filter_group_lock_new,
406                                  xkb_filter_group_lock_func },
407 };
408
409 /**
410  * Applies any relevant filters to the key, first from the list of filters
411  * that are currently active, then if no filter has claimed the key, possibly
412  * apply a new filter from the key action.
413  */
414 static void
415 xkb_filter_apply_all(struct xkb_state *state,
416                      const struct xkb_key *key,
417                      enum xkb_key_direction direction)
418 {
419     struct xkb_filter *filter;
420     const union xkb_action *action;
421     int send = 1;
422
423     /* First run through all the currently active filters and see if any of
424      * them have claimed this event. */
425     darray_foreach(filter, state->filters) {
426         if (!filter->func)
427             continue;
428         send &= filter->func(state, filter, key, direction);
429     }
430
431     if (!send || direction == XKB_KEY_UP)
432         return;
433
434     action = xkb_key_get_action(state, key);
435     if (!filter_action_funcs[action->type].new)
436         return;
437
438     filter = xkb_filter_new(state);
439     if (!filter)
440         return; /* WSGO */
441
442     filter->key = key;
443     filter->func = filter_action_funcs[action->type].func;
444     filter->action = *action;
445     filter_action_funcs[action->type].new(state, filter);
446 }
447
448 XKB_EXPORT struct xkb_state *
449 xkb_state_new(struct xkb_keymap *keymap)
450 {
451     struct xkb_state *ret;
452
453     ret = calloc(sizeof(*ret), 1);
454     if (!ret)
455         return NULL;
456
457     ret->refcnt = 1;
458     ret->keymap = xkb_map_ref(keymap);
459
460     return ret;
461 }
462
463 XKB_EXPORT struct xkb_state *
464 xkb_state_ref(struct xkb_state *state)
465 {
466     state->refcnt++;
467     return state;
468 }
469
470 XKB_EXPORT void
471 xkb_state_unref(struct xkb_state *state)
472 {
473     if (--state->refcnt > 0)
474         return;
475
476     xkb_map_unref(state->keymap);
477     darray_free(state->filters);
478     free(state);
479 }
480
481 XKB_EXPORT struct xkb_keymap *
482 xkb_state_get_map(struct xkb_state *state)
483 {
484     return state->keymap;
485 }
486
487 /**
488  * Update the LED state to match the rest of the xkb_state.
489  */
490 static void
491 xkb_state_led_update_all(struct xkb_state *state)
492 {
493     xkb_led_index_t led;
494
495     state->leds = 0;
496
497     for (led = 0; led < XKB_NUM_INDICATORS; led++) {
498         struct xkb_indicator_map *map = &state->keymap->indicators[led];
499         xkb_mod_mask_t mod_mask = 0;
500         uint32_t group_mask = 0;
501
502         if (map->which_mods & XKB_STATE_DEPRESSED)
503             mod_mask |= state->base_mods;
504         if (map->which_mods & XKB_STATE_LATCHED)
505             mod_mask |= state->latched_mods;
506         if (map->which_mods & XKB_STATE_LOCKED)
507             mod_mask |= state->locked_mods;
508         if ((map->mods.mask & mod_mask))
509             state->leds |= (1 << led);
510
511         if (map->which_groups & XKB_STATE_DEPRESSED)
512             group_mask |= (1 << state->base_group);
513         if (map->which_groups & XKB_STATE_LATCHED)
514             group_mask |= (1 << state->latched_group);
515         if (map->which_groups & XKB_STATE_LOCKED)
516             group_mask |= (1 << state->locked_group);
517         if ((map->groups & group_mask))
518             state->leds |= (1 << led);
519
520         if (map->ctrls) {
521             if ((map->ctrls & state->keymap->enabled_ctrls))
522                 state->leds |= (1 << led);
523         }
524     }
525 }
526
527 /**
528  * Calculates the derived state (effective mods/group and LEDs) from an
529  * up-to-date xkb_state.
530  */
531 static void
532 xkb_state_update_derived(struct xkb_state *state)
533 {
534     state->mods =
535         (state->base_mods | state->latched_mods | state->locked_mods);
536     /* FIXME: Clamp/wrap locked_group */
537     state->group = state->locked_group + state->base_group +
538                    state->latched_group;
539     /* FIXME: Clamp/wrap effective group */
540
541     xkb_state_led_update_all(state);
542 }
543
544 /**
545  * Given a particular key event, updates the state structure to reflect the
546  * new modifiers.
547  */
548 XKB_EXPORT void
549 xkb_state_update_key(struct xkb_state *state, xkb_keycode_t kc,
550                      enum xkb_key_direction direction)
551 {
552     xkb_mod_index_t i;
553     xkb_mod_mask_t bit;
554     const struct xkb_key *key = XkbKey(state->keymap, kc);
555     if (!key)
556         return;
557
558     state->set_mods = 0;
559     state->clear_mods = 0;
560
561     xkb_filter_apply_all(state, key, direction);
562
563     for (i = 0, bit = 1; state->set_mods; i++, bit <<= 1) {
564         if (state->set_mods & bit) {
565             state->mod_key_count[i]++;
566             state->base_mods |= bit;
567             state->set_mods &= ~bit;
568         }
569     }
570
571     for (i = 0, bit = 1; state->clear_mods; i++, bit <<= 1) {
572         if (state->clear_mods & bit) {
573             state->mod_key_count[i]--;
574             if (state->mod_key_count[i] <= 0) {
575                 state->base_mods &= ~bit;
576                 state->mod_key_count[i] = 0;
577             }
578             state->clear_mods &= ~bit;
579         }
580     }
581
582     xkb_state_update_derived(state);
583 }
584
585 /**
586  * Updates the state from a set of explicit masks as gained from
587  * xkb_state_serialize_mods and xkb_state_serialize_groups.  As noted in the
588  * documentation for these functions in xkbcommon.h, this round-trip is
589  * lossy, and should only be used to update a slave state mirroring the
590  * master, e.g. in a client/server window system.
591  */
592 XKB_EXPORT void
593 xkb_state_update_mask(struct xkb_state *state,
594                       xkb_mod_mask_t base_mods,
595                       xkb_mod_mask_t latched_mods,
596                       xkb_mod_mask_t locked_mods,
597                       xkb_group_index_t base_group,
598                       xkb_group_index_t latched_group,
599                       xkb_group_index_t locked_group)
600 {
601     xkb_mod_index_t num_mods;
602     xkb_mod_index_t idx;
603
604     state->base_mods = 0;
605     state->latched_mods = 0;
606     state->locked_mods = 0;
607     num_mods = xkb_map_num_mods(state->keymap);
608
609     for (idx = 0; idx < num_mods; idx++) {
610         xkb_mod_mask_t mod = (1 << idx);
611         if (base_mods & mod)
612             state->base_mods |= mod;
613         if (latched_mods & mod)
614             state->latched_mods |= mod;
615         if (locked_mods & mod)
616             state->locked_mods |= mod;
617     }
618
619     state->base_group = base_group;
620     state->latched_group = latched_group;
621     state->locked_group = locked_group;
622
623     xkb_state_update_derived(state);
624 }
625
626 /**
627  * Serialises the requested modifier state into an xkb_mod_mask_t, with all
628  * the same disclaimers as in xkb_state_update_mask.
629  */
630 XKB_EXPORT xkb_mod_mask_t
631 xkb_state_serialize_mods(struct xkb_state *state,
632                          enum xkb_state_component type)
633 {
634     xkb_mod_mask_t ret = 0;
635
636     if (type == XKB_STATE_EFFECTIVE)
637         return state->mods;
638
639     if (type & XKB_STATE_DEPRESSED)
640         ret |= state->base_mods;
641     if (type & XKB_STATE_LATCHED)
642         ret |= state->latched_mods;
643     if (type & XKB_STATE_LOCKED)
644         ret |= state->locked_mods;
645
646     return ret;
647 }
648
649 /**
650  * Serialises the requested group state, with all the same disclaimers as
651  * in xkb_state_update_mask.
652  */
653 XKB_EXPORT xkb_group_index_t
654 xkb_state_serialize_group(struct xkb_state *state,
655                           enum xkb_state_component type)
656 {
657     xkb_group_index_t ret = 0;
658
659     if (type == XKB_STATE_EFFECTIVE)
660         return state->group;
661
662     if (type & XKB_STATE_DEPRESSED)
663         ret += state->base_group;
664     if (type & XKB_STATE_LATCHED)
665         ret += state->latched_group;
666     if (type & XKB_STATE_LOCKED)
667         ret += state->locked_group;
668
669     return ret;
670 }
671
672 /**
673  * Returns 1 if the given modifier is active with the specified type(s), 0 if
674  * not, or -1 if the modifier is invalid.
675  */
676 XKB_EXPORT int
677 xkb_state_mod_index_is_active(struct xkb_state *state,
678                               xkb_mod_index_t idx,
679                               enum xkb_state_component type)
680 {
681     int ret = 0;
682
683     if (idx >= xkb_map_num_mods(state->keymap))
684         return -1;
685
686     if (type & XKB_STATE_DEPRESSED)
687         ret |= (state->base_mods & (1 << idx));
688     if (type & XKB_STATE_LATCHED)
689         ret |= (state->latched_mods & (1 << idx));
690     if (type & XKB_STATE_LOCKED)
691         ret |= (state->locked_mods & (1 << idx));
692
693     return !!ret;
694 }
695
696 /**
697  * Helper function for xkb_state_mod_indices_are_active and
698  * xkb_state_mod_names_are_active.
699  */
700 static int
701 match_mod_masks(struct xkb_state *state, enum xkb_state_match match,
702                 uint32_t wanted)
703 {
704     uint32_t active = xkb_state_serialize_mods(state, XKB_STATE_EFFECTIVE);
705
706     if (!(match & XKB_STATE_MATCH_NON_EXCLUSIVE) && (active & ~wanted))
707         return 0;
708
709     if (match & XKB_STATE_MATCH_ANY)
710         return !!(active & wanted);
711     else
712         return (active & wanted) == wanted;
713
714     return 0;
715 }
716
717 /**
718  * Returns 1 if the modifiers are active with the specified type(s), 0 if
719  * not, or -1 if any of the modifiers are invalid.
720  */
721 XKB_EXPORT int
722 xkb_state_mod_indices_are_active(struct xkb_state *state,
723                                  enum xkb_state_component type,
724                                  enum xkb_state_match match,
725                                  ...)
726 {
727     va_list ap;
728     xkb_mod_index_t idx = 0;
729     uint32_t wanted = 0;
730     int ret = 0;
731     xkb_mod_index_t num_mods = xkb_map_num_mods(state->keymap);
732
733     va_start(ap, match);
734     while (1) {
735         idx = va_arg(ap, xkb_mod_index_t);
736         if (idx == XKB_MOD_INVALID)
737             break;
738         if (idx >= num_mods) {
739             ret = -1;
740             break;
741         }
742         wanted |= (1 << idx);
743     }
744     va_end(ap);
745
746     if (ret == -1)
747         return ret;
748
749     return match_mod_masks(state, match, wanted);
750 }
751
752 /**
753  * Returns 1 if the given modifier is active with the specified type(s), 0 if
754  * not, or -1 if the modifier is invalid.
755  */
756 XKB_EXPORT int
757 xkb_state_mod_name_is_active(struct xkb_state *state, const char *name,
758                              enum xkb_state_component type)
759 {
760     xkb_mod_index_t idx = xkb_map_mod_get_index(state->keymap, name);
761
762     if (idx == XKB_MOD_INVALID)
763         return -1;
764
765     return xkb_state_mod_index_is_active(state, idx, type);
766 }
767
768 /**
769  * Returns 1 if the modifiers are active with the specified type(s), 0 if
770  * not, or -1 if any of the modifiers are invalid.
771  */
772 XKB_EXPORT ATTR_NULL_SENTINEL int
773 xkb_state_mod_names_are_active(struct xkb_state *state,
774                                enum xkb_state_component type,
775                                enum xkb_state_match match,
776                                ...)
777 {
778     va_list ap;
779     xkb_mod_index_t idx = 0;
780     const char *str;
781     uint32_t wanted = 0;
782     int ret = 0;
783
784     va_start(ap, match);
785     while (1) {
786         str = va_arg(ap, const char *);
787         if (str == NULL)
788             break;
789         idx = xkb_map_mod_get_index(state->keymap, str);
790         if (idx == XKB_MOD_INVALID) {
791             ret = -1;
792             break;
793         }
794         wanted |= (1 << idx);
795     }
796     va_end(ap);
797
798     if (ret == -1)
799         return ret;
800
801     return match_mod_masks(state, match, wanted);
802 }
803
804 /**
805  * Returns 1 if the given group is active with the specified type(s), 0 if
806  * not, or -1 if the group is invalid.
807  */
808 XKB_EXPORT int
809 xkb_state_group_index_is_active(struct xkb_state *state,
810                                 xkb_group_index_t idx,
811                                 enum xkb_state_component type)
812 {
813     int ret = 0;
814
815     if (idx >= xkb_map_num_groups(state->keymap))
816         return -1;
817
818     if (type & XKB_STATE_DEPRESSED)
819         ret |= (state->base_group == idx);
820     if (type & XKB_STATE_LATCHED)
821         ret |= (state->latched_group == idx);
822     if (type & XKB_STATE_LOCKED)
823         ret |= (state->locked_group == idx);
824
825     return ret;
826 }
827
828 /**
829  * Returns 1 if the given modifier is active with the specified type(s), 0 if
830  * not, or -1 if the modifier is invalid.
831  */
832 XKB_EXPORT int
833 xkb_state_group_name_is_active(struct xkb_state *state, const char *name,
834                                enum xkb_state_component type)
835 {
836     xkb_group_index_t idx = xkb_map_group_get_index(state->keymap, name);
837
838     if (idx == XKB_GROUP_INVALID)
839         return -1;
840
841     return xkb_state_group_index_is_active(state, idx, type);
842 }
843
844 /**
845  * Returns 1 if the given LED is active, 0 if not, or -1 if the LED is invalid.
846  */
847 XKB_EXPORT int
848 xkb_state_led_index_is_active(struct xkb_state *state, xkb_led_index_t idx)
849 {
850     if (idx >= xkb_map_num_leds(state->keymap))
851         return -1;
852
853     return !!(state->leds & (1 << idx));
854 }
855
856 /**
857  * Returns 1 if the given LED is active, 0 if not, or -1 if the LED is invalid.
858  */
859 XKB_EXPORT int
860 xkb_state_led_name_is_active(struct xkb_state *state, const char *name)
861 {
862     xkb_led_index_t idx = xkb_map_led_get_index(state->keymap, name);
863
864     if (idx == XKB_LED_INVALID)
865         return -1;
866
867     return xkb_state_led_index_is_active(state, idx);
868 }