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