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