1/************************************************************
2 * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3 *
4 * Permission to use, copy, modify, and distribute this
5 * software and its documentation for any purpose and without
6 * fee is hereby granted, provided that the above copyright
7 * notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting
9 * documentation, and that the name of Silicon Graphics not be
10 * used in advertising or publicity pertaining to distribution
11 * of the software without specific prior written permission.
12 * Silicon Graphics makes no representation about the suitability
13 * of this software for any purpose. It is provided "as is"
14 * without any express or implied warranty.
15 *
16 * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23 * THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 *
25 ********************************************************/
26
27#include "keymap.h"
28#include "text.h"
29
30bool
31LookupString(const LookupEntry tab[], const char *string,
32              unsigned int *value_rtrn)
33{
34    if (!string)
35        return false;
36
37    for (const LookupEntry *entry = tab; entry->name; entry++) {
38        if (istreq(entry->name, string)) {
39            *value_rtrn = entry->value;
40            return true;
41        }
42    }
43
44    return false;
45}
46
47const char *
48LookupValue(const LookupEntry tab[], unsigned int value)
49{
50    for (const LookupEntry *entry = tab; entry->name; entry++)
51        if (entry->value == value)
52            return entry->name;
53
54    return NULL;
55}
56
57const LookupEntry ctrlMaskNames[] = {
58    { "RepeatKeys", CONTROL_REPEAT },
59    { "Repeat", CONTROL_REPEAT },
60    { "AutoRepeat", CONTROL_REPEAT },
61    { "SlowKeys", CONTROL_SLOW },
62    { "BounceKeys", CONTROL_DEBOUNCE },
63    { "StickyKeys", CONTROL_STICKY },
64    { "MouseKeys", CONTROL_MOUSEKEYS },
65    { "MouseKeysAccel", CONTROL_MOUSEKEYS_ACCEL },
66    { "AccessXKeys", CONTROL_AX },
67    { "AccessXTimeout", CONTROL_AX_TIMEOUT },
68    { "AccessXFeedback", CONTROL_AX_FEEDBACK },
69    { "AudibleBell", CONTROL_BELL },
70    { "IgnoreGroupLock", CONTROL_IGNORE_GROUP_LOCK },
71    { "all", CONTROL_ALL },
72    { "none", 0 },
73    { "Overlay1", 0 },
74    { "Overlay2", 0 },
75    { NULL, 0 }
76};
77
78const LookupEntry modComponentMaskNames[] = {
79    { "base", XKB_STATE_MODS_DEPRESSED },
80    { "latched", XKB_STATE_MODS_LATCHED },
81    { "locked", XKB_STATE_MODS_LOCKED },
82    { "effective", XKB_STATE_MODS_EFFECTIVE },
83    { "compat", XKB_STATE_MODS_EFFECTIVE },
84    { "any", XKB_STATE_MODS_EFFECTIVE },
85    { "none", 0 },
86    { NULL, 0 }
87};
88
89const LookupEntry groupComponentMaskNames[] = {
90    { "base", XKB_STATE_LAYOUT_DEPRESSED },
91    { "latched", XKB_STATE_LAYOUT_LATCHED },
92    { "locked", XKB_STATE_LAYOUT_LOCKED },
93    { "effective", XKB_STATE_LAYOUT_EFFECTIVE },
94    { "any", XKB_STATE_LAYOUT_EFFECTIVE },
95    { "none", 0 },
96    { NULL, 0 }
97};
98
99const LookupEntry groupMaskNames[] = {
100    { "Group1", 0x01 },
101    { "Group2", 0x02 },
102    { "Group3", 0x04 },
103    { "Group4", 0x08 },
104    { "Group5", 0x10 },
105    { "Group6", 0x20 },
106    { "Group7", 0x40 },
107    { "Group8", 0x80 },
108    { "none", 0x00 },
109    { "all", 0xff },
110    { NULL, 0 }
111};
112
113const LookupEntry groupNames[] = {
114    { "Group1", 1 },
115    { "Group2", 2 },
116    { "Group3", 3 },
117    { "Group4", 4 },
118    { "Group5", 5 },
119    { "Group6", 6 },
120    { "Group7", 7 },
121    { "Group8", 8 },
122    { NULL, 0 }
123};
124
125const LookupEntry levelNames[] = {
126    { "Level1", 1 },
127    { "Level2", 2 },
128    { "Level3", 3 },
129    { "Level4", 4 },
130    { "Level5", 5 },
131    { "Level6", 6 },
132    { "Level7", 7 },
133    { "Level8", 8 },
134    { NULL, 0 }
135};
136
137const LookupEntry buttonNames[] = {
138    { "Button1", 1 },
139    { "Button2", 2 },
140    { "Button3", 3 },
141    { "Button4", 4 },
142    { "Button5", 5 },
143    { "default", 0 },
144    { NULL, 0 }
145};
146
147const LookupEntry useModMapValueNames[] = {
148    { "LevelOne", 1 },
149    { "Level1", 1 },
150    { "AnyLevel", 0 },
151    { "any", 0 },
152    { NULL, 0 }
153};
154
155const LookupEntry actionTypeNames[] = {
156    { "NoAction", ACTION_TYPE_NONE },
157    { "SetMods", ACTION_TYPE_MOD_SET },
158    { "LatchMods", ACTION_TYPE_MOD_LATCH },
159    { "LockMods", ACTION_TYPE_MOD_LOCK },
160    { "SetGroup", ACTION_TYPE_GROUP_SET },
161    { "LatchGroup", ACTION_TYPE_GROUP_LATCH },
162    { "LockGroup", ACTION_TYPE_GROUP_LOCK },
163    { "MovePtr", ACTION_TYPE_PTR_MOVE },
164    { "MovePointer", ACTION_TYPE_PTR_MOVE },
165    { "PtrBtn", ACTION_TYPE_PTR_BUTTON },
166    { "PointerButton", ACTION_TYPE_PTR_BUTTON },
167    { "LockPtrBtn", ACTION_TYPE_PTR_LOCK },
168    { "LockPtrButton", ACTION_TYPE_PTR_LOCK },
169    { "LockPointerButton", ACTION_TYPE_PTR_LOCK },
170    { "LockPointerBtn", ACTION_TYPE_PTR_LOCK },
171    { "SetPtrDflt", ACTION_TYPE_PTR_DEFAULT },
172    { "SetPointerDefault", ACTION_TYPE_PTR_DEFAULT },
173    { "Terminate", ACTION_TYPE_TERMINATE },
174    { "TerminateServer", ACTION_TYPE_TERMINATE },
175    { "SwitchScreen", ACTION_TYPE_SWITCH_VT },
176    { "SetControls", ACTION_TYPE_CTRL_SET },
177    { "LockControls", ACTION_TYPE_CTRL_LOCK },
178    { "Private", ACTION_TYPE_PRIVATE },
179    /* deprecated actions below here - unused */
180    { "RedirectKey", ACTION_TYPE_NONE },
181    { "Redirect", ACTION_TYPE_NONE },
182    { "ISOLock", ACTION_TYPE_NONE },
183    { "ActionMessage", ACTION_TYPE_NONE },
184    { "MessageAction", ACTION_TYPE_NONE },
185    { "Message", ACTION_TYPE_NONE },
186    { "DeviceBtn", ACTION_TYPE_NONE },
187    { "DevBtn", ACTION_TYPE_NONE },
188    { "DevButton", ACTION_TYPE_NONE },
189    { "DeviceButton", ACTION_TYPE_NONE },
190    { "LockDeviceBtn", ACTION_TYPE_NONE },
191    { "LockDevBtn", ACTION_TYPE_NONE },
192    { "LockDevButton", ACTION_TYPE_NONE },
193    { "LockDeviceButton", ACTION_TYPE_NONE },
194    { "DeviceValuator", ACTION_TYPE_NONE },
195    { "DevVal", ACTION_TYPE_NONE },
196    { "DeviceVal", ACTION_TYPE_NONE },
197    { "DevValuator", ACTION_TYPE_NONE },
198    { NULL, 0 },
199};
200
201const LookupEntry symInterpretMatchMaskNames[] = {
202    { "NoneOf", MATCH_NONE },
203    { "AnyOfOrNone", MATCH_ANY_OR_NONE },
204    { "AnyOf", MATCH_ANY },
205    { "AllOf", MATCH_ALL },
206    { "Exactly", MATCH_EXACTLY },
207};
208
209const char *
210ModIndexText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
211             xkb_mod_index_t ndx)
212{
213    if (ndx == XKB_MOD_INVALID)
214        return "none";
215
216    if (ndx >= mods->num_mods)
217        return NULL;
218
219    return xkb_atom_text(ctx, mods->mods[ndx].name);
220}
221
222const char *
223ActionTypeText(enum xkb_action_type type)
224{
225    const char *name = LookupValue(actionTypeNames, type);
226    return name ? name : "Private";
227}
228
229const char *
230KeysymText(struct xkb_context *ctx, xkb_keysym_t sym)
231{
232    char *buffer = xkb_context_get_buffer(ctx, 64);
233    xkb_keysym_get_name(sym, buffer, 64);
234    return buffer;
235}
236
237const char *
238KeyNameText(struct xkb_context *ctx, xkb_atom_t name)
239{
240    const char *sname = xkb_atom_text(ctx, name);
241    size_t len = strlen_safe(sname) + 3;
242    char *buf = xkb_context_get_buffer(ctx, len);
243    snprintf(buf, len, "<%s>", strempty(sname));
244    return buf;
245}
246
247const char *
248SIMatchText(enum xkb_match_operation type)
249{
250    return LookupValue(symInterpretMatchMaskNames, type);
251}
252
253const char *
254ModMaskText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
255            xkb_mod_mask_t mask)
256{
257    char buf[1024];
258    size_t pos = 0;
259    xkb_mod_index_t i;
260    const struct xkb_mod *mod;
261
262    if (mask == 0)
263        return "none";
264
265    if (mask == MOD_REAL_MASK_ALL)
266        return "all";
267
268    xkb_mods_enumerate(i, mod, mods) {
269        int ret;
270
271        if (!(mask & (1u << i)))
272            continue;
273
274        ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s",
275                       pos == 0 ? "" : "+",
276                       xkb_atom_text(ctx, mod->name));
277        if (ret <= 0 || pos + ret >= sizeof(buf))
278            break;
279        else
280            pos += ret;
281    }
282
283    return strcpy(xkb_context_get_buffer(ctx, pos + 1), buf);
284}
285
286const char *
287LedStateMaskText(struct xkb_context *ctx, enum xkb_state_component mask)
288{
289    char buf[1024];
290    size_t pos = 0;
291
292    if (mask == 0)
293        return "0";
294
295    for (unsigned i = 0; mask; i++) {
296        int ret;
297
298        if (!(mask & (1u << i)))
299            continue;
300
301        mask &= ~(1u << i);
302
303        ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s",
304                       pos == 0 ? "" : "+",
305                       LookupValue(modComponentMaskNames, 1u << i));
306        if (ret <= 0 || pos + ret >= sizeof(buf))
307            break;
308        else
309            pos += ret;
310    }
311
312    return strcpy(xkb_context_get_buffer(ctx, pos + 1), buf);
313}
314
315const char *
316ControlMaskText(struct xkb_context *ctx, enum xkb_action_controls mask)
317{
318    char buf[1024];
319    size_t pos = 0;
320
321    if (mask == 0)
322        return "none";
323
324    if (mask == CONTROL_ALL)
325        return "all";
326
327    for (unsigned i = 0; mask; i++) {
328        int ret;
329
330        if (!(mask & (1u << i)))
331            continue;
332
333        mask &= ~(1u << i);
334
335        ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s",
336                       pos == 0 ? "" : "+",
337                       LookupValue(ctrlMaskNames, 1u << i));
338        if (ret <= 0 || pos + ret >= sizeof(buf))
339            break;
340        else
341            pos += ret;
342    }
343
344    return strcpy(xkb_context_get_buffer(ctx, pos + 1), buf);
345}
346