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 /* -- pointer.c -- */ 34 35 #include "x11vnc.h" 36 #include "xwrappers.h" 37 #include "keyboard.h" 38 #include "xinerama.h" 39 #include "xrecord.h" 40 #include "win_utils.h" 41 #include "cursor.h" 42 #include "userinput.h" 43 #include "connections.h" 44 #include "cleanup.h" 45 #include "unixpw.h" 46 #include "v4l.h" 47 #include "linuxfb.h" 48 #include "uinput.h" 49 #include "scan.h" 50 #include "macosx.h" 51 #include "screen.h" 52 53 int pointer_queued_sent = 0; 54 55 void initialize_pointer_map(char *pointer_remap); 56 void do_button_mask_change(int mask, int button); 57 void pointer_event(int mask, int x, int y, rfbClientPtr client); 58 void initialize_pipeinput(void); 59 int check_pipeinput(void); 60 void update_x11_pointer_position(int x, int y); 61 62 63 static void buttonparse(int from, char **s); 64 static void update_x11_pointer_mask(int mask); 65 static void pipe_pointer(int mask, int x, int y, rfbClientPtr client); 66 67 /* 68 * pointer event (motion and button click) handling routines. 69 */ 70 typedef struct ptrremap { 71 KeySym keysym; 72 KeyCode keycode; 73 int end; 74 int button; 75 int down; 76 int up; 77 } prtremap_t; 78 79 #define MAX_BUTTON_EVENTS 50 80 static prtremap_t pointer_map[MAX_BUTTONS+1][MAX_BUTTON_EVENTS]; 81 82 /* 83 * For parsing the -buttonmap sections, e.g. "4" or ":Up+Up+Up:" 84 */ 85 static void buttonparse(int from, char **s) { 86 #if (0 && NO_X11) 87 if (!from || !s) {} 88 return; 89 #else 90 char *q; 91 int to, i; 92 int modisdown[256]; 93 94 q = *s; 95 96 for (i=0; i<256; i++) { 97 modisdown[i] = 0; 98 } 99 100 if (*q == ':') { 101 /* :sym1+sym2+...+symN: format */ 102 int l = 0, n = 0; 103 char list[1000]; 104 char *t, *kp = q + 1; 105 KeyCode kcode; 106 107 while (*(kp+l) != ':' && *(kp+l) != '\0') { 108 /* loop to the matching ':' */ 109 l++; 110 if (l >= 1000) { 111 rfbLog("buttonparse: keysym list too long: " 112 "%s\n", q); 113 break; 114 } 115 } 116 *(kp+l) = '\0'; 117 strncpy(list, kp, l); 118 list[l] = '\0'; 119 rfbLog("remap button %d using \"%s\"\n", from, list); 120 121 /* loop over tokens separated by '+' */ 122 t = strtok(list, "+"); 123 while (t) { 124 KeySym ksym; 125 unsigned int ui; 126 int i; 127 if (n >= MAX_BUTTON_EVENTS - 20) { 128 rfbLog("buttonparse: too many button map " 129 "events: %s\n", list); 130 break; 131 } 132 if (sscanf(t, "0x%x", &ui) == 1) { 133 ksym = (KeySym) ui; /* hex value */ 134 } else { 135 X_LOCK; 136 ksym = XStringToKeysym(t); /* string value */ 137 X_UNLOCK; 138 } 139 if (ksym == NoSymbol) { 140 /* see if Button<N> "keysym" was used: */ 141 if (sscanf(t, "Button%d", &i) == 1) { 142 rfbLog(" event %d: button %d\n", 143 from, n+1, i); 144 if (i == 0) i = -1; /* bah */ 145 pointer_map[from][n].keysym = NoSymbol; 146 pointer_map[from][n].keycode = NoSymbol; 147 pointer_map[from][n].button = i; 148 pointer_map[from][n].end = 0; 149 pointer_map[from][n].down = 0; 150 pointer_map[from][n].up = 0; 151 } else { 152 rfbLog("buttonparse: ignoring unknown " 153 "keysym: %s\n", t); 154 n--; 155 } 156 } else if (dpy) { 157 /* 158 * XXX may not work with -modtweak or -xkb 159 */ 160 char *str; 161 X_LOCK; 162 #if NO_X11 163 kcode = NoSymbol; 164 #else 165 kcode = XKeysymToKeycode(dpy, ksym); 166 #endif 167 168 pointer_map[from][n].keysym = ksym; 169 pointer_map[from][n].keycode = kcode; 170 pointer_map[from][n].button = 0; 171 pointer_map[from][n].end = 0; 172 if (! ismodkey(ksym) ) { 173 /* do both down then up */ 174 pointer_map[from][n].down = 1; 175 pointer_map[from][n].up = 1; 176 } else { 177 if (modisdown[kcode]) { 178 pointer_map[from][n].down = 0; 179 pointer_map[from][n].up = 1; 180 modisdown[kcode] = 0; 181 } else { 182 pointer_map[from][n].down = 1; 183 pointer_map[from][n].up = 0; 184 modisdown[kcode] = 1; 185 } 186 } 187 str = XKeysymToString(ksym); 188 rfbLog(" event %d: keysym %s (0x%x) -> " 189 "keycode 0x%x down=%d up=%d\n", n+1, 190 str ? str : "null", ksym, kcode, 191 pointer_map[from][n].down, 192 pointer_map[from][n].up); 193 X_UNLOCK; 194 } 195 t = strtok(NULL, "+"); 196 n++; 197 } 198 199 /* we must release any modifiers that are still down: */ 200 for (i=0; i<256; i++) { 201 kcode = (KeyCode) i; 202 if (n >= MAX_BUTTON_EVENTS) { 203 rfbLog("buttonparse: too many button map " 204 "events: %s\n", list); 205 break; 206 } 207 if (modisdown[kcode]) { 208 pointer_map[from][n].keysym = NoSymbol; 209 pointer_map[from][n].keycode = kcode; 210 pointer_map[from][n].button = 0; 211 pointer_map[from][n].end = 0; 212 pointer_map[from][n].down = 0; 213 pointer_map[from][n].up = 1; 214 modisdown[kcode] = 0; 215 n++; 216 } 217 } 218 219 /* advance the source pointer position */ 220 (*s) += l+2; 221 } else { 222 /* single digit format */ 223 char str[2]; 224 str[0] = *q; 225 str[1] = '\0'; 226 227 to = atoi(str); 228 if (to < 1) { 229 rfbLog("skipping invalid remap button \"%d\" for button" 230 " %d from string \"%s\"\n", 231 to, from, str); 232 } else { 233 rfbLog("remap button %d using \"%s\"\n", from, str); 234 rfbLog(" button: %d -> %d\n", from, to); 235 pointer_map[from][0].keysym = NoSymbol; 236 pointer_map[from][0].keycode = NoSymbol; 237 pointer_map[from][0].button = to; 238 pointer_map[from][0].end = 0; 239 pointer_map[from][0].down = 0; 240 pointer_map[from][0].up = 0; 241 } 242 /* advance the source pointer position */ 243 (*s)++; 244 } 245 #endif /* NO_X11 */ 246 } 247 248 /* 249 * process the -buttonmap string 250 */ 251 void initialize_pointer_map(char *pointer_remap) { 252 unsigned char map[MAX_BUTTONS]; 253 int i, k; 254 /* 255 * This routine counts the number of pointer buttons on the X 256 * server (to avoid problems, even crashes, if a client has more 257 * buttons). And also initializes any pointer button remapping 258 * from -buttonmap option. 259 */ 260 261 if (!raw_fb_str) { 262 #if NO_X11 263 num_buttons = 5; 264 #else 265 X_LOCK; 266 num_buttons = XGetPointerMapping(dpy, map, MAX_BUTTONS); 267 X_UNLOCK; 268 rfbLog("The X server says there are %d mouse buttons.\n", num_buttons); 269 #endif 270 } else { 271 num_buttons = 5; 272 rfbLog("Manually set num_buttons to: %d\n", num_buttons); 273 } 274 275 if (num_buttons < 0) { 276 num_buttons = 0; 277 } 278 279 /* FIXME: should use info in map[] */ 280 for (i=1; i<= MAX_BUTTONS; i++) { 281 for (k=0; k < MAX_BUTTON_EVENTS; k++) { 282 pointer_map[i][k].end = 1; 283 } 284 pointer_map[i][0].keysym = NoSymbol; 285 pointer_map[i][0].keycode = NoSymbol; 286 pointer_map[i][0].button = i; 287 pointer_map[i][0].end = 0; 288 pointer_map[i][0].down = 0; 289 pointer_map[i][0].up = 0; 290 } 291 292 if (pointer_remap && *pointer_remap != '\0') { 293 /* -buttonmap, format is like: 12-21=2 */ 294 char *p, *q, *remap = strdup(pointer_remap); 295 int n; 296 297 if ((p = strchr(remap, '=')) != NULL) { 298 /* undocumented max button number */ 299 n = atoi(p+1); 300 *p = '\0'; 301 if (n < num_buttons || num_buttons == 0) { 302 num_buttons = n; 303 } else { 304 rfbLog("warning: increasing number of mouse " 305 "buttons from %d to %d\n", num_buttons, n); 306 num_buttons = n; 307 } 308 } 309 if ((q = strchr(remap, '-')) != NULL) { 310 /* 311 * The '-' separates the 'from' and 'to' lists, 312 * then it is kind of like tr(1). 313 */ 314 char str[2]; 315 int from; 316 317 rfbLog("remapping pointer buttons using string:\n"); 318 rfbLog(" \"%s\"\n", remap); 319 320 p = remap; 321 q++; 322 i = 0; 323 str[1] = '\0'; 324 while (*p != '-') { 325 str[0] = *p; 326 from = atoi(str); 327 buttonparse(from, &q); 328 p++; 329 } 330 } 331 free(remap); 332 } 333 } 334 335 /* 336 * Send a pointer position event to the X server. 337 */ 338 void update_x11_pointer_position(int x, int y) { 339 #if NO_X11 340 RAWFB_RET_VOID 341 if (!x || !y) {} 342 return; 343 #else 344 int rc; 345 346 RAWFB_RET_VOID 347 348 X_LOCK; 349 if (!always_inject && cursor_x == x && cursor_y == y) { 350 ; 351 } else if (use_xwarppointer) { 352 /* 353 * off_x and off_y not needed with XWarpPointer since 354 * window is used: 355 */ 356 XWarpPointer(dpy, None, window, 0, 0, 0, 0, x + coff_x, 357 y + coff_y); 358 } else { 359 XTestFakeMotionEvent_wr(dpy, scr, x + off_x + coff_x, 360 y + off_y + coff_y, CurrentTime); 361 } 362 X_UNLOCK; 363 364 if (cursor_x != x || cursor_y != y) { 365 last_pointer_motion_time = dnow(); 366 } 367 368 cursor_x = x; 369 cursor_y = y; 370 371 /* record the x, y position for the rfb screen as well. */ 372 cursor_position(x, y); 373 374 /* change the cursor shape if necessary */ 375 rc = set_cursor(x, y, get_which_cursor()); 376 cursor_changes += rc; 377 378 last_event = last_input = last_pointer_input = time(NULL); 379 #endif /* NO_X11 */ 380 } 381 382 void do_button_mask_change(int mask, int button) { 383 #if NO_X11 384 if (!mask || !button) {} 385 return; 386 #else 387 int mb, k, i = button-1; 388 389 /* 390 * this expands to any pointer_map button -> keystrokes 391 * remappings. Usually just k=0 and we send one button event. 392 */ 393 for (k=0; k < MAX_BUTTON_EVENTS; k++) { 394 int bmask = (mask & (1<<i)); 395 396 if (pointer_map[i+1][k].end) { 397 break; 398 } 399 400 if (pointer_map[i+1][k].button) { 401 /* send button up or down */ 402 403 mb = pointer_map[i+1][k].button; 404 if ((num_buttons && mb > num_buttons) || mb < 1) { 405 rfbLog("ignoring mouse button out of " 406 "bounds: %d>%d mask: 0x%x -> 0x%x\n", 407 mb, num_buttons, button_mask, mask); 408 continue; 409 } 410 if (debug_pointer) { 411 rfbLog("pointer(): sending button %d" 412 " %s (event %d)\n", mb, bmask 413 ? "down" : "up", k+1); 414 } 415 XTestFakeButtonEvent_wr(dpy, mb, (mask & (1<<i)) 416 ? True : False, CurrentTime); 417 } else { 418 /* send keysym up or down */ 419 KeyCode key = pointer_map[i+1][k].keycode; 420 int up = pointer_map[i+1][k].up; 421 int down = pointer_map[i+1][k].down; 422 423 if (! bmask) { 424 /* do not send keysym on button up */ 425 continue; 426 } 427 if (debug_pointer && dpy) { 428 char *str = XKeysymToString(XKeycodeToKeysym( 429 dpy, key, 0)); 430 rfbLog("pointer(): sending button %d " 431 "down as keycode 0x%x (event %d)\n", 432 i+1, key, k+1); 433 rfbLog(" down=%d up=%d keysym: " 434 "%s\n", down, up, str ? str : "null"); 435 } 436 if (down) { 437 XTestFakeKeyEvent_wr(dpy, key, True, 438 CurrentTime); 439 } 440 if (up) { 441 XTestFakeKeyEvent_wr(dpy, key, False, 442 CurrentTime); 443 } 444 } 445 } 446 #endif /* NO_X11 */ 447 } 448 449 /* 450 * Send a pointer button event to the X server. 451 */ 452 static void update_x11_pointer_mask(int mask) { 453 #if NO_X11 454 last_event = last_input = last_pointer_input = time(NULL); 455 456 RAWFB_RET_VOID 457 if (!mask) {} 458 return; 459 #else 460 int snapped = 0, xr_mouse = 1, i; 461 last_event = last_input = last_pointer_input = time(NULL); 462 463 RAWFB_RET_VOID 464 465 if (mask != button_mask) { 466 last_pointer_click_time = dnow(); 467 } 468 469 if (nofb) { 470 xr_mouse = 0; 471 } else if (!strcmp(scroll_copyrect, "never")) { 472 xr_mouse = 0; 473 } else if (!strcmp(scroll_copyrect, "keys")) { 474 xr_mouse = 0; 475 } else if (skip_cr_when_scaling("scroll")) { 476 xr_mouse = 0; 477 } else if (xrecord_skip_button(mask, button_mask)) { 478 xr_mouse = 0; 479 } 480 481 if (mask && use_xrecord && ! xrecording && xr_mouse) { 482 static int px, py, x, y, w, h, got_wm_frame; 483 static XWindowAttributes attr; 484 Window frame = None, mwin = None; 485 int skip = 0; 486 487 if (!button_mask) { 488 X_LOCK; 489 if (get_wm_frame_pos(&px, &py, &x, &y, &w, &h, 490 &frame, &mwin)) { 491 got_wm_frame = 1; 492 if (debug_scroll > 1) fprintf(stderr, "wm_win: 0x%lx\n", mwin); 493 if (mwin != None) { 494 if (!valid_window(mwin, &attr, 1)) { 495 mwin = None; 496 } 497 } 498 } else { 499 got_wm_frame = 0; 500 } 501 X_UNLOCK; 502 } 503 if (got_wm_frame) { 504 if (wireframe && near_wm_edge(x, y, w, h, px, py)) { 505 /* step out of wireframe's way */ 506 skip = 1; 507 } else { 508 int ok = 0; 509 int btn4 = (1<<3); 510 int btn5 = (1<<4); 511 512 if (near_scrollbar_edge(x, y, w, h, px, py)) { 513 ok = 1; 514 } 515 if (mask & (btn4|btn5)) { 516 /* scroll wheel mouse */ 517 ok = 1; 518 } 519 if (mwin != None) { 520 /* skinny internal window */ 521 int w = attr.width; 522 int h = attr.height; 523 if (h > 10 * w || w > 10 * h) { 524 if (debug_scroll > 1) fprintf(stderr, "internal scrollbar: %dx%d\n", w, h); 525 ok = 1; 526 } 527 } 528 if (! ok) { 529 skip = 1; 530 } 531 } 532 } 533 534 if (! skip) { 535 xrecord_watch(1, SCR_MOUSE); 536 snapshot_stack_list(0, 0.50); 537 snapped = 1; 538 if (button_mask) { 539 xrecord_set_by_mouse = 1; 540 } else { 541 update_stack_list(); 542 xrecord_set_by_mouse = 2; 543 } 544 } 545 } 546 547 if (mask && !button_mask) { 548 /* button down, snapshot the stacking list before flushing */ 549 if (wireframe && !wireframe_in_progress && 550 strcmp(wireframe_copyrect, "never")) { 551 if (! snapped) { 552 snapshot_stack_list(0, 0.0); 553 } 554 } 555 } 556 557 X_LOCK; 558 559 /* look for buttons that have be clicked or released: */ 560 for (i=0; i < MAX_BUTTONS; i++) { 561 if ( (button_mask & (1<<i)) != (mask & (1<<i)) ) { 562 if (debug_pointer) { 563 rfbLog("pointer(): mask change: mask: 0x%x -> " 564 "0x%x button: %d\n", button_mask, mask,i+1); 565 } 566 do_button_mask_change(mask, i+1); /* button # is i+1 */ 567 } 568 } 569 570 X_UNLOCK; 571 572 /* 573 * Remember the button state for next time and also for the 574 * -nodragging case: 575 */ 576 button_mask_prev = button_mask; 577 button_mask = mask; 578 #endif /* NO_X11 */ 579 } 580 581 /* for -pipeinput */ 582 583 584 static void pipe_pointer(int mask, int x, int y, rfbClientPtr client) { 585 int can_input = 0, uid = 0; 586 allowed_input_t input; 587 ClientData *cd = (ClientData *) client->clientData; 588 char hint[MAX_BUTTONS * 20]; 589 590 if (pipeinput_int == PIPEINPUT_VID) { 591 v4l_pointer_command(mask, x, y, client); 592 } else if (pipeinput_int == PIPEINPUT_CONSOLE) { 593 console_pointer_command(mask, x, y, client); 594 } else if (pipeinput_int == PIPEINPUT_UINPUT) { 595 uinput_pointer_command(mask, x, y, client); 596 } else if (pipeinput_int == PIPEINPUT_MACOSX) { 597 macosx_pointer_command(mask, x, y, client); 598 } else if (pipeinput_int == PIPEINPUT_VNC) { 599 vnc_reflect_send_pointer(x, y, mask); 600 } 601 if (pipeinput_fh == NULL) { 602 return; 603 } 604 605 if (! view_only) { 606 get_allowed_input(client, &input); 607 if (input.motion || input.button) { 608 can_input = 1; /* XXX distinguish later */ 609 } 610 } 611 612 if (cd) { 613 uid = cd->uid; 614 } 615 if (! can_input) { 616 uid = -uid; 617 } 618 619 hint[0] = '\0'; 620 if (mask == button_mask) { 621 strcat(hint, "None"); 622 } else { 623 int i, old, newb, m = 1, cnt = 0; 624 for (i=0; i<MAX_BUTTONS; i++) { 625 char s[20]; 626 627 old = button_mask & m; 628 newb = mask & m; 629 m = m << 1; 630 631 if (old == newb) { 632 continue; 633 } 634 if (hint[0] != '\0') { 635 strcat(hint, ","); 636 } 637 if (newb && ! old) { 638 sprintf(s, "ButtonPress-%d", i+1); 639 cnt++; 640 } else if (! newb && old) { 641 sprintf(s, "ButtonRelease-%d", i+1); 642 cnt++; 643 } 644 strcat(hint, s); 645 } 646 if (! cnt) { 647 strcpy(hint, "None"); 648 } 649 } 650 651 fprintf(pipeinput_fh, "Pointer %d %d %d %d %s\n", uid, x, y, 652 mask, hint); 653 fflush(pipeinput_fh); 654 check_pipeinput(); 655 } 656 657 /* 658 * Actual callback from libvncserver when it gets a pointer event. 659 * This may queue pointer events rather than sending them immediately 660 * to the X server. (see update_x11_pointer*()) 661 */ 662 void pointer_event(int mask, int x, int y, rfbClientPtr client) { 663 allowed_input_t input; 664 int sent = 0, buffer_it = 0; 665 double now; 666 667 if (threads_drop_input) { 668 return; 669 } 670 671 if (mask >= 0) { 672 got_pointer_calls++; 673 } 674 675 if (debug_pointer && mask >= 0) { 676 static int show_motion = -1; 677 static double last_pointer = 0.0; 678 double tnow, dt; 679 static int last_x, last_y; 680 if (show_motion == -1) { 681 if (getenv("X11VNC_DB_NOMOTION")) { 682 show_motion = 0; 683 } else { 684 show_motion = 1; 685 } 686 } 687 dtime0(&tnow); 688 tnow -= x11vnc_start; 689 dt = tnow - last_pointer; 690 last_pointer = tnow; 691 if (show_motion) { 692 rfbLog("# pointer(mask: 0x%x, x:%4d, y:%4d) " 693 "dx: %3d dy: %3d dt: %.4f t: %.4f\n", mask, x, y, 694 x - last_x, y - last_y, dt, tnow); 695 } 696 last_x = x; 697 last_y = y; 698 } 699 700 if (unixpw_in_progress) { 701 return; 702 } 703 704 get_allowed_input(client, &input); 705 706 if (rotating) { 707 rotate_coords_inverse(x, y, &x, &y, -1, -1); 708 } 709 710 if (scaling) { 711 /* map from rfb size to X11 size: */ 712 x = ((double) x / scaled_x) * dpy_x; 713 x = nfix(x, dpy_x); 714 y = ((double) y / scaled_y) * dpy_y; 715 y = nfix(y, dpy_y); 716 } 717 718 INPUT_LOCK; 719 720 if ((pipeinput_fh != NULL || pipeinput_int) && mask >= 0) { 721 pipe_pointer(mask, x, y, client); /* MACOSX here. */ 722 if (! pipeinput_tee) { 723 if (! view_only || raw_fb) { /* raw_fb hack */ 724 got_user_input++; 725 got_pointer_input++; 726 last_pointer_client = client; 727 last_pointer_time = dnow(); 728 last_event = last_input = last_pointer_input = time(NULL); 729 } 730 if (input.motion) { 731 /* raw_fb hack track button state */ 732 button_mask_prev = button_mask; 733 button_mask = mask; 734 } 735 if (!view_only && (input.motion || input.button)) { 736 last_rfb_ptr_injected = dnow(); 737 } 738 INPUT_UNLOCK; 739 return; 740 } 741 } 742 743 if (view_only) { 744 INPUT_UNLOCK; 745 return; 746 } 747 748 now = dnow(); 749 750 if (mask >= 0) { 751 /* 752 * mask = -1 is a special case call from scan_for_updates() 753 * to flush the event queue; there is no real pointer event. 754 */ 755 if (! input.motion && ! input.button) { 756 INPUT_UNLOCK; 757 return; 758 } 759 760 got_user_input++; 761 got_pointer_input++; 762 last_pointer_client = client; 763 764 last_pointer_time = now; 765 last_rfb_ptr_injected = dnow(); 766 767 if (blackout_ptr && blackouts) { 768 int b, ok = 1; 769 /* see if it goes into the blacked out region */ 770 for (b=0; b < blackouts; b++) { 771 if (x < blackr[b].x1 || x > blackr[b].x2) { 772 continue; 773 } 774 if (y < blackr[b].y1 || y > blackr[b].y2) { 775 continue; 776 } 777 /* x1 <= x <= x2 and y1 <= y <= y2 */ 778 ok = 0; 779 break; 780 } 781 if (! ok) { 782 if (debug_pointer) { 783 rfbLog("pointer(): blackout_ptr skipping " 784 "x=%d y=%d in rectangle %d,%d %d,%d\n", x, y, 785 blackr[b].x1, blackr[b].y1, 786 blackr[b].x2, blackr[b].y2); 787 } 788 INPUT_UNLOCK; 789 return; 790 } 791 } 792 } 793 794 /* 795 * The following is hopefully an improvement wrt response during 796 * pointer user input (window drags) for the threaded case. 797 * See check_user_input() for the more complicated things we do 798 * in the non-threaded case. 799 */ 800 if ((use_threads && pointer_mode != 1) || pointer_flush_delay > 0.0) { 801 # define NEV 32 802 /* storage for the event queue */ 803 static int nevents = 0; 804 static int ev[NEV][3]; 805 int i; 806 /* timer things */ 807 static double dt = 0.0, tmr = 0.0, maxwait = 0.4; 808 809 if (pointer_flush_delay > 0.0) { 810 maxwait = pointer_flush_delay; 811 } 812 if (mask >= 0) { 813 if (fb_copy_in_progress || pointer_flush_delay > 0.0) { 814 buffer_it = 1; 815 } 816 } 817 818 POINTER_LOCK; 819 820 /* 821 * If the framebuffer is being copied in another thread 822 * (scan_for_updates()), we will queue up to 32 pointer 823 * events for later. The idea is by delaying these input 824 * events, the screen is less likely to change during the 825 * copying period, and so will give rise to less window 826 * "tearing". 827 * 828 * Tearing is not completely eliminated because we do 829 * not suspend work in the other libvncserver threads. 830 * Maybe that is a possibility with a mutex... 831 */ 832 if (buffer_it) { 833 /* 834 * mask = -1 is an all-clear signal from 835 * scan_for_updates(). 836 * 837 * dt is a timer in seconds; we only queue for so long. 838 */ 839 dt += dtime(&tmr); 840 841 if (nevents < NEV && dt < maxwait) { 842 i = nevents++; 843 ev[i][0] = mask; 844 ev[i][1] = x; 845 ev[i][2] = y; 846 if (! input.button) { 847 ev[i][0] = -1; 848 } 849 if (! input.motion) { 850 ev[i][1] = -1; 851 ev[i][2] = -1; 852 } 853 if (debug_pointer) { 854 rfbLog("pointer(): deferring event %d" 855 " %.4f\n", i, tmr - x11vnc_start); 856 } 857 POINTER_UNLOCK; 858 INPUT_UNLOCK; 859 return; 860 } 861 } 862 863 /* time to send the queue */ 864 for (i=0; i<nevents; i++) { 865 int sent = 0; 866 if (mask < 0 && client != NULL) { 867 /* hack to only push the latest event */ 868 if (i < nevents - 1) { 869 if (debug_pointer) { 870 rfbLog("- skip deferred event:" 871 " %d\n", i); 872 } 873 continue; 874 } 875 } 876 if (debug_pointer) { 877 rfbLog("pointer(): sending event %d %.4f\n", 878 i+1, dnowx()); 879 } 880 if (ev[i][1] >= 0) { 881 update_x11_pointer_position(ev[i][1], ev[i][2]); 882 sent = 1; 883 } 884 if (ev[i][0] >= 0) { 885 update_x11_pointer_mask(ev[i][0]); 886 sent = 1; 887 } 888 889 if (sent) { 890 pointer_queued_sent++; 891 } 892 } 893 if (nevents && dt > maxwait) { 894 if (dpy) { /* raw_fb hack */ 895 if (mask < 0) { 896 if (debug_pointer) { 897 rfbLog("pointer(): calling XFlush " 898 "%.4f\n", dnowx()); 899 } 900 X_LOCK; 901 XFlush_wr(dpy); 902 X_UNLOCK; 903 } 904 } 905 } 906 nevents = 0; /* reset everything */ 907 dt = 0.0; 908 dtime0(&tmr); 909 910 POINTER_UNLOCK; 911 } 912 if (mask < 0) { /* -1 just means flush the event queue */ 913 if (debug_pointer) { 914 rfbLog("pointer(): flush only. %.4f\n", 915 dnowx()); 916 } 917 INPUT_UNLOCK; 918 return; 919 } 920 921 /* update the X display with the event: */ 922 if (input.motion) { 923 update_x11_pointer_position(x, y); 924 sent = 1; 925 } 926 if (input.button) { 927 if (mask != button_mask) { 928 button_change_x = cursor_x; 929 button_change_y = cursor_y; 930 } 931 update_x11_pointer_mask(mask); 932 sent = 1; 933 } 934 935 if (! dpy) { 936 ; 937 } else if (nofb && sent) { 938 /* 939 * nofb is for, e.g. Win2VNC, where fastest pointer 940 * updates are desired. 941 */ 942 X_LOCK; 943 XFlush_wr(dpy); 944 X_UNLOCK; 945 } else if (buffer_it) { 946 if (debug_pointer) { 947 rfbLog("pointer(): calling XFlush+" 948 "%.4f\n", dnowx()); 949 } 950 X_LOCK; 951 XFlush_wr(dpy); 952 X_UNLOCK; 953 } 954 INPUT_UNLOCK; 955 } 956 957 void initialize_pipeinput(void) { 958 char *p = NULL; 959 960 if (pipeinput_fh != NULL) { 961 rfbLog("closing pipeinput stream: %p\n", pipeinput_fh); 962 pclose(pipeinput_fh); 963 pipeinput_fh = NULL; 964 } 965 966 pipeinput_tee = 0; 967 if (pipeinput_opts) { 968 free(pipeinput_opts); 969 pipeinput_opts = NULL; 970 } 971 972 if (! pipeinput_str) { 973 return; 974 } 975 976 /* look for options: tee, reopen, ... */ 977 if (strstr(pipeinput_str, "UINPUT") == pipeinput_str) { 978 ; 979 } else { 980 p = strchr(pipeinput_str, ':'); 981 } 982 if (p != NULL) { 983 char *str, *opt, *q; 984 int got = 0; 985 *p = '\0'; 986 str = strdup(pipeinput_str); 987 opt = strdup(pipeinput_str); 988 *p = ':'; 989 q = strtok(str, ","); 990 while (q) { 991 if (!strcmp(q, "key") || !strcmp(q, "keycodes")) { 992 got = 1; 993 } 994 if (!strcmp(q, "reopen")) { 995 got = 1; 996 } 997 if (!strcmp(q, "tee")) { 998 pipeinput_tee = 1; 999 got = 1; 1000 } 1001 q = strtok(NULL, ","); 1002 } 1003 if (got) { 1004 pipeinput_opts = opt; 1005 } else { 1006 free(opt); 1007 } 1008 free(str); 1009 p++; 1010 } else { 1011 p = pipeinput_str; 1012 } 1013 if (0) fprintf(stderr, "initialize_pipeinput: %s -- %s\n", pipeinput_str, p); 1014 1015 if (!strcmp(p, "VID")) { 1016 pipeinput_int = PIPEINPUT_VID; 1017 return; 1018 } else if (strstr(p, "CONSOLE") == p) { 1019 int tty = 0, n; 1020 char dev[32]; 1021 if (sscanf(p, "CONSOLE%d", &n) == 1) { 1022 tty = n; 1023 } 1024 sprintf(dev, "/dev/tty%d", tty); 1025 pipeinput_cons_fd = open(dev, O_WRONLY); 1026 if (pipeinput_cons_fd >= 0) { 1027 rfbLog("pipeinput: using linux console: %s\n", dev); 1028 if (pipeinput_cons_dev) { 1029 free(pipeinput_cons_dev); 1030 } 1031 pipeinput_cons_dev = strdup(dev); 1032 pipeinput_int = PIPEINPUT_CONSOLE; 1033 } else { 1034 rfbLog("pipeinput: could not open: %s\n", dev); 1035 rfbLogPerror("open"); 1036 rfbLog("You may need to be root to open %s.\n", dev); 1037 rfbLog("\n"); 1038 } 1039 return; 1040 } else if (strstr(p, "UINPUT") == p) { 1041 char *q = strchr(p, ':'); 1042 if (q) { 1043 parse_uinput_str(q+1); 1044 } 1045 pipeinput_int = PIPEINPUT_UINPUT; 1046 initialize_uinput(); 1047 return; 1048 } else if (strstr(p, "MACOSX") == p) { 1049 pipeinput_int = PIPEINPUT_MACOSX; 1050 return; 1051 } else if (strstr(p, "VNC") == p) { 1052 pipeinput_int = PIPEINPUT_VNC; 1053 return; 1054 } 1055 1056 set_child_info(); 1057 /* pipeinput */ 1058 if (no_external_cmds || !cmd_ok("pipeinput")) { 1059 rfbLogEnable(1); 1060 rfbLog("cannot run external commands in -nocmds mode:\n"); 1061 rfbLog(" \"%s\"\n", p); 1062 rfbLog(" exiting.\n"); 1063 clean_up_exit(1); 1064 } 1065 rfbLog("pipeinput: starting: \"%s\"...\n", p); 1066 close_exec_fds(); 1067 pipeinput_fh = popen(p, "w"); 1068 1069 if (! pipeinput_fh) { 1070 rfbLog("popen(\"%s\", \"w\") failed.\n", p); 1071 rfbLogPerror("popen"); 1072 rfbLog("Disabling -pipeinput mode.\n"); 1073 return; 1074 } 1075 1076 fprintf(pipeinput_fh, "%s", 1077 "# \n" 1078 "# Format of the -pipeinput stream:\n" 1079 "# --------------------------------\n" 1080 "#\n" 1081 "# Lines like these beginning with '#' are to be ignored.\n" 1082 "#\n" 1083 "# Pointer events (mouse motion and button clicks) come in the form:\n" 1084 "#\n" 1085 "#\n" 1086 "# Pointer <client#> <x> <y> <mask> <hint>\n" 1087 "#\n" 1088 "#\n" 1089 "# The <client#> is a decimal integer uniquely identifying the client\n" 1090 "# that generated the event. If it is negative that means this event\n" 1091 "# would have been discarded since the client was viewonly.\n" 1092 "#\n" 1093 "# <x> and <y> are decimal integers reflecting the position on the screen\n" 1094 "# the event took place at.\n" 1095 "#\n" 1096 "# <mask> is the button mask indicating the button press state, as normal\n" 1097 "# 0 means no buttons pressed, 1 means button 1 is down 3 (11) means buttons\n" 1098 "# 1 and 2 are down, etc.\n" 1099 "#\n" 1100 "# <hint> is a string containing no spaces and may be ignored.\n" 1101 "# It contains some interpretation about what has happened.\n" 1102 "# It can be:\n" 1103 "#\n" 1104 "# None (nothing to report)\n" 1105 "# ButtonPress-N (this event will cause button-N to be pressed) \n" 1106 "# ButtonRelease-N (this event will cause button-N to be released) \n" 1107 "#\n" 1108 "# if two more more buttons change state in one event they are listed\n" 1109 "# separated by commas.\n" 1110 "#\n" 1111 "# One might parse a Pointer line with:\n" 1112 "#\n" 1113 "# int client, x, y, mask; char hint[100];\n" 1114 "# sscanf(line, \"Pointer %d %d %d %d %s\", &client, &x, &y, &mask, hint);\n" 1115 "#\n" 1116 "#\n" 1117 "# Keysym events (keyboard presses and releases) come in the form:\n" 1118 "#\n" 1119 "#\n" 1120 "# Keysym <client#> <down> <keysym#> <keysym-name> <hint>\n" 1121 "#\n" 1122 "#\n" 1123 "# The <client#> is as with Pointer.\n" 1124 "#\n" 1125 "# <down> is a decimal either 1 or 0 indicating KeyPress or KeyRelease,\n" 1126 "# respectively.\n" 1127 "#\n" 1128 "# <keysym#> is a decimal integer incidating the Keysym of the event.\n" 1129 "#\n" 1130 "# <keysym-name> is the corresponding Keysym name.\n" 1131 "#\n" 1132 "# See the file /usr/include/X11/keysymdef.h for the mappings.\n" 1133 "# You basically remove the leading 'XK_' prefix from the macro name in\n" 1134 "# that file to get the Keysym name.\n" 1135 "#\n" 1136 "# One might parse a Keysym line with:\n" 1137 "#\n" 1138 "# int client, down, keysym; char name[100], hint[100];\n" 1139 "# sscanf(line, \"Keysym %d %d %d %s %s\", &client, &down, &keysym, name, hint);\n" 1140 "#\n" 1141 "# The <hint> value is currently just None, KeyPress, or KeyRelease.\n" 1142 "#\n" 1143 "# In the future <hint> will provide a hint for the sequence of KeyCodes\n" 1144 "# (i.e. keyboard scancodes) that x11vnc would inject to an X display to\n" 1145 "# simulate the Keysym.\n" 1146 "#\n" 1147 "# You see, some Keysyms will require more than one injected Keycode to\n" 1148 "# generate the symbol. E.g. the Keysym \"ampersand\" going down usually\n" 1149 "# requires a Shift key going down, then the key with the \"&\" on it going\n" 1150 "# down, and, perhaps, the Shift key going up (that is how x11vnc does it).\n" 1151 "#\n" 1152 "# The Keysym => Keycode(s) stuff gets pretty messy. Hopefully the Keysym\n" 1153 "# info will be enough for most purposes (having identical keyboards on\n" 1154 "# both sides helps).\n" 1155 "#\n" 1156 "# Parsing example for perl:\n" 1157 "#\n" 1158 "# while (<>) {\n" 1159 "# chomp;\n" 1160 "# if (/^Pointer/) {\n" 1161 "# my ($p, $client, $x, $y, $mask, $hint) = split(' ', $_, 6);\n" 1162 "# do_pointer($client, $x, $y, $mask, $hint);\n" 1163 "# } elsif (/^Keysym/) {\n" 1164 "# my ($k, $client, $down, $keysym, $name, $hint) = split(' ', $_, 6);\n" 1165 "# do_keysym($client, $down, $keysym, $name, $hint);\n" 1166 "# }\n" 1167 "# }\n" 1168 "#\n" 1169 "#\n" 1170 "# Here comes your stream. The following token will always indicate the\n" 1171 "# end of this informational text:\n" 1172 "# END_OF_TOP\n" 1173 ); 1174 fflush(pipeinput_fh); 1175 if (raw_fb_str) { 1176 /* the pipe program may actually create the fb */ 1177 sleep(1); 1178 } 1179 } 1180 1181 int check_pipeinput(void) { 1182 if (! pipeinput_fh) { 1183 return 1; 1184 } 1185 if (ferror(pipeinput_fh)) { 1186 rfbLog("pipeinput pipe has ferror. %p\n", pipeinput_fh); 1187 1188 if (pipeinput_opts && strstr(pipeinput_opts, "reopen")) { 1189 rfbLog("restarting -pipeinput pipe...\n"); 1190 initialize_pipeinput(); 1191 if (pipeinput_fh) { 1192 return 1; 1193 } else { 1194 return 0; 1195 } 1196 } else { 1197 rfbLog("closing -pipeinput pipe...\n"); 1198 pclose(pipeinput_fh); 1199 pipeinput_fh = NULL; 1200 return 0; 1201 } 1202 } 1203 return 1; 1204 } 1205 1206 1207