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