state: add GTK consumed modifiers mode
[platform/upstream/libxkbcommon.git] / test / state.c
1 /*
2  * Copyright © 2012 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Author: Daniel Stone <daniel@fooishbar.org>
24  */
25
26 #include <assert.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include "evdev-scancodes.h"
31 #include "test.h"
32
33 /* Offset between evdev keycodes (where KEY_ESCAPE is 1), and the evdev XKB
34  * keycode set (where ESC is 9). */
35 #define EVDEV_OFFSET 8
36
37 static void
38 print_state(struct xkb_state *state)
39 {
40     struct xkb_keymap *keymap;
41     xkb_layout_index_t group;
42     xkb_mod_index_t mod;
43     xkb_led_index_t led;
44
45     group = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_EFFECTIVE);
46     mod = xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE);
47     /* led = xkb_state_serialize_leds(state, XKB_STATE_LEDS); */
48     if (!group && !mod /* && !led */) {
49         fprintf(stderr, "\tno state\n");
50         return;
51     }
52
53     keymap = xkb_state_get_keymap(state);
54
55     for (group = 0; group < xkb_keymap_num_layouts(keymap); group++) {
56         if (xkb_state_layout_index_is_active(state, group,
57                                              XKB_STATE_LAYOUT_EFFECTIVE |
58                                              XKB_STATE_LAYOUT_DEPRESSED |
59                                              XKB_STATE_LAYOUT_LATCHED |
60                                              XKB_STATE_LAYOUT_LOCKED) <= 0)
61             continue;
62         fprintf(stderr, "\tgroup %s (%d): %s%s%s%s\n",
63                 xkb_keymap_layout_get_name(keymap, group),
64                 group,
65                 xkb_state_layout_index_is_active(state, group, XKB_STATE_LAYOUT_EFFECTIVE) > 0 ?
66                     "effective " : "",
67                 xkb_state_layout_index_is_active(state, group, XKB_STATE_LAYOUT_DEPRESSED) > 0 ?
68                     "depressed " : "",
69                 xkb_state_layout_index_is_active(state, group, XKB_STATE_LAYOUT_LATCHED) > 0 ?
70                     "latched " : "",
71                 xkb_state_layout_index_is_active(state, group, XKB_STATE_LAYOUT_LOCKED) > 0 ?
72                     "locked " : "");
73     }
74
75     for (mod = 0; mod < xkb_keymap_num_mods(keymap); mod++) {
76         if (xkb_state_mod_index_is_active(state, mod,
77                                           XKB_STATE_MODS_EFFECTIVE |
78                                           XKB_STATE_MODS_DEPRESSED |
79                                           XKB_STATE_MODS_LATCHED |
80                                           XKB_STATE_MODS_LOCKED) <= 0)
81             continue;
82         fprintf(stderr, "\tmod %s (%d): %s%s%s%s\n",
83                 xkb_keymap_mod_get_name(keymap, mod),
84                 mod,
85                 xkb_state_mod_index_is_active(state, mod, XKB_STATE_MODS_EFFECTIVE) > 0 ?
86                     "effective " : "",
87                 xkb_state_mod_index_is_active(state, mod, XKB_STATE_MODS_DEPRESSED) > 0 ?
88                     "depressed " : "",
89                 xkb_state_mod_index_is_active(state, mod, XKB_STATE_MODS_LATCHED) > 0 ?
90                     "latched " : "",
91                 xkb_state_mod_index_is_active(state, mod, XKB_STATE_MODS_LOCKED) > 0 ?
92                     "locked " : "");
93     }
94
95     for (led = 0; led < xkb_keymap_num_leds(keymap); led++) {
96         if (xkb_state_led_index_is_active(state, led) <= 0)
97             continue;
98         fprintf(stderr, "\tled %s (%d): active\n",
99                 xkb_keymap_led_get_name(keymap, led),
100                 led);
101     }
102 }
103
104 static void
105 test_update_key(struct xkb_keymap *keymap)
106 {
107     struct xkb_state *state = xkb_state_new(keymap);
108     const xkb_keysym_t *syms;
109     xkb_keysym_t one_sym;
110     int num_syms;
111
112     assert(state);
113
114     /* LCtrl down */
115     xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_DOWN);
116     fprintf(stderr, "dumping state for LCtrl down:\n");
117     print_state(state);
118     assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL,
119                                         XKB_STATE_MODS_DEPRESSED) > 0);
120
121     /* LCtrl + RAlt down */
122     xkb_state_update_key(state, KEY_RIGHTALT + EVDEV_OFFSET, XKB_KEY_DOWN);
123     fprintf(stderr, "dumping state for LCtrl + RAlt down:\n");
124     print_state(state);
125     assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL,
126                                         XKB_STATE_MODS_DEPRESSED) > 0);
127     assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT,
128                                         XKB_STATE_MODS_DEPRESSED) > 0);
129     assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
130                                           XKB_STATE_MATCH_ALL,
131                                           XKB_MOD_NAME_CTRL,
132                                           XKB_MOD_NAME_ALT,
133                                           NULL) > 0);
134     assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_DEPRESSED,
135                                             XKB_STATE_MATCH_ALL,
136                                             xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL),
137                                             xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT),
138                                             XKB_MOD_INVALID) > 0);
139     assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
140                                           XKB_STATE_MATCH_ALL,
141                                           XKB_MOD_NAME_ALT,
142                                           NULL) == 0);
143     assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
144                                           XKB_STATE_MATCH_ALL |
145                                           XKB_STATE_MATCH_NON_EXCLUSIVE,
146                                           XKB_MOD_NAME_ALT,
147                                           NULL) > 0);
148     assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
149                                           (XKB_STATE_MATCH_ANY |
150                                            XKB_STATE_MATCH_NON_EXCLUSIVE),
151                                           XKB_MOD_NAME_ALT,
152                                           NULL) > 0);
153
154     /* RAlt down */
155     xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_UP);
156     fprintf(stderr, "dumping state for RAlt down:\n");
157     print_state(state);
158     assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL,
159                                         XKB_STATE_MODS_EFFECTIVE) == 0);
160     assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT,
161                                         XKB_STATE_MODS_DEPRESSED) > 0);
162     assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
163                                           XKB_STATE_MATCH_ANY,
164                                           XKB_MOD_NAME_CTRL,
165                                           XKB_MOD_NAME_ALT,
166                                           NULL) > 0);
167     assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_LATCHED,
168                                           XKB_STATE_MATCH_ANY,
169                                           XKB_MOD_NAME_CTRL,
170                                           XKB_MOD_NAME_ALT,
171                                           NULL) == 0);
172
173     /* none down */
174     xkb_state_update_key(state, KEY_RIGHTALT + EVDEV_OFFSET, XKB_KEY_UP);
175     assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT,
176                                         XKB_STATE_MODS_EFFECTIVE) == 0);
177
178     /* Caps locked */
179     xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_DOWN);
180     assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CAPS,
181                                         XKB_STATE_MODS_DEPRESSED) > 0);
182     xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_UP);
183     fprintf(stderr, "dumping state for Caps Lock:\n");
184     print_state(state);
185     assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CAPS,
186                                         XKB_STATE_MODS_DEPRESSED) == 0);
187     assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CAPS,
188                                         XKB_STATE_MODS_LOCKED) > 0);
189     assert(xkb_state_led_name_is_active(state, XKB_LED_NAME_CAPS) > 0);
190     num_syms = xkb_state_key_get_syms(state, KEY_Q + EVDEV_OFFSET, &syms);
191     assert(num_syms == 1 && syms[0] == XKB_KEY_Q);
192
193     /* Num Lock locked */
194     xkb_state_update_key(state, KEY_NUMLOCK + EVDEV_OFFSET, XKB_KEY_DOWN);
195     xkb_state_update_key(state, KEY_NUMLOCK + EVDEV_OFFSET, XKB_KEY_UP);
196     fprintf(stderr, "dumping state for Caps Lock + Num Lock:\n");
197     print_state(state);
198     assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CAPS,
199                                         XKB_STATE_MODS_LOCKED) > 0);
200     assert(xkb_state_mod_name_is_active(state, "Mod2",
201                                         XKB_STATE_MODS_LOCKED) > 0);
202     num_syms = xkb_state_key_get_syms(state, KEY_KP1 + EVDEV_OFFSET, &syms);
203     assert(num_syms == 1 && syms[0] == XKB_KEY_KP_1);
204     assert(xkb_state_led_name_is_active(state, XKB_LED_NAME_NUM) > 0);
205
206     /* Num Lock unlocked */
207     xkb_state_update_key(state, KEY_NUMLOCK + EVDEV_OFFSET, XKB_KEY_DOWN);
208     xkb_state_update_key(state, KEY_NUMLOCK + EVDEV_OFFSET, XKB_KEY_UP);
209
210     /* Switch to group 2 */
211     xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_DOWN);
212     xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_UP);
213     assert(xkb_state_led_name_is_active(state, "Group 2") > 0);
214     assert(xkb_state_led_name_is_active(state, XKB_LED_NAME_NUM) == 0);
215
216     /* Switch back to group 1. */
217     xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_DOWN);
218     xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_UP);
219
220     /* Caps unlocked */
221     xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_DOWN);
222     xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_UP);
223     assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CAPS,
224                                         XKB_STATE_MODS_EFFECTIVE) == 0);
225     assert(xkb_state_led_name_is_active(state, XKB_LED_NAME_CAPS) == 0);
226     num_syms = xkb_state_key_get_syms(state, KEY_Q + EVDEV_OFFSET, &syms);
227     assert(num_syms == 1 && syms[0] == XKB_KEY_q);
228
229     /* Multiple symbols */
230     num_syms = xkb_state_key_get_syms(state, KEY_6 + EVDEV_OFFSET, &syms);
231     assert(num_syms == 5 &&
232            syms[0] == XKB_KEY_H && syms[1] == XKB_KEY_E &&
233            syms[2] == XKB_KEY_L && syms[3] == XKB_KEY_L &&
234            syms[4] == XKB_KEY_O);
235     one_sym = xkb_state_key_get_one_sym(state, KEY_6 + EVDEV_OFFSET);
236     assert(one_sym == XKB_KEY_NoSymbol);
237     xkb_state_update_key(state, KEY_6 + EVDEV_OFFSET, XKB_KEY_DOWN);
238     xkb_state_update_key(state, KEY_6 + EVDEV_OFFSET, XKB_KEY_UP);
239
240     one_sym = xkb_state_key_get_one_sym(state, KEY_5 + EVDEV_OFFSET);
241     assert(one_sym == XKB_KEY_5);
242
243     xkb_state_unref(state);
244 }
245
246 static void
247 test_serialisation(struct xkb_keymap *keymap)
248 {
249     struct xkb_state *state = xkb_state_new(keymap);
250     xkb_mod_mask_t base_mods;
251     xkb_mod_mask_t latched_mods;
252     xkb_mod_mask_t locked_mods;
253     xkb_mod_mask_t effective_mods;
254     xkb_mod_index_t caps, shift, ctrl;
255     xkb_layout_index_t base_group = 0;
256     xkb_layout_index_t latched_group = 0;
257     xkb_layout_index_t locked_group = 0;
258
259     assert(state);
260
261     caps = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS);
262     assert(caps != XKB_MOD_INVALID);
263     shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
264     assert(shift != XKB_MOD_INVALID);
265     ctrl = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL);
266     assert(ctrl != XKB_MOD_INVALID);
267
268     xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_DOWN);
269     xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_UP);
270     base_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED);
271     assert(base_mods == 0);
272     latched_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED);
273     assert(latched_mods == 0);
274     locked_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED);
275     assert(locked_mods == (1U << caps));
276     effective_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE);
277     assert(effective_mods == locked_mods);
278
279     xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN);
280     base_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED);
281     assert(base_mods == (1U << shift));
282     latched_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED);
283     assert(latched_mods == 0);
284     locked_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED);
285     assert(locked_mods == (1U << caps));
286     effective_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE);
287     assert(effective_mods == (base_mods | locked_mods));
288
289     base_mods |= (1U << ctrl);
290     xkb_state_update_mask(state, base_mods, latched_mods, locked_mods,
291                           base_group, latched_group, locked_group);
292
293     assert(xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_DEPRESSED) > 0);
294     assert(xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_EFFECTIVE) > 0);
295
296     xkb_state_unref(state);
297 }
298
299 static void
300 test_update_mask_mods(struct xkb_keymap *keymap)
301 {
302     struct xkb_state *state = xkb_state_new(keymap);
303     xkb_mod_index_t caps, shift, num, alt, mod1, mod2;
304     enum xkb_state_component changed;
305
306     assert(state);
307
308     caps = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS);
309     assert(caps != XKB_MOD_INVALID);
310     shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
311     assert(shift != XKB_MOD_INVALID);
312     num = xkb_keymap_mod_get_index(keymap, "NumLock");
313     assert(num != XKB_MOD_INVALID);
314     alt = xkb_keymap_mod_get_index(keymap, "Alt");
315     assert(alt != XKB_MOD_INVALID);
316     mod1 = xkb_keymap_mod_get_index(keymap, "Mod1");
317     assert(mod1 != XKB_MOD_INVALID);
318     mod2 = xkb_keymap_mod_get_index(keymap, "Mod2");
319     assert(mod2 != XKB_MOD_INVALID);
320
321     changed = xkb_state_update_mask(state, 1 << caps, 0, 0, 0, 0, 0);
322     assert(changed == (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_EFFECTIVE));
323     assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) ==
324            (1u << caps));
325
326     changed = xkb_state_update_mask(state, (1 << caps), 0, (1 << shift), 0, 0, 0);
327     assert(changed == (XKB_STATE_MODS_LOCKED | XKB_STATE_MODS_EFFECTIVE |
328                        XKB_STATE_LEDS));
329     assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) ==
330            ((1u << caps) | (1u << shift)));
331     assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED) ==
332            (1u << caps));
333     assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED) == 0);
334     assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED) ==
335            (1u << shift));
336
337     changed = xkb_state_update_mask(state, 0, 0, 0, 0, 0, 0);
338     assert(changed == (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LOCKED |
339                        XKB_STATE_MODS_EFFECTIVE | XKB_STATE_LEDS));
340     assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) == 0);
341
342     changed = xkb_state_update_mask(state, (1 << alt), 0, 0, 0, 0, 0);
343     assert(changed == (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_EFFECTIVE));
344     assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) ==
345            ((1u << alt) | (1u << mod1)));
346
347     changed = xkb_state_update_mask(state, 0, 0, (1 << num), 0, 0, 0);
348     assert(changed == (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LOCKED |
349                        XKB_STATE_MODS_EFFECTIVE | XKB_STATE_LEDS));
350     assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) ==
351            ((1u << num) | (1u << mod2)));
352
353     xkb_state_update_mask(state, 0, 0, 0, 0, 0, 0);
354
355     changed = xkb_state_update_mask(state, (1 << mod2), 0, (1 << num), 0, 0, 0);
356     assert(changed == (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LOCKED |
357                        XKB_STATE_MODS_EFFECTIVE | XKB_STATE_LEDS));
358     assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) ==
359            ((1u << mod2) | (1u << num)));
360     assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED) ==
361            (1u << mod2));
362     assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED) ==
363            ((1u << num) | (1u << mod2)));
364
365     xkb_state_unref(state);
366 }
367
368 static void
369 test_repeat(struct xkb_keymap *keymap)
370 {
371     assert(!xkb_keymap_key_repeats(keymap, KEY_LEFTSHIFT + 8));
372     assert(xkb_keymap_key_repeats(keymap, KEY_A + 8));
373     assert(xkb_keymap_key_repeats(keymap, KEY_8 + 8));
374     assert(xkb_keymap_key_repeats(keymap, KEY_DOWN + 8));
375     assert(xkb_keymap_key_repeats(keymap, KEY_KBDILLUMDOWN + 8));
376 }
377
378 static void
379 test_consume(struct xkb_keymap *keymap)
380 {
381     struct xkb_state *state;
382     xkb_mod_index_t alt, shift, caps, ctrl, mod5;
383     xkb_mod_mask_t mask;
384
385     state = xkb_state_new(keymap);
386     assert(state);
387
388     alt = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT);
389     assert(alt != XKB_MOD_INVALID);
390     shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
391     assert(shift != XKB_MOD_INVALID);
392     caps = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS);
393     assert(caps != XKB_MOD_INVALID);
394     ctrl = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL);
395     assert(ctrl != XKB_MOD_INVALID);
396     mod5 = xkb_keymap_mod_get_index(keymap, "Mod5");
397     assert(mod5 != XKB_MOD_INVALID);
398
399     /* Test remove_consumed() */
400     xkb_state_update_key(state, KEY_LEFTALT + EVDEV_OFFSET, XKB_KEY_DOWN);
401     xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN);
402     xkb_state_update_key(state, KEY_EQUAL + EVDEV_OFFSET, XKB_KEY_DOWN);
403
404     fprintf(stderr, "dumping state for Alt-Shift-+\n");
405     print_state(state);
406
407     mask = xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE);
408     assert(mask == ((1U << alt) | (1U << shift)));
409     mask = xkb_state_mod_mask_remove_consumed(state, KEY_EQUAL + EVDEV_OFFSET,
410                                               mask);
411     assert(mask == (1U << alt));
412
413     /* Test get_consumed_mods() */
414     mask = xkb_state_key_get_consumed_mods(state, KEY_EQUAL + EVDEV_OFFSET);
415     assert(mask == (1U << shift));
416
417     mask = xkb_state_key_get_consumed_mods(state, KEY_ESC + EVDEV_OFFSET);
418     assert(mask == 0);
419
420     xkb_state_unref(state);
421
422     /* Test is_consumed() - simple ALPHABETIC type. */
423     state = xkb_state_new(keymap);
424     assert(state);
425
426     mask = xkb_state_key_get_consumed_mods(state, KEY_A + EVDEV_OFFSET);
427     assert(mask == ((1U << shift) | (1U << caps)));
428
429     assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, caps) > 0);
430     assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, shift) > 0);
431     xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_DOWN);
432     xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_UP);
433     assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, caps) > 0);
434     assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, shift) > 0);
435     xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN);
436     assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, caps) > 0);
437     assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, shift) > 0);
438     xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_UP);
439     xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_DOWN);
440     xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_UP);
441     assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, caps) > 0);
442     assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, shift) > 0);
443
444     xkb_state_unref(state);
445
446     /* More complicated - CTRL+ALT */
447     state = xkb_state_new(keymap);
448     assert(state);
449
450     mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET);
451     assert(mask == ((1U << shift) | (1U << alt) | (1U << ctrl) | (1U << mod5)));
452
453     /* Shift is preserved. */
454     xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN);
455     mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET);
456     assert(mask == ((1U << alt) | (1U << ctrl) | (1U << mod5)));
457     xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_UP);
458
459     mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET);
460     assert(mask == ((1U << shift) | (1U << alt) | (1U << ctrl) | (1U << mod5)));
461
462     xkb_state_unref(state);
463
464     /* Test XKB_CONSUMED_MODE_GTK, CTRL+ALT */
465     state = xkb_state_new(keymap);
466     assert(state);
467
468     mask = xkb_state_key_get_consumed_mods2(state, KEY_F1 + EVDEV_OFFSET,
469                                             XKB_CONSUMED_MODE_GTK);
470     assert(mask == 0);
471
472     xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_DOWN);
473     mask = xkb_state_key_get_consumed_mods2(state, KEY_F1 + EVDEV_OFFSET,
474                                             XKB_CONSUMED_MODE_GTK);
475     assert(mask == 0);
476
477     xkb_state_update_key(state, KEY_LEFTALT + EVDEV_OFFSET, XKB_KEY_DOWN);
478     mask = xkb_state_key_get_consumed_mods2(state, KEY_F1 + EVDEV_OFFSET,
479                                             XKB_CONSUMED_MODE_GTK);
480     assert(mask == ((1U << alt) | (1U << ctrl)));
481
482     xkb_state_unref(state);
483
484     /* Test XKB_CONSUMED_MODE_GTK, Simple Shift */
485     state = xkb_state_new(keymap);
486     assert(state);
487
488     mask = xkb_state_key_get_consumed_mods2(state, KEY_A + EVDEV_OFFSET,
489                                             XKB_CONSUMED_MODE_GTK);
490     assert(mask == ((1U << shift) | (1U << caps)));
491
492     xkb_state_update_key(state, KEY_LEFTALT + EVDEV_OFFSET, XKB_KEY_DOWN);
493     mask = xkb_state_key_get_consumed_mods2(state, KEY_A + EVDEV_OFFSET,
494                                             XKB_CONSUMED_MODE_GTK);
495     assert(mask == ((1U << shift) | (1U << caps)));
496
497     xkb_state_unref(state);
498 }
499
500 static void
501 key_iter(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
502 {
503     xkb_keycode_t *counter = data;
504
505     assert(*counter == key);
506     (*counter)++;
507 }
508
509 static void
510 test_range(struct xkb_keymap *keymap)
511 {
512     xkb_keycode_t counter;
513
514     assert(xkb_keymap_min_keycode(keymap) == 9);
515     assert(xkb_keymap_max_keycode(keymap) == 253);
516
517     counter = xkb_keymap_min_keycode(keymap);
518     xkb_keymap_key_for_each(keymap, key_iter, &counter);
519     assert(counter == xkb_keymap_max_keycode(keymap) + 1);
520 }
521
522 static void
523 test_caps_keysym_transformation(struct xkb_keymap *keymap)
524 {
525     struct xkb_state *state = xkb_state_new(keymap);
526     xkb_mod_index_t caps, shift;
527     int nsyms;
528     xkb_keysym_t sym;
529     const xkb_keysym_t *syms;
530
531     assert(state);
532
533     /* See xkb_state_key_get_one_sym() for what's this all about. */
534
535     caps = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS);
536     shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
537     assert(caps != XKB_MOD_INVALID && shift != XKB_MOD_INVALID);
538
539     assert(xkb_state_key_get_layout(state, KEY_A + 8) == 0);
540     assert(xkb_state_key_get_layout(state, KEY_SEMICOLON + 8) == 0);
541
542     /* Without caps, no transformation. */
543     assert(xkb_state_mod_index_is_active(state, caps, XKB_STATE_MODS_EFFECTIVE) == 0);
544     assert(xkb_state_mod_index_is_active(state, shift, XKB_STATE_MODS_EFFECTIVE) == 0);
545     assert(xkb_state_key_get_level(state, KEY_A + 8, 0) == 0);
546     sym = xkb_state_key_get_one_sym(state, KEY_A + 8);
547     assert(sym == XKB_KEY_a);
548     assert(xkb_state_key_get_level(state, KEY_SEMICOLON + 8, 0) == 0);
549     sym = xkb_state_key_get_one_sym(state, KEY_SEMICOLON + 8);
550     assert(sym == XKB_KEY_eacute);
551     nsyms = xkb_state_key_get_syms(state, KEY_SEMICOLON + 8, &syms);
552     assert(nsyms == 1 && syms[0] == XKB_KEY_eacute);
553
554     /* With shift, no transformation (only different level). */
555     xkb_state_update_key(state, KEY_LEFTSHIFT + 8, XKB_KEY_DOWN);
556     assert(xkb_state_mod_index_is_active(state, caps, XKB_STATE_MODS_EFFECTIVE) == 0);
557     assert(xkb_state_mod_index_is_active(state, shift, XKB_STATE_MODS_EFFECTIVE) > 0);
558     assert(xkb_state_key_get_level(state, KEY_A + 8, 0) == 1);
559     sym = xkb_state_key_get_one_sym(state, KEY_A + 8);
560     assert(sym == XKB_KEY_A);
561     sym = xkb_state_key_get_one_sym(state, KEY_SEMICOLON + 8);
562     assert(sym == XKB_KEY_odiaeresis);
563     nsyms = xkb_state_key_get_syms(state, KEY_SEMICOLON + 8, &syms);
564     assert(nsyms == 1 && syms[0] == XKB_KEY_odiaeresis);
565     xkb_state_update_key(state, KEY_LEFTSHIFT + 8, XKB_KEY_UP);
566     assert(xkb_state_mod_index_is_active(state, shift, XKB_STATE_MODS_EFFECTIVE) == 0);
567
568     /* With caps, transform in same level, only with _get_one_sym(). */
569     xkb_state_update_key(state, KEY_CAPSLOCK + 8, XKB_KEY_DOWN);
570     xkb_state_update_key(state, KEY_CAPSLOCK + 8, XKB_KEY_UP);
571     assert(xkb_state_mod_index_is_active(state, caps, XKB_STATE_MODS_EFFECTIVE) > 0);
572     assert(xkb_state_mod_index_is_active(state, shift, XKB_STATE_MODS_EFFECTIVE) == 0);
573     assert(xkb_state_key_get_level(state, KEY_A + 8, 0) == 1);
574     sym = xkb_state_key_get_one_sym(state, KEY_A + 8);
575     assert(sym == XKB_KEY_A);
576     assert(xkb_state_key_get_level(state, KEY_SEMICOLON + 8, 0) == 0);
577     sym = xkb_state_key_get_one_sym(state, KEY_SEMICOLON + 8);
578     assert(sym == XKB_KEY_Eacute);
579     nsyms = xkb_state_key_get_syms(state, KEY_SEMICOLON + 8, &syms);
580     assert(nsyms == 1 && syms[0] == XKB_KEY_eacute);
581     xkb_state_update_key(state, KEY_LEFTSHIFT + 8, XKB_KEY_UP);
582     assert(xkb_state_mod_index_is_active(state, shift, XKB_STATE_MODS_EFFECTIVE) == 0);
583     xkb_state_update_key(state, KEY_CAPSLOCK + 8, XKB_KEY_DOWN);
584     xkb_state_update_key(state, KEY_CAPSLOCK + 8, XKB_KEY_UP);
585
586     xkb_state_unref(state);
587 }
588
589 static void
590 test_get_utf8_utf32(struct xkb_keymap *keymap)
591 {
592     char buf[256];
593     struct xkb_state *state = xkb_state_new(keymap);
594     assert(state);
595
596 #define TEST_KEY(key, expected_utf8, expected_utf32) do { \
597     assert(xkb_state_key_get_utf8(state, key + 8, NULL, 0) == strlen(expected_utf8)); \
598     assert(xkb_state_key_get_utf8(state, key + 8, buf, sizeof(buf)) == strlen(expected_utf8)); \
599     assert(memcmp(buf, expected_utf8, sizeof(expected_utf8)) == 0); \
600     assert(xkb_state_key_get_utf32(state, key + 8) == expected_utf32); \
601 } while (0)
602
603     /* Simple ASCII. */
604     TEST_KEY(KEY_A, "a", 0x61);
605     TEST_KEY(KEY_ESC, "\x1B", 0x1B);
606     TEST_KEY(KEY_1, "1", 0x31);
607
608     /* Invalid. */
609     TEST_KEY(XKB_KEYCODE_INVALID - 8, "", 0);
610     TEST_KEY(300, "", 0);
611
612     /* No string. */
613     TEST_KEY(KEY_LEFTCTRL, "", 0);
614     TEST_KEY(KEY_NUMLOCK, "", 0);
615
616     /* Multiple keysyms. */
617     TEST_KEY(KEY_6, "HELLO", 0);
618     TEST_KEY(KEY_7, "YES THIS IS DOG", 0);
619
620     /* Check truncation. */
621     memset(buf, 'X', sizeof(buf));
622     assert(xkb_state_key_get_utf8(state, KEY_6 + 8, buf, 0) == strlen("HELLO"));
623     assert(memcmp(buf, "X", 1) == 0);
624     assert(xkb_state_key_get_utf8(state, KEY_6 + 8, buf, 1) == strlen("HELLO"));
625     assert(memcmp(buf, "", 1) == 0);
626     assert(xkb_state_key_get_utf8(state, KEY_6 + 8, buf, 2) == strlen("HELLO"));
627     assert(memcmp(buf, "H", 2) == 0);
628     assert(xkb_state_key_get_utf8(state, KEY_6 + 8, buf, 3) == strlen("HELLO"));
629     assert(memcmp(buf, "HE", 3) == 0);
630     assert(xkb_state_key_get_utf8(state, KEY_6 + 8, buf, 5) == strlen("HELLO"));
631     assert(memcmp(buf, "HELL", 5) == 0);
632     assert(xkb_state_key_get_utf8(state, KEY_6 + 8, buf, 6) == strlen("HELLO"));
633     assert(memcmp(buf, "HELLO", 6) == 0);
634     assert(xkb_state_key_get_utf8(state, KEY_6 + 8, buf, 7) == strlen("HELLO"));
635     assert(memcmp(buf, "HELLO\0X", 7) == 0);
636
637     /* Switch to ru layout */
638     xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_DOWN);
639     xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_UP);
640     assert(xkb_state_key_get_layout(state, KEY_A + 8) == 1);
641
642     /* Non ASCII. */
643     TEST_KEY(KEY_ESC, "\x1B", 0x1B);
644     TEST_KEY(KEY_A, "ф", 0x0444);
645     TEST_KEY(KEY_Z, "я", 0x044F);
646
647     /* Switch back to us layout */
648     xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_DOWN);
649     xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_UP);
650     assert(xkb_state_key_get_layout(state, KEY_A + 8) == 0);
651
652     xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN);
653     TEST_KEY(KEY_A, "A", 0x41);
654     TEST_KEY(KEY_ESC, "\x1B", 0x1B);
655     TEST_KEY(KEY_1, "!", 0x21);
656     xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_UP);
657
658     TEST_KEY(KEY_6, "HELLO", 0);
659     TEST_KEY(KEY_7, "YES THIS IS DOG", 0);
660
661     xkb_state_unref(state);
662 }
663
664 static void
665 test_ctrl_string_transformation(struct xkb_keymap *keymap)
666 {
667     char buf[256];
668     struct xkb_state *state = xkb_state_new(keymap);
669     xkb_mod_index_t ctrl;
670
671     assert(state);
672
673     /* See xkb_state_key_get_utf8() for what's this all about. */
674
675     ctrl = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL);
676     assert(ctrl != XKB_MOD_INVALID);
677
678     /* First without. */
679     TEST_KEY(KEY_A, "a", 0x61);
680     TEST_KEY(KEY_B, "b", 0x62);
681     TEST_KEY(KEY_C, "c", 0x63);
682     TEST_KEY(KEY_ESC, "\x1B", 0x1B);
683     TEST_KEY(KEY_1, "1", 0x31);
684
685     /* And with. */
686     xkb_state_update_key(state, KEY_RIGHTCTRL + EVDEV_OFFSET, XKB_KEY_DOWN);
687     assert(xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_EFFECTIVE) > 0);
688     TEST_KEY(KEY_A, "\x01", 0x01);
689     TEST_KEY(KEY_B, "\x02", 0x02);
690     TEST_KEY(KEY_C, "\x03", 0x03);
691     TEST_KEY(KEY_ESC, "\x1B", 0x1B);
692     TEST_KEY(KEY_1, "1", 0x31);
693     xkb_state_update_key(state, KEY_RIGHTCTRL + EVDEV_OFFSET, XKB_KEY_UP);
694
695     /* Switch to ru layout */
696     xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_DOWN);
697     xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_UP);
698     assert(xkb_state_key_get_layout(state, KEY_A + 8) == 1);
699
700     /* Non ASCII. */
701     xkb_state_update_key(state, KEY_RIGHTCTRL + EVDEV_OFFSET, XKB_KEY_DOWN);
702     assert(xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_EFFECTIVE) > 0);
703     TEST_KEY(KEY_A, "\x01", 0x01);
704     TEST_KEY(KEY_B, "\x02", 0x02);
705     xkb_state_update_key(state, KEY_RIGHTCTRL + EVDEV_OFFSET, XKB_KEY_UP);
706
707     xkb_state_unref(state);
708 }
709
710 int
711 main(void)
712 {
713     struct xkb_context *context = test_get_context(0);
714     struct xkb_keymap *keymap;
715
716     assert(context);
717
718     /* Make sure these are allowed. */
719     xkb_context_unref(NULL);
720     xkb_keymap_unref(NULL);
721     xkb_state_unref(NULL);
722
723     keymap = test_compile_rules(context, "evdev", "pc104", "us,ru", NULL, "grp:menu_toggle");
724     assert(keymap);
725
726     test_update_key(keymap);
727     test_serialisation(keymap);
728     test_update_mask_mods(keymap);
729     test_repeat(keymap);
730     test_consume(keymap);
731     test_range(keymap);
732     test_get_utf8_utf32(keymap);
733     test_ctrl_string_transformation(keymap);
734
735     xkb_keymap_unref(keymap);
736     keymap = test_compile_rules(context, "evdev", NULL, "ch", "fr", NULL);
737     assert(keymap);
738
739     test_caps_keysym_transformation(keymap);
740
741     xkb_keymap_unref(keymap);
742     xkb_context_unref(context);
743 }