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