Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  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 "keysym2ucs.h"
  34. #define NoSymbol 0
  35. // This wasn't added until 10.12
  36. #if !defined(MAC_OS_X_VERSION_10_12) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
  37. const int kVK_RightCommand = 0x36;
  38. #endif
  39. // And this is still missing
  40. const int kVK_Menu = 0x6E;
  41. static bool captured = false;
  42. int cocoa_capture_display(Fl_Window *win, bool all_displays)
  43. {
  44. NSWindow *nsw;
  45. nsw = (NSWindow*)fl_xid(win);
  46. if (!captured) {
  47. if (all_displays) {
  48. if (CGCaptureAllDisplays() != kCGErrorSuccess)
  49. return 1;
  50. } else {
  51. CGDirectDisplayID displays[16];
  52. CGDisplayCount count;
  53. int index;
  54. if (CGGetActiveDisplayList(16, displays, &count) != kCGErrorSuccess)
  55. return 1;
  56. if (count != (unsigned)Fl::screen_count())
  57. return 1;
  58. index = Fl::screen_num(win->x(), win->y(), win->w(), win->h());
  59. if (CGDisplayCapture(displays[index]) != kCGErrorSuccess)
  60. return 1;
  61. }
  62. captured = true;
  63. }
  64. if ([nsw level] == CGShieldingWindowLevel())
  65. return 0;
  66. [nsw setLevel:CGShieldingWindowLevel()];
  67. return 0;
  68. }
  69. void cocoa_release_display(Fl_Window *win)
  70. {
  71. NSWindow *nsw;
  72. int newlevel;
  73. if (captured)
  74. CGReleaseAllDisplays();
  75. captured = false;
  76. nsw = (NSWindow*)fl_xid(win);
  77. // Someone else has already changed the level of this window
  78. if ([nsw level] != CGShieldingWindowLevel())
  79. return;
  80. // FIXME: Store the previous level somewhere so we don't have to hard
  81. // code a level here.
  82. if (win->fullscreen_active() && win->contains(Fl::focus()))
  83. newlevel = NSStatusWindowLevel;
  84. else
  85. newlevel = NSNormalWindowLevel;
  86. // Only change if different as the level change also moves the window
  87. // to the top of that level.
  88. if ([nsw level] != newlevel)
  89. [nsw setLevel:newlevel];
  90. }
  91. CGColorSpaceRef cocoa_win_color_space(Fl_Window *win)
  92. {
  93. NSWindow *nsw;
  94. NSColorSpace *nscs;
  95. nsw = (NSWindow*)fl_xid(win);
  96. nscs = [nsw colorSpace];
  97. if (nscs == nil) {
  98. // Offscreen, so return standard SRGB color space
  99. assert(false);
  100. return CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
  101. }
  102. CGColorSpaceRef lut = [nscs CGColorSpace];
  103. // We want a permanent reference, not an autorelease
  104. CGColorSpaceRetain(lut);
  105. return lut;
  106. }
  107. bool cocoa_win_is_zoomed(Fl_Window *win)
  108. {
  109. NSWindow *nsw;
  110. nsw = (NSWindow*)fl_xid(win);
  111. return [nsw isZoomed];
  112. }
  113. void cocoa_win_zoom(Fl_Window *win)
  114. {
  115. NSWindow *nsw;
  116. nsw = (NSWindow*)fl_xid(win);
  117. [nsw zoom:nsw];
  118. }
  119. int cocoa_is_keyboard_event(const void *event)
  120. {
  121. NSEvent *nsevent;
  122. nsevent = (NSEvent*)event;
  123. switch ([nsevent type]) {
  124. case NSKeyDown:
  125. case NSKeyUp:
  126. case NSFlagsChanged:
  127. return 1;
  128. default:
  129. return 0;
  130. }
  131. }
  132. int cocoa_is_key_press(const void *event)
  133. {
  134. NSEvent *nsevent;
  135. nsevent = (NSEvent*)event;
  136. if ([nsevent type] == NSKeyDown)
  137. return 1;
  138. if ([nsevent type] == NSFlagsChanged) {
  139. UInt32 mask;
  140. // We don't see any event on release of CapsLock
  141. if ([nsevent keyCode] == kVK_CapsLock)
  142. return 1;
  143. // These are entirely undocumented, but I cannot find any other way
  144. // of differentiating between left and right keys
  145. switch ([nsevent keyCode]) {
  146. case kVK_RightCommand:
  147. mask = 0x0010;
  148. break;
  149. case kVK_Command:
  150. mask = 0x0008;
  151. break;
  152. case kVK_Shift:
  153. mask = 0x0002;
  154. break;
  155. case kVK_CapsLock:
  156. // We don't see any event on release of CapsLock
  157. return 1;
  158. case kVK_Option:
  159. mask = 0x0020;
  160. break;
  161. case kVK_Control:
  162. mask = 0x0001;
  163. break;
  164. case kVK_RightShift:
  165. mask = 0x0004;
  166. break;
  167. case kVK_RightOption:
  168. mask = 0x0040;
  169. break;
  170. case kVK_RightControl:
  171. mask = 0x2000;
  172. break;
  173. default:
  174. return 0;
  175. }
  176. if ([nsevent modifierFlags] & mask)
  177. return 1;
  178. else
  179. return 0;
  180. }
  181. return 0;
  182. }
  183. int cocoa_event_keycode(const void *event)
  184. {
  185. NSEvent *nsevent;
  186. nsevent = (NSEvent*)event;
  187. return [nsevent keyCode];
  188. }
  189. static NSString *key_translate(UInt16 keyCode, UInt32 modifierFlags)
  190. {
  191. const UCKeyboardLayout *layout;
  192. OSStatus err;
  193. layout = NULL;
  194. TISInputSourceRef keyboard;
  195. CFDataRef uchr;
  196. keyboard = TISCopyCurrentKeyboardLayoutInputSource();
  197. uchr = (CFDataRef)TISGetInputSourceProperty(keyboard,
  198. kTISPropertyUnicodeKeyLayoutData);
  199. if (uchr == NULL)
  200. return nil;
  201. layout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
  202. if (layout == NULL)
  203. return nil;
  204. UInt32 dead_state;
  205. UniCharCount max_len, actual_len;
  206. UniChar string[255];
  207. dead_state = 0;
  208. max_len = sizeof(string)/sizeof(*string);
  209. modifierFlags = (modifierFlags >> 8) & 0xff;
  210. err = UCKeyTranslate(layout, keyCode, kUCKeyActionDown, modifierFlags,
  211. LMGetKbdType(), 0, &dead_state, max_len, &actual_len,
  212. string);
  213. if (err != noErr)
  214. return nil;
  215. // Dead key?
  216. if (dead_state != 0) {
  217. // We have no fool proof way of asking what dead key this is.
  218. // Assume we get a spacing equivalent if we press the
  219. // same key again, and try to deduce something from that.
  220. err = UCKeyTranslate(layout, keyCode, kUCKeyActionDown, modifierFlags,
  221. LMGetKbdType(), 0, &dead_state, max_len, &actual_len,
  222. string);
  223. if (err != noErr)
  224. return nil;
  225. }
  226. return [NSString stringWithCharacters:string length:actual_len];
  227. }
  228. static const int kvk_map[][2] = {
  229. { kVK_Return, XK_Return },
  230. { kVK_Tab, XK_Tab },
  231. { kVK_Space, XK_space },
  232. { kVK_Delete, XK_BackSpace },
  233. { kVK_Escape, XK_Escape },
  234. { kVK_RightCommand, XK_Super_R },
  235. { kVK_Command, XK_Super_L },
  236. { kVK_Shift, XK_Shift_L },
  237. { kVK_CapsLock, XK_Caps_Lock },
  238. { kVK_Option, XK_Alt_L },
  239. { kVK_Control, XK_Control_L },
  240. { kVK_RightShift, XK_Shift_R },
  241. { kVK_RightOption, XK_Alt_R },
  242. { kVK_RightControl, XK_Control_R },
  243. { kVK_F17, XK_F17 },
  244. { kVK_VolumeUp, XF86XK_AudioRaiseVolume },
  245. { kVK_VolumeDown, XF86XK_AudioLowerVolume },
  246. { kVK_Mute, XF86XK_AudioMute },
  247. { kVK_F18, XK_F18 },
  248. { kVK_F19, XK_F19 },
  249. { kVK_F20, XK_F20 },
  250. { kVK_F5, XK_F5 },
  251. { kVK_F6, XK_F6 },
  252. { kVK_F7, XK_F7 },
  253. { kVK_F3, XK_F3 },
  254. { kVK_F8, XK_F8 },
  255. { kVK_F9, XK_F9 },
  256. { kVK_F11, XK_F11 },
  257. { kVK_F13, XK_F13 },
  258. { kVK_F16, XK_F16 },
  259. { kVK_F14, XK_F14 },
  260. { kVK_F10, XK_F10 },
  261. { kVK_Menu, XK_Menu },
  262. { kVK_F12, XK_F12 },
  263. { kVK_F15, XK_F15 },
  264. // Should we send Insert here?
  265. { kVK_Help, XK_Help },
  266. { kVK_Home, XK_Home },
  267. { kVK_PageUp, XK_Page_Up },
  268. { kVK_ForwardDelete, XK_Delete },
  269. { kVK_F4, XK_F4 },
  270. { kVK_End, XK_End },
  271. { kVK_F2, XK_F2 },
  272. { kVK_PageDown, XK_Page_Down },
  273. { kVK_F1, XK_F1 },
  274. { kVK_LeftArrow, XK_Left },
  275. { kVK_RightArrow, XK_Right },
  276. { kVK_DownArrow, XK_Down },
  277. { kVK_UpArrow, XK_Up },
  278. // The OS X headers claim these keys are not layout independent.
  279. // Could it be because of the state of the decimal key?
  280. /* { kVK_ANSI_KeypadDecimal, XK_KP_Decimal }, */ // see below
  281. { kVK_ANSI_KeypadMultiply, XK_KP_Multiply },
  282. { kVK_ANSI_KeypadPlus, XK_KP_Add },
  283. // OS X doesn't have NumLock, so is this really correct?
  284. { kVK_ANSI_KeypadClear, XK_Num_Lock },
  285. { kVK_ANSI_KeypadDivide, XK_KP_Divide },
  286. { kVK_ANSI_KeypadEnter, XK_KP_Enter },
  287. { kVK_ANSI_KeypadMinus, XK_KP_Subtract },
  288. { kVK_ANSI_KeypadEquals, XK_KP_Equal },
  289. { kVK_ANSI_Keypad0, XK_KP_0 },
  290. { kVK_ANSI_Keypad1, XK_KP_1 },
  291. { kVK_ANSI_Keypad2, XK_KP_2 },
  292. { kVK_ANSI_Keypad3, XK_KP_3 },
  293. { kVK_ANSI_Keypad4, XK_KP_4 },
  294. { kVK_ANSI_Keypad5, XK_KP_5 },
  295. { kVK_ANSI_Keypad6, XK_KP_6 },
  296. { kVK_ANSI_Keypad7, XK_KP_7 },
  297. { kVK_ANSI_Keypad8, XK_KP_8 },
  298. { kVK_ANSI_Keypad9, XK_KP_9 },
  299. };
  300. int cocoa_event_keysym(const void *event)
  301. {
  302. NSEvent *nsevent;
  303. UInt16 key_code;
  304. size_t i;
  305. NSString *chars;
  306. UInt32 modifiers;
  307. nsevent = (NSEvent*)event;
  308. key_code = [nsevent keyCode];
  309. // Start with keys that either don't generate a symbol, or
  310. // generate the same symbol as some other key.
  311. for (i = 0;i < sizeof(kvk_map)/sizeof(kvk_map[0]);i++) {
  312. if (key_code == kvk_map[i][0])
  313. return kvk_map[i][1];
  314. }
  315. // OS X always sends the same key code for the decimal key on the
  316. // num pad, but X11 wants different keysyms depending on if it should
  317. // be a comma or full stop.
  318. if (key_code == 0x41) {
  319. switch ([[nsevent charactersIgnoringModifiers] UTF8String][0]) {
  320. case ',':
  321. return XK_KP_Separator;
  322. case '.':
  323. return XK_KP_Decimal;
  324. default:
  325. return NoSymbol;
  326. }
  327. }
  328. // We want a "normal" symbol out of the event, which basically means
  329. // we only respect the shift and alt/altgr modifiers. Cocoa can help
  330. // us if we only wanted shift, but as we also want alt/altgr, we'll
  331. // have to do some lookup ourselves. This matches our behaviour on
  332. // other platforms.
  333. modifiers = 0;
  334. if ([nsevent modifierFlags] & NSAlphaShiftKeyMask)
  335. modifiers |= alphaLock;
  336. if ([nsevent modifierFlags] & NSShiftKeyMask)
  337. modifiers |= shiftKey;
  338. if ([nsevent modifierFlags] & NSAlternateKeyMask)
  339. modifiers |= optionKey;
  340. chars = key_translate(key_code, modifiers);
  341. if (chars == nil)
  342. return NoSymbol;
  343. // FIXME: Some dead keys are given as NBSP + combining character
  344. if ([chars length] != 1)
  345. return NoSymbol;
  346. // Dead key?
  347. if ([[nsevent characters] length] == 0)
  348. return ucs2keysym(ucs2combining([chars characterAtIndex:0]));
  349. return ucs2keysym([chars characterAtIndex:0]);
  350. }
  351. static int cocoa_open_hid(io_connect_t *ioc)
  352. {
  353. kern_return_t ret;
  354. io_service_t ios;
  355. CFMutableDictionaryRef mdict;
  356. mdict = IOServiceMatching(kIOHIDSystemClass);
  357. ios = IOServiceGetMatchingService(kIOMasterPortDefault,
  358. (CFDictionaryRef) mdict);
  359. if (!ios)
  360. return KERN_FAILURE;
  361. ret = IOServiceOpen(ios, mach_task_self(), kIOHIDParamConnectType, ioc);
  362. IOObjectRelease(ios);
  363. if (ret != KERN_SUCCESS)
  364. return ret;
  365. return KERN_SUCCESS;
  366. }
  367. static int cocoa_set_modifier_lock_state(int modifier, bool on)
  368. {
  369. kern_return_t ret;
  370. io_connect_t ioc;
  371. ret = cocoa_open_hid(&ioc);
  372. if (ret != KERN_SUCCESS)
  373. return ret;
  374. ret = IOHIDSetModifierLockState(ioc, modifier, on);
  375. IOServiceClose(ioc);
  376. if (ret != KERN_SUCCESS)
  377. return ret;
  378. return KERN_SUCCESS;
  379. }
  380. static int cocoa_get_modifier_lock_state(int modifier, bool *on)
  381. {
  382. kern_return_t ret;
  383. io_connect_t ioc;
  384. ret = cocoa_open_hid(&ioc);
  385. if (ret != KERN_SUCCESS)
  386. return ret;
  387. ret = IOHIDGetModifierLockState(ioc, modifier, on);
  388. IOServiceClose(ioc);
  389. if (ret != KERN_SUCCESS)
  390. return ret;
  391. return KERN_SUCCESS;
  392. }
  393. int cocoa_set_caps_lock_state(bool on)
  394. {
  395. return cocoa_set_modifier_lock_state(kIOHIDCapsLockState, on);
  396. }
  397. int cocoa_set_num_lock_state(bool on)
  398. {
  399. return cocoa_set_modifier_lock_state(kIOHIDNumLockState, on);
  400. }
  401. int cocoa_get_caps_lock_state(bool *on)
  402. {
  403. return cocoa_get_modifier_lock_state(kIOHIDCapsLockState, on);
  404. }
  405. int cocoa_get_num_lock_state(bool *on)
  406. {
  407. return cocoa_get_modifier_lock_state(kIOHIDNumLockState, on);
  408. }