chiark / gitweb /
fix spelling
[elogind.git] / extras / 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 <ctype.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <limits.h>
32 #include <fcntl.h>
33 #include <getopt.h>
34 #include <sys/ioctl.h>
35 #include <linux/input.h>
36
37 const struct key* lookup_key (const char *str, unsigned int len);
38
39 #include "keys-from-name.h"
40 #include "keys-to-name.h"
41
42 #define MAX_SCANCODES 1024
43
44 static int evdev_open(const char *dev)
45 {
46         int fd;
47         char fn[PATH_MAX];
48
49         if (strncmp(dev, "/dev", 4) != 0) {
50                 snprintf(fn, sizeof(fn), "/dev/%s", dev);
51                 dev = fn;
52         }
53
54         if ((fd = open(dev, O_RDWR)) < 0) {
55                 fprintf(stderr, "error open('%s'): %m\n", dev);
56                 return -1;
57         }
58         return fd;
59 }
60
61 static int evdev_get_keycode(int fd, int scancode, int e)
62 {
63         int codes[2];
64
65         codes[0] = scancode;
66         if (ioctl(fd, EVIOCGKEYCODE, codes) < 0) {
67                 if (e && errno == EINVAL) {
68                         return -2;
69                 } else {
70                         fprintf(stderr, "EVIOCGKEYCODE: %m\n");
71                         return -1;
72                 }
73         }
74         return codes[1];
75 }
76
77 static int evdev_set_keycode(int fd, int scancode, int keycode)
78 {
79         int codes[2];
80
81         codes[0] = scancode;
82         codes[1] = keycode;
83
84         if (ioctl(fd, EVIOCSKEYCODE, codes) < 0) {
85                 fprintf(stderr, "EVIOCSKEYCODE: %m\n");
86                 return -1;
87         }
88         return 0;
89 }
90
91 static int evdev_driver_version(int fd, char *v, size_t l)
92 {
93         int version;
94
95         if (ioctl(fd, EVIOCGVERSION, &version)) {
96                 fprintf(stderr, "EVIOCGVERSION: %m\n");
97                 return -1;
98         }
99
100         snprintf(v, l, "%i.%i.%i.", version >> 16, (version >> 8) & 0xff, version & 0xff);
101         return 0;
102 }
103
104 static int evdev_device_name(int fd, char *n, size_t l)
105 {
106         if (ioctl(fd, EVIOCGNAME(l), n) < 0) {
107                 fprintf(stderr, "EVIOCGNAME: %m\n");
108                 return -1;
109         }
110         return 0;
111 }
112
113 /* Return a lower-case string with KEY_ prefix removed */
114 static const char* format_keyname(const char* key) {
115         static char result[101];
116         const char* s;
117         int len;
118
119         for (s = key+4, len = 0; *s && len < 100; ++len, ++s)
120                 result[len] = tolower(*s);
121         result[len] = '\0';
122         return result;
123 }
124
125 static int dump_table(int fd) {
126         char version[256], name[256];
127         int scancode, r = -1;
128
129         if (evdev_driver_version(fd, version, sizeof(version)) < 0)
130                 goto fail;
131
132         if (evdev_device_name(fd, name, sizeof(name)) < 0)
133                 goto fail;
134
135         printf("### evdev %s, driver '%s'\n", version, name);
136
137         r = 0;
138         for (scancode = 0; scancode < MAX_SCANCODES; scancode++) {
139                 int keycode;
140
141                 if ((keycode = evdev_get_keycode(fd, scancode, 1)) < 0) {
142                         if (keycode != -2)
143                                 r = -1;
144                         break;
145                 }
146
147                 if (keycode < KEY_MAX && key_names[keycode])
148                         printf("0x%03x %s\n", scancode, format_keyname(key_names[keycode]));
149                 else
150                         printf("0x%03x 0x%03x\n", scancode, keycode);
151         }
152 fail:
153         return r;
154 }
155
156 static void set_key(int fd, const char* scancode_str, const char* keyname)
157 {
158         unsigned scancode;
159         char *endptr;
160         char t[105] = "KEY_UNKNOWN";
161         const struct key *k;
162
163         scancode = (unsigned) strtol(scancode_str, &endptr, 0);
164         if (*endptr != '\0') {
165                 fprintf(stderr, "ERROR: Invalid scancode\n");
166                 exit(1);
167         }
168
169         snprintf(t, sizeof(t), "KEY_%s", keyname);
170
171         if (!(k = lookup_key(t, strlen(t)))) {
172                 fprintf(stderr, "ERROR: Unknown key name '%s'\n", keyname);
173                 exit(1);
174         }
175
176         if (evdev_set_keycode(fd, scancode, k->id) < 0)
177                 fprintf(stderr, "setting scancode 0x%2X to key code %i failed\n", 
178                         scancode, k->id);
179         else
180                 printf("setting scancode 0x%2X to key code %i\n", 
181                         scancode, k->id);
182 }
183
184 static int merge_table(int fd, const char *filename) {
185         int r = 0;
186         int line = 0;
187         FILE* f;
188
189         f = fopen(filename, "r");
190         if (!f) {
191                 perror(filename);
192                 r = -1;
193                 goto fail;
194         }
195
196         while (!feof(f)) {
197                 char s[256], *p;
198                 int scancode, new_keycode, old_keycode;
199
200                 if (!fgets(s, sizeof(s), f))
201                         break;
202
203                 line++;
204                 p = s+strspn(s, "\t ");
205                 if (*p == '#' || *p == '\n')
206                         continue;
207
208                 if (sscanf(p, "%i %i", &scancode, &new_keycode) != 2) {
209                         char t[105] = "KEY_UNKNOWN";
210                         const struct key *k;
211
212                         if (sscanf(p, "%i %100s", &scancode, t+4) != 2) {
213                                 fprintf(stderr, "WARNING: Parse failure at line %i, ignoring.\n", line);
214                                 r = -1;
215                                 continue;
216                         }
217
218                         if (!(k = lookup_key(t, strlen(t)))) {
219                                 fprintf(stderr, "WARNING: Unknown key '%s' at line %i, ignoring.\n", t, line);
220                                 r = -1;
221                                 continue;
222                         }
223
224                         new_keycode = k->id;
225                 }
226
227
228                 if ((old_keycode = evdev_get_keycode(fd, scancode, 0)) < 0) {
229                         r = -1;
230                         goto fail;
231                 }
232
233                 if (evdev_set_keycode(fd, scancode, new_keycode) < 0) {
234                         r = -1;
235                         goto fail;
236                 }
237
238                 if (new_keycode != old_keycode)
239                         fprintf(stderr, "Remapped scancode 0x%02x to 0x%02x (prior: 0x%02x)\n",
240                                 scancode, new_keycode, old_keycode);
241         }
242 fail:
243         return r;
244 }
245
246 static const char* default_keymap_path(const char* path)
247 {
248         static char result[PATH_MAX];
249
250         /* If keymap file is given without a path, assume udev directory; must end with '/' * */
251         if (!strchr(path, '/')) {
252                 snprintf(result, sizeof(result), "%s%s", LIBEXECDIR "/keymaps/", path);
253                 return result;
254         }
255         return path;
256 }
257
258 static void print_key(struct input_event *event)
259 {
260         static int cur_scancode = 0;
261         const char *keyname;
262
263         /* save scan code for next EV_KEY event */
264         if (event->type == EV_MSC && event->code == MSC_SCAN)
265             cur_scancode = event->value;
266
267         /* key press */
268         if (event->type == EV_KEY && event->value) {
269                 keyname = key_names[event->code];
270                 if (keyname != NULL)
271                         printf("scan code: 0x%02X   key code: %s\n", cur_scancode,
272                             format_keyname(key_names[event->code]));
273                 else
274                         printf("scan code: 0x%02X   key code: %03X\n", cur_scancode,
275                             event->code);
276         }
277 }
278
279 static void interactive(int fd)
280 {
281         struct input_event ev;
282         int run = 1;
283
284         /* grab input device */
285         ioctl(fd, EVIOCGRAB, 1);
286
287         puts("Press ESC to finish");
288         while (run) {
289                 switch (read(fd, &ev, sizeof(ev))) {
290                 case -1:
291                         perror("read");
292                         run = 0;
293                         break;
294                 case 0:
295                         run = 0;
296                         break;
297                 default:
298                         print_key(&ev);
299                         /* stop on Escape key release */
300                         if (ev.type == EV_KEY && ev.code == KEY_ESC && ev.value == 0)
301                                 run = 0;
302                         break;
303                 }
304         }
305
306         /* release input device */
307         ioctl(fd, EVIOCGRAB, 0);
308 }
309
310 static void help(int error)
311 {
312         const char* h = "Usage: keymap <event device> [<map file>]\n"
313                         "       keymap <event device> scancode keyname [...]\n"
314                         "       keymap -i <event device>\n";
315         if (error) {
316                 fputs(h, stderr);
317                 exit(2);
318         } else {
319                 fputs(h, stdout);
320                 exit(0);
321         }
322 }
323
324 int main(int argc, char **argv)
325 {
326         static const struct option options[] = {
327                 { "help", no_argument, NULL, 'h' },
328                 { "interactive", no_argument, NULL, 'i' },
329                 {}
330         };
331         int fd = -1;
332         int opt_interactive = 0;
333         int i;
334
335         while (1) {
336                 int option;
337
338                 option = getopt_long(argc, argv, "hi", options, NULL);
339                 if (option == -1)
340                         break;
341
342                 switch (option) {
343                 case 'h':
344                         help(0);
345
346                 case 'i':
347                         opt_interactive = 1;
348                         break;
349                 default:
350                         return 1;
351                 }
352         }
353
354         if (argc < optind+1)
355                 help (1);
356
357         if ((fd = evdev_open(argv[optind])) < 0)
358                 return 3;
359
360         /* one argument (device): dump or interactive */
361         if (argc == optind+1) {
362                 if (opt_interactive)
363                         interactive(fd);
364                 else
365                         dump_table(fd);
366                 return 0;
367         }
368
369         /* two arguments (device, mapfile): set map file */
370         if (argc == optind+2) {
371                 merge_table(fd, default_keymap_path(argv[optind+1]));
372                 return 0;
373         }
374
375         /* more arguments (device, scancode/keyname pairs): set keys directly */
376         if ((argc - optind - 1) % 2 == 0) {
377                 for (i = optind+1; i < argc; i += 2)
378                         set_key(fd, argv[i], argv[i+1]);        
379                 return 0;
380         }
381
382         /* invalid number of arguments */
383         help(1);
384         return 1; /* not reached */
385 }