1 2/* 3 * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>. 4 * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge. 5 * All Rights Reserved. 6 * 7 * Cut in two parts by Johannes Schindelin (2001): libvncserver and OSXvnc. 8 * 9 * 10 * This file implements every system specific function for Mac OS X. 11 * 12 * It includes the keyboard functions: 13 * 14 void KbdAddEvent(down, keySym, cl) 15 rfbBool down; 16 rfbKeySym keySym; 17 rfbClientPtr cl; 18 void KbdReleaseAllKeys() 19 * 20 * the mouse functions: 21 * 22 void PtrAddEvent(buttonMask, x, y, cl) 23 int buttonMask; 24 int x; 25 int y; 26 rfbClientPtr cl; 27 * 28 */ 29 30#include <unistd.h> 31#include <ApplicationServices/ApplicationServices.h> 32#include <Carbon/Carbon.h> 33/* zlib doesn't like Byte already defined */ 34#undef Byte 35#undef TRUE 36#undef rfbBool 37#include <rfb/rfb.h> 38#include <rfb/keysym.h> 39 40#include <IOKit/pwr_mgt/IOPMLib.h> 41#include <IOKit/pwr_mgt/IOPM.h> 42#include <stdio.h> 43#include <signal.h> 44#include <pthread.h> 45 46rfbBool rfbNoDimming = FALSE; 47rfbBool rfbNoSleep = TRUE; 48 49static pthread_mutex_t dimming_mutex; 50static unsigned long dim_time; 51static unsigned long sleep_time; 52static mach_port_t master_dev_port; 53static io_connect_t power_mgt; 54static rfbBool initialized = FALSE; 55static rfbBool dim_time_saved = FALSE; 56static rfbBool sleep_time_saved = FALSE; 57 58static int 59saveDimSettings(void) 60{ 61 if (IOPMGetAggressiveness(power_mgt, 62 kPMMinutesToDim, 63 &dim_time) != kIOReturnSuccess) 64 return -1; 65 66 dim_time_saved = TRUE; 67 return 0; 68} 69 70static int 71restoreDimSettings(void) 72{ 73 if (!dim_time_saved) 74 return -1; 75 76 if (IOPMSetAggressiveness(power_mgt, 77 kPMMinutesToDim, 78 dim_time) != kIOReturnSuccess) 79 return -1; 80 81 dim_time_saved = FALSE; 82 dim_time = 0; 83 return 0; 84} 85 86static int 87saveSleepSettings(void) 88{ 89 if (IOPMGetAggressiveness(power_mgt, 90 kPMMinutesToSleep, 91 &sleep_time) != kIOReturnSuccess) 92 return -1; 93 94 sleep_time_saved = TRUE; 95 return 0; 96} 97 98static int 99restoreSleepSettings(void) 100{ 101 if (!sleep_time_saved) 102 return -1; 103 104 if (IOPMSetAggressiveness(power_mgt, 105 kPMMinutesToSleep, 106 sleep_time) != kIOReturnSuccess) 107 return -1; 108 109 sleep_time_saved = FALSE; 110 sleep_time = 0; 111 return 0; 112} 113 114 115int 116rfbDimmingInit(void) 117{ 118 pthread_mutex_init(&dimming_mutex, NULL); 119 120 if (IOMasterPort(bootstrap_port, &master_dev_port) != kIOReturnSuccess) 121 return -1; 122 123 if (!(power_mgt = IOPMFindPowerManagement(master_dev_port))) 124 return -1; 125 126 if (rfbNoDimming) { 127 if (saveDimSettings() < 0) 128 return -1; 129 if (IOPMSetAggressiveness(power_mgt, 130 kPMMinutesToDim, 0) != kIOReturnSuccess) 131 return -1; 132 } 133 134 if (rfbNoSleep) { 135 if (saveSleepSettings() < 0) 136 return -1; 137 if (IOPMSetAggressiveness(power_mgt, 138 kPMMinutesToSleep, 0) != kIOReturnSuccess) 139 return -1; 140 } 141 142 initialized = TRUE; 143 return 0; 144} 145 146 147int 148rfbUndim(void) 149{ 150 int result = -1; 151 152 pthread_mutex_lock(&dimming_mutex); 153 154 if (!initialized) 155 goto DONE; 156 157 if (!rfbNoDimming) { 158 if (saveDimSettings() < 0) 159 goto DONE; 160 if (IOPMSetAggressiveness(power_mgt, kPMMinutesToDim, 0) != kIOReturnSuccess) 161 goto DONE; 162 if (restoreDimSettings() < 0) 163 goto DONE; 164 } 165 166 if (!rfbNoSleep) { 167 if (saveSleepSettings() < 0) 168 goto DONE; 169 if (IOPMSetAggressiveness(power_mgt, kPMMinutesToSleep, 0) != kIOReturnSuccess) 170 goto DONE; 171 if (restoreSleepSettings() < 0) 172 goto DONE; 173 } 174 175 result = 0; 176 177 DONE: 178 pthread_mutex_unlock(&dimming_mutex); 179 return result; 180} 181 182 183int 184rfbDimmingShutdown(void) 185{ 186 int result = -1; 187 188 if (!initialized) 189 goto DONE; 190 191 pthread_mutex_lock(&dimming_mutex); 192 if (dim_time_saved) 193 if (restoreDimSettings() < 0) 194 goto DONE; 195 if (sleep_time_saved) 196 if (restoreSleepSettings() < 0) 197 goto DONE; 198 199 result = 0; 200 201 DONE: 202 pthread_mutex_unlock(&dimming_mutex); 203 return result; 204} 205 206rfbScreenInfoPtr rfbScreen; 207 208void rfbShutdown(rfbClientPtr cl); 209 210/* some variables to enable special behaviour */ 211int startTime = -1, maxSecsToConnect = 0; 212rfbBool disconnectAfterFirstClient = TRUE; 213 214/* Where do I get the "official" list of Mac key codes? 215 Ripped these out of a Mac II emulator called Basilisk II 216 that I found on the net. */ 217static int keyTable[] = { 218 /* The alphabet */ 219 XK_A, 0, /* A */ 220 XK_B, 11, /* B */ 221 XK_C, 8, /* C */ 222 XK_D, 2, /* D */ 223 XK_E, 14, /* E */ 224 XK_F, 3, /* F */ 225 XK_G, 5, /* G */ 226 XK_H, 4, /* H */ 227 XK_I, 34, /* I */ 228 XK_J, 38, /* J */ 229 XK_K, 40, /* K */ 230 XK_L, 37, /* L */ 231 XK_M, 46, /* M */ 232 XK_N, 45, /* N */ 233 XK_O, 31, /* O */ 234 XK_P, 35, /* P */ 235 XK_Q, 12, /* Q */ 236 XK_R, 15, /* R */ 237 XK_S, 1, /* S */ 238 XK_T, 17, /* T */ 239 XK_U, 32, /* U */ 240 XK_V, 9, /* V */ 241 XK_W, 13, /* W */ 242 XK_X, 7, /* X */ 243 XK_Y, 16, /* Y */ 244 XK_Z, 6, /* Z */ 245 XK_a, 0, /* a */ 246 XK_b, 11, /* b */ 247 XK_c, 8, /* c */ 248 XK_d, 2, /* d */ 249 XK_e, 14, /* e */ 250 XK_f, 3, /* f */ 251 XK_g, 5, /* g */ 252 XK_h, 4, /* h */ 253 XK_i, 34, /* i */ 254 XK_j, 38, /* j */ 255 XK_k, 40, /* k */ 256 XK_l, 37, /* l */ 257 XK_m, 46, /* m */ 258 XK_n, 45, /* n */ 259 XK_o, 31, /* o */ 260 XK_p, 35, /* p */ 261 XK_q, 12, /* q */ 262 XK_r, 15, /* r */ 263 XK_s, 1, /* s */ 264 XK_t, 17, /* t */ 265 XK_u, 32, /* u */ 266 XK_v, 9, /* v */ 267 XK_w, 13, /* w */ 268 XK_x, 7, /* x */ 269 XK_y, 16, /* y */ 270 XK_z, 6, /* z */ 271 272 /* Numbers */ 273 XK_0, 29, /* 0 */ 274 XK_1, 18, /* 1 */ 275 XK_2, 19, /* 2 */ 276 XK_3, 20, /* 3 */ 277 XK_4, 21, /* 4 */ 278 XK_5, 23, /* 5 */ 279 XK_6, 22, /* 6 */ 280 XK_7, 26, /* 7 */ 281 XK_8, 28, /* 8 */ 282 XK_9, 25, /* 9 */ 283 284 /* Symbols */ 285 XK_exclam, 18, /* ! */ 286 XK_at, 19, /* @ */ 287 XK_numbersign, 20, /* # */ 288 XK_dollar, 21, /* $ */ 289 XK_percent, 23, /* % */ 290 XK_asciicircum, 22, /* ^ */ 291 XK_ampersand, 26, /* & */ 292 XK_asterisk, 28, /* * */ 293 XK_parenleft, 25, /* ( */ 294 XK_parenright, 29, /* ) */ 295 XK_minus, 27, /* - */ 296 XK_underscore, 27, /* _ */ 297 XK_equal, 24, /* = */ 298 XK_plus, 24, /* + */ 299 XK_grave, 10, /* ` */ /* XXX ? */ 300 XK_asciitilde, 10, /* ~ */ 301 XK_bracketleft, 33, /* [ */ 302 XK_braceleft, 33, /* { */ 303 XK_bracketright, 30, /* ] */ 304 XK_braceright, 30, /* } */ 305 XK_semicolon, 41, /* ; */ 306 XK_colon, 41, /* : */ 307 XK_apostrophe, 39, /* ' */ 308 XK_quotedbl, 39, /* " */ 309 XK_comma, 43, /* , */ 310 XK_less, 43, /* < */ 311 XK_period, 47, /* . */ 312 XK_greater, 47, /* > */ 313 XK_slash, 44, /* / */ 314 XK_question, 44, /* ? */ 315 XK_backslash, 42, /* \ */ 316 XK_bar, 42, /* | */ 317 318 /* "Special" keys */ 319 XK_space, 49, /* Space */ 320 XK_Return, 36, /* Return */ 321 XK_Delete, 117, /* Delete */ 322 XK_Tab, 48, /* Tab */ 323 XK_Escape, 53, /* Esc */ 324 XK_Caps_Lock, 57, /* Caps Lock */ 325 XK_Num_Lock, 71, /* Num Lock */ 326 XK_Scroll_Lock, 107, /* Scroll Lock */ 327 XK_Pause, 113, /* Pause */ 328 XK_BackSpace, 51, /* Backspace */ 329 XK_Insert, 114, /* Insert */ 330 331 /* Cursor movement */ 332 XK_Up, 126, /* Cursor Up */ 333 XK_Down, 125, /* Cursor Down */ 334 XK_Left, 123, /* Cursor Left */ 335 XK_Right, 124, /* Cursor Right */ 336 XK_Page_Up, 116, /* Page Up */ 337 XK_Page_Down, 121, /* Page Down */ 338 XK_Home, 115, /* Home */ 339 XK_End, 119, /* End */ 340 341 /* Numeric keypad */ 342 XK_KP_0, 82, /* KP 0 */ 343 XK_KP_1, 83, /* KP 1 */ 344 XK_KP_2, 84, /* KP 2 */ 345 XK_KP_3, 85, /* KP 3 */ 346 XK_KP_4, 86, /* KP 4 */ 347 XK_KP_5, 87, /* KP 5 */ 348 XK_KP_6, 88, /* KP 6 */ 349 XK_KP_7, 89, /* KP 7 */ 350 XK_KP_8, 91, /* KP 8 */ 351 XK_KP_9, 92, /* KP 9 */ 352 XK_KP_Enter, 76, /* KP Enter */ 353 XK_KP_Decimal, 65, /* KP . */ 354 XK_KP_Add, 69, /* KP + */ 355 XK_KP_Subtract, 78, /* KP - */ 356 XK_KP_Multiply, 67, /* KP * */ 357 XK_KP_Divide, 75, /* KP / */ 358 359 /* Function keys */ 360 XK_F1, 122, /* F1 */ 361 XK_F2, 120, /* F2 */ 362 XK_F3, 99, /* F3 */ 363 XK_F4, 118, /* F4 */ 364 XK_F5, 96, /* F5 */ 365 XK_F6, 97, /* F6 */ 366 XK_F7, 98, /* F7 */ 367 XK_F8, 100, /* F8 */ 368 XK_F9, 101, /* F9 */ 369 XK_F10, 109, /* F10 */ 370 XK_F11, 103, /* F11 */ 371 XK_F12, 111, /* F12 */ 372 373 /* Modifier keys */ 374 XK_Shift_L, 56, /* Shift Left */ 375 XK_Shift_R, 56, /* Shift Right */ 376 XK_Control_L, 59, /* Ctrl Left */ 377 XK_Control_R, 59, /* Ctrl Right */ 378 XK_Meta_L, 58, /* Logo Left (-> Option) */ 379 XK_Meta_R, 58, /* Logo Right (-> Option) */ 380 XK_Alt_L, 55, /* Alt Left (-> Command) */ 381 XK_Alt_R, 55, /* Alt Right (-> Command) */ 382 383 /* Weirdness I can't figure out */ 384#if 0 385 XK_3270_PrintScreen, 105, /* PrintScrn */ 386 ??? 94, 50, /* International */ 387 XK_Menu, 50, /* Menu (-> International) */ 388#endif 389}; 390 391void 392KbdAddEvent(rfbBool down, rfbKeySym keySym, struct _rfbClientRec* cl) 393{ 394 int i; 395 CGKeyCode keyCode = -1; 396 int found = 0; 397 398 if(((int)cl->clientData)==-1) return; /* viewOnly */ 399 400 rfbUndim(); 401 402 for (i = 0; i < (sizeof(keyTable) / sizeof(int)); i += 2) { 403 if (keyTable[i] == keySym) { 404 keyCode = keyTable[i+1]; 405 found = 1; 406 break; 407 } 408 } 409 410 if (!found) { 411 rfbErr("warning: couldn't figure out keycode for X keysym %d (0x%x)\n", 412 (int)keySym, (int)keySym); 413 } else { 414 /* Hopefully I can get away with not specifying a CGCharCode. 415 (Why would you need both?) */ 416 CGPostKeyboardEvent((CGCharCode)0, keyCode, down); 417 } 418} 419 420void 421PtrAddEvent(buttonMask, x, y, cl) 422 int buttonMask; 423 int x; 424 int y; 425 rfbClientPtr cl; 426{ 427 CGPoint position; 428 429 if(((int)cl->clientData)==-1) return; /* viewOnly */ 430 431 rfbUndim(); 432 433 position.x = x; 434 position.y = y; 435 436 CGPostMouseEvent(position, TRUE, 8, 437 (buttonMask & (1 << 0)) ? TRUE : FALSE, 438 (buttonMask & (1 << 1)) ? TRUE : FALSE, 439 (buttonMask & (1 << 2)) ? TRUE : FALSE, 440 (buttonMask & (1 << 3)) ? TRUE : FALSE, 441 (buttonMask & (1 << 4)) ? TRUE : FALSE, 442 (buttonMask & (1 << 5)) ? TRUE : FALSE, 443 (buttonMask & (1 << 6)) ? TRUE : FALSE, 444 (buttonMask & (1 << 7)) ? TRUE : FALSE); 445} 446 447rfbBool viewOnly = FALSE, sharedMode = FALSE; 448 449void 450ScreenInit(int argc, char**argv) 451{ 452 int bitsPerSample=CGDisplayBitsPerSample(kCGDirectMainDisplay); 453 rfbScreen = rfbGetScreen(&argc,argv, 454 CGDisplayPixelsWide(kCGDirectMainDisplay), 455 CGDisplayPixelsHigh(kCGDirectMainDisplay), 456 bitsPerSample, 457 CGDisplaySamplesPerPixel(kCGDirectMainDisplay),4); 458 if(!rfbScreen) 459 exit(0); 460 rfbScreen->serverFormat.redShift = bitsPerSample*2; 461 rfbScreen->serverFormat.greenShift = bitsPerSample*1; 462 rfbScreen->serverFormat.blueShift = 0; 463 464 gethostname(rfbScreen->thisHost, 255); 465 rfbScreen->paddedWidthInBytes = CGDisplayBytesPerRow(kCGDirectMainDisplay); 466 rfbScreen->frameBuffer = 467 (char *)CGDisplayBaseAddress(kCGDirectMainDisplay); 468 469 /* we cannot write to the frame buffer */ 470 rfbScreen->cursor = NULL; 471 472 rfbScreen->ptrAddEvent = PtrAddEvent; 473 rfbScreen->kbdAddEvent = KbdAddEvent; 474 475 if(sharedMode) { 476 rfbScreen->alwaysShared = TRUE; 477 } 478 479 rfbInitServer(rfbScreen); 480} 481 482static void 483refreshCallback(CGRectCount count, const CGRect *rectArray, void *ignore) 484{ 485 int i; 486 487 if(startTime>0 && time(0)>startTime+maxSecsToConnect) 488 rfbShutdown(0); 489 490 for (i = 0; i < count; i++) 491 rfbMarkRectAsModified(rfbScreen, 492 rectArray[i].origin.x,rectArray[i].origin.y, 493 rectArray[i].origin.x + rectArray[i].size.width, 494 rectArray[i].origin.y + rectArray[i].size.height); 495} 496 497void clientGone(rfbClientPtr cl) 498{ 499 rfbShutdown(cl); 500} 501 502enum rfbNewClientAction newClient(rfbClientPtr cl) 503{ 504 if(startTime>0 && time(0)>startTime+maxSecsToConnect) 505 rfbShutdown(cl); 506 507 if(disconnectAfterFirstClient) 508 cl->clientGoneHook = clientGone; 509 510 cl->clientData=(void*)((viewOnly)?-1:0); 511 512 return(RFB_CLIENT_ACCEPT); 513} 514 515int main(int argc,char *argv[]) 516{ 517 int i; 518 519 for(i=argc-1;i>0;i--) 520 if(i<argc-1 && strcmp(argv[i],"-wait4client")==0) { 521 maxSecsToConnect = atoi(argv[i+1])/1000; 522 startTime = time(0); 523 } else if(strcmp(argv[i],"-runforever")==0) { 524 disconnectAfterFirstClient = FALSE; 525 } else if(strcmp(argv[i],"-viewonly")==0) { 526 viewOnly=TRUE; 527 } else if(strcmp(argv[i],"-shared")==0) { 528 sharedMode=TRUE; 529 } 530 531 rfbDimmingInit(); 532 533 ScreenInit(argc,argv); 534 rfbScreen->newClientHook = newClient; 535 536 /* enter background event loop */ 537 rfbRunEventLoop(rfbScreen,40,TRUE); 538 539 /* enter OS X loop */ 540 CGRegisterScreenRefreshCallback(refreshCallback, NULL); 541 RunApplicationEventLoop(); 542 543 rfbDimmingShutdown(); 544 545 return(0); /* never ... */ 546} 547 548void rfbShutdown(rfbClientPtr cl) 549{ 550 rfbScreenCleanup(rfbScreen); 551 rfbDimmingShutdown(); 552 exit(0); 553} 554