blob: 92bd1d81329bfb247c7dc9fb1312adf1d4d2b38f [file] [log] [blame]
San Mehata430b2b2014-09-23 08:30:51 -07001/*
2 Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3 All rights reserved.
4
5This file is part of x11vnc.
6
7x11vnc is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or (at
10your option) any later version.
11
12x11vnc is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with x11vnc; if not, write to the Free Software
19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20or see <http://www.gnu.org/licenses/>.
21
22In addition, as a special exception, Karl J. Runge
23gives permission to link the code of its release of x11vnc with the
24OpenSSL project's "OpenSSL" library (or with modified versions of it
25that use the same license as the "OpenSSL" library), and distribute
26the linked executables. You must obey the GNU General Public License
27in all respects for all of the code used other than "OpenSSL". If you
28modify this file, you may extend this exception to your version of the
29file, but you are not obligated to do so. If you do not wish to do
30so, 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
64int check_uinput(void);
65int initialize_uinput(void);
66void shutdown_uinput(void);
67int set_uinput_accel(char *str);
68int set_uinput_thresh(char *str);
69void set_uinput_reset(int ms);
70void set_uinput_always(int);
71void set_uinput_touchscreen(int);
72void set_uinput_abs(int);
73char *get_uinput_accel();
74char *get_uinput_thresh();
75int get_uinput_reset();
76int get_uinput_always();
77int get_uinput_touchscreen();
78int get_uinput_abs();
79void parse_uinput_str(char *str);
80void uinput_pointer_command(int mask, int x, int y, rfbClientPtr client);
81void uinput_key_command(int down, int keysym, rfbClientPtr client);
82
83static void init_key_tracker(void);
84static int mod_is_down(void);
85static int key_is_down(void);
86static void set_uinput_accel_xy(double fx, double fy);
87static void ptr_move(int dx, int dy);
88static void ptr_rel(int dx, int dy);
89static void button_click(int down, int btn);
90static int lookup_code(int keysym);
91
92static int fd = -1;
93static int direct_rel_fd = -1;
94static int direct_abs_fd = -1;
95static int direct_btn_fd = -1;
96static int direct_key_fd = -1;
97static int bmask = 0;
98static int db = 0;
99
100static char *injectable = NULL;
101static char *uinput_dev = NULL;
102static char *tslib_cal = NULL;
103static double a[7];
104static int uinput_touchscreen = 0;
105static int uinput_abs = 0;
106static int btn_touch = 0;
107static int dragskip = 0;
108static int touch_always = 0;
109static int touch_pressure = 1;
110static int abs_x = 0, abs_y = 0;
111
112static 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
133int 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
170static int key_pressed[256];
171static int key_ismod[256];
172
173static 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
189static 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
200static 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
210void 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/*
234grep 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 */
236static 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
303static 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
355int 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 */
503static double fudge_x = 0.5; /* accel=2.0 */
504static double fudge_y = 0.5;
505
506static int thresh = 5;
507static int thresh_or = 1;
508
509static double resid_x = 0.0;
510static double resid_y = 0.0;
511
512static double zero_delay = 0.15;
513static double last_button_click = 0.0;
514
515static int uinput_always = 0;
516
517static 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
524static char *uinput_accel_str = NULL;
525static char *uinput_thresh_str = NULL;
526
527int 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
545int 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
558void set_uinput_reset(int ms) {
559 zero_delay = (double) ms/1000.;
560 rfbLog("set_uinput_reset: %d\n", ms);
561}
562
563void set_uinput_always(int a) {
564 uinput_always = a;
565}
566
567void set_uinput_touchscreen(int b) {
568 uinput_touchscreen = b;
569}
570
571void set_uinput_abs(int b) {
572 uinput_abs = b;
573}
574
575char *get_uinput_accel(void) {
576 return uinput_accel_str;
577}
578char *get_uinput_thresh(void) {
579 return uinput_thresh_str;
580}
581int get_uinput_reset(void) {
582 return (int) (1000 * zero_delay);
583}
584
585int get_uinput_always(void) {
586 return uinput_always;
587}
588
589int get_uinput_touchscreen(void) {
590 return uinput_touchscreen;
591}
592
593int get_uinput_abs(void) {
594 return uinput_abs;
595}
596
597void 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
710static 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
743static 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
755static 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
803static 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
818static 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);
937if (0) {usleep(100*1000) ;}
938 ptr_move(dxf, dyf);
939 }
940 }
941}
942
943static 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
990void 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
1222void 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
1272static 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
1453From /usr/include/linux/input.h
1454
1455We maintain it here since it is such a painful mess.
1456
1457Here is a little script to make it easier:
1458
1459#!/usr/bin/perl
1460while (<>) {
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
1476This only handles US kbd, we would need a kbd database in general...
1477Ugh: parse dumpkeys(1) or -fookeys /usr/share/keymaps/i386/qwerty/dk.kmap.gz
1478
1479XK_Escape KEY_ESC
1480XK_1 KEY_1
1481XK_2 KEY_2
1482XK_3 KEY_3
1483XK_4 KEY_4
1484XK_5 KEY_5
1485XK_6 KEY_6
1486XK_7 KEY_7
1487XK_8 KEY_8
1488XK_9 KEY_9
1489XK_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
1500XK_minus KEY_MINUS
1501-XK_underscore KEY_MINUS
1502XK_equal KEY_EQUAL
1503-XK_plus KEY_EQUAL
1504XK_BackSpace KEY_BACKSPACE
1505XK_Tab KEY_TAB
1506XK_q KEY_Q
1507XK_w KEY_W
1508XK_e KEY_E
1509XK_r KEY_R
1510XK_t KEY_T
1511XK_y KEY_Y
1512XK_u KEY_U
1513XK_i KEY_I
1514XK_o KEY_O
1515XK_p KEY_P
1516XK_braceleft KEY_LEFTBRACE
1517XK_braceright KEY_RIGHTBRACE
1518-XK_bracketleft KEY_LEFTBRACE
1519-XK_bracketright KEY_RIGHTBRACE
1520XK_Return KEY_ENTER
1521XK_Control_L KEY_LEFTCTRL
1522XK_a KEY_A
1523XK_s KEY_S
1524XK_d KEY_D
1525XK_f KEY_F
1526XK_g KEY_G
1527XK_h KEY_H
1528XK_j KEY_J
1529XK_k KEY_K
1530XK_l KEY_L
1531XK_semicolon KEY_SEMICOLON
1532-XK_colon KEY_SEMICOLON
1533XK_apostrophe KEY_APOSTROPHE
1534-XK_quotedbl KEY_APOSTROPHE
1535XK_grave KEY_GRAVE
1536-XK_asciitilde KEY_GRAVE
1537XK_Shift_L KEY_LEFTSHIFT
1538XK_backslash KEY_BACKSLASH
1539-XK_bar KEY_BACKSLASH
1540XK_z KEY_Z
1541XK_x KEY_X
1542XK_c KEY_C
1543XK_v KEY_V
1544XK_b KEY_B
1545XK_n KEY_N
1546XK_m KEY_M
1547XK_comma KEY_COMMA
1548-XK_less KEY_COMMA
1549XK_period KEY_DOT
1550-XK_greater KEY_DOT
1551XK_slash KEY_SLASH
1552-XK_question KEY_SLASH
1553XK_Shift_R KEY_RIGHTSHIFT
1554XK_KP_Multiply KEY_KPASTERISK
1555XK_Alt_L KEY_LEFTALT
1556XK_space KEY_SPACE
1557XK_Caps_Lock KEY_CAPSLOCK
1558XK_F1 KEY_F1
1559XK_F2 KEY_F2
1560XK_F3 KEY_F3
1561XK_F4 KEY_F4
1562XK_F5 KEY_F5
1563XK_F6 KEY_F6
1564XK_F7 KEY_F7
1565XK_F8 KEY_F8
1566XK_F9 KEY_F9
1567XK_F10 KEY_F10
1568XK_Num_Lock KEY_NUMLOCK
1569XK_Scroll_Lock KEY_SCROLLLOCK
1570XK_KP_7 KEY_KP7
1571XK_KP_8 KEY_KP8
1572XK_KP_9 KEY_KP9
1573XK_KP_Subtract KEY_KPMINUS
1574XK_KP_4 KEY_KP4
1575XK_KP_5 KEY_KP5
1576XK_KP_6 KEY_KP6
1577XK_KP_Add KEY_KPPLUS
1578XK_KP_1 KEY_KP1
1579XK_KP_2 KEY_KP2
1580XK_KP_3 KEY_KP3
1581XK_KP_0 KEY_KP0
1582XK_KP_Decimal KEY_KPDOT
1583NoSymbol KEY_103RD
1584XK_F13 KEY_F13
1585NoSymbol KEY_102ND
1586XK_F11 KEY_F11
1587XK_F12 KEY_F12
1588XK_F14 KEY_F14
1589XK_F15 KEY_F15
1590XK_F16 KEY_F16
1591XK_F17 KEY_F17
1592XK_F18 KEY_F18
1593XK_F19 KEY_F19
1594XK_F20 KEY_F20
1595XK_KP_Enter KEY_KPENTER
1596XK_Control_R KEY_RIGHTCTRL
1597XK_KP_Divide KEY_KPSLASH
1598XK_Sys_Req KEY_SYSRQ
1599XK_Alt_R KEY_RIGHTALT
1600XK_Linefeed KEY_LINEFEED
1601XK_Home KEY_HOME
1602XK_Up KEY_UP
1603XK_Page_Up KEY_PAGEUP
1604XK_Left KEY_LEFT
1605XK_Right KEY_RIGHT
1606XK_End KEY_END
1607XK_Down KEY_DOWN
1608XK_Page_Down KEY_PAGEDOWN
1609XK_Insert KEY_INSERT
1610XK_Delete KEY_DELETE
1611NoSymbol KEY_MACRO
1612NoSymbol KEY_MUTE
1613NoSymbol KEY_VOLUMEDOWN
1614NoSymbol KEY_VOLUMEUP
1615NoSymbol KEY_POWER
1616XK_KP_Equal KEY_KPEQUAL
1617NoSymbol KEY_KPPLUSMINUS
1618XK_Pause KEY_PAUSE
1619XK_F21 KEY_F21
1620XK_F22 KEY_F22
1621XK_F23 KEY_F23
1622XK_F24 KEY_F24
1623XK_KP_Separator KEY_KPCOMMA
1624XK_Meta_L KEY_LEFTMETA
1625XK_Meta_R KEY_RIGHTMETA
1626XK_Multi_key KEY_COMPOSE
1627
1628NoSymbol KEY_STOP
1629NoSymbol KEY_AGAIN
1630NoSymbol KEY_PROPS
1631NoSymbol KEY_UNDO
1632NoSymbol KEY_FRONT
1633NoSymbol KEY_COPY
1634NoSymbol KEY_OPEN
1635NoSymbol KEY_PASTE
1636NoSymbol KEY_FIND
1637NoSymbol KEY_CUT
1638NoSymbol KEY_HELP
1639NoSymbol KEY_MENU
1640NoSymbol KEY_CALC
1641NoSymbol KEY_SETUP
1642NoSymbol KEY_SLEEP
1643NoSymbol KEY_WAKEUP
1644NoSymbol KEY_FILE
1645NoSymbol KEY_SENDFILE
1646NoSymbol KEY_DELETEFILE
1647NoSymbol KEY_XFER
1648NoSymbol KEY_PROG1
1649NoSymbol KEY_PROG2
1650NoSymbol KEY_WWW
1651NoSymbol KEY_MSDOS
1652NoSymbol KEY_COFFEE
1653NoSymbol KEY_DIRECTION
1654NoSymbol KEY_CYCLEWINDOWS
1655NoSymbol KEY_MAIL
1656NoSymbol KEY_BOOKMARKS
1657NoSymbol KEY_COMPUTER
1658NoSymbol KEY_BACK
1659NoSymbol KEY_FORWARD
1660NoSymbol KEY_CLOSECD
1661NoSymbol KEY_EJECTCD
1662NoSymbol KEY_EJECTCLOSECD
1663NoSymbol KEY_NEXTSONG
1664NoSymbol KEY_PLAYPAUSE
1665NoSymbol KEY_PREVIOUSSONG
1666NoSymbol KEY_STOPCD
1667NoSymbol KEY_RECORD
1668NoSymbol KEY_REWIND
1669NoSymbol KEY_PHONE
1670NoSymbol KEY_ISO
1671NoSymbol KEY_CONFIG
1672NoSymbol KEY_HOMEPAGE
1673NoSymbol KEY_REFRESH
1674NoSymbol KEY_EXIT
1675NoSymbol KEY_MOVE
1676NoSymbol KEY_EDIT
1677NoSymbol KEY_SCROLLUP
1678NoSymbol KEY_SCROLLDOWN
1679NoSymbol KEY_KPLEFTPAREN
1680NoSymbol KEY_KPRIGHTPAREN
1681
1682NoSymbol KEY_INTL1
1683NoSymbol KEY_INTL2
1684NoSymbol KEY_INTL3
1685NoSymbol KEY_INTL4
1686NoSymbol KEY_INTL5
1687NoSymbol KEY_INTL6
1688NoSymbol KEY_INTL7
1689NoSymbol KEY_INTL8
1690NoSymbol KEY_INTL9
1691NoSymbol KEY_LANG1
1692NoSymbol KEY_LANG2
1693NoSymbol KEY_LANG3
1694NoSymbol KEY_LANG4
1695NoSymbol KEY_LANG5
1696NoSymbol KEY_LANG6
1697NoSymbol KEY_LANG7
1698NoSymbol KEY_LANG8
1699NoSymbol KEY_LANG9
1700
1701NoSymbol KEY_PLAYCD
1702NoSymbol KEY_PAUSECD
1703NoSymbol KEY_PROG3
1704NoSymbol KEY_PROG4
1705NoSymbol KEY_SUSPEND
1706NoSymbol KEY_CLOSE
1707NoSymbol KEY_PLAY
1708NoSymbol KEY_FASTFORWARD
1709NoSymbol KEY_BASSBOOST
1710NoSymbol KEY_PRINT
1711NoSymbol KEY_HP
1712NoSymbol KEY_CAMERA
1713NoSymbol KEY_SOUND
1714NoSymbol KEY_QUESTION
1715NoSymbol KEY_EMAIL
1716NoSymbol KEY_CHAT
1717NoSymbol KEY_SEARCH
1718NoSymbol KEY_CONNECT
1719NoSymbol KEY_FINANCE
1720NoSymbol KEY_SPORT
1721NoSymbol KEY_SHOP
1722NoSymbol KEY_ALTERASE
1723NoSymbol KEY_CANCEL
1724NoSymbol KEY_BRIGHTNESSDOWN
1725NoSymbol KEY_BRIGHTNESSUP
1726NoSymbol KEY_MEDIA
1727
1728NoSymbol KEY_UNKNOWN
1729NoSymbol
1730NoSymbol BTN_MISC
1731NoSymbol BTN_0
1732NoSymbol BTN_1
1733NoSymbol BTN_2
1734NoSymbol BTN_3
1735NoSymbol BTN_4
1736NoSymbol BTN_5
1737NoSymbol BTN_6
1738NoSymbol BTN_7
1739NoSymbol BTN_8
1740NoSymbol BTN_9
1741NoSymbol
1742NoSymbol BTN_MOUSE
1743NoSymbol BTN_LEFT
1744NoSymbol BTN_RIGHT
1745NoSymbol BTN_MIDDLE
1746NoSymbol BTN_SIDE
1747NoSymbol BTN_EXTRA
1748NoSymbol BTN_FORWARD
1749NoSymbol BTN_BACK
1750NoSymbol BTN_TASK
1751NoSymbol
1752NoSymbol BTN_JOYSTICK
1753NoSymbol BTN_TRIGGER
1754NoSymbol BTN_THUMB
1755NoSymbol BTN_THUMB2
1756NoSymbol BTN_TOP
1757NoSymbol BTN_TOP2
1758NoSymbol BTN_PINKIE
1759NoSymbol BTN_BASE
1760NoSymbol BTN_BASE2
1761NoSymbol BTN_BASE3
1762NoSymbol BTN_BASE4
1763NoSymbol BTN_BASE5
1764NoSymbol BTN_BASE6
1765NoSymbol BTN_DEAD
1766
1767NoSymbol BTN_GAMEPAD
1768NoSymbol BTN_A
1769NoSymbol BTN_B
1770NoSymbol BTN_C
1771NoSymbol BTN_X
1772NoSymbol BTN_Y
1773NoSymbol BTN_Z
1774NoSymbol BTN_TL
1775NoSymbol BTN_TR
1776NoSymbol BTN_TL2
1777NoSymbol BTN_TR2
1778NoSymbol BTN_SELECT
1779NoSymbol BTN_START
1780NoSymbol BTN_MODE
1781NoSymbol BTN_THUMBL
1782NoSymbol BTN_THUMBR
1783
1784NoSymbol BTN_DIGI
1785NoSymbol BTN_TOOL_PEN
1786NoSymbol BTN_TOOL_RUBBER
1787NoSymbol BTN_TOOL_BRUSH
1788NoSymbol BTN_TOOL_PENCIL
1789NoSymbol BTN_TOOL_AIRBRUSH
1790NoSymbol BTN_TOOL_FINGER
1791NoSymbol BTN_TOOL_MOUSE
1792NoSymbol BTN_TOOL_LENS
1793NoSymbol BTN_TOUCH
1794NoSymbol BTN_STYLUS
1795NoSymbol BTN_STYLUS2
1796NoSymbol BTN_TOOL_DOUBLETAP
1797NoSymbol BTN_TOOL_TRIPLETAP
1798
1799NoSymbol BTN_WHEEL
1800NoSymbol BTN_GEAR_DOWN
1801NoSymbol BTN_GEAR_UP
1802
1803NoSymbol KEY_OK
1804NoSymbol KEY_SELECT
1805NoSymbol KEY_GOTO
1806NoSymbol KEY_CLEAR
1807NoSymbol KEY_POWER2
1808NoSymbol KEY_OPTION
1809NoSymbol KEY_INFO
1810NoSymbol KEY_TIME
1811NoSymbol KEY_VENDOR
1812NoSymbol KEY_ARCHIVE
1813NoSymbol KEY_PROGRAM
1814NoSymbol KEY_CHANNEL
1815NoSymbol KEY_FAVORITES
1816NoSymbol KEY_EPG
1817NoSymbol KEY_PVR
1818NoSymbol KEY_MHP
1819NoSymbol KEY_LANGUAGE
1820NoSymbol KEY_TITLE
1821NoSymbol KEY_SUBTITLE
1822NoSymbol KEY_ANGLE
1823NoSymbol KEY_ZOOM
1824NoSymbol KEY_MODE
1825NoSymbol KEY_KEYBOARD
1826NoSymbol KEY_SCREEN
1827NoSymbol KEY_PC
1828NoSymbol KEY_TV
1829NoSymbol KEY_TV2
1830NoSymbol KEY_VCR
1831NoSymbol KEY_VCR2
1832NoSymbol KEY_SAT
1833NoSymbol KEY_SAT2
1834NoSymbol KEY_CD
1835NoSymbol KEY_TAPE
1836NoSymbol KEY_RADIO
1837NoSymbol KEY_TUNER
1838NoSymbol KEY_PLAYER
1839NoSymbol KEY_TEXT
1840NoSymbol KEY_DVD
1841NoSymbol KEY_AUX
1842NoSymbol KEY_MP3
1843NoSymbol KEY_AUDIO
1844NoSymbol KEY_VIDEO
1845NoSymbol KEY_DIRECTORY
1846NoSymbol KEY_LIST
1847NoSymbol KEY_MEMO
1848NoSymbol KEY_CALENDAR
1849NoSymbol KEY_RED
1850NoSymbol KEY_GREEN
1851NoSymbol KEY_YELLOW
1852NoSymbol KEY_BLUE
1853NoSymbol KEY_CHANNELUP
1854NoSymbol KEY_CHANNELDOWN
1855NoSymbol KEY_FIRST
1856NoSymbol KEY_LAST
1857NoSymbol KEY_AB
1858NoSymbol KEY_NEXT
1859NoSymbol KEY_RESTART
1860NoSymbol KEY_SLOW
1861NoSymbol KEY_SHUFFLE
1862NoSymbol KEY_BREAK
1863NoSymbol KEY_PREVIOUS
1864NoSymbol KEY_DIGITS
1865NoSymbol KEY_TEEN
1866NoSymbol KEY_TWEN
1867
1868NoSymbol KEY_DEL_EOL
1869NoSymbol KEY_DEL_EOS
1870NoSymbol KEY_INS_LINE
1871NoSymbol KEY_DEL_LINE
1872NoSymbol KEY_MAX
1873
1874#endif
1875
1876