1 /*
2 Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3 All rights reserved.
4
5 This file is part of x11vnc.
6
7 x11vnc is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at
10 your option) any later version.
11
12 x11vnc is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with x11vnc; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20 or see <http://www.gnu.org/licenses/>.
21
22 In addition, as a special exception, Karl J. Runge
23 gives permission to link the code of its release of x11vnc with the
24 OpenSSL project's "OpenSSL" library (or with modified versions of it
25 that use the same license as the "OpenSSL" library), and distribute
26 the linked executables. You must obey the GNU General Public License
27 in all respects for all of the code used other than "OpenSSL". If you
28 modify this file, you may extend this exception to your version of the
29 file, but you are not obligated to do so. If you do not wish to do
30 so, delete this exception statement from your version.
31 */
32
33 /* -- uinput.c -- */
34
35 #include "x11vnc.h"
36 #include "cleanup.h"
37 #include "scan.h"
38 #include "xinerama.h"
39 #include "screen.h"
40 #include "pointer.h"
41 #include "keyboard.h"
42 #include "allowed_input_t.h"
43
44 #if LIBVNCSERVER_HAVE_SYS_IOCTL_H
45 #if LIBVNCSERVER_HAVE_LINUX_INPUT_H
46 #if LIBVNCSERVER_HAVE_LINUX_UINPUT_H
47 #define UINPUT_OK
48 #endif
49 #endif
50 #endif
51
52 #ifdef UINPUT_OK
53 #include <sys/ioctl.h>
54 #include <linux/input.h>
55 #include <linux/uinput.h>
56
57 #if !defined(EV_SYN) || !defined(SYN_REPORT)
58 #undef UINPUT_OK
59 #endif
60
61 #endif
62
63
64 int check_uinput(void);
65 int initialize_uinput(void);
66 void shutdown_uinput(void);
67 int set_uinput_accel(char *str);
68 int set_uinput_thresh(char *str);
69 void set_uinput_reset(int ms);
70 void set_uinput_always(int);
71 void set_uinput_touchscreen(int);
72 void set_uinput_abs(int);
73 char *get_uinput_accel();
74 char *get_uinput_thresh();
75 int get_uinput_reset();
76 int get_uinput_always();
77 int get_uinput_touchscreen();
78 int get_uinput_abs();
79 void parse_uinput_str(char *str);
80 void uinput_pointer_command(int mask, int x, int y, rfbClientPtr client);
81 void uinput_key_command(int down, int keysym, rfbClientPtr client);
82
83 static void init_key_tracker(void);
84 static int mod_is_down(void);
85 static int key_is_down(void);
86 static void set_uinput_accel_xy(double fx, double fy);
87 static void ptr_move(int dx, int dy);
88 static void ptr_rel(int dx, int dy);
89 static void button_click(int down, int btn);
90 static int lookup_code(int keysym);
91
92 static int fd = -1;
93 static int direct_rel_fd = -1;
94 static int direct_abs_fd = -1;
95 static int direct_btn_fd = -1;
96 static int direct_key_fd = -1;
97 static int bmask = 0;
98 static int db = 0;
99
100 static char *injectable = NULL;
101 static char *uinput_dev = NULL;
102 static char *tslib_cal = NULL;
103 static double a[7];
104 static int uinput_touchscreen = 0;
105 static int uinput_abs = 0;
106 static int btn_touch = 0;
107 static int dragskip = 0;
108 static int touch_always = 0;
109 static int touch_pressure = 1;
110 static int abs_x = 0, abs_y = 0;
111
112 static char *devs[] = {
113 "/dev/misc/uinput",
114 "/dev/input/uinput",
115 "/dev/uinput",
116 NULL
117 };
118
119 #ifndef O_NDELAY
120 #ifdef O_NONBLOCK
121 #define O_NDELAY O_NONBLOCK
122 #else
123 #define O_NDELAY 0
124 #endif
125 #endif
126
127 /*
128 * User may need to do:
129 modprode uinput
130 mknod /dev/input/uinput c 10 223
131 */
132
check_uinput(void)133 int check_uinput(void) {
134 #ifndef UINPUT_OK
135 return 0;
136 #else
137 int i;
138 if (UT.release) {
139 int maj, min;
140 /* guard against linux 2.4 */
141 if (sscanf(UT.release, "%d.%d.", &maj, &min) == 2) {
142 if (maj < 2) {
143 return 0;
144 } else if (maj == 2) {
145 /* hmmm IPAQ 2.4.19-rmk6-pxa1-hh37 works... */
146 #if 0
147 if (min < 6) {
148 return 0;
149 }
150 #endif
151 }
152 }
153 }
154 fd = -1;
155 i = 0;
156 while (devs[i] != NULL) {
157 if ( (fd = open(devs[i++], O_WRONLY | O_NDELAY)) >= 0) {
158 break;
159 }
160 }
161 if (fd < 0) {
162 return 0;
163 }
164 close(fd);
165 fd = -1;
166 return 1;
167 #endif
168 }
169
170 static int key_pressed[256];
171 static int key_ismod[256];
172
init_key_tracker(void)173 static void init_key_tracker(void) {
174 int i;
175 for (i = 0; i < 256; i++) {
176 key_pressed[i] = 0;
177 key_ismod[i] = 0;
178 }
179 i = lookup_code(XK_Shift_L); if (0<=i && i<256) key_ismod[i] = 1;
180 i = lookup_code(XK_Shift_R); if (0<=i && i<256) key_ismod[i] = 1;
181 i = lookup_code(XK_Control_L); if (0<=i && i<256) key_ismod[i] = 1;
182 i = lookup_code(XK_Control_R); if (0<=i && i<256) key_ismod[i] = 1;
183 i = lookup_code(XK_Alt_L); if (0<=i && i<256) key_ismod[i] = 1;
184 i = lookup_code(XK_Alt_R); if (0<=i && i<256) key_ismod[i] = 1;
185 i = lookup_code(XK_Meta_L); if (0<=i && i<256) key_ismod[i] = 1;
186 i = lookup_code(XK_Meta_R); if (0<=i && i<256) key_ismod[i] = 1;
187 }
188
mod_is_down(void)189 static int mod_is_down(void) {
190 int i;
191 if (0) {key_is_down();}
192 for (i = 0; i < 256; i++) {
193 if (key_pressed[i] && key_ismod[i]) {
194 return 1;
195 }
196 }
197 return 0;
198 }
199
key_is_down(void)200 static int key_is_down(void) {
201 int i;
202 for (i = 0; i < 256; i++) {
203 if (key_pressed[i]) {
204 return 1;
205 }
206 }
207 return 0;
208 }
209
shutdown_uinput(void)210 void shutdown_uinput(void) {
211 #ifdef UINPUT_OK
212 if (fd >= 0) {
213 if (db) {
214 rfbLog("shutdown_uinput called on fd=%d\n", fd);
215 }
216 ioctl(fd, UI_DEV_DESTROY);
217 close(fd);
218 fd = -1;
219 }
220
221 /* close direct injection files too: */
222 if (direct_rel_fd >= 0) close(direct_rel_fd);
223 if (direct_abs_fd >= 0) close(direct_abs_fd);
224 if (direct_btn_fd >= 0) close(direct_btn_fd);
225 if (direct_key_fd >= 0) close(direct_key_fd);
226 direct_rel_fd = -1;
227 direct_abs_fd = -1;
228 direct_btn_fd = -1;
229 direct_key_fd = -1;
230 #endif
231 }
232
233 /*
234 grep BUS_ /usr/include/linux/input.h | awk '{print $2}' | perl -e 'while (<>) {chomp; print "#ifdef $_\n\t\tif(!strcmp(s, \"$_\"))\tudev.id.bustype = $_\n#endif\n"}'
235 */
get_bustype(char * s)236 static int get_bustype(char *s) {
237 #ifdef UINPUT_OK
238
239 if (!s) return 0;
240
241 #ifdef BUS_PCI
242 if(!strcmp(s, "BUS_PCI")) return BUS_PCI;
243 #endif
244 #ifdef BUS_ISAPNP
245 if(!strcmp(s, "BUS_ISAPNP")) return BUS_ISAPNP;
246 #endif
247 #ifdef BUS_USB
248 if(!strcmp(s, "BUS_USB")) return BUS_USB;
249 #endif
250 #ifdef BUS_HIL
251 if(!strcmp(s, "BUS_HIL")) return BUS_HIL;
252 #endif
253 #ifdef BUS_BLUETOOTH
254 if(!strcmp(s, "BUS_BLUETOOTH")) return BUS_BLUETOOTH;
255 #endif
256 #ifdef BUS_VIRTUAL
257 if(!strcmp(s, "BUS_VIRTUAL")) return BUS_VIRTUAL;
258 #endif
259 #ifdef BUS_ISA
260 if(!strcmp(s, "BUS_ISA")) return BUS_ISA;
261 #endif
262 #ifdef BUS_I8042
263 if(!strcmp(s, "BUS_I8042")) return BUS_I8042;
264 #endif
265 #ifdef BUS_XTKBD
266 if(!strcmp(s, "BUS_XTKBD")) return BUS_XTKBD;
267 #endif
268 #ifdef BUS_RS232
269 if(!strcmp(s, "BUS_RS232")) return BUS_RS232;
270 #endif
271 #ifdef BUS_GAMEPORT
272 if(!strcmp(s, "BUS_GAMEPORT")) return BUS_GAMEPORT;
273 #endif
274 #ifdef BUS_PARPORT
275 if(!strcmp(s, "BUS_PARPORT")) return BUS_PARPORT;
276 #endif
277 #ifdef BUS_AMIGA
278 if(!strcmp(s, "BUS_AMIGA")) return BUS_AMIGA;
279 #endif
280 #ifdef BUS_ADB
281 if(!strcmp(s, "BUS_ADB")) return BUS_ADB;
282 #endif
283 #ifdef BUS_I2C
284 if(!strcmp(s, "BUS_I2C")) return BUS_I2C;
285 #endif
286 #ifdef BUS_HOST
287 if(!strcmp(s, "BUS_HOST")) return BUS_HOST;
288 #endif
289 #ifdef BUS_GSC
290 if(!strcmp(s, "BUS_GSC")) return BUS_GSC;
291 #endif
292 #ifdef BUS_ATARI
293 if(!strcmp(s, "BUS_ATARI")) return BUS_ATARI;
294 #endif
295 if (atoi(s) > 0) {
296 return atoi(s);
297 }
298
299 #endif
300 return 0;
301 }
302
load_tslib_cal(void)303 static void load_tslib_cal(void) {
304 FILE *f;
305 char line[1024], *p;
306 int i;
307
308 /* /etc/pointercal -528 33408 -3417516 -44200 408 40292028 56541 */
309
310 /* this is the identity transformation: */
311 a[0] = 1.0;
312 a[1] = 0.0;
313 a[2] = 0.0;
314 a[3] = 0.0;
315 a[4] = 1.0;
316 a[5] = 0.0;
317 a[6] = 1.0;
318
319 if (tslib_cal == NULL) {
320 return;
321 }
322
323 rfbLog("load_tslib_cal: reading %s\n", tslib_cal);
324 f = fopen(tslib_cal, "r");
325 if (f == NULL) {
326 rfbLogPerror("load_tslib_cal: fopen");
327 clean_up_exit(1);
328 }
329
330 if (fgets(line, sizeof(line), f) == NULL) {
331 rfbLogPerror("load_tslib_cal: fgets");
332 clean_up_exit(1);
333 }
334 fclose(f);
335
336 p = strtok(line, " \t");
337 i = 0;
338 while (p) {
339 a[i] = (double) atoi(p);
340 rfbLog("load_tslib_cal: a[%d] %.3f\n", i, a[i]);
341 p = strtok(NULL, " \t");
342 i++;
343 if (i >= 7) {
344 break;
345 }
346 }
347 if (i != 7) {
348 rfbLog("load_tslib_cal: invalid tslib file format: i=%d %s\n",
349 i, tslib_cal);
350 clean_up_exit(1);
351 }
352 }
353
354
initialize_uinput(void)355 int initialize_uinput(void) {
356 #ifndef UINPUT_OK
357 return 0;
358 #else
359 int i;
360 char *s;
361 struct uinput_user_dev udev;
362
363 if (fd >= 0) {
364 shutdown_uinput();
365 }
366 fd = -1;
367
368 if (getenv("X11VNC_UINPUT_DEBUG")) {
369 db = atoi(getenv("X11VNC_UINPUT_DEBUG"));
370 rfbLog("set uinput debug to: %d\n", db);
371 }
372
373 if (tslib_cal) {
374 load_tslib_cal();
375 }
376
377 init_key_tracker();
378
379 if (uinput_dev) {
380 if (!strcmp(uinput_dev, "nouinput")) {
381 rfbLog("initialize_uinput: not creating uinput device.\n");
382 return 1;
383 } else {
384 fd = open(uinput_dev, O_WRONLY | O_NDELAY);
385 rfbLog("initialize_uinput: using: %s %d\n", uinput_dev, fd);
386 }
387 } else {
388 i = 0;
389 while (devs[i] != NULL) {
390 if ( (fd = open(devs[i], O_WRONLY | O_NDELAY)) >= 0) {
391 rfbLog("initialize_uinput: using: %s %d\n",
392 devs[i], fd);
393 break;
394 }
395 i++;
396 }
397 }
398 if (fd < 0) {
399 rfbLog("initialize_uinput: could not open an uinput device.\n");
400 rfbLogPerror("open");
401 if (direct_rel_fd < 0 && direct_abs_fd < 0 && direct_btn_fd < 0 && direct_key_fd < 0) {
402 clean_up_exit(1);
403 }
404 return 1;
405 }
406
407 memset(&udev, 0, sizeof(udev));
408
409 strncpy(udev.name, "x11vnc injector", UINPUT_MAX_NAME_SIZE);
410
411 s = getenv("X11VNC_UINPUT_BUS");
412 if (s) {
413 udev.id.bustype = get_bustype(s);
414 } else if (0) {
415 udev.id.bustype = BUS_USB;
416 }
417
418 s = getenv("X11VNC_UINPUT_VERSION");
419 if (s) {
420 udev.id.version = atoi(s);
421 } else if (0) {
422 udev.id.version = 4;
423 }
424
425 ioctl(fd, UI_SET_EVBIT, EV_REL);
426 ioctl(fd, UI_SET_RELBIT, REL_X);
427 ioctl(fd, UI_SET_RELBIT, REL_Y);
428
429 ioctl(fd, UI_SET_EVBIT, EV_KEY);
430
431 ioctl(fd, UI_SET_EVBIT, EV_SYN);
432
433 for (i=0; i < 256; i++) {
434 ioctl(fd, UI_SET_KEYBIT, i);
435 }
436
437 ioctl(fd, UI_SET_KEYBIT, BTN_MOUSE);
438 ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
439 ioctl(fd, UI_SET_KEYBIT, BTN_MIDDLE);
440 ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT);
441 ioctl(fd, UI_SET_KEYBIT, BTN_FORWARD);
442 ioctl(fd, UI_SET_KEYBIT, BTN_BACK);
443
444 if (uinput_touchscreen) {
445 ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH);
446 rfbLog("uinput: touchscreen enabled.\n");
447 }
448 if (uinput_touchscreen || uinput_abs) {
449 int gw = abs_x, gh = abs_y;
450 if (! gw || ! gh) {
451 gw = fb_x; gh = fb_y;
452 }
453 if (! gw || ! gh) {
454 gw = dpy_x; gh = dpy_y;
455 }
456 abs_x = gw;
457 abs_y = gh;
458 ioctl(fd, UI_SET_EVBIT, EV_ABS);
459 ioctl(fd, UI_SET_ABSBIT, ABS_X);
460 ioctl(fd, UI_SET_ABSBIT, ABS_Y);
461 udev.absmin[ABS_X] = 0;
462 udev.absmax[ABS_X] = gw;
463 udev.absfuzz[ABS_X] = 0;
464 udev.absflat[ABS_X] = 0;
465 udev.absmin[ABS_Y] = 0;
466 udev.absmax[ABS_Y] = gh;
467 udev.absfuzz[ABS_Y] = 0;
468 udev.absflat[ABS_Y] = 0;
469 rfbLog("uinput: absolute pointer enabled at %dx%d.\n", abs_x, abs_y);
470 set_uinput_accel_xy(1.0, 1.0);
471 }
472
473 if (db) {
474 rfbLog(" udev.name: %s\n", udev.name);
475 rfbLog(" udev.id.bustype: %d\n", udev.id.bustype);
476 rfbLog(" udev.id.vendor: %d\n", udev.id.vendor);
477 rfbLog(" udev.id.product: %d\n", udev.id.product);
478 rfbLog(" udev.id.version: %d\n", udev.id.version);
479 rfbLog(" udev.ff_effects_max: %d\n", udev.ff_effects_max);
480 rfbLog(" udev.absmin[ABS_X]: %d\n", udev.absmin[ABS_X]);
481 rfbLog(" udev.absmax[ABS_X]: %d\n", udev.absmax[ABS_X]);
482 rfbLog(" udev.absfuzz[ABS_X]: %d\n", udev.absfuzz[ABS_X]);
483 rfbLog(" udev.absflat[ABS_X]: %d\n", udev.absflat[ABS_X]);
484 rfbLog(" udev.absmin[ABS_Y]: %d\n", udev.absmin[ABS_Y]);
485 rfbLog(" udev.absmax[ABS_Y]: %d\n", udev.absmax[ABS_Y]);
486 rfbLog(" udev.absfuzz[ABS_Y]: %d\n", udev.absfuzz[ABS_Y]);
487 rfbLog(" udev.absflat[ABS_Y]: %d\n", udev.absflat[ABS_Y]);
488 }
489
490 write(fd, &udev, sizeof(udev));
491
492 if (ioctl(fd, UI_DEV_CREATE) != 0) {
493 rfbLog("ioctl(fd, UI_DEV_CREATE) failed.\n");
494 rfbLogPerror("ioctl");
495 close(fd);
496 clean_up_exit(1);
497 }
498 return 1;
499 #endif
500 }
501
502 /* these defaults are based on qt-embedded 7/2006 */
503 static double fudge_x = 0.5; /* accel=2.0 */
504 static double fudge_y = 0.5;
505
506 static int thresh = 5;
507 static int thresh_or = 1;
508
509 static double resid_x = 0.0;
510 static double resid_y = 0.0;
511
512 static double zero_delay = 0.15;
513 static double last_button_click = 0.0;
514
515 static int uinput_always = 0;
516
set_uinput_accel_xy(double fx,double fy)517 static void set_uinput_accel_xy(double fx, double fy) {
518 fudge_x = 1.0/fx;
519 fudge_y = 1.0/fy;
520 rfbLog("set_uinput_accel: fx=%.5f fy=%.5f\n", fx, fy);
521 rfbLog("set_uinput_accel: ix=%.5f iy=%.5f\n", fudge_x, fudge_y);
522 }
523
524 static char *uinput_accel_str = NULL;
525 static char *uinput_thresh_str = NULL;
526
set_uinput_accel(char * str)527 int set_uinput_accel(char *str) {
528 double fx, fy;
529 rfbLog("set_uinput_accel: str=%s\n", str);
530 if (sscanf(str, "%lf+%lf", &fx, &fy) == 2) {
531 set_uinput_accel_xy(fx, fy);
532 } else if (sscanf(str, "%lf", &fx) == 1) {
533 set_uinput_accel_xy(fx, fx);
534 } else {
535 rfbLog("invalid UINPUT accel= option: %s\n", str);
536 return 0;
537 }
538 if (uinput_accel_str) {
539 free(uinput_accel_str);
540 }
541 uinput_accel_str = strdup(str);
542 return 1;
543 }
544
set_uinput_thresh(char * str)545 int set_uinput_thresh(char *str) {
546 rfbLog("set_uinput_thresh: str=%s\n", str);
547 if (str[0] == '+') {
548 thresh_or = 0;
549 }
550 thresh = atoi(str);
551 if (uinput_thresh_str) {
552 free(uinput_thresh_str);
553 }
554 uinput_thresh_str = strdup(str);
555 return 1;
556 }
557
set_uinput_reset(int ms)558 void set_uinput_reset(int ms) {
559 zero_delay = (double) ms/1000.;
560 rfbLog("set_uinput_reset: %d\n", ms);
561 }
562
set_uinput_always(int a)563 void set_uinput_always(int a) {
564 uinput_always = a;
565 }
566
set_uinput_touchscreen(int b)567 void set_uinput_touchscreen(int b) {
568 uinput_touchscreen = b;
569 }
570
set_uinput_abs(int b)571 void set_uinput_abs(int b) {
572 uinput_abs = b;
573 }
574
get_uinput_accel(void)575 char *get_uinput_accel(void) {
576 return uinput_accel_str;
577 }
get_uinput_thresh(void)578 char *get_uinput_thresh(void) {
579 return uinput_thresh_str;
580 }
get_uinput_reset(void)581 int get_uinput_reset(void) {
582 return (int) (1000 * zero_delay);
583 }
584
get_uinput_always(void)585 int get_uinput_always(void) {
586 return uinput_always;
587 }
588
get_uinput_touchscreen(void)589 int get_uinput_touchscreen(void) {
590 return uinput_touchscreen;
591 }
592
get_uinput_abs(void)593 int get_uinput_abs(void) {
594 return uinput_abs;
595 }
596
parse_uinput_str(char * in)597 void parse_uinput_str(char *in) {
598 char *p, *q, *str = strdup(in);
599
600 if (injectable) {
601 free(injectable);
602 injectable = strdup("KMB");
603 }
604
605 uinput_touchscreen = 0;
606 uinput_abs = 0;
607 abs_x = abs_y = 0;
608
609 if (tslib_cal) {
610 free(tslib_cal);
611 tslib_cal = NULL;
612 }
613
614 p = strtok(str, ",");
615 while (p) {
616 if (p[0] == '/') {
617 if (uinput_dev) {
618 free(uinput_dev);
619 }
620 uinput_dev = strdup(p);
621 } else if (strstr(p, "nouinput") == p) {
622 if (uinput_dev) {
623 free(uinput_dev);
624 }
625 uinput_dev = strdup(p);
626 } else if (strstr(p, "accel=") == p) {
627 q = p + strlen("accel=");
628 if (! set_uinput_accel(q)) {
629 clean_up_exit(1);
630 }
631 } else if (strstr(p, "thresh=") == p) {
632 q = p + strlen("thresh=");
633 set_uinput_thresh(q);
634
635 } else if (strstr(p, "reset=") == p) {
636 int n = atoi(p + strlen("reset="));
637 set_uinput_reset(n);
638 } else if (strstr(p, "always=") == p) {
639 int n = atoi(p + strlen("always="));
640 set_uinput_always(n);
641 } else if (strpbrk(p, "KMB") == p) {
642 if (injectable) {
643 free(injectable);
644 }
645 injectable = strdup(p);
646 } else if (strstr(p, "touch_always=") == p) {
647 touch_always = atoi(p + strlen("touch_always="));
648 } else if (strstr(p, "btn_touch=") == p) {
649 btn_touch = atoi(p + strlen("btn_touch="));
650 } else if (strstr(p, "dragskip=") == p) {
651 dragskip = atoi(p + strlen("dragskip="));
652 } else if (strstr(p, "touch") == p) {
653 int gw, gh;
654 q = strchr(p, '=');
655 set_uinput_touchscreen(1);
656 set_uinput_abs(1);
657 if (q && sscanf(q+1, "%dx%d", &gw, &gh) == 2) {
658 abs_x = gw;
659 abs_y = gh;
660 }
661 } else if (strstr(p, "abs") == p) {
662 int gw, gh;
663 q = strchr(p, '=');
664 set_uinput_abs(1);
665 if (q && sscanf(q+1, "%dx%d", &gw, &gh) == 2) {
666 abs_x = gw;
667 abs_y = gh;
668 }
669 } else if (strstr(p, "pressure=") == p) {
670 touch_pressure = atoi(p + strlen("pressure="));
671 } else if (strstr(p, "direct_rel=") == p) {
672 direct_rel_fd = open(p+strlen("direct_rel="), O_WRONLY);
673 if (direct_rel_fd < 0) {
674 rfbLogPerror("uinput: direct_rel open");
675 } else {
676 rfbLog("uinput: opened: %s fd=%d\n", p, direct_rel_fd);
677 }
678 } else if (strstr(p, "direct_abs=") == p) {
679 direct_abs_fd = open(p+strlen("direct_abs="), O_WRONLY);
680 if (direct_abs_fd < 0) {
681 rfbLogPerror("uinput: direct_abs open");
682 } else {
683 rfbLog("uinput: opened: %s fd=%d\n", p, direct_abs_fd);
684 }
685 } else if (strstr(p, "direct_btn=") == p) {
686 direct_btn_fd = open(p+strlen("direct_btn="), O_WRONLY);
687 if (direct_btn_fd < 0) {
688 rfbLogPerror("uinput: direct_btn open");
689 } else {
690 rfbLog("uinput: opened: %s fd=%d\n", p, direct_btn_fd);
691 }
692 } else if (strstr(p, "direct_key=") == p) {
693 direct_key_fd = open(p+strlen("direct_key="), O_WRONLY);
694 if (direct_key_fd < 0) {
695 rfbLogPerror("uinput: direct_key open");
696 } else {
697 rfbLog("uinput: opened: %s fd=%d\n", p, direct_key_fd);
698 }
699 } else if (strstr(p, "tslib_cal=") == p) {
700 tslib_cal = strdup(p+strlen("tslib_cal="));
701 } else {
702 rfbLog("invalid UINPUT option: %s\n", p);
703 clean_up_exit(1);
704 }
705 p = strtok(NULL, ",");
706 }
707 free(str);
708 }
709
ptr_move(int dx,int dy)710 static void ptr_move(int dx, int dy) {
711 #ifdef UINPUT_OK
712 struct input_event ev;
713 int d = direct_rel_fd < 0 ? fd : direct_rel_fd;
714
715 if (injectable && strchr(injectable, 'M') == NULL) {
716 return;
717 }
718
719 memset(&ev, 0, sizeof(ev));
720
721 if (db) fprintf(stderr, "ptr_move(%d, %d) fd=%d\n", dx, dy, d);
722
723 gettimeofday(&ev.time, NULL);
724 ev.type = EV_REL;
725 ev.code = REL_Y;
726 ev.value = dy;
727 write(d, &ev, sizeof(ev));
728
729 ev.type = EV_REL;
730 ev.code = REL_X;
731 ev.value = dx;
732 write(d, &ev, sizeof(ev));
733
734 ev.type = EV_SYN;
735 ev.code = SYN_REPORT;
736 ev.value = 0;
737 write(d, &ev, sizeof(ev));
738 #else
739 if (!dx || !dy) {}
740 #endif
741 }
742
apply_tslib(int * x,int * y)743 static void apply_tslib(int *x, int *y) {
744 double x1 = *x, y1 = *y, x2, y2;
745
746 /* this is the inverse of the tslib linear transform: */
747 x2 = (a[4] * (a[6] * x1 - a[2]) - a[1] * (a[6] * y1 - a[5]))/(a[4]*a[0] - a[1]*a[3]);
748 y2 = (a[0] * (a[6] * y1 - a[5]) - a[3] * (a[6] * x1 - a[2]))/(a[4]*a[0] - a[1]*a[3]);
749
750 *x = (int) x2;
751 *y = (int) y2;
752 }
753
754
ptr_abs(int x,int y,int p)755 static void ptr_abs(int x, int y, int p) {
756 #ifdef UINPUT_OK
757 struct input_event ev;
758 int x0, y0;
759 int d = direct_abs_fd < 0 ? fd : direct_abs_fd;
760
761 if (injectable && strchr(injectable, 'M') == NULL) {
762 return;
763 }
764
765 memset(&ev, 0, sizeof(ev));
766
767 x0 = x;
768 y0 = y;
769
770 if (tslib_cal) {
771 apply_tslib(&x, &y);
772 }
773
774 if (db) fprintf(stderr, "ptr_abs(%d, %d => %d %d, p=%d) fd=%d\n", x0, y0, x, y, p, d);
775
776 gettimeofday(&ev.time, NULL);
777 ev.type = EV_ABS;
778 ev.code = ABS_Y;
779 ev.value = y;
780 write(d, &ev, sizeof(ev));
781
782 ev.type = EV_ABS;
783 ev.code = ABS_X;
784 ev.value = x;
785 write(d, &ev, sizeof(ev));
786
787 if (p >= 0) {
788 ev.type = EV_ABS;
789 ev.code = ABS_PRESSURE;
790 ev.value = p;
791 write(d, &ev, sizeof(ev));
792 }
793
794 ev.type = EV_SYN;
795 ev.code = SYN_REPORT;
796 ev.value = 0;
797 write(d, &ev, sizeof(ev));
798 #else
799 if (!x || !y) {}
800 #endif
801 }
802
inside_thresh(int dx,int dy,int thr)803 static int inside_thresh(int dx, int dy, int thr) {
804 if (thresh_or) {
805 /* this is peeking at qt-embedded qmouse_qws.cpp */
806 if (nabs(dx) <= thresh && nabs(dy) <= thr) {
807 return 1;
808 }
809 } else {
810 /* this is peeking at xfree/xorg xf86Xinput.c */
811 if (nabs(dx) + nabs(dy) < thr) {
812 return 1;
813 }
814 }
815 return 0;
816 }
817
ptr_rel(int dx,int dy)818 static void ptr_rel(int dx, int dy) {
819 int dxf, dyf, nx, ny, k;
820 int accel, thresh_high, thresh_mid;
821 double fx, fy;
822 static int try_threshes = -1;
823
824 if (try_threshes < 0) {
825 if (getenv("X11VNC_UINPUT_THRESHOLDS")) {
826 try_threshes = 1;
827 } else {
828 try_threshes = 0;
829 }
830 }
831
832 if (try_threshes) {
833 thresh_high = (int) ( (double) thresh/fudge_x );
834 thresh_mid = (int) ( (double) (thresh + thresh_high) / 2.0 );
835
836 if (thresh_mid <= thresh) {
837 thresh_mid = thresh + 1;
838 }
839 if (thresh_high <= thresh_mid) {
840 thresh_high = thresh_mid + 1;
841 }
842
843 if (inside_thresh(dx, dy, thresh)) {
844 accel = 0;
845 } else {
846 accel = 1;
847 }
848 nx = nabs(dx);
849 ny = nabs(dy);
850
851 } else {
852 accel = 1;
853 thresh_high = 0;
854 nx = ny = 1;
855 }
856
857 if (accel && nx + ny > 0 ) {
858 if (thresh_high > 0 && inside_thresh(dx, dy, thresh_high)) {
859 double alpha, t;
860 /* XXX */
861 if (1 || inside_thresh(dx, dy, thresh_mid)) {
862 t = thresh;
863 accel = 2;
864 } else {
865 accel = 3;
866 t = thresh_high;
867 }
868 if (thresh_or) {
869 if (nx > ny) {
870 fx = t;
871 fy = ((double) ny / (double) nx) * t;
872 } else {
873 fx = ((double) nx / (double) ny) * t;
874 fy = t;
875 }
876 dxf = (int) fx;
877 dyf = (int) fy;
878 fx = dx;
879 fy = dy;
880
881 } else {
882 if (t > 1) {
883 /* XXX */
884 t = t - 1.0;
885 }
886 alpha = t/(nx + ny);
887 fx = alpha * dx;
888 fy = alpha * dy;
889 dxf = (int) fx;
890 dyf = (int) fy;
891 fx = dx;
892 fy = dy;
893 }
894 } else {
895 fx = fudge_x * (double) dx;
896 fy = fudge_y * (double) dy;
897 dxf = (int) fx;
898 dyf = (int) fy;
899 }
900 } else {
901 fx = dx;
902 fy = dy;
903 dxf = dx;
904 dyf = dy;
905 }
906
907 if (db > 1) fprintf(stderr, "old dx dy: %d %d\n", dx, dy);
908 if (db > 1) fprintf(stderr, "new dx dy: %d %d accel: %d\n", dxf, dyf, accel);
909
910 ptr_move(dxf, dyf);
911
912 resid_x += fx - dxf;
913 resid_y += fy - dyf;
914
915 for (k = 0; k < 4; k++) {
916 if (resid_x <= -1.0 || resid_x >= 1.0 || resid_y <= -1.0 || resid_y >= 1.0) {
917 dxf = 0;
918 dyf = 0;
919 if (resid_x >= 1.0) {
920 dxf = (int) resid_x;
921 dxf = 1;
922 } else if (resid_x <= -1.0) {
923 dxf = -((int) (-resid_x));
924 dxf = -1;
925 }
926 resid_x -= dxf;
927 if (resid_y >= 1.0) {
928 dyf = (int) resid_y;
929 dyf = 1;
930 } else if (resid_y <= -1.0) {
931 dyf = -((int) (-resid_y));
932 dyf = -1;
933 }
934 resid_y -= dyf;
935
936 if (db > 1) fprintf(stderr, "*%s resid: dx dy: %d %d %f %f\n", accel > 1 ? "*" : " ", dxf, dyf, resid_x, resid_y);
937 if (0) {usleep(100*1000) ;}
938 ptr_move(dxf, dyf);
939 }
940 }
941 }
942
button_click(int down,int btn)943 static void button_click(int down, int btn) {
944 #ifdef UINPUT_OK
945 struct input_event ev;
946 int d = direct_btn_fd < 0 ? fd : direct_btn_fd;
947
948 if (injectable && strchr(injectable, 'B') == NULL) {
949 return;
950 }
951
952 if (db) fprintf(stderr, "button_click: btn %d %s fd=%d\n", btn, down ? "down" : "up", d);
953
954 memset(&ev, 0, sizeof(ev));
955 gettimeofday(&ev.time, NULL);
956 ev.type = EV_KEY;
957 ev.value = down;
958
959 if (uinput_touchscreen) {
960 ev.code = BTN_TOUCH;
961 if (db) fprintf(stderr, "set code to BTN_TOUCH\n");
962 } else if (btn == 1) {
963 ev.code = BTN_LEFT;
964 } else if (btn == 2) {
965 ev.code = BTN_MIDDLE;
966 } else if (btn == 3) {
967 ev.code = BTN_RIGHT;
968 } else if (btn == 4) {
969 ev.code = BTN_FORWARD;
970 } else if (btn == 5) {
971 ev.code = BTN_BACK;
972 } else {
973 return;
974 }
975
976 write(d, &ev, sizeof(ev));
977
978 ev.type = EV_SYN;
979 ev.code = SYN_REPORT;
980 ev.value = 0;
981 write(d, &ev, sizeof(ev));
982
983 last_button_click = dnow();
984 #else
985 if (!down || !btn) {}
986 #endif
987 }
988
989
uinput_pointer_command(int mask,int x,int y,rfbClientPtr client)990 void uinput_pointer_command(int mask, int x, int y, rfbClientPtr client) {
991 static int last_x = -1, last_y = -1, last_mask = -1;
992 static double last_zero = 0.0;
993 allowed_input_t input;
994 int do_reset, reset_lower_right = 1;
995 double now;
996 static int first = 1;
997
998 if (first) {
999 if (getenv("RESET_ALWAYS")) {
1000 set_uinput_always(1);
1001 } else {
1002 set_uinput_always(0);
1003 }
1004 }
1005 first = 0;
1006
1007 if (db) fprintf(stderr, "uinput_pointer_command: %d %d - %d\n", x, y, mask);
1008
1009 if (view_only) {
1010 return;
1011 }
1012 get_allowed_input(client, &input);
1013
1014 now = dnow();
1015
1016 do_reset = 1;
1017 if (mask || bmask) {
1018 do_reset = 0; /* do not do reset if mouse button down */
1019 } else if (! input.motion) {
1020 do_reset = 0;
1021 } else if (now < last_zero + zero_delay) {
1022 do_reset = 0;
1023 }
1024 if (do_reset) {
1025 if (mod_is_down()) {
1026 do_reset = 0;
1027 } else if (now < last_button_click + 0.25) {
1028 do_reset = 0;
1029 }
1030 }
1031
1032 if (uinput_always && !mask && !bmask && input.motion) {
1033 do_reset = 1;
1034 }
1035 if (uinput_abs) {
1036 do_reset = 0;
1037 }
1038
1039 if (do_reset) {
1040 static int first = 1;
1041
1042 if (zero_delay > 0.0 || first) {
1043 /* try to push it to 0,0 */
1044 int tx, ty, bigjump = 1;
1045
1046 if (reset_lower_right) {
1047 tx = fudge_x * (dpy_x - last_x);
1048 ty = fudge_y * (dpy_y - last_y);
1049 } else {
1050 tx = fudge_x * last_x;
1051 ty = fudge_y * last_y;
1052 }
1053
1054 tx += 50;
1055 ty += 50;
1056
1057 if (bigjump) {
1058 if (reset_lower_right) {
1059 ptr_move(0, +ty);
1060 usleep(2*1000);
1061 ptr_move(+tx, +ty);
1062 ptr_move(+tx, +ty);
1063 } else {
1064 ptr_move(0, -ty);
1065 usleep(2*1000);
1066 ptr_move(-tx, -ty);
1067 ptr_move(-tx, -ty);
1068 }
1069 } else {
1070 int i, step, n = 20;
1071 step = dpy_x / n;
1072
1073 if (step < 100) step = 100;
1074
1075 for (i=0; i < n; i++) {
1076 if (reset_lower_right) {
1077 ptr_move(+step, +step);
1078 } else {
1079 ptr_move(-step, -step);
1080 }
1081 }
1082 for (i=0; i < n; i++) {
1083 if (reset_lower_right) {
1084 ptr_move(+1, +1);
1085 } else {
1086 ptr_move(-1, -1);
1087 }
1088 }
1089 }
1090 if (db) {
1091 if (reset_lower_right) {
1092 fprintf(stderr, "uinput_pointer_command: reset -> (W,H) (%d,%d) [%d,%d]\n", x, y, tx, ty);
1093 } else {
1094 fprintf(stderr, "uinput_pointer_command: reset -> (0,0) (%d,%d) [%d,%d]\n", x, y, tx, ty);
1095 }
1096 }
1097
1098 /* rest a bit for system to absorb the change */
1099 if (uinput_always) {
1100 static double last_sleep = 0.0;
1101 double nw = dnow(), delay = zero_delay;
1102 if (delay <= 0.0) delay = 0.1;
1103 if (nw > last_sleep + delay) {
1104 usleep(10*1000);
1105 last_sleep = nw;
1106 } else {
1107 usleep(1*1000);
1108 }
1109
1110 } else {
1111 usleep(30*1000);
1112 }
1113
1114 /* now jump back out */
1115 if (reset_lower_right) {
1116 ptr_rel(x - dpy_x, y - dpy_y);
1117 } else {
1118 ptr_rel(x, y);
1119 }
1120 if (1) {usleep(10*1000) ;}
1121
1122 last_x = x;
1123 last_y = y;
1124 resid_x = 0.0;
1125 resid_y = 0.0;
1126
1127 first = 0;
1128 }
1129 last_zero = dnow();
1130 }
1131
1132 if (input.motion) {
1133 if (x != last_x || y != last_y) {
1134 if (uinput_touchscreen) {
1135 ;
1136 } else if (uinput_abs) {
1137 ptr_abs(x, y, -1);
1138 } else {
1139 ptr_rel(x - last_x, y - last_y);
1140 }
1141 last_x = x;
1142 last_y = y;
1143 }
1144 }
1145
1146 if (! input.button) {
1147 return;
1148 }
1149
1150 if (last_mask < 0) {
1151 last_mask = mask;
1152 }
1153
1154 if (db > 2) {
1155 fprintf(stderr, "mask: %s\n", bitprint(mask, 16));
1156 fprintf(stderr, "bmask: %s\n", bitprint(bmask, 16));
1157 fprintf(stderr, "last_mask: %s\n", bitprint(last_mask, 16));
1158 fprintf(stderr, "button_mask: %s\n", bitprint(button_mask, 16));
1159 }
1160
1161 if (uinput_touchscreen) {
1162 if (!btn_touch) {
1163 static int down_count = 0;
1164 int p = touch_pressure >=0 ? touch_pressure : 0;
1165 if (!last_mask && !mask) {
1166 if (touch_always) {
1167 ptr_abs(last_x, last_y, 0);
1168 }
1169 } else if (!last_mask && mask) {
1170 ptr_abs(last_x, last_y, p);
1171 down_count = 0;
1172 } else if (last_mask && !mask) {
1173 ptr_abs(last_x, last_y, 0);
1174 } else if (last_mask && mask) {
1175 down_count++;
1176 if (dragskip > 0) {
1177 if (down_count % dragskip == 0) {
1178 ptr_abs(last_x, last_y, p);
1179 }
1180 } else {
1181 ptr_abs(last_x, last_y, p);
1182 }
1183 }
1184 } else {
1185 if (!last_mask && !mask) {
1186 if (touch_always) {
1187 ptr_abs(last_x, last_y, 0);
1188 }
1189 } else if (!last_mask && mask) {
1190 ptr_abs(last_x, last_y, 0);
1191 button_click(1, 0);
1192 } else if (last_mask && !mask) {
1193 ptr_abs(last_x, last_y, 0);
1194 button_click(0, 0);
1195 } else if (last_mask && mask) {
1196 ;
1197 }
1198 }
1199 last_mask = mask;
1200 } else if (mask != last_mask) {
1201 int i;
1202 for (i=1; i <= MAX_BUTTONS; i++) {
1203 int down, b = 1 << (i-1);
1204 if ( (last_mask & b) == (mask & b)) {
1205 continue;
1206 }
1207 if (mask & b) {
1208 down = 1;
1209 } else {
1210 down = 0;
1211 }
1212 button_click(down, i);
1213 }
1214 if (mask && uinput_abs && touch_pressure >= 0) {
1215 ptr_abs(last_x, last_y, touch_pressure);
1216 }
1217 last_mask = mask;
1218 }
1219 bmask = mask;
1220 }
1221
uinput_key_command(int down,int keysym,rfbClientPtr client)1222 void uinput_key_command(int down, int keysym, rfbClientPtr client) {
1223 #ifdef UINPUT_OK
1224 struct input_event ev;
1225 int scancode;
1226 allowed_input_t input;
1227 int d = direct_key_fd < 0 ? fd : direct_key_fd;
1228
1229 if (injectable && strchr(injectable, 'K') == NULL) {
1230 return;
1231 }
1232 if (view_only) {
1233 return;
1234 }
1235 get_allowed_input(client, &input);
1236 if (! input.keystroke) {
1237 return;
1238 }
1239
1240 scancode = lookup_code(keysym);
1241
1242 if (scancode < 0) {
1243 return;
1244 }
1245 if (db) fprintf(stderr, "uinput_key_command: %d -> %d %s fd=%d\n", keysym, scancode, down ? "down" : "up", d);
1246
1247 memset(&ev, 0, sizeof(ev));
1248 gettimeofday(&ev.time, NULL);
1249 ev.type = EV_KEY;
1250 ev.code = (unsigned char) scancode;
1251 ev.value = down;
1252
1253 write(d, &ev, sizeof(ev));
1254
1255 ev.type = EV_SYN;
1256 ev.code = SYN_REPORT;
1257 ev.value = 0;
1258 write(d, &ev, sizeof(ev));
1259
1260 if (0 <= scancode && scancode < 256) {
1261 key_pressed[scancode] = down ? 1 : 0;
1262 }
1263 #else
1264 if (!down || !keysym || !client) {}
1265 #endif
1266 }
1267
1268 #if 0
1269 grep 'case XK_' x0vnc.c | sed -e 's/case /$key_lookup{/' -e 's/:/}/' -e 's/return /= $/'
1270 #endif
1271
lookup_code(int keysym)1272 static int lookup_code(int keysym) {
1273
1274 if (keysym == NoSymbol) {
1275 return -1;
1276 }
1277
1278 switch(keysym) {
1279 #ifdef UINPUT_OK
1280 case XK_Escape: return KEY_ESC;
1281 case XK_1: return KEY_1;
1282 case XK_2: return KEY_2;
1283 case XK_3: return KEY_3;
1284 case XK_4: return KEY_4;
1285 case XK_5: return KEY_5;
1286 case XK_6: return KEY_6;
1287 case XK_7: return KEY_7;
1288 case XK_8: return KEY_8;
1289 case XK_9: return KEY_9;
1290 case XK_0: return KEY_0;
1291 case XK_exclam: return KEY_1;
1292 case XK_at: return KEY_2;
1293 case XK_numbersign: return KEY_3;
1294 case XK_dollar: return KEY_4;
1295 case XK_percent: return KEY_5;
1296 case XK_asciicircum: return KEY_6;
1297 case XK_ampersand: return KEY_7;
1298 case XK_asterisk: return KEY_8;
1299 case XK_parenleft: return KEY_9;
1300 case XK_parenright: return KEY_0;
1301 case XK_minus: return KEY_MINUS;
1302 case XK_underscore: return KEY_MINUS;
1303 case XK_equal: return KEY_EQUAL;
1304 case XK_plus: return KEY_EQUAL;
1305 case XK_BackSpace: return KEY_BACKSPACE;
1306 case XK_Tab: return KEY_TAB;
1307 case XK_q: return KEY_Q;
1308 case XK_Q: return KEY_Q;
1309 case XK_w: return KEY_W;
1310 case XK_W: return KEY_W;
1311 case XK_e: return KEY_E;
1312 case XK_E: return KEY_E;
1313 case XK_r: return KEY_R;
1314 case XK_R: return KEY_R;
1315 case XK_t: return KEY_T;
1316 case XK_T: return KEY_T;
1317 case XK_y: return KEY_Y;
1318 case XK_Y: return KEY_Y;
1319 case XK_u: return KEY_U;
1320 case XK_U: return KEY_U;
1321 case XK_i: return KEY_I;
1322 case XK_I: return KEY_I;
1323 case XK_o: return KEY_O;
1324 case XK_O: return KEY_O;
1325 case XK_p: return KEY_P;
1326 case XK_P: return KEY_P;
1327 case XK_braceleft: return KEY_LEFTBRACE;
1328 case XK_braceright: return KEY_RIGHTBRACE;
1329 case XK_bracketleft: return KEY_LEFTBRACE;
1330 case XK_bracketright: return KEY_RIGHTBRACE;
1331 case XK_Return: return KEY_ENTER;
1332 case XK_Control_L: return KEY_LEFTCTRL;
1333 case XK_a: return KEY_A;
1334 case XK_A: return KEY_A;
1335 case XK_s: return KEY_S;
1336 case XK_S: return KEY_S;
1337 case XK_d: return KEY_D;
1338 case XK_D: return KEY_D;
1339 case XK_f: return KEY_F;
1340 case XK_F: return KEY_F;
1341 case XK_g: return KEY_G;
1342 case XK_G: return KEY_G;
1343 case XK_h: return KEY_H;
1344 case XK_H: return KEY_H;
1345 case XK_j: return KEY_J;
1346 case XK_J: return KEY_J;
1347 case XK_k: return KEY_K;
1348 case XK_K: return KEY_K;
1349 case XK_l: return KEY_L;
1350 case XK_L: return KEY_L;
1351 case XK_semicolon: return KEY_SEMICOLON;
1352 case XK_colon: return KEY_SEMICOLON;
1353 case XK_apostrophe: return KEY_APOSTROPHE;
1354 case XK_quotedbl: return KEY_APOSTROPHE;
1355 case XK_grave: return KEY_GRAVE;
1356 case XK_asciitilde: return KEY_GRAVE;
1357 case XK_Shift_L: return KEY_LEFTSHIFT;
1358 case XK_backslash: return KEY_BACKSLASH;
1359 case XK_bar: return KEY_BACKSLASH;
1360 case XK_z: return KEY_Z;
1361 case XK_Z: return KEY_Z;
1362 case XK_x: return KEY_X;
1363 case XK_X: return KEY_X;
1364 case XK_c: return KEY_C;
1365 case XK_C: return KEY_C;
1366 case XK_v: return KEY_V;
1367 case XK_V: return KEY_V;
1368 case XK_b: return KEY_B;
1369 case XK_B: return KEY_B;
1370 case XK_n: return KEY_N;
1371 case XK_N: return KEY_N;
1372 case XK_m: return KEY_M;
1373 case XK_M: return KEY_M;
1374 case XK_comma: return KEY_COMMA;
1375 case XK_less: return KEY_COMMA;
1376 case XK_period: return KEY_DOT;
1377 case XK_greater: return KEY_DOT;
1378 case XK_slash: return KEY_SLASH;
1379 case XK_question: return KEY_SLASH;
1380 case XK_Shift_R: return KEY_RIGHTSHIFT;
1381 case XK_KP_Multiply: return KEY_KPASTERISK;
1382 case XK_Alt_L: return KEY_LEFTALT;
1383 case XK_space: return KEY_SPACE;
1384 case XK_Caps_Lock: return KEY_CAPSLOCK;
1385 case XK_F1: return KEY_F1;
1386 case XK_F2: return KEY_F2;
1387 case XK_F3: return KEY_F3;
1388 case XK_F4: return KEY_F4;
1389 case XK_F5: return KEY_F5;
1390 case XK_F6: return KEY_F6;
1391 case XK_F7: return KEY_F7;
1392 case XK_F8: return KEY_F8;
1393 case XK_F9: return KEY_F9;
1394 case XK_F10: return KEY_F10;
1395 case XK_Num_Lock: return KEY_NUMLOCK;
1396 case XK_Scroll_Lock: return KEY_SCROLLLOCK;
1397 case XK_KP_7: return KEY_KP7;
1398 case XK_KP_8: return KEY_KP8;
1399 case XK_KP_9: return KEY_KP9;
1400 case XK_KP_Subtract: return KEY_KPMINUS;
1401 case XK_KP_4: return KEY_KP4;
1402 case XK_KP_5: return KEY_KP5;
1403 case XK_KP_6: return KEY_KP6;
1404 case XK_KP_Add: return KEY_KPPLUS;
1405 case XK_KP_1: return KEY_KP1;
1406 case XK_KP_2: return KEY_KP2;
1407 case XK_KP_3: return KEY_KP3;
1408 case XK_KP_0: return KEY_KP0;
1409 case XK_KP_Decimal: return KEY_KPDOT;
1410 case XK_F13: return KEY_F13;
1411 case XK_F11: return KEY_F11;
1412 case XK_F12: return KEY_F12;
1413 case XK_F14: return KEY_F14;
1414 case XK_F15: return KEY_F15;
1415 case XK_F16: return KEY_F16;
1416 case XK_F17: return KEY_F17;
1417 case XK_F18: return KEY_F18;
1418 case XK_F19: return KEY_F19;
1419 case XK_F20: return KEY_F20;
1420 case XK_KP_Enter: return KEY_KPENTER;
1421 case XK_Control_R: return KEY_RIGHTCTRL;
1422 case XK_KP_Divide: return KEY_KPSLASH;
1423 case XK_Sys_Req: return KEY_SYSRQ;
1424 case XK_Alt_R: return KEY_RIGHTALT;
1425 case XK_Linefeed: return KEY_LINEFEED;
1426 case XK_Home: return KEY_HOME;
1427 case XK_Up: return KEY_UP;
1428 case XK_Page_Up: return KEY_PAGEUP;
1429 case XK_Left: return KEY_LEFT;
1430 case XK_Right: return KEY_RIGHT;
1431 case XK_End: return KEY_END;
1432 case XK_Down: return KEY_DOWN;
1433 case XK_Page_Down: return KEY_PAGEDOWN;
1434 case XK_Insert: return KEY_INSERT;
1435 case XK_Delete: return KEY_DELETE;
1436 case XK_KP_Equal: return KEY_KPEQUAL;
1437 case XK_Pause: return KEY_PAUSE;
1438 case XK_F21: return KEY_F21;
1439 case XK_F22: return KEY_F22;
1440 case XK_F23: return KEY_F23;
1441 case XK_F24: return KEY_F24;
1442 case XK_KP_Separator: return KEY_KPCOMMA;
1443 case XK_Meta_L: return KEY_LEFTMETA;
1444 case XK_Meta_R: return KEY_RIGHTMETA;
1445 case XK_Multi_key: return KEY_COMPOSE;
1446 #endif
1447 default: return -1;
1448 }
1449 }
1450
1451 #if 0
1452
1453 From /usr/include/linux/input.h
1454
1455 We maintain it here since it is such a painful mess.
1456
1457 Here is a little script to make it easier:
1458
1459 #!/usr/bin/perl
1460 while (<>) {
1461 $_ =~ s/-XK_/XK_/;
1462 next unless /^XK_/;
1463 chomp;
1464 if (/^(\S+)(\s+)(\S+)/) {
1465 $a = $1;
1466 $t = $2;
1467 $b = $3;
1468 print "\tcase $a:${t}return $b;\n";
1469 if ($a =~ /XK_[a-z]$/) {
1470 $a = uc($a);
1471 print "\tcase $a:${t}return $b;\n";
1472 }
1473 }
1474 }
1475
1476 This only handles US kbd, we would need a kbd database in general...
1477 Ugh: parse dumpkeys(1) or -fookeys /usr/share/keymaps/i386/qwerty/dk.kmap.gz
1478
1479 XK_Escape KEY_ESC
1480 XK_1 KEY_1
1481 XK_2 KEY_2
1482 XK_3 KEY_3
1483 XK_4 KEY_4
1484 XK_5 KEY_5
1485 XK_6 KEY_6
1486 XK_7 KEY_7
1487 XK_8 KEY_8
1488 XK_9 KEY_9
1489 XK_0 KEY_0
1490 -XK_exclam KEY_1
1491 -XK_at KEY_2
1492 -XK_numbersign KEY_3
1493 -XK_dollar KEY_4
1494 -XK_percent KEY_5
1495 -XK_asciicircum KEY_6
1496 -XK_ampersand KEY_7
1497 -XK_asterisk KEY_8
1498 -XK_parenleft KEY_9
1499 -XK_parenright KEY_0
1500 XK_minus KEY_MINUS
1501 -XK_underscore KEY_MINUS
1502 XK_equal KEY_EQUAL
1503 -XK_plus KEY_EQUAL
1504 XK_BackSpace KEY_BACKSPACE
1505 XK_Tab KEY_TAB
1506 XK_q KEY_Q
1507 XK_w KEY_W
1508 XK_e KEY_E
1509 XK_r KEY_R
1510 XK_t KEY_T
1511 XK_y KEY_Y
1512 XK_u KEY_U
1513 XK_i KEY_I
1514 XK_o KEY_O
1515 XK_p KEY_P
1516 XK_braceleft KEY_LEFTBRACE
1517 XK_braceright KEY_RIGHTBRACE
1518 -XK_bracketleft KEY_LEFTBRACE
1519 -XK_bracketright KEY_RIGHTBRACE
1520 XK_Return KEY_ENTER
1521 XK_Control_L KEY_LEFTCTRL
1522 XK_a KEY_A
1523 XK_s KEY_S
1524 XK_d KEY_D
1525 XK_f KEY_F
1526 XK_g KEY_G
1527 XK_h KEY_H
1528 XK_j KEY_J
1529 XK_k KEY_K
1530 XK_l KEY_L
1531 XK_semicolon KEY_SEMICOLON
1532 -XK_colon KEY_SEMICOLON
1533 XK_apostrophe KEY_APOSTROPHE
1534 -XK_quotedbl KEY_APOSTROPHE
1535 XK_grave KEY_GRAVE
1536 -XK_asciitilde KEY_GRAVE
1537 XK_Shift_L KEY_LEFTSHIFT
1538 XK_backslash KEY_BACKSLASH
1539 -XK_bar KEY_BACKSLASH
1540 XK_z KEY_Z
1541 XK_x KEY_X
1542 XK_c KEY_C
1543 XK_v KEY_V
1544 XK_b KEY_B
1545 XK_n KEY_N
1546 XK_m KEY_M
1547 XK_comma KEY_COMMA
1548 -XK_less KEY_COMMA
1549 XK_period KEY_DOT
1550 -XK_greater KEY_DOT
1551 XK_slash KEY_SLASH
1552 -XK_question KEY_SLASH
1553 XK_Shift_R KEY_RIGHTSHIFT
1554 XK_KP_Multiply KEY_KPASTERISK
1555 XK_Alt_L KEY_LEFTALT
1556 XK_space KEY_SPACE
1557 XK_Caps_Lock KEY_CAPSLOCK
1558 XK_F1 KEY_F1
1559 XK_F2 KEY_F2
1560 XK_F3 KEY_F3
1561 XK_F4 KEY_F4
1562 XK_F5 KEY_F5
1563 XK_F6 KEY_F6
1564 XK_F7 KEY_F7
1565 XK_F8 KEY_F8
1566 XK_F9 KEY_F9
1567 XK_F10 KEY_F10
1568 XK_Num_Lock KEY_NUMLOCK
1569 XK_Scroll_Lock KEY_SCROLLLOCK
1570 XK_KP_7 KEY_KP7
1571 XK_KP_8 KEY_KP8
1572 XK_KP_9 KEY_KP9
1573 XK_KP_Subtract KEY_KPMINUS
1574 XK_KP_4 KEY_KP4
1575 XK_KP_5 KEY_KP5
1576 XK_KP_6 KEY_KP6
1577 XK_KP_Add KEY_KPPLUS
1578 XK_KP_1 KEY_KP1
1579 XK_KP_2 KEY_KP2
1580 XK_KP_3 KEY_KP3
1581 XK_KP_0 KEY_KP0
1582 XK_KP_Decimal KEY_KPDOT
1583 NoSymbol KEY_103RD
1584 XK_F13 KEY_F13
1585 NoSymbol KEY_102ND
1586 XK_F11 KEY_F11
1587 XK_F12 KEY_F12
1588 XK_F14 KEY_F14
1589 XK_F15 KEY_F15
1590 XK_F16 KEY_F16
1591 XK_F17 KEY_F17
1592 XK_F18 KEY_F18
1593 XK_F19 KEY_F19
1594 XK_F20 KEY_F20
1595 XK_KP_Enter KEY_KPENTER
1596 XK_Control_R KEY_RIGHTCTRL
1597 XK_KP_Divide KEY_KPSLASH
1598 XK_Sys_Req KEY_SYSRQ
1599 XK_Alt_R KEY_RIGHTALT
1600 XK_Linefeed KEY_LINEFEED
1601 XK_Home KEY_HOME
1602 XK_Up KEY_UP
1603 XK_Page_Up KEY_PAGEUP
1604 XK_Left KEY_LEFT
1605 XK_Right KEY_RIGHT
1606 XK_End KEY_END
1607 XK_Down KEY_DOWN
1608 XK_Page_Down KEY_PAGEDOWN
1609 XK_Insert KEY_INSERT
1610 XK_Delete KEY_DELETE
1611 NoSymbol KEY_MACRO
1612 NoSymbol KEY_MUTE
1613 NoSymbol KEY_VOLUMEDOWN
1614 NoSymbol KEY_VOLUMEUP
1615 NoSymbol KEY_POWER
1616 XK_KP_Equal KEY_KPEQUAL
1617 NoSymbol KEY_KPPLUSMINUS
1618 XK_Pause KEY_PAUSE
1619 XK_F21 KEY_F21
1620 XK_F22 KEY_F22
1621 XK_F23 KEY_F23
1622 XK_F24 KEY_F24
1623 XK_KP_Separator KEY_KPCOMMA
1624 XK_Meta_L KEY_LEFTMETA
1625 XK_Meta_R KEY_RIGHTMETA
1626 XK_Multi_key KEY_COMPOSE
1627
1628 NoSymbol KEY_STOP
1629 NoSymbol KEY_AGAIN
1630 NoSymbol KEY_PROPS
1631 NoSymbol KEY_UNDO
1632 NoSymbol KEY_FRONT
1633 NoSymbol KEY_COPY
1634 NoSymbol KEY_OPEN
1635 NoSymbol KEY_PASTE
1636 NoSymbol KEY_FIND
1637 NoSymbol KEY_CUT
1638 NoSymbol KEY_HELP
1639 NoSymbol KEY_MENU
1640 NoSymbol KEY_CALC
1641 NoSymbol KEY_SETUP
1642 NoSymbol KEY_SLEEP
1643 NoSymbol KEY_WAKEUP
1644 NoSymbol KEY_FILE
1645 NoSymbol KEY_SENDFILE
1646 NoSymbol KEY_DELETEFILE
1647 NoSymbol KEY_XFER
1648 NoSymbol KEY_PROG1
1649 NoSymbol KEY_PROG2
1650 NoSymbol KEY_WWW
1651 NoSymbol KEY_MSDOS
1652 NoSymbol KEY_COFFEE
1653 NoSymbol KEY_DIRECTION
1654 NoSymbol KEY_CYCLEWINDOWS
1655 NoSymbol KEY_MAIL
1656 NoSymbol KEY_BOOKMARKS
1657 NoSymbol KEY_COMPUTER
1658 NoSymbol KEY_BACK
1659 NoSymbol KEY_FORWARD
1660 NoSymbol KEY_CLOSECD
1661 NoSymbol KEY_EJECTCD
1662 NoSymbol KEY_EJECTCLOSECD
1663 NoSymbol KEY_NEXTSONG
1664 NoSymbol KEY_PLAYPAUSE
1665 NoSymbol KEY_PREVIOUSSONG
1666 NoSymbol KEY_STOPCD
1667 NoSymbol KEY_RECORD
1668 NoSymbol KEY_REWIND
1669 NoSymbol KEY_PHONE
1670 NoSymbol KEY_ISO
1671 NoSymbol KEY_CONFIG
1672 NoSymbol KEY_HOMEPAGE
1673 NoSymbol KEY_REFRESH
1674 NoSymbol KEY_EXIT
1675 NoSymbol KEY_MOVE
1676 NoSymbol KEY_EDIT
1677 NoSymbol KEY_SCROLLUP
1678 NoSymbol KEY_SCROLLDOWN
1679 NoSymbol KEY_KPLEFTPAREN
1680 NoSymbol KEY_KPRIGHTPAREN
1681
1682 NoSymbol KEY_INTL1
1683 NoSymbol KEY_INTL2
1684 NoSymbol KEY_INTL3
1685 NoSymbol KEY_INTL4
1686 NoSymbol KEY_INTL5
1687 NoSymbol KEY_INTL6
1688 NoSymbol KEY_INTL7
1689 NoSymbol KEY_INTL8
1690 NoSymbol KEY_INTL9
1691 NoSymbol KEY_LANG1
1692 NoSymbol KEY_LANG2
1693 NoSymbol KEY_LANG3
1694 NoSymbol KEY_LANG4
1695 NoSymbol KEY_LANG5
1696 NoSymbol KEY_LANG6
1697 NoSymbol KEY_LANG7
1698 NoSymbol KEY_LANG8
1699 NoSymbol KEY_LANG9
1700
1701 NoSymbol KEY_PLAYCD
1702 NoSymbol KEY_PAUSECD
1703 NoSymbol KEY_PROG3
1704 NoSymbol KEY_PROG4
1705 NoSymbol KEY_SUSPEND
1706 NoSymbol KEY_CLOSE
1707 NoSymbol KEY_PLAY
1708 NoSymbol KEY_FASTFORWARD
1709 NoSymbol KEY_BASSBOOST
1710 NoSymbol KEY_PRINT
1711 NoSymbol KEY_HP
1712 NoSymbol KEY_CAMERA
1713 NoSymbol KEY_SOUND
1714 NoSymbol KEY_QUESTION
1715 NoSymbol KEY_EMAIL
1716 NoSymbol KEY_CHAT
1717 NoSymbol KEY_SEARCH
1718 NoSymbol KEY_CONNECT
1719 NoSymbol KEY_FINANCE
1720 NoSymbol KEY_SPORT
1721 NoSymbol KEY_SHOP
1722 NoSymbol KEY_ALTERASE
1723 NoSymbol KEY_CANCEL
1724 NoSymbol KEY_BRIGHTNESSDOWN
1725 NoSymbol KEY_BRIGHTNESSUP
1726 NoSymbol KEY_MEDIA
1727
1728 NoSymbol KEY_UNKNOWN
1729 NoSymbol
1730 NoSymbol BTN_MISC
1731 NoSymbol BTN_0
1732 NoSymbol BTN_1
1733 NoSymbol BTN_2
1734 NoSymbol BTN_3
1735 NoSymbol BTN_4
1736 NoSymbol BTN_5
1737 NoSymbol BTN_6
1738 NoSymbol BTN_7
1739 NoSymbol BTN_8
1740 NoSymbol BTN_9
1741 NoSymbol
1742 NoSymbol BTN_MOUSE
1743 NoSymbol BTN_LEFT
1744 NoSymbol BTN_RIGHT
1745 NoSymbol BTN_MIDDLE
1746 NoSymbol BTN_SIDE
1747 NoSymbol BTN_EXTRA
1748 NoSymbol BTN_FORWARD
1749 NoSymbol BTN_BACK
1750 NoSymbol BTN_TASK
1751 NoSymbol
1752 NoSymbol BTN_JOYSTICK
1753 NoSymbol BTN_TRIGGER
1754 NoSymbol BTN_THUMB
1755 NoSymbol BTN_THUMB2
1756 NoSymbol BTN_TOP
1757 NoSymbol BTN_TOP2
1758 NoSymbol BTN_PINKIE
1759 NoSymbol BTN_BASE
1760 NoSymbol BTN_BASE2
1761 NoSymbol BTN_BASE3
1762 NoSymbol BTN_BASE4
1763 NoSymbol BTN_BASE5
1764 NoSymbol BTN_BASE6
1765 NoSymbol BTN_DEAD
1766
1767 NoSymbol BTN_GAMEPAD
1768 NoSymbol BTN_A
1769 NoSymbol BTN_B
1770 NoSymbol BTN_C
1771 NoSymbol BTN_X
1772 NoSymbol BTN_Y
1773 NoSymbol BTN_Z
1774 NoSymbol BTN_TL
1775 NoSymbol BTN_TR
1776 NoSymbol BTN_TL2
1777 NoSymbol BTN_TR2
1778 NoSymbol BTN_SELECT
1779 NoSymbol BTN_START
1780 NoSymbol BTN_MODE
1781 NoSymbol BTN_THUMBL
1782 NoSymbol BTN_THUMBR
1783
1784 NoSymbol BTN_DIGI
1785 NoSymbol BTN_TOOL_PEN
1786 NoSymbol BTN_TOOL_RUBBER
1787 NoSymbol BTN_TOOL_BRUSH
1788 NoSymbol BTN_TOOL_PENCIL
1789 NoSymbol BTN_TOOL_AIRBRUSH
1790 NoSymbol BTN_TOOL_FINGER
1791 NoSymbol BTN_TOOL_MOUSE
1792 NoSymbol BTN_TOOL_LENS
1793 NoSymbol BTN_TOUCH
1794 NoSymbol BTN_STYLUS
1795 NoSymbol BTN_STYLUS2
1796 NoSymbol BTN_TOOL_DOUBLETAP
1797 NoSymbol BTN_TOOL_TRIPLETAP
1798
1799 NoSymbol BTN_WHEEL
1800 NoSymbol BTN_GEAR_DOWN
1801 NoSymbol BTN_GEAR_UP
1802
1803 NoSymbol KEY_OK
1804 NoSymbol KEY_SELECT
1805 NoSymbol KEY_GOTO
1806 NoSymbol KEY_CLEAR
1807 NoSymbol KEY_POWER2
1808 NoSymbol KEY_OPTION
1809 NoSymbol KEY_INFO
1810 NoSymbol KEY_TIME
1811 NoSymbol KEY_VENDOR
1812 NoSymbol KEY_ARCHIVE
1813 NoSymbol KEY_PROGRAM
1814 NoSymbol KEY_CHANNEL
1815 NoSymbol KEY_FAVORITES
1816 NoSymbol KEY_EPG
1817 NoSymbol KEY_PVR
1818 NoSymbol KEY_MHP
1819 NoSymbol KEY_LANGUAGE
1820 NoSymbol KEY_TITLE
1821 NoSymbol KEY_SUBTITLE
1822 NoSymbol KEY_ANGLE
1823 NoSymbol KEY_ZOOM
1824 NoSymbol KEY_MODE
1825 NoSymbol KEY_KEYBOARD
1826 NoSymbol KEY_SCREEN
1827 NoSymbol KEY_PC
1828 NoSymbol KEY_TV
1829 NoSymbol KEY_TV2
1830 NoSymbol KEY_VCR
1831 NoSymbol KEY_VCR2
1832 NoSymbol KEY_SAT
1833 NoSymbol KEY_SAT2
1834 NoSymbol KEY_CD
1835 NoSymbol KEY_TAPE
1836 NoSymbol KEY_RADIO
1837 NoSymbol KEY_TUNER
1838 NoSymbol KEY_PLAYER
1839 NoSymbol KEY_TEXT
1840 NoSymbol KEY_DVD
1841 NoSymbol KEY_AUX
1842 NoSymbol KEY_MP3
1843 NoSymbol KEY_AUDIO
1844 NoSymbol KEY_VIDEO
1845 NoSymbol KEY_DIRECTORY
1846 NoSymbol KEY_LIST
1847 NoSymbol KEY_MEMO
1848 NoSymbol KEY_CALENDAR
1849 NoSymbol KEY_RED
1850 NoSymbol KEY_GREEN
1851 NoSymbol KEY_YELLOW
1852 NoSymbol KEY_BLUE
1853 NoSymbol KEY_CHANNELUP
1854 NoSymbol KEY_CHANNELDOWN
1855 NoSymbol KEY_FIRST
1856 NoSymbol KEY_LAST
1857 NoSymbol KEY_AB
1858 NoSymbol KEY_NEXT
1859 NoSymbol KEY_RESTART
1860 NoSymbol KEY_SLOW
1861 NoSymbol KEY_SHUFFLE
1862 NoSymbol KEY_BREAK
1863 NoSymbol KEY_PREVIOUS
1864 NoSymbol KEY_DIGITS
1865 NoSymbol KEY_TEEN
1866 NoSymbol KEY_TWEN
1867
1868 NoSymbol KEY_DEL_EOL
1869 NoSymbol KEY_DEL_EOS
1870 NoSymbol KEY_INS_LINE
1871 NoSymbol KEY_DEL_LINE
1872 NoSymbol KEY_MAX
1873
1874 #endif
1875
1876
1877