chiark / gitweb /
Revert "keymap: add --version option"
[elogind.git] / src / udev / keymap / keymap.c
1 /*
2  * keymap - dump keymap of an evdev device or set a new keymap from a file
3  *
4  * Based on keyfuzz by Lennart Poettering <mzqrovna@0pointer.net>
5  * Adapted for udev-extras by Martin Pitt <martin.pitt@ubuntu.com>
6  *
7  * Copyright (C) 2006, Lennart Poettering
8  * Copyright (C) 2009, Canonical Ltd.
9  *
10  * keymap is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * keymap is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with keymap; if not, write to the Free Software Foundation,
22  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23  */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdint.h>
29 #include <ctype.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <limits.h>
33 #include <fcntl.h>
34 #include <getopt.h>
35 #include <sys/ioctl.h>
36 #include <linux/limits.h>
37 #include <linux/input.h>
38
39 const struct key* lookup_key (const char *str, unsigned int len);
40
41 #include "keys-from-name.h"
42 #include "keys-to-name.h"
43 #include "util.h"
44
45 #define MAX_SCANCODES 1024
46
47 static int evdev_open(const char *dev)
48 {
49         int fd;
50         char fn[PATH_MAX];
51
52         if (!startswith(dev, "/dev")) {
53                 snprintf(fn, sizeof(fn), "/dev/%s", dev);
54                 dev = fn;
55         }
56
57         if ((fd = open(dev, O_RDWR)) < 0) {
58                 fprintf(stderr, "error open('%s'): %m\n", dev);
59                 return -1;
60         }
61         return fd;
62 }
63
64 static int evdev_get_keycode(int fd, int scancode, int e)
65 {
66         int codes[2];
67
68         codes[0] = scancode;
69         if (ioctl(fd, EVIOCGKEYCODE, codes) < 0) {
70                 if (e && errno == EINVAL) {
71                         return -2;
72                 } else {
73                         fprintf(stderr, "EVIOCGKEYCODE: %m\n");
74                         return -1;
75                 }
76         }
77         return codes[1];
78 }
79
80 static int evdev_set_keycode(int fd, int scancode, int keycode)
81 {
82         int codes[2];
83
84         codes[0] = scancode;
85         codes[1] = keycode;
86
87         if (ioctl(fd, EVIOCSKEYCODE, codes) < 0) {
88                 fprintf(stderr, "EVIOCSKEYCODE: %m\n");
89                 return -1;
90         }
91         return 0;
92 }
93
94 static int evdev_driver_version(int fd, char *v, size_t l)
95 {
96         int version;
97
98         if (ioctl(fd, EVIOCGVERSION, &version)) {
99                 fprintf(stderr, "EVIOCGVERSION: %m\n");
100                 return -1;
101         }
102
103         snprintf(v, l, "%i.%i.%i.", version >> 16, (version >> 8) & 0xff, version & 0xff);
104         return 0;
105 }
106
107 static int evdev_device_name(int fd, char *n, size_t l)
108 {
109         if (ioctl(fd, EVIOCGNAME(l), n) < 0) {
110                 fprintf(stderr, "EVIOCGNAME: %m\n");
111                 return -1;
112         }
113         return 0;
114 }
115
116 /* Return a lower-case string with KEY_ prefix removed */
117 static const char* format_keyname(const char* key) {
118         static char result[101];
119         const char* s;
120         int len;
121
122         for (s = key+4, len = 0; *s && len < 100; ++len, ++s)
123                 result[len] = tolower(*s);
124         result[len] = '\0';
125         return result;
126 }
127
128 static int dump_table(int fd) {
129         char version[256], name[256];
130         int scancode, r = -1;
131
132         if (evdev_driver_version(fd, version, sizeof(version)) < 0)
133                 goto fail;
134
135         if (evdev_device_name(fd, name, sizeof(name)) < 0)
136                 goto fail;
137
138         printf("### evdev %s, driver '%s'\n", version, name);
139
140         r = 0;
141         for (scancode = 0; scancode < MAX_SCANCODES; scancode++) {
142                 int keycode;
143
144                 if ((keycode = evdev_get_keycode(fd, scancode, 1)) < 0) {
145                         if (keycode == -2)
146                                 continue;
147                         r = -1;
148                         break;
149                 }
150
151                 if (keycode < KEY_MAX && key_names[keycode])
152                         printf("0x%03x %s\n", scancode, format_keyname(key_names[keycode]));
153                 else
154                         printf("0x%03x 0x%03x\n", scancode, keycode);
155         }
156 fail:
157         return r;
158 }
159
160 static void set_key(int fd, const char* scancode_str, const char* keyname)
161 {
162         unsigned scancode;
163         char *endptr;
164         char t[105] = "KEY_UNKNOWN";
165         const struct key *k;
166
167         scancode = (unsigned) strtol(scancode_str, &endptr, 0);
168         if (*endptr != '\0') {
169                 fprintf(stderr, "ERROR: Invalid scancode\n");
170                 exit(1);
171         }
172
173         snprintf(t, sizeof(t), "KEY_%s", keyname);
174
175         if (!(k = lookup_key(t, strlen(t)))) {
176                 fprintf(stderr, "ERROR: Unknown key name '%s'\n", keyname);
177                 exit(1);
178         }
179
180         if (evdev_set_keycode(fd, scancode, k->id) < 0)
181                 fprintf(stderr, "setting scancode 0x%2X to key code %i failed\n",
182                         scancode, k->id);
183         else
184                 printf("setting scancode 0x%2X to key code %i\n",
185                         scancode, k->id);
186 }
187
188 static int merge_table(int fd, FILE *f) {
189         int r = 0;
190         int line = 0;
191
192         while (!feof(f)) {
193                 char s[256], *p;
194                 int scancode, new_keycode, old_keycode;
195
196                 if (!fgets(s, sizeof(s), f))
197                         break;
198
199                 line++;
200                 p = s+strspn(s, "\t ");
201                 if (*p == '#' || *p == '\n')
202                         continue;
203
204                 if (sscanf(p, "%i %i", &scancode, &new_keycode) != 2) {
205                         char t[105] = "KEY_UNKNOWN";
206                         const struct key *k;
207
208                         if (sscanf(p, "%i %100s", &scancode, t+4) != 2) {
209                                 fprintf(stderr, "WARNING: Parse failure at line %i, ignoring.\n", line);
210                                 r = -1;
211                                 continue;
212                         }
213
214                         if (!(k = lookup_key(t, strlen(t)))) {
215                                 fprintf(stderr, "WARNING: Unknown key '%s' at line %i, ignoring.\n", t, line);
216                                 r = -1;
217                                 continue;
218                         }
219
220                         new_keycode = k->id;
221                 }
222
223
224                 if ((old_keycode = evdev_get_keycode(fd, scancode, 0)) < 0) {
225                         r = -1;
226                         goto fail;
227                 }
228
229                 if (evdev_set_keycode(fd, scancode, new_keycode) < 0) {
230                         r = -1;
231                         goto fail;
232                 }
233
234                 if (new_keycode != old_keycode)
235                         fprintf(stderr, "Remapped scancode 0x%02x to 0x%02x (prior: 0x%02x)\n",
236                                 scancode, new_keycode, old_keycode);
237         }
238 fail:
239         fclose(f);
240         return r;
241 }
242
243
244 /* read one event; return 1 if valid */
245 static int read_event(int fd, struct input_event* ev)
246 {
247         int ret;
248         ret = read(fd, ev, sizeof(struct input_event));
249
250         if (ret < 0) {
251                 perror("read");
252                 return 0;
253         }
254         if (ret != sizeof(struct input_event)) {
255                 fprintf(stderr, "did not get enough data for event struct, aborting\n");
256                 return 0;
257         }
258
259         return 1;
260 }
261
262 static void print_key(uint32_t scancode, uint16_t keycode, int has_scan, int has_key)
263 {
264         const char *keyname;
265
266         /* ignore key release events */
267         if (has_key == 1)
268                 return;
269
270         if (has_key == 0 && has_scan != 0) {
271                 fprintf(stderr, "got scan code event 0x%02X without a key code event\n",
272                         scancode);
273                 return;
274         }
275
276         if (has_scan != 0)
277                 printf("scan code: 0x%02X   ", scancode);
278         else
279                 printf("(no scan code received)  ");
280
281         keyname = key_names[keycode];
282         if (keyname != NULL)
283                 printf("key code: %s\n", format_keyname(keyname));
284         else
285                 printf("key code: %03X\n", keycode);
286 }
287
288 static void interactive(int fd)
289 {
290         struct input_event ev;
291         uint32_t last_scan = 0;
292         uint16_t last_key = 0;
293         int has_scan; /* boolean */
294         int has_key; /* 0: none, 1: release, 2: press */
295
296         /* grab input device */
297         ioctl(fd, EVIOCGRAB, 1);
298         puts("Press ESC to finish, or Control-C if this device is not your primary keyboard");
299
300         has_scan = has_key = 0;
301         while (read_event(fd, &ev)) {
302                 /* Drivers usually send the scan code first, then the key code,
303                  * then a SYN. Some drivers (like thinkpad_acpi) send the key
304                  * code first, and some drivers might not send SYN events, so
305                  * keep a robust state machine which can deal with any of those
306                  */
307
308                 if (ev.type == EV_MSC && ev.code == MSC_SCAN) {
309                         if (has_scan) {
310                                 fputs("driver did not send SYN event in between key events; previous event:\n",
311                                       stderr);
312                                 print_key(last_scan, last_key, has_scan, has_key);
313                                 has_key = 0;
314                         }
315
316                         last_scan = ev.value;
317                         has_scan = 1;
318                         /*printf("--- got scan %u; has scan %i key %i\n", last_scan, has_scan, has_key); */
319                 }
320                 else if (ev.type == EV_KEY) {
321                         if (has_key) {
322                                 fputs("driver did not send SYN event in between key events; previous event:\n",
323                                       stderr);
324                                 print_key(last_scan, last_key, has_scan, has_key);
325                                 has_scan = 0;
326                         }
327
328                         last_key = ev.code;
329                         has_key = 1 + ev.value;
330                         /*printf("--- got key %hu; has scan %i key %i\n", last_key, has_scan, has_key);*/
331
332                         /* Stop on ESC */
333                         if (ev.code == KEY_ESC && ev.value == 0)
334                                 break;
335                 }
336                 else if (ev.type == EV_SYN) {
337                         /*printf("--- got SYN; has scan %i key %i\n", has_scan, has_key);*/
338                         print_key(last_scan, last_key, has_scan, has_key);
339
340                         has_scan = has_key = 0;
341                 }
342
343         }
344
345         /* release input device */
346         ioctl(fd, EVIOCGRAB, 0);
347 }
348
349 static void help(int error)
350 {
351         const char* h = "Usage: keymap <event device> [<map file>]\n"
352                         "       keymap <event device> scancode keyname [...]\n"
353                         "       keymap -i <event device>\n";
354         if (error) {
355                 fputs(h, stderr);
356                 exit(2);
357         } else {
358                 fputs(h, stdout);
359                 exit(0);
360         }
361 }
362
363 int main(int argc, char **argv)
364 {
365         static const struct option options[] = {
366                 { "help", no_argument, NULL, 'h' },
367                 { "interactive", no_argument, NULL, 'i' },
368                 {}
369         };
370         int fd = -1;
371         int opt_interactive = 0;
372         int i;
373
374         while (1) {
375                 int option;
376
377                 option = getopt_long(argc, argv, "hi", options, NULL);
378                 if (option == -1)
379                         break;
380
381                 switch (option) {
382                 case 'h':
383                         help(0);
384
385                 case 'i':
386                         opt_interactive = 1;
387                         break;
388                 default:
389                         return 1;
390                 }
391         }
392
393         if (argc < optind+1)
394                 help (1);
395
396         if ((fd = evdev_open(argv[optind])) < 0)
397                 return 3;
398
399         /* one argument (device): dump or interactive */
400         if (argc == optind+1) {
401                 if (opt_interactive)
402                         interactive(fd);
403                 else
404                         dump_table(fd);
405                 return 0;
406         }
407
408         /* two arguments (device, mapfile): set map file */
409         if (argc == optind+2) {
410                 const char *filearg = argv[optind+1];
411                 if (strchr(filearg, '/')) {
412                         /* Keymap file argument is a path */
413                         FILE *f = fopen(filearg, "re");
414                         if (f)
415                                 merge_table(fd, f);
416                         else
417                                 perror(filearg);
418                 } else {
419                         /* Keymap file argument is a filename */
420                         /* Open override file if present, otherwise default file */
421                         char keymap_path[PATH_MAX];
422                         FILE *f;
423                         snprintf(keymap_path, sizeof(keymap_path), "%s%s", SYSCONFDIR "/udev/keymaps/", filearg);
424                         f = fopen(keymap_path, "re");
425                         if (f) {
426                                 merge_table(fd, f);
427                         } else {
428                                 snprintf(keymap_path, sizeof(keymap_path), "%s%s", UDEVLIBEXECDIR "/keymaps/", filearg);
429                                 f = fopen(keymap_path, "re");
430                                 if (f)
431                                         merge_table(fd, f);
432                                 else
433                                         perror(keymap_path);
434                         }
435                 }
436                 return 0;
437         }
438
439         /* more arguments (device, scancode/keyname pairs): set keys directly */
440         if ((argc - optind - 1) % 2 == 0) {
441                 for (i = optind+1; i < argc; i += 2)
442                         set_key(fd, argv[i], argv[i+1]);
443                 return 0;
444         }
445
446         /* invalid number of arguments */
447         help(1);
448         return 1; /* not reached */
449 }