xref: /aosp_15_r20/external/libxkbcommon/src/state.c (revision 2b949d0487e80d67f1fda82db69e101e761f8064)
1*2b949d04SAndroid Build Coastguard Worker /************************************************************
2*2b949d04SAndroid Build Coastguard Worker  * Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3*2b949d04SAndroid Build Coastguard Worker  *
4*2b949d04SAndroid Build Coastguard Worker  * Permission to use, copy, modify, and distribute this
5*2b949d04SAndroid Build Coastguard Worker  * software and its documentation for any purpose and without
6*2b949d04SAndroid Build Coastguard Worker  * fee is hereby granted, provided that the above copyright
7*2b949d04SAndroid Build Coastguard Worker  * notice appear in all copies and that both that copyright
8*2b949d04SAndroid Build Coastguard Worker  * notice and this permission notice appear in supporting
9*2b949d04SAndroid Build Coastguard Worker  * documentation, and that the name of Silicon Graphics not be
10*2b949d04SAndroid Build Coastguard Worker  * used in advertising or publicity pertaining to distribution
11*2b949d04SAndroid Build Coastguard Worker  * of the software without specific prior written permission.
12*2b949d04SAndroid Build Coastguard Worker  * Silicon Graphics makes no representation about the suitability
13*2b949d04SAndroid Build Coastguard Worker  * of this software for any purpose. It is provided "as is"
14*2b949d04SAndroid Build Coastguard Worker  * without any express or implied warranty.
15*2b949d04SAndroid Build Coastguard Worker  *
16*2b949d04SAndroid Build Coastguard Worker  * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17*2b949d04SAndroid Build Coastguard Worker  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18*2b949d04SAndroid Build Coastguard Worker  * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19*2b949d04SAndroid Build Coastguard Worker  * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20*2b949d04SAndroid Build Coastguard Worker  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21*2b949d04SAndroid Build Coastguard Worker  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22*2b949d04SAndroid Build Coastguard Worker  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23*2b949d04SAndroid Build Coastguard Worker  * THE USE OR PERFORMANCE OF THIS SOFTWARE.
24*2b949d04SAndroid Build Coastguard Worker  *
25*2b949d04SAndroid Build Coastguard Worker  ********************************************************/
26*2b949d04SAndroid Build Coastguard Worker 
27*2b949d04SAndroid Build Coastguard Worker /*
28*2b949d04SAndroid Build Coastguard Worker  * Copyright © 2012 Intel Corporation
29*2b949d04SAndroid Build Coastguard Worker  * Copyright © 2012 Ran Benita <[email protected]>
30*2b949d04SAndroid Build Coastguard Worker  *
31*2b949d04SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
32*2b949d04SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
33*2b949d04SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
34*2b949d04SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
35*2b949d04SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
36*2b949d04SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
37*2b949d04SAndroid Build Coastguard Worker  *
38*2b949d04SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
39*2b949d04SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
40*2b949d04SAndroid Build Coastguard Worker  * Software.
41*2b949d04SAndroid Build Coastguard Worker  *
42*2b949d04SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43*2b949d04SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44*2b949d04SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
45*2b949d04SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46*2b949d04SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
47*2b949d04SAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
48*2b949d04SAndroid Build Coastguard Worker  * DEALINGS IN THE SOFTWARE.
49*2b949d04SAndroid Build Coastguard Worker  *
50*2b949d04SAndroid Build Coastguard Worker  * Author: Daniel Stone <[email protected]>
51*2b949d04SAndroid Build Coastguard Worker  */
52*2b949d04SAndroid Build Coastguard Worker 
53*2b949d04SAndroid Build Coastguard Worker /*
54*2b949d04SAndroid Build Coastguard Worker  * This is a bastardised version of xkbActions.c from the X server which
55*2b949d04SAndroid Build Coastguard Worker  * does not support, for the moment:
56*2b949d04SAndroid Build Coastguard Worker  *   - AccessX sticky/debounce/etc (will come later)
57*2b949d04SAndroid Build Coastguard Worker  *   - pointer keys (may come later)
58*2b949d04SAndroid Build Coastguard Worker  *   - key redirects (unlikely)
59*2b949d04SAndroid Build Coastguard Worker  *   - messages (very unlikely)
60*2b949d04SAndroid Build Coastguard Worker  */
61*2b949d04SAndroid Build Coastguard Worker 
62*2b949d04SAndroid Build Coastguard Worker #include "config.h"
63*2b949d04SAndroid Build Coastguard Worker 
64*2b949d04SAndroid Build Coastguard Worker #include "keymap.h"
65*2b949d04SAndroid Build Coastguard Worker #include "keysym.h"
66*2b949d04SAndroid Build Coastguard Worker #include "utf8.h"
67*2b949d04SAndroid Build Coastguard Worker 
68*2b949d04SAndroid Build Coastguard Worker struct xkb_filter {
69*2b949d04SAndroid Build Coastguard Worker     union xkb_action action;
70*2b949d04SAndroid Build Coastguard Worker     const struct xkb_key *key;
71*2b949d04SAndroid Build Coastguard Worker     uint32_t priv;
72*2b949d04SAndroid Build Coastguard Worker     bool (*func)(struct xkb_state *state,
73*2b949d04SAndroid Build Coastguard Worker                  struct xkb_filter *filter,
74*2b949d04SAndroid Build Coastguard Worker                  const struct xkb_key *key,
75*2b949d04SAndroid Build Coastguard Worker                  enum xkb_key_direction direction);
76*2b949d04SAndroid Build Coastguard Worker     int refcnt;
77*2b949d04SAndroid Build Coastguard Worker };
78*2b949d04SAndroid Build Coastguard Worker 
79*2b949d04SAndroid Build Coastguard Worker struct state_components {
80*2b949d04SAndroid Build Coastguard Worker     /* These may be negative, because of -1 group actions. */
81*2b949d04SAndroid Build Coastguard Worker     int32_t base_group; /**< depressed */
82*2b949d04SAndroid Build Coastguard Worker     int32_t latched_group;
83*2b949d04SAndroid Build Coastguard Worker     int32_t locked_group;
84*2b949d04SAndroid Build Coastguard Worker     xkb_layout_index_t group; /**< effective */
85*2b949d04SAndroid Build Coastguard Worker 
86*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t base_mods; /**< depressed */
87*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t latched_mods;
88*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t locked_mods;
89*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t mods; /**< effective */
90*2b949d04SAndroid Build Coastguard Worker 
91*2b949d04SAndroid Build Coastguard Worker     xkb_led_mask_t leds;
92*2b949d04SAndroid Build Coastguard Worker };
93*2b949d04SAndroid Build Coastguard Worker 
94*2b949d04SAndroid Build Coastguard Worker struct xkb_state {
95*2b949d04SAndroid Build Coastguard Worker     /*
96*2b949d04SAndroid Build Coastguard Worker      * Before updating the state, we keep a copy of just this struct. This
97*2b949d04SAndroid Build Coastguard Worker      * allows us to report which components of the state have changed.
98*2b949d04SAndroid Build Coastguard Worker      */
99*2b949d04SAndroid Build Coastguard Worker     struct state_components components;
100*2b949d04SAndroid Build Coastguard Worker 
101*2b949d04SAndroid Build Coastguard Worker     /*
102*2b949d04SAndroid Build Coastguard Worker      * At each event, we accumulate all the needed modifications to the base
103*2b949d04SAndroid Build Coastguard Worker      * modifiers, and apply them at the end. These keep track of this state.
104*2b949d04SAndroid Build Coastguard Worker      */
105*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t set_mods;
106*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t clear_mods;
107*2b949d04SAndroid Build Coastguard Worker 
108*2b949d04SAndroid Build Coastguard Worker     /*
109*2b949d04SAndroid Build Coastguard Worker      * We mustn't clear a base modifier if there's another depressed key
110*2b949d04SAndroid Build Coastguard Worker      * which affects it, e.g. given this sequence
111*2b949d04SAndroid Build Coastguard Worker      * < Left Shift down, Right Shift down, Left Shift Up >
112*2b949d04SAndroid Build Coastguard Worker      * the modifier should still be set. This keeps the count.
113*2b949d04SAndroid Build Coastguard Worker      */
114*2b949d04SAndroid Build Coastguard Worker     int16_t mod_key_count[XKB_MAX_MODS];
115*2b949d04SAndroid Build Coastguard Worker 
116*2b949d04SAndroid Build Coastguard Worker     int refcnt;
117*2b949d04SAndroid Build Coastguard Worker     darray(struct xkb_filter) filters;
118*2b949d04SAndroid Build Coastguard Worker     struct xkb_keymap *keymap;
119*2b949d04SAndroid Build Coastguard Worker };
120*2b949d04SAndroid Build Coastguard Worker 
121*2b949d04SAndroid Build Coastguard Worker static const struct xkb_key_type_entry *
get_entry_for_mods(const struct xkb_key_type * type,xkb_mod_mask_t mods)122*2b949d04SAndroid Build Coastguard Worker get_entry_for_mods(const struct xkb_key_type *type, xkb_mod_mask_t mods)
123*2b949d04SAndroid Build Coastguard Worker {
124*2b949d04SAndroid Build Coastguard Worker     for (unsigned i = 0; i < type->num_entries; i++)
125*2b949d04SAndroid Build Coastguard Worker         if (entry_is_active(&type->entries[i]) &&
126*2b949d04SAndroid Build Coastguard Worker             type->entries[i].mods.mask == mods)
127*2b949d04SAndroid Build Coastguard Worker             return &type->entries[i];
128*2b949d04SAndroid Build Coastguard Worker     return NULL;
129*2b949d04SAndroid Build Coastguard Worker }
130*2b949d04SAndroid Build Coastguard Worker 
131*2b949d04SAndroid Build Coastguard Worker static const struct xkb_key_type_entry *
get_entry_for_key_state(struct xkb_state * state,const struct xkb_key * key,xkb_layout_index_t group)132*2b949d04SAndroid Build Coastguard Worker get_entry_for_key_state(struct xkb_state *state, const struct xkb_key *key,
133*2b949d04SAndroid Build Coastguard Worker                         xkb_layout_index_t group)
134*2b949d04SAndroid Build Coastguard Worker {
135*2b949d04SAndroid Build Coastguard Worker     const struct xkb_key_type *type = key->groups[group].type;
136*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t active_mods = state->components.mods & type->mods.mask;
137*2b949d04SAndroid Build Coastguard Worker     return get_entry_for_mods(type, active_mods);
138*2b949d04SAndroid Build Coastguard Worker }
139*2b949d04SAndroid Build Coastguard Worker 
140*2b949d04SAndroid Build Coastguard Worker /**
141*2b949d04SAndroid Build Coastguard Worker  * Returns the level to use for the given key and state, or
142*2b949d04SAndroid Build Coastguard Worker  * XKB_LEVEL_INVALID.
143*2b949d04SAndroid Build Coastguard Worker  */
144*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT xkb_level_index_t
xkb_state_key_get_level(struct xkb_state * state,xkb_keycode_t kc,xkb_layout_index_t layout)145*2b949d04SAndroid Build Coastguard Worker xkb_state_key_get_level(struct xkb_state *state, xkb_keycode_t kc,
146*2b949d04SAndroid Build Coastguard Worker                         xkb_layout_index_t layout)
147*2b949d04SAndroid Build Coastguard Worker {
148*2b949d04SAndroid Build Coastguard Worker     const struct xkb_key *key = XkbKey(state->keymap, kc);
149*2b949d04SAndroid Build Coastguard Worker     const struct xkb_key_type_entry *entry;
150*2b949d04SAndroid Build Coastguard Worker 
151*2b949d04SAndroid Build Coastguard Worker     if (!key || layout >= key->num_groups)
152*2b949d04SAndroid Build Coastguard Worker         return XKB_LEVEL_INVALID;
153*2b949d04SAndroid Build Coastguard Worker 
154*2b949d04SAndroid Build Coastguard Worker     /* If we don't find an explicit match the default is 0. */
155*2b949d04SAndroid Build Coastguard Worker     entry = get_entry_for_key_state(state, key, layout);
156*2b949d04SAndroid Build Coastguard Worker     if (!entry)
157*2b949d04SAndroid Build Coastguard Worker         return 0;
158*2b949d04SAndroid Build Coastguard Worker 
159*2b949d04SAndroid Build Coastguard Worker     return entry->level;
160*2b949d04SAndroid Build Coastguard Worker }
161*2b949d04SAndroid Build Coastguard Worker 
162*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t
XkbWrapGroupIntoRange(int32_t group,xkb_layout_index_t num_groups,enum xkb_range_exceed_type out_of_range_group_action,xkb_layout_index_t out_of_range_group_number)163*2b949d04SAndroid Build Coastguard Worker XkbWrapGroupIntoRange(int32_t group,
164*2b949d04SAndroid Build Coastguard Worker                       xkb_layout_index_t num_groups,
165*2b949d04SAndroid Build Coastguard Worker                       enum xkb_range_exceed_type out_of_range_group_action,
166*2b949d04SAndroid Build Coastguard Worker                       xkb_layout_index_t out_of_range_group_number)
167*2b949d04SAndroid Build Coastguard Worker {
168*2b949d04SAndroid Build Coastguard Worker     if (num_groups == 0)
169*2b949d04SAndroid Build Coastguard Worker         return XKB_LAYOUT_INVALID;
170*2b949d04SAndroid Build Coastguard Worker 
171*2b949d04SAndroid Build Coastguard Worker     if (group >= 0 && (xkb_layout_index_t) group < num_groups)
172*2b949d04SAndroid Build Coastguard Worker         return group;
173*2b949d04SAndroid Build Coastguard Worker 
174*2b949d04SAndroid Build Coastguard Worker     switch (out_of_range_group_action) {
175*2b949d04SAndroid Build Coastguard Worker     case RANGE_REDIRECT:
176*2b949d04SAndroid Build Coastguard Worker         if (out_of_range_group_number >= num_groups)
177*2b949d04SAndroid Build Coastguard Worker             return 0;
178*2b949d04SAndroid Build Coastguard Worker         return out_of_range_group_number;
179*2b949d04SAndroid Build Coastguard Worker 
180*2b949d04SAndroid Build Coastguard Worker     case RANGE_SATURATE:
181*2b949d04SAndroid Build Coastguard Worker         if (group < 0)
182*2b949d04SAndroid Build Coastguard Worker             return 0;
183*2b949d04SAndroid Build Coastguard Worker         else
184*2b949d04SAndroid Build Coastguard Worker             return num_groups - 1;
185*2b949d04SAndroid Build Coastguard Worker 
186*2b949d04SAndroid Build Coastguard Worker     case RANGE_WRAP:
187*2b949d04SAndroid Build Coastguard Worker     default:
188*2b949d04SAndroid Build Coastguard Worker         /*
189*2b949d04SAndroid Build Coastguard Worker          * C99 says a negative dividend in a modulo operation always
190*2b949d04SAndroid Build Coastguard Worker          * gives a negative result.
191*2b949d04SAndroid Build Coastguard Worker          */
192*2b949d04SAndroid Build Coastguard Worker         if (group < 0)
193*2b949d04SAndroid Build Coastguard Worker             return ((int) num_groups + (group % (int) num_groups));
194*2b949d04SAndroid Build Coastguard Worker         else
195*2b949d04SAndroid Build Coastguard Worker             return group % num_groups;
196*2b949d04SAndroid Build Coastguard Worker     }
197*2b949d04SAndroid Build Coastguard Worker }
198*2b949d04SAndroid Build Coastguard Worker 
199*2b949d04SAndroid Build Coastguard Worker /**
200*2b949d04SAndroid Build Coastguard Worker  * Returns the layout to use for the given key and state, taking
201*2b949d04SAndroid Build Coastguard Worker  * wrapping/clamping/etc into account, or XKB_LAYOUT_INVALID.
202*2b949d04SAndroid Build Coastguard Worker  */
203*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT xkb_layout_index_t
xkb_state_key_get_layout(struct xkb_state * state,xkb_keycode_t kc)204*2b949d04SAndroid Build Coastguard Worker xkb_state_key_get_layout(struct xkb_state *state, xkb_keycode_t kc)
205*2b949d04SAndroid Build Coastguard Worker {
206*2b949d04SAndroid Build Coastguard Worker     const struct xkb_key *key = XkbKey(state->keymap, kc);
207*2b949d04SAndroid Build Coastguard Worker 
208*2b949d04SAndroid Build Coastguard Worker     if (!key)
209*2b949d04SAndroid Build Coastguard Worker         return XKB_LAYOUT_INVALID;
210*2b949d04SAndroid Build Coastguard Worker 
211*2b949d04SAndroid Build Coastguard Worker     return XkbWrapGroupIntoRange(state->components.group, key->num_groups,
212*2b949d04SAndroid Build Coastguard Worker                                  key->out_of_range_group_action,
213*2b949d04SAndroid Build Coastguard Worker                                  key->out_of_range_group_number);
214*2b949d04SAndroid Build Coastguard Worker }
215*2b949d04SAndroid Build Coastguard Worker 
216*2b949d04SAndroid Build Coastguard Worker static const union xkb_action *
xkb_key_get_action(struct xkb_state * state,const struct xkb_key * key)217*2b949d04SAndroid Build Coastguard Worker xkb_key_get_action(struct xkb_state *state, const struct xkb_key *key)
218*2b949d04SAndroid Build Coastguard Worker {
219*2b949d04SAndroid Build Coastguard Worker     static const union xkb_action dummy = { .type = ACTION_TYPE_NONE };
220*2b949d04SAndroid Build Coastguard Worker 
221*2b949d04SAndroid Build Coastguard Worker     xkb_layout_index_t layout;
222*2b949d04SAndroid Build Coastguard Worker     xkb_level_index_t level;
223*2b949d04SAndroid Build Coastguard Worker 
224*2b949d04SAndroid Build Coastguard Worker     layout = xkb_state_key_get_layout(state, key->keycode);
225*2b949d04SAndroid Build Coastguard Worker     if (layout == XKB_LAYOUT_INVALID)
226*2b949d04SAndroid Build Coastguard Worker         return &dummy;
227*2b949d04SAndroid Build Coastguard Worker 
228*2b949d04SAndroid Build Coastguard Worker     level = xkb_state_key_get_level(state, key->keycode, layout);
229*2b949d04SAndroid Build Coastguard Worker     if (level == XKB_LEVEL_INVALID)
230*2b949d04SAndroid Build Coastguard Worker         return &dummy;
231*2b949d04SAndroid Build Coastguard Worker 
232*2b949d04SAndroid Build Coastguard Worker     return &key->groups[layout].levels[level].action;
233*2b949d04SAndroid Build Coastguard Worker }
234*2b949d04SAndroid Build Coastguard Worker 
235*2b949d04SAndroid Build Coastguard Worker static struct xkb_filter *
xkb_filter_new(struct xkb_state * state)236*2b949d04SAndroid Build Coastguard Worker xkb_filter_new(struct xkb_state *state)
237*2b949d04SAndroid Build Coastguard Worker {
238*2b949d04SAndroid Build Coastguard Worker     struct xkb_filter *filter = NULL, *iter;
239*2b949d04SAndroid Build Coastguard Worker 
240*2b949d04SAndroid Build Coastguard Worker     darray_foreach(iter, state->filters) {
241*2b949d04SAndroid Build Coastguard Worker         if (iter->func)
242*2b949d04SAndroid Build Coastguard Worker             continue;
243*2b949d04SAndroid Build Coastguard Worker         filter = iter;
244*2b949d04SAndroid Build Coastguard Worker         break;
245*2b949d04SAndroid Build Coastguard Worker     }
246*2b949d04SAndroid Build Coastguard Worker 
247*2b949d04SAndroid Build Coastguard Worker     if (!filter) {
248*2b949d04SAndroid Build Coastguard Worker         darray_resize0(state->filters, darray_size(state->filters) + 1);
249*2b949d04SAndroid Build Coastguard Worker         filter = &darray_item(state->filters, darray_size(state->filters) -1);
250*2b949d04SAndroid Build Coastguard Worker     }
251*2b949d04SAndroid Build Coastguard Worker 
252*2b949d04SAndroid Build Coastguard Worker     filter->refcnt = 1;
253*2b949d04SAndroid Build Coastguard Worker     return filter;
254*2b949d04SAndroid Build Coastguard Worker }
255*2b949d04SAndroid Build Coastguard Worker 
256*2b949d04SAndroid Build Coastguard Worker /***====================================================================***/
257*2b949d04SAndroid Build Coastguard Worker 
258*2b949d04SAndroid Build Coastguard Worker enum xkb_filter_result {
259*2b949d04SAndroid Build Coastguard Worker     /*
260*2b949d04SAndroid Build Coastguard Worker      * The event is consumed by the filters.
261*2b949d04SAndroid Build Coastguard Worker      *
262*2b949d04SAndroid Build Coastguard Worker      * An event is always processed by all filters, but any filter can
263*2b949d04SAndroid Build Coastguard Worker      * prevent it from being processed further by consuming it.
264*2b949d04SAndroid Build Coastguard Worker      */
265*2b949d04SAndroid Build Coastguard Worker     XKB_FILTER_CONSUME,
266*2b949d04SAndroid Build Coastguard Worker     /*
267*2b949d04SAndroid Build Coastguard Worker      * The event may continue to be processed as far as this filter is
268*2b949d04SAndroid Build Coastguard Worker      * concerned.
269*2b949d04SAndroid Build Coastguard Worker      */
270*2b949d04SAndroid Build Coastguard Worker     XKB_FILTER_CONTINUE,
271*2b949d04SAndroid Build Coastguard Worker };
272*2b949d04SAndroid Build Coastguard Worker 
273*2b949d04SAndroid Build Coastguard Worker static void
xkb_filter_group_set_new(struct xkb_state * state,struct xkb_filter * filter)274*2b949d04SAndroid Build Coastguard Worker xkb_filter_group_set_new(struct xkb_state *state, struct xkb_filter *filter)
275*2b949d04SAndroid Build Coastguard Worker {
276*2b949d04SAndroid Build Coastguard Worker     filter->priv = state->components.base_group;
277*2b949d04SAndroid Build Coastguard Worker     if (filter->action.group.flags & ACTION_ABSOLUTE_SWITCH)
278*2b949d04SAndroid Build Coastguard Worker         state->components.base_group = filter->action.group.group;
279*2b949d04SAndroid Build Coastguard Worker     else
280*2b949d04SAndroid Build Coastguard Worker         state->components.base_group += filter->action.group.group;
281*2b949d04SAndroid Build Coastguard Worker }
282*2b949d04SAndroid Build Coastguard Worker 
283*2b949d04SAndroid Build Coastguard Worker static bool
xkb_filter_group_set_func(struct xkb_state * state,struct xkb_filter * filter,const struct xkb_key * key,enum xkb_key_direction direction)284*2b949d04SAndroid Build Coastguard Worker xkb_filter_group_set_func(struct xkb_state *state,
285*2b949d04SAndroid Build Coastguard Worker                           struct xkb_filter *filter,
286*2b949d04SAndroid Build Coastguard Worker                           const struct xkb_key *key,
287*2b949d04SAndroid Build Coastguard Worker                           enum xkb_key_direction direction)
288*2b949d04SAndroid Build Coastguard Worker {
289*2b949d04SAndroid Build Coastguard Worker     if (key != filter->key) {
290*2b949d04SAndroid Build Coastguard Worker         filter->action.group.flags &= ~ACTION_LOCK_CLEAR;
291*2b949d04SAndroid Build Coastguard Worker         return XKB_FILTER_CONTINUE;
292*2b949d04SAndroid Build Coastguard Worker     }
293*2b949d04SAndroid Build Coastguard Worker 
294*2b949d04SAndroid Build Coastguard Worker     if (direction == XKB_KEY_DOWN) {
295*2b949d04SAndroid Build Coastguard Worker         filter->refcnt++;
296*2b949d04SAndroid Build Coastguard Worker         return XKB_FILTER_CONSUME;
297*2b949d04SAndroid Build Coastguard Worker     }
298*2b949d04SAndroid Build Coastguard Worker     else if (--filter->refcnt > 0) {
299*2b949d04SAndroid Build Coastguard Worker         return XKB_FILTER_CONSUME;
300*2b949d04SAndroid Build Coastguard Worker     }
301*2b949d04SAndroid Build Coastguard Worker 
302*2b949d04SAndroid Build Coastguard Worker     state->components.base_group = filter->priv;
303*2b949d04SAndroid Build Coastguard Worker 
304*2b949d04SAndroid Build Coastguard Worker     if (filter->action.group.flags & ACTION_LOCK_CLEAR)
305*2b949d04SAndroid Build Coastguard Worker         state->components.locked_group = 0;
306*2b949d04SAndroid Build Coastguard Worker 
307*2b949d04SAndroid Build Coastguard Worker     filter->func = NULL;
308*2b949d04SAndroid Build Coastguard Worker     return XKB_FILTER_CONTINUE;
309*2b949d04SAndroid Build Coastguard Worker }
310*2b949d04SAndroid Build Coastguard Worker 
311*2b949d04SAndroid Build Coastguard Worker static void
xkb_filter_group_lock_new(struct xkb_state * state,struct xkb_filter * filter)312*2b949d04SAndroid Build Coastguard Worker xkb_filter_group_lock_new(struct xkb_state *state, struct xkb_filter *filter)
313*2b949d04SAndroid Build Coastguard Worker {
314*2b949d04SAndroid Build Coastguard Worker     if (filter->action.group.flags & ACTION_ABSOLUTE_SWITCH)
315*2b949d04SAndroid Build Coastguard Worker         state->components.locked_group = filter->action.group.group;
316*2b949d04SAndroid Build Coastguard Worker     else
317*2b949d04SAndroid Build Coastguard Worker         state->components.locked_group += filter->action.group.group;
318*2b949d04SAndroid Build Coastguard Worker }
319*2b949d04SAndroid Build Coastguard Worker 
320*2b949d04SAndroid Build Coastguard Worker static bool
xkb_filter_group_lock_func(struct xkb_state * state,struct xkb_filter * filter,const struct xkb_key * key,enum xkb_key_direction direction)321*2b949d04SAndroid Build Coastguard Worker xkb_filter_group_lock_func(struct xkb_state *state,
322*2b949d04SAndroid Build Coastguard Worker                            struct xkb_filter *filter,
323*2b949d04SAndroid Build Coastguard Worker                            const struct xkb_key *key,
324*2b949d04SAndroid Build Coastguard Worker                            enum xkb_key_direction direction)
325*2b949d04SAndroid Build Coastguard Worker {
326*2b949d04SAndroid Build Coastguard Worker     if (key != filter->key)
327*2b949d04SAndroid Build Coastguard Worker         return XKB_FILTER_CONTINUE;
328*2b949d04SAndroid Build Coastguard Worker 
329*2b949d04SAndroid Build Coastguard Worker     if (direction == XKB_KEY_DOWN) {
330*2b949d04SAndroid Build Coastguard Worker         filter->refcnt++;
331*2b949d04SAndroid Build Coastguard Worker         return XKB_FILTER_CONSUME;
332*2b949d04SAndroid Build Coastguard Worker     }
333*2b949d04SAndroid Build Coastguard Worker     if (--filter->refcnt > 0)
334*2b949d04SAndroid Build Coastguard Worker         return XKB_FILTER_CONSUME;
335*2b949d04SAndroid Build Coastguard Worker 
336*2b949d04SAndroid Build Coastguard Worker     filter->func = NULL;
337*2b949d04SAndroid Build Coastguard Worker     return XKB_FILTER_CONTINUE;
338*2b949d04SAndroid Build Coastguard Worker }
339*2b949d04SAndroid Build Coastguard Worker 
340*2b949d04SAndroid Build Coastguard Worker static void
xkb_filter_mod_set_new(struct xkb_state * state,struct xkb_filter * filter)341*2b949d04SAndroid Build Coastguard Worker xkb_filter_mod_set_new(struct xkb_state *state, struct xkb_filter *filter)
342*2b949d04SAndroid Build Coastguard Worker {
343*2b949d04SAndroid Build Coastguard Worker     state->set_mods = filter->action.mods.mods.mask;
344*2b949d04SAndroid Build Coastguard Worker }
345*2b949d04SAndroid Build Coastguard Worker 
346*2b949d04SAndroid Build Coastguard Worker static bool
xkb_filter_mod_set_func(struct xkb_state * state,struct xkb_filter * filter,const struct xkb_key * key,enum xkb_key_direction direction)347*2b949d04SAndroid Build Coastguard Worker xkb_filter_mod_set_func(struct xkb_state *state,
348*2b949d04SAndroid Build Coastguard Worker                         struct xkb_filter *filter,
349*2b949d04SAndroid Build Coastguard Worker                         const struct xkb_key *key,
350*2b949d04SAndroid Build Coastguard Worker                         enum xkb_key_direction direction)
351*2b949d04SAndroid Build Coastguard Worker {
352*2b949d04SAndroid Build Coastguard Worker     if (key != filter->key) {
353*2b949d04SAndroid Build Coastguard Worker         filter->action.mods.flags &= ~ACTION_LOCK_CLEAR;
354*2b949d04SAndroid Build Coastguard Worker         return XKB_FILTER_CONTINUE;
355*2b949d04SAndroid Build Coastguard Worker     }
356*2b949d04SAndroid Build Coastguard Worker 
357*2b949d04SAndroid Build Coastguard Worker     if (direction == XKB_KEY_DOWN) {
358*2b949d04SAndroid Build Coastguard Worker         filter->refcnt++;
359*2b949d04SAndroid Build Coastguard Worker         return XKB_FILTER_CONSUME;
360*2b949d04SAndroid Build Coastguard Worker     }
361*2b949d04SAndroid Build Coastguard Worker     else if (--filter->refcnt > 0) {
362*2b949d04SAndroid Build Coastguard Worker         return XKB_FILTER_CONSUME;
363*2b949d04SAndroid Build Coastguard Worker     }
364*2b949d04SAndroid Build Coastguard Worker 
365*2b949d04SAndroid Build Coastguard Worker     state->clear_mods = filter->action.mods.mods.mask;
366*2b949d04SAndroid Build Coastguard Worker     if (filter->action.mods.flags & ACTION_LOCK_CLEAR)
367*2b949d04SAndroid Build Coastguard Worker         state->components.locked_mods &= ~filter->action.mods.mods.mask;
368*2b949d04SAndroid Build Coastguard Worker 
369*2b949d04SAndroid Build Coastguard Worker     filter->func = NULL;
370*2b949d04SAndroid Build Coastguard Worker     return XKB_FILTER_CONTINUE;
371*2b949d04SAndroid Build Coastguard Worker }
372*2b949d04SAndroid Build Coastguard Worker 
373*2b949d04SAndroid Build Coastguard Worker static void
xkb_filter_mod_lock_new(struct xkb_state * state,struct xkb_filter * filter)374*2b949d04SAndroid Build Coastguard Worker xkb_filter_mod_lock_new(struct xkb_state *state, struct xkb_filter *filter)
375*2b949d04SAndroid Build Coastguard Worker {
376*2b949d04SAndroid Build Coastguard Worker     filter->priv = (state->components.locked_mods &
377*2b949d04SAndroid Build Coastguard Worker                     filter->action.mods.mods.mask);
378*2b949d04SAndroid Build Coastguard Worker     state->set_mods |= filter->action.mods.mods.mask;
379*2b949d04SAndroid Build Coastguard Worker     if (!(filter->action.mods.flags & ACTION_LOCK_NO_LOCK))
380*2b949d04SAndroid Build Coastguard Worker         state->components.locked_mods |= filter->action.mods.mods.mask;
381*2b949d04SAndroid Build Coastguard Worker }
382*2b949d04SAndroid Build Coastguard Worker 
383*2b949d04SAndroid Build Coastguard Worker static bool
xkb_filter_mod_lock_func(struct xkb_state * state,struct xkb_filter * filter,const struct xkb_key * key,enum xkb_key_direction direction)384*2b949d04SAndroid Build Coastguard Worker xkb_filter_mod_lock_func(struct xkb_state *state,
385*2b949d04SAndroid Build Coastguard Worker                          struct xkb_filter *filter,
386*2b949d04SAndroid Build Coastguard Worker                          const struct xkb_key *key,
387*2b949d04SAndroid Build Coastguard Worker                          enum xkb_key_direction direction)
388*2b949d04SAndroid Build Coastguard Worker {
389*2b949d04SAndroid Build Coastguard Worker     if (key != filter->key)
390*2b949d04SAndroid Build Coastguard Worker         return XKB_FILTER_CONTINUE;
391*2b949d04SAndroid Build Coastguard Worker 
392*2b949d04SAndroid Build Coastguard Worker     if (direction == XKB_KEY_DOWN) {
393*2b949d04SAndroid Build Coastguard Worker         filter->refcnt++;
394*2b949d04SAndroid Build Coastguard Worker         return XKB_FILTER_CONSUME;
395*2b949d04SAndroid Build Coastguard Worker     }
396*2b949d04SAndroid Build Coastguard Worker     if (--filter->refcnt > 0)
397*2b949d04SAndroid Build Coastguard Worker         return XKB_FILTER_CONSUME;
398*2b949d04SAndroid Build Coastguard Worker 
399*2b949d04SAndroid Build Coastguard Worker     state->clear_mods |= filter->action.mods.mods.mask;
400*2b949d04SAndroid Build Coastguard Worker     if (!(filter->action.mods.flags & ACTION_LOCK_NO_UNLOCK))
401*2b949d04SAndroid Build Coastguard Worker         state->components.locked_mods &= ~filter->priv;
402*2b949d04SAndroid Build Coastguard Worker 
403*2b949d04SAndroid Build Coastguard Worker     filter->func = NULL;
404*2b949d04SAndroid Build Coastguard Worker     return XKB_FILTER_CONTINUE;
405*2b949d04SAndroid Build Coastguard Worker }
406*2b949d04SAndroid Build Coastguard Worker 
407*2b949d04SAndroid Build Coastguard Worker enum xkb_key_latch_state {
408*2b949d04SAndroid Build Coastguard Worker     NO_LATCH,
409*2b949d04SAndroid Build Coastguard Worker     LATCH_KEY_DOWN,
410*2b949d04SAndroid Build Coastguard Worker     LATCH_PENDING,
411*2b949d04SAndroid Build Coastguard Worker };
412*2b949d04SAndroid Build Coastguard Worker 
413*2b949d04SAndroid Build Coastguard Worker static bool
xkb_action_breaks_latch(const union xkb_action * action)414*2b949d04SAndroid Build Coastguard Worker xkb_action_breaks_latch(const union xkb_action *action)
415*2b949d04SAndroid Build Coastguard Worker {
416*2b949d04SAndroid Build Coastguard Worker     switch (action->type) {
417*2b949d04SAndroid Build Coastguard Worker     case ACTION_TYPE_NONE:
418*2b949d04SAndroid Build Coastguard Worker     case ACTION_TYPE_PTR_BUTTON:
419*2b949d04SAndroid Build Coastguard Worker     case ACTION_TYPE_PTR_LOCK:
420*2b949d04SAndroid Build Coastguard Worker     case ACTION_TYPE_CTRL_SET:
421*2b949d04SAndroid Build Coastguard Worker     case ACTION_TYPE_CTRL_LOCK:
422*2b949d04SAndroid Build Coastguard Worker     case ACTION_TYPE_SWITCH_VT:
423*2b949d04SAndroid Build Coastguard Worker     case ACTION_TYPE_TERMINATE:
424*2b949d04SAndroid Build Coastguard Worker         return true;
425*2b949d04SAndroid Build Coastguard Worker     default:
426*2b949d04SAndroid Build Coastguard Worker         return false;
427*2b949d04SAndroid Build Coastguard Worker     }
428*2b949d04SAndroid Build Coastguard Worker }
429*2b949d04SAndroid Build Coastguard Worker 
430*2b949d04SAndroid Build Coastguard Worker static void
xkb_filter_mod_latch_new(struct xkb_state * state,struct xkb_filter * filter)431*2b949d04SAndroid Build Coastguard Worker xkb_filter_mod_latch_new(struct xkb_state *state, struct xkb_filter *filter)
432*2b949d04SAndroid Build Coastguard Worker {
433*2b949d04SAndroid Build Coastguard Worker     filter->priv = LATCH_KEY_DOWN;
434*2b949d04SAndroid Build Coastguard Worker     state->set_mods = filter->action.mods.mods.mask;
435*2b949d04SAndroid Build Coastguard Worker }
436*2b949d04SAndroid Build Coastguard Worker 
437*2b949d04SAndroid Build Coastguard Worker static bool
xkb_filter_mod_latch_func(struct xkb_state * state,struct xkb_filter * filter,const struct xkb_key * key,enum xkb_key_direction direction)438*2b949d04SAndroid Build Coastguard Worker xkb_filter_mod_latch_func(struct xkb_state *state,
439*2b949d04SAndroid Build Coastguard Worker                           struct xkb_filter *filter,
440*2b949d04SAndroid Build Coastguard Worker                           const struct xkb_key *key,
441*2b949d04SAndroid Build Coastguard Worker                           enum xkb_key_direction direction)
442*2b949d04SAndroid Build Coastguard Worker {
443*2b949d04SAndroid Build Coastguard Worker     enum xkb_key_latch_state latch = filter->priv;
444*2b949d04SAndroid Build Coastguard Worker 
445*2b949d04SAndroid Build Coastguard Worker     if (direction == XKB_KEY_DOWN && latch == LATCH_PENDING) {
446*2b949d04SAndroid Build Coastguard Worker         /* If this is a new keypress and we're awaiting our single latched
447*2b949d04SAndroid Build Coastguard Worker          * keypress, then either break the latch if any random key is pressed,
448*2b949d04SAndroid Build Coastguard Worker          * or promote it to a lock or plain base set if it's the same
449*2b949d04SAndroid Build Coastguard Worker          * modifier. */
450*2b949d04SAndroid Build Coastguard Worker         const union xkb_action *action = xkb_key_get_action(state, key);
451*2b949d04SAndroid Build Coastguard Worker         if (action->type == ACTION_TYPE_MOD_LATCH &&
452*2b949d04SAndroid Build Coastguard Worker             action->mods.flags == filter->action.mods.flags &&
453*2b949d04SAndroid Build Coastguard Worker             action->mods.mods.mask == filter->action.mods.mods.mask) {
454*2b949d04SAndroid Build Coastguard Worker             filter->action = *action;
455*2b949d04SAndroid Build Coastguard Worker             if (filter->action.mods.flags & ACTION_LATCH_TO_LOCK) {
456*2b949d04SAndroid Build Coastguard Worker                 filter->action.type = ACTION_TYPE_MOD_LOCK;
457*2b949d04SAndroid Build Coastguard Worker                 filter->func = xkb_filter_mod_lock_func;
458*2b949d04SAndroid Build Coastguard Worker                 state->components.locked_mods |= filter->action.mods.mods.mask;
459*2b949d04SAndroid Build Coastguard Worker             }
460*2b949d04SAndroid Build Coastguard Worker             else {
461*2b949d04SAndroid Build Coastguard Worker                 filter->action.type = ACTION_TYPE_MOD_SET;
462*2b949d04SAndroid Build Coastguard Worker                 filter->func = xkb_filter_mod_set_func;
463*2b949d04SAndroid Build Coastguard Worker                 state->set_mods = filter->action.mods.mods.mask;
464*2b949d04SAndroid Build Coastguard Worker             }
465*2b949d04SAndroid Build Coastguard Worker             filter->key = key;
466*2b949d04SAndroid Build Coastguard Worker             state->components.latched_mods &= ~filter->action.mods.mods.mask;
467*2b949d04SAndroid Build Coastguard Worker             /* XXX beep beep! */
468*2b949d04SAndroid Build Coastguard Worker             return XKB_FILTER_CONSUME;
469*2b949d04SAndroid Build Coastguard Worker         }
470*2b949d04SAndroid Build Coastguard Worker         else if (xkb_action_breaks_latch(action)) {
471*2b949d04SAndroid Build Coastguard Worker             /* XXX: This may be totally broken, we might need to break the
472*2b949d04SAndroid Build Coastguard Worker              *      latch in the next run after this press? */
473*2b949d04SAndroid Build Coastguard Worker             state->components.latched_mods &= ~filter->action.mods.mods.mask;
474*2b949d04SAndroid Build Coastguard Worker             filter->func = NULL;
475*2b949d04SAndroid Build Coastguard Worker             return XKB_FILTER_CONTINUE;
476*2b949d04SAndroid Build Coastguard Worker         }
477*2b949d04SAndroid Build Coastguard Worker     }
478*2b949d04SAndroid Build Coastguard Worker     else if (direction == XKB_KEY_UP && key == filter->key) {
479*2b949d04SAndroid Build Coastguard Worker         /* Our key got released.  If we've set it to clear locks, and we
480*2b949d04SAndroid Build Coastguard Worker          * currently have the same modifiers locked, then release them and
481*2b949d04SAndroid Build Coastguard Worker          * don't actually latch.  Else we've actually hit the latching
482*2b949d04SAndroid Build Coastguard Worker          * stage, so set PENDING and move our modifier from base to
483*2b949d04SAndroid Build Coastguard Worker          * latched. */
484*2b949d04SAndroid Build Coastguard Worker         if (latch == NO_LATCH ||
485*2b949d04SAndroid Build Coastguard Worker             ((filter->action.mods.flags & ACTION_LOCK_CLEAR) &&
486*2b949d04SAndroid Build Coastguard Worker              (state->components.locked_mods & filter->action.mods.mods.mask) ==
487*2b949d04SAndroid Build Coastguard Worker              filter->action.mods.mods.mask)) {
488*2b949d04SAndroid Build Coastguard Worker             /* XXX: We might be a bit overenthusiastic about clearing
489*2b949d04SAndroid Build Coastguard Worker              *      mods other filters have set here? */
490*2b949d04SAndroid Build Coastguard Worker             if (latch == LATCH_PENDING)
491*2b949d04SAndroid Build Coastguard Worker                 state->components.latched_mods &=
492*2b949d04SAndroid Build Coastguard Worker                     ~filter->action.mods.mods.mask;
493*2b949d04SAndroid Build Coastguard Worker             else
494*2b949d04SAndroid Build Coastguard Worker                 state->clear_mods = filter->action.mods.mods.mask;
495*2b949d04SAndroid Build Coastguard Worker             state->components.locked_mods &= ~filter->action.mods.mods.mask;
496*2b949d04SAndroid Build Coastguard Worker             filter->func = NULL;
497*2b949d04SAndroid Build Coastguard Worker         }
498*2b949d04SAndroid Build Coastguard Worker         else {
499*2b949d04SAndroid Build Coastguard Worker             latch = LATCH_PENDING;
500*2b949d04SAndroid Build Coastguard Worker             state->clear_mods = filter->action.mods.mods.mask;
501*2b949d04SAndroid Build Coastguard Worker             state->components.latched_mods |= filter->action.mods.mods.mask;
502*2b949d04SAndroid Build Coastguard Worker             /* XXX beep beep! */
503*2b949d04SAndroid Build Coastguard Worker         }
504*2b949d04SAndroid Build Coastguard Worker     }
505*2b949d04SAndroid Build Coastguard Worker     else if (direction == XKB_KEY_DOWN && latch == LATCH_KEY_DOWN) {
506*2b949d04SAndroid Build Coastguard Worker         /* Someone's pressed another key while we've still got the latching
507*2b949d04SAndroid Build Coastguard Worker          * key held down, so keep the base modifier state active (from
508*2b949d04SAndroid Build Coastguard Worker          * xkb_filter_mod_latch_new), but don't trip the latch, just clear
509*2b949d04SAndroid Build Coastguard Worker          * it as soon as the modifier gets released. */
510*2b949d04SAndroid Build Coastguard Worker         latch = NO_LATCH;
511*2b949d04SAndroid Build Coastguard Worker     }
512*2b949d04SAndroid Build Coastguard Worker 
513*2b949d04SAndroid Build Coastguard Worker     filter->priv = latch;
514*2b949d04SAndroid Build Coastguard Worker 
515*2b949d04SAndroid Build Coastguard Worker     return XKB_FILTER_CONTINUE;
516*2b949d04SAndroid Build Coastguard Worker }
517*2b949d04SAndroid Build Coastguard Worker 
518*2b949d04SAndroid Build Coastguard Worker static const struct {
519*2b949d04SAndroid Build Coastguard Worker     void (*new)(struct xkb_state *state, struct xkb_filter *filter);
520*2b949d04SAndroid Build Coastguard Worker     bool (*func)(struct xkb_state *state, struct xkb_filter *filter,
521*2b949d04SAndroid Build Coastguard Worker                  const struct xkb_key *key, enum xkb_key_direction direction);
522*2b949d04SAndroid Build Coastguard Worker } filter_action_funcs[_ACTION_TYPE_NUM_ENTRIES] = {
523*2b949d04SAndroid Build Coastguard Worker     [ACTION_TYPE_MOD_SET]    = { xkb_filter_mod_set_new,
524*2b949d04SAndroid Build Coastguard Worker                                  xkb_filter_mod_set_func },
525*2b949d04SAndroid Build Coastguard Worker     [ACTION_TYPE_MOD_LATCH]  = { xkb_filter_mod_latch_new,
526*2b949d04SAndroid Build Coastguard Worker                                  xkb_filter_mod_latch_func },
527*2b949d04SAndroid Build Coastguard Worker     [ACTION_TYPE_MOD_LOCK]   = { xkb_filter_mod_lock_new,
528*2b949d04SAndroid Build Coastguard Worker                                  xkb_filter_mod_lock_func },
529*2b949d04SAndroid Build Coastguard Worker     [ACTION_TYPE_GROUP_SET]  = { xkb_filter_group_set_new,
530*2b949d04SAndroid Build Coastguard Worker                                  xkb_filter_group_set_func },
531*2b949d04SAndroid Build Coastguard Worker     [ACTION_TYPE_GROUP_LOCK] = { xkb_filter_group_lock_new,
532*2b949d04SAndroid Build Coastguard Worker                                  xkb_filter_group_lock_func },
533*2b949d04SAndroid Build Coastguard Worker };
534*2b949d04SAndroid Build Coastguard Worker 
535*2b949d04SAndroid Build Coastguard Worker /**
536*2b949d04SAndroid Build Coastguard Worker  * Applies any relevant filters to the key, first from the list of filters
537*2b949d04SAndroid Build Coastguard Worker  * that are currently active, then if no filter has claimed the key, possibly
538*2b949d04SAndroid Build Coastguard Worker  * apply a new filter from the key action.
539*2b949d04SAndroid Build Coastguard Worker  */
540*2b949d04SAndroid Build Coastguard Worker static void
xkb_filter_apply_all(struct xkb_state * state,const struct xkb_key * key,enum xkb_key_direction direction)541*2b949d04SAndroid Build Coastguard Worker xkb_filter_apply_all(struct xkb_state *state,
542*2b949d04SAndroid Build Coastguard Worker                      const struct xkb_key *key,
543*2b949d04SAndroid Build Coastguard Worker                      enum xkb_key_direction direction)
544*2b949d04SAndroid Build Coastguard Worker {
545*2b949d04SAndroid Build Coastguard Worker     struct xkb_filter *filter;
546*2b949d04SAndroid Build Coastguard Worker     const union xkb_action *action;
547*2b949d04SAndroid Build Coastguard Worker     bool consumed;
548*2b949d04SAndroid Build Coastguard Worker 
549*2b949d04SAndroid Build Coastguard Worker     /* First run through all the currently active filters and see if any of
550*2b949d04SAndroid Build Coastguard Worker      * them have consumed this event. */
551*2b949d04SAndroid Build Coastguard Worker     consumed = false;
552*2b949d04SAndroid Build Coastguard Worker     darray_foreach(filter, state->filters) {
553*2b949d04SAndroid Build Coastguard Worker         if (!filter->func)
554*2b949d04SAndroid Build Coastguard Worker             continue;
555*2b949d04SAndroid Build Coastguard Worker 
556*2b949d04SAndroid Build Coastguard Worker         if (filter->func(state, filter, key, direction) == XKB_FILTER_CONSUME)
557*2b949d04SAndroid Build Coastguard Worker             consumed = true;
558*2b949d04SAndroid Build Coastguard Worker     }
559*2b949d04SAndroid Build Coastguard Worker     if (consumed || direction == XKB_KEY_UP)
560*2b949d04SAndroid Build Coastguard Worker         return;
561*2b949d04SAndroid Build Coastguard Worker 
562*2b949d04SAndroid Build Coastguard Worker     action = xkb_key_get_action(state, key);
563*2b949d04SAndroid Build Coastguard Worker 
564*2b949d04SAndroid Build Coastguard Worker     /*
565*2b949d04SAndroid Build Coastguard Worker      * It's possible for the keymap to set action->type explicitly, like so:
566*2b949d04SAndroid Build Coastguard Worker      *     interpret XF86_Next_VMode {
567*2b949d04SAndroid Build Coastguard Worker      *         action = Private(type=0x86, data="+VMode");
568*2b949d04SAndroid Build Coastguard Worker      *     };
569*2b949d04SAndroid Build Coastguard Worker      * We don't handle those.
570*2b949d04SAndroid Build Coastguard Worker      */
571*2b949d04SAndroid Build Coastguard Worker     if (action->type >= _ACTION_TYPE_NUM_ENTRIES)
572*2b949d04SAndroid Build Coastguard Worker         return;
573*2b949d04SAndroid Build Coastguard Worker 
574*2b949d04SAndroid Build Coastguard Worker     if (!filter_action_funcs[action->type].new)
575*2b949d04SAndroid Build Coastguard Worker         return;
576*2b949d04SAndroid Build Coastguard Worker 
577*2b949d04SAndroid Build Coastguard Worker     filter = xkb_filter_new(state);
578*2b949d04SAndroid Build Coastguard Worker     filter->key = key;
579*2b949d04SAndroid Build Coastguard Worker     filter->func = filter_action_funcs[action->type].func;
580*2b949d04SAndroid Build Coastguard Worker     filter->action = *action;
581*2b949d04SAndroid Build Coastguard Worker     filter_action_funcs[action->type].new(state, filter);
582*2b949d04SAndroid Build Coastguard Worker }
583*2b949d04SAndroid Build Coastguard Worker 
584*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT struct xkb_state *
xkb_state_new(struct xkb_keymap * keymap)585*2b949d04SAndroid Build Coastguard Worker xkb_state_new(struct xkb_keymap *keymap)
586*2b949d04SAndroid Build Coastguard Worker {
587*2b949d04SAndroid Build Coastguard Worker     struct xkb_state *ret;
588*2b949d04SAndroid Build Coastguard Worker 
589*2b949d04SAndroid Build Coastguard Worker     ret = calloc(sizeof(*ret), 1);
590*2b949d04SAndroid Build Coastguard Worker     if (!ret)
591*2b949d04SAndroid Build Coastguard Worker         return NULL;
592*2b949d04SAndroid Build Coastguard Worker 
593*2b949d04SAndroid Build Coastguard Worker     ret->refcnt = 1;
594*2b949d04SAndroid Build Coastguard Worker     ret->keymap = xkb_keymap_ref(keymap);
595*2b949d04SAndroid Build Coastguard Worker 
596*2b949d04SAndroid Build Coastguard Worker     return ret;
597*2b949d04SAndroid Build Coastguard Worker }
598*2b949d04SAndroid Build Coastguard Worker 
599*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT struct xkb_state *
xkb_state_ref(struct xkb_state * state)600*2b949d04SAndroid Build Coastguard Worker xkb_state_ref(struct xkb_state *state)
601*2b949d04SAndroid Build Coastguard Worker {
602*2b949d04SAndroid Build Coastguard Worker     state->refcnt++;
603*2b949d04SAndroid Build Coastguard Worker     return state;
604*2b949d04SAndroid Build Coastguard Worker }
605*2b949d04SAndroid Build Coastguard Worker 
606*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT void
xkb_state_unref(struct xkb_state * state)607*2b949d04SAndroid Build Coastguard Worker xkb_state_unref(struct xkb_state *state)
608*2b949d04SAndroid Build Coastguard Worker {
609*2b949d04SAndroid Build Coastguard Worker     if (!state || --state->refcnt > 0)
610*2b949d04SAndroid Build Coastguard Worker         return;
611*2b949d04SAndroid Build Coastguard Worker 
612*2b949d04SAndroid Build Coastguard Worker     xkb_keymap_unref(state->keymap);
613*2b949d04SAndroid Build Coastguard Worker     darray_free(state->filters);
614*2b949d04SAndroid Build Coastguard Worker     free(state);
615*2b949d04SAndroid Build Coastguard Worker }
616*2b949d04SAndroid Build Coastguard Worker 
617*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT struct xkb_keymap *
xkb_state_get_keymap(struct xkb_state * state)618*2b949d04SAndroid Build Coastguard Worker xkb_state_get_keymap(struct xkb_state *state)
619*2b949d04SAndroid Build Coastguard Worker {
620*2b949d04SAndroid Build Coastguard Worker     return state->keymap;
621*2b949d04SAndroid Build Coastguard Worker }
622*2b949d04SAndroid Build Coastguard Worker 
623*2b949d04SAndroid Build Coastguard Worker /**
624*2b949d04SAndroid Build Coastguard Worker  * Update the LED state to match the rest of the xkb_state.
625*2b949d04SAndroid Build Coastguard Worker  */
626*2b949d04SAndroid Build Coastguard Worker static void
xkb_state_led_update_all(struct xkb_state * state)627*2b949d04SAndroid Build Coastguard Worker xkb_state_led_update_all(struct xkb_state *state)
628*2b949d04SAndroid Build Coastguard Worker {
629*2b949d04SAndroid Build Coastguard Worker     xkb_led_index_t idx;
630*2b949d04SAndroid Build Coastguard Worker     const struct xkb_led *led;
631*2b949d04SAndroid Build Coastguard Worker 
632*2b949d04SAndroid Build Coastguard Worker     state->components.leds = 0;
633*2b949d04SAndroid Build Coastguard Worker 
634*2b949d04SAndroid Build Coastguard Worker     xkb_leds_enumerate(idx, led, state->keymap) {
635*2b949d04SAndroid Build Coastguard Worker         xkb_mod_mask_t mod_mask = 0;
636*2b949d04SAndroid Build Coastguard Worker         xkb_layout_mask_t group_mask = 0;
637*2b949d04SAndroid Build Coastguard Worker 
638*2b949d04SAndroid Build Coastguard Worker         if (led->which_mods != 0 && led->mods.mask != 0) {
639*2b949d04SAndroid Build Coastguard Worker             if (led->which_mods & XKB_STATE_MODS_EFFECTIVE)
640*2b949d04SAndroid Build Coastguard Worker                 mod_mask |= state->components.mods;
641*2b949d04SAndroid Build Coastguard Worker             if (led->which_mods & XKB_STATE_MODS_DEPRESSED)
642*2b949d04SAndroid Build Coastguard Worker                 mod_mask |= state->components.base_mods;
643*2b949d04SAndroid Build Coastguard Worker             if (led->which_mods & XKB_STATE_MODS_LATCHED)
644*2b949d04SAndroid Build Coastguard Worker                 mod_mask |= state->components.latched_mods;
645*2b949d04SAndroid Build Coastguard Worker             if (led->which_mods & XKB_STATE_MODS_LOCKED)
646*2b949d04SAndroid Build Coastguard Worker                 mod_mask |= state->components.locked_mods;
647*2b949d04SAndroid Build Coastguard Worker 
648*2b949d04SAndroid Build Coastguard Worker             if (led->mods.mask & mod_mask) {
649*2b949d04SAndroid Build Coastguard Worker                 state->components.leds |= (1u << idx);
650*2b949d04SAndroid Build Coastguard Worker                 continue;
651*2b949d04SAndroid Build Coastguard Worker             }
652*2b949d04SAndroid Build Coastguard Worker         }
653*2b949d04SAndroid Build Coastguard Worker 
654*2b949d04SAndroid Build Coastguard Worker         if (led->which_groups != 0 && led->groups != 0) {
655*2b949d04SAndroid Build Coastguard Worker             if (led->which_groups & XKB_STATE_LAYOUT_EFFECTIVE)
656*2b949d04SAndroid Build Coastguard Worker                 group_mask |= (1u << state->components.group);
657*2b949d04SAndroid Build Coastguard Worker             if (led->which_groups & XKB_STATE_LAYOUT_DEPRESSED)
658*2b949d04SAndroid Build Coastguard Worker                 group_mask |= (1u << state->components.base_group);
659*2b949d04SAndroid Build Coastguard Worker             if (led->which_groups & XKB_STATE_LAYOUT_LATCHED)
660*2b949d04SAndroid Build Coastguard Worker                 group_mask |= (1u << state->components.latched_group);
661*2b949d04SAndroid Build Coastguard Worker             if (led->which_groups & XKB_STATE_LAYOUT_LOCKED)
662*2b949d04SAndroid Build Coastguard Worker                 group_mask |= (1u << state->components.locked_group);
663*2b949d04SAndroid Build Coastguard Worker 
664*2b949d04SAndroid Build Coastguard Worker             if (led->groups & group_mask) {
665*2b949d04SAndroid Build Coastguard Worker                 state->components.leds |= (1u << idx);
666*2b949d04SAndroid Build Coastguard Worker                 continue;
667*2b949d04SAndroid Build Coastguard Worker             }
668*2b949d04SAndroid Build Coastguard Worker         }
669*2b949d04SAndroid Build Coastguard Worker 
670*2b949d04SAndroid Build Coastguard Worker         if (led->ctrls & state->keymap->enabled_ctrls) {
671*2b949d04SAndroid Build Coastguard Worker             state->components.leds |= (1u << idx);
672*2b949d04SAndroid Build Coastguard Worker             continue;
673*2b949d04SAndroid Build Coastguard Worker         }
674*2b949d04SAndroid Build Coastguard Worker     }
675*2b949d04SAndroid Build Coastguard Worker }
676*2b949d04SAndroid Build Coastguard Worker 
677*2b949d04SAndroid Build Coastguard Worker /**
678*2b949d04SAndroid Build Coastguard Worker  * Calculates the derived state (effective mods/group and LEDs) from an
679*2b949d04SAndroid Build Coastguard Worker  * up-to-date xkb_state.
680*2b949d04SAndroid Build Coastguard Worker  */
681*2b949d04SAndroid Build Coastguard Worker static void
xkb_state_update_derived(struct xkb_state * state)682*2b949d04SAndroid Build Coastguard Worker xkb_state_update_derived(struct xkb_state *state)
683*2b949d04SAndroid Build Coastguard Worker {
684*2b949d04SAndroid Build Coastguard Worker     xkb_layout_index_t wrapped;
685*2b949d04SAndroid Build Coastguard Worker 
686*2b949d04SAndroid Build Coastguard Worker     state->components.mods = (state->components.base_mods |
687*2b949d04SAndroid Build Coastguard Worker                               state->components.latched_mods |
688*2b949d04SAndroid Build Coastguard Worker                               state->components.locked_mods);
689*2b949d04SAndroid Build Coastguard Worker 
690*2b949d04SAndroid Build Coastguard Worker     /* TODO: Use groups_wrap control instead of always RANGE_WRAP. */
691*2b949d04SAndroid Build Coastguard Worker 
692*2b949d04SAndroid Build Coastguard Worker     wrapped = XkbWrapGroupIntoRange(state->components.locked_group,
693*2b949d04SAndroid Build Coastguard Worker                                     state->keymap->num_groups,
694*2b949d04SAndroid Build Coastguard Worker                                     RANGE_WRAP, 0);
695*2b949d04SAndroid Build Coastguard Worker     state->components.locked_group =
696*2b949d04SAndroid Build Coastguard Worker         (wrapped == XKB_LAYOUT_INVALID ? 0 : wrapped);
697*2b949d04SAndroid Build Coastguard Worker 
698*2b949d04SAndroid Build Coastguard Worker     wrapped = XkbWrapGroupIntoRange(state->components.base_group +
699*2b949d04SAndroid Build Coastguard Worker                                     state->components.latched_group +
700*2b949d04SAndroid Build Coastguard Worker                                     state->components.locked_group,
701*2b949d04SAndroid Build Coastguard Worker                                     state->keymap->num_groups,
702*2b949d04SAndroid Build Coastguard Worker                                     RANGE_WRAP, 0);
703*2b949d04SAndroid Build Coastguard Worker     state->components.group =
704*2b949d04SAndroid Build Coastguard Worker         (wrapped == XKB_LAYOUT_INVALID ? 0 : wrapped);
705*2b949d04SAndroid Build Coastguard Worker 
706*2b949d04SAndroid Build Coastguard Worker     xkb_state_led_update_all(state);
707*2b949d04SAndroid Build Coastguard Worker }
708*2b949d04SAndroid Build Coastguard Worker 
709*2b949d04SAndroid Build Coastguard Worker static enum xkb_state_component
get_state_component_changes(const struct state_components * a,const struct state_components * b)710*2b949d04SAndroid Build Coastguard Worker get_state_component_changes(const struct state_components *a,
711*2b949d04SAndroid Build Coastguard Worker                             const struct state_components *b)
712*2b949d04SAndroid Build Coastguard Worker {
713*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t mask = 0;
714*2b949d04SAndroid Build Coastguard Worker 
715*2b949d04SAndroid Build Coastguard Worker     if (a->group != b->group)
716*2b949d04SAndroid Build Coastguard Worker         mask |= XKB_STATE_LAYOUT_EFFECTIVE;
717*2b949d04SAndroid Build Coastguard Worker     if (a->base_group != b->base_group)
718*2b949d04SAndroid Build Coastguard Worker         mask |= XKB_STATE_LAYOUT_DEPRESSED;
719*2b949d04SAndroid Build Coastguard Worker     if (a->latched_group != b->latched_group)
720*2b949d04SAndroid Build Coastguard Worker         mask |= XKB_STATE_LAYOUT_LATCHED;
721*2b949d04SAndroid Build Coastguard Worker     if (a->locked_group != b->locked_group)
722*2b949d04SAndroid Build Coastguard Worker         mask |= XKB_STATE_LAYOUT_LOCKED;
723*2b949d04SAndroid Build Coastguard Worker     if (a->mods != b->mods)
724*2b949d04SAndroid Build Coastguard Worker         mask |= XKB_STATE_MODS_EFFECTIVE;
725*2b949d04SAndroid Build Coastguard Worker     if (a->base_mods != b->base_mods)
726*2b949d04SAndroid Build Coastguard Worker         mask |= XKB_STATE_MODS_DEPRESSED;
727*2b949d04SAndroid Build Coastguard Worker     if (a->latched_mods != b->latched_mods)
728*2b949d04SAndroid Build Coastguard Worker         mask |= XKB_STATE_MODS_LATCHED;
729*2b949d04SAndroid Build Coastguard Worker     if (a->locked_mods != b->locked_mods)
730*2b949d04SAndroid Build Coastguard Worker         mask |= XKB_STATE_MODS_LOCKED;
731*2b949d04SAndroid Build Coastguard Worker     if (a->leds != b->leds)
732*2b949d04SAndroid Build Coastguard Worker         mask |= XKB_STATE_LEDS;
733*2b949d04SAndroid Build Coastguard Worker 
734*2b949d04SAndroid Build Coastguard Worker     return mask;
735*2b949d04SAndroid Build Coastguard Worker }
736*2b949d04SAndroid Build Coastguard Worker 
737*2b949d04SAndroid Build Coastguard Worker /**
738*2b949d04SAndroid Build Coastguard Worker  * Given a particular key event, updates the state structure to reflect the
739*2b949d04SAndroid Build Coastguard Worker  * new modifiers.
740*2b949d04SAndroid Build Coastguard Worker  */
741*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT enum xkb_state_component
xkb_state_update_key(struct xkb_state * state,xkb_keycode_t kc,enum xkb_key_direction direction)742*2b949d04SAndroid Build Coastguard Worker xkb_state_update_key(struct xkb_state *state, xkb_keycode_t kc,
743*2b949d04SAndroid Build Coastguard Worker                      enum xkb_key_direction direction)
744*2b949d04SAndroid Build Coastguard Worker {
745*2b949d04SAndroid Build Coastguard Worker     xkb_mod_index_t i;
746*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t bit;
747*2b949d04SAndroid Build Coastguard Worker     struct state_components prev_components;
748*2b949d04SAndroid Build Coastguard Worker     const struct xkb_key *key = XkbKey(state->keymap, kc);
749*2b949d04SAndroid Build Coastguard Worker 
750*2b949d04SAndroid Build Coastguard Worker     if (!key)
751*2b949d04SAndroid Build Coastguard Worker         return 0;
752*2b949d04SAndroid Build Coastguard Worker 
753*2b949d04SAndroid Build Coastguard Worker     prev_components = state->components;
754*2b949d04SAndroid Build Coastguard Worker 
755*2b949d04SAndroid Build Coastguard Worker     state->set_mods = 0;
756*2b949d04SAndroid Build Coastguard Worker     state->clear_mods = 0;
757*2b949d04SAndroid Build Coastguard Worker 
758*2b949d04SAndroid Build Coastguard Worker     xkb_filter_apply_all(state, key, direction);
759*2b949d04SAndroid Build Coastguard Worker 
760*2b949d04SAndroid Build Coastguard Worker     for (i = 0, bit = 1; state->set_mods; i++, bit <<= 1) {
761*2b949d04SAndroid Build Coastguard Worker         if (state->set_mods & bit) {
762*2b949d04SAndroid Build Coastguard Worker             state->mod_key_count[i]++;
763*2b949d04SAndroid Build Coastguard Worker             state->components.base_mods |= bit;
764*2b949d04SAndroid Build Coastguard Worker             state->set_mods &= ~bit;
765*2b949d04SAndroid Build Coastguard Worker         }
766*2b949d04SAndroid Build Coastguard Worker     }
767*2b949d04SAndroid Build Coastguard Worker 
768*2b949d04SAndroid Build Coastguard Worker     for (i = 0, bit = 1; state->clear_mods; i++, bit <<= 1) {
769*2b949d04SAndroid Build Coastguard Worker         if (state->clear_mods & bit) {
770*2b949d04SAndroid Build Coastguard Worker             state->mod_key_count[i]--;
771*2b949d04SAndroid Build Coastguard Worker             if (state->mod_key_count[i] <= 0) {
772*2b949d04SAndroid Build Coastguard Worker                 state->components.base_mods &= ~bit;
773*2b949d04SAndroid Build Coastguard Worker                 state->mod_key_count[i] = 0;
774*2b949d04SAndroid Build Coastguard Worker             }
775*2b949d04SAndroid Build Coastguard Worker             state->clear_mods &= ~bit;
776*2b949d04SAndroid Build Coastguard Worker         }
777*2b949d04SAndroid Build Coastguard Worker     }
778*2b949d04SAndroid Build Coastguard Worker 
779*2b949d04SAndroid Build Coastguard Worker     xkb_state_update_derived(state);
780*2b949d04SAndroid Build Coastguard Worker 
781*2b949d04SAndroid Build Coastguard Worker     return get_state_component_changes(&prev_components, &state->components);
782*2b949d04SAndroid Build Coastguard Worker }
783*2b949d04SAndroid Build Coastguard Worker 
784*2b949d04SAndroid Build Coastguard Worker /**
785*2b949d04SAndroid Build Coastguard Worker  * Updates the state from a set of explicit masks as gained from
786*2b949d04SAndroid Build Coastguard Worker  * xkb_state_serialize_mods and xkb_state_serialize_groups.  As noted in the
787*2b949d04SAndroid Build Coastguard Worker  * documentation for these functions in xkbcommon.h, this round-trip is
788*2b949d04SAndroid Build Coastguard Worker  * lossy, and should only be used to update a slave state mirroring the
789*2b949d04SAndroid Build Coastguard Worker  * master, e.g. in a client/server window system.
790*2b949d04SAndroid Build Coastguard Worker  */
791*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT enum xkb_state_component
xkb_state_update_mask(struct xkb_state * state,xkb_mod_mask_t base_mods,xkb_mod_mask_t latched_mods,xkb_mod_mask_t locked_mods,xkb_layout_index_t base_group,xkb_layout_index_t latched_group,xkb_layout_index_t locked_group)792*2b949d04SAndroid Build Coastguard Worker xkb_state_update_mask(struct xkb_state *state,
793*2b949d04SAndroid Build Coastguard Worker                       xkb_mod_mask_t base_mods,
794*2b949d04SAndroid Build Coastguard Worker                       xkb_mod_mask_t latched_mods,
795*2b949d04SAndroid Build Coastguard Worker                       xkb_mod_mask_t locked_mods,
796*2b949d04SAndroid Build Coastguard Worker                       xkb_layout_index_t base_group,
797*2b949d04SAndroid Build Coastguard Worker                       xkb_layout_index_t latched_group,
798*2b949d04SAndroid Build Coastguard Worker                       xkb_layout_index_t locked_group)
799*2b949d04SAndroid Build Coastguard Worker {
800*2b949d04SAndroid Build Coastguard Worker     struct state_components prev_components;
801*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t mask;
802*2b949d04SAndroid Build Coastguard Worker 
803*2b949d04SAndroid Build Coastguard Worker     prev_components = state->components;
804*2b949d04SAndroid Build Coastguard Worker 
805*2b949d04SAndroid Build Coastguard Worker     /* Only include modifiers which exist in the keymap. */
806*2b949d04SAndroid Build Coastguard Worker     mask = (xkb_mod_mask_t) ((1ull << xkb_keymap_num_mods(state->keymap)) - 1u);
807*2b949d04SAndroid Build Coastguard Worker 
808*2b949d04SAndroid Build Coastguard Worker     state->components.base_mods = base_mods & mask;
809*2b949d04SAndroid Build Coastguard Worker     state->components.latched_mods = latched_mods & mask;
810*2b949d04SAndroid Build Coastguard Worker     state->components.locked_mods = locked_mods & mask;
811*2b949d04SAndroid Build Coastguard Worker 
812*2b949d04SAndroid Build Coastguard Worker     /* Make sure the mods are fully resolved - since we get arbitrary
813*2b949d04SAndroid Build Coastguard Worker      * input, they might not be.
814*2b949d04SAndroid Build Coastguard Worker      *
815*2b949d04SAndroid Build Coastguard Worker      * It might seem more reasonable to do this only for components.mods
816*2b949d04SAndroid Build Coastguard Worker      * in xkb_state_update_derived(), rather than for each component
817*2b949d04SAndroid Build Coastguard Worker      * seperately.  That would allow to distinguish between "really"
818*2b949d04SAndroid Build Coastguard Worker      * depressed mods (would be in MODS_DEPRESSED) and indirectly
819*2b949d04SAndroid Build Coastguard Worker      * depressed to to a mapping (would only be in MODS_EFFECTIVE).
820*2b949d04SAndroid Build Coastguard Worker      * However, the traditional behavior of xkb_state_update_key() is that
821*2b949d04SAndroid Build Coastguard Worker      * if a vmod is depressed, its mappings are depressed with it; so we're
822*2b949d04SAndroid Build Coastguard Worker      * expected to do the same here.  Also, LEDs (usually) look if a real
823*2b949d04SAndroid Build Coastguard Worker      * mod is locked, not just effective; otherwise it won't be lit.
824*2b949d04SAndroid Build Coastguard Worker      *
825*2b949d04SAndroid Build Coastguard Worker      * We OR here because mod_mask_get_effective() drops vmods. */
826*2b949d04SAndroid Build Coastguard Worker     state->components.base_mods |=
827*2b949d04SAndroid Build Coastguard Worker         mod_mask_get_effective(state->keymap, state->components.base_mods);
828*2b949d04SAndroid Build Coastguard Worker     state->components.latched_mods |=
829*2b949d04SAndroid Build Coastguard Worker         mod_mask_get_effective(state->keymap, state->components.latched_mods);
830*2b949d04SAndroid Build Coastguard Worker     state->components.locked_mods |=
831*2b949d04SAndroid Build Coastguard Worker         mod_mask_get_effective(state->keymap, state->components.locked_mods);
832*2b949d04SAndroid Build Coastguard Worker 
833*2b949d04SAndroid Build Coastguard Worker     state->components.base_group = base_group;
834*2b949d04SAndroid Build Coastguard Worker     state->components.latched_group = latched_group;
835*2b949d04SAndroid Build Coastguard Worker     state->components.locked_group = locked_group;
836*2b949d04SAndroid Build Coastguard Worker 
837*2b949d04SAndroid Build Coastguard Worker     xkb_state_update_derived(state);
838*2b949d04SAndroid Build Coastguard Worker 
839*2b949d04SAndroid Build Coastguard Worker     return get_state_component_changes(&prev_components, &state->components);
840*2b949d04SAndroid Build Coastguard Worker }
841*2b949d04SAndroid Build Coastguard Worker 
842*2b949d04SAndroid Build Coastguard Worker /**
843*2b949d04SAndroid Build Coastguard Worker  * Provides the symbols to use for the given key and state.  Returns the
844*2b949d04SAndroid Build Coastguard Worker  * number of symbols pointed to in syms_out.
845*2b949d04SAndroid Build Coastguard Worker  */
846*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT int
xkb_state_key_get_syms(struct xkb_state * state,xkb_keycode_t kc,const xkb_keysym_t ** syms_out)847*2b949d04SAndroid Build Coastguard Worker xkb_state_key_get_syms(struct xkb_state *state, xkb_keycode_t kc,
848*2b949d04SAndroid Build Coastguard Worker                        const xkb_keysym_t **syms_out)
849*2b949d04SAndroid Build Coastguard Worker {
850*2b949d04SAndroid Build Coastguard Worker     xkb_layout_index_t layout;
851*2b949d04SAndroid Build Coastguard Worker     xkb_level_index_t level;
852*2b949d04SAndroid Build Coastguard Worker 
853*2b949d04SAndroid Build Coastguard Worker     layout = xkb_state_key_get_layout(state, kc);
854*2b949d04SAndroid Build Coastguard Worker     if (layout == XKB_LAYOUT_INVALID)
855*2b949d04SAndroid Build Coastguard Worker         goto err;
856*2b949d04SAndroid Build Coastguard Worker 
857*2b949d04SAndroid Build Coastguard Worker     level = xkb_state_key_get_level(state, kc, layout);
858*2b949d04SAndroid Build Coastguard Worker     if (level == XKB_LEVEL_INVALID)
859*2b949d04SAndroid Build Coastguard Worker         goto err;
860*2b949d04SAndroid Build Coastguard Worker 
861*2b949d04SAndroid Build Coastguard Worker     return xkb_keymap_key_get_syms_by_level(state->keymap, kc, layout, level,
862*2b949d04SAndroid Build Coastguard Worker                                             syms_out);
863*2b949d04SAndroid Build Coastguard Worker 
864*2b949d04SAndroid Build Coastguard Worker err:
865*2b949d04SAndroid Build Coastguard Worker     *syms_out = NULL;
866*2b949d04SAndroid Build Coastguard Worker     return 0;
867*2b949d04SAndroid Build Coastguard Worker }
868*2b949d04SAndroid Build Coastguard Worker 
869*2b949d04SAndroid Build Coastguard Worker /*
870*2b949d04SAndroid Build Coastguard Worker  * https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Lock_Modifier
871*2b949d04SAndroid Build Coastguard Worker  */
872*2b949d04SAndroid Build Coastguard Worker static bool
should_do_caps_transformation(struct xkb_state * state,xkb_keycode_t kc)873*2b949d04SAndroid Build Coastguard Worker should_do_caps_transformation(struct xkb_state *state, xkb_keycode_t kc)
874*2b949d04SAndroid Build Coastguard Worker {
875*2b949d04SAndroid Build Coastguard Worker     xkb_mod_index_t caps =
876*2b949d04SAndroid Build Coastguard Worker         xkb_keymap_mod_get_index(state->keymap, XKB_MOD_NAME_CAPS);
877*2b949d04SAndroid Build Coastguard Worker 
878*2b949d04SAndroid Build Coastguard Worker     return
879*2b949d04SAndroid Build Coastguard Worker         xkb_state_mod_index_is_active(state, caps, XKB_STATE_MODS_EFFECTIVE) > 0 &&
880*2b949d04SAndroid Build Coastguard Worker         xkb_state_mod_index_is_consumed(state, kc, caps) == 0;
881*2b949d04SAndroid Build Coastguard Worker }
882*2b949d04SAndroid Build Coastguard Worker 
883*2b949d04SAndroid Build Coastguard Worker /*
884*2b949d04SAndroid Build Coastguard Worker  * https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Control_Modifier
885*2b949d04SAndroid Build Coastguard Worker  */
886*2b949d04SAndroid Build Coastguard Worker static bool
should_do_ctrl_transformation(struct xkb_state * state,xkb_keycode_t kc)887*2b949d04SAndroid Build Coastguard Worker should_do_ctrl_transformation(struct xkb_state *state, xkb_keycode_t kc)
888*2b949d04SAndroid Build Coastguard Worker {
889*2b949d04SAndroid Build Coastguard Worker     xkb_mod_index_t ctrl =
890*2b949d04SAndroid Build Coastguard Worker         xkb_keymap_mod_get_index(state->keymap, XKB_MOD_NAME_CTRL);
891*2b949d04SAndroid Build Coastguard Worker 
892*2b949d04SAndroid Build Coastguard Worker     return
893*2b949d04SAndroid Build Coastguard Worker         xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_EFFECTIVE) > 0 &&
894*2b949d04SAndroid Build Coastguard Worker         xkb_state_mod_index_is_consumed(state, kc, ctrl) == 0;
895*2b949d04SAndroid Build Coastguard Worker }
896*2b949d04SAndroid Build Coastguard Worker 
897*2b949d04SAndroid Build Coastguard Worker /* Verbatim from libX11:src/xkb/XKBBind.c */
898*2b949d04SAndroid Build Coastguard Worker static char
XkbToControl(char ch)899*2b949d04SAndroid Build Coastguard Worker XkbToControl(char ch)
900*2b949d04SAndroid Build Coastguard Worker {
901*2b949d04SAndroid Build Coastguard Worker     char c = ch;
902*2b949d04SAndroid Build Coastguard Worker 
903*2b949d04SAndroid Build Coastguard Worker     if ((c >= '@' && c < '\177') || c == ' ')
904*2b949d04SAndroid Build Coastguard Worker         c &= 0x1F;
905*2b949d04SAndroid Build Coastguard Worker     else if (c == '2')
906*2b949d04SAndroid Build Coastguard Worker         c = '\000';
907*2b949d04SAndroid Build Coastguard Worker     else if (c >= '3' && c <= '7')
908*2b949d04SAndroid Build Coastguard Worker         c -= ('3' - '\033');
909*2b949d04SAndroid Build Coastguard Worker     else if (c == '8')
910*2b949d04SAndroid Build Coastguard Worker         c = '\177';
911*2b949d04SAndroid Build Coastguard Worker     else if (c == '/')
912*2b949d04SAndroid Build Coastguard Worker         c = '_' & 0x1F;
913*2b949d04SAndroid Build Coastguard Worker     return c;
914*2b949d04SAndroid Build Coastguard Worker }
915*2b949d04SAndroid Build Coastguard Worker 
916*2b949d04SAndroid Build Coastguard Worker /**
917*2b949d04SAndroid Build Coastguard Worker  * Provides either exactly one symbol, or XKB_KEY_NoSymbol.
918*2b949d04SAndroid Build Coastguard Worker  */
919*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT xkb_keysym_t
xkb_state_key_get_one_sym(struct xkb_state * state,xkb_keycode_t kc)920*2b949d04SAndroid Build Coastguard Worker xkb_state_key_get_one_sym(struct xkb_state *state, xkb_keycode_t kc)
921*2b949d04SAndroid Build Coastguard Worker {
922*2b949d04SAndroid Build Coastguard Worker     const xkb_keysym_t *syms;
923*2b949d04SAndroid Build Coastguard Worker     xkb_keysym_t sym;
924*2b949d04SAndroid Build Coastguard Worker     int num_syms;
925*2b949d04SAndroid Build Coastguard Worker 
926*2b949d04SAndroid Build Coastguard Worker     num_syms = xkb_state_key_get_syms(state, kc, &syms);
927*2b949d04SAndroid Build Coastguard Worker     if (num_syms != 1)
928*2b949d04SAndroid Build Coastguard Worker         return XKB_KEY_NoSymbol;
929*2b949d04SAndroid Build Coastguard Worker 
930*2b949d04SAndroid Build Coastguard Worker     sym = syms[0];
931*2b949d04SAndroid Build Coastguard Worker 
932*2b949d04SAndroid Build Coastguard Worker     if (should_do_caps_transformation(state, kc))
933*2b949d04SAndroid Build Coastguard Worker         sym = xkb_keysym_to_upper(sym);
934*2b949d04SAndroid Build Coastguard Worker 
935*2b949d04SAndroid Build Coastguard Worker     return sym;
936*2b949d04SAndroid Build Coastguard Worker }
937*2b949d04SAndroid Build Coastguard Worker 
938*2b949d04SAndroid Build Coastguard Worker /*
939*2b949d04SAndroid Build Coastguard Worker  * The caps and ctrl transformations require some special handling,
940*2b949d04SAndroid Build Coastguard Worker  * so we cannot simply use xkb_state_get_one_sym() for them.
941*2b949d04SAndroid Build Coastguard Worker  * In particular, if Control is set, we must try very hard to find
942*2b949d04SAndroid Build Coastguard Worker  * some layout in which the keysym is ASCII and thus can be (maybe)
943*2b949d04SAndroid Build Coastguard Worker  * converted to a control character. libX11 allows to disable this
944*2b949d04SAndroid Build Coastguard Worker  * behavior with the XkbLC_ControlFallback (see XkbSetXlibControls(3)),
945*2b949d04SAndroid Build Coastguard Worker  * but it is enabled by default, yippee.
946*2b949d04SAndroid Build Coastguard Worker  */
947*2b949d04SAndroid Build Coastguard Worker static xkb_keysym_t
get_one_sym_for_string(struct xkb_state * state,xkb_keycode_t kc)948*2b949d04SAndroid Build Coastguard Worker get_one_sym_for_string(struct xkb_state *state, xkb_keycode_t kc)
949*2b949d04SAndroid Build Coastguard Worker {
950*2b949d04SAndroid Build Coastguard Worker     xkb_level_index_t level;
951*2b949d04SAndroid Build Coastguard Worker     xkb_layout_index_t layout, num_layouts;
952*2b949d04SAndroid Build Coastguard Worker     const xkb_keysym_t *syms;
953*2b949d04SAndroid Build Coastguard Worker     int nsyms;
954*2b949d04SAndroid Build Coastguard Worker     xkb_keysym_t sym;
955*2b949d04SAndroid Build Coastguard Worker 
956*2b949d04SAndroid Build Coastguard Worker     layout = xkb_state_key_get_layout(state, kc);
957*2b949d04SAndroid Build Coastguard Worker     num_layouts = xkb_keymap_num_layouts_for_key(state->keymap, kc);
958*2b949d04SAndroid Build Coastguard Worker     level = xkb_state_key_get_level(state, kc, layout);
959*2b949d04SAndroid Build Coastguard Worker     if (layout == XKB_LAYOUT_INVALID || num_layouts == 0 ||
960*2b949d04SAndroid Build Coastguard Worker         level == XKB_LEVEL_INVALID)
961*2b949d04SAndroid Build Coastguard Worker         return XKB_KEY_NoSymbol;
962*2b949d04SAndroid Build Coastguard Worker 
963*2b949d04SAndroid Build Coastguard Worker     nsyms = xkb_keymap_key_get_syms_by_level(state->keymap, kc,
964*2b949d04SAndroid Build Coastguard Worker                                              layout, level, &syms);
965*2b949d04SAndroid Build Coastguard Worker     if (nsyms != 1)
966*2b949d04SAndroid Build Coastguard Worker         return XKB_KEY_NoSymbol;
967*2b949d04SAndroid Build Coastguard Worker     sym = syms[0];
968*2b949d04SAndroid Build Coastguard Worker 
969*2b949d04SAndroid Build Coastguard Worker     if (should_do_ctrl_transformation(state, kc) && sym > 127u) {
970*2b949d04SAndroid Build Coastguard Worker         for (xkb_layout_index_t i = 0; i < num_layouts; i++) {
971*2b949d04SAndroid Build Coastguard Worker             level = xkb_state_key_get_level(state, kc, i);
972*2b949d04SAndroid Build Coastguard Worker             if (level == XKB_LEVEL_INVALID)
973*2b949d04SAndroid Build Coastguard Worker                 continue;
974*2b949d04SAndroid Build Coastguard Worker 
975*2b949d04SAndroid Build Coastguard Worker             nsyms = xkb_keymap_key_get_syms_by_level(state->keymap, kc,
976*2b949d04SAndroid Build Coastguard Worker                                                      i, level, &syms);
977*2b949d04SAndroid Build Coastguard Worker             if (nsyms == 1 && syms[0] <= 127u) {
978*2b949d04SAndroid Build Coastguard Worker                 sym = syms[0];
979*2b949d04SAndroid Build Coastguard Worker                 break;
980*2b949d04SAndroid Build Coastguard Worker             }
981*2b949d04SAndroid Build Coastguard Worker         }
982*2b949d04SAndroid Build Coastguard Worker     }
983*2b949d04SAndroid Build Coastguard Worker 
984*2b949d04SAndroid Build Coastguard Worker     if (should_do_caps_transformation(state, kc)) {
985*2b949d04SAndroid Build Coastguard Worker         sym = xkb_keysym_to_upper(sym);
986*2b949d04SAndroid Build Coastguard Worker     }
987*2b949d04SAndroid Build Coastguard Worker 
988*2b949d04SAndroid Build Coastguard Worker     return sym;
989*2b949d04SAndroid Build Coastguard Worker }
990*2b949d04SAndroid Build Coastguard Worker 
991*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT int
xkb_state_key_get_utf8(struct xkb_state * state,xkb_keycode_t kc,char * buffer,size_t size)992*2b949d04SAndroid Build Coastguard Worker xkb_state_key_get_utf8(struct xkb_state *state, xkb_keycode_t kc,
993*2b949d04SAndroid Build Coastguard Worker                        char *buffer, size_t size)
994*2b949d04SAndroid Build Coastguard Worker {
995*2b949d04SAndroid Build Coastguard Worker     xkb_keysym_t sym;
996*2b949d04SAndroid Build Coastguard Worker     const xkb_keysym_t *syms;
997*2b949d04SAndroid Build Coastguard Worker     int nsyms;
998*2b949d04SAndroid Build Coastguard Worker     int offset;
999*2b949d04SAndroid Build Coastguard Worker     char tmp[7];
1000*2b949d04SAndroid Build Coastguard Worker 
1001*2b949d04SAndroid Build Coastguard Worker     sym = get_one_sym_for_string(state, kc);
1002*2b949d04SAndroid Build Coastguard Worker     if (sym != XKB_KEY_NoSymbol) {
1003*2b949d04SAndroid Build Coastguard Worker         nsyms = 1; syms = &sym;
1004*2b949d04SAndroid Build Coastguard Worker     }
1005*2b949d04SAndroid Build Coastguard Worker     else {
1006*2b949d04SAndroid Build Coastguard Worker         nsyms = xkb_state_key_get_syms(state, kc, &syms);
1007*2b949d04SAndroid Build Coastguard Worker     }
1008*2b949d04SAndroid Build Coastguard Worker 
1009*2b949d04SAndroid Build Coastguard Worker     /* Make sure not to truncate in the middle of a UTF-8 sequence. */
1010*2b949d04SAndroid Build Coastguard Worker     offset = 0;
1011*2b949d04SAndroid Build Coastguard Worker     for (int i = 0; i < nsyms; i++) {
1012*2b949d04SAndroid Build Coastguard Worker         int ret = xkb_keysym_to_utf8(syms[i], tmp, sizeof(tmp));
1013*2b949d04SAndroid Build Coastguard Worker         if (ret <= 0)
1014*2b949d04SAndroid Build Coastguard Worker             goto err_bad;
1015*2b949d04SAndroid Build Coastguard Worker 
1016*2b949d04SAndroid Build Coastguard Worker         ret--;
1017*2b949d04SAndroid Build Coastguard Worker         if ((size_t) (offset + ret) <= size)
1018*2b949d04SAndroid Build Coastguard Worker             memcpy(buffer + offset, tmp, ret);
1019*2b949d04SAndroid Build Coastguard Worker         offset += ret;
1020*2b949d04SAndroid Build Coastguard Worker     }
1021*2b949d04SAndroid Build Coastguard Worker 
1022*2b949d04SAndroid Build Coastguard Worker     if ((size_t) offset >= size)
1023*2b949d04SAndroid Build Coastguard Worker         goto err_trunc;
1024*2b949d04SAndroid Build Coastguard Worker     buffer[offset] = '\0';
1025*2b949d04SAndroid Build Coastguard Worker 
1026*2b949d04SAndroid Build Coastguard Worker     if (!is_valid_utf8(buffer, offset))
1027*2b949d04SAndroid Build Coastguard Worker         goto err_bad;
1028*2b949d04SAndroid Build Coastguard Worker 
1029*2b949d04SAndroid Build Coastguard Worker     if (offset == 1 && (unsigned int) buffer[0] <= 127u &&
1030*2b949d04SAndroid Build Coastguard Worker         should_do_ctrl_transformation(state, kc))
1031*2b949d04SAndroid Build Coastguard Worker         buffer[0] = XkbToControl(buffer[0]);
1032*2b949d04SAndroid Build Coastguard Worker 
1033*2b949d04SAndroid Build Coastguard Worker     return offset;
1034*2b949d04SAndroid Build Coastguard Worker 
1035*2b949d04SAndroid Build Coastguard Worker err_trunc:
1036*2b949d04SAndroid Build Coastguard Worker     if (size > 0)
1037*2b949d04SAndroid Build Coastguard Worker         buffer[size - 1] = '\0';
1038*2b949d04SAndroid Build Coastguard Worker     return offset;
1039*2b949d04SAndroid Build Coastguard Worker 
1040*2b949d04SAndroid Build Coastguard Worker err_bad:
1041*2b949d04SAndroid Build Coastguard Worker     if (size > 0)
1042*2b949d04SAndroid Build Coastguard Worker         buffer[0] = '\0';
1043*2b949d04SAndroid Build Coastguard Worker     return 0;
1044*2b949d04SAndroid Build Coastguard Worker }
1045*2b949d04SAndroid Build Coastguard Worker 
1046*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT uint32_t
xkb_state_key_get_utf32(struct xkb_state * state,xkb_keycode_t kc)1047*2b949d04SAndroid Build Coastguard Worker xkb_state_key_get_utf32(struct xkb_state *state, xkb_keycode_t kc)
1048*2b949d04SAndroid Build Coastguard Worker {
1049*2b949d04SAndroid Build Coastguard Worker     xkb_keysym_t sym;
1050*2b949d04SAndroid Build Coastguard Worker     uint32_t cp;
1051*2b949d04SAndroid Build Coastguard Worker 
1052*2b949d04SAndroid Build Coastguard Worker     sym = get_one_sym_for_string(state, kc);
1053*2b949d04SAndroid Build Coastguard Worker     cp = xkb_keysym_to_utf32(sym);
1054*2b949d04SAndroid Build Coastguard Worker 
1055*2b949d04SAndroid Build Coastguard Worker     if (cp <= 127u && should_do_ctrl_transformation(state, kc))
1056*2b949d04SAndroid Build Coastguard Worker         cp = (uint32_t) XkbToControl((char) cp);
1057*2b949d04SAndroid Build Coastguard Worker 
1058*2b949d04SAndroid Build Coastguard Worker     return cp;
1059*2b949d04SAndroid Build Coastguard Worker }
1060*2b949d04SAndroid Build Coastguard Worker 
1061*2b949d04SAndroid Build Coastguard Worker /**
1062*2b949d04SAndroid Build Coastguard Worker  * Serialises the requested modifier state into an xkb_mod_mask_t, with all
1063*2b949d04SAndroid Build Coastguard Worker  * the same disclaimers as in xkb_state_update_mask.
1064*2b949d04SAndroid Build Coastguard Worker  */
1065*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT xkb_mod_mask_t
xkb_state_serialize_mods(struct xkb_state * state,enum xkb_state_component type)1066*2b949d04SAndroid Build Coastguard Worker xkb_state_serialize_mods(struct xkb_state *state,
1067*2b949d04SAndroid Build Coastguard Worker                          enum xkb_state_component type)
1068*2b949d04SAndroid Build Coastguard Worker {
1069*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t ret = 0;
1070*2b949d04SAndroid Build Coastguard Worker 
1071*2b949d04SAndroid Build Coastguard Worker     if (type & XKB_STATE_MODS_EFFECTIVE)
1072*2b949d04SAndroid Build Coastguard Worker         return state->components.mods;
1073*2b949d04SAndroid Build Coastguard Worker 
1074*2b949d04SAndroid Build Coastguard Worker     if (type & XKB_STATE_MODS_DEPRESSED)
1075*2b949d04SAndroid Build Coastguard Worker         ret |= state->components.base_mods;
1076*2b949d04SAndroid Build Coastguard Worker     if (type & XKB_STATE_MODS_LATCHED)
1077*2b949d04SAndroid Build Coastguard Worker         ret |= state->components.latched_mods;
1078*2b949d04SAndroid Build Coastguard Worker     if (type & XKB_STATE_MODS_LOCKED)
1079*2b949d04SAndroid Build Coastguard Worker         ret |= state->components.locked_mods;
1080*2b949d04SAndroid Build Coastguard Worker 
1081*2b949d04SAndroid Build Coastguard Worker     return ret;
1082*2b949d04SAndroid Build Coastguard Worker }
1083*2b949d04SAndroid Build Coastguard Worker 
1084*2b949d04SAndroid Build Coastguard Worker /**
1085*2b949d04SAndroid Build Coastguard Worker  * Serialises the requested group state, with all the same disclaimers as
1086*2b949d04SAndroid Build Coastguard Worker  * in xkb_state_update_mask.
1087*2b949d04SAndroid Build Coastguard Worker  */
1088*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT xkb_layout_index_t
xkb_state_serialize_layout(struct xkb_state * state,enum xkb_state_component type)1089*2b949d04SAndroid Build Coastguard Worker xkb_state_serialize_layout(struct xkb_state *state,
1090*2b949d04SAndroid Build Coastguard Worker                            enum xkb_state_component type)
1091*2b949d04SAndroid Build Coastguard Worker {
1092*2b949d04SAndroid Build Coastguard Worker     xkb_layout_index_t ret = 0;
1093*2b949d04SAndroid Build Coastguard Worker 
1094*2b949d04SAndroid Build Coastguard Worker     if (type & XKB_STATE_LAYOUT_EFFECTIVE)
1095*2b949d04SAndroid Build Coastguard Worker         return state->components.group;
1096*2b949d04SAndroid Build Coastguard Worker 
1097*2b949d04SAndroid Build Coastguard Worker     if (type & XKB_STATE_LAYOUT_DEPRESSED)
1098*2b949d04SAndroid Build Coastguard Worker         ret += state->components.base_group;
1099*2b949d04SAndroid Build Coastguard Worker     if (type & XKB_STATE_LAYOUT_LATCHED)
1100*2b949d04SAndroid Build Coastguard Worker         ret += state->components.latched_group;
1101*2b949d04SAndroid Build Coastguard Worker     if (type & XKB_STATE_LAYOUT_LOCKED)
1102*2b949d04SAndroid Build Coastguard Worker         ret += state->components.locked_group;
1103*2b949d04SAndroid Build Coastguard Worker 
1104*2b949d04SAndroid Build Coastguard Worker     return ret;
1105*2b949d04SAndroid Build Coastguard Worker }
1106*2b949d04SAndroid Build Coastguard Worker 
1107*2b949d04SAndroid Build Coastguard Worker /**
1108*2b949d04SAndroid Build Coastguard Worker  * Gets a modifier mask and returns the resolved effective mask; this
1109*2b949d04SAndroid Build Coastguard Worker  * is needed because some modifiers can also map to other modifiers, e.g.
1110*2b949d04SAndroid Build Coastguard Worker  * the "NumLock" modifier usually also sets the "Mod2" modifier.
1111*2b949d04SAndroid Build Coastguard Worker  */
1112*2b949d04SAndroid Build Coastguard Worker xkb_mod_mask_t
mod_mask_get_effective(struct xkb_keymap * keymap,xkb_mod_mask_t mods)1113*2b949d04SAndroid Build Coastguard Worker mod_mask_get_effective(struct xkb_keymap *keymap, xkb_mod_mask_t mods)
1114*2b949d04SAndroid Build Coastguard Worker {
1115*2b949d04SAndroid Build Coastguard Worker     const struct xkb_mod *mod;
1116*2b949d04SAndroid Build Coastguard Worker     xkb_mod_index_t i;
1117*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t mask;
1118*2b949d04SAndroid Build Coastguard Worker 
1119*2b949d04SAndroid Build Coastguard Worker     /* The effective mask is only real mods for now. */
1120*2b949d04SAndroid Build Coastguard Worker     mask = mods & MOD_REAL_MASK_ALL;
1121*2b949d04SAndroid Build Coastguard Worker 
1122*2b949d04SAndroid Build Coastguard Worker     xkb_mods_enumerate(i, mod, &keymap->mods)
1123*2b949d04SAndroid Build Coastguard Worker         if (mods & (1u << i))
1124*2b949d04SAndroid Build Coastguard Worker             mask |= mod->mapping;
1125*2b949d04SAndroid Build Coastguard Worker 
1126*2b949d04SAndroid Build Coastguard Worker     return mask;
1127*2b949d04SAndroid Build Coastguard Worker }
1128*2b949d04SAndroid Build Coastguard Worker 
1129*2b949d04SAndroid Build Coastguard Worker /**
1130*2b949d04SAndroid Build Coastguard Worker  * Returns 1 if the given modifier is active with the specified type(s), 0 if
1131*2b949d04SAndroid Build Coastguard Worker  * not, or -1 if the modifier is invalid.
1132*2b949d04SAndroid Build Coastguard Worker  */
1133*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT int
xkb_state_mod_index_is_active(struct xkb_state * state,xkb_mod_index_t idx,enum xkb_state_component type)1134*2b949d04SAndroid Build Coastguard Worker xkb_state_mod_index_is_active(struct xkb_state *state,
1135*2b949d04SAndroid Build Coastguard Worker                               xkb_mod_index_t idx,
1136*2b949d04SAndroid Build Coastguard Worker                               enum xkb_state_component type)
1137*2b949d04SAndroid Build Coastguard Worker {
1138*2b949d04SAndroid Build Coastguard Worker     if (idx >= xkb_keymap_num_mods(state->keymap))
1139*2b949d04SAndroid Build Coastguard Worker         return -1;
1140*2b949d04SAndroid Build Coastguard Worker 
1141*2b949d04SAndroid Build Coastguard Worker     return !!(xkb_state_serialize_mods(state, type) & (1u << idx));
1142*2b949d04SAndroid Build Coastguard Worker }
1143*2b949d04SAndroid Build Coastguard Worker 
1144*2b949d04SAndroid Build Coastguard Worker /**
1145*2b949d04SAndroid Build Coastguard Worker  * Helper function for xkb_state_mod_indices_are_active and
1146*2b949d04SAndroid Build Coastguard Worker  * xkb_state_mod_names_are_active.
1147*2b949d04SAndroid Build Coastguard Worker  */
1148*2b949d04SAndroid Build Coastguard Worker static bool
match_mod_masks(struct xkb_state * state,enum xkb_state_component type,enum xkb_state_match match,xkb_mod_mask_t wanted)1149*2b949d04SAndroid Build Coastguard Worker match_mod_masks(struct xkb_state *state,
1150*2b949d04SAndroid Build Coastguard Worker                 enum xkb_state_component type,
1151*2b949d04SAndroid Build Coastguard Worker                 enum xkb_state_match match,
1152*2b949d04SAndroid Build Coastguard Worker                 xkb_mod_mask_t wanted)
1153*2b949d04SAndroid Build Coastguard Worker {
1154*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t active = xkb_state_serialize_mods(state, type);
1155*2b949d04SAndroid Build Coastguard Worker 
1156*2b949d04SAndroid Build Coastguard Worker     if (!(match & XKB_STATE_MATCH_NON_EXCLUSIVE) && (active & ~wanted))
1157*2b949d04SAndroid Build Coastguard Worker         return false;
1158*2b949d04SAndroid Build Coastguard Worker 
1159*2b949d04SAndroid Build Coastguard Worker     if (match & XKB_STATE_MATCH_ANY)
1160*2b949d04SAndroid Build Coastguard Worker         return active & wanted;
1161*2b949d04SAndroid Build Coastguard Worker 
1162*2b949d04SAndroid Build Coastguard Worker     return (active & wanted) == wanted;
1163*2b949d04SAndroid Build Coastguard Worker }
1164*2b949d04SAndroid Build Coastguard Worker 
1165*2b949d04SAndroid Build Coastguard Worker /**
1166*2b949d04SAndroid Build Coastguard Worker  * Returns 1 if the modifiers are active with the specified type(s), 0 if
1167*2b949d04SAndroid Build Coastguard Worker  * not, or -1 if any of the modifiers are invalid.
1168*2b949d04SAndroid Build Coastguard Worker  */
1169*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT int
xkb_state_mod_indices_are_active(struct xkb_state * state,enum xkb_state_component type,enum xkb_state_match match,...)1170*2b949d04SAndroid Build Coastguard Worker xkb_state_mod_indices_are_active(struct xkb_state *state,
1171*2b949d04SAndroid Build Coastguard Worker                                  enum xkb_state_component type,
1172*2b949d04SAndroid Build Coastguard Worker                                  enum xkb_state_match match,
1173*2b949d04SAndroid Build Coastguard Worker                                  ...)
1174*2b949d04SAndroid Build Coastguard Worker {
1175*2b949d04SAndroid Build Coastguard Worker     va_list ap;
1176*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t wanted = 0;
1177*2b949d04SAndroid Build Coastguard Worker     int ret = 0;
1178*2b949d04SAndroid Build Coastguard Worker     xkb_mod_index_t num_mods = xkb_keymap_num_mods(state->keymap);
1179*2b949d04SAndroid Build Coastguard Worker 
1180*2b949d04SAndroid Build Coastguard Worker     va_start(ap, match);
1181*2b949d04SAndroid Build Coastguard Worker     while (1) {
1182*2b949d04SAndroid Build Coastguard Worker         xkb_mod_index_t idx = va_arg(ap, xkb_mod_index_t);
1183*2b949d04SAndroid Build Coastguard Worker         if (idx == XKB_MOD_INVALID)
1184*2b949d04SAndroid Build Coastguard Worker             break;
1185*2b949d04SAndroid Build Coastguard Worker         if (idx >= num_mods) {
1186*2b949d04SAndroid Build Coastguard Worker             ret = -1;
1187*2b949d04SAndroid Build Coastguard Worker             break;
1188*2b949d04SAndroid Build Coastguard Worker         }
1189*2b949d04SAndroid Build Coastguard Worker         wanted |= (1u << idx);
1190*2b949d04SAndroid Build Coastguard Worker     }
1191*2b949d04SAndroid Build Coastguard Worker     va_end(ap);
1192*2b949d04SAndroid Build Coastguard Worker 
1193*2b949d04SAndroid Build Coastguard Worker     if (ret == -1)
1194*2b949d04SAndroid Build Coastguard Worker         return ret;
1195*2b949d04SAndroid Build Coastguard Worker 
1196*2b949d04SAndroid Build Coastguard Worker     return match_mod_masks(state, type, match, wanted);
1197*2b949d04SAndroid Build Coastguard Worker }
1198*2b949d04SAndroid Build Coastguard Worker 
1199*2b949d04SAndroid Build Coastguard Worker /**
1200*2b949d04SAndroid Build Coastguard Worker  * Returns 1 if the given modifier is active with the specified type(s), 0 if
1201*2b949d04SAndroid Build Coastguard Worker  * not, or -1 if the modifier is invalid.
1202*2b949d04SAndroid Build Coastguard Worker  */
1203*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT int
xkb_state_mod_name_is_active(struct xkb_state * state,const char * name,enum xkb_state_component type)1204*2b949d04SAndroid Build Coastguard Worker xkb_state_mod_name_is_active(struct xkb_state *state, const char *name,
1205*2b949d04SAndroid Build Coastguard Worker                              enum xkb_state_component type)
1206*2b949d04SAndroid Build Coastguard Worker {
1207*2b949d04SAndroid Build Coastguard Worker     xkb_mod_index_t idx = xkb_keymap_mod_get_index(state->keymap, name);
1208*2b949d04SAndroid Build Coastguard Worker 
1209*2b949d04SAndroid Build Coastguard Worker     if (idx == XKB_MOD_INVALID)
1210*2b949d04SAndroid Build Coastguard Worker         return -1;
1211*2b949d04SAndroid Build Coastguard Worker 
1212*2b949d04SAndroid Build Coastguard Worker     return xkb_state_mod_index_is_active(state, idx, type);
1213*2b949d04SAndroid Build Coastguard Worker }
1214*2b949d04SAndroid Build Coastguard Worker 
1215*2b949d04SAndroid Build Coastguard Worker /**
1216*2b949d04SAndroid Build Coastguard Worker  * Returns 1 if the modifiers are active with the specified type(s), 0 if
1217*2b949d04SAndroid Build Coastguard Worker  * not, or -1 if any of the modifiers are invalid.
1218*2b949d04SAndroid Build Coastguard Worker  */
1219*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT ATTR_NULL_SENTINEL int
xkb_state_mod_names_are_active(struct xkb_state * state,enum xkb_state_component type,enum xkb_state_match match,...)1220*2b949d04SAndroid Build Coastguard Worker xkb_state_mod_names_are_active(struct xkb_state *state,
1221*2b949d04SAndroid Build Coastguard Worker                                enum xkb_state_component type,
1222*2b949d04SAndroid Build Coastguard Worker                                enum xkb_state_match match,
1223*2b949d04SAndroid Build Coastguard Worker                                ...)
1224*2b949d04SAndroid Build Coastguard Worker {
1225*2b949d04SAndroid Build Coastguard Worker     va_list ap;
1226*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t wanted = 0;
1227*2b949d04SAndroid Build Coastguard Worker     int ret = 0;
1228*2b949d04SAndroid Build Coastguard Worker 
1229*2b949d04SAndroid Build Coastguard Worker     va_start(ap, match);
1230*2b949d04SAndroid Build Coastguard Worker     while (1) {
1231*2b949d04SAndroid Build Coastguard Worker         xkb_mod_index_t idx;
1232*2b949d04SAndroid Build Coastguard Worker         const char *str = va_arg(ap, const char *);
1233*2b949d04SAndroid Build Coastguard Worker         if (str == NULL)
1234*2b949d04SAndroid Build Coastguard Worker             break;
1235*2b949d04SAndroid Build Coastguard Worker         idx = xkb_keymap_mod_get_index(state->keymap, str);
1236*2b949d04SAndroid Build Coastguard Worker         if (idx == XKB_MOD_INVALID) {
1237*2b949d04SAndroid Build Coastguard Worker             ret = -1;
1238*2b949d04SAndroid Build Coastguard Worker             break;
1239*2b949d04SAndroid Build Coastguard Worker         }
1240*2b949d04SAndroid Build Coastguard Worker         wanted |= (1u << idx);
1241*2b949d04SAndroid Build Coastguard Worker     }
1242*2b949d04SAndroid Build Coastguard Worker     va_end(ap);
1243*2b949d04SAndroid Build Coastguard Worker 
1244*2b949d04SAndroid Build Coastguard Worker     if (ret == -1)
1245*2b949d04SAndroid Build Coastguard Worker         return ret;
1246*2b949d04SAndroid Build Coastguard Worker 
1247*2b949d04SAndroid Build Coastguard Worker     return match_mod_masks(state, type, match, wanted);
1248*2b949d04SAndroid Build Coastguard Worker }
1249*2b949d04SAndroid Build Coastguard Worker 
1250*2b949d04SAndroid Build Coastguard Worker /**
1251*2b949d04SAndroid Build Coastguard Worker  * Returns 1 if the given group is active with the specified type(s), 0 if
1252*2b949d04SAndroid Build Coastguard Worker  * not, or -1 if the group is invalid.
1253*2b949d04SAndroid Build Coastguard Worker  */
1254*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT int
xkb_state_layout_index_is_active(struct xkb_state * state,xkb_layout_index_t idx,enum xkb_state_component type)1255*2b949d04SAndroid Build Coastguard Worker xkb_state_layout_index_is_active(struct xkb_state *state,
1256*2b949d04SAndroid Build Coastguard Worker                                 xkb_layout_index_t idx,
1257*2b949d04SAndroid Build Coastguard Worker                                 enum xkb_state_component type)
1258*2b949d04SAndroid Build Coastguard Worker {
1259*2b949d04SAndroid Build Coastguard Worker     int ret = 0;
1260*2b949d04SAndroid Build Coastguard Worker 
1261*2b949d04SAndroid Build Coastguard Worker     if (idx >= state->keymap->num_groups)
1262*2b949d04SAndroid Build Coastguard Worker         return -1;
1263*2b949d04SAndroid Build Coastguard Worker 
1264*2b949d04SAndroid Build Coastguard Worker     if (type & XKB_STATE_LAYOUT_EFFECTIVE)
1265*2b949d04SAndroid Build Coastguard Worker         ret |= (state->components.group == idx);
1266*2b949d04SAndroid Build Coastguard Worker     if (type & XKB_STATE_LAYOUT_DEPRESSED)
1267*2b949d04SAndroid Build Coastguard Worker         ret |= (state->components.base_group == (int32_t) idx);
1268*2b949d04SAndroid Build Coastguard Worker     if (type & XKB_STATE_LAYOUT_LATCHED)
1269*2b949d04SAndroid Build Coastguard Worker         ret |= (state->components.latched_group == (int32_t) idx);
1270*2b949d04SAndroid Build Coastguard Worker     if (type & XKB_STATE_LAYOUT_LOCKED)
1271*2b949d04SAndroid Build Coastguard Worker         ret |= (state->components.locked_group == (int32_t) idx);
1272*2b949d04SAndroid Build Coastguard Worker 
1273*2b949d04SAndroid Build Coastguard Worker     return ret;
1274*2b949d04SAndroid Build Coastguard Worker }
1275*2b949d04SAndroid Build Coastguard Worker 
1276*2b949d04SAndroid Build Coastguard Worker /**
1277*2b949d04SAndroid Build Coastguard Worker  * Returns 1 if the given modifier is active with the specified type(s), 0 if
1278*2b949d04SAndroid Build Coastguard Worker  * not, or -1 if the modifier is invalid.
1279*2b949d04SAndroid Build Coastguard Worker  */
1280*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT int
xkb_state_layout_name_is_active(struct xkb_state * state,const char * name,enum xkb_state_component type)1281*2b949d04SAndroid Build Coastguard Worker xkb_state_layout_name_is_active(struct xkb_state *state, const char *name,
1282*2b949d04SAndroid Build Coastguard Worker                                 enum xkb_state_component type)
1283*2b949d04SAndroid Build Coastguard Worker {
1284*2b949d04SAndroid Build Coastguard Worker     xkb_layout_index_t idx = xkb_keymap_layout_get_index(state->keymap, name);
1285*2b949d04SAndroid Build Coastguard Worker 
1286*2b949d04SAndroid Build Coastguard Worker     if (idx == XKB_LAYOUT_INVALID)
1287*2b949d04SAndroid Build Coastguard Worker         return -1;
1288*2b949d04SAndroid Build Coastguard Worker 
1289*2b949d04SAndroid Build Coastguard Worker     return xkb_state_layout_index_is_active(state, idx, type);
1290*2b949d04SAndroid Build Coastguard Worker }
1291*2b949d04SAndroid Build Coastguard Worker 
1292*2b949d04SAndroid Build Coastguard Worker /**
1293*2b949d04SAndroid Build Coastguard Worker  * Returns 1 if the given LED is active, 0 if not, or -1 if the LED is invalid.
1294*2b949d04SAndroid Build Coastguard Worker  */
1295*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT int
xkb_state_led_index_is_active(struct xkb_state * state,xkb_led_index_t idx)1296*2b949d04SAndroid Build Coastguard Worker xkb_state_led_index_is_active(struct xkb_state *state, xkb_led_index_t idx)
1297*2b949d04SAndroid Build Coastguard Worker {
1298*2b949d04SAndroid Build Coastguard Worker     if (idx >= state->keymap->num_leds ||
1299*2b949d04SAndroid Build Coastguard Worker         state->keymap->leds[idx].name == XKB_ATOM_NONE)
1300*2b949d04SAndroid Build Coastguard Worker         return -1;
1301*2b949d04SAndroid Build Coastguard Worker 
1302*2b949d04SAndroid Build Coastguard Worker     return !!(state->components.leds & (1u << idx));
1303*2b949d04SAndroid Build Coastguard Worker }
1304*2b949d04SAndroid Build Coastguard Worker 
1305*2b949d04SAndroid Build Coastguard Worker /**
1306*2b949d04SAndroid Build Coastguard Worker  * Returns 1 if the given LED is active, 0 if not, or -1 if the LED is invalid.
1307*2b949d04SAndroid Build Coastguard Worker  */
1308*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT int
xkb_state_led_name_is_active(struct xkb_state * state,const char * name)1309*2b949d04SAndroid Build Coastguard Worker xkb_state_led_name_is_active(struct xkb_state *state, const char *name)
1310*2b949d04SAndroid Build Coastguard Worker {
1311*2b949d04SAndroid Build Coastguard Worker     xkb_led_index_t idx = xkb_keymap_led_get_index(state->keymap, name);
1312*2b949d04SAndroid Build Coastguard Worker 
1313*2b949d04SAndroid Build Coastguard Worker     if (idx == XKB_LED_INVALID)
1314*2b949d04SAndroid Build Coastguard Worker         return -1;
1315*2b949d04SAndroid Build Coastguard Worker 
1316*2b949d04SAndroid Build Coastguard Worker     return xkb_state_led_index_is_active(state, idx);
1317*2b949d04SAndroid Build Coastguard Worker }
1318*2b949d04SAndroid Build Coastguard Worker 
1319*2b949d04SAndroid Build Coastguard Worker /**
1320*2b949d04SAndroid Build Coastguard Worker  * See:
1321*2b949d04SAndroid Build Coastguard Worker  * - XkbTranslateKeyCode(3), mod_rtrn return value, from libX11.
1322*2b949d04SAndroid Build Coastguard Worker  * - MyEnhancedXkbTranslateKeyCode(), a modification of the above, from GTK+.
1323*2b949d04SAndroid Build Coastguard Worker  */
1324*2b949d04SAndroid Build Coastguard Worker static xkb_mod_mask_t
key_get_consumed(struct xkb_state * state,const struct xkb_key * key,enum xkb_consumed_mode mode)1325*2b949d04SAndroid Build Coastguard Worker key_get_consumed(struct xkb_state *state, const struct xkb_key *key,
1326*2b949d04SAndroid Build Coastguard Worker                  enum xkb_consumed_mode mode)
1327*2b949d04SAndroid Build Coastguard Worker {
1328*2b949d04SAndroid Build Coastguard Worker     const struct xkb_key_type *type;
1329*2b949d04SAndroid Build Coastguard Worker     const struct xkb_key_type_entry *matching_entry;
1330*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t preserve = 0;
1331*2b949d04SAndroid Build Coastguard Worker     xkb_layout_index_t group;
1332*2b949d04SAndroid Build Coastguard Worker     xkb_mod_mask_t consumed = 0;
1333*2b949d04SAndroid Build Coastguard Worker 
1334*2b949d04SAndroid Build Coastguard Worker     group = xkb_state_key_get_layout(state, key->keycode);
1335*2b949d04SAndroid Build Coastguard Worker     if (group == XKB_LAYOUT_INVALID)
1336*2b949d04SAndroid Build Coastguard Worker         return 0;
1337*2b949d04SAndroid Build Coastguard Worker 
1338*2b949d04SAndroid Build Coastguard Worker     type = key->groups[group].type;
1339*2b949d04SAndroid Build Coastguard Worker 
1340*2b949d04SAndroid Build Coastguard Worker     matching_entry = get_entry_for_key_state(state, key, group);
1341*2b949d04SAndroid Build Coastguard Worker     if (matching_entry)
1342*2b949d04SAndroid Build Coastguard Worker         preserve = matching_entry->preserve.mask;
1343*2b949d04SAndroid Build Coastguard Worker 
1344*2b949d04SAndroid Build Coastguard Worker     switch (mode) {
1345*2b949d04SAndroid Build Coastguard Worker     case XKB_CONSUMED_MODE_XKB:
1346*2b949d04SAndroid Build Coastguard Worker         consumed = type->mods.mask;
1347*2b949d04SAndroid Build Coastguard Worker         break;
1348*2b949d04SAndroid Build Coastguard Worker 
1349*2b949d04SAndroid Build Coastguard Worker     case XKB_CONSUMED_MODE_GTK: {
1350*2b949d04SAndroid Build Coastguard Worker         const struct xkb_key_type_entry *no_mods_entry;
1351*2b949d04SAndroid Build Coastguard Worker         xkb_level_index_t no_mods_leveli;
1352*2b949d04SAndroid Build Coastguard Worker         const struct xkb_level *no_mods_level, *level;
1353*2b949d04SAndroid Build Coastguard Worker 
1354*2b949d04SAndroid Build Coastguard Worker         no_mods_entry = get_entry_for_mods(type, 0);
1355*2b949d04SAndroid Build Coastguard Worker         no_mods_leveli = no_mods_entry ? no_mods_entry->level : 0;
1356*2b949d04SAndroid Build Coastguard Worker         no_mods_level = &key->groups[group].levels[no_mods_leveli];
1357*2b949d04SAndroid Build Coastguard Worker 
1358*2b949d04SAndroid Build Coastguard Worker         for (unsigned i = 0; i < type->num_entries; i++) {
1359*2b949d04SAndroid Build Coastguard Worker             const struct xkb_key_type_entry *entry = &type->entries[i];
1360*2b949d04SAndroid Build Coastguard Worker             if (!entry_is_active(entry))
1361*2b949d04SAndroid Build Coastguard Worker                 continue;
1362*2b949d04SAndroid Build Coastguard Worker 
1363*2b949d04SAndroid Build Coastguard Worker             level = &key->groups[group].levels[entry->level];
1364*2b949d04SAndroid Build Coastguard Worker             if (XkbLevelsSameSyms(level, no_mods_level))
1365*2b949d04SAndroid Build Coastguard Worker                 continue;
1366*2b949d04SAndroid Build Coastguard Worker 
1367*2b949d04SAndroid Build Coastguard Worker             if (entry == matching_entry || one_bit_set(entry->mods.mask))
1368*2b949d04SAndroid Build Coastguard Worker                 consumed |= entry->mods.mask & ~entry->preserve.mask;
1369*2b949d04SAndroid Build Coastguard Worker         }
1370*2b949d04SAndroid Build Coastguard Worker         break;
1371*2b949d04SAndroid Build Coastguard Worker     }
1372*2b949d04SAndroid Build Coastguard Worker     }
1373*2b949d04SAndroid Build Coastguard Worker 
1374*2b949d04SAndroid Build Coastguard Worker     return consumed & ~preserve;
1375*2b949d04SAndroid Build Coastguard Worker }
1376*2b949d04SAndroid Build Coastguard Worker 
1377*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT int
xkb_state_mod_index_is_consumed2(struct xkb_state * state,xkb_keycode_t kc,xkb_mod_index_t idx,enum xkb_consumed_mode mode)1378*2b949d04SAndroid Build Coastguard Worker xkb_state_mod_index_is_consumed2(struct xkb_state *state, xkb_keycode_t kc,
1379*2b949d04SAndroid Build Coastguard Worker                                  xkb_mod_index_t idx,
1380*2b949d04SAndroid Build Coastguard Worker                                  enum xkb_consumed_mode mode)
1381*2b949d04SAndroid Build Coastguard Worker {
1382*2b949d04SAndroid Build Coastguard Worker     const struct xkb_key *key = XkbKey(state->keymap, kc);
1383*2b949d04SAndroid Build Coastguard Worker 
1384*2b949d04SAndroid Build Coastguard Worker     if (!key || idx >= xkb_keymap_num_mods(state->keymap))
1385*2b949d04SAndroid Build Coastguard Worker         return -1;
1386*2b949d04SAndroid Build Coastguard Worker 
1387*2b949d04SAndroid Build Coastguard Worker     return !!((1u << idx) & key_get_consumed(state, key, mode));
1388*2b949d04SAndroid Build Coastguard Worker }
1389*2b949d04SAndroid Build Coastguard Worker 
1390*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT int
xkb_state_mod_index_is_consumed(struct xkb_state * state,xkb_keycode_t kc,xkb_mod_index_t idx)1391*2b949d04SAndroid Build Coastguard Worker xkb_state_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t kc,
1392*2b949d04SAndroid Build Coastguard Worker                                 xkb_mod_index_t idx)
1393*2b949d04SAndroid Build Coastguard Worker {
1394*2b949d04SAndroid Build Coastguard Worker     return xkb_state_mod_index_is_consumed2(state, kc, idx,
1395*2b949d04SAndroid Build Coastguard Worker                                             XKB_CONSUMED_MODE_XKB);
1396*2b949d04SAndroid Build Coastguard Worker }
1397*2b949d04SAndroid Build Coastguard Worker 
1398*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT xkb_mod_mask_t
xkb_state_mod_mask_remove_consumed(struct xkb_state * state,xkb_keycode_t kc,xkb_mod_mask_t mask)1399*2b949d04SAndroid Build Coastguard Worker xkb_state_mod_mask_remove_consumed(struct xkb_state *state, xkb_keycode_t kc,
1400*2b949d04SAndroid Build Coastguard Worker                                    xkb_mod_mask_t mask)
1401*2b949d04SAndroid Build Coastguard Worker {
1402*2b949d04SAndroid Build Coastguard Worker     const struct xkb_key *key = XkbKey(state->keymap, kc);
1403*2b949d04SAndroid Build Coastguard Worker 
1404*2b949d04SAndroid Build Coastguard Worker     if (!key)
1405*2b949d04SAndroid Build Coastguard Worker         return 0;
1406*2b949d04SAndroid Build Coastguard Worker 
1407*2b949d04SAndroid Build Coastguard Worker     return mask & ~key_get_consumed(state, key, XKB_CONSUMED_MODE_XKB);
1408*2b949d04SAndroid Build Coastguard Worker }
1409*2b949d04SAndroid Build Coastguard Worker 
1410*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT xkb_mod_mask_t
xkb_state_key_get_consumed_mods2(struct xkb_state * state,xkb_keycode_t kc,enum xkb_consumed_mode mode)1411*2b949d04SAndroid Build Coastguard Worker xkb_state_key_get_consumed_mods2(struct xkb_state *state, xkb_keycode_t kc,
1412*2b949d04SAndroid Build Coastguard Worker                                  enum xkb_consumed_mode mode)
1413*2b949d04SAndroid Build Coastguard Worker {
1414*2b949d04SAndroid Build Coastguard Worker     const struct xkb_key *key;
1415*2b949d04SAndroid Build Coastguard Worker 
1416*2b949d04SAndroid Build Coastguard Worker     switch (mode) {
1417*2b949d04SAndroid Build Coastguard Worker     case XKB_CONSUMED_MODE_XKB:
1418*2b949d04SAndroid Build Coastguard Worker     case XKB_CONSUMED_MODE_GTK:
1419*2b949d04SAndroid Build Coastguard Worker         break;
1420*2b949d04SAndroid Build Coastguard Worker     default:
1421*2b949d04SAndroid Build Coastguard Worker         log_err_func(state->keymap->ctx,
1422*2b949d04SAndroid Build Coastguard Worker                      "unrecognized consumed modifiers mode: %d\n", mode);
1423*2b949d04SAndroid Build Coastguard Worker         return 0;
1424*2b949d04SAndroid Build Coastguard Worker     }
1425*2b949d04SAndroid Build Coastguard Worker 
1426*2b949d04SAndroid Build Coastguard Worker     key = XkbKey(state->keymap, kc);
1427*2b949d04SAndroid Build Coastguard Worker     if (!key)
1428*2b949d04SAndroid Build Coastguard Worker         return 0;
1429*2b949d04SAndroid Build Coastguard Worker 
1430*2b949d04SAndroid Build Coastguard Worker     return key_get_consumed(state, key, mode);
1431*2b949d04SAndroid Build Coastguard Worker }
1432*2b949d04SAndroid Build Coastguard Worker 
1433*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT xkb_mod_mask_t
xkb_state_key_get_consumed_mods(struct xkb_state * state,xkb_keycode_t kc)1434*2b949d04SAndroid Build Coastguard Worker xkb_state_key_get_consumed_mods(struct xkb_state *state, xkb_keycode_t kc)
1435*2b949d04SAndroid Build Coastguard Worker {
1436*2b949d04SAndroid Build Coastguard Worker     return xkb_state_key_get_consumed_mods2(state, kc, XKB_CONSUMED_MODE_XKB);
1437*2b949d04SAndroid Build Coastguard Worker }
1438