You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libtdevnc/x11vnc/macosxCG.c

631 lines
18 KiB

/* -- macosxCG.c -- */
/*
* We need to keep this separate from nearly everything else, e.g. rfb.h
* and the other stuff, otherwise it does not work properly, mouse drags
* will not work!!
*/
void macosxCG_dummy(void) {}
#if (defined(__MACH__) && defined(__APPLE__))
#include <ApplicationServices/ApplicationServices.h>
#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h>
void macosxCG_init(void);
void macosxCG_fini(void);
void macosxCG_event_loop(void);
char *macosxCG_get_fb_addr(void);
int macosxCG_CGDisplayPixelsWide(void);
int macosxCG_CGDisplayPixelsHigh(void);
int macosxCG_CGDisplayBitsPerPixel(void);
int macosxCG_CGDisplayBitsPerSample(void);
int macosxCG_CGDisplaySamplesPerPixel(void);
int macosxCG_CGDisplayBytesPerRow(void);
void macosxCG_pointer_inject(int mask, int x, int y);
int macosxCG_get_cursor_pos(int *x, int *y);
int macosxCG_get_cursor(void);
void macosxCG_init_key_table(void);
void macosxCG_key_inject(int down, unsigned int keysym);
void macosxCG_keycode_inject(int down, int keycode);
CGDirectDisplayID displayID = 0;
extern void macosx_log(char *);
extern int collect_non_X_xdamage(int x_in, int y_in, int w_in, int h_in, int call);
static void macosxCG_callback(CGRectCount n, const CGRect *rects, void *dum) {
int i, db = 0;
if (db) fprintf(stderr, "macosx_callback: n=%d\n", (int) n);
if (!dum) {}
for (i=0; i < (int) n; i++) {
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);
collect_non_X_xdamage( (int) rects[i].origin.x, (int) rects[i].origin.y,
(int) rects[i].size.width, (int) rects[i].size.height, 1);
}
}
int dragum(void) {
#if 0
int x =200, y = 150, dy = 10, i;
CGPoint loc;
CGDirectDisplayID displayID2 = kCGDirectMainDisplay;
(void) GetMainDevice();
for (i=0; i< 50; i++) {
usleep(1000*100);
loc.x = x;
loc.y = y + i*dy;
CGPostMouseEvent(loc, TRUE, 1, TRUE);
}
CGPostMouseEvent(loc, TRUE, 1, FALSE);
usleep(4*1000*1000);
#endif
return 0;
}
static int callback_set = 0;
extern int nofb;
void macosxCG_refresh_callback_on(void) {
if (nofb) {
return;
}
if (! callback_set) {
if (1) macosx_log("macosxCG_callback: register\n");
CGRegisterScreenRefreshCallback(macosxCG_callback, NULL);
}
callback_set = 1;
}
void macosxCG_refresh_callback_off(void) {
if (callback_set) {
if (1) macosx_log("macosxCG_callback: unregister\n");
CGUnregisterScreenRefreshCallback(macosxCG_callback, NULL);
}
callback_set = 0;
}
extern int macosx_noscreensaver;
extern void macosxGCS_initpb(void);
extern int macosxCGP_init_dimming(void);
extern int macosxCGP_undim(void);
extern int macosxCGP_dim_shutdown(void);
extern void macosxCGP_screensaver_timer_off(void);
extern void macosxCGP_screensaver_timer_on(void);
void macosxCG_init(void) {
if (displayID == 0) {
macosx_log("macosxCG_init: initializing display.\n");
#if 0
dragum();
#endif
displayID = kCGDirectMainDisplay;
(void) GetMainDevice();
CGSetLocalEventsSuppressionInterval(0.0);
CGSetLocalEventsFilterDuringSupressionState(
kCGEventFilterMaskPermitAllEvents,
kCGEventSupressionStateSupressionInterval);
CGSetLocalEventsFilterDuringSupressionState(
kCGEventFilterMaskPermitAllEvents,
kCGEventSupressionStateRemoteMouseDrag);
macosxCGP_init_dimming();
if (macosx_noscreensaver) {
macosxCGP_screensaver_timer_on();
}
macosxGCS_initpb();
}
}
void macosxCG_fini(void) {
macosxCGP_dim_shutdown();
if (macosx_noscreensaver) {
macosxCGP_screensaver_timer_off();
}
macosxCG_refresh_callback_off();
}
extern int dpy_x, dpy_y, bpp, wdpy_x, wdpy_y;
extern int client_count, nofb;
extern void do_new_fb(int);
extern int macosx_wait_for_switch, macosx_resize;
extern void macosxGCS_poll_pb(void);
#if 0
extern void usleep(unsigned long usec);
#else
extern int usleep(useconds_t usec);
#endif
extern unsigned int sleep(unsigned int seconds);
extern void clean_up_exit(int ret);
void macosxCG_event_loop(void) {
OSStatus rc;
int nbpp;
macosxGCS_poll_pb();
if (nofb) {
return;
}
rc = RunCurrentEventLoop(kEventDurationSecond/30);
if (client_count) {
macosxCG_refresh_callback_on();
} else {
macosxCG_refresh_callback_off();
}
nbpp = macosxCG_CGDisplayBitsPerPixel();
if (nbpp > 0 && nbpp != bpp) {
if (macosx_resize) {
do_new_fb(1);
}
} else if (wdpy_x != (int) CGDisplayPixelsWide(displayID)) {
if (wdpy_y != (int) CGDisplayPixelsHigh(displayID)) {
if (macosx_wait_for_switch) {
int cnt = 0;
while (1) {
if(CGDisplayPixelsWide(displayID) > 0) {
if(CGDisplayPixelsHigh(displayID) > 0) {
usleep(500*1000);
break;
}
}
if ((cnt++ % 120) == 0) {
macosx_log("waiting for user to "
"switch back..\n");
}
sleep(1);
}
if (wdpy_x == (int) CGDisplayPixelsWide(displayID)) {
if (wdpy_y == (int) CGDisplayPixelsHigh(displayID)) {
macosx_log("we're back...\n");
return;
}
}
}
if (macosx_resize) {
do_new_fb(1);
}
}
}
}
char *macosxCG_get_fb_addr(void) {
macosxCG_init();
return (char *) CGDisplayBaseAddress(displayID);
}
int macosxCG_CGDisplayPixelsWide(void) {
return (int) CGDisplayPixelsWide(displayID);
}
int macosxCG_CGDisplayPixelsHigh(void) {
return (int) CGDisplayPixelsHigh(displayID);
}
int macosxCG_CGDisplayBitsPerPixel(void) {
return (int) CGDisplayBitsPerPixel(displayID);
}
int macosxCG_CGDisplayBitsPerSample(void) {
return (int) CGDisplayBitsPerSample(displayID);
}
int macosxCG_CGDisplaySamplesPerPixel(void) {
return (int) CGDisplaySamplesPerPixel(displayID);
}
int macosxCG_CGDisplayBytesPerRow(void) {
return (int) CGDisplayBytesPerRow(displayID);;
}
typedef int CGSConnectionRef;
static CGSConnectionRef conn = 0;
extern CGError CGSNewConnection(void*, CGSConnectionRef*);
extern CGError CGSReleaseConnection(CGSConnectionRef);
extern CGError CGSGetGlobalCursorDataSize(CGSConnectionRef, int*);
extern CGError CGSGetGlobalCursorData(CGSConnectionRef, unsigned char*,
int*, int*, CGRect*, CGPoint*, int*, int*, int*);
extern CGError CGSGetCurrentCursorLocation(CGSConnectionRef, CGPoint*);
extern int CGSCurrentCursorSeed(void);
extern int CGSHardwareCursorActive();
static unsigned int last_local_button_mask = 0;
static unsigned int last_local_mod_mask = 0;
static int last_local_x = 0;
static int last_local_y = 0;
extern unsigned int display_button_mask;
extern unsigned int display_mod_mask;
extern int got_local_pointer_input;
extern time_t last_local_input;
static CGPoint current_cursor_pos(void) {
CGPoint pos;
pos.x = 0;
pos.y = 0;
if (! conn) {
if (CGSNewConnection(NULL, &conn) != kCGErrorSuccess) {
macosx_log("CGSNewConnection error.\n");
if (!dpy_x || !dpy_y || !wdpy_x || !wdpy_y) {
clean_up_exit(1);
}
}
}
if (CGSGetCurrentCursorLocation(conn, &pos) != kCGErrorSuccess) {
macosx_log("CGSGetCurrentCursorLocation error\n");
}
display_button_mask = GetCurrentButtonState();
#if 0
/* not used yet */
display_mod_mask = GetCurrentKeyModifiers();
#endif
if (last_local_button_mask != display_button_mask) {
got_local_pointer_input++;
last_local_input = time(NULL);
} else if (pos.x != last_local_x || pos.y != last_local_y) {
got_local_pointer_input++;
last_local_input = time(NULL);
}
last_local_button_mask = display_button_mask;
last_local_mod_mask = display_mod_mask;
last_local_x = pos.x;
last_local_y = pos.y;
return pos;
}
int macosxCG_get_cursor_pos(int *x, int *y) {
CGPoint pos = current_cursor_pos();
*x = pos.x;
*y = pos.y;
return 1;
}
extern int get_cursor_serial(int);
extern int store_cursor(int serial, unsigned long *data, int w, int h, int cbpp, int xhot, int yhot);
int macosxCG_get_cursor(void) {
int last_idx = (int) get_cursor_serial(1);
int which = 1;
CGError err;
int datasize, row_bytes, cdepth, comps, bpcomp;
CGRect rect;
CGPoint hot;
unsigned char *data;
int cursor_seed;
static int last_cursor_seed = -1;
static time_t last_fetch = 0;
time_t now = time(NULL);
if (last_idx) {
which = last_idx;
}
if (! conn) {
if (CGSNewConnection(NULL, &conn) != kCGErrorSuccess) {
macosx_log("CGSNewConnection error.\n");
if (!dpy_x || !dpy_y || !wdpy_x || !wdpy_y) {
clean_up_exit(1);
}
return which;
}
}
cursor_seed = CGSCurrentCursorSeed();
if (last_idx && cursor_seed == last_cursor_seed) {
if (now < last_fetch + 2) {
return which;
}
}
last_cursor_seed = cursor_seed;
last_fetch = now;
if (CGSGetGlobalCursorDataSize(conn, &datasize) != kCGErrorSuccess) {
macosx_log("CGSGetGlobalCursorDataSize error\n");
return which;
}
data = (unsigned char*) malloc(datasize);
err = CGSGetGlobalCursorData(conn, data, &datasize, &row_bytes,
&rect, &hot, &cdepth, &comps, &bpcomp);
if (err != kCGErrorSuccess) {
macosx_log("CGSGetGlobalCursorData error\n");
return which;
}
if (cdepth == 24) {
cdepth = 32;
}
which = store_cursor(cursor_seed, (unsigned long*) data,
(int) rect.size.width, (int) rect.size.height, cdepth, (int) hot.x, (int) hot.y);
free(data);
return(which);
}
extern int macosx_mouse_wheel_speed;
extern int macosx_swap23;
extern int off_x, coff_x, off_y, coff_y;
void macosxCG_pointer_inject(int mask, int x, int y) {
int swap23 = macosx_swap23;
int s1 = 0, s2 = 1, s3 = 2, s4 = 3, s5 = 4;
CGPoint loc;
int wheel_distance = macosx_mouse_wheel_speed;
static int cnt = 0;
if (swap23) {
s2 = 2;
s3 = 1;
}
loc.x = x + off_x + coff_x;
loc.y = y + off_y + coff_y;
if ((cnt++ % 10) == 0) {
macosxCGP_undim();
}
if ((mask & (1 << s4))) {
CGPostScrollWheelEvent(1, wheel_distance);
}
if ((mask & (1 << s5))) {
CGPostScrollWheelEvent(1, -wheel_distance);
}
CGPostMouseEvent(loc, TRUE, 3,
(mask & (1 << s1)) ? TRUE : FALSE,
(mask & (1 << s2)) ? TRUE : FALSE,
(mask & (1 << s3)) ? TRUE : FALSE
);
}
#define keyTableSize 0xFFFF
#include <rfb/keysym.h>
static int USKeyCodes[] = {
/* The alphabet */
XK_A, 0, /* A */
XK_B, 11, /* B */
XK_C, 8, /* C */
XK_D, 2, /* D */
XK_E, 14, /* E */
XK_F, 3, /* F */
XK_G, 5, /* G */
XK_H, 4, /* H */
XK_I, 34, /* I */
XK_J, 38, /* J */
XK_K, 40, /* K */
XK_L, 37, /* L */
XK_M, 46, /* M */
XK_N, 45, /* N */
XK_O, 31, /* O */
XK_P, 35, /* P */
XK_Q, 12, /* Q */
XK_R, 15, /* R */
XK_S, 1, /* S */
XK_T, 17, /* T */
XK_U, 32, /* U */
XK_V, 9, /* V */
XK_W, 13, /* W */
XK_X, 7, /* X */
XK_Y, 16, /* Y */
XK_Z, 6, /* Z */
XK_a, 0, /* a */
XK_b, 11, /* b */
XK_c, 8, /* c */
XK_d, 2, /* d */
XK_e, 14, /* e */
XK_f, 3, /* f */
XK_g, 5, /* g */
XK_h, 4, /* h */
XK_i, 34, /* i */
XK_j, 38, /* j */
XK_k, 40, /* k */
XK_l, 37, /* l */
XK_m, 46, /* m */
XK_n, 45, /* n */
XK_o, 31, /* o */
XK_p, 35, /* p */
XK_q, 12, /* q */
XK_r, 15, /* r */
XK_s, 1, /* s */
XK_t, 17, /* t */
XK_u, 32, /* u */
XK_v, 9, /* v */
XK_w, 13, /* w */
XK_x, 7, /* x */
XK_y, 16, /* y */
XK_z, 6, /* z */
/* Numbers */
XK_0, 29, /* 0 */
XK_1, 18, /* 1 */
XK_2, 19, /* 2 */
XK_3, 20, /* 3 */
XK_4, 21, /* 4 */
XK_5, 23, /* 5 */
XK_6, 22, /* 6 */
XK_7, 26, /* 7 */
XK_8, 28, /* 8 */
XK_9, 25, /* 9 */
/* Symbols */
XK_exclam, 18, /* ! */
XK_at, 19, /* @ */
XK_numbersign, 20, /* # */
XK_dollar, 21, /* $ */
XK_percent, 23, /* % */
XK_asciicircum, 22, /* ^ */
XK_ampersand, 26, /* & */
XK_asterisk, 28, /* * */
XK_parenleft, 25, /* ( */
XK_parenright, 29, /* ) */
XK_minus, 27, /* - */
XK_underscore, 27, /* _ */
XK_equal, 24, /* = */
XK_plus, 24, /* + */
XK_grave, 50, /* ` */ /* XXX ? */
XK_asciitilde, 50, /* ~ */
XK_bracketleft, 33, /* [ */
XK_braceleft, 33, /* { */
XK_bracketright, 30, /* ] */
XK_braceright, 30, /* } */
XK_semicolon, 41, /* ; */
XK_colon, 41, /* : */
XK_apostrophe, 39, /* ' */
XK_quotedbl, 39, /* " */
XK_comma, 43, /* , */
XK_less, 43, /* < */
XK_period, 47, /* . */
XK_greater, 47, /* > */
XK_slash, 44, /* / */
XK_question, 44, /* ? */
XK_backslash, 42, /* \ */
XK_bar, 42, /* | */
/* OS X Sends this (END OF MEDIUM) for Shift-Tab (with US Keyboard) */
0x0019, 48, /* Tab */
XK_space, 49, /* Space */
};
static int SpecialKeyCodes[] = {
/* "Special" keys */
XK_Return, 36, /* Return */
XK_Delete, 117, /* Delete */
XK_Tab, 48, /* Tab */
XK_Escape, 53, /* Esc */
XK_Caps_Lock, 57, /* Caps Lock */
XK_Num_Lock, 71, /* Num Lock */
XK_Scroll_Lock, 107, /* Scroll Lock */
XK_Pause, 113, /* Pause */
XK_BackSpace, 51, /* Backspace */
XK_Insert, 114, /* Insert */
/* Cursor movement */
XK_Up, 126, /* Cursor Up */
XK_Down, 125, /* Cursor Down */
XK_Left, 123, /* Cursor Left */
XK_Right, 124, /* Cursor Right */
XK_Page_Up, 116, /* Page Up */
XK_Page_Down, 121, /* Page Down */
XK_Home, 115, /* Home */
XK_End, 119, /* End */
/* Numeric keypad */
XK_KP_0, 82, /* KP 0 */
XK_KP_1, 83, /* KP 1 */
XK_KP_2, 84, /* KP 2 */
XK_KP_3, 85, /* KP 3 */
XK_KP_4, 86, /* KP 4 */
XK_KP_5, 87, /* KP 5 */
XK_KP_6, 88, /* KP 6 */
XK_KP_7, 89, /* KP 7 */
XK_KP_8, 91, /* KP 8 */
XK_KP_9, 92, /* KP 9 */
XK_KP_Enter, 76, /* KP Enter */
XK_KP_Decimal, 65, /* KP . */
XK_KP_Add, 69, /* KP + */
XK_KP_Subtract, 78, /* KP - */
XK_KP_Multiply, 67, /* KP * */
XK_KP_Divide, 75, /* KP / */
/* Function keys */
XK_F1, 122, /* F1 */
XK_F2, 120, /* F2 */
XK_F3, 99, /* F3 */
XK_F4, 118, /* F4 */
XK_F5, 96, /* F5 */
XK_F6, 97, /* F6 */
XK_F7, 98, /* F7 */
XK_F8, 100, /* F8 */
XK_F9, 101, /* F9 */
XK_F10, 109, /* F10 */
XK_F11, 103, /* F11 */
XK_F12, 111, /* F12 */
/* Modifier keys */
XK_Alt_L, 55, /* Alt Left (-> Command) */
XK_Alt_R, 55, /* Alt Right (-> Command) */
XK_Shift_L, 56, /* Shift Left */
XK_Shift_R, 56, /* Shift Right */
XK_Meta_L, 58, /* Option Left (-> Option) */
XK_Meta_R, 58, /* Option Right (-> Option) */
XK_Super_L, 58, /* Option Left (-> Option) */
XK_Super_R, 58, /* Option Right (-> Option) */
XK_Control_L, 59, /* Ctrl Left */
XK_Control_R, 59, /* Ctrl Right */
};
CGKeyCode keyTable[keyTableSize];
unsigned char keyTableMods[keyTableSize];
void macosxCG_init_key_table(void) {
static int init = 0;
int i;
if (init) {
return;
}
init = 1;
for (i=0; i < keyTableSize; i++) {
keyTable[i] = 0xFFFF;
keyTableMods[i] = 0;
}
for (i=0; i< (int) (sizeof(USKeyCodes) / sizeof(int)); i += 2) {
int j = USKeyCodes[i];
keyTable[(unsigned short) j] = (CGKeyCode) USKeyCodes[i+1];
}
for (i=0; i< (int) (sizeof(SpecialKeyCodes) / sizeof(int)); i += 2) {
int j = SpecialKeyCodes[i];
keyTable[(unsigned short) j] = (CGKeyCode) SpecialKeyCodes[i+1];
}
}
extern void init_key_table(void);
extern int macosx_us_kbd;
void macosxCG_keycode_inject(int down, int keycode) {
CGKeyCode keyCode = (CGKeyCode) keycode;
CGCharCode keyChar = 0;
CGPostKeyboardEvent(keyChar, keyCode, down);
}
void macosxCG_key_inject(int down, unsigned int keysym) {
CGKeyCode keyCode = keyTable[(unsigned short)keysym];
CGCharCode keyChar = 0;
#if 0
int pressModsForKeys = FALSE;
UInt32 modsForKey = keyTableMods[keysym] << 8;
#endif
init_key_table();
if (keysym < 0xFF && macosx_us_kbd) {
keyChar = (CGCharCode) keysym;
}
if (keyCode == 0xFFFF) {
return;
}
macosxCGP_undim();
CGPostKeyboardEvent(keyChar, keyCode, down);
}
#endif /* __APPLE__ */