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