blob: f2995c3c36355544c88fba7486be52b84edb8f95 [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/* -- 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
53int pointer_queued_sent = 0;
54
55void initialize_pointer_map(char *pointer_remap);
56void do_button_mask_change(int mask, int button);
57void pointer_event(int mask, int x, int y, rfbClientPtr client);
58void initialize_pipeinput(void);
59int check_pipeinput(void);
60void update_x11_pointer_position(int x, int y);
61
62
63static void buttonparse(int from, char **s);
64static void update_x11_pointer_mask(int mask);
65static void pipe_pointer(int mask, int x, int y, rfbClientPtr client);
66
67/*
68 * pointer event (motion and button click) handling routines.
69 */
70typedef 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
80static 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 */
85static 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 */
251void 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 */
338void 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
382void 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 */
452static 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;
492if (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) {
524if (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
584static 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 */
662void 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
957void 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 }
1013if (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
1181int 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