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.

пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. /* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. #include <config.h>
  20. #endif
  21. #include <FL/Fl.H>
  22. #include <FL/Fl_Window.H>
  23. #include <FL/x.H>
  24. #import <Cocoa/Cocoa.h>
  25. #import <Carbon/Carbon.h>
  26. #include <IOKit/hidsystem/IOHIDLib.h>
  27. #include <IOKit/hidsystem/IOHIDParameter.h>
  28. #define XK_LATIN1
  29. #define XK_MISCELLANY
  30. #define XK_XKB_KEYS
  31. #include <rfb/keysymdef.h>
  32. #include <rfb/XF86keysym.h>
  33. #include <rfb/Rect.h>
  34. #include "keysym2ucs.h"
  35. #define NoSymbol 0
  36. // This wasn't added until 10.12
  37. #if !defined(MAC_OS_X_VERSION_10_12) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
  38. const int kVK_RightCommand = 0x36;
  39. #endif
  40. // And this is still missing
  41. const int kVK_Menu = 0x6E;
  42. static bool captured = false;
  43. int cocoa_get_level(Fl_Window *win)
  44. {
  45. NSWindow *nsw;
  46. nsw = (NSWindow*)fl_xid(win);
  47. return [nsw level];
  48. }
  49. void cocoa_set_level(Fl_Window *win, int level)
  50. {
  51. NSWindow *nsw;
  52. nsw = (NSWindow*)fl_xid(win);
  53. [nsw setLevel:level];
  54. }
  55. int cocoa_capture_displays(Fl_Window *win)
  56. {
  57. NSWindow *nsw;
  58. nsw = (NSWindow*)fl_xid(win);
  59. CGDisplayCount count;
  60. CGDirectDisplayID displays[16];
  61. int sx, sy, sw, sh;
  62. rfb::Rect windows_rect, screen_rect;
  63. windows_rect.setXYWH(win->x(), win->y(), win->w(), win->h());
  64. if (CGGetActiveDisplayList(16, displays, &count) != kCGErrorSuccess)
  65. return 1;
  66. if (count != (unsigned)Fl::screen_count())
  67. return 1;
  68. for (int i = 0; i < Fl::screen_count(); i++) {
  69. Fl::screen_xywh(sx, sy, sw, sh, i);
  70. screen_rect.setXYWH(sx, sy, sw, sh);
  71. if (screen_rect.enclosed_by(windows_rect)) {
  72. if (CGDisplayCapture(displays[i]) != kCGErrorSuccess)
  73. return 1;
  74. } else {
  75. // A display might have been captured with the previous
  76. // monitor selection. In that case we don't want to keep
  77. // it when its no longer inside the window_rect.
  78. CGDisplayRelease(displays[i]);
  79. }
  80. }
  81. captured = true;
  82. if ([nsw level] == CGShieldingWindowLevel())
  83. return 0;
  84. [nsw setLevel:CGShieldingWindowLevel()];
  85. // We're not getting put in front of the shielding window in many
  86. // cases on macOS 13, despite setLevel: being documented as also
  87. // pushing the window to the front. So let's explicitly move it.
  88. [nsw orderFront:nsw];
  89. return 0;
  90. }
  91. void cocoa_release_displays(Fl_Window *win)
  92. {
  93. NSWindow *nsw;
  94. int newlevel;
  95. if (captured)
  96. CGReleaseAllDisplays();
  97. captured = false;
  98. nsw = (NSWindow*)fl_xid(win);
  99. // Someone else has already changed the level of this window
  100. if ([nsw level] != CGShieldingWindowLevel())
  101. return;
  102. // FIXME: Store the previous level somewhere so we don't have to hard
  103. // code a level here.
  104. if (win->fullscreen_active() && win->contains(Fl::focus()))
  105. newlevel = NSStatusWindowLevel;
  106. else
  107. newlevel = NSNormalWindowLevel;
  108. // Only change if different as the level change also moves the window
  109. // to the top of that level.
  110. if ([nsw level] != newlevel)
  111. [nsw setLevel:newlevel];
  112. }
  113. CGColorSpaceRef cocoa_win_color_space(Fl_Window *win)
  114. {
  115. NSWindow *nsw;
  116. NSColorSpace *nscs;
  117. nsw = (NSWindow*)fl_xid(win);
  118. nscs = [nsw colorSpace];
  119. if (nscs == nil) {
  120. // Offscreen, so return standard SRGB color space
  121. assert(false);
  122. return CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
  123. }
  124. CGColorSpaceRef lut = [nscs CGColorSpace];
  125. // We want a permanent reference, not an autorelease
  126. CGColorSpaceRetain(lut);
  127. return lut;
  128. }
  129. bool cocoa_win_is_zoomed(Fl_Window *win)
  130. {
  131. NSWindow *nsw;
  132. nsw = (NSWindow*)fl_xid(win);
  133. return [nsw isZoomed];
  134. }
  135. void cocoa_win_zoom(Fl_Window *win)
  136. {
  137. NSWindow *nsw;
  138. nsw = (NSWindow*)fl_xid(win);
  139. [nsw zoom:nsw];
  140. }
  141. int cocoa_is_keyboard_sync(const void *event)
  142. {
  143. const NSEvent* nsevent = (const NSEvent*)event;
  144. assert(event);
  145. // If we get a NSFlagsChanged event with key code 0 then this isn't
  146. // an actual keyboard event but rather the system trying to sync up
  147. // modifier state after it has stolen input for some reason (e.g.
  148. // Cmd+Tab)
  149. if ([nsevent type] != NSFlagsChanged)
  150. return 0;
  151. if ([nsevent keyCode] != 0)
  152. return 0;
  153. return 1;
  154. }
  155. int cocoa_is_keyboard_event(const void *event)
  156. {
  157. NSEvent *nsevent;
  158. nsevent = (NSEvent*)event;
  159. switch ([nsevent type]) {
  160. case NSKeyDown:
  161. case NSKeyUp:
  162. case NSFlagsChanged:
  163. if (cocoa_is_keyboard_sync(event))
  164. return 0;
  165. return 1;
  166. default:
  167. return 0;
  168. }
  169. }
  170. int cocoa_is_key_press(const void *event)
  171. {
  172. NSEvent *nsevent;
  173. nsevent = (NSEvent*)event;
  174. if ([nsevent type] == NSKeyDown)
  175. return 1;
  176. if ([nsevent type] == NSFlagsChanged) {
  177. UInt32 mask;
  178. // We don't see any event on release of CapsLock
  179. if ([nsevent keyCode] == kVK_CapsLock)
  180. return 1;
  181. // These are entirely undocumented, but I cannot find any other way
  182. // of differentiating between left and right keys
  183. switch ([nsevent keyCode]) {
  184. case kVK_RightCommand:
  185. mask = 0x0010;
  186. break;
  187. case kVK_Command:
  188. mask = 0x0008;
  189. break;
  190. case kVK_Shift:
  191. mask = 0x0002;
  192. break;
  193. case kVK_CapsLock:
  194. // We don't see any event on release of CapsLock
  195. return 1;
  196. case kVK_Option:
  197. mask = 0x0020;
  198. break;
  199. case kVK_Control:
  200. mask = 0x0001;
  201. break;
  202. case kVK_RightShift:
  203. mask = 0x0004;
  204. break;
  205. case kVK_RightOption:
  206. mask = 0x0040;
  207. break;
  208. case kVK_RightControl:
  209. mask = 0x2000;
  210. break;
  211. default:
  212. return 0;
  213. }
  214. if ([nsevent modifierFlags] & mask)
  215. return 1;
  216. else
  217. return 0;
  218. }
  219. return 0;
  220. }
  221. int cocoa_event_keycode(const void *event)
  222. {
  223. NSEvent *nsevent;
  224. int keycode;
  225. nsevent = (NSEvent*)event;
  226. keycode = [nsevent keyCode];
  227. // macOS swaps these two keys for unknown reasons for ISO layouts
  228. if (KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) {
  229. if (keycode == kVK_ANSI_Grave)
  230. return kVK_ISO_Section;
  231. if (keycode == kVK_ISO_Section)
  232. return kVK_ANSI_Grave;
  233. }
  234. return keycode;
  235. }
  236. static NSString *key_translate(UInt16 keyCode, UInt32 modifierFlags)
  237. {
  238. const UCKeyboardLayout *layout;
  239. OSStatus err;
  240. layout = NULL;
  241. TISInputSourceRef keyboard;
  242. CFDataRef uchr;
  243. keyboard = TISCopyCurrentKeyboardLayoutInputSource();
  244. uchr = (CFDataRef)TISGetInputSourceProperty(keyboard,
  245. kTISPropertyUnicodeKeyLayoutData);
  246. if (uchr == NULL)
  247. return nil;
  248. layout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
  249. if (layout == NULL)
  250. return nil;
  251. UInt32 dead_state;
  252. UniCharCount max_len, actual_len;
  253. UniChar string[255];
  254. dead_state = 0;
  255. max_len = sizeof(string)/sizeof(*string);
  256. modifierFlags = (modifierFlags >> 8) & 0xff;
  257. err = UCKeyTranslate(layout, keyCode, kUCKeyActionDown, modifierFlags,
  258. LMGetKbdType(), 0, &dead_state, max_len, &actual_len,
  259. string);
  260. if (err != noErr)
  261. return nil;
  262. // Dead key?
  263. if (dead_state != 0) {
  264. // We have no fool proof way of asking what dead key this is.
  265. // Assume we get a spacing equivalent if we press the
  266. // same key again, and try to deduce something from that.
  267. err = UCKeyTranslate(layout, keyCode, kUCKeyActionDown, modifierFlags,
  268. LMGetKbdType(), 0, &dead_state, max_len, &actual_len,
  269. string);
  270. if (err != noErr)
  271. return nil;
  272. }
  273. return [NSString stringWithCharacters:string length:actual_len];
  274. }
  275. static const int kvk_map[][2] = {
  276. { kVK_Return, XK_Return },
  277. { kVK_Tab, XK_Tab },
  278. { kVK_Space, XK_space },
  279. { kVK_Delete, XK_BackSpace },
  280. { kVK_Escape, XK_Escape },
  281. { kVK_RightCommand, XK_Super_R },
  282. { kVK_Command, XK_Super_L },
  283. { kVK_Shift, XK_Shift_L },
  284. { kVK_CapsLock, XK_Caps_Lock },
  285. { kVK_Option, XK_Alt_L },
  286. { kVK_Control, XK_Control_L },
  287. { kVK_RightShift, XK_Shift_R },
  288. { kVK_RightOption, XK_Alt_R },
  289. { kVK_RightControl, XK_Control_R },
  290. { kVK_F17, XK_F17 },
  291. { kVK_VolumeUp, XF86XK_AudioRaiseVolume },
  292. { kVK_VolumeDown, XF86XK_AudioLowerVolume },
  293. { kVK_Mute, XF86XK_AudioMute },
  294. { kVK_F18, XK_F18 },
  295. { kVK_F19, XK_F19 },
  296. { kVK_F20, XK_F20 },
  297. { kVK_F5, XK_F5 },
  298. { kVK_F6, XK_F6 },
  299. { kVK_F7, XK_F7 },
  300. { kVK_F3, XK_F3 },
  301. { kVK_F8, XK_F8 },
  302. { kVK_F9, XK_F9 },
  303. { kVK_F11, XK_F11 },
  304. { kVK_F13, XK_F13 },
  305. { kVK_F16, XK_F16 },
  306. { kVK_F14, XK_F14 },
  307. { kVK_F10, XK_F10 },
  308. { kVK_Menu, XK_Menu },
  309. { kVK_F12, XK_F12 },
  310. { kVK_F15, XK_F15 },
  311. // Should we send Insert here?
  312. { kVK_Help, XK_Help },
  313. { kVK_Home, XK_Home },
  314. { kVK_PageUp, XK_Page_Up },
  315. { kVK_ForwardDelete, XK_Delete },
  316. { kVK_F4, XK_F4 },
  317. { kVK_End, XK_End },
  318. { kVK_F2, XK_F2 },
  319. { kVK_PageDown, XK_Page_Down },
  320. { kVK_F1, XK_F1 },
  321. { kVK_LeftArrow, XK_Left },
  322. { kVK_RightArrow, XK_Right },
  323. { kVK_DownArrow, XK_Down },
  324. { kVK_UpArrow, XK_Up },
  325. // The OS X headers claim these keys are not layout independent.
  326. // Could it be because of the state of the decimal key?
  327. /* { kVK_ANSI_KeypadDecimal, XK_KP_Decimal }, */ // see below
  328. { kVK_ANSI_KeypadMultiply, XK_KP_Multiply },
  329. { kVK_ANSI_KeypadPlus, XK_KP_Add },
  330. // OS X doesn't have NumLock, so is this really correct?
  331. { kVK_ANSI_KeypadClear, XK_Num_Lock },
  332. { kVK_ANSI_KeypadDivide, XK_KP_Divide },
  333. { kVK_ANSI_KeypadEnter, XK_KP_Enter },
  334. { kVK_ANSI_KeypadMinus, XK_KP_Subtract },
  335. { kVK_ANSI_KeypadEquals, XK_KP_Equal },
  336. { kVK_ANSI_Keypad0, XK_KP_0 },
  337. { kVK_ANSI_Keypad1, XK_KP_1 },
  338. { kVK_ANSI_Keypad2, XK_KP_2 },
  339. { kVK_ANSI_Keypad3, XK_KP_3 },
  340. { kVK_ANSI_Keypad4, XK_KP_4 },
  341. { kVK_ANSI_Keypad5, XK_KP_5 },
  342. { kVK_ANSI_Keypad6, XK_KP_6 },
  343. { kVK_ANSI_Keypad7, XK_KP_7 },
  344. { kVK_ANSI_Keypad8, XK_KP_8 },
  345. { kVK_ANSI_Keypad9, XK_KP_9 },
  346. // Japanese Keyboard Support
  347. { kVK_JIS_Eisu, XK_Eisu_toggle },
  348. { kVK_JIS_Kana, XK_Hiragana_Katakana },
  349. };
  350. int cocoa_event_keysym(const void *event)
  351. {
  352. NSEvent *nsevent;
  353. UInt16 key_code;
  354. size_t i;
  355. NSString *chars;
  356. UInt32 modifiers;
  357. nsevent = (NSEvent*)event;
  358. key_code = [nsevent keyCode];
  359. // Start with keys that either don't generate a symbol, or
  360. // generate the same symbol as some other key.
  361. for (i = 0;i < sizeof(kvk_map)/sizeof(kvk_map[0]);i++) {
  362. if (key_code == kvk_map[i][0])
  363. return kvk_map[i][1];
  364. }
  365. // OS X always sends the same key code for the decimal key on the
  366. // num pad, but X11 wants different keysyms depending on if it should
  367. // be a comma or full stop.
  368. if (key_code == 0x41) {
  369. switch ([[nsevent charactersIgnoringModifiers] UTF8String][0]) {
  370. case ',':
  371. return XK_KP_Separator;
  372. case '.':
  373. return XK_KP_Decimal;
  374. default:
  375. return NoSymbol;
  376. }
  377. }
  378. // We want a "normal" symbol out of the event, which basically means
  379. // we only respect the shift and alt/altgr modifiers. Cocoa can help
  380. // us if we only wanted shift, but as we also want alt/altgr, we'll
  381. // have to do some lookup ourselves. This matches our behaviour on
  382. // other platforms.
  383. modifiers = 0;
  384. if ([nsevent modifierFlags] & NSAlphaShiftKeyMask)
  385. modifiers |= alphaLock;
  386. if ([nsevent modifierFlags] & NSShiftKeyMask)
  387. modifiers |= shiftKey;
  388. if ([nsevent modifierFlags] & NSAlternateKeyMask)
  389. modifiers |= optionKey;
  390. chars = key_translate(key_code, modifiers);
  391. if (chars == nil)
  392. return NoSymbol;
  393. // FIXME: Some dead keys are given as NBSP + combining character
  394. if ([chars length] != 1)
  395. return NoSymbol;
  396. // Dead key?
  397. if ([[nsevent characters] length] == 0)
  398. return ucs2keysym(ucs2combining([chars characterAtIndex:0]));
  399. return ucs2keysym([chars characterAtIndex:0]);
  400. }
  401. static int cocoa_open_hid(io_connect_t *ioc)
  402. {
  403. kern_return_t ret;
  404. io_service_t ios;
  405. CFMutableDictionaryRef mdict;
  406. mdict = IOServiceMatching(kIOHIDSystemClass);
  407. ios = IOServiceGetMatchingService(kIOMasterPortDefault,
  408. (CFDictionaryRef) mdict);
  409. if (!ios)
  410. return KERN_FAILURE;
  411. ret = IOServiceOpen(ios, mach_task_self(), kIOHIDParamConnectType, ioc);
  412. IOObjectRelease(ios);
  413. if (ret != KERN_SUCCESS)
  414. return ret;
  415. return KERN_SUCCESS;
  416. }
  417. static int cocoa_set_modifier_lock_state(int modifier, bool on)
  418. {
  419. kern_return_t ret;
  420. io_connect_t ioc;
  421. ret = cocoa_open_hid(&ioc);
  422. if (ret != KERN_SUCCESS)
  423. return ret;
  424. ret = IOHIDSetModifierLockState(ioc, modifier, on);
  425. IOServiceClose(ioc);
  426. if (ret != KERN_SUCCESS)
  427. return ret;
  428. return KERN_SUCCESS;
  429. }
  430. static int cocoa_get_modifier_lock_state(int modifier, bool *on)
  431. {
  432. kern_return_t ret;
  433. io_connect_t ioc;
  434. ret = cocoa_open_hid(&ioc);
  435. if (ret != KERN_SUCCESS)
  436. return ret;
  437. ret = IOHIDGetModifierLockState(ioc, modifier, on);
  438. IOServiceClose(ioc);
  439. if (ret != KERN_SUCCESS)
  440. return ret;
  441. return KERN_SUCCESS;
  442. }
  443. int cocoa_set_caps_lock_state(bool on)
  444. {
  445. return cocoa_set_modifier_lock_state(kIOHIDCapsLockState, on);
  446. }
  447. int cocoa_set_num_lock_state(bool on)
  448. {
  449. return cocoa_set_modifier_lock_state(kIOHIDNumLockState, on);
  450. }
  451. int cocoa_get_caps_lock_state(bool *on)
  452. {
  453. return cocoa_get_modifier_lock_state(kIOHIDCapsLockState, on);
  454. }
  455. int cocoa_get_num_lock_state(bool *on)
  456. {
  457. return cocoa_get_modifier_lock_state(kIOHIDNumLockState, on);
  458. }