1*2b949d04SAndroid Build Coastguard Worker /************************************************************
2*2b949d04SAndroid Build Coastguard Worker * Copyright (c) 1994 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 * Ran Benita <[email protected]>
52*2b949d04SAndroid Build Coastguard Worker */
53*2b949d04SAndroid Build Coastguard Worker
54*2b949d04SAndroid Build Coastguard Worker #include "config.h"
55*2b949d04SAndroid Build Coastguard Worker
56*2b949d04SAndroid Build Coastguard Worker #include "xkbcomp-priv.h"
57*2b949d04SAndroid Build Coastguard Worker #include "text.h"
58*2b949d04SAndroid Build Coastguard Worker #include "expr.h"
59*2b949d04SAndroid Build Coastguard Worker #include "action.h"
60*2b949d04SAndroid Build Coastguard Worker #include "vmod.h"
61*2b949d04SAndroid Build Coastguard Worker #include "include.h"
62*2b949d04SAndroid Build Coastguard Worker #include "keysym.h"
63*2b949d04SAndroid Build Coastguard Worker
64*2b949d04SAndroid Build Coastguard Worker enum key_repeat {
65*2b949d04SAndroid Build Coastguard Worker KEY_REPEAT_UNDEFINED = 0,
66*2b949d04SAndroid Build Coastguard Worker KEY_REPEAT_YES = 1,
67*2b949d04SAndroid Build Coastguard Worker KEY_REPEAT_NO = 2,
68*2b949d04SAndroid Build Coastguard Worker };
69*2b949d04SAndroid Build Coastguard Worker
70*2b949d04SAndroid Build Coastguard Worker enum group_field {
71*2b949d04SAndroid Build Coastguard Worker GROUP_FIELD_SYMS = (1 << 0),
72*2b949d04SAndroid Build Coastguard Worker GROUP_FIELD_ACTS = (1 << 1),
73*2b949d04SAndroid Build Coastguard Worker GROUP_FIELD_TYPE = (1 << 2),
74*2b949d04SAndroid Build Coastguard Worker };
75*2b949d04SAndroid Build Coastguard Worker
76*2b949d04SAndroid Build Coastguard Worker enum key_field {
77*2b949d04SAndroid Build Coastguard Worker KEY_FIELD_REPEAT = (1 << 0),
78*2b949d04SAndroid Build Coastguard Worker KEY_FIELD_DEFAULT_TYPE = (1 << 1),
79*2b949d04SAndroid Build Coastguard Worker KEY_FIELD_GROUPINFO = (1 << 2),
80*2b949d04SAndroid Build Coastguard Worker KEY_FIELD_VMODMAP = (1 << 3),
81*2b949d04SAndroid Build Coastguard Worker };
82*2b949d04SAndroid Build Coastguard Worker
83*2b949d04SAndroid Build Coastguard Worker typedef struct {
84*2b949d04SAndroid Build Coastguard Worker enum group_field defined;
85*2b949d04SAndroid Build Coastguard Worker darray(struct xkb_level) levels;
86*2b949d04SAndroid Build Coastguard Worker xkb_atom_t type;
87*2b949d04SAndroid Build Coastguard Worker } GroupInfo;
88*2b949d04SAndroid Build Coastguard Worker
89*2b949d04SAndroid Build Coastguard Worker typedef struct {
90*2b949d04SAndroid Build Coastguard Worker enum key_field defined;
91*2b949d04SAndroid Build Coastguard Worker enum merge_mode merge;
92*2b949d04SAndroid Build Coastguard Worker
93*2b949d04SAndroid Build Coastguard Worker xkb_atom_t name;
94*2b949d04SAndroid Build Coastguard Worker
95*2b949d04SAndroid Build Coastguard Worker darray(GroupInfo) groups;
96*2b949d04SAndroid Build Coastguard Worker
97*2b949d04SAndroid Build Coastguard Worker enum key_repeat repeat;
98*2b949d04SAndroid Build Coastguard Worker xkb_mod_mask_t vmodmap;
99*2b949d04SAndroid Build Coastguard Worker xkb_atom_t default_type;
100*2b949d04SAndroid Build Coastguard Worker
101*2b949d04SAndroid Build Coastguard Worker enum xkb_range_exceed_type out_of_range_group_action;
102*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t out_of_range_group_number;
103*2b949d04SAndroid Build Coastguard Worker } KeyInfo;
104*2b949d04SAndroid Build Coastguard Worker
105*2b949d04SAndroid Build Coastguard Worker static void
ClearLevelInfo(struct xkb_level * leveli)106*2b949d04SAndroid Build Coastguard Worker ClearLevelInfo(struct xkb_level *leveli)
107*2b949d04SAndroid Build Coastguard Worker {
108*2b949d04SAndroid Build Coastguard Worker if (leveli->num_syms > 1)
109*2b949d04SAndroid Build Coastguard Worker free(leveli->u.syms);
110*2b949d04SAndroid Build Coastguard Worker }
111*2b949d04SAndroid Build Coastguard Worker
112*2b949d04SAndroid Build Coastguard Worker static void
InitGroupInfo(GroupInfo * groupi)113*2b949d04SAndroid Build Coastguard Worker InitGroupInfo(GroupInfo *groupi)
114*2b949d04SAndroid Build Coastguard Worker {
115*2b949d04SAndroid Build Coastguard Worker memset(groupi, 0, sizeof(*groupi));
116*2b949d04SAndroid Build Coastguard Worker }
117*2b949d04SAndroid Build Coastguard Worker
118*2b949d04SAndroid Build Coastguard Worker static void
ClearGroupInfo(GroupInfo * groupi)119*2b949d04SAndroid Build Coastguard Worker ClearGroupInfo(GroupInfo *groupi)
120*2b949d04SAndroid Build Coastguard Worker {
121*2b949d04SAndroid Build Coastguard Worker struct xkb_level *leveli;
122*2b949d04SAndroid Build Coastguard Worker darray_foreach(leveli, groupi->levels)
123*2b949d04SAndroid Build Coastguard Worker ClearLevelInfo(leveli);
124*2b949d04SAndroid Build Coastguard Worker darray_free(groupi->levels);
125*2b949d04SAndroid Build Coastguard Worker }
126*2b949d04SAndroid Build Coastguard Worker
127*2b949d04SAndroid Build Coastguard Worker static void
CopyGroupInfo(GroupInfo * to,const GroupInfo * from)128*2b949d04SAndroid Build Coastguard Worker CopyGroupInfo(GroupInfo *to, const GroupInfo *from)
129*2b949d04SAndroid Build Coastguard Worker {
130*2b949d04SAndroid Build Coastguard Worker to->defined = from->defined;
131*2b949d04SAndroid Build Coastguard Worker to->type = from->type;
132*2b949d04SAndroid Build Coastguard Worker darray_init(to->levels);
133*2b949d04SAndroid Build Coastguard Worker darray_copy(to->levels, from->levels);
134*2b949d04SAndroid Build Coastguard Worker for (xkb_level_index_t j = 0; j < darray_size(to->levels); j++)
135*2b949d04SAndroid Build Coastguard Worker if (darray_item(from->levels, j).num_syms > 1)
136*2b949d04SAndroid Build Coastguard Worker darray_item(to->levels, j).u.syms =
137*2b949d04SAndroid Build Coastguard Worker memdup(darray_item(from->levels, j).u.syms,
138*2b949d04SAndroid Build Coastguard Worker darray_item(from->levels, j).num_syms,
139*2b949d04SAndroid Build Coastguard Worker sizeof(xkb_keysym_t));
140*2b949d04SAndroid Build Coastguard Worker }
141*2b949d04SAndroid Build Coastguard Worker
142*2b949d04SAndroid Build Coastguard Worker static void
InitKeyInfo(struct xkb_context * ctx,KeyInfo * keyi)143*2b949d04SAndroid Build Coastguard Worker InitKeyInfo(struct xkb_context *ctx, KeyInfo *keyi)
144*2b949d04SAndroid Build Coastguard Worker {
145*2b949d04SAndroid Build Coastguard Worker memset(keyi, 0, sizeof(*keyi));
146*2b949d04SAndroid Build Coastguard Worker keyi->merge = MERGE_OVERRIDE;
147*2b949d04SAndroid Build Coastguard Worker keyi->name = xkb_atom_intern_literal(ctx, "*");
148*2b949d04SAndroid Build Coastguard Worker keyi->out_of_range_group_action = RANGE_WRAP;
149*2b949d04SAndroid Build Coastguard Worker }
150*2b949d04SAndroid Build Coastguard Worker
151*2b949d04SAndroid Build Coastguard Worker static void
ClearKeyInfo(KeyInfo * keyi)152*2b949d04SAndroid Build Coastguard Worker ClearKeyInfo(KeyInfo *keyi)
153*2b949d04SAndroid Build Coastguard Worker {
154*2b949d04SAndroid Build Coastguard Worker GroupInfo *groupi;
155*2b949d04SAndroid Build Coastguard Worker darray_foreach(groupi, keyi->groups)
156*2b949d04SAndroid Build Coastguard Worker ClearGroupInfo(groupi);
157*2b949d04SAndroid Build Coastguard Worker darray_free(keyi->groups);
158*2b949d04SAndroid Build Coastguard Worker }
159*2b949d04SAndroid Build Coastguard Worker
160*2b949d04SAndroid Build Coastguard Worker /***====================================================================***/
161*2b949d04SAndroid Build Coastguard Worker
162*2b949d04SAndroid Build Coastguard Worker typedef struct {
163*2b949d04SAndroid Build Coastguard Worker enum merge_mode merge;
164*2b949d04SAndroid Build Coastguard Worker bool haveSymbol;
165*2b949d04SAndroid Build Coastguard Worker xkb_mod_index_t modifier;
166*2b949d04SAndroid Build Coastguard Worker union {
167*2b949d04SAndroid Build Coastguard Worker xkb_atom_t keyName;
168*2b949d04SAndroid Build Coastguard Worker xkb_keysym_t keySym;
169*2b949d04SAndroid Build Coastguard Worker } u;
170*2b949d04SAndroid Build Coastguard Worker } ModMapEntry;
171*2b949d04SAndroid Build Coastguard Worker
172*2b949d04SAndroid Build Coastguard Worker typedef struct {
173*2b949d04SAndroid Build Coastguard Worker char *name; /* e.g. pc+us+inet(evdev) */
174*2b949d04SAndroid Build Coastguard Worker int errorCount;
175*2b949d04SAndroid Build Coastguard Worker enum merge_mode merge;
176*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t explicit_group;
177*2b949d04SAndroid Build Coastguard Worker darray(KeyInfo) keys;
178*2b949d04SAndroid Build Coastguard Worker KeyInfo default_key;
179*2b949d04SAndroid Build Coastguard Worker ActionsInfo *actions;
180*2b949d04SAndroid Build Coastguard Worker darray(xkb_atom_t) group_names;
181*2b949d04SAndroid Build Coastguard Worker darray(ModMapEntry) modmaps;
182*2b949d04SAndroid Build Coastguard Worker struct xkb_mod_set mods;
183*2b949d04SAndroid Build Coastguard Worker
184*2b949d04SAndroid Build Coastguard Worker struct xkb_context *ctx;
185*2b949d04SAndroid Build Coastguard Worker /* Needed for AddKeySymbols. */
186*2b949d04SAndroid Build Coastguard Worker const struct xkb_keymap *keymap;
187*2b949d04SAndroid Build Coastguard Worker } SymbolsInfo;
188*2b949d04SAndroid Build Coastguard Worker
189*2b949d04SAndroid Build Coastguard Worker static void
InitSymbolsInfo(SymbolsInfo * info,const struct xkb_keymap * keymap,ActionsInfo * actions,const struct xkb_mod_set * mods)190*2b949d04SAndroid Build Coastguard Worker InitSymbolsInfo(SymbolsInfo *info, const struct xkb_keymap *keymap,
191*2b949d04SAndroid Build Coastguard Worker ActionsInfo *actions, const struct xkb_mod_set *mods)
192*2b949d04SAndroid Build Coastguard Worker {
193*2b949d04SAndroid Build Coastguard Worker memset(info, 0, sizeof(*info));
194*2b949d04SAndroid Build Coastguard Worker info->ctx = keymap->ctx;
195*2b949d04SAndroid Build Coastguard Worker info->keymap = keymap;
196*2b949d04SAndroid Build Coastguard Worker info->merge = MERGE_OVERRIDE;
197*2b949d04SAndroid Build Coastguard Worker InitKeyInfo(keymap->ctx, &info->default_key);
198*2b949d04SAndroid Build Coastguard Worker info->actions = actions;
199*2b949d04SAndroid Build Coastguard Worker info->mods = *mods;
200*2b949d04SAndroid Build Coastguard Worker info->explicit_group = XKB_LAYOUT_INVALID;
201*2b949d04SAndroid Build Coastguard Worker }
202*2b949d04SAndroid Build Coastguard Worker
203*2b949d04SAndroid Build Coastguard Worker static void
ClearSymbolsInfo(SymbolsInfo * info)204*2b949d04SAndroid Build Coastguard Worker ClearSymbolsInfo(SymbolsInfo *info)
205*2b949d04SAndroid Build Coastguard Worker {
206*2b949d04SAndroid Build Coastguard Worker KeyInfo *keyi;
207*2b949d04SAndroid Build Coastguard Worker free(info->name);
208*2b949d04SAndroid Build Coastguard Worker darray_foreach(keyi, info->keys)
209*2b949d04SAndroid Build Coastguard Worker ClearKeyInfo(keyi);
210*2b949d04SAndroid Build Coastguard Worker darray_free(info->keys);
211*2b949d04SAndroid Build Coastguard Worker darray_free(info->group_names);
212*2b949d04SAndroid Build Coastguard Worker darray_free(info->modmaps);
213*2b949d04SAndroid Build Coastguard Worker ClearKeyInfo(&info->default_key);
214*2b949d04SAndroid Build Coastguard Worker }
215*2b949d04SAndroid Build Coastguard Worker
216*2b949d04SAndroid Build Coastguard Worker static const char *
KeyInfoText(SymbolsInfo * info,KeyInfo * keyi)217*2b949d04SAndroid Build Coastguard Worker KeyInfoText(SymbolsInfo *info, KeyInfo *keyi)
218*2b949d04SAndroid Build Coastguard Worker {
219*2b949d04SAndroid Build Coastguard Worker return KeyNameText(info->ctx, keyi->name);
220*2b949d04SAndroid Build Coastguard Worker }
221*2b949d04SAndroid Build Coastguard Worker
222*2b949d04SAndroid Build Coastguard Worker static bool
MergeGroups(SymbolsInfo * info,GroupInfo * into,GroupInfo * from,bool clobber,bool report,xkb_layout_index_t group,xkb_atom_t key_name)223*2b949d04SAndroid Build Coastguard Worker MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber,
224*2b949d04SAndroid Build Coastguard Worker bool report, xkb_layout_index_t group, xkb_atom_t key_name)
225*2b949d04SAndroid Build Coastguard Worker {
226*2b949d04SAndroid Build Coastguard Worker xkb_level_index_t i, levels_in_both;
227*2b949d04SAndroid Build Coastguard Worker struct xkb_level *level;
228*2b949d04SAndroid Build Coastguard Worker
229*2b949d04SAndroid Build Coastguard Worker /* First find the type of the merged group. */
230*2b949d04SAndroid Build Coastguard Worker if (into->type != from->type) {
231*2b949d04SAndroid Build Coastguard Worker if (from->type == XKB_ATOM_NONE) {
232*2b949d04SAndroid Build Coastguard Worker /* it's empty for consistency with other comparisons */
233*2b949d04SAndroid Build Coastguard Worker }
234*2b949d04SAndroid Build Coastguard Worker else if (into->type == XKB_ATOM_NONE) {
235*2b949d04SAndroid Build Coastguard Worker into->type = from->type;
236*2b949d04SAndroid Build Coastguard Worker }
237*2b949d04SAndroid Build Coastguard Worker else {
238*2b949d04SAndroid Build Coastguard Worker xkb_atom_t use = (clobber ? from->type : into->type);
239*2b949d04SAndroid Build Coastguard Worker xkb_atom_t ignore = (clobber ? into->type : from->type);
240*2b949d04SAndroid Build Coastguard Worker
241*2b949d04SAndroid Build Coastguard Worker if (report)
242*2b949d04SAndroid Build Coastguard Worker log_warn(info->ctx,
243*2b949d04SAndroid Build Coastguard Worker "Multiple definitions for group %d type of key %s; "
244*2b949d04SAndroid Build Coastguard Worker "Using %s, ignoring %s\n",
245*2b949d04SAndroid Build Coastguard Worker group + 1, KeyNameText(info->ctx, key_name),
246*2b949d04SAndroid Build Coastguard Worker xkb_atom_text(info->ctx, use),
247*2b949d04SAndroid Build Coastguard Worker xkb_atom_text(info->ctx, ignore));
248*2b949d04SAndroid Build Coastguard Worker
249*2b949d04SAndroid Build Coastguard Worker into->type = use;
250*2b949d04SAndroid Build Coastguard Worker }
251*2b949d04SAndroid Build Coastguard Worker }
252*2b949d04SAndroid Build Coastguard Worker into->defined |= (from->defined & GROUP_FIELD_TYPE);
253*2b949d04SAndroid Build Coastguard Worker
254*2b949d04SAndroid Build Coastguard Worker /* Now look at the levels. */
255*2b949d04SAndroid Build Coastguard Worker
256*2b949d04SAndroid Build Coastguard Worker if (darray_empty(from->levels)) {
257*2b949d04SAndroid Build Coastguard Worker InitGroupInfo(from);
258*2b949d04SAndroid Build Coastguard Worker return true;
259*2b949d04SAndroid Build Coastguard Worker }
260*2b949d04SAndroid Build Coastguard Worker
261*2b949d04SAndroid Build Coastguard Worker if (darray_empty(into->levels)) {
262*2b949d04SAndroid Build Coastguard Worker from->type = into->type;
263*2b949d04SAndroid Build Coastguard Worker *into = *from;
264*2b949d04SAndroid Build Coastguard Worker InitGroupInfo(from);
265*2b949d04SAndroid Build Coastguard Worker return true;
266*2b949d04SAndroid Build Coastguard Worker }
267*2b949d04SAndroid Build Coastguard Worker
268*2b949d04SAndroid Build Coastguard Worker /* Merge the actions and syms. */
269*2b949d04SAndroid Build Coastguard Worker levels_in_both = MIN(darray_size(into->levels), darray_size(from->levels));
270*2b949d04SAndroid Build Coastguard Worker for (i = 0; i < levels_in_both; i++) {
271*2b949d04SAndroid Build Coastguard Worker struct xkb_level *intoLevel = &darray_item(into->levels, i);
272*2b949d04SAndroid Build Coastguard Worker struct xkb_level *fromLevel = &darray_item(from->levels, i);
273*2b949d04SAndroid Build Coastguard Worker
274*2b949d04SAndroid Build Coastguard Worker if (fromLevel->action.type == ACTION_TYPE_NONE) {
275*2b949d04SAndroid Build Coastguard Worker /* it's empty for consistency with other comparisons */
276*2b949d04SAndroid Build Coastguard Worker }
277*2b949d04SAndroid Build Coastguard Worker else if (intoLevel->action.type == ACTION_TYPE_NONE) {
278*2b949d04SAndroid Build Coastguard Worker intoLevel->action = fromLevel->action;
279*2b949d04SAndroid Build Coastguard Worker }
280*2b949d04SAndroid Build Coastguard Worker else {
281*2b949d04SAndroid Build Coastguard Worker union xkb_action *use, *ignore;
282*2b949d04SAndroid Build Coastguard Worker use = (clobber ? &fromLevel->action : &intoLevel->action);
283*2b949d04SAndroid Build Coastguard Worker ignore = (clobber ? &intoLevel->action : &fromLevel->action);
284*2b949d04SAndroid Build Coastguard Worker
285*2b949d04SAndroid Build Coastguard Worker if (report)
286*2b949d04SAndroid Build Coastguard Worker log_warn(info->ctx,
287*2b949d04SAndroid Build Coastguard Worker "Multiple actions for level %d/group %u on key %s; "
288*2b949d04SAndroid Build Coastguard Worker "Using %s, ignoring %s\n",
289*2b949d04SAndroid Build Coastguard Worker i + 1, group + 1, KeyNameText(info->ctx, key_name),
290*2b949d04SAndroid Build Coastguard Worker ActionTypeText(use->type),
291*2b949d04SAndroid Build Coastguard Worker ActionTypeText(ignore->type));
292*2b949d04SAndroid Build Coastguard Worker
293*2b949d04SAndroid Build Coastguard Worker intoLevel->action = *use;
294*2b949d04SAndroid Build Coastguard Worker }
295*2b949d04SAndroid Build Coastguard Worker
296*2b949d04SAndroid Build Coastguard Worker if (fromLevel->num_syms == 0) {
297*2b949d04SAndroid Build Coastguard Worker /* it's empty for consistency with other comparisons */
298*2b949d04SAndroid Build Coastguard Worker }
299*2b949d04SAndroid Build Coastguard Worker else if (intoLevel->num_syms == 0) {
300*2b949d04SAndroid Build Coastguard Worker intoLevel->num_syms = fromLevel->num_syms;
301*2b949d04SAndroid Build Coastguard Worker if (fromLevel->num_syms > 1)
302*2b949d04SAndroid Build Coastguard Worker intoLevel->u.syms = fromLevel->u.syms;
303*2b949d04SAndroid Build Coastguard Worker else
304*2b949d04SAndroid Build Coastguard Worker intoLevel->u.sym = fromLevel->u.sym;
305*2b949d04SAndroid Build Coastguard Worker fromLevel->num_syms = 0;
306*2b949d04SAndroid Build Coastguard Worker }
307*2b949d04SAndroid Build Coastguard Worker else if (!XkbLevelsSameSyms(fromLevel, intoLevel)) {
308*2b949d04SAndroid Build Coastguard Worker if (report)
309*2b949d04SAndroid Build Coastguard Worker log_warn(info->ctx,
310*2b949d04SAndroid Build Coastguard Worker "Multiple symbols for level %d/group %u on key %s; "
311*2b949d04SAndroid Build Coastguard Worker "Using %s, ignoring %s\n",
312*2b949d04SAndroid Build Coastguard Worker i + 1, group + 1, KeyNameText(info->ctx, key_name),
313*2b949d04SAndroid Build Coastguard Worker (clobber ? "from" : "to"),
314*2b949d04SAndroid Build Coastguard Worker (clobber ? "to" : "from"));
315*2b949d04SAndroid Build Coastguard Worker
316*2b949d04SAndroid Build Coastguard Worker if (clobber) {
317*2b949d04SAndroid Build Coastguard Worker ClearLevelInfo(intoLevel);
318*2b949d04SAndroid Build Coastguard Worker intoLevel->num_syms = fromLevel->num_syms;
319*2b949d04SAndroid Build Coastguard Worker if (fromLevel->num_syms > 1)
320*2b949d04SAndroid Build Coastguard Worker intoLevel->u.syms = fromLevel->u.syms;
321*2b949d04SAndroid Build Coastguard Worker else
322*2b949d04SAndroid Build Coastguard Worker intoLevel->u.sym = fromLevel->u.sym;
323*2b949d04SAndroid Build Coastguard Worker fromLevel->num_syms = 0;
324*2b949d04SAndroid Build Coastguard Worker }
325*2b949d04SAndroid Build Coastguard Worker }
326*2b949d04SAndroid Build Coastguard Worker }
327*2b949d04SAndroid Build Coastguard Worker /* If @from has extra levels, get them as well. */
328*2b949d04SAndroid Build Coastguard Worker darray_foreach_from(level, from->levels, levels_in_both) {
329*2b949d04SAndroid Build Coastguard Worker darray_append(into->levels, *level);
330*2b949d04SAndroid Build Coastguard Worker level->num_syms = 0;
331*2b949d04SAndroid Build Coastguard Worker }
332*2b949d04SAndroid Build Coastguard Worker into->defined |= (from->defined & GROUP_FIELD_ACTS);
333*2b949d04SAndroid Build Coastguard Worker into->defined |= (from->defined & GROUP_FIELD_SYMS);
334*2b949d04SAndroid Build Coastguard Worker
335*2b949d04SAndroid Build Coastguard Worker return true;
336*2b949d04SAndroid Build Coastguard Worker }
337*2b949d04SAndroid Build Coastguard Worker
338*2b949d04SAndroid Build Coastguard Worker static bool
UseNewKeyField(enum key_field field,enum key_field old,enum key_field new,bool clobber,bool report,enum key_field * collide)339*2b949d04SAndroid Build Coastguard Worker UseNewKeyField(enum key_field field, enum key_field old, enum key_field new,
340*2b949d04SAndroid Build Coastguard Worker bool clobber, bool report, enum key_field *collide)
341*2b949d04SAndroid Build Coastguard Worker {
342*2b949d04SAndroid Build Coastguard Worker if (!(old & field))
343*2b949d04SAndroid Build Coastguard Worker return (new & field);
344*2b949d04SAndroid Build Coastguard Worker
345*2b949d04SAndroid Build Coastguard Worker if (new & field) {
346*2b949d04SAndroid Build Coastguard Worker if (report)
347*2b949d04SAndroid Build Coastguard Worker *collide |= field;
348*2b949d04SAndroid Build Coastguard Worker
349*2b949d04SAndroid Build Coastguard Worker if (clobber)
350*2b949d04SAndroid Build Coastguard Worker return true;
351*2b949d04SAndroid Build Coastguard Worker }
352*2b949d04SAndroid Build Coastguard Worker
353*2b949d04SAndroid Build Coastguard Worker return false;
354*2b949d04SAndroid Build Coastguard Worker }
355*2b949d04SAndroid Build Coastguard Worker
356*2b949d04SAndroid Build Coastguard Worker static bool
MergeKeys(SymbolsInfo * info,KeyInfo * into,KeyInfo * from,bool same_file)357*2b949d04SAndroid Build Coastguard Worker MergeKeys(SymbolsInfo *info, KeyInfo *into, KeyInfo *from, bool same_file)
358*2b949d04SAndroid Build Coastguard Worker {
359*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t i;
360*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t groups_in_both;
361*2b949d04SAndroid Build Coastguard Worker enum key_field collide = 0;
362*2b949d04SAndroid Build Coastguard Worker const int verbosity = xkb_context_get_log_verbosity(info->ctx);
363*2b949d04SAndroid Build Coastguard Worker const bool clobber = (from->merge != MERGE_AUGMENT);
364*2b949d04SAndroid Build Coastguard Worker const bool report = (same_file && verbosity > 0) || verbosity > 9;
365*2b949d04SAndroid Build Coastguard Worker
366*2b949d04SAndroid Build Coastguard Worker if (from->merge == MERGE_REPLACE) {
367*2b949d04SAndroid Build Coastguard Worker ClearKeyInfo(into);
368*2b949d04SAndroid Build Coastguard Worker *into = *from;
369*2b949d04SAndroid Build Coastguard Worker InitKeyInfo(info->ctx, from);
370*2b949d04SAndroid Build Coastguard Worker return true;
371*2b949d04SAndroid Build Coastguard Worker }
372*2b949d04SAndroid Build Coastguard Worker
373*2b949d04SAndroid Build Coastguard Worker groups_in_both = MIN(darray_size(into->groups), darray_size(from->groups));
374*2b949d04SAndroid Build Coastguard Worker for (i = 0; i < groups_in_both; i++)
375*2b949d04SAndroid Build Coastguard Worker MergeGroups(info,
376*2b949d04SAndroid Build Coastguard Worker &darray_item(into->groups, i),
377*2b949d04SAndroid Build Coastguard Worker &darray_item(from->groups, i),
378*2b949d04SAndroid Build Coastguard Worker clobber, report, i, into->name);
379*2b949d04SAndroid Build Coastguard Worker /* If @from has extra groups, just move them to @into. */
380*2b949d04SAndroid Build Coastguard Worker for (i = groups_in_both; i < darray_size(from->groups); i++) {
381*2b949d04SAndroid Build Coastguard Worker darray_append(into->groups, darray_item(from->groups, i));
382*2b949d04SAndroid Build Coastguard Worker InitGroupInfo(&darray_item(from->groups, i));
383*2b949d04SAndroid Build Coastguard Worker }
384*2b949d04SAndroid Build Coastguard Worker
385*2b949d04SAndroid Build Coastguard Worker if (UseNewKeyField(KEY_FIELD_VMODMAP, into->defined, from->defined,
386*2b949d04SAndroid Build Coastguard Worker clobber, report, &collide)) {
387*2b949d04SAndroid Build Coastguard Worker into->vmodmap = from->vmodmap;
388*2b949d04SAndroid Build Coastguard Worker into->defined |= KEY_FIELD_VMODMAP;
389*2b949d04SAndroid Build Coastguard Worker }
390*2b949d04SAndroid Build Coastguard Worker if (UseNewKeyField(KEY_FIELD_REPEAT, into->defined, from->defined,
391*2b949d04SAndroid Build Coastguard Worker clobber, report, &collide)) {
392*2b949d04SAndroid Build Coastguard Worker into->repeat = from->repeat;
393*2b949d04SAndroid Build Coastguard Worker into->defined |= KEY_FIELD_REPEAT;
394*2b949d04SAndroid Build Coastguard Worker }
395*2b949d04SAndroid Build Coastguard Worker if (UseNewKeyField(KEY_FIELD_DEFAULT_TYPE, into->defined, from->defined,
396*2b949d04SAndroid Build Coastguard Worker clobber, report, &collide)) {
397*2b949d04SAndroid Build Coastguard Worker into->default_type = from->default_type;
398*2b949d04SAndroid Build Coastguard Worker into->defined |= KEY_FIELD_DEFAULT_TYPE;
399*2b949d04SAndroid Build Coastguard Worker }
400*2b949d04SAndroid Build Coastguard Worker if (UseNewKeyField(KEY_FIELD_GROUPINFO, into->defined, from->defined,
401*2b949d04SAndroid Build Coastguard Worker clobber, report, &collide)) {
402*2b949d04SAndroid Build Coastguard Worker into->out_of_range_group_action = from->out_of_range_group_action;
403*2b949d04SAndroid Build Coastguard Worker into->out_of_range_group_number = from->out_of_range_group_number;
404*2b949d04SAndroid Build Coastguard Worker into->defined |= KEY_FIELD_GROUPINFO;
405*2b949d04SAndroid Build Coastguard Worker }
406*2b949d04SAndroid Build Coastguard Worker
407*2b949d04SAndroid Build Coastguard Worker if (collide)
408*2b949d04SAndroid Build Coastguard Worker log_warn(info->ctx,
409*2b949d04SAndroid Build Coastguard Worker "Symbol map for key %s redefined; "
410*2b949d04SAndroid Build Coastguard Worker "Using %s definition for conflicting fields\n",
411*2b949d04SAndroid Build Coastguard Worker KeyNameText(info->ctx, into->name),
412*2b949d04SAndroid Build Coastguard Worker (clobber ? "first" : "last"));
413*2b949d04SAndroid Build Coastguard Worker
414*2b949d04SAndroid Build Coastguard Worker ClearKeyInfo(from);
415*2b949d04SAndroid Build Coastguard Worker InitKeyInfo(info->ctx, from);
416*2b949d04SAndroid Build Coastguard Worker return true;
417*2b949d04SAndroid Build Coastguard Worker }
418*2b949d04SAndroid Build Coastguard Worker
419*2b949d04SAndroid Build Coastguard Worker /* TODO: Make it so this function doesn't need the entire keymap. */
420*2b949d04SAndroid Build Coastguard Worker static bool
AddKeySymbols(SymbolsInfo * info,KeyInfo * keyi,bool same_file)421*2b949d04SAndroid Build Coastguard Worker AddKeySymbols(SymbolsInfo *info, KeyInfo *keyi, bool same_file)
422*2b949d04SAndroid Build Coastguard Worker {
423*2b949d04SAndroid Build Coastguard Worker xkb_atom_t real_name;
424*2b949d04SAndroid Build Coastguard Worker KeyInfo *iter;
425*2b949d04SAndroid Build Coastguard Worker
426*2b949d04SAndroid Build Coastguard Worker /*
427*2b949d04SAndroid Build Coastguard Worker * Don't keep aliases in the keys array; this guarantees that
428*2b949d04SAndroid Build Coastguard Worker * searching for keys to merge with by straight comparison (see the
429*2b949d04SAndroid Build Coastguard Worker * following loop) is enough, and we won't get multiple KeyInfo's
430*2b949d04SAndroid Build Coastguard Worker * for the same key because of aliases.
431*2b949d04SAndroid Build Coastguard Worker */
432*2b949d04SAndroid Build Coastguard Worker real_name = XkbResolveKeyAlias(info->keymap, keyi->name);
433*2b949d04SAndroid Build Coastguard Worker if (real_name != XKB_ATOM_NONE)
434*2b949d04SAndroid Build Coastguard Worker keyi->name = real_name;
435*2b949d04SAndroid Build Coastguard Worker
436*2b949d04SAndroid Build Coastguard Worker darray_foreach(iter, info->keys)
437*2b949d04SAndroid Build Coastguard Worker if (iter->name == keyi->name)
438*2b949d04SAndroid Build Coastguard Worker return MergeKeys(info, iter, keyi, same_file);
439*2b949d04SAndroid Build Coastguard Worker
440*2b949d04SAndroid Build Coastguard Worker darray_append(info->keys, *keyi);
441*2b949d04SAndroid Build Coastguard Worker InitKeyInfo(info->ctx, keyi);
442*2b949d04SAndroid Build Coastguard Worker return true;
443*2b949d04SAndroid Build Coastguard Worker }
444*2b949d04SAndroid Build Coastguard Worker
445*2b949d04SAndroid Build Coastguard Worker static bool
AddModMapEntry(SymbolsInfo * info,ModMapEntry * new)446*2b949d04SAndroid Build Coastguard Worker AddModMapEntry(SymbolsInfo *info, ModMapEntry *new)
447*2b949d04SAndroid Build Coastguard Worker {
448*2b949d04SAndroid Build Coastguard Worker ModMapEntry *old;
449*2b949d04SAndroid Build Coastguard Worker bool clobber = (new->merge != MERGE_AUGMENT);
450*2b949d04SAndroid Build Coastguard Worker
451*2b949d04SAndroid Build Coastguard Worker darray_foreach(old, info->modmaps) {
452*2b949d04SAndroid Build Coastguard Worker xkb_mod_index_t use, ignore;
453*2b949d04SAndroid Build Coastguard Worker
454*2b949d04SAndroid Build Coastguard Worker if ((new->haveSymbol != old->haveSymbol) ||
455*2b949d04SAndroid Build Coastguard Worker (new->haveSymbol && new->u.keySym != old->u.keySym) ||
456*2b949d04SAndroid Build Coastguard Worker (!new->haveSymbol && new->u.keyName != old->u.keyName))
457*2b949d04SAndroid Build Coastguard Worker continue;
458*2b949d04SAndroid Build Coastguard Worker
459*2b949d04SAndroid Build Coastguard Worker if (new->modifier == old->modifier)
460*2b949d04SAndroid Build Coastguard Worker return true;
461*2b949d04SAndroid Build Coastguard Worker
462*2b949d04SAndroid Build Coastguard Worker use = (clobber ? new->modifier : old->modifier);
463*2b949d04SAndroid Build Coastguard Worker ignore = (clobber ? old->modifier : new->modifier);
464*2b949d04SAndroid Build Coastguard Worker
465*2b949d04SAndroid Build Coastguard Worker if (new->haveSymbol)
466*2b949d04SAndroid Build Coastguard Worker log_warn(info->ctx,
467*2b949d04SAndroid Build Coastguard Worker "Symbol \"%s\" added to modifier map for multiple modifiers; "
468*2b949d04SAndroid Build Coastguard Worker "Using %s, ignoring %s\n",
469*2b949d04SAndroid Build Coastguard Worker KeysymText(info->ctx, new->u.keySym),
470*2b949d04SAndroid Build Coastguard Worker ModIndexText(info->ctx, &info->mods, use),
471*2b949d04SAndroid Build Coastguard Worker ModIndexText(info->ctx, &info->mods, ignore));
472*2b949d04SAndroid Build Coastguard Worker else
473*2b949d04SAndroid Build Coastguard Worker log_warn(info->ctx,
474*2b949d04SAndroid Build Coastguard Worker "Key \"%s\" added to modifier map for multiple modifiers; "
475*2b949d04SAndroid Build Coastguard Worker "Using %s, ignoring %s\n",
476*2b949d04SAndroid Build Coastguard Worker KeyNameText(info->ctx, new->u.keyName),
477*2b949d04SAndroid Build Coastguard Worker ModIndexText(info->ctx, &info->mods, use),
478*2b949d04SAndroid Build Coastguard Worker ModIndexText(info->ctx, &info->mods, ignore));
479*2b949d04SAndroid Build Coastguard Worker
480*2b949d04SAndroid Build Coastguard Worker old->modifier = use;
481*2b949d04SAndroid Build Coastguard Worker return true;
482*2b949d04SAndroid Build Coastguard Worker }
483*2b949d04SAndroid Build Coastguard Worker
484*2b949d04SAndroid Build Coastguard Worker darray_append(info->modmaps, *new);
485*2b949d04SAndroid Build Coastguard Worker return true;
486*2b949d04SAndroid Build Coastguard Worker }
487*2b949d04SAndroid Build Coastguard Worker
488*2b949d04SAndroid Build Coastguard Worker /***====================================================================***/
489*2b949d04SAndroid Build Coastguard Worker
490*2b949d04SAndroid Build Coastguard Worker static void
MergeIncludedSymbols(SymbolsInfo * into,SymbolsInfo * from,enum merge_mode merge)491*2b949d04SAndroid Build Coastguard Worker MergeIncludedSymbols(SymbolsInfo *into, SymbolsInfo *from,
492*2b949d04SAndroid Build Coastguard Worker enum merge_mode merge)
493*2b949d04SAndroid Build Coastguard Worker {
494*2b949d04SAndroid Build Coastguard Worker xkb_atom_t *group_name;
495*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t group_names_in_both;
496*2b949d04SAndroid Build Coastguard Worker
497*2b949d04SAndroid Build Coastguard Worker if (from->errorCount > 0) {
498*2b949d04SAndroid Build Coastguard Worker into->errorCount += from->errorCount;
499*2b949d04SAndroid Build Coastguard Worker return;
500*2b949d04SAndroid Build Coastguard Worker }
501*2b949d04SAndroid Build Coastguard Worker
502*2b949d04SAndroid Build Coastguard Worker into->mods = from->mods;
503*2b949d04SAndroid Build Coastguard Worker
504*2b949d04SAndroid Build Coastguard Worker if (into->name == NULL) {
505*2b949d04SAndroid Build Coastguard Worker into->name = from->name;
506*2b949d04SAndroid Build Coastguard Worker from->name = NULL;
507*2b949d04SAndroid Build Coastguard Worker }
508*2b949d04SAndroid Build Coastguard Worker
509*2b949d04SAndroid Build Coastguard Worker group_names_in_both = MIN(darray_size(into->group_names),
510*2b949d04SAndroid Build Coastguard Worker darray_size(from->group_names));
511*2b949d04SAndroid Build Coastguard Worker for (xkb_layout_index_t i = 0; i < group_names_in_both; i++) {
512*2b949d04SAndroid Build Coastguard Worker if (!darray_item(from->group_names, i))
513*2b949d04SAndroid Build Coastguard Worker continue;
514*2b949d04SAndroid Build Coastguard Worker
515*2b949d04SAndroid Build Coastguard Worker if (merge == MERGE_AUGMENT && darray_item(into->group_names, i))
516*2b949d04SAndroid Build Coastguard Worker continue;
517*2b949d04SAndroid Build Coastguard Worker
518*2b949d04SAndroid Build Coastguard Worker darray_item(into->group_names, i) = darray_item(from->group_names, i);
519*2b949d04SAndroid Build Coastguard Worker }
520*2b949d04SAndroid Build Coastguard Worker /* If @from has more, get them as well. */
521*2b949d04SAndroid Build Coastguard Worker darray_foreach_from(group_name, from->group_names, group_names_in_both)
522*2b949d04SAndroid Build Coastguard Worker darray_append(into->group_names, *group_name);
523*2b949d04SAndroid Build Coastguard Worker
524*2b949d04SAndroid Build Coastguard Worker if (darray_empty(into->keys)) {
525*2b949d04SAndroid Build Coastguard Worker into->keys = from->keys;
526*2b949d04SAndroid Build Coastguard Worker darray_init(from->keys);
527*2b949d04SAndroid Build Coastguard Worker }
528*2b949d04SAndroid Build Coastguard Worker else {
529*2b949d04SAndroid Build Coastguard Worker KeyInfo *keyi;
530*2b949d04SAndroid Build Coastguard Worker darray_foreach(keyi, from->keys) {
531*2b949d04SAndroid Build Coastguard Worker keyi->merge = (merge == MERGE_DEFAULT ? keyi->merge : merge);
532*2b949d04SAndroid Build Coastguard Worker if (!AddKeySymbols(into, keyi, false))
533*2b949d04SAndroid Build Coastguard Worker into->errorCount++;
534*2b949d04SAndroid Build Coastguard Worker }
535*2b949d04SAndroid Build Coastguard Worker }
536*2b949d04SAndroid Build Coastguard Worker
537*2b949d04SAndroid Build Coastguard Worker if (darray_empty(into->modmaps)) {
538*2b949d04SAndroid Build Coastguard Worker into->modmaps = from->modmaps;
539*2b949d04SAndroid Build Coastguard Worker darray_init(from->modmaps);
540*2b949d04SAndroid Build Coastguard Worker }
541*2b949d04SAndroid Build Coastguard Worker else {
542*2b949d04SAndroid Build Coastguard Worker ModMapEntry *mm;
543*2b949d04SAndroid Build Coastguard Worker darray_foreach(mm, from->modmaps) {
544*2b949d04SAndroid Build Coastguard Worker mm->merge = (merge == MERGE_DEFAULT ? mm->merge : merge);
545*2b949d04SAndroid Build Coastguard Worker if (!AddModMapEntry(into, mm))
546*2b949d04SAndroid Build Coastguard Worker into->errorCount++;
547*2b949d04SAndroid Build Coastguard Worker }
548*2b949d04SAndroid Build Coastguard Worker }
549*2b949d04SAndroid Build Coastguard Worker }
550*2b949d04SAndroid Build Coastguard Worker
551*2b949d04SAndroid Build Coastguard Worker static void
552*2b949d04SAndroid Build Coastguard Worker HandleSymbolsFile(SymbolsInfo *info, XkbFile *file, enum merge_mode merge);
553*2b949d04SAndroid Build Coastguard Worker
554*2b949d04SAndroid Build Coastguard Worker static bool
HandleIncludeSymbols(SymbolsInfo * info,IncludeStmt * include)555*2b949d04SAndroid Build Coastguard Worker HandleIncludeSymbols(SymbolsInfo *info, IncludeStmt *include)
556*2b949d04SAndroid Build Coastguard Worker {
557*2b949d04SAndroid Build Coastguard Worker SymbolsInfo included;
558*2b949d04SAndroid Build Coastguard Worker
559*2b949d04SAndroid Build Coastguard Worker InitSymbolsInfo(&included, info->keymap, info->actions, &info->mods);
560*2b949d04SAndroid Build Coastguard Worker included.name = include->stmt;
561*2b949d04SAndroid Build Coastguard Worker include->stmt = NULL;
562*2b949d04SAndroid Build Coastguard Worker
563*2b949d04SAndroid Build Coastguard Worker for (IncludeStmt *stmt = include; stmt; stmt = stmt->next_incl) {
564*2b949d04SAndroid Build Coastguard Worker SymbolsInfo next_incl;
565*2b949d04SAndroid Build Coastguard Worker XkbFile *file;
566*2b949d04SAndroid Build Coastguard Worker
567*2b949d04SAndroid Build Coastguard Worker file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_SYMBOLS);
568*2b949d04SAndroid Build Coastguard Worker if (!file) {
569*2b949d04SAndroid Build Coastguard Worker info->errorCount += 10;
570*2b949d04SAndroid Build Coastguard Worker ClearSymbolsInfo(&included);
571*2b949d04SAndroid Build Coastguard Worker return false;
572*2b949d04SAndroid Build Coastguard Worker }
573*2b949d04SAndroid Build Coastguard Worker
574*2b949d04SAndroid Build Coastguard Worker InitSymbolsInfo(&next_incl, info->keymap, info->actions,
575*2b949d04SAndroid Build Coastguard Worker &included.mods);
576*2b949d04SAndroid Build Coastguard Worker if (stmt->modifier) {
577*2b949d04SAndroid Build Coastguard Worker next_incl.explicit_group = atoi(stmt->modifier) - 1;
578*2b949d04SAndroid Build Coastguard Worker if (next_incl.explicit_group >= XKB_MAX_GROUPS) {
579*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
580*2b949d04SAndroid Build Coastguard Worker "Cannot set explicit group to %d - must be between 1..%d; "
581*2b949d04SAndroid Build Coastguard Worker "Ignoring group number\n",
582*2b949d04SAndroid Build Coastguard Worker next_incl.explicit_group + 1, XKB_MAX_GROUPS);
583*2b949d04SAndroid Build Coastguard Worker next_incl.explicit_group = info->explicit_group;
584*2b949d04SAndroid Build Coastguard Worker }
585*2b949d04SAndroid Build Coastguard Worker }
586*2b949d04SAndroid Build Coastguard Worker else {
587*2b949d04SAndroid Build Coastguard Worker next_incl.explicit_group = info->explicit_group;
588*2b949d04SAndroid Build Coastguard Worker }
589*2b949d04SAndroid Build Coastguard Worker
590*2b949d04SAndroid Build Coastguard Worker HandleSymbolsFile(&next_incl, file, MERGE_OVERRIDE);
591*2b949d04SAndroid Build Coastguard Worker
592*2b949d04SAndroid Build Coastguard Worker MergeIncludedSymbols(&included, &next_incl, stmt->merge);
593*2b949d04SAndroid Build Coastguard Worker
594*2b949d04SAndroid Build Coastguard Worker ClearSymbolsInfo(&next_incl);
595*2b949d04SAndroid Build Coastguard Worker FreeXkbFile(file);
596*2b949d04SAndroid Build Coastguard Worker }
597*2b949d04SAndroid Build Coastguard Worker
598*2b949d04SAndroid Build Coastguard Worker MergeIncludedSymbols(info, &included, include->merge);
599*2b949d04SAndroid Build Coastguard Worker ClearSymbolsInfo(&included);
600*2b949d04SAndroid Build Coastguard Worker
601*2b949d04SAndroid Build Coastguard Worker return (info->errorCount == 0);
602*2b949d04SAndroid Build Coastguard Worker }
603*2b949d04SAndroid Build Coastguard Worker
604*2b949d04SAndroid Build Coastguard Worker #define SYMBOLS 1
605*2b949d04SAndroid Build Coastguard Worker #define ACTIONS 2
606*2b949d04SAndroid Build Coastguard Worker
607*2b949d04SAndroid Build Coastguard Worker static bool
GetGroupIndex(SymbolsInfo * info,KeyInfo * keyi,ExprDef * arrayNdx,unsigned what,xkb_layout_index_t * ndx_rtrn)608*2b949d04SAndroid Build Coastguard Worker GetGroupIndex(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
609*2b949d04SAndroid Build Coastguard Worker unsigned what, xkb_layout_index_t *ndx_rtrn)
610*2b949d04SAndroid Build Coastguard Worker {
611*2b949d04SAndroid Build Coastguard Worker const char *name = (what == SYMBOLS ? "symbols" : "actions");
612*2b949d04SAndroid Build Coastguard Worker
613*2b949d04SAndroid Build Coastguard Worker if (arrayNdx == NULL) {
614*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t i;
615*2b949d04SAndroid Build Coastguard Worker GroupInfo *groupi;
616*2b949d04SAndroid Build Coastguard Worker enum group_field field = (what == SYMBOLS ?
617*2b949d04SAndroid Build Coastguard Worker GROUP_FIELD_SYMS : GROUP_FIELD_ACTS);
618*2b949d04SAndroid Build Coastguard Worker
619*2b949d04SAndroid Build Coastguard Worker darray_enumerate(i, groupi, keyi->groups) {
620*2b949d04SAndroid Build Coastguard Worker if (!(groupi->defined & field)) {
621*2b949d04SAndroid Build Coastguard Worker *ndx_rtrn = i;
622*2b949d04SAndroid Build Coastguard Worker return true;
623*2b949d04SAndroid Build Coastguard Worker }
624*2b949d04SAndroid Build Coastguard Worker }
625*2b949d04SAndroid Build Coastguard Worker
626*2b949d04SAndroid Build Coastguard Worker if (i >= XKB_MAX_GROUPS) {
627*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
628*2b949d04SAndroid Build Coastguard Worker "Too many groups of %s for key %s (max %u); "
629*2b949d04SAndroid Build Coastguard Worker "Ignoring %s defined for extra groups\n",
630*2b949d04SAndroid Build Coastguard Worker name, KeyInfoText(info, keyi), XKB_MAX_GROUPS, name);
631*2b949d04SAndroid Build Coastguard Worker return false;
632*2b949d04SAndroid Build Coastguard Worker }
633*2b949d04SAndroid Build Coastguard Worker
634*2b949d04SAndroid Build Coastguard Worker darray_resize0(keyi->groups, darray_size(keyi->groups) + 1);
635*2b949d04SAndroid Build Coastguard Worker *ndx_rtrn = darray_size(keyi->groups) - 1;
636*2b949d04SAndroid Build Coastguard Worker return true;
637*2b949d04SAndroid Build Coastguard Worker }
638*2b949d04SAndroid Build Coastguard Worker
639*2b949d04SAndroid Build Coastguard Worker if (!ExprResolveGroup(info->ctx, arrayNdx, ndx_rtrn)) {
640*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
641*2b949d04SAndroid Build Coastguard Worker "Illegal group index for %s of key %s\n"
642*2b949d04SAndroid Build Coastguard Worker "Definition with non-integer array index ignored\n",
643*2b949d04SAndroid Build Coastguard Worker name, KeyInfoText(info, keyi));
644*2b949d04SAndroid Build Coastguard Worker return false;
645*2b949d04SAndroid Build Coastguard Worker }
646*2b949d04SAndroid Build Coastguard Worker
647*2b949d04SAndroid Build Coastguard Worker (*ndx_rtrn)--;
648*2b949d04SAndroid Build Coastguard Worker if (*ndx_rtrn >= darray_size(keyi->groups))
649*2b949d04SAndroid Build Coastguard Worker darray_resize0(keyi->groups, *ndx_rtrn + 1);
650*2b949d04SAndroid Build Coastguard Worker
651*2b949d04SAndroid Build Coastguard Worker return true;
652*2b949d04SAndroid Build Coastguard Worker }
653*2b949d04SAndroid Build Coastguard Worker
654*2b949d04SAndroid Build Coastguard Worker static bool
AddSymbolsToKey(SymbolsInfo * info,KeyInfo * keyi,ExprDef * arrayNdx,ExprDef * value)655*2b949d04SAndroid Build Coastguard Worker AddSymbolsToKey(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
656*2b949d04SAndroid Build Coastguard Worker ExprDef *value)
657*2b949d04SAndroid Build Coastguard Worker {
658*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t ndx;
659*2b949d04SAndroid Build Coastguard Worker GroupInfo *groupi;
660*2b949d04SAndroid Build Coastguard Worker xkb_level_index_t nLevels;
661*2b949d04SAndroid Build Coastguard Worker
662*2b949d04SAndroid Build Coastguard Worker if (!GetGroupIndex(info, keyi, arrayNdx, SYMBOLS, &ndx))
663*2b949d04SAndroid Build Coastguard Worker return false;
664*2b949d04SAndroid Build Coastguard Worker
665*2b949d04SAndroid Build Coastguard Worker groupi = &darray_item(keyi->groups, ndx);
666*2b949d04SAndroid Build Coastguard Worker
667*2b949d04SAndroid Build Coastguard Worker if (value == NULL) {
668*2b949d04SAndroid Build Coastguard Worker groupi->defined |= GROUP_FIELD_SYMS;
669*2b949d04SAndroid Build Coastguard Worker return true;
670*2b949d04SAndroid Build Coastguard Worker }
671*2b949d04SAndroid Build Coastguard Worker
672*2b949d04SAndroid Build Coastguard Worker if (value->expr.op != EXPR_KEYSYM_LIST) {
673*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
674*2b949d04SAndroid Build Coastguard Worker "Expected a list of symbols, found %s; "
675*2b949d04SAndroid Build Coastguard Worker "Ignoring symbols for group %u of %s\n",
676*2b949d04SAndroid Build Coastguard Worker expr_op_type_to_string(value->expr.op), ndx + 1,
677*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi));
678*2b949d04SAndroid Build Coastguard Worker return false;
679*2b949d04SAndroid Build Coastguard Worker }
680*2b949d04SAndroid Build Coastguard Worker
681*2b949d04SAndroid Build Coastguard Worker if (groupi->defined & GROUP_FIELD_SYMS) {
682*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
683*2b949d04SAndroid Build Coastguard Worker "Symbols for key %s, group %u already defined; "
684*2b949d04SAndroid Build Coastguard Worker "Ignoring duplicate definition\n",
685*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi), ndx + 1);
686*2b949d04SAndroid Build Coastguard Worker return false;
687*2b949d04SAndroid Build Coastguard Worker }
688*2b949d04SAndroid Build Coastguard Worker
689*2b949d04SAndroid Build Coastguard Worker nLevels = darray_size(value->keysym_list.symsMapIndex);
690*2b949d04SAndroid Build Coastguard Worker if (darray_size(groupi->levels) < nLevels)
691*2b949d04SAndroid Build Coastguard Worker darray_resize0(groupi->levels, nLevels);
692*2b949d04SAndroid Build Coastguard Worker
693*2b949d04SAndroid Build Coastguard Worker groupi->defined |= GROUP_FIELD_SYMS;
694*2b949d04SAndroid Build Coastguard Worker
695*2b949d04SAndroid Build Coastguard Worker for (xkb_level_index_t i = 0; i < nLevels; i++) {
696*2b949d04SAndroid Build Coastguard Worker unsigned int sym_index;
697*2b949d04SAndroid Build Coastguard Worker struct xkb_level *leveli = &darray_item(groupi->levels, i);
698*2b949d04SAndroid Build Coastguard Worker
699*2b949d04SAndroid Build Coastguard Worker sym_index = darray_item(value->keysym_list.symsMapIndex, i);
700*2b949d04SAndroid Build Coastguard Worker leveli->num_syms = darray_item(value->keysym_list.symsNumEntries, i);
701*2b949d04SAndroid Build Coastguard Worker if (leveli->num_syms > 1)
702*2b949d04SAndroid Build Coastguard Worker leveli->u.syms = calloc(leveli->num_syms, sizeof(*leveli->u.syms));
703*2b949d04SAndroid Build Coastguard Worker
704*2b949d04SAndroid Build Coastguard Worker for (unsigned j = 0; j < leveli->num_syms; j++) {
705*2b949d04SAndroid Build Coastguard Worker xkb_keysym_t keysym = darray_item(value->keysym_list.syms,
706*2b949d04SAndroid Build Coastguard Worker sym_index + j);
707*2b949d04SAndroid Build Coastguard Worker
708*2b949d04SAndroid Build Coastguard Worker if (leveli->num_syms == 1) {
709*2b949d04SAndroid Build Coastguard Worker if (keysym == XKB_KEY_NoSymbol)
710*2b949d04SAndroid Build Coastguard Worker leveli->num_syms = 0;
711*2b949d04SAndroid Build Coastguard Worker else
712*2b949d04SAndroid Build Coastguard Worker leveli->u.sym = keysym;
713*2b949d04SAndroid Build Coastguard Worker }
714*2b949d04SAndroid Build Coastguard Worker else if (leveli->num_syms > 1) {
715*2b949d04SAndroid Build Coastguard Worker leveli->u.syms[j] = keysym;
716*2b949d04SAndroid Build Coastguard Worker }
717*2b949d04SAndroid Build Coastguard Worker }
718*2b949d04SAndroid Build Coastguard Worker }
719*2b949d04SAndroid Build Coastguard Worker
720*2b949d04SAndroid Build Coastguard Worker return true;
721*2b949d04SAndroid Build Coastguard Worker }
722*2b949d04SAndroid Build Coastguard Worker
723*2b949d04SAndroid Build Coastguard Worker static bool
AddActionsToKey(SymbolsInfo * info,KeyInfo * keyi,ExprDef * arrayNdx,ExprDef * value)724*2b949d04SAndroid Build Coastguard Worker AddActionsToKey(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
725*2b949d04SAndroid Build Coastguard Worker ExprDef *value)
726*2b949d04SAndroid Build Coastguard Worker {
727*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t ndx;
728*2b949d04SAndroid Build Coastguard Worker GroupInfo *groupi;
729*2b949d04SAndroid Build Coastguard Worker unsigned int nActs;
730*2b949d04SAndroid Build Coastguard Worker ExprDef *act;
731*2b949d04SAndroid Build Coastguard Worker
732*2b949d04SAndroid Build Coastguard Worker if (!GetGroupIndex(info, keyi, arrayNdx, ACTIONS, &ndx))
733*2b949d04SAndroid Build Coastguard Worker return false;
734*2b949d04SAndroid Build Coastguard Worker
735*2b949d04SAndroid Build Coastguard Worker groupi = &darray_item(keyi->groups, ndx);
736*2b949d04SAndroid Build Coastguard Worker
737*2b949d04SAndroid Build Coastguard Worker if (value == NULL) {
738*2b949d04SAndroid Build Coastguard Worker groupi->defined |= GROUP_FIELD_ACTS;
739*2b949d04SAndroid Build Coastguard Worker return true;
740*2b949d04SAndroid Build Coastguard Worker }
741*2b949d04SAndroid Build Coastguard Worker
742*2b949d04SAndroid Build Coastguard Worker if (value->expr.op != EXPR_ACTION_LIST) {
743*2b949d04SAndroid Build Coastguard Worker log_wsgo(info->ctx,
744*2b949d04SAndroid Build Coastguard Worker "Bad expression type (%d) for action list value; "
745*2b949d04SAndroid Build Coastguard Worker "Ignoring actions for group %u of %s\n",
746*2b949d04SAndroid Build Coastguard Worker value->expr.op, ndx, KeyInfoText(info, keyi));
747*2b949d04SAndroid Build Coastguard Worker return false;
748*2b949d04SAndroid Build Coastguard Worker }
749*2b949d04SAndroid Build Coastguard Worker
750*2b949d04SAndroid Build Coastguard Worker if (groupi->defined & GROUP_FIELD_ACTS) {
751*2b949d04SAndroid Build Coastguard Worker log_wsgo(info->ctx,
752*2b949d04SAndroid Build Coastguard Worker "Actions for key %s, group %u already defined\n",
753*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi), ndx);
754*2b949d04SAndroid Build Coastguard Worker return false;
755*2b949d04SAndroid Build Coastguard Worker }
756*2b949d04SAndroid Build Coastguard Worker
757*2b949d04SAndroid Build Coastguard Worker nActs = 0;
758*2b949d04SAndroid Build Coastguard Worker for (act = value->actions.actions; act; act = (ExprDef *) act->common.next)
759*2b949d04SAndroid Build Coastguard Worker nActs++;
760*2b949d04SAndroid Build Coastguard Worker
761*2b949d04SAndroid Build Coastguard Worker if (darray_size(groupi->levels) < nActs)
762*2b949d04SAndroid Build Coastguard Worker darray_resize0(groupi->levels, nActs);
763*2b949d04SAndroid Build Coastguard Worker
764*2b949d04SAndroid Build Coastguard Worker groupi->defined |= GROUP_FIELD_ACTS;
765*2b949d04SAndroid Build Coastguard Worker
766*2b949d04SAndroid Build Coastguard Worker act = value->actions.actions;
767*2b949d04SAndroid Build Coastguard Worker for (unsigned i = 0; i < nActs; i++) {
768*2b949d04SAndroid Build Coastguard Worker union xkb_action *toAct = &darray_item(groupi->levels, i).action;
769*2b949d04SAndroid Build Coastguard Worker
770*2b949d04SAndroid Build Coastguard Worker if (!HandleActionDef(info->ctx, info->actions, &info->mods, act, toAct))
771*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
772*2b949d04SAndroid Build Coastguard Worker "Illegal action definition for %s; "
773*2b949d04SAndroid Build Coastguard Worker "Action for group %u/level %u ignored\n",
774*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi), ndx + 1, i + 1);
775*2b949d04SAndroid Build Coastguard Worker
776*2b949d04SAndroid Build Coastguard Worker act = (ExprDef *) act->common.next;
777*2b949d04SAndroid Build Coastguard Worker }
778*2b949d04SAndroid Build Coastguard Worker
779*2b949d04SAndroid Build Coastguard Worker return true;
780*2b949d04SAndroid Build Coastguard Worker }
781*2b949d04SAndroid Build Coastguard Worker
782*2b949d04SAndroid Build Coastguard Worker static const LookupEntry repeatEntries[] = {
783*2b949d04SAndroid Build Coastguard Worker { "true", KEY_REPEAT_YES },
784*2b949d04SAndroid Build Coastguard Worker { "yes", KEY_REPEAT_YES },
785*2b949d04SAndroid Build Coastguard Worker { "on", KEY_REPEAT_YES },
786*2b949d04SAndroid Build Coastguard Worker { "false", KEY_REPEAT_NO },
787*2b949d04SAndroid Build Coastguard Worker { "no", KEY_REPEAT_NO },
788*2b949d04SAndroid Build Coastguard Worker { "off", KEY_REPEAT_NO },
789*2b949d04SAndroid Build Coastguard Worker { "default", KEY_REPEAT_UNDEFINED },
790*2b949d04SAndroid Build Coastguard Worker { NULL, 0 }
791*2b949d04SAndroid Build Coastguard Worker };
792*2b949d04SAndroid Build Coastguard Worker
793*2b949d04SAndroid Build Coastguard Worker static bool
SetSymbolsField(SymbolsInfo * info,KeyInfo * keyi,const char * field,ExprDef * arrayNdx,ExprDef * value)794*2b949d04SAndroid Build Coastguard Worker SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field,
795*2b949d04SAndroid Build Coastguard Worker ExprDef *arrayNdx, ExprDef *value)
796*2b949d04SAndroid Build Coastguard Worker {
797*2b949d04SAndroid Build Coastguard Worker if (istreq(field, "type")) {
798*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t ndx;
799*2b949d04SAndroid Build Coastguard Worker xkb_atom_t val;
800*2b949d04SAndroid Build Coastguard Worker
801*2b949d04SAndroid Build Coastguard Worker if (!ExprResolveString(info->ctx, value, &val)) {
802*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
803*2b949d04SAndroid Build Coastguard Worker "The type field of a key symbol map must be a string; "
804*2b949d04SAndroid Build Coastguard Worker "Ignoring illegal type definition\n");
805*2b949d04SAndroid Build Coastguard Worker return false;
806*2b949d04SAndroid Build Coastguard Worker }
807*2b949d04SAndroid Build Coastguard Worker
808*2b949d04SAndroid Build Coastguard Worker if (!arrayNdx) {
809*2b949d04SAndroid Build Coastguard Worker keyi->default_type = val;
810*2b949d04SAndroid Build Coastguard Worker keyi->defined |= KEY_FIELD_DEFAULT_TYPE;
811*2b949d04SAndroid Build Coastguard Worker }
812*2b949d04SAndroid Build Coastguard Worker else if (!ExprResolveGroup(info->ctx, arrayNdx, &ndx)) {
813*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
814*2b949d04SAndroid Build Coastguard Worker "Illegal group index for type of key %s; "
815*2b949d04SAndroid Build Coastguard Worker "Definition with non-integer array index ignored\n",
816*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi));
817*2b949d04SAndroid Build Coastguard Worker return false;
818*2b949d04SAndroid Build Coastguard Worker }
819*2b949d04SAndroid Build Coastguard Worker else {
820*2b949d04SAndroid Build Coastguard Worker ndx--;
821*2b949d04SAndroid Build Coastguard Worker if (ndx >= darray_size(keyi->groups))
822*2b949d04SAndroid Build Coastguard Worker darray_resize0(keyi->groups, ndx + 1);
823*2b949d04SAndroid Build Coastguard Worker darray_item(keyi->groups, ndx).type = val;
824*2b949d04SAndroid Build Coastguard Worker darray_item(keyi->groups, ndx).defined |= GROUP_FIELD_TYPE;
825*2b949d04SAndroid Build Coastguard Worker }
826*2b949d04SAndroid Build Coastguard Worker }
827*2b949d04SAndroid Build Coastguard Worker else if (istreq(field, "symbols")) {
828*2b949d04SAndroid Build Coastguard Worker return AddSymbolsToKey(info, keyi, arrayNdx, value);
829*2b949d04SAndroid Build Coastguard Worker }
830*2b949d04SAndroid Build Coastguard Worker else if (istreq(field, "actions")) {
831*2b949d04SAndroid Build Coastguard Worker return AddActionsToKey(info, keyi, arrayNdx, value);
832*2b949d04SAndroid Build Coastguard Worker }
833*2b949d04SAndroid Build Coastguard Worker else if (istreq(field, "vmods") ||
834*2b949d04SAndroid Build Coastguard Worker istreq(field, "virtualmods") ||
835*2b949d04SAndroid Build Coastguard Worker istreq(field, "virtualmodifiers")) {
836*2b949d04SAndroid Build Coastguard Worker xkb_mod_mask_t mask;
837*2b949d04SAndroid Build Coastguard Worker
838*2b949d04SAndroid Build Coastguard Worker if (!ExprResolveModMask(info->ctx, value, MOD_VIRT, &info->mods,
839*2b949d04SAndroid Build Coastguard Worker &mask)) {
840*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
841*2b949d04SAndroid Build Coastguard Worker "Expected a virtual modifier mask, found %s; "
842*2b949d04SAndroid Build Coastguard Worker "Ignoring virtual modifiers definition for key %s\n",
843*2b949d04SAndroid Build Coastguard Worker expr_op_type_to_string(value->expr.op),
844*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi));
845*2b949d04SAndroid Build Coastguard Worker return false;
846*2b949d04SAndroid Build Coastguard Worker }
847*2b949d04SAndroid Build Coastguard Worker
848*2b949d04SAndroid Build Coastguard Worker keyi->vmodmap = mask;
849*2b949d04SAndroid Build Coastguard Worker keyi->defined |= KEY_FIELD_VMODMAP;
850*2b949d04SAndroid Build Coastguard Worker }
851*2b949d04SAndroid Build Coastguard Worker else if (istreq(field, "locking") ||
852*2b949d04SAndroid Build Coastguard Worker istreq(field, "lock") ||
853*2b949d04SAndroid Build Coastguard Worker istreq(field, "locks")) {
854*2b949d04SAndroid Build Coastguard Worker log_vrb(info->ctx, 1,
855*2b949d04SAndroid Build Coastguard Worker "Key behaviors not supported; "
856*2b949d04SAndroid Build Coastguard Worker "Ignoring locking specification for key %s\n",
857*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi));
858*2b949d04SAndroid Build Coastguard Worker }
859*2b949d04SAndroid Build Coastguard Worker else if (istreq(field, "radiogroup") ||
860*2b949d04SAndroid Build Coastguard Worker istreq(field, "permanentradiogroup") ||
861*2b949d04SAndroid Build Coastguard Worker istreq(field, "allownone")) {
862*2b949d04SAndroid Build Coastguard Worker log_vrb(info->ctx, 1,
863*2b949d04SAndroid Build Coastguard Worker "Radio groups not supported; "
864*2b949d04SAndroid Build Coastguard Worker "Ignoring radio group specification for key %s\n",
865*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi));
866*2b949d04SAndroid Build Coastguard Worker }
867*2b949d04SAndroid Build Coastguard Worker else if (istreq_prefix("overlay", field) ||
868*2b949d04SAndroid Build Coastguard Worker istreq_prefix("permanentoverlay", field)) {
869*2b949d04SAndroid Build Coastguard Worker log_vrb(info->ctx, 1,
870*2b949d04SAndroid Build Coastguard Worker "Overlays not supported; "
871*2b949d04SAndroid Build Coastguard Worker "Ignoring overlay specification for key %s\n",
872*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi));
873*2b949d04SAndroid Build Coastguard Worker }
874*2b949d04SAndroid Build Coastguard Worker else if (istreq(field, "repeating") ||
875*2b949d04SAndroid Build Coastguard Worker istreq(field, "repeats") ||
876*2b949d04SAndroid Build Coastguard Worker istreq(field, "repeat")) {
877*2b949d04SAndroid Build Coastguard Worker unsigned int val;
878*2b949d04SAndroid Build Coastguard Worker
879*2b949d04SAndroid Build Coastguard Worker if (!ExprResolveEnum(info->ctx, value, &val, repeatEntries)) {
880*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
881*2b949d04SAndroid Build Coastguard Worker "Illegal repeat setting for %s; "
882*2b949d04SAndroid Build Coastguard Worker "Non-boolean repeat setting ignored\n",
883*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi));
884*2b949d04SAndroid Build Coastguard Worker return false;
885*2b949d04SAndroid Build Coastguard Worker }
886*2b949d04SAndroid Build Coastguard Worker
887*2b949d04SAndroid Build Coastguard Worker keyi->repeat = val;
888*2b949d04SAndroid Build Coastguard Worker keyi->defined |= KEY_FIELD_REPEAT;
889*2b949d04SAndroid Build Coastguard Worker }
890*2b949d04SAndroid Build Coastguard Worker else if (istreq(field, "groupswrap") ||
891*2b949d04SAndroid Build Coastguard Worker istreq(field, "wrapgroups")) {
892*2b949d04SAndroid Build Coastguard Worker bool set;
893*2b949d04SAndroid Build Coastguard Worker
894*2b949d04SAndroid Build Coastguard Worker if (!ExprResolveBoolean(info->ctx, value, &set)) {
895*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
896*2b949d04SAndroid Build Coastguard Worker "Illegal groupsWrap setting for %s; "
897*2b949d04SAndroid Build Coastguard Worker "Non-boolean value ignored\n",
898*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi));
899*2b949d04SAndroid Build Coastguard Worker return false;
900*2b949d04SAndroid Build Coastguard Worker }
901*2b949d04SAndroid Build Coastguard Worker
902*2b949d04SAndroid Build Coastguard Worker keyi->out_of_range_group_action = (set ? RANGE_WRAP : RANGE_SATURATE);
903*2b949d04SAndroid Build Coastguard Worker keyi->defined |= KEY_FIELD_GROUPINFO;
904*2b949d04SAndroid Build Coastguard Worker }
905*2b949d04SAndroid Build Coastguard Worker else if (istreq(field, "groupsclamp") ||
906*2b949d04SAndroid Build Coastguard Worker istreq(field, "clampgroups")) {
907*2b949d04SAndroid Build Coastguard Worker bool set;
908*2b949d04SAndroid Build Coastguard Worker
909*2b949d04SAndroid Build Coastguard Worker if (!ExprResolveBoolean(info->ctx, value, &set)) {
910*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
911*2b949d04SAndroid Build Coastguard Worker "Illegal groupsClamp setting for %s; "
912*2b949d04SAndroid Build Coastguard Worker "Non-boolean value ignored\n",
913*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi));
914*2b949d04SAndroid Build Coastguard Worker return false;
915*2b949d04SAndroid Build Coastguard Worker }
916*2b949d04SAndroid Build Coastguard Worker
917*2b949d04SAndroid Build Coastguard Worker keyi->out_of_range_group_action = (set ? RANGE_SATURATE : RANGE_WRAP);
918*2b949d04SAndroid Build Coastguard Worker keyi->defined |= KEY_FIELD_GROUPINFO;
919*2b949d04SAndroid Build Coastguard Worker }
920*2b949d04SAndroid Build Coastguard Worker else if (istreq(field, "groupsredirect") ||
921*2b949d04SAndroid Build Coastguard Worker istreq(field, "redirectgroups")) {
922*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t grp;
923*2b949d04SAndroid Build Coastguard Worker
924*2b949d04SAndroid Build Coastguard Worker if (!ExprResolveGroup(info->ctx, value, &grp)) {
925*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
926*2b949d04SAndroid Build Coastguard Worker "Illegal group index for redirect of key %s; "
927*2b949d04SAndroid Build Coastguard Worker "Definition with non-integer group ignored\n",
928*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi));
929*2b949d04SAndroid Build Coastguard Worker return false;
930*2b949d04SAndroid Build Coastguard Worker }
931*2b949d04SAndroid Build Coastguard Worker
932*2b949d04SAndroid Build Coastguard Worker keyi->out_of_range_group_action = RANGE_REDIRECT;
933*2b949d04SAndroid Build Coastguard Worker keyi->out_of_range_group_number = grp - 1;
934*2b949d04SAndroid Build Coastguard Worker keyi->defined |= KEY_FIELD_GROUPINFO;
935*2b949d04SAndroid Build Coastguard Worker }
936*2b949d04SAndroid Build Coastguard Worker else {
937*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
938*2b949d04SAndroid Build Coastguard Worker "Unknown field %s in a symbol interpretation; "
939*2b949d04SAndroid Build Coastguard Worker "Definition ignored\n",
940*2b949d04SAndroid Build Coastguard Worker field);
941*2b949d04SAndroid Build Coastguard Worker return false;
942*2b949d04SAndroid Build Coastguard Worker }
943*2b949d04SAndroid Build Coastguard Worker
944*2b949d04SAndroid Build Coastguard Worker return true;
945*2b949d04SAndroid Build Coastguard Worker }
946*2b949d04SAndroid Build Coastguard Worker
947*2b949d04SAndroid Build Coastguard Worker static bool
SetGroupName(SymbolsInfo * info,ExprDef * arrayNdx,ExprDef * value)948*2b949d04SAndroid Build Coastguard Worker SetGroupName(SymbolsInfo *info, ExprDef *arrayNdx, ExprDef *value)
949*2b949d04SAndroid Build Coastguard Worker {
950*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t group, group_to_use;
951*2b949d04SAndroid Build Coastguard Worker xkb_atom_t name;
952*2b949d04SAndroid Build Coastguard Worker
953*2b949d04SAndroid Build Coastguard Worker if (!arrayNdx) {
954*2b949d04SAndroid Build Coastguard Worker log_vrb(info->ctx, 1,
955*2b949d04SAndroid Build Coastguard Worker "You must specify an index when specifying a group name; "
956*2b949d04SAndroid Build Coastguard Worker "Group name definition without array subscript ignored\n");
957*2b949d04SAndroid Build Coastguard Worker return false;
958*2b949d04SAndroid Build Coastguard Worker }
959*2b949d04SAndroid Build Coastguard Worker
960*2b949d04SAndroid Build Coastguard Worker if (!ExprResolveGroup(info->ctx, arrayNdx, &group)) {
961*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
962*2b949d04SAndroid Build Coastguard Worker "Illegal index in group name definition; "
963*2b949d04SAndroid Build Coastguard Worker "Definition with non-integer array index ignored\n");
964*2b949d04SAndroid Build Coastguard Worker return false;
965*2b949d04SAndroid Build Coastguard Worker }
966*2b949d04SAndroid Build Coastguard Worker
967*2b949d04SAndroid Build Coastguard Worker if (!ExprResolveString(info->ctx, value, &name)) {
968*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
969*2b949d04SAndroid Build Coastguard Worker "Group name must be a string; "
970*2b949d04SAndroid Build Coastguard Worker "Illegal name for group %d ignored\n", group);
971*2b949d04SAndroid Build Coastguard Worker return false;
972*2b949d04SAndroid Build Coastguard Worker }
973*2b949d04SAndroid Build Coastguard Worker
974*2b949d04SAndroid Build Coastguard Worker if (info->explicit_group == XKB_LAYOUT_INVALID) {
975*2b949d04SAndroid Build Coastguard Worker group_to_use = group - 1;
976*2b949d04SAndroid Build Coastguard Worker }
977*2b949d04SAndroid Build Coastguard Worker else if (group - 1 == 0) {
978*2b949d04SAndroid Build Coastguard Worker group_to_use = info->explicit_group;
979*2b949d04SAndroid Build Coastguard Worker }
980*2b949d04SAndroid Build Coastguard Worker else {
981*2b949d04SAndroid Build Coastguard Worker log_warn(info->ctx,
982*2b949d04SAndroid Build Coastguard Worker "An explicit group was specified for the '%s' map, "
983*2b949d04SAndroid Build Coastguard Worker "but it provides a name for a group other than Group1 (%d); "
984*2b949d04SAndroid Build Coastguard Worker "Ignoring group name '%s'\n",
985*2b949d04SAndroid Build Coastguard Worker info->name, group,
986*2b949d04SAndroid Build Coastguard Worker xkb_atom_text(info->ctx, name));
987*2b949d04SAndroid Build Coastguard Worker return false;
988*2b949d04SAndroid Build Coastguard Worker }
989*2b949d04SAndroid Build Coastguard Worker
990*2b949d04SAndroid Build Coastguard Worker if (group_to_use >= darray_size(info->group_names))
991*2b949d04SAndroid Build Coastguard Worker darray_resize0(info->group_names, group_to_use + 1);
992*2b949d04SAndroid Build Coastguard Worker darray_item(info->group_names, group_to_use) = name;
993*2b949d04SAndroid Build Coastguard Worker
994*2b949d04SAndroid Build Coastguard Worker return true;
995*2b949d04SAndroid Build Coastguard Worker }
996*2b949d04SAndroid Build Coastguard Worker
997*2b949d04SAndroid Build Coastguard Worker static bool
HandleGlobalVar(SymbolsInfo * info,VarDef * stmt)998*2b949d04SAndroid Build Coastguard Worker HandleGlobalVar(SymbolsInfo *info, VarDef *stmt)
999*2b949d04SAndroid Build Coastguard Worker {
1000*2b949d04SAndroid Build Coastguard Worker const char *elem, *field;
1001*2b949d04SAndroid Build Coastguard Worker ExprDef *arrayNdx;
1002*2b949d04SAndroid Build Coastguard Worker bool ret;
1003*2b949d04SAndroid Build Coastguard Worker
1004*2b949d04SAndroid Build Coastguard Worker if (!ExprResolveLhs(info->ctx, stmt->name, &elem, &field, &arrayNdx))
1005*2b949d04SAndroid Build Coastguard Worker return false;
1006*2b949d04SAndroid Build Coastguard Worker
1007*2b949d04SAndroid Build Coastguard Worker if (elem && istreq(elem, "key")) {
1008*2b949d04SAndroid Build Coastguard Worker ret = SetSymbolsField(info, &info->default_key, field, arrayNdx,
1009*2b949d04SAndroid Build Coastguard Worker stmt->value);
1010*2b949d04SAndroid Build Coastguard Worker }
1011*2b949d04SAndroid Build Coastguard Worker else if (!elem && (istreq(field, "name") ||
1012*2b949d04SAndroid Build Coastguard Worker istreq(field, "groupname"))) {
1013*2b949d04SAndroid Build Coastguard Worker ret = SetGroupName(info, arrayNdx, stmt->value);
1014*2b949d04SAndroid Build Coastguard Worker }
1015*2b949d04SAndroid Build Coastguard Worker else if (!elem && (istreq(field, "groupswrap") ||
1016*2b949d04SAndroid Build Coastguard Worker istreq(field, "wrapgroups"))) {
1017*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
1018*2b949d04SAndroid Build Coastguard Worker "Global \"groupswrap\" not supported; Ignored\n");
1019*2b949d04SAndroid Build Coastguard Worker ret = true;
1020*2b949d04SAndroid Build Coastguard Worker }
1021*2b949d04SAndroid Build Coastguard Worker else if (!elem && (istreq(field, "groupsclamp") ||
1022*2b949d04SAndroid Build Coastguard Worker istreq(field, "clampgroups"))) {
1023*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
1024*2b949d04SAndroid Build Coastguard Worker "Global \"groupsclamp\" not supported; Ignored\n");
1025*2b949d04SAndroid Build Coastguard Worker ret = true;
1026*2b949d04SAndroid Build Coastguard Worker }
1027*2b949d04SAndroid Build Coastguard Worker else if (!elem && (istreq(field, "groupsredirect") ||
1028*2b949d04SAndroid Build Coastguard Worker istreq(field, "redirectgroups"))) {
1029*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
1030*2b949d04SAndroid Build Coastguard Worker "Global \"groupsredirect\" not supported; Ignored\n");
1031*2b949d04SAndroid Build Coastguard Worker ret = true;
1032*2b949d04SAndroid Build Coastguard Worker }
1033*2b949d04SAndroid Build Coastguard Worker else if (!elem && istreq(field, "allownone")) {
1034*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
1035*2b949d04SAndroid Build Coastguard Worker "Radio groups not supported; "
1036*2b949d04SAndroid Build Coastguard Worker "Ignoring \"allownone\" specification\n");
1037*2b949d04SAndroid Build Coastguard Worker ret = true;
1038*2b949d04SAndroid Build Coastguard Worker }
1039*2b949d04SAndroid Build Coastguard Worker else {
1040*2b949d04SAndroid Build Coastguard Worker ret = SetActionField(info->ctx, info->actions, &info->mods,
1041*2b949d04SAndroid Build Coastguard Worker elem, field, arrayNdx, stmt->value);
1042*2b949d04SAndroid Build Coastguard Worker }
1043*2b949d04SAndroid Build Coastguard Worker
1044*2b949d04SAndroid Build Coastguard Worker return ret;
1045*2b949d04SAndroid Build Coastguard Worker }
1046*2b949d04SAndroid Build Coastguard Worker
1047*2b949d04SAndroid Build Coastguard Worker static bool
HandleSymbolsBody(SymbolsInfo * info,VarDef * def,KeyInfo * keyi)1048*2b949d04SAndroid Build Coastguard Worker HandleSymbolsBody(SymbolsInfo *info, VarDef *def, KeyInfo *keyi)
1049*2b949d04SAndroid Build Coastguard Worker {
1050*2b949d04SAndroid Build Coastguard Worker bool ok = true;
1051*2b949d04SAndroid Build Coastguard Worker const char *elem, *field;
1052*2b949d04SAndroid Build Coastguard Worker ExprDef *arrayNdx;
1053*2b949d04SAndroid Build Coastguard Worker
1054*2b949d04SAndroid Build Coastguard Worker for (; def; def = (VarDef *) def->common.next) {
1055*2b949d04SAndroid Build Coastguard Worker if (def->name && def->name->expr.op == EXPR_FIELD_REF) {
1056*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
1057*2b949d04SAndroid Build Coastguard Worker "Cannot set a global default value from within a key statement; "
1058*2b949d04SAndroid Build Coastguard Worker "Move statements to the global file scope\n");
1059*2b949d04SAndroid Build Coastguard Worker continue;
1060*2b949d04SAndroid Build Coastguard Worker }
1061*2b949d04SAndroid Build Coastguard Worker
1062*2b949d04SAndroid Build Coastguard Worker if (!def->name) {
1063*2b949d04SAndroid Build Coastguard Worker if (!def->value || def->value->expr.op == EXPR_KEYSYM_LIST)
1064*2b949d04SAndroid Build Coastguard Worker field = "symbols";
1065*2b949d04SAndroid Build Coastguard Worker else
1066*2b949d04SAndroid Build Coastguard Worker field = "actions";
1067*2b949d04SAndroid Build Coastguard Worker arrayNdx = NULL;
1068*2b949d04SAndroid Build Coastguard Worker }
1069*2b949d04SAndroid Build Coastguard Worker else {
1070*2b949d04SAndroid Build Coastguard Worker ok = ExprResolveLhs(info->ctx, def->name, &elem, &field,
1071*2b949d04SAndroid Build Coastguard Worker &arrayNdx);
1072*2b949d04SAndroid Build Coastguard Worker }
1073*2b949d04SAndroid Build Coastguard Worker
1074*2b949d04SAndroid Build Coastguard Worker if (ok)
1075*2b949d04SAndroid Build Coastguard Worker ok = SetSymbolsField(info, keyi, field, arrayNdx, def->value);
1076*2b949d04SAndroid Build Coastguard Worker }
1077*2b949d04SAndroid Build Coastguard Worker
1078*2b949d04SAndroid Build Coastguard Worker return ok;
1079*2b949d04SAndroid Build Coastguard Worker }
1080*2b949d04SAndroid Build Coastguard Worker
1081*2b949d04SAndroid Build Coastguard Worker static bool
SetExplicitGroup(SymbolsInfo * info,KeyInfo * keyi)1082*2b949d04SAndroid Build Coastguard Worker SetExplicitGroup(SymbolsInfo *info, KeyInfo *keyi)
1083*2b949d04SAndroid Build Coastguard Worker {
1084*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t i;
1085*2b949d04SAndroid Build Coastguard Worker GroupInfo *groupi;
1086*2b949d04SAndroid Build Coastguard Worker bool warn = false;
1087*2b949d04SAndroid Build Coastguard Worker
1088*2b949d04SAndroid Build Coastguard Worker if (info->explicit_group == XKB_LAYOUT_INVALID)
1089*2b949d04SAndroid Build Coastguard Worker return true;
1090*2b949d04SAndroid Build Coastguard Worker
1091*2b949d04SAndroid Build Coastguard Worker darray_enumerate_from(i, groupi, keyi->groups, 1) {
1092*2b949d04SAndroid Build Coastguard Worker if (groupi->defined) {
1093*2b949d04SAndroid Build Coastguard Worker warn = true;
1094*2b949d04SAndroid Build Coastguard Worker ClearGroupInfo(groupi);
1095*2b949d04SAndroid Build Coastguard Worker InitGroupInfo(groupi);
1096*2b949d04SAndroid Build Coastguard Worker }
1097*2b949d04SAndroid Build Coastguard Worker }
1098*2b949d04SAndroid Build Coastguard Worker
1099*2b949d04SAndroid Build Coastguard Worker if (warn)
1100*2b949d04SAndroid Build Coastguard Worker log_warn(info->ctx,
1101*2b949d04SAndroid Build Coastguard Worker "For the map %s an explicit group specified, "
1102*2b949d04SAndroid Build Coastguard Worker "but key %s has more than one group defined; "
1103*2b949d04SAndroid Build Coastguard Worker "All groups except first one will be ignored\n",
1104*2b949d04SAndroid Build Coastguard Worker info->name, KeyInfoText(info, keyi));
1105*2b949d04SAndroid Build Coastguard Worker
1106*2b949d04SAndroid Build Coastguard Worker darray_resize0(keyi->groups, info->explicit_group + 1);
1107*2b949d04SAndroid Build Coastguard Worker if (info->explicit_group > 0) {
1108*2b949d04SAndroid Build Coastguard Worker darray_item(keyi->groups, info->explicit_group) =
1109*2b949d04SAndroid Build Coastguard Worker darray_item(keyi->groups, 0);
1110*2b949d04SAndroid Build Coastguard Worker InitGroupInfo(&darray_item(keyi->groups, 0));
1111*2b949d04SAndroid Build Coastguard Worker }
1112*2b949d04SAndroid Build Coastguard Worker
1113*2b949d04SAndroid Build Coastguard Worker return true;
1114*2b949d04SAndroid Build Coastguard Worker }
1115*2b949d04SAndroid Build Coastguard Worker
1116*2b949d04SAndroid Build Coastguard Worker static bool
HandleSymbolsDef(SymbolsInfo * info,SymbolsDef * stmt)1117*2b949d04SAndroid Build Coastguard Worker HandleSymbolsDef(SymbolsInfo *info, SymbolsDef *stmt)
1118*2b949d04SAndroid Build Coastguard Worker {
1119*2b949d04SAndroid Build Coastguard Worker KeyInfo keyi;
1120*2b949d04SAndroid Build Coastguard Worker
1121*2b949d04SAndroid Build Coastguard Worker keyi = info->default_key;
1122*2b949d04SAndroid Build Coastguard Worker darray_init(keyi.groups);
1123*2b949d04SAndroid Build Coastguard Worker darray_copy(keyi.groups, info->default_key.groups);
1124*2b949d04SAndroid Build Coastguard Worker for (xkb_layout_index_t i = 0; i < darray_size(keyi.groups); i++)
1125*2b949d04SAndroid Build Coastguard Worker CopyGroupInfo(&darray_item(keyi.groups, i),
1126*2b949d04SAndroid Build Coastguard Worker &darray_item(info->default_key.groups, i));
1127*2b949d04SAndroid Build Coastguard Worker keyi.merge = stmt->merge;
1128*2b949d04SAndroid Build Coastguard Worker keyi.name = stmt->keyName;
1129*2b949d04SAndroid Build Coastguard Worker
1130*2b949d04SAndroid Build Coastguard Worker if (!HandleSymbolsBody(info, stmt->symbols, &keyi)) {
1131*2b949d04SAndroid Build Coastguard Worker info->errorCount++;
1132*2b949d04SAndroid Build Coastguard Worker return false;
1133*2b949d04SAndroid Build Coastguard Worker }
1134*2b949d04SAndroid Build Coastguard Worker
1135*2b949d04SAndroid Build Coastguard Worker if (!SetExplicitGroup(info, &keyi)) {
1136*2b949d04SAndroid Build Coastguard Worker info->errorCount++;
1137*2b949d04SAndroid Build Coastguard Worker return false;
1138*2b949d04SAndroid Build Coastguard Worker }
1139*2b949d04SAndroid Build Coastguard Worker
1140*2b949d04SAndroid Build Coastguard Worker if (!AddKeySymbols(info, &keyi, true)) {
1141*2b949d04SAndroid Build Coastguard Worker info->errorCount++;
1142*2b949d04SAndroid Build Coastguard Worker return false;
1143*2b949d04SAndroid Build Coastguard Worker }
1144*2b949d04SAndroid Build Coastguard Worker
1145*2b949d04SAndroid Build Coastguard Worker return true;
1146*2b949d04SAndroid Build Coastguard Worker }
1147*2b949d04SAndroid Build Coastguard Worker
1148*2b949d04SAndroid Build Coastguard Worker static bool
HandleModMapDef(SymbolsInfo * info,ModMapDef * def)1149*2b949d04SAndroid Build Coastguard Worker HandleModMapDef(SymbolsInfo *info, ModMapDef *def)
1150*2b949d04SAndroid Build Coastguard Worker {
1151*2b949d04SAndroid Build Coastguard Worker ModMapEntry tmp;
1152*2b949d04SAndroid Build Coastguard Worker xkb_mod_index_t ndx;
1153*2b949d04SAndroid Build Coastguard Worker bool ok;
1154*2b949d04SAndroid Build Coastguard Worker struct xkb_context *ctx = info->ctx;
1155*2b949d04SAndroid Build Coastguard Worker
1156*2b949d04SAndroid Build Coastguard Worker ndx = XkbModNameToIndex(&info->mods, def->modifier, MOD_REAL);
1157*2b949d04SAndroid Build Coastguard Worker if (ndx == XKB_MOD_INVALID) {
1158*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
1159*2b949d04SAndroid Build Coastguard Worker "Illegal modifier map definition; "
1160*2b949d04SAndroid Build Coastguard Worker "Ignoring map for non-modifier \"%s\"\n",
1161*2b949d04SAndroid Build Coastguard Worker xkb_atom_text(ctx, def->modifier));
1162*2b949d04SAndroid Build Coastguard Worker return false;
1163*2b949d04SAndroid Build Coastguard Worker }
1164*2b949d04SAndroid Build Coastguard Worker
1165*2b949d04SAndroid Build Coastguard Worker ok = true;
1166*2b949d04SAndroid Build Coastguard Worker tmp.modifier = ndx;
1167*2b949d04SAndroid Build Coastguard Worker tmp.merge = def->merge;
1168*2b949d04SAndroid Build Coastguard Worker
1169*2b949d04SAndroid Build Coastguard Worker for (ExprDef *key = def->keys; key; key = (ExprDef *) key->common.next) {
1170*2b949d04SAndroid Build Coastguard Worker xkb_keysym_t sym;
1171*2b949d04SAndroid Build Coastguard Worker
1172*2b949d04SAndroid Build Coastguard Worker if (key->expr.op == EXPR_VALUE &&
1173*2b949d04SAndroid Build Coastguard Worker key->expr.value_type == EXPR_TYPE_KEYNAME) {
1174*2b949d04SAndroid Build Coastguard Worker tmp.haveSymbol = false;
1175*2b949d04SAndroid Build Coastguard Worker tmp.u.keyName = key->key_name.key_name;
1176*2b949d04SAndroid Build Coastguard Worker }
1177*2b949d04SAndroid Build Coastguard Worker else if (ExprResolveKeySym(ctx, key, &sym)) {
1178*2b949d04SAndroid Build Coastguard Worker tmp.haveSymbol = true;
1179*2b949d04SAndroid Build Coastguard Worker tmp.u.keySym = sym;
1180*2b949d04SAndroid Build Coastguard Worker }
1181*2b949d04SAndroid Build Coastguard Worker else {
1182*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
1183*2b949d04SAndroid Build Coastguard Worker "Modmap entries may contain only key names or keysyms; "
1184*2b949d04SAndroid Build Coastguard Worker "Illegal definition for %s modifier ignored\n",
1185*2b949d04SAndroid Build Coastguard Worker ModIndexText(info->ctx, &info->mods, tmp.modifier));
1186*2b949d04SAndroid Build Coastguard Worker continue;
1187*2b949d04SAndroid Build Coastguard Worker }
1188*2b949d04SAndroid Build Coastguard Worker
1189*2b949d04SAndroid Build Coastguard Worker ok = AddModMapEntry(info, &tmp) && ok;
1190*2b949d04SAndroid Build Coastguard Worker }
1191*2b949d04SAndroid Build Coastguard Worker return ok;
1192*2b949d04SAndroid Build Coastguard Worker }
1193*2b949d04SAndroid Build Coastguard Worker
1194*2b949d04SAndroid Build Coastguard Worker static void
HandleSymbolsFile(SymbolsInfo * info,XkbFile * file,enum merge_mode merge)1195*2b949d04SAndroid Build Coastguard Worker HandleSymbolsFile(SymbolsInfo *info, XkbFile *file, enum merge_mode merge)
1196*2b949d04SAndroid Build Coastguard Worker {
1197*2b949d04SAndroid Build Coastguard Worker bool ok;
1198*2b949d04SAndroid Build Coastguard Worker
1199*2b949d04SAndroid Build Coastguard Worker free(info->name);
1200*2b949d04SAndroid Build Coastguard Worker info->name = strdup_safe(file->name);
1201*2b949d04SAndroid Build Coastguard Worker
1202*2b949d04SAndroid Build Coastguard Worker for (ParseCommon *stmt = file->defs; stmt; stmt = stmt->next) {
1203*2b949d04SAndroid Build Coastguard Worker switch (stmt->type) {
1204*2b949d04SAndroid Build Coastguard Worker case STMT_INCLUDE:
1205*2b949d04SAndroid Build Coastguard Worker ok = HandleIncludeSymbols(info, (IncludeStmt *) stmt);
1206*2b949d04SAndroid Build Coastguard Worker break;
1207*2b949d04SAndroid Build Coastguard Worker case STMT_SYMBOLS:
1208*2b949d04SAndroid Build Coastguard Worker ok = HandleSymbolsDef(info, (SymbolsDef *) stmt);
1209*2b949d04SAndroid Build Coastguard Worker break;
1210*2b949d04SAndroid Build Coastguard Worker case STMT_VAR:
1211*2b949d04SAndroid Build Coastguard Worker ok = HandleGlobalVar(info, (VarDef *) stmt);
1212*2b949d04SAndroid Build Coastguard Worker break;
1213*2b949d04SAndroid Build Coastguard Worker case STMT_VMOD:
1214*2b949d04SAndroid Build Coastguard Worker ok = HandleVModDef(info->ctx, &info->mods, (VModDef *) stmt, merge);
1215*2b949d04SAndroid Build Coastguard Worker break;
1216*2b949d04SAndroid Build Coastguard Worker case STMT_MODMAP:
1217*2b949d04SAndroid Build Coastguard Worker ok = HandleModMapDef(info, (ModMapDef *) stmt);
1218*2b949d04SAndroid Build Coastguard Worker break;
1219*2b949d04SAndroid Build Coastguard Worker default:
1220*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx,
1221*2b949d04SAndroid Build Coastguard Worker "Symbols files may not include other types; "
1222*2b949d04SAndroid Build Coastguard Worker "Ignoring %s\n", stmt_type_to_string(stmt->type));
1223*2b949d04SAndroid Build Coastguard Worker ok = false;
1224*2b949d04SAndroid Build Coastguard Worker break;
1225*2b949d04SAndroid Build Coastguard Worker }
1226*2b949d04SAndroid Build Coastguard Worker
1227*2b949d04SAndroid Build Coastguard Worker if (!ok)
1228*2b949d04SAndroid Build Coastguard Worker info->errorCount++;
1229*2b949d04SAndroid Build Coastguard Worker
1230*2b949d04SAndroid Build Coastguard Worker if (info->errorCount > 10) {
1231*2b949d04SAndroid Build Coastguard Worker log_err(info->ctx, "Abandoning symbols file \"%s\"\n",
1232*2b949d04SAndroid Build Coastguard Worker file->name);
1233*2b949d04SAndroid Build Coastguard Worker break;
1234*2b949d04SAndroid Build Coastguard Worker }
1235*2b949d04SAndroid Build Coastguard Worker }
1236*2b949d04SAndroid Build Coastguard Worker }
1237*2b949d04SAndroid Build Coastguard Worker
1238*2b949d04SAndroid Build Coastguard Worker /**
1239*2b949d04SAndroid Build Coastguard Worker * Given a keysym @sym, return a key which generates it, or NULL.
1240*2b949d04SAndroid Build Coastguard Worker * This is used for example in a modifier map definition, such as:
1241*2b949d04SAndroid Build Coastguard Worker * modifier_map Lock { Caps_Lock };
1242*2b949d04SAndroid Build Coastguard Worker * where we want to add the Lock modifier to the modmap of the key
1243*2b949d04SAndroid Build Coastguard Worker * which matches the keysym Caps_Lock.
1244*2b949d04SAndroid Build Coastguard Worker * Since there can be many keys which generates the keysym, the key
1245*2b949d04SAndroid Build Coastguard Worker * is chosen first by lowest group in which the keysym appears, than
1246*2b949d04SAndroid Build Coastguard Worker * by lowest level and than by lowest key code.
1247*2b949d04SAndroid Build Coastguard Worker */
1248*2b949d04SAndroid Build Coastguard Worker static struct xkb_key *
FindKeyForSymbol(struct xkb_keymap * keymap,xkb_keysym_t sym)1249*2b949d04SAndroid Build Coastguard Worker FindKeyForSymbol(struct xkb_keymap *keymap, xkb_keysym_t sym)
1250*2b949d04SAndroid Build Coastguard Worker {
1251*2b949d04SAndroid Build Coastguard Worker struct xkb_key *key;
1252*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t group;
1253*2b949d04SAndroid Build Coastguard Worker bool got_one_group, got_one_level;
1254*2b949d04SAndroid Build Coastguard Worker
1255*2b949d04SAndroid Build Coastguard Worker group = 0;
1256*2b949d04SAndroid Build Coastguard Worker do {
1257*2b949d04SAndroid Build Coastguard Worker xkb_level_index_t level = 0;
1258*2b949d04SAndroid Build Coastguard Worker got_one_group = false;
1259*2b949d04SAndroid Build Coastguard Worker do {
1260*2b949d04SAndroid Build Coastguard Worker got_one_level = false;
1261*2b949d04SAndroid Build Coastguard Worker xkb_keys_foreach(key, keymap) {
1262*2b949d04SAndroid Build Coastguard Worker if (group < key->num_groups &&
1263*2b949d04SAndroid Build Coastguard Worker level < XkbKeyNumLevels(key, group)) {
1264*2b949d04SAndroid Build Coastguard Worker got_one_group = got_one_level = true;
1265*2b949d04SAndroid Build Coastguard Worker if (key->groups[group].levels[level].num_syms == 1 &&
1266*2b949d04SAndroid Build Coastguard Worker key->groups[group].levels[level].u.sym == sym)
1267*2b949d04SAndroid Build Coastguard Worker return key;
1268*2b949d04SAndroid Build Coastguard Worker }
1269*2b949d04SAndroid Build Coastguard Worker }
1270*2b949d04SAndroid Build Coastguard Worker level++;
1271*2b949d04SAndroid Build Coastguard Worker } while (got_one_level);
1272*2b949d04SAndroid Build Coastguard Worker group++;
1273*2b949d04SAndroid Build Coastguard Worker } while (got_one_group);
1274*2b949d04SAndroid Build Coastguard Worker
1275*2b949d04SAndroid Build Coastguard Worker return NULL;
1276*2b949d04SAndroid Build Coastguard Worker }
1277*2b949d04SAndroid Build Coastguard Worker
1278*2b949d04SAndroid Build Coastguard Worker /*
1279*2b949d04SAndroid Build Coastguard Worker * Find an appropriate type for a group and return its name.
1280*2b949d04SAndroid Build Coastguard Worker *
1281*2b949d04SAndroid Build Coastguard Worker * Simple recipe:
1282*2b949d04SAndroid Build Coastguard Worker * - ONE_LEVEL for width 0/1
1283*2b949d04SAndroid Build Coastguard Worker * - ALPHABETIC for 2 shift levels, with lower/upercase keysyms
1284*2b949d04SAndroid Build Coastguard Worker * - KEYPAD for keypad keys.
1285*2b949d04SAndroid Build Coastguard Worker * - TWO_LEVEL for other 2 shift level keys.
1286*2b949d04SAndroid Build Coastguard Worker * and the same for four level keys.
1287*2b949d04SAndroid Build Coastguard Worker *
1288*2b949d04SAndroid Build Coastguard Worker * FIXME: Decide how to handle multiple-syms-per-level, and do it.
1289*2b949d04SAndroid Build Coastguard Worker */
1290*2b949d04SAndroid Build Coastguard Worker static xkb_atom_t
FindAutomaticType(struct xkb_context * ctx,GroupInfo * groupi)1291*2b949d04SAndroid Build Coastguard Worker FindAutomaticType(struct xkb_context *ctx, GroupInfo *groupi)
1292*2b949d04SAndroid Build Coastguard Worker {
1293*2b949d04SAndroid Build Coastguard Worker xkb_keysym_t sym0, sym1;
1294*2b949d04SAndroid Build Coastguard Worker const xkb_level_index_t width = darray_size(groupi->levels);
1295*2b949d04SAndroid Build Coastguard Worker
1296*2b949d04SAndroid Build Coastguard Worker #define GET_SYM(level) \
1297*2b949d04SAndroid Build Coastguard Worker (darray_item(groupi->levels, level).num_syms == 0 ? \
1298*2b949d04SAndroid Build Coastguard Worker XKB_KEY_NoSymbol : \
1299*2b949d04SAndroid Build Coastguard Worker darray_item(groupi->levels, level).num_syms == 1 ? \
1300*2b949d04SAndroid Build Coastguard Worker darray_item(groupi->levels, level).u.sym : \
1301*2b949d04SAndroid Build Coastguard Worker /* num_syms > 1 */ \
1302*2b949d04SAndroid Build Coastguard Worker darray_item(groupi->levels, level).u.syms[0])
1303*2b949d04SAndroid Build Coastguard Worker
1304*2b949d04SAndroid Build Coastguard Worker if (width == 1 || width <= 0)
1305*2b949d04SAndroid Build Coastguard Worker return xkb_atom_intern_literal(ctx, "ONE_LEVEL");
1306*2b949d04SAndroid Build Coastguard Worker
1307*2b949d04SAndroid Build Coastguard Worker sym0 = GET_SYM(0);
1308*2b949d04SAndroid Build Coastguard Worker sym1 = GET_SYM(1);
1309*2b949d04SAndroid Build Coastguard Worker
1310*2b949d04SAndroid Build Coastguard Worker if (width == 2) {
1311*2b949d04SAndroid Build Coastguard Worker if (xkb_keysym_is_lower(sym0) && xkb_keysym_is_upper(sym1))
1312*2b949d04SAndroid Build Coastguard Worker return xkb_atom_intern_literal(ctx, "ALPHABETIC");
1313*2b949d04SAndroid Build Coastguard Worker
1314*2b949d04SAndroid Build Coastguard Worker if (xkb_keysym_is_keypad(sym0) || xkb_keysym_is_keypad(sym1))
1315*2b949d04SAndroid Build Coastguard Worker return xkb_atom_intern_literal(ctx, "KEYPAD");
1316*2b949d04SAndroid Build Coastguard Worker
1317*2b949d04SAndroid Build Coastguard Worker return xkb_atom_intern_literal(ctx, "TWO_LEVEL");
1318*2b949d04SAndroid Build Coastguard Worker }
1319*2b949d04SAndroid Build Coastguard Worker
1320*2b949d04SAndroid Build Coastguard Worker if (width <= 4) {
1321*2b949d04SAndroid Build Coastguard Worker if (xkb_keysym_is_lower(sym0) && xkb_keysym_is_upper(sym1)) {
1322*2b949d04SAndroid Build Coastguard Worker xkb_keysym_t sym2, sym3;
1323*2b949d04SAndroid Build Coastguard Worker sym2 = GET_SYM(2);
1324*2b949d04SAndroid Build Coastguard Worker sym3 = (width == 4 ? GET_SYM(3) : XKB_KEY_NoSymbol);
1325*2b949d04SAndroid Build Coastguard Worker
1326*2b949d04SAndroid Build Coastguard Worker if (xkb_keysym_is_lower(sym2) && xkb_keysym_is_upper(sym3))
1327*2b949d04SAndroid Build Coastguard Worker return xkb_atom_intern_literal(ctx, "FOUR_LEVEL_ALPHABETIC");
1328*2b949d04SAndroid Build Coastguard Worker
1329*2b949d04SAndroid Build Coastguard Worker return xkb_atom_intern_literal(ctx, "FOUR_LEVEL_SEMIALPHABETIC");
1330*2b949d04SAndroid Build Coastguard Worker }
1331*2b949d04SAndroid Build Coastguard Worker
1332*2b949d04SAndroid Build Coastguard Worker if (xkb_keysym_is_keypad(sym0) || xkb_keysym_is_keypad(sym1))
1333*2b949d04SAndroid Build Coastguard Worker return xkb_atom_intern_literal(ctx, "FOUR_LEVEL_KEYPAD");
1334*2b949d04SAndroid Build Coastguard Worker
1335*2b949d04SAndroid Build Coastguard Worker return xkb_atom_intern_literal(ctx, "FOUR_LEVEL");
1336*2b949d04SAndroid Build Coastguard Worker }
1337*2b949d04SAndroid Build Coastguard Worker
1338*2b949d04SAndroid Build Coastguard Worker return XKB_ATOM_NONE;
1339*2b949d04SAndroid Build Coastguard Worker
1340*2b949d04SAndroid Build Coastguard Worker #undef GET_SYM
1341*2b949d04SAndroid Build Coastguard Worker }
1342*2b949d04SAndroid Build Coastguard Worker
1343*2b949d04SAndroid Build Coastguard Worker static const struct xkb_key_type *
FindTypeForGroup(struct xkb_keymap * keymap,KeyInfo * keyi,xkb_layout_index_t group,bool * explicit_type)1344*2b949d04SAndroid Build Coastguard Worker FindTypeForGroup(struct xkb_keymap *keymap, KeyInfo *keyi,
1345*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t group, bool *explicit_type)
1346*2b949d04SAndroid Build Coastguard Worker {
1347*2b949d04SAndroid Build Coastguard Worker unsigned int i;
1348*2b949d04SAndroid Build Coastguard Worker GroupInfo *groupi = &darray_item(keyi->groups, group);
1349*2b949d04SAndroid Build Coastguard Worker xkb_atom_t type_name = groupi->type;
1350*2b949d04SAndroid Build Coastguard Worker
1351*2b949d04SAndroid Build Coastguard Worker *explicit_type = true;
1352*2b949d04SAndroid Build Coastguard Worker
1353*2b949d04SAndroid Build Coastguard Worker if (type_name == XKB_ATOM_NONE) {
1354*2b949d04SAndroid Build Coastguard Worker if (keyi->default_type != XKB_ATOM_NONE) {
1355*2b949d04SAndroid Build Coastguard Worker type_name = keyi->default_type;
1356*2b949d04SAndroid Build Coastguard Worker }
1357*2b949d04SAndroid Build Coastguard Worker else {
1358*2b949d04SAndroid Build Coastguard Worker type_name = FindAutomaticType(keymap->ctx, groupi);
1359*2b949d04SAndroid Build Coastguard Worker if (type_name != XKB_ATOM_NONE)
1360*2b949d04SAndroid Build Coastguard Worker *explicit_type = false;
1361*2b949d04SAndroid Build Coastguard Worker }
1362*2b949d04SAndroid Build Coastguard Worker }
1363*2b949d04SAndroid Build Coastguard Worker
1364*2b949d04SAndroid Build Coastguard Worker if (type_name == XKB_ATOM_NONE) {
1365*2b949d04SAndroid Build Coastguard Worker log_warn(keymap->ctx,
1366*2b949d04SAndroid Build Coastguard Worker "Couldn't find an automatic type for key '%s' group %d with %lu levels; "
1367*2b949d04SAndroid Build Coastguard Worker "Using the default type\n",
1368*2b949d04SAndroid Build Coastguard Worker KeyNameText(keymap->ctx, keyi->name), group + 1,
1369*2b949d04SAndroid Build Coastguard Worker (unsigned long) darray_size(groupi->levels));
1370*2b949d04SAndroid Build Coastguard Worker goto use_default;
1371*2b949d04SAndroid Build Coastguard Worker }
1372*2b949d04SAndroid Build Coastguard Worker
1373*2b949d04SAndroid Build Coastguard Worker for (i = 0; i < keymap->num_types; i++)
1374*2b949d04SAndroid Build Coastguard Worker if (keymap->types[i].name == type_name)
1375*2b949d04SAndroid Build Coastguard Worker break;
1376*2b949d04SAndroid Build Coastguard Worker
1377*2b949d04SAndroid Build Coastguard Worker if (i >= keymap->num_types) {
1378*2b949d04SAndroid Build Coastguard Worker log_warn(keymap->ctx,
1379*2b949d04SAndroid Build Coastguard Worker "The type \"%s\" for key '%s' group %d was not previously defined; "
1380*2b949d04SAndroid Build Coastguard Worker "Using the default type\n",
1381*2b949d04SAndroid Build Coastguard Worker xkb_atom_text(keymap->ctx, type_name),
1382*2b949d04SAndroid Build Coastguard Worker KeyNameText(keymap->ctx, keyi->name), group + 1);
1383*2b949d04SAndroid Build Coastguard Worker goto use_default;
1384*2b949d04SAndroid Build Coastguard Worker }
1385*2b949d04SAndroid Build Coastguard Worker
1386*2b949d04SAndroid Build Coastguard Worker return &keymap->types[i];
1387*2b949d04SAndroid Build Coastguard Worker
1388*2b949d04SAndroid Build Coastguard Worker use_default:
1389*2b949d04SAndroid Build Coastguard Worker /*
1390*2b949d04SAndroid Build Coastguard Worker * Index 0 is guaranteed to contain something, usually
1391*2b949d04SAndroid Build Coastguard Worker * ONE_LEVEL or at least some default one-level type.
1392*2b949d04SAndroid Build Coastguard Worker */
1393*2b949d04SAndroid Build Coastguard Worker return &keymap->types[0];
1394*2b949d04SAndroid Build Coastguard Worker }
1395*2b949d04SAndroid Build Coastguard Worker
1396*2b949d04SAndroid Build Coastguard Worker static bool
CopySymbolsDefToKeymap(struct xkb_keymap * keymap,SymbolsInfo * info,KeyInfo * keyi)1397*2b949d04SAndroid Build Coastguard Worker CopySymbolsDefToKeymap(struct xkb_keymap *keymap, SymbolsInfo *info,
1398*2b949d04SAndroid Build Coastguard Worker KeyInfo *keyi)
1399*2b949d04SAndroid Build Coastguard Worker {
1400*2b949d04SAndroid Build Coastguard Worker struct xkb_key *key;
1401*2b949d04SAndroid Build Coastguard Worker GroupInfo *groupi;
1402*2b949d04SAndroid Build Coastguard Worker const GroupInfo *group0;
1403*2b949d04SAndroid Build Coastguard Worker xkb_layout_index_t i;
1404*2b949d04SAndroid Build Coastguard Worker
1405*2b949d04SAndroid Build Coastguard Worker /*
1406*2b949d04SAndroid Build Coastguard Worker * The name is guaranteed to be real and not an alias (see
1407*2b949d04SAndroid Build Coastguard Worker * AddKeySymbols), so 'false' is safe here.
1408*2b949d04SAndroid Build Coastguard Worker */
1409*2b949d04SAndroid Build Coastguard Worker key = XkbKeyByName(keymap, keyi->name, false);
1410*2b949d04SAndroid Build Coastguard Worker if (!key) {
1411*2b949d04SAndroid Build Coastguard Worker log_vrb(info->ctx, 5,
1412*2b949d04SAndroid Build Coastguard Worker "Key %s not found in keycodes; Symbols ignored\n",
1413*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi));
1414*2b949d04SAndroid Build Coastguard Worker return false;
1415*2b949d04SAndroid Build Coastguard Worker }
1416*2b949d04SAndroid Build Coastguard Worker
1417*2b949d04SAndroid Build Coastguard Worker /* Find the range of groups we need. */
1418*2b949d04SAndroid Build Coastguard Worker key->num_groups = 0;
1419*2b949d04SAndroid Build Coastguard Worker darray_enumerate(i, groupi, keyi->groups)
1420*2b949d04SAndroid Build Coastguard Worker if (groupi->defined)
1421*2b949d04SAndroid Build Coastguard Worker key->num_groups = i + 1;
1422*2b949d04SAndroid Build Coastguard Worker
1423*2b949d04SAndroid Build Coastguard Worker if (key->num_groups <= 0)
1424*2b949d04SAndroid Build Coastguard Worker return false; /* WSGO */
1425*2b949d04SAndroid Build Coastguard Worker
1426*2b949d04SAndroid Build Coastguard Worker darray_resize(keyi->groups, key->num_groups);
1427*2b949d04SAndroid Build Coastguard Worker
1428*2b949d04SAndroid Build Coastguard Worker /*
1429*2b949d04SAndroid Build Coastguard Worker * If there are empty groups between non-empty ones, fill them with data
1430*2b949d04SAndroid Build Coastguard Worker * from the first group.
1431*2b949d04SAndroid Build Coastguard Worker * We can make a wrong assumption here. But leaving gaps is worse.
1432*2b949d04SAndroid Build Coastguard Worker */
1433*2b949d04SAndroid Build Coastguard Worker group0 = &darray_item(keyi->groups, 0);
1434*2b949d04SAndroid Build Coastguard Worker darray_foreach_from(groupi, keyi->groups, 1) {
1435*2b949d04SAndroid Build Coastguard Worker if (groupi->defined)
1436*2b949d04SAndroid Build Coastguard Worker continue;
1437*2b949d04SAndroid Build Coastguard Worker
1438*2b949d04SAndroid Build Coastguard Worker CopyGroupInfo(groupi, group0);
1439*2b949d04SAndroid Build Coastguard Worker }
1440*2b949d04SAndroid Build Coastguard Worker
1441*2b949d04SAndroid Build Coastguard Worker key->groups = calloc(key->num_groups, sizeof(*key->groups));
1442*2b949d04SAndroid Build Coastguard Worker
1443*2b949d04SAndroid Build Coastguard Worker /* Find and assign the groups' types in the keymap. */
1444*2b949d04SAndroid Build Coastguard Worker darray_enumerate(i, groupi, keyi->groups) {
1445*2b949d04SAndroid Build Coastguard Worker const struct xkb_key_type *type;
1446*2b949d04SAndroid Build Coastguard Worker bool explicit_type;
1447*2b949d04SAndroid Build Coastguard Worker
1448*2b949d04SAndroid Build Coastguard Worker type = FindTypeForGroup(keymap, keyi, i, &explicit_type);
1449*2b949d04SAndroid Build Coastguard Worker
1450*2b949d04SAndroid Build Coastguard Worker /* Always have as many levels as the type specifies. */
1451*2b949d04SAndroid Build Coastguard Worker if (type->num_levels < darray_size(groupi->levels)) {
1452*2b949d04SAndroid Build Coastguard Worker struct xkb_level *leveli;
1453*2b949d04SAndroid Build Coastguard Worker
1454*2b949d04SAndroid Build Coastguard Worker log_vrb(info->ctx, 1,
1455*2b949d04SAndroid Build Coastguard Worker "Type \"%s\" has %d levels, but %s has %d levels; "
1456*2b949d04SAndroid Build Coastguard Worker "Ignoring extra symbols\n",
1457*2b949d04SAndroid Build Coastguard Worker xkb_atom_text(keymap->ctx, type->name), type->num_levels,
1458*2b949d04SAndroid Build Coastguard Worker KeyInfoText(info, keyi),
1459*2b949d04SAndroid Build Coastguard Worker (int) darray_size(groupi->levels));
1460*2b949d04SAndroid Build Coastguard Worker
1461*2b949d04SAndroid Build Coastguard Worker darray_foreach_from(leveli, groupi->levels, type->num_levels)
1462*2b949d04SAndroid Build Coastguard Worker ClearLevelInfo(leveli);
1463*2b949d04SAndroid Build Coastguard Worker }
1464*2b949d04SAndroid Build Coastguard Worker darray_resize0(groupi->levels, type->num_levels);
1465*2b949d04SAndroid Build Coastguard Worker
1466*2b949d04SAndroid Build Coastguard Worker key->groups[i].explicit_type = explicit_type;
1467*2b949d04SAndroid Build Coastguard Worker key->groups[i].type = type;
1468*2b949d04SAndroid Build Coastguard Worker }
1469*2b949d04SAndroid Build Coastguard Worker
1470*2b949d04SAndroid Build Coastguard Worker /* Copy levels. */
1471*2b949d04SAndroid Build Coastguard Worker darray_enumerate(i, groupi, keyi->groups)
1472*2b949d04SAndroid Build Coastguard Worker darray_steal(groupi->levels, &key->groups[i].levels, NULL);
1473*2b949d04SAndroid Build Coastguard Worker
1474*2b949d04SAndroid Build Coastguard Worker key->out_of_range_group_number = keyi->out_of_range_group_number;
1475*2b949d04SAndroid Build Coastguard Worker key->out_of_range_group_action = keyi->out_of_range_group_action;
1476*2b949d04SAndroid Build Coastguard Worker
1477*2b949d04SAndroid Build Coastguard Worker if (keyi->defined & KEY_FIELD_VMODMAP) {
1478*2b949d04SAndroid Build Coastguard Worker key->vmodmap = keyi->vmodmap;
1479*2b949d04SAndroid Build Coastguard Worker key->explicit |= EXPLICIT_VMODMAP;
1480*2b949d04SAndroid Build Coastguard Worker }
1481*2b949d04SAndroid Build Coastguard Worker
1482*2b949d04SAndroid Build Coastguard Worker if (keyi->repeat != KEY_REPEAT_UNDEFINED) {
1483*2b949d04SAndroid Build Coastguard Worker key->repeats = (keyi->repeat == KEY_REPEAT_YES);
1484*2b949d04SAndroid Build Coastguard Worker key->explicit |= EXPLICIT_REPEAT;
1485*2b949d04SAndroid Build Coastguard Worker }
1486*2b949d04SAndroid Build Coastguard Worker
1487*2b949d04SAndroid Build Coastguard Worker darray_foreach(groupi, keyi->groups) {
1488*2b949d04SAndroid Build Coastguard Worker if (groupi->defined & GROUP_FIELD_ACTS) {
1489*2b949d04SAndroid Build Coastguard Worker key->explicit |= EXPLICIT_INTERP;
1490*2b949d04SAndroid Build Coastguard Worker break;
1491*2b949d04SAndroid Build Coastguard Worker }
1492*2b949d04SAndroid Build Coastguard Worker }
1493*2b949d04SAndroid Build Coastguard Worker
1494*2b949d04SAndroid Build Coastguard Worker return true;
1495*2b949d04SAndroid Build Coastguard Worker }
1496*2b949d04SAndroid Build Coastguard Worker
1497*2b949d04SAndroid Build Coastguard Worker static bool
CopyModMapDefToKeymap(struct xkb_keymap * keymap,SymbolsInfo * info,ModMapEntry * entry)1498*2b949d04SAndroid Build Coastguard Worker CopyModMapDefToKeymap(struct xkb_keymap *keymap, SymbolsInfo *info,
1499*2b949d04SAndroid Build Coastguard Worker ModMapEntry *entry)
1500*2b949d04SAndroid Build Coastguard Worker {
1501*2b949d04SAndroid Build Coastguard Worker struct xkb_key *key;
1502*2b949d04SAndroid Build Coastguard Worker
1503*2b949d04SAndroid Build Coastguard Worker if (!entry->haveSymbol) {
1504*2b949d04SAndroid Build Coastguard Worker key = XkbKeyByName(keymap, entry->u.keyName, true);
1505*2b949d04SAndroid Build Coastguard Worker if (!key) {
1506*2b949d04SAndroid Build Coastguard Worker log_vrb(info->ctx, 5,
1507*2b949d04SAndroid Build Coastguard Worker "Key %s not found in keycodes; "
1508*2b949d04SAndroid Build Coastguard Worker "Modifier map entry for %s not updated\n",
1509*2b949d04SAndroid Build Coastguard Worker KeyNameText(info->ctx, entry->u.keyName),
1510*2b949d04SAndroid Build Coastguard Worker ModIndexText(info->ctx, &info->mods, entry->modifier));
1511*2b949d04SAndroid Build Coastguard Worker return false;
1512*2b949d04SAndroid Build Coastguard Worker }
1513*2b949d04SAndroid Build Coastguard Worker }
1514*2b949d04SAndroid Build Coastguard Worker else {
1515*2b949d04SAndroid Build Coastguard Worker key = FindKeyForSymbol(keymap, entry->u.keySym);
1516*2b949d04SAndroid Build Coastguard Worker if (!key) {
1517*2b949d04SAndroid Build Coastguard Worker log_vrb(info->ctx, 5,
1518*2b949d04SAndroid Build Coastguard Worker "Key \"%s\" not found in symbol map; "
1519*2b949d04SAndroid Build Coastguard Worker "Modifier map entry for %s not updated\n",
1520*2b949d04SAndroid Build Coastguard Worker KeysymText(info->ctx, entry->u.keySym),
1521*2b949d04SAndroid Build Coastguard Worker ModIndexText(info->ctx, &info->mods, entry->modifier));
1522*2b949d04SAndroid Build Coastguard Worker return false;
1523*2b949d04SAndroid Build Coastguard Worker }
1524*2b949d04SAndroid Build Coastguard Worker }
1525*2b949d04SAndroid Build Coastguard Worker
1526*2b949d04SAndroid Build Coastguard Worker key->modmap |= (1u << entry->modifier);
1527*2b949d04SAndroid Build Coastguard Worker return true;
1528*2b949d04SAndroid Build Coastguard Worker }
1529*2b949d04SAndroid Build Coastguard Worker
1530*2b949d04SAndroid Build Coastguard Worker static bool
CopySymbolsToKeymap(struct xkb_keymap * keymap,SymbolsInfo * info)1531*2b949d04SAndroid Build Coastguard Worker CopySymbolsToKeymap(struct xkb_keymap *keymap, SymbolsInfo *info)
1532*2b949d04SAndroid Build Coastguard Worker {
1533*2b949d04SAndroid Build Coastguard Worker KeyInfo *keyi;
1534*2b949d04SAndroid Build Coastguard Worker ModMapEntry *mm;
1535*2b949d04SAndroid Build Coastguard Worker
1536*2b949d04SAndroid Build Coastguard Worker keymap->symbols_section_name = strdup_safe(info->name);
1537*2b949d04SAndroid Build Coastguard Worker XkbEscapeMapName(keymap->symbols_section_name);
1538*2b949d04SAndroid Build Coastguard Worker
1539*2b949d04SAndroid Build Coastguard Worker keymap->mods = info->mods;
1540*2b949d04SAndroid Build Coastguard Worker
1541*2b949d04SAndroid Build Coastguard Worker darray_steal(info->group_names,
1542*2b949d04SAndroid Build Coastguard Worker &keymap->group_names, &keymap->num_group_names);
1543*2b949d04SAndroid Build Coastguard Worker
1544*2b949d04SAndroid Build Coastguard Worker darray_foreach(keyi, info->keys)
1545*2b949d04SAndroid Build Coastguard Worker if (!CopySymbolsDefToKeymap(keymap, info, keyi))
1546*2b949d04SAndroid Build Coastguard Worker info->errorCount++;
1547*2b949d04SAndroid Build Coastguard Worker
1548*2b949d04SAndroid Build Coastguard Worker if (xkb_context_get_log_verbosity(keymap->ctx) > 3) {
1549*2b949d04SAndroid Build Coastguard Worker struct xkb_key *key;
1550*2b949d04SAndroid Build Coastguard Worker
1551*2b949d04SAndroid Build Coastguard Worker xkb_keys_foreach(key, keymap) {
1552*2b949d04SAndroid Build Coastguard Worker if (key->name == XKB_ATOM_NONE)
1553*2b949d04SAndroid Build Coastguard Worker continue;
1554*2b949d04SAndroid Build Coastguard Worker
1555*2b949d04SAndroid Build Coastguard Worker if (key->num_groups < 1)
1556*2b949d04SAndroid Build Coastguard Worker log_info(info->ctx,
1557*2b949d04SAndroid Build Coastguard Worker "No symbols defined for %s\n",
1558*2b949d04SAndroid Build Coastguard Worker KeyNameText(info->ctx, key->name));
1559*2b949d04SAndroid Build Coastguard Worker }
1560*2b949d04SAndroid Build Coastguard Worker }
1561*2b949d04SAndroid Build Coastguard Worker
1562*2b949d04SAndroid Build Coastguard Worker darray_foreach(mm, info->modmaps)
1563*2b949d04SAndroid Build Coastguard Worker if (!CopyModMapDefToKeymap(keymap, info, mm))
1564*2b949d04SAndroid Build Coastguard Worker info->errorCount++;
1565*2b949d04SAndroid Build Coastguard Worker
1566*2b949d04SAndroid Build Coastguard Worker /* XXX: If we don't ignore errorCount, things break. */
1567*2b949d04SAndroid Build Coastguard Worker return true;
1568*2b949d04SAndroid Build Coastguard Worker }
1569*2b949d04SAndroid Build Coastguard Worker
1570*2b949d04SAndroid Build Coastguard Worker bool
CompileSymbols(XkbFile * file,struct xkb_keymap * keymap,enum merge_mode merge)1571*2b949d04SAndroid Build Coastguard Worker CompileSymbols(XkbFile *file, struct xkb_keymap *keymap,
1572*2b949d04SAndroid Build Coastguard Worker enum merge_mode merge)
1573*2b949d04SAndroid Build Coastguard Worker {
1574*2b949d04SAndroid Build Coastguard Worker SymbolsInfo info;
1575*2b949d04SAndroid Build Coastguard Worker ActionsInfo *actions;
1576*2b949d04SAndroid Build Coastguard Worker
1577*2b949d04SAndroid Build Coastguard Worker actions = NewActionsInfo();
1578*2b949d04SAndroid Build Coastguard Worker if (!actions)
1579*2b949d04SAndroid Build Coastguard Worker return false;
1580*2b949d04SAndroid Build Coastguard Worker
1581*2b949d04SAndroid Build Coastguard Worker InitSymbolsInfo(&info, keymap, actions, &keymap->mods);
1582*2b949d04SAndroid Build Coastguard Worker info.default_key.merge = merge;
1583*2b949d04SAndroid Build Coastguard Worker
1584*2b949d04SAndroid Build Coastguard Worker HandleSymbolsFile(&info, file, merge);
1585*2b949d04SAndroid Build Coastguard Worker
1586*2b949d04SAndroid Build Coastguard Worker if (info.errorCount != 0)
1587*2b949d04SAndroid Build Coastguard Worker goto err_info;
1588*2b949d04SAndroid Build Coastguard Worker
1589*2b949d04SAndroid Build Coastguard Worker if (!CopySymbolsToKeymap(keymap, &info))
1590*2b949d04SAndroid Build Coastguard Worker goto err_info;
1591*2b949d04SAndroid Build Coastguard Worker
1592*2b949d04SAndroid Build Coastguard Worker ClearSymbolsInfo(&info);
1593*2b949d04SAndroid Build Coastguard Worker FreeActionsInfo(actions);
1594*2b949d04SAndroid Build Coastguard Worker return true;
1595*2b949d04SAndroid Build Coastguard Worker
1596*2b949d04SAndroid Build Coastguard Worker err_info:
1597*2b949d04SAndroid Build Coastguard Worker FreeActionsInfo(actions);
1598*2b949d04SAndroid Build Coastguard Worker ClearSymbolsInfo(&info);
1599*2b949d04SAndroid Build Coastguard Worker return false;
1600*2b949d04SAndroid Build Coastguard Worker }
1601