symbols: remove support for key behaviors
[platform/upstream/libxkbcommon.git] / test / interactive.c
1 /*
2  * Copyright © 2012 Ran Benita <ran234@gmail.com>
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
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <fnmatch.h>
28 #include <limits.h>
29 #include <locale.h>
30 #include <signal.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sysexits.h>
36 #include <unistd.h>
37
38 #include <sys/epoll.h>
39 #include <linux/input.h>
40
41 #include "xkbcommon/xkbcommon.h"
42
43 struct keyboard {
44     char *path;
45     int fd;
46     struct xkb_state *state;
47     struct keyboard *next;
48 };
49
50 bool terminate;
51
52 #define NLONGS(n) (((n) + LONG_BIT - 1) / LONG_BIT)
53
54 static bool
55 evdev_bit_is_set(const unsigned long *array, int bit)
56 {
57     return !!(array[bit / LONG_BIT] & (1LL << (bit % LONG_BIT)));
58 }
59
60 /* Some heuristics to see if the device is a keyboard. */
61 static bool
62 is_keyboard(int fd)
63 {
64     int i;
65     unsigned long evbits[NLONGS(EV_CNT)] = { 0 };
66     unsigned long keybits[NLONGS(KEY_CNT)] = { 0 };
67
68     errno = 0;
69     ioctl(fd, EVIOCGBIT(0, sizeof(evbits)), evbits);
70     if (errno)
71         return false;
72
73     if (!evdev_bit_is_set(evbits, EV_KEY))
74         return false;
75
76     errno = 0;
77     ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits);
78     if (errno)
79         return false;
80
81     for (i = KEY_RESERVED; i <= KEY_MIN_INTERESTING; i++)
82         if (evdev_bit_is_set(keybits, i))
83             return true;
84
85     return false;
86 }
87
88 static int
89 keyboard_new(struct dirent *ent, struct xkb_keymap *xkb, struct keyboard **out)
90 {
91     int ret;
92     char *path;
93     int fd;
94     struct xkb_state *state;
95     struct keyboard *kbd;
96
97     ret = asprintf(&path, "/dev/input/%s", ent->d_name);
98     if (ret < 0)
99         return -ENOMEM;
100
101     fd = open(path, O_NONBLOCK | O_CLOEXEC | O_RDONLY);
102     if (fd < 0) {
103         ret = -errno;
104         goto err_path;
105     }
106
107     if (!is_keyboard(fd)) {
108         /* Dummy "skip this device" value. */
109         ret = -ENOTSUP;
110         goto err_fd;
111     }
112
113     state = xkb_state_new(xkb);
114     if (!state) {
115         fprintf(stderr, "Couldn't create xkb state for %s\n", path);
116         ret = -EFAULT;
117         goto err_fd;
118     }
119
120     kbd = calloc(1, sizeof(*kbd));
121     if (!kbd) {
122         ret = -ENOMEM;
123         goto err_state;
124     }
125
126     kbd->path = path;
127     kbd->fd = fd;
128     kbd->state = state;
129     *out = kbd;
130     return 0;
131
132 err_state:
133     xkb_state_unref(state);
134 err_fd:
135     close(fd);
136 err_path:
137     free(path);
138     return ret;
139 }
140
141 static void
142 keyboard_free(struct keyboard *kbd)
143 {
144     if (!kbd)
145         return;
146     if (kbd->fd >= 0)
147         close(kbd->fd);
148     free(kbd->path);
149     xkb_state_unref(kbd->state);
150     free(kbd);
151 }
152
153 static int
154 filter_device_name(const struct dirent *ent)
155 {
156     return !fnmatch("event*", ent->d_name, 0);
157 }
158
159 static struct keyboard *
160 get_keyboards(struct xkb_keymap *keymap)
161 {
162     int ret, i, nents;
163     struct dirent **ents;
164     struct keyboard *kbds = NULL, *kbd = NULL;
165
166     nents = scandir("/dev/input", &ents, filter_device_name, alphasort);
167     if (nents < 0) {
168         fprintf(stderr, "Couldn't scan /dev/input: %s\n", strerror(errno));
169         return NULL;
170     }
171
172     for (i = 0; i < nents; i++) {
173         ret = keyboard_new(ents[i], keymap, &kbd);
174         if (ret) {
175             if (ret == -EACCES) {
176                 fprintf(stderr, "Couldn't open /dev/input/%s: %s. "
177                                 "You probably need root to run this.\n",
178                         ents[i]->d_name, strerror(-ret));
179                 break;
180             }
181             if (ret != -ENOTSUP) {
182                 fprintf(stderr, "Couldn't open /dev/input/%s: %s. Skipping.\n",
183                         ents[i]->d_name, strerror(-ret));
184             }
185             continue;
186         }
187
188         kbd->next = kbds;
189         kbds = kbd;
190     }
191
192     if (!kbds) {
193         fprintf(stderr, "Couldn't find any keyboards I can use! Quitting.\n");
194         goto err;
195     }
196
197 err:
198     for (i = 0; i < nents; i++)
199         free(ents[i]);
200     free(ents);
201     return kbds;
202 }
203
204 static void
205 free_keyboards(struct keyboard *kbds)
206 {
207     struct keyboard *next;
208
209     while (kbds) {
210         next = kbds->next;
211         keyboard_free(kbds);
212         kbds = next;
213     }
214 }
215
216 static void
217 print_keycode(struct keyboard *kbd, xkb_keycode_t keycode)
218 {
219     unsigned int i;
220     struct xkb_keymap *keymap;
221     struct xkb_state *state;
222
223     const xkb_keysym_t *syms;
224     unsigned int nsyms;
225     char s[16];
226     uint32_t unicode;
227     xkb_group_index_t group;
228     xkb_mod_index_t mod;
229     xkb_led_index_t led;
230
231     state = kbd->state;
232     keymap = xkb_state_get_map(state);
233
234     nsyms = xkb_key_get_syms(state, keycode, &syms);
235
236     if (nsyms <= 0)
237         return;
238
239     printf("keysyms [ ");
240     for (i = 0; i < nsyms; i++) {
241         xkb_keysym_get_name(syms[i], s, sizeof(s));
242         printf("%-*s ", (int)sizeof(s), s);
243     }
244     printf("] ");
245
246     /*
247      * Only do this if wchar_t is UCS-4, so we can be lazy and print
248      * with %lc.
249      */
250 #ifdef __STDC_ISO_10646__
251     printf("unicode [ ");
252     for (i = 0; i < nsyms; i++) {
253         unicode = xkb_keysym_to_utf32(syms[i]);
254         printf("%lc ", (int)(unicode ? unicode : L' '));
255     }
256     printf("] ");
257 #endif
258
259     printf("groups [ ");
260     for (group = 0; group < xkb_map_num_groups(keymap); group++) {
261         if (!xkb_state_group_index_is_active(state, group, XKB_STATE_EFFECTIVE))
262             continue;
263         printf("%s (%d) ", xkb_map_group_get_name(keymap, group), group);
264     }
265     printf("] ");
266
267     printf("mods [ ");
268     for (mod = 0; mod < xkb_map_num_mods(keymap); mod++) {
269         if (!xkb_state_mod_index_is_active(state, mod, XKB_STATE_EFFECTIVE))
270             continue;
271         printf("%s ", xkb_map_mod_get_name(keymap, mod));
272     }
273     printf("] ");
274
275     printf("leds [ ");
276     for (led = 0; led < xkb_map_num_leds(keymap); led++) {
277         if (!xkb_state_led_index_is_active(state, led))
278             continue;
279         printf("%s ", xkb_map_led_get_name(keymap, led));
280     }
281     printf("] ");
282
283     printf("\n");
284 }
285
286 /* The meaning of the input_event 'value' field. */
287 enum {
288     KEY_STATE_RELEASE = 0,
289     KEY_STATE_PRESS = 1,
290     KEY_STATE_REPEAT = 2,
291 };
292
293 #define EVDEV_OFFSET 8
294
295 static void
296 process_event(struct keyboard *kbd, uint16_t type, uint16_t code, int32_t value)
297 {
298     xkb_keycode_t keycode;
299     struct xkb_keymap *keymap;
300
301     if (type != EV_KEY)
302         return;
303
304     keycode = EVDEV_OFFSET + code;
305     keymap = xkb_state_get_map(kbd->state);
306
307     if (value == KEY_STATE_REPEAT && !xkb_key_repeats(keymap, keycode))
308         return;
309
310     if (value != KEY_STATE_RELEASE)
311         print_keycode(kbd, keycode);
312
313     if (value == KEY_STATE_RELEASE)
314         xkb_state_update_key(kbd->state, keycode, XKB_KEY_UP);
315     else
316         xkb_state_update_key(kbd->state, keycode, XKB_KEY_DOWN);
317 }
318
319 static int
320 read_keyboard(struct keyboard *kbd)
321 {
322     size_t i;
323     ssize_t len;
324     struct input_event evs[16];
325     size_t nevs;
326
327     /* No fancy error checking here. */
328     while ((len = read(kbd->fd, &evs, sizeof(evs))) > 0) {
329         nevs = len / sizeof(struct input_event);
330         for (i = 0; i < nevs; i++)
331             process_event(kbd, evs[i].type, evs[i].code, evs[i].value);
332     }
333
334     if (len < 0 && errno != EWOULDBLOCK) {
335         fprintf(stderr, "Couldn't read %s: %s\n", kbd->path,
336                 strerror(errno));
337         return -errno;
338     }
339
340     return 0;
341 }
342
343 static int
344 loop(struct keyboard *kbds)
345 {
346     int i, ret;
347     int epfd;
348     struct keyboard *kbd;
349     struct epoll_event ev;
350     struct epoll_event evs[16];
351
352     epfd = epoll_create1(0);
353     if (epfd < 0) {
354         fprintf(stderr, "Couldn't create epoll instance: %s\n",
355                 strerror(errno));
356         return -errno;
357     }
358
359     for (kbd = kbds; kbd; kbd = kbd->next) {
360         memset(&ev, 0, sizeof(ev));
361         ev.events = EPOLLIN;
362         ev.data.ptr = kbd;
363         ret = epoll_ctl(epfd, EPOLL_CTL_ADD, kbd->fd, &ev);
364         if (ret) {
365             ret = -errno;
366             fprintf(stderr, "Couldn't add %s to epoll: %s\n",
367                     kbd->path, strerror(errno));
368             goto err_epoll;
369         }
370     }
371
372     while (!terminate) {
373         ret = epoll_wait(epfd, evs, 16, -1);
374         if (ret < 0) {
375             if (errno == EINTR)
376                 continue;
377             ret = -errno;
378             fprintf(stderr, "Couldn't poll for events: %s\n",
379                     strerror(errno));
380             goto err_epoll;
381         }
382
383         for (i = 0; i < ret; i++) {
384             kbd = evs[i].data.ptr;
385             ret = read_keyboard(kbd);
386             if (ret) {
387                 goto err_epoll;
388             }
389         }
390     }
391
392     close(epfd);
393     return 0;
394
395 err_epoll:
396     close(epfd);
397     return ret;
398 }
399
400 static void
401 sigintr_handler(int signum)
402 {
403     terminate = true;
404 }
405
406 int
407 main(int argc, char *argv[])
408 {
409     int ret;
410     int opt;
411     struct keyboard *kbds;
412     struct xkb_context *ctx;
413     struct xkb_keymap *keymap;
414     struct xkb_rule_names names = {
415         .rules = "evdev",
416         .model = "evdev",
417         .layout = "us",
418         .variant = "",
419         .options = "",
420     };
421     const char *keymap_path = NULL;
422     FILE *file;
423     struct sigaction act;
424
425     setlocale(LC_ALL, "");
426
427     while ((opt = getopt(argc, argv, "r:m:l:v:o:k:")) != -1) {
428         switch (opt) {
429         case 'r':
430             names.rules = optarg;
431             break;
432         case 'm':
433             names.model = optarg;
434             break;
435         case 'l':
436             names.layout = optarg;
437             break;
438         case 'v':
439             names.variant = optarg;
440             break;
441         case 'o':
442             names.options = optarg;
443             break;
444         case 'k':
445             keymap_path = optarg;
446             break;
447         case '?':
448             fprintf(stderr, "Usage: %s [-r <rules>] [-m <model>] "
449                     "[-l <layout>] [-v <variant>] [-o <options>]\n",
450                     argv[0]);
451             fprintf(stderr, "   or: %s -k <path to keymap file>\n",
452                     argv[0]);
453             exit(EX_USAGE);
454         }
455     }
456
457     ctx = xkb_context_new(0);
458     if (!ctx) {
459         ret = -1;
460         fprintf(stderr, "Couldn't create xkb context\n");
461         goto err_out;
462     }
463
464     if (keymap_path) {
465         file = fopen(keymap_path, "r");
466         if (!file) {
467             fprintf(stderr, "Couldn't open file %s: %s\n",
468                     keymap_path, strerror(errno));
469             goto err_ctx;
470         }
471         keymap = xkb_map_new_from_file(ctx, file,
472                                        XKB_KEYMAP_FORMAT_TEXT_V1, 0);
473     } else {
474         keymap = xkb_map_new_from_names(ctx, &names, 0);
475     }
476     if (!keymap) {
477         ret = -1;
478         fprintf(stderr, "Couldn't create xkb keymap\n");
479         goto err_ctx;
480     }
481
482     kbds = get_keyboards(keymap);
483     if (!kbds) {
484         ret = -1;
485         goto err_xkb;
486     }
487
488     act.sa_handler = sigintr_handler;
489     sigemptyset(&act.sa_mask);
490     act.sa_flags = 0;
491     sigaction(SIGINT, &act, NULL);
492     sigaction(SIGTERM, &act, NULL);
493
494     /* Instead of fiddling with termios.. */
495     system("stty -echo");
496
497     ret = loop(kbds);
498     if (ret) {
499         goto err_stty;
500     }
501
502 err_stty:
503     system("stty echo");
504     free_keyboards(kbds);
505 err_xkb:
506     xkb_map_unref(keymap);
507 err_ctx:
508     xkb_context_unref(ctx);
509 err_out:
510     exit(ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
511 }