1 /* 2 Copyright (C) 2002-2010 Karl J. Runge <runge (at) 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 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 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 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 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 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 */ 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 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 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 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 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 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 558 void set_uinput_reset(int ms) { 559 zero_delay = (double) ms/1000.; 560 rfbLog("set_uinput_reset: %d\n", ms); 561 } 562 563 void set_uinput_always(int a) { 564 uinput_always = a; 565 } 566 567 void set_uinput_touchscreen(int b) { 568 uinput_touchscreen = b; 569 } 570 571 void set_uinput_abs(int b) { 572 uinput_abs = b; 573 } 574 575 char *get_uinput_accel(void) { 576 return uinput_accel_str; 577 } 578 char *get_uinput_thresh(void) { 579 return uinput_thresh_str; 580 } 581 int get_uinput_reset(void) { 582 return (int) (1000 * zero_delay); 583 } 584 585 int get_uinput_always(void) { 586 return uinput_always; 587 } 588 589 int get_uinput_touchscreen(void) { 590 return uinput_touchscreen; 591 } 592 593 int get_uinput_abs(void) { 594 return uinput_abs; 595 } 596 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 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 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 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 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 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 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 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 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 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