1+ #import " KeyCodeConverter.h"
2+ #import < Carbon/Carbon.h>
3+
4+ @implementation KeyCodeConverter
5+
6+ + (int )toKeyCode : (NSString *)character {
7+ return keyCodeForChar ([[character lowercaseString ] characterAtIndex: 0 ]);
8+ }
9+
10+ // Mapping from https://github.com/davedelong/DDHotKey/
11+
12+ + (NSDictionary *)fixKeys {
13+ static NSDictionary *keyCodeMap = nil ;
14+ static dispatch_once_t onceToken;
15+ dispatch_once (&onceToken, ^{
16+ keyCodeMap = @{
17+ @" ↩" :@(kVK_Return ),
18+ @" ⇥" :@(kVK_Tab ),
19+ @" ⎵" :@(kVK_Space ),
20+ @" ⌫" :@(kVK_Delete ),
21+ @" ⎋" :@(kVK_Escape ),
22+ @" ⌘" :@(kVK_Command ),
23+ @" ⇧" :@(kVK_Shift ),
24+ @" ⇪" :@(kVK_CapsLock ),
25+ @" ⌥" :@(kVK_Option ),
26+ @" ⌃" :@(kVK_Control ),
27+ @" ⇧" :@(kVK_RightShift ),
28+ @" ⌥" :@(kVK_RightOption ),
29+ @" ⌃" :@(kVK_RightControl ),
30+ @" 🔊" :@(kVK_VolumeUp ),
31+ @" 🔈" :@(kVK_VolumeDown ),
32+ @" 🔇" :@(kVK_Mute ),
33+ @" \u2318 " :@(kVK_Function ),
34+ @" F1" :@(kVK_F1 ),
35+ @" F2" :@(kVK_F2 ),
36+ @" F3" :@(kVK_F3 ),
37+ @" F4" :@(kVK_F4 ),
38+ @" F5" :@(kVK_F5 ),
39+ @" F6" :@(kVK_F6 ),
40+ @" F7" :@(kVK_F7 ),
41+ @" F8" :@(kVK_F8 ),
42+ @" F9" :@(kVK_F9 ),
43+ @" F10" :@(kVK_F10 ),
44+ @" F11" :@(kVK_F11 ),
45+ @" F12" :@(kVK_F12 ),
46+ @" F13" :@(kVK_F13 ),
47+ @" F14" :@(kVK_F14 ),
48+ @" F15" :@(kVK_F15 ),
49+ @" F16" :@(kVK_F16 ),
50+ @" F17" :@(kVK_F17 ),
51+ @" F18" :@(kVK_F18 ),
52+ @" F19" :@(kVK_F19 ),
53+ @" F20" :@(kVK_F20 ),
54+ @" ⌦" :@(kVK_ForwardDelete ),
55+ @" ↖" :@(kVK_Home ),
56+ @" ↘" :@(kVK_End ),
57+ @" ⇞" :@(kVK_PageUp ),
58+ @" ⇟" :@(kVK_PageDown ),
59+ @" ←" :@(kVK_LeftArrow ),
60+ @" →" :@(kVK_RightArrow ),
61+ @" ↓" :@(kVK_DownArrow ),
62+ @" ↑" :@(kVK_UpArrow )
63+ };
64+ });
65+
66+ return keyCodeMap;
67+ }
68+
69+ // Uses code from: http://stackoverflow.com/questions/1918841/how-to-convert-ascii-character-to-cgkeycode
70+
71+ static CGKeyCode keyCodeForChar (const char c) {
72+ static CFMutableDictionaryRef charToCodeDict = NULL ;
73+ CGKeyCode code;
74+ UniChar character = c;
75+ CFStringRef charStr = NULL ;
76+
77+ if (charToCodeDict == NULL ) {
78+ size_t i;
79+ charToCodeDict = CFDictionaryCreateMutable (kCFAllocatorDefault ,
80+ 128 ,
81+ &kCFCopyStringDictionaryKeyCallBacks ,
82+ NULL );
83+ if (charToCodeDict == NULL ) return UINT16_MAX;
84+
85+ for (i = 0 ; i < 128 ; ++i) {
86+ CFStringRef string = createStringForKey ((CGKeyCode)i);
87+ if (string != NULL ) {
88+ CFDictionaryAddValue (charToCodeDict, string, (const void *)i);
89+ CFRelease (string);
90+ }
91+ }
92+ }
93+
94+ charStr = CFStringCreateWithCharacters (kCFAllocatorDefault , &character, 1 );
95+
96+ if (!CFDictionaryGetValueIfPresent (charToCodeDict, charStr, (const void **)&code)) {
97+ code = UINT16_MAX;
98+ }
99+
100+ CFRelease (charStr);
101+
102+ return code;
103+ }
104+
105+ static CFStringRef createStringForKey (CGKeyCode keyCode) {
106+ TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource ();
107+ CFDataRef layoutData = TISGetInputSourceProperty (currentKeyboard,
108+ kTISPropertyUnicodeKeyLayoutData );
109+
110+ const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr (layoutData);
111+
112+ UInt32 keysDown = 0 ;
113+ UniChar chars[4 ];
114+ UniCharCount realLength;
115+
116+ UCKeyTranslate (keyboardLayout,
117+ keyCode,
118+ kUCKeyActionDisplay ,
119+ 0 ,
120+ LMGetKbdType (),
121+ kUCKeyTranslateNoDeadKeysBit ,
122+ &keysDown,
123+ sizeof (chars) / sizeof (chars[0 ]),
124+ &realLength,
125+ chars);
126+ CFRelease (currentKeyboard);
127+
128+ return CFStringCreateWithCharacters (kCFAllocatorDefault , chars, 1 );
129+ }
130+
131+ @end
0 commit comments