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