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