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