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