1/*
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/* -- macosxCG.c -- */
34
35/*
36 * We need to keep this separate from nearly everything else, e.g. rfb.h
37 * and the other stuff, otherwise it does not work properly, mouse drags
38 * will not work!!
39 */
40
41void macosxCG_dummy(void) {}
42
43#if (defined(__MACH__) && defined(__APPLE__))
44
45#include <ApplicationServices/ApplicationServices.h>
46#include <Cocoa/Cocoa.h>
47#include <Carbon/Carbon.h>
48
49void macosxCG_init(void);
50void macosxCG_fini(void);
51void macosxCG_event_loop(void);
52char *macosxCG_get_fb_addr(void);
53
54int macosxCG_CGDisplayPixelsWide(void);
55int macosxCG_CGDisplayPixelsHigh(void);
56int macosxCG_CGDisplayBitsPerPixel(void);
57int macosxCG_CGDisplayBitsPerSample(void);
58int macosxCG_CGDisplaySamplesPerPixel(void);
59int macosxCG_CGDisplayBytesPerRow(void);
60
61void macosxCG_pointer_inject(int mask, int x, int y);
62int macosxCG_get_cursor_pos(int *x, int *y);
63int macosxCG_get_cursor(void);
64void macosxCG_init_key_table(void);
65void macosxCG_keysym_inject(int down, unsigned int keysym);
66void macosxCG_keycode_inject(int down, int keycode);
67
68CGDirectDisplayID displayID = 0;
69
70extern void macosx_log(char *);
71extern int collect_non_X_xdamage(int x_in, int y_in, int w_in, int h_in, int call);
72
73static void macosxCG_callback(CGRectCount n, const CGRect *rects, void *dum) {
74	int i, db = 0;
75	if (db) fprintf(stderr, "macosx_callback: n=%d\n", (int) n);
76	if (!dum) {}
77	for (i=0; i < (int) n; i++) {
78		if (db > 1) fprintf(stderr, "               : %g %g - %g %g\n", rects[i].origin.x, rects[i].origin.y, rects[i].size.width, rects[i].size.height);
79		collect_non_X_xdamage( (int) rects[i].origin.x, (int) rects[i].origin.y,
80		    (int) rects[i].size.width, (int) rects[i].size.height, 1);
81	}
82}
83
84#if 0
85>
86> if gcc -DHAVE_CONFIG_H -I. -I. -I..   -I/opt/local/include   -I/opt/local/include -ObjC -g -O2 -Wall -MT x11vnc-macosxCG.o -MD -MP -MF ".deps/x11vnc-macosxCG.Tpo" -c -o x11vnc-macosxCG.o `test -f 'macosxCG.c' || echo './'`macosxCG.c; \
87> 	then mv -f ".deps/x11vnc-macosxCG.Tpo" ".deps/x11vnc-macosxCG.Po"; else rm -f ".deps/x11vnc-macosxCG.Tpo"; exit 1; fi
88> macosxCG.c:149: warning: CGSetLocalEventsSuppressionInterval is deprecated (declared at /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGRemoteOperation.h:373)
89> macosxCG.c:150: warning: CGSetLocalEventsFilterDuringSuppressionState is deprecated (declared at /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGRemoteOperation.h:366)
90> macosxCG.c:153: warning: CGSetLocalEventsFilterDuringSuppressionState is deprecated (declared at /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGRemoteOperation.h:366)
91> macosxCG.c:244: warning: CGDisplayBaseAddress is deprecated (declared at /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGDirectDisplay.h:466)
92> macosxCG.c:254: warning: CGDisplayBitsPerPixel is deprecated (declared at /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGDirectDisplay.h:517)
93> macosxCG.c:257: warning: CGDisplayBitsPerSample is deprecated (declared at /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGDirectDisplay.h:522)
94> macosxCG.c:260: warning: CGDisplaySamplesPerPixel is deprecated (declared at /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGDirectDisplay.h:526)
95> macosxCG.c:263: warning: CGDisplayBytesPerRow is deprecated (declared at /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGDirectDisplay.h:476)
96> macosxCG.c:419: warning: CGPostScrollWheelEvent is deprecated (declared at /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGRemoteOperation.h:327)
97> macosxCG.c:422: warning: CGPostScrollWheelEvent is deprecated (declared at /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGRemoteOperation.h:327)
98> macosxCG.c:425: warning: CGPostMouseEvent is deprecated (declared at /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGRemoteOperation.h:307)
99> macosxCG.c:641: warning: CGPostKeyboardEvent is deprecated (declared at /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGRemoteOperation.h:333)
100> macosxCG.c:661: warning: CGPostKeyboardEvent is deprecated (declared at /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Headers/CGRemoteOperation.h:333)
101>
102
103X11VNC_MACOSX_NO_DEPRECATED_LOCALEVENTS
104X11VNC_MACOSX_NO_DEPRECATED_POSTEVENTS
105X11VNC_MACOSX_NO_DEPRECATED_FRAMEBUFFER
106X11VNC_MACOSX_NO_DEPRECATED
107
108#endif
109
110static int callback_set = 0;
111extern int nofb;
112
113void macosxCG_refresh_callback_on(void) {
114	if (nofb) {
115		return;
116	}
117
118	if (! callback_set) {
119		if (1) macosx_log("macosxCG_refresh_callback: register\n");
120		CGRegisterScreenRefreshCallback(macosxCG_callback, NULL);
121	}
122	callback_set = 1;
123}
124
125void macosxCG_refresh_callback_off(void) {
126	if (callback_set) {
127		if (1) macosx_log("macosxCG_refresh_callback: unregister\n");
128		CGUnregisterScreenRefreshCallback(macosxCG_callback, NULL);
129	}
130	callback_set = 0;
131}
132
133extern int macosx_noscreensaver;
134extern int macosx_read_opengl;
135extern int macosx_read_rawfb;
136
137extern void macosxGCS_initpb(void);
138extern int macosxCGP_init_dimming(void);
139extern int macosxCGP_undim(void);
140extern int macosxCGP_dim_shutdown(void);
141extern void macosxCGP_screensaver_timer_off(void);
142extern void macosxCGP_screensaver_timer_on(void);
143extern void macosx_opengl_init(void);
144extern void macosx_opengl_fini(void);
145
146int x11vnc_macosx_no_deprecated_localevents = 0;
147int x11vnc_macosx_no_deprecated_postevents  = 0;
148int x11vnc_macosx_no_deprecated_framebuffer = 0;
149
150void macosxCG_init(void) {
151
152	x11vnc_macosx_no_deprecated_localevents = 0;
153	x11vnc_macosx_no_deprecated_postevents  = 0;
154	x11vnc_macosx_no_deprecated_framebuffer = 0;
155
156	if (getenv("X11VNC_MACOSX_NO_DEPRECATED_LOCALEVENTS") || getenv("X11VNC_MACOSX_NO_DEPRECATED")) {
157		x11vnc_macosx_no_deprecated_localevents = 1;
158	}
159	if (getenv("X11VNC_MACOSX_NO_DEPRECATED_POSTEVENTS") || getenv("X11VNC_MACOSX_NO_DEPRECATED")) {
160		x11vnc_macosx_no_deprecated_postevents = 1;
161	}
162	if (getenv("X11VNC_MACOSX_NO_DEPRECATED_FRAMEBUFFER") || getenv("X11VNC_MACOSX_NO_DEPRECATED")) {
163		x11vnc_macosx_no_deprecated_framebuffer = 1;
164	}
165
166	if (displayID == 0) {
167		macosx_log("macosxCG_init: initializing display.\n");
168
169		displayID = kCGDirectMainDisplay;
170#ifdef X11VNC_MACOSX_USE_GETMAINDEVICE
171		/* not sure this ever did anything. */
172		(void) GetMainDevice();
173#endif
174		if (displayID == 0) {
175			macosx_log("macosxCG_init: could not get kCGDirectMainDisplay / CGMainDisplayID() display.\n");
176			exit(1);
177		}
178
179#if X11VNC_MACOSX_NO_DEPRECATED_LOCALEVENTS || X11VNC_MACOSX_NO_DEPRECATED
180		macosx_log("NO_DEPRECATED_LOCALEVENTS: not calling CGSetLocalEventsSuppressionInterval()\n");
181		macosx_log("NO_DEPRECATED_LOCALEVENTS: not calling CGSetLocalEventsFilterDuringSupressionState()\n");
182#else
183		if (!x11vnc_macosx_no_deprecated_localevents) {
184			CGSetLocalEventsSuppressionInterval(0.0);
185			CGSetLocalEventsFilterDuringSupressionState(
186			    kCGEventFilterMaskPermitAllEvents,
187			    kCGEventSupressionStateSupressionInterval);
188			CGSetLocalEventsFilterDuringSupressionState(
189			    kCGEventFilterMaskPermitAllEvents,
190			    kCGEventSupressionStateRemoteMouseDrag);
191		} else {
192			macosx_log("NO_DEPRECATED_LOCALEVENTS: not calling CGSetLocalEventsSuppressionInterval()\n");
193			macosx_log("NO_DEPRECATED_LOCALEVENTS: not calling CGSetLocalEventsFilterDuringSupressionState()\n");
194		}
195#endif
196
197		macosx_opengl_init();
198
199		if (!macosx_read_opengl) {
200			char *addr = macosxCG_get_fb_addr();
201			if (addr == NULL) {
202				macosx_log("macosxCG_init: could not get raw framebuffer address / CGDisplayBaseAddress().\n");
203				exit(1);
204			}
205			macosx_read_rawfb = 1;
206			macosx_log("macosxCG_init: using raw framebuffer address for screen capture.\n");
207		}
208
209		macosxCGP_init_dimming();
210		if (macosx_noscreensaver) {
211			macosxCGP_screensaver_timer_on();
212		}
213
214		macosxGCS_initpb();
215	}
216}
217
218void macosxCG_fini(void) {
219	macosxCGP_dim_shutdown();
220	if (macosx_noscreensaver) {
221		macosxCGP_screensaver_timer_off();
222	}
223	macosxCG_refresh_callback_off();
224	macosx_opengl_fini();
225	displayID = 0;
226}
227
228extern int dpy_x, dpy_y, bpp, wdpy_x, wdpy_y;
229extern int client_count, nofb;
230extern void do_new_fb(int);
231extern int macosx_wait_for_switch, macosx_resize;
232
233extern void macosxGCS_poll_pb(void);
234#if 0
235extern void usleep(unsigned long usec);
236#else
237extern int usleep(useconds_t usec);
238#endif
239extern unsigned int sleep(unsigned int seconds);
240extern void clean_up_exit(int ret);
241
242void macosxCG_event_loop(void) {
243	OSStatus rc;
244	int nbpp;
245	static int nbpp_save = -1;
246
247	macosxGCS_poll_pb();
248	if (nofb) {
249		return;
250	}
251
252	rc = RunCurrentEventLoop(kEventDurationSecond/30);
253
254	if (client_count) {
255		macosxCG_refresh_callback_on();
256	} else {
257		macosxCG_refresh_callback_off();
258	}
259
260	nbpp = macosxCG_CGDisplayBitsPerPixel();
261
262	if (nbpp_save < 0) {
263		nbpp_save = nbpp;
264	}
265
266	if (nbpp > 0 && nbpp != nbpp_save) {
267		nbpp_save = nbpp;
268		if (macosx_resize) {
269			do_new_fb(1);
270		}
271	} else if (wdpy_x != macosxCG_CGDisplayPixelsWide()) {
272	    if (wdpy_y != macosxCG_CGDisplayPixelsHigh()) {
273		if (macosx_wait_for_switch) {
274			int cnt = 0;
275			while (1) {
276				if(macosxCG_CGDisplayPixelsWide() > 0) {
277					if(macosxCG_CGDisplayPixelsHigh() > 0) {
278						usleep(500*1000);
279						break;
280					}
281				}
282				if ((cnt++ % 120) == 0) {
283					macosx_log("waiting for user to "
284					    "switch back..\n");
285				}
286				sleep(1);
287			}
288			if (wdpy_x == macosxCG_CGDisplayPixelsWide()) {
289				if (wdpy_y == macosxCG_CGDisplayPixelsHigh()) {
290					macosx_log("we're back...\n");
291					return;
292				}
293			}
294		}
295		if (macosx_resize) {
296			do_new_fb(1);
297		}
298	    }
299	}
300	if (nbpp > 0) {
301		nbpp_save = nbpp;
302	}
303}
304
305extern int macosx_no_rawfb;
306extern int macosx_read_opengl;
307extern int macosx_opengl_get_width();
308extern int macosx_opengl_get_height();
309extern int macosx_opengl_get_bpp();
310extern int macosx_opengl_get_bps();
311extern int macosx_opengl_get_spp();
312
313#if X11VNC_MACOSX_NO_DEPRECATED_FRAMEBUFFER || X11VNC_MACOSX_NO_DEPRECATED
314
315char *macosxCG_get_fb_addr(void) {
316	return NULL;
317}
318int macosxCG_CGDisplayPixelsWide(void) {
319	return macosx_opengl_get_width();
320}
321int macosxCG_CGDisplayPixelsHigh(void) {
322	return macosx_opengl_get_height();
323}
324int macosxCG_CGDisplayBitsPerPixel(void) {
325	return macosx_opengl_get_bpp();
326}
327int macosxCG_CGDisplayBitsPerSample(void) {
328	return macosx_opengl_get_bps();
329}
330int macosxCG_CGDisplaySamplesPerPixel(void) {
331	return macosx_opengl_get_spp();
332}
333int macosxCG_CGDisplayBytesPerRow(void) {
334	return macosx_opengl_get_width() * macosx_opengl_get_bpp() / 8;
335}
336
337#else
338
339char *macosxCG_get_fb_addr(void) {
340	if (x11vnc_macosx_no_deprecated_framebuffer) {
341		macosx_log("CGDisplayBaseAddress disabled by env. var\n");
342		return NULL;
343	}
344	if (macosx_no_rawfb) {
345		macosx_log("CGDisplayBaseAddress disabled by user.\n");
346		return NULL;
347	}
348	if (macosx_read_opengl) {
349		macosx_log("CGDisplayBaseAddress disabled by OpenGL.\n");
350		return NULL;
351	}
352	return (char *) CGDisplayBaseAddress(displayID);
353}
354
355int macosxCG_CGDisplayPixelsWide(void) {
356	if ((0 && macosx_read_opengl) || x11vnc_macosx_no_deprecated_framebuffer) {
357		return macosx_opengl_get_width();
358	}
359	return (int) CGDisplayPixelsWide(displayID);
360}
361int macosxCG_CGDisplayPixelsHigh(void) {
362	if ((0 && macosx_read_opengl) || x11vnc_macosx_no_deprecated_framebuffer) {
363		return macosx_opengl_get_height();
364	}
365	return (int) CGDisplayPixelsHigh(displayID);
366}
367int macosxCG_CGDisplayBitsPerPixel(void) {
368	if ((0 && macosx_read_opengl) || x11vnc_macosx_no_deprecated_framebuffer) {
369		return macosx_opengl_get_bpp();
370	}
371	return (int) CGDisplayBitsPerPixel(displayID);
372}
373int macosxCG_CGDisplayBitsPerSample(void) {
374	if (macosx_read_opengl || x11vnc_macosx_no_deprecated_framebuffer) {
375		return macosx_opengl_get_bps();
376	}
377	return (int) CGDisplayBitsPerSample(displayID);
378}
379int macosxCG_CGDisplaySamplesPerPixel(void) {
380	if (macosx_read_opengl || x11vnc_macosx_no_deprecated_framebuffer) {
381		return macosx_opengl_get_spp();
382	}
383	return (int) CGDisplaySamplesPerPixel(displayID);
384}
385int macosxCG_CGDisplayBytesPerRow(void) {
386	if (macosx_read_opengl || x11vnc_macosx_no_deprecated_framebuffer) {
387		return macosx_opengl_get_width() * macosx_opengl_get_bpp()/8;
388	}
389	return (int) CGDisplayBytesPerRow(displayID);;
390}
391
392#endif
393
394typedef int CGSConnectionRef;
395static CGSConnectionRef conn = 0;
396extern CGError CGSNewConnection(void*, CGSConnectionRef*);
397extern CGError CGSReleaseConnection(CGSConnectionRef);
398extern CGError CGSGetGlobalCursorDataSize(CGSConnectionRef, int*);
399extern CGError CGSGetGlobalCursorData(CGSConnectionRef, unsigned char*,
400    int*, int*, CGRect*, CGPoint*, int*, int*, int*);
401extern CGError CGSGetCurrentCursorLocation(CGSConnectionRef, CGPoint*);
402extern int CGSCurrentCursorSeed(void);
403extern int CGSHardwareCursorActive();
404
405static unsigned int last_local_button_mask = 0;
406static unsigned int last_local_mod_mask = 0;
407static int last_local_x = 0;
408static int last_local_y = 0;
409
410extern unsigned int display_button_mask;
411extern unsigned int display_mod_mask;
412extern int got_local_pointer_input;
413extern time_t last_local_input;
414
415static CGPoint current_cursor_pos(void) {
416	CGPoint pos;
417	pos.x = 0;
418	pos.y = 0;
419	if (! conn) {
420		if (CGSNewConnection(NULL, &conn) != kCGErrorSuccess) {
421			macosx_log("CGSNewConnection error.\n");
422			if (!dpy_x || !dpy_y || !wdpy_x || !wdpy_y) {
423				clean_up_exit(1);
424			}
425		}
426	}
427	if (CGSGetCurrentCursorLocation(conn, &pos) != kCGErrorSuccess) {
428		macosx_log("CGSGetCurrentCursorLocation error\n");
429	}
430
431	display_button_mask = GetCurrentButtonState();
432#if 0
433/* not used yet */
434	display_mod_mask = GetCurrentKeyModifiers();
435#endif
436
437	if (last_local_button_mask != display_button_mask) {
438		got_local_pointer_input++;
439		last_local_input = time(NULL);
440	} else if (pos.x != last_local_x || pos.y != last_local_y) {
441		got_local_pointer_input++;
442		last_local_input = time(NULL);
443	}
444	last_local_button_mask = display_button_mask;
445	last_local_mod_mask = display_mod_mask;
446	last_local_x = pos.x;
447	last_local_y = pos.y;
448
449	return pos;
450}
451
452int macosxCG_get_cursor_pos(int *x, int *y) {
453	CGPoint pos = current_cursor_pos();
454	*x = pos.x;
455	*y = pos.y;
456	return 1;
457}
458
459extern int get_cursor_serial(int);
460extern int store_cursor(int serial, unsigned long *data, int w, int h, int cbpp, int xhot, int yhot);
461
462int macosxCG_get_cursor(void) {
463	int last_idx = (int) get_cursor_serial(1);
464	int which = 1;
465	CGError err;
466	int datasize, row_bytes, cdepth, comps, bpcomp;
467	CGRect rect;
468	CGPoint hot;
469	unsigned char *data;
470	int cursor_seed;
471	static int last_cursor_seed = -1;
472	static time_t last_fetch = 0;
473	time_t now = time(NULL);
474
475	if (last_idx) {
476		which = last_idx;
477	}
478
479	if (! conn) {
480		if (CGSNewConnection(NULL, &conn) != kCGErrorSuccess) {
481			macosx_log("CGSNewConnection error.\n");
482			if (!dpy_x || !dpy_y || !wdpy_x || !wdpy_y) {
483				clean_up_exit(1);
484			}
485			return which;
486		}
487	}
488
489	/* XXX all of these interfaces are undocumented. */
490
491	cursor_seed = CGSCurrentCursorSeed();
492	if (last_idx && cursor_seed == last_cursor_seed) {
493		if (now < last_fetch + 2) {
494			return which;
495		}
496	}
497	last_cursor_seed = cursor_seed;
498	last_fetch = now;
499
500	if (CGSGetGlobalCursorDataSize(conn, &datasize) != kCGErrorSuccess) {
501		macosx_log("CGSGetGlobalCursorDataSize error\n");
502		return which;
503	}
504
505	data = (unsigned char*) malloc(datasize);
506
507	err = CGSGetGlobalCursorData(conn, data, &datasize, &row_bytes,
508	    &rect, &hot, &cdepth, &comps, &bpcomp);
509#if 0
510	fprintf(stderr, "datasize: %d row_bytes: %d cdepth: %d comps: %d bpcomp: %d w: %d h: %d\n",
511	  datasize, row_bytes, cdepth, comps, bpcomp, (int) rect.size.width, (int) rect.size.height);
512#endif
513	if (err != kCGErrorSuccess) {
514		macosx_log("CGSGetGlobalCursorData error\n");
515		return which;
516	}
517
518	if (cdepth == 24) {
519		cdepth = 32;
520	}
521
522	if (sizeof(long) == 8 && comps * bpcomp <= 32) {
523		/* pad it out to unsigned long array size (like xfixes) */
524		int i;
525		unsigned char *dsave;
526		unsigned char *data64 = (unsigned char*) malloc(2 *datasize);
527		unsigned int  *uI = (unsigned int  *) data;
528		unsigned long *uL = (unsigned long *) data64;
529		for (i=0; i < datasize/4; i++) {
530			uL[i] = uI[i];
531		}
532		dsave = data;
533		data = data64;
534		free(dsave);
535	}
536
537	which = store_cursor(cursor_seed, (unsigned long*) data,
538	    (int) rect.size.width, (int) rect.size.height, cdepth, (int) hot.x, (int) hot.y);
539
540	free(data);
541	return(which);
542}
543
544extern int macosx_mouse_wheel_speed;
545extern int macosx_swap23;
546extern int off_x, coff_x, off_y, coff_y;
547
548extern int debug_pointer;
549
550static void CGPostScrollWheelEvent_wr(CGWheelCount wheel_count, int wheel_distance) {
551	static int post_mode = -1, mcnt = 0;
552
553#if !X11VNC_MACOSX_NO_DEPRECATED_POSTEVENTS && !X11VNC_MACOSX_NO_DEPRECATED
554	if (post_mode < 0) {
555		post_mode = 1;
556		if (getenv("X11VNC_MACOSX_NO_DEPRECATED_POSTEVENTS") || getenv("X11VNC_MACOSX_NO_DEPRECATED")) {
557			post_mode = 0;
558		}
559	}
560
561	if (post_mode) {
562		if (mcnt++ < 10 || debug_pointer) fprintf(stderr, "CGPostScrollWheelEvent()\n");
563		CGPostScrollWheelEvent(wheel_count, wheel_distance);
564	} else
565#endif
566	{
567		/* XXX 10.5 and later */
568#ifndef X11VNC_MACOSX_NO_CGEVENTCREATESCROLLWHEELEVENT
569		CGEventRef event;
570		event = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitLine, wheel_count, wheel_distance);
571		if (event != NULL) {
572			CGEventPost(kCGHIDEventTap, event);
573			CFRelease(event);
574		}
575#endif
576		if (mcnt++ < 10 || debug_pointer) fprintf(stderr, "CGEventCreateScrollWheelEvent()\n");
577	}
578}
579
580static void CGPostMouseEvent_wr(CGPoint loc, int update, int count, int d1, int d2, int d3, int p1, int p2, int p3) {
581	static int post_mode = -1, mcnt = 0;
582
583#if !X11VNC_MACOSX_NO_DEPRECATED_POSTEVENTS && !X11VNC_MACOSX_NO_DEPRECATED
584	if (post_mode < 0) {
585		post_mode = 1;
586		if (getenv("X11VNC_MACOSX_NO_DEPRECATED_POSTEVENTS") || getenv("X11VNC_MACOSX_NO_DEPRECATED")) {
587			post_mode = 0;
588		}
589	}
590
591	if (post_mode) {
592		if (mcnt++ < 10 || debug_pointer) fprintf(stderr, "CGPostMouseEvent()\n");
593		CGPostMouseEvent(loc, update, count, d1, d2, d3);
594	} else
595#endif
596	{
597		/* XXX 10.4 and later */
598#ifndef X11VNC_MACOSX_NO_CGEVENTCREATEMOUSEEVENT
599		CGEventRef event;
600		static int xp = -1, yp;
601
602		if (xp == -1) {
603			xp = loc.x;
604			yp = loc.y;
605		}
606		if (xp != loc.x || yp != loc.y) {
607			int moved = 0;
608			if (p1 && p1 == d1) {
609				event = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDragged, loc, 0);
610				if (event != NULL) {
611					moved = 1;
612					CGEventPost(kCGHIDEventTap, event);
613					CFRelease(event);
614				}
615			}
616			if (p3 && p3 == d3) {
617				event = CGEventCreateMouseEvent(NULL, kCGEventOtherMouseDragged, loc, 0);
618				if (event != NULL) {
619					moved = 1;
620					CGEventPost(kCGHIDEventTap, event);
621					CFRelease(event);
622				}
623			}
624			if (p2 && p2 == d2) {
625				event = CGEventCreateMouseEvent(NULL, kCGEventRightMouseDragged, loc, 0);
626				if (event != NULL) {
627					moved = 1;
628					CGEventPost(kCGHIDEventTap, event);
629					CFRelease(event);
630				}
631			}
632			if (!moved) {
633				event = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, loc, 0);
634				if (event != NULL) {
635					CGEventPost(kCGHIDEventTap, event);
636					CFRelease(event);
637				}
638			}
639		}
640		xp = loc.x;
641		yp = loc.y;
642		if (p1 != d1) {
643			CGEventType type = (!p1 && d1) ? kCGEventLeftMouseDown : kCGEventLeftMouseUp;
644			event = CGEventCreateMouseEvent(NULL, type, loc, 0);
645			if (event != NULL) {
646				CGEventPost(kCGHIDEventTap, event);
647				CFRelease(event);
648			}
649		}
650		if (p3 != d3) {
651			CGEventType type = (!p3 && d3) ? kCGEventOtherMouseDown : kCGEventOtherMouseUp;
652			event = CGEventCreateMouseEvent(NULL, type, loc, kCGMouseButtonCenter);
653			if (event != NULL) {
654				CGEventPost(kCGHIDEventTap, event);
655				CFRelease(event);
656			}
657		}
658		if (p2 != d2) {
659			CGEventType type = (!p2 && d2) ? kCGEventRightMouseDown : kCGEventRightMouseUp;
660			event = CGEventCreateMouseEvent(NULL, type, loc, 0);
661			if (event != NULL) {
662				CGEventPost(kCGHIDEventTap, event);
663				CFRelease(event);
664			}
665		}
666#endif
667		if (mcnt++ < 10 || debug_pointer) fprintf(stderr, "CGEventCreateMouseEvent()\n");
668	}
669}
670
671void macosxCG_pointer_inject(int mask, int x, int y) {
672	int swap23 = macosx_swap23;
673	int s1 = 0, s2 = 1, s3 = 2, s4 = 3, s5 = 4;
674	CGPoint loc;
675	int wheel_distance = macosx_mouse_wheel_speed;
676	static int cnt = 0;
677	static int first = 1, prev1 = 0, prev2 = 0, prev3 = 0;
678	int curr1, curr2, curr3;
679
680	if (swap23) {
681		s2 = 2;
682		s3 = 1;
683	}
684
685	loc.x = x + off_x + coff_x;
686	loc.y = y + off_y + coff_y;
687
688	if ((cnt++ % 10) == 0) {
689		macosxCGP_undim();
690	}
691
692	if ((mask & (1 << s4))) {
693		CGPostScrollWheelEvent_wr(1,  wheel_distance);
694	}
695	if ((mask & (1 << s5))) {
696		CGPostScrollWheelEvent_wr(1, -wheel_distance);
697	}
698
699	curr1 = (mask & (1 << s1)) ? TRUE : FALSE;
700	curr2 = (mask & (1 << s2)) ? TRUE : FALSE;
701	curr3 = (mask & (1 << s3)) ? TRUE : FALSE;
702
703	if (first) {
704		prev1 = curr1;
705		prev2 = curr2;
706		prev3 = curr3;
707		first = 0;
708	}
709
710	CGPostMouseEvent_wr(loc, TRUE, 3, curr1, curr2, curr3, prev1, prev2, prev3);
711
712	prev1 = curr1;
713	prev2 = curr2;
714	prev3 = curr3;
715}
716
717#define keyTableSize 0xFFFF
718
719#include <rfb/keysym.h>
720
721static int USKeyCodes[] = {
722    /* The alphabet */
723    XK_A,                  0,      /* A */
724    XK_B,                 11,      /* B */
725    XK_C,                  8,      /* C */
726    XK_D,                  2,      /* D */
727    XK_E,                 14,      /* E */
728    XK_F,                  3,      /* F */
729    XK_G,                  5,      /* G */
730    XK_H,                  4,      /* H */
731    XK_I,                 34,      /* I */
732    XK_J,                 38,      /* J */
733    XK_K,                 40,      /* K */
734    XK_L,                 37,      /* L */
735    XK_M,                 46,      /* M */
736    XK_N,                 45,      /* N */
737    XK_O,                 31,      /* O */
738    XK_P,                 35,      /* P */
739    XK_Q,                 12,      /* Q */
740    XK_R,                 15,      /* R */
741    XK_S,                  1,      /* S */
742    XK_T,                 17,      /* T */
743    XK_U,                 32,      /* U */
744    XK_V,                  9,      /* V */
745    XK_W,                 13,      /* W */
746    XK_X,                  7,      /* X */
747    XK_Y,                 16,      /* Y */
748    XK_Z,                  6,      /* Z */
749    XK_a,                  0,      /* a */
750    XK_b,                 11,      /* b */
751    XK_c,                  8,      /* c */
752    XK_d,                  2,      /* d */
753    XK_e,                 14,      /* e */
754    XK_f,                  3,      /* f */
755    XK_g,                  5,      /* g */
756    XK_h,                  4,      /* h */
757    XK_i,                 34,      /* i */
758    XK_j,                 38,      /* j */
759    XK_k,                 40,      /* k */
760    XK_l,                 37,      /* l */
761    XK_m,                 46,      /* m */
762    XK_n,                 45,      /* n */
763    XK_o,                 31,      /* o */
764    XK_p,                 35,      /* p */
765    XK_q,                 12,      /* q */
766    XK_r,                 15,      /* r */
767    XK_s,                  1,      /* s */
768    XK_t,                 17,      /* t */
769    XK_u,                 32,      /* u */
770    XK_v,                  9,      /* v */
771    XK_w,                 13,      /* w */
772    XK_x,                  7,      /* x */
773    XK_y,                 16,      /* y */
774    XK_z,                  6,      /* z */
775
776    /* Numbers */
777    XK_0,                 29,      /* 0 */
778    XK_1,                 18,      /* 1 */
779    XK_2,                 19,      /* 2 */
780    XK_3,                 20,      /* 3 */
781    XK_4,                 21,      /* 4 */
782    XK_5,                 23,      /* 5 */
783    XK_6,                 22,      /* 6 */
784    XK_7,                 26,      /* 7 */
785    XK_8,                 28,      /* 8 */
786    XK_9,                 25,      /* 9 */
787
788    /* Symbols */
789    XK_exclam,            18,      /* ! */
790    XK_at,                19,      /* @ */
791    XK_numbersign,        20,      /* # */
792    XK_dollar,            21,      /* $ */
793    XK_percent,           23,      /* % */
794    XK_asciicircum,       22,      /* ^ */
795    XK_ampersand,         26,      /* & */
796    XK_asterisk,          28,      /* * */
797    XK_parenleft,         25,      /* ( */
798    XK_parenright,        29,      /* ) */
799    XK_minus,             27,      /* - */
800    XK_underscore,        27,      /* _ */
801    XK_equal,             24,      /* = */
802    XK_plus,              24,      /* + */
803    XK_grave,             50,      /* ` */  /* XXX ? */
804    XK_asciitilde,        50,      /* ~ */
805    XK_bracketleft,       33,      /* [ */
806    XK_braceleft,         33,      /* { */
807    XK_bracketright,      30,      /* ] */
808    XK_braceright,        30,      /* } */
809    XK_semicolon,         41,      /* ; */
810    XK_colon,             41,      /* : */
811    XK_apostrophe,        39,      /* ' */
812    XK_quotedbl,          39,      /* " */
813    XK_comma,             43,      /* , */
814    XK_less,              43,      /* < */
815    XK_period,            47,      /* . */
816    XK_greater,           47,      /* > */
817    XK_slash,             44,      /* / */
818    XK_question,          44,      /* ? */
819    XK_backslash,         42,      /* \ */
820    XK_bar,               42,      /* | */
821    /* OS X Sends this (END OF MEDIUM) for Shift-Tab (with US Keyboard) */
822    0x0019,               48,      /* Tab */
823    XK_space,             49,      /* Space */
824};
825
826static int SpecialKeyCodes[] = {
827    /* "Special" keys */
828    XK_Return,            36,      /* Return */
829    XK_Delete,           117,      /* Delete */
830    XK_Tab,               48,      /* Tab */
831    XK_Escape,            53,      /* Esc */
832    XK_Caps_Lock,         57,      /* Caps Lock */
833    XK_Num_Lock,          71,      /* Num Lock */
834    XK_Scroll_Lock,      107,      /* Scroll Lock */
835    XK_Pause,            113,      /* Pause */
836    XK_BackSpace,         51,      /* Backspace */
837    XK_Insert,           114,      /* Insert */
838
839    /* Cursor movement */
840    XK_Up,               126,      /* Cursor Up */
841    XK_Down,             125,      /* Cursor Down */
842    XK_Left,             123,      /* Cursor Left */
843    XK_Right,            124,      /* Cursor Right */
844    XK_Page_Up,          116,      /* Page Up */
845    XK_Page_Down,        121,      /* Page Down */
846    XK_Home,             115,      /* Home */
847    XK_End,              119,      /* End */
848
849    /* Numeric keypad */
850    XK_KP_0,              82,      /* KP 0 */
851    XK_KP_1,              83,      /* KP 1 */
852    XK_KP_2,              84,      /* KP 2 */
853    XK_KP_3,              85,      /* KP 3 */
854    XK_KP_4,              86,      /* KP 4 */
855    XK_KP_5,              87,      /* KP 5 */
856    XK_KP_6,              88,      /* KP 6 */
857    XK_KP_7,              89,      /* KP 7 */
858    XK_KP_8,              91,      /* KP 8 */
859    XK_KP_9,              92,      /* KP 9 */
860    XK_KP_Enter,          76,      /* KP Enter */
861    XK_KP_Decimal,        65,      /* KP . */
862    XK_KP_Add,            69,      /* KP + */
863    XK_KP_Subtract,       78,      /* KP - */
864    XK_KP_Multiply,       67,      /* KP * */
865    XK_KP_Divide,         75,      /* KP / */
866
867    /* Function keys */
868    XK_F1,               122,      /* F1 */
869    XK_F2,               120,      /* F2 */
870    XK_F3,                99,      /* F3 */
871    XK_F4,               118,      /* F4 */
872    XK_F5,                96,      /* F5 */
873    XK_F6,                97,      /* F6 */
874    XK_F7,                98,      /* F7 */
875    XK_F8,               100,      /* F8 */
876    XK_F9,               101,      /* F9 */
877    XK_F10,              109,      /* F10 */
878    XK_F11,              103,      /* F11 */
879    XK_F12,              111,      /* F12 */
880
881    /* Modifier keys */
882    XK_Alt_L,             55,      /* Alt Left (-> Command) */
883    XK_Alt_R,             55,      /* Alt Right (-> Command) */
884    XK_Shift_L,           56,      /* Shift Left */
885    XK_Shift_R,           56,      /* Shift Right */
886    XK_Meta_L,            58,      /* Option Left (-> Option) */
887    XK_Meta_R,            58,      /* Option Right (-> Option) */
888    XK_Super_L,           58,      /* Option Left (-> Option) */
889    XK_Super_R,           58,      /* Option Right (-> Option) */
890    XK_Control_L,         59,      /* Ctrl Left */
891    XK_Control_R,         59,      /* Ctrl Right */
892};
893
894CGKeyCode keyTable[keyTableSize];
895unsigned char keyTableMods[keyTableSize];
896
897void macosxCG_init_key_table(void) {
898	static int init = 0;
899	int i;
900	if (init) {
901		return;
902	}
903	init = 1;
904
905	for (i=0; i < keyTableSize; i++) {
906		keyTable[i] = 0xFFFF;
907		keyTableMods[i] = 0;
908	}
909	for (i=0; i< (int) (sizeof(USKeyCodes) / sizeof(int)); i += 2) {
910		int j = USKeyCodes[i];
911		keyTable[(unsigned short) j] = (CGKeyCode) USKeyCodes[i+1];
912	}
913	for (i=0; i< (int) (sizeof(SpecialKeyCodes) / sizeof(int)); i += 2) {
914		int j = SpecialKeyCodes[i];
915		keyTable[(unsigned short) j] = (CGKeyCode) SpecialKeyCodes[i+1];
916	}
917}
918
919extern void init_key_table(void);
920extern int macosx_us_kbd;
921
922extern int debug_keyboard;
923
924void CGPostKeyboardEvent_wr(CGCharCode keyChar, CGKeyCode keyCode, int down) {
925	static int post_mode = -1, mcnt = 0;
926
927#if !X11VNC_MACOSX_NO_DEPRECATED_POSTEVENTS && !X11VNC_MACOSX_NO_DEPRECATED
928	if (post_mode < 0) {
929		post_mode = 1;
930		if (getenv("X11VNC_MACOSX_NO_DEPRECATED_POSTEVENTS") || getenv("X11VNC_MACOSX_NO_DEPRECATED")) {
931			post_mode = 0;
932		}
933	}
934
935	if (post_mode) {
936		if (mcnt++ < 10 || debug_keyboard) fprintf(stderr, "CGPostKeyboardEvent(keyChar=%d, keyCode=%d, down=%d)\n", keyChar, keyCode, down);
937		CGPostKeyboardEvent(keyChar, keyCode, down);
938	} else
939#endif
940	{
941		/* XXX 10.4 and later */
942#ifndef X11VNC_MACOSX_NO_CGEVENTCREATEKEYBOARDEVENT
943		CGEventRef event;
944		event = CGEventCreateKeyboardEvent(NULL, keyCode, down);
945		if (event != NULL) {
946			CGEventPost(kCGHIDEventTap, event);
947			CFRelease(event);
948		}
949#endif
950		if (mcnt++ < 10 || debug_keyboard) fprintf(stderr, "CGEventCreateKeyboardEvent(NULL, keyCode=%d, down=%d)\n", keyCode, down);
951	}
952}
953
954void macosxCG_keycode_inject(int down, int keycode) {
955	CGKeyCode keyCode = (CGKeyCode) keycode;
956	CGCharCode keyChar = 0;
957
958	if (debug_keyboard) fprintf(stderr, "macosxCG_keycode_inject(down=%d, keycode=%d)\n", down, keycode);
959
960	CGPostKeyboardEvent_wr(keyChar, keyCode, down);
961}
962
963void macosxCG_keysym_inject(int down, unsigned int keysym) {
964	CGKeyCode keyCode = keyTable[(unsigned short)keysym];
965	CGCharCode keyChar = 0;
966#if 0
967	int pressModsForKeys = FALSE;
968	UInt32 modsForKey = keyTableMods[keysym] << 8;
969#endif
970
971	init_key_table();
972
973	if (debug_keyboard) fprintf(stderr, "macosxCG_keysym_inject(down=%d, keysym=%d)\n", down, (int) keysym);
974
975	if (keysym < 0xFF && macosx_us_kbd) {
976		keyChar = (CGCharCode) keysym;
977		if (debug_keyboard) fprintf(stderr, "macosxCG_keysym_inject keyChar=>%d\n", (int) keyChar);
978	}
979	if (keyCode == 0xFFFF) {
980		return;
981	}
982	macosxCGP_undim();
983
984	CGPostKeyboardEvent_wr(keyChar, keyCode, down);
985}
986
987#endif	/* __APPLE__ */
988
989
990