Remove MERGE_ALT_FORM merge mode
[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 keycode;
70     uint32_t priv;
71     int (*func)(struct xkb_filter *filter, xkb_keycode_t key,
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 key)
111 {
112     int group, level;
113
114     if (!XkbKeyHasActions(state->keymap, key) ||
115         !XkbKeycodeInRange(state->keymap, key)) {
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, key);
123     level = xkb_key_get_level(state, key, group);
124
125     return XkbKeyActionEntry(state->keymap, key, level, group);
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 keycode,
155                           enum xkb_key_direction direction)
156 {
157     if (keycode != filter->keycode) {
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 keycode,
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->keycode = keycode;
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 keycode,
207                            enum xkb_key_direction direction)
208 {
209     if (keycode != filter->keycode)
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 keycode,
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->keycode = keycode;
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 keycode,
246                         enum xkb_key_direction direction)
247 {
248     if (keycode != filter->keycode) {
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 keycode,
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->keycode = keycode;
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 keycode,
289                          enum xkb_key_direction direction)
290 {
291     if (keycode != filter->keycode)
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 keycode,
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->keycode = keycode;
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 keycode,
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, keycode);
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->keycode = keycode;
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 && keycode == filter->keycode) {
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 keycode,
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->keycode = keycode;
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 key,
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, key, direction);
446     }
447
448     if (!send || direction == XKB_KEY_UP)
449         return;
450
451     act = xkb_key_get_action(state, key);
452     switch (act->type) {
453     case XkbSA_SetMods:
454         send = xkb_filter_mod_set_new(state, key, act);
455         break;
456     case XkbSA_LatchMods:
457         send = xkb_filter_mod_latch_new(state, key, act);
458         break;
459     case XkbSA_LockMods:
460         send = xkb_filter_mod_lock_new(state, key, act);
461         break;
462     case XkbSA_SetGroup:
463         send = xkb_filter_group_set_new(state, key, 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, key, 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->maps[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->ctrls->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 = (state->base_mods | state->latched_mods | state->locked_mods);
579     /* FIXME: Clamp/wrap locked_group */
580     state->group = state->locked_group + state->base_group +
581                    state->latched_group;
582     /* FIXME: Clamp/wrap effective group */
583
584     xkb_state_led_update_all(state);
585 }
586
587 /**
588  * Given a particular key event, updates the state structure to reflect the
589  * new modifiers.
590  */
591 _X_EXPORT void
592 xkb_state_update_key(struct xkb_state *state, xkb_keycode_t key,
593                      enum xkb_key_direction direction)
594 {
595     xkb_mod_index_t i;
596     xkb_mod_mask_t bit;
597
598     state->set_mods = 0;
599     state->clear_mods = 0;
600
601     xkb_filter_apply_all(state, key, direction);
602
603     for (i = 0, bit = 1; state->set_mods; i++, bit <<= 1) {
604         if (state->set_mods & bit) {
605             state->mod_key_count[i]++;
606             state->base_mods |= bit;
607             state->set_mods &= ~bit;
608         }
609     }
610
611     for (i = 0, bit = 1; state->clear_mods; i++, bit <<= 1) {
612         if (state->clear_mods & bit) {
613             state->mod_key_count[i]--;
614             if (state->mod_key_count[i] <= 0) {
615                 state->base_mods &= ~bit;
616                 state->mod_key_count[i] = 0;
617             }
618             state->clear_mods &= ~bit;
619         }
620     }
621
622     xkb_state_update_derived(state);
623 }
624
625 /**
626  * Updates the state from a set of explicit masks as gained from
627  * xkb_state_serialize_mods and xkb_state_serialize_groups.  As noted in the
628  * documentation for these functions in xkbcommon.h, this round-trip is
629  * lossy, and should only be used to update a slave state mirroring the
630  * master, e.g. in a client/server window system.
631  */
632 _X_EXPORT void
633 xkb_state_update_mask(struct xkb_state *state,
634                       xkb_mod_mask_t base_mods,
635                       xkb_mod_mask_t latched_mods,
636                       xkb_mod_mask_t locked_mods,
637                       xkb_group_index_t base_group,
638                       xkb_group_index_t latched_group,
639                       xkb_group_index_t locked_group)
640 {
641     xkb_mod_mask_t mod;
642
643     state->base_mods = 0;
644     state->latched_mods = 0;
645     state->locked_mods = 0;
646     for (mod = 0; mod < xkb_map_num_mods(state->keymap); mod++) {
647         xkb_mod_mask_t idx = (1 << mod);
648         if (base_mods & idx)
649             state->base_mods |= idx;
650         if (latched_mods & idx)
651             state->latched_mods |= idx;
652         if (locked_mods & idx)
653             state->locked_mods |= idx;
654     }
655
656     state->base_group = base_group;
657     state->latched_group = latched_group;
658     state->locked_group = locked_group;
659
660     xkb_state_update_derived(state);
661 }
662
663 /**
664  * Serialises the requested modifier state into an xkb_mod_mask_t, with all
665  * the same disclaimers as in xkb_state_update_mask.
666  */
667 _X_EXPORT xkb_mod_mask_t
668 xkb_state_serialize_mods(struct xkb_state *state,
669                          enum xkb_state_component type)
670 {
671     xkb_mod_mask_t ret = 0;
672
673     if (type == XKB_STATE_EFFECTIVE)
674         return state->mods;
675
676     if (type & XKB_STATE_DEPRESSED)
677         ret |= state->base_mods;
678     if (type & XKB_STATE_LATCHED)
679         ret |= state->latched_mods;
680     if (type & XKB_STATE_LOCKED)
681         ret |= state->locked_mods;
682
683     return ret;
684 }
685
686 /**
687  * Serialises the requested group state, with all the same disclaimers as
688  * in xkb_state_update_mask.
689  */
690 _X_EXPORT xkb_group_index_t
691 xkb_state_serialize_group(struct xkb_state *state,
692                           enum xkb_state_component type)
693 {
694     xkb_group_index_t ret = 0;
695
696     if (type == XKB_STATE_EFFECTIVE)
697         return state->group;
698
699     if (type & XKB_STATE_DEPRESSED)
700         ret += state->base_group;
701     if (type & XKB_STATE_LATCHED)
702         ret += state->latched_group;
703     if (type & XKB_STATE_LOCKED)
704         ret += state->locked_group;
705
706     return ret;
707 }
708
709 /**
710  * Returns 1 if the given modifier is active with the specified type(s), 0 if
711  * not, or -1 if the modifier is invalid.
712  */
713 _X_EXPORT int
714 xkb_state_mod_index_is_active(struct xkb_state *state,
715                               xkb_mod_index_t idx,
716                               enum xkb_state_component type)
717 {
718     int ret = 0;
719
720     if (idx >= xkb_map_num_mods(state->keymap))
721         return -1;
722
723     if (type & XKB_STATE_DEPRESSED)
724         ret |= (state->base_mods & (1 << idx));
725     if (type & XKB_STATE_LATCHED)
726         ret |= (state->latched_mods & (1 << idx));
727     if (type & XKB_STATE_LOCKED)
728         ret |= (state->locked_mods & (1 << idx));
729
730     return ret;
731 }
732
733 /**
734  * Helper function for xkb_state_mod_indices_are_active and
735  * xkb_state_mod_names_are_active.
736  */
737 static int
738 match_mod_masks(struct xkb_state *state, enum xkb_state_match match,
739                 uint32_t wanted)
740 {
741     uint32_t active = xkb_state_serialize_mods(state, XKB_STATE_EFFECTIVE);
742
743     if (!(match & XKB_STATE_MATCH_NON_EXCLUSIVE) && (active & ~wanted))
744         return 0;
745
746     if (match & XKB_STATE_MATCH_ANY)
747         return !!(active & wanted);
748     else
749         return (active & wanted) == wanted;
750
751     return 0;
752 }
753
754 /**
755  * Returns 1 if the modifiers are active with the specified type(s), 0 if
756  * not, or -1 if any of the modifiers are invalid.
757  */
758 _X_EXPORT int
759 xkb_state_mod_indices_are_active(struct xkb_state *state,
760                                  enum xkb_state_component type,
761                                  enum xkb_state_match match,
762                                  ...)
763 {
764     va_list ap;
765     xkb_mod_index_t idx = 0;
766     uint32_t wanted = 0;
767     int ret = 0;
768
769     va_start(ap, match);
770     while (1) {
771         idx = va_arg(ap, xkb_mod_index_t);
772         if (idx == XKB_MOD_INVALID ||
773             idx >= xkb_map_num_mods(state->keymap)) {
774             ret = -1;
775             break;
776         }
777         wanted |= (1 << idx);
778     }
779     va_end(ap);
780
781     if (ret == -1)
782         return ret;
783
784     return match_mod_masks(state, match, wanted);
785 }
786
787 /**
788  * Returns 1 if the given modifier is active with the specified type(s), 0 if
789  * not, or -1 if the modifier is invalid.
790  */
791 _X_EXPORT int
792 xkb_state_mod_name_is_active(struct xkb_state *state, const char *name,
793                              enum xkb_state_component type)
794 {
795     xkb_mod_index_t idx = xkb_map_mod_get_index(state->keymap, name);
796
797     if (idx == XKB_MOD_INVALID)
798         return -1;
799
800     return xkb_state_mod_index_is_active(state, idx, type);
801 }
802
803 /**
804  * Returns 1 if the modifiers are active with the specified type(s), 0 if
805  * not, or -1 if any of the modifiers are invalid.
806  */
807 _X_EXPORT int
808 xkb_state_mod_names_are_active(struct xkb_state *state,
809                                enum xkb_state_component type,
810                                enum xkb_state_match match,
811                                ...)
812 {
813     va_list ap;
814     xkb_mod_index_t idx = 0;
815     const char *str;
816     uint32_t wanted = 0;
817     int ret = 0;
818
819     va_start(ap, match);
820     while (1) {
821         str = va_arg(ap, const char *);
822         if (str == NULL)
823             break;
824         idx = xkb_map_mod_get_index(state->keymap, str);
825         if (idx == XKB_MOD_INVALID) {
826             ret = -1;
827             break;
828         }
829         wanted |= (1 << idx);
830     }
831     va_end(ap);
832
833     if (ret == -1)
834         return ret;
835
836     return match_mod_masks(state, match, wanted);
837 }
838
839 /**
840  * Returns 1 if the given group is active with the specified type(s), 0 if
841  * not, or -1 if the group is invalid.
842  */
843 _X_EXPORT int
844 xkb_state_group_index_is_active(struct xkb_state *state,
845                                 xkb_group_index_t idx,
846                                 enum xkb_state_component type)
847 {
848     int ret = 0;
849
850     if (idx >= xkb_map_num_groups(state->keymap))
851         return -1;
852
853     if (type & XKB_STATE_DEPRESSED)
854         ret |= (state->base_group == idx);
855     if (type & XKB_STATE_LATCHED)
856         ret |= (state->latched_group == idx);
857     if (type & XKB_STATE_LOCKED)
858         ret |= (state->locked_group == idx);
859
860     return ret;
861 }
862
863 /**
864  * Returns 1 if the given modifier is active with the specified type(s), 0 if
865  * not, or -1 if the modifier is invalid.
866  */
867 _X_EXPORT int
868 xkb_state_group_name_is_active(struct xkb_state *state, const char *name,
869                                enum xkb_state_component type)
870 {
871     xkb_group_index_t idx = xkb_map_group_get_index(state->keymap, name);
872
873     if (idx == XKB_GROUP_INVALID)
874         return -1;
875
876     return xkb_state_group_index_is_active(state, idx, type);
877 }
878
879 /**
880  * Returns 1 if the given LED is active, 0 if not, or -1 if the LED is invalid.
881  */
882 _X_EXPORT int
883 xkb_state_led_index_is_active(struct xkb_state *state, xkb_led_index_t idx)
884 {
885     if (idx >= xkb_map_num_leds(state->keymap))
886         return -1;
887
888     return !!(state->leds & (1 << idx));
889 }
890
891 /**
892  * Returns 1 if the given LED is active, 0 if not, or -1 if the LED is invalid.
893  */
894 _X_EXPORT int
895 xkb_state_led_name_is_active(struct xkb_state *state, const char *name)
896 {
897     xkb_led_index_t idx = xkb_map_led_get_index(state->keymap, name);
898
899     if (idx == XKB_LED_INVALID)
900         return -1;
901
902     return xkb_state_led_index_is_active(state, idx);
903 }