1 /*
2  * synergy -- mouse and keyboard sharing utility
3  * Copyright (C) 2016 Symless Ltd.
4  *
5  * This package is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * found in the file LICENSE that should have accompanied this file.
8  *
9  * This package is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "platform/IOSXKeyResource.h"
19 
20 #include <Carbon/Carbon.h>
21 
22 KeyID
getKeyID(UInt8 c)23 IOSXKeyResource::getKeyID(UInt8 c)
24 {
25     if (c == 0) {
26         return kKeyNone;
27     }
28     else if (c >= 32 && c < 127) {
29         // ASCII
30         return static_cast<KeyID>(c);
31     }
32     else {
33         // handle special keys
34         switch (c) {
35         case 0x01:
36             return kKeyHome;
37 
38         case 0x02:
39             return kKeyKP_Enter;
40 
41         case 0x03:
42             return kKeyKP_Enter;
43 
44         case 0x04:
45             return kKeyEnd;
46 
47         case 0x05:
48             return kKeyHelp;
49 
50         case 0x08:
51             return kKeyBackSpace;
52 
53         case 0x09:
54             return kKeyTab;
55 
56         case 0x0b:
57             return kKeyPageUp;
58 
59         case 0x0c:
60             return kKeyPageDown;
61 
62         case 0x0d:
63             return kKeyReturn;
64 
65         case 0x10:
66             // OS X maps all the function keys (F1, etc) to this one key.
67             // we can't determine the right key here so we have to do it
68             // some other way.
69             return kKeyNone;
70 
71         case 0x1b:
72             return kKeyEscape;
73 
74         case 0x1c:
75             return kKeyLeft;
76 
77         case 0x1d:
78             return kKeyRight;
79 
80         case 0x1e:
81             return kKeyUp;
82 
83         case 0x1f:
84             return kKeyDown;
85 
86         case 0x7f:
87             return kKeyDelete;
88 
89         case 0x06:
90         case 0x07:
91         case 0x0a:
92         case 0x0e:
93         case 0x0f:
94         case 0x11:
95         case 0x12:
96         case 0x13:
97         case 0x14:
98         case 0x15:
99         case 0x16:
100         case 0x17:
101         case 0x18:
102         case 0x19:
103         case 0x1a:
104             // discard other control characters
105             return kKeyNone;
106 
107         default:
108             // not special or unknown
109             break;
110         }
111 
112         // create string with character
113         char str[2];
114         str[0] = static_cast<char>(c);
115         str[1] = 0;
116 
117         // get current keyboard script
118         TISInputSourceRef isref = TISCopyCurrentKeyboardInputSource();
119         CFArrayRef langs = (CFArrayRef) TISGetInputSourceProperty(isref, kTISPropertyInputSourceLanguages);
120         CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding(
121                                         (CFStringRef)CFArrayGetValueAtIndex(langs, 0));
122         // convert to unicode
123         CFStringRef cfString =
124             CFStringCreateWithCStringNoCopy(
125                 kCFAllocatorDefault, str, encoding, kCFAllocatorNull);
126 
127         // sometimes CFStringCreate...() returns NULL (e.g. Apple Korean
128         // encoding with char value 214).  if it did then make no key,
129         // otherwise CFStringCreateMutableCopy() will crash.
130         if (cfString == NULL) {
131             return kKeyNone;
132         }
133 
134         // convert to precomposed
135         CFMutableStringRef mcfString =
136             CFStringCreateMutableCopy(kCFAllocatorDefault, 0, cfString);
137         CFRelease(cfString);
138         CFStringNormalize(mcfString, kCFStringNormalizationFormC);
139 
140         // check result
141         int unicodeLength = CFStringGetLength(mcfString);
142         if (unicodeLength == 0) {
143             CFRelease(mcfString);
144             return kKeyNone;
145         }
146         if (unicodeLength > 1) {
147             // FIXME -- more than one character, we should handle this
148             CFRelease(mcfString);
149             return kKeyNone;
150         }
151 
152         // get unicode character
153         UniChar uc = CFStringGetCharacterAtIndex(mcfString, 0);
154         CFRelease(mcfString);
155 
156         // convert to KeyID
157         return static_cast<KeyID>(uc);
158     }
159 }
160 
161 KeyID
unicharToKeyID(UniChar c)162 IOSXKeyResource::unicharToKeyID(UniChar c)
163 {
164     switch (c) {
165     case 3:
166         return kKeyKP_Enter;
167 
168     case 8:
169         return kKeyBackSpace;
170 
171     case 9:
172         return kKeyTab;
173 
174     case 13:
175         return kKeyReturn;
176 
177     case 27:
178         return kKeyEscape;
179 
180     case 127:
181         return kKeyDelete;
182 
183     default:
184         if (c < 32) {
185             return kKeyNone;
186         }
187         return static_cast<KeyID>(c);
188     }
189 }
190