makefiles: Generate the common rules for programs from configure.
[wine.git] / dlls / winemac.drv / keyboard.c
blobd4a3090c46b1221e94da2a60f5ca0eeb374a7c92
1 /*
2 * MACDRV keyboard driver
4 * Copyright 1993 Bob Amstadt
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1997 David Faure
7 * Copyright 1998 Morten Welinder
8 * Copyright 1998 Ulrich Weigand
9 * Copyright 1999 Ove Kåven
10 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
29 #include "macdrv.h"
30 #include "winuser.h"
31 #include "wine/unicode.h"
32 #include "wine/server.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
35 WINE_DECLARE_DEBUG_CHANNEL(key);
38 /* Carbon-style modifier mask definitions from <Carbon/HIToolbox/Events.h>. */
39 enum {
40 cmdKeyBit = 8,
41 shiftKeyBit = 9,
42 alphaLockBit = 10,
43 optionKeyBit = 11,
44 controlKeyBit = 12,
47 enum {
48 cmdKey = 1 << cmdKeyBit,
49 shiftKey = 1 << shiftKeyBit,
50 alphaLock = 1 << alphaLockBit,
51 optionKey = 1 << optionKeyBit,
52 controlKey = 1 << controlKeyBit,
56 /* Mac virtual key code definitions from <Carbon/HIToolbox/Events.h>. */
57 enum {
58 kVK_ANSI_A = 0x00,
59 kVK_ANSI_S = 0x01,
60 kVK_ANSI_D = 0x02,
61 kVK_ANSI_F = 0x03,
62 kVK_ANSI_H = 0x04,
63 kVK_ANSI_G = 0x05,
64 kVK_ANSI_Z = 0x06,
65 kVK_ANSI_X = 0x07,
66 kVK_ANSI_C = 0x08,
67 kVK_ANSI_V = 0x09,
68 kVK_ISO_Section = 0x0A,
69 kVK_ANSI_B = 0x0B,
70 kVK_ANSI_Q = 0x0C,
71 kVK_ANSI_W = 0x0D,
72 kVK_ANSI_E = 0x0E,
73 kVK_ANSI_R = 0x0F,
74 kVK_ANSI_Y = 0x10,
75 kVK_ANSI_T = 0x11,
76 kVK_ANSI_1 = 0x12,
77 kVK_ANSI_2 = 0x13,
78 kVK_ANSI_3 = 0x14,
79 kVK_ANSI_4 = 0x15,
80 kVK_ANSI_6 = 0x16,
81 kVK_ANSI_5 = 0x17,
82 kVK_ANSI_Equal = 0x18,
83 kVK_ANSI_9 = 0x19,
84 kVK_ANSI_7 = 0x1A,
85 kVK_ANSI_Minus = 0x1B,
86 kVK_ANSI_8 = 0x1C,
87 kVK_ANSI_0 = 0x1D,
88 kVK_ANSI_RightBracket = 0x1E,
89 kVK_ANSI_O = 0x1F,
90 kVK_ANSI_U = 0x20,
91 kVK_ANSI_LeftBracket = 0x21,
92 kVK_ANSI_I = 0x22,
93 kVK_ANSI_P = 0x23,
94 kVK_Return = 0x24,
95 kVK_ANSI_L = 0x25,
96 kVK_ANSI_J = 0x26,
97 kVK_ANSI_Quote = 0x27,
98 kVK_ANSI_K = 0x28,
99 kVK_ANSI_Semicolon = 0x29,
100 kVK_ANSI_Backslash = 0x2A,
101 kVK_ANSI_Comma = 0x2B,
102 kVK_ANSI_Slash = 0x2C,
103 kVK_ANSI_N = 0x2D,
104 kVK_ANSI_M = 0x2E,
105 kVK_ANSI_Period = 0x2F,
106 kVK_Tab = 0x30,
107 kVK_Space = 0x31,
108 kVK_ANSI_Grave = 0x32,
109 kVK_Delete = 0x33,
110 kVK_Escape = 0x35,
111 kVK_RightCommand = 0x36, /* invented for Wine; co-opt unused key code */
112 kVK_Command = 0x37,
113 kVK_Shift = 0x38,
114 kVK_CapsLock = 0x39,
115 kVK_Option = 0x3A,
116 kVK_Control = 0x3B,
117 kVK_RightShift = 0x3C,
118 kVK_RightOption = 0x3D,
119 kVK_RightControl = 0x3E,
120 kVK_Function = 0x3F,
121 kVK_F17 = 0x40,
122 kVK_ANSI_KeypadDecimal = 0x41,
123 kVK_ANSI_KeypadMultiply = 0x43,
124 kVK_ANSI_KeypadPlus = 0x45,
125 kVK_ANSI_KeypadClear = 0x47,
126 kVK_VolumeUp = 0x48,
127 kVK_VolumeDown = 0x49,
128 kVK_Mute = 0x4A,
129 kVK_ANSI_KeypadDivide = 0x4B,
130 kVK_ANSI_KeypadEnter = 0x4C,
131 kVK_ANSI_KeypadMinus = 0x4E,
132 kVK_F18 = 0x4F,
133 kVK_F19 = 0x50,
134 kVK_ANSI_KeypadEquals = 0x51,
135 kVK_ANSI_Keypad0 = 0x52,
136 kVK_ANSI_Keypad1 = 0x53,
137 kVK_ANSI_Keypad2 = 0x54,
138 kVK_ANSI_Keypad3 = 0x55,
139 kVK_ANSI_Keypad4 = 0x56,
140 kVK_ANSI_Keypad5 = 0x57,
141 kVK_ANSI_Keypad6 = 0x58,
142 kVK_ANSI_Keypad7 = 0x59,
143 kVK_F20 = 0x5A,
144 kVK_ANSI_Keypad8 = 0x5B,
145 kVK_ANSI_Keypad9 = 0x5C,
146 kVK_JIS_Yen = 0x5D,
147 kVK_JIS_Underscore = 0x5E,
148 kVK_JIS_KeypadComma = 0x5F,
149 kVK_F5 = 0x60,
150 kVK_F6 = 0x61,
151 kVK_F7 = 0x62,
152 kVK_F3 = 0x63,
153 kVK_F8 = 0x64,
154 kVK_F9 = 0x65,
155 kVK_JIS_Eisu = 0x66,
156 kVK_F11 = 0x67,
157 kVK_JIS_Kana = 0x68,
158 kVK_F13 = 0x69,
159 kVK_F16 = 0x6A,
160 kVK_F14 = 0x6B,
161 kVK_F10 = 0x6D,
162 kVK_F12 = 0x6F,
163 kVK_F15 = 0x71,
164 kVK_Help = 0x72,
165 kVK_Home = 0x73,
166 kVK_PageUp = 0x74,
167 kVK_ForwardDelete = 0x75,
168 kVK_F4 = 0x76,
169 kVK_End = 0x77,
170 kVK_F2 = 0x78,
171 kVK_PageDown = 0x79,
172 kVK_F1 = 0x7A,
173 kVK_LeftArrow = 0x7B,
174 kVK_RightArrow = 0x7C,
175 kVK_DownArrow = 0x7D,
176 kVK_UpArrow = 0x7E,
180 /* Indexed by Mac virtual keycode values defined above. */
181 static const struct {
182 WORD vkey;
183 WORD scan;
184 BOOL fixed;
185 } default_map[128] = {
186 { 'A', 0x1E, FALSE }, /* kVK_ANSI_A */
187 { 'S', 0x1F, FALSE }, /* kVK_ANSI_S */
188 { 'D', 0x20, FALSE }, /* kVK_ANSI_D */
189 { 'F', 0x21, FALSE }, /* kVK_ANSI_F */
190 { 'H', 0x23, FALSE }, /* kVK_ANSI_H */
191 { 'G', 0x22, FALSE }, /* kVK_ANSI_G */
192 { 'Z', 0x2C, FALSE }, /* kVK_ANSI_Z */
193 { 'X', 0x2D, FALSE }, /* kVK_ANSI_X */
194 { 'C', 0x2E, FALSE }, /* kVK_ANSI_C */
195 { 'V', 0x2F, FALSE }, /* kVK_ANSI_V */
196 { VK_OEM_102, 0x56, TRUE }, /* kVK_ISO_Section */
197 { 'B', 0x30, FALSE }, /* kVK_ANSI_B */
198 { 'Q', 0x10, FALSE }, /* kVK_ANSI_Q */
199 { 'W', 0x11, FALSE }, /* kVK_ANSI_W */
200 { 'E', 0x12, FALSE }, /* kVK_ANSI_E */
201 { 'R', 0x13, FALSE }, /* kVK_ANSI_R */
202 { 'Y', 0x15, FALSE }, /* kVK_ANSI_Y */
203 { 'T', 0x14, FALSE }, /* kVK_ANSI_T */
204 { '1', 0x02, FALSE }, /* kVK_ANSI_1 */
205 { '2', 0x03, FALSE }, /* kVK_ANSI_2 */
206 { '3', 0x04, FALSE }, /* kVK_ANSI_3 */
207 { '4', 0x05, FALSE }, /* kVK_ANSI_4 */
208 { '6', 0x07, FALSE }, /* kVK_ANSI_6 */
209 { '5', 0x06, FALSE }, /* kVK_ANSI_5 */
210 { VK_OEM_PLUS, 0x0D, FALSE }, /* kVK_ANSI_Equal */
211 { '9', 0x0A, FALSE }, /* kVK_ANSI_9 */
212 { '7', 0x08, FALSE }, /* kVK_ANSI_7 */
213 { VK_OEM_MINUS, 0x0C, FALSE }, /* kVK_ANSI_Minus */
214 { '8', 0x09, FALSE }, /* kVK_ANSI_8 */
215 { '0', 0x0B, FALSE }, /* kVK_ANSI_0 */
216 { VK_OEM_6, 0x1B, FALSE }, /* kVK_ANSI_RightBracket */
217 { 'O', 0x18, FALSE }, /* kVK_ANSI_O */
218 { 'U', 0x16, FALSE }, /* kVK_ANSI_U */
219 { VK_OEM_4, 0x1A, FALSE }, /* kVK_ANSI_LeftBracket */
220 { 'I', 0x17, FALSE }, /* kVK_ANSI_I */
221 { 'P', 0x19, FALSE }, /* kVK_ANSI_P */
222 { VK_RETURN, 0x1C, TRUE }, /* kVK_Return */
223 { 'L', 0x26, FALSE }, /* kVK_ANSI_L */
224 { 'J', 0x24, FALSE }, /* kVK_ANSI_J */
225 { VK_OEM_7, 0x28, FALSE }, /* kVK_ANSI_Quote */
226 { 'K', 0x25, FALSE }, /* kVK_ANSI_K */
227 { VK_OEM_1, 0x27, FALSE }, /* kVK_ANSI_Semicolon */
228 { VK_OEM_5, 0x2B, FALSE }, /* kVK_ANSI_Backslash */
229 { VK_OEM_COMMA, 0x33, FALSE }, /* kVK_ANSI_Comma */
230 { VK_OEM_2, 0x35, FALSE }, /* kVK_ANSI_Slash */
231 { 'N', 0x31, FALSE }, /* kVK_ANSI_N */
232 { 'M', 0x32, FALSE }, /* kVK_ANSI_M */
233 { VK_OEM_PERIOD, 0x34, FALSE }, /* kVK_ANSI_Period */
234 { VK_TAB, 0x0F, TRUE }, /* kVK_Tab */
235 { VK_SPACE, 0x39, TRUE }, /* kVK_Space */
236 { VK_OEM_3, 0x29, FALSE }, /* kVK_ANSI_Grave */
237 { VK_BACK, 0x0E, TRUE }, /* kVK_Delete */
238 { 0, 0, FALSE }, /* 0x34 unused */
239 { VK_ESCAPE, 0x01, TRUE }, /* kVK_Escape */
240 { VK_RMENU, 0x38 | 0x100, TRUE }, /* kVK_RightCommand */
241 { VK_LMENU, 0x38, TRUE }, /* kVK_Command */
242 { VK_LSHIFT, 0x2A, TRUE }, /* kVK_Shift */
243 { VK_CAPITAL, 0x3A, TRUE }, /* kVK_CapsLock */
244 { 0, 0, FALSE }, /* kVK_Option */
245 { VK_LCONTROL, 0x1D, TRUE }, /* kVK_Control */
246 { VK_RSHIFT, 0x36, TRUE }, /* kVK_RightShift */
247 { 0, 0, FALSE }, /* kVK_RightOption */
248 { VK_RCONTROL, 0x1D | 0x100, TRUE }, /* kVK_RightControl */
249 { 0, 0, FALSE }, /* kVK_Function */
250 { VK_F17, 0x68, TRUE }, /* kVK_F17 */
251 { VK_DECIMAL, 0x53, TRUE }, /* kVK_ANSI_KeypadDecimal */
252 { 0, 0, FALSE }, /* 0x42 unused */
253 { VK_MULTIPLY, 0x37, TRUE }, /* kVK_ANSI_KeypadMultiply */
254 { 0, 0, FALSE }, /* 0x44 unused */
255 { VK_ADD, 0x4E, TRUE }, /* kVK_ANSI_KeypadPlus */
256 { 0, 0, FALSE }, /* 0x46 unused */
257 { VK_OEM_CLEAR, 0x59, TRUE }, /* kVK_ANSI_KeypadClear */
258 { VK_VOLUME_UP, 0 | 0x100, TRUE }, /* kVK_VolumeUp */
259 { VK_VOLUME_DOWN, 0 | 0x100, TRUE }, /* kVK_VolumeDown */
260 { VK_VOLUME_MUTE, 0 | 0x100, TRUE }, /* kVK_Mute */
261 { VK_DIVIDE, 0x35 | 0x100, TRUE }, /* kVK_ANSI_KeypadDivide */
262 { VK_RETURN, 0x1C | 0x100, TRUE }, /* kVK_ANSI_KeypadEnter */
263 { 0, 0, FALSE }, /* 0x4D unused */
264 { VK_SUBTRACT, 0x4A, TRUE }, /* kVK_ANSI_KeypadMinus */
265 { VK_F18, 0x69, TRUE }, /* kVK_F18 */
266 { VK_F19, 0x6A, TRUE }, /* kVK_F19 */
267 { VK_OEM_NEC_EQUAL, 0x0D | 0x100, TRUE }, /* kVK_ANSI_KeypadEquals */
268 { VK_NUMPAD0, 0x52, TRUE }, /* kVK_ANSI_Keypad0 */
269 { VK_NUMPAD1, 0x4F, TRUE }, /* kVK_ANSI_Keypad1 */
270 { VK_NUMPAD2, 0x50, TRUE }, /* kVK_ANSI_Keypad2 */
271 { VK_NUMPAD3, 0x51, TRUE }, /* kVK_ANSI_Keypad3 */
272 { VK_NUMPAD4, 0x4B, TRUE }, /* kVK_ANSI_Keypad4 */
273 { VK_NUMPAD5, 0x4C, TRUE }, /* kVK_ANSI_Keypad5 */
274 { VK_NUMPAD6, 0x4D, TRUE }, /* kVK_ANSI_Keypad6 */
275 { VK_NUMPAD7, 0x47, TRUE }, /* kVK_ANSI_Keypad7 */
276 { VK_F20, 0x6B, TRUE }, /* kVK_F20 */
277 { VK_NUMPAD8, 0x48, TRUE }, /* kVK_ANSI_Keypad8 */
278 { VK_NUMPAD9, 0x49, TRUE }, /* kVK_ANSI_Keypad9 */
279 { 0xFF, 0x7D, TRUE }, /* kVK_JIS_Yen */
280 { 0xC1, 0x73, TRUE }, /* kVK_JIS_Underscore */
281 { VK_SEPARATOR, 0x7E, TRUE }, /* kVK_JIS_KeypadComma */
282 { VK_F5, 0x3F, TRUE }, /* kVK_F5 */
283 { VK_F6, 0x40, TRUE }, /* kVK_F6 */
284 { VK_F7, 0x41, TRUE }, /* kVK_F7 */
285 { VK_F3, 0x3D, TRUE }, /* kVK_F3 */
286 { VK_F8, 0x42, TRUE }, /* kVK_F8 */
287 { VK_F9, 0x43, TRUE }, /* kVK_F9 */
288 { 0xFF, 0x72, TRUE }, /* kVK_JIS_Eisu */
289 { VK_F11, 0x57, TRUE }, /* kVK_F11 */
290 { VK_OEM_RESET, 0x71, TRUE }, /* kVK_JIS_Kana */
291 { VK_F13, 0x64, TRUE }, /* kVK_F13 */
292 { VK_F16, 0x67, TRUE }, /* kVK_F16 */
293 { VK_F14, 0x65, TRUE }, /* kVK_F14 */
294 { 0, 0, FALSE }, /* 0x6C unused */
295 { VK_F10, 0x44, TRUE }, /* kVK_F10 */
296 { 0, 0, FALSE }, /* 0x6E unused */
297 { VK_F12, 0x58, TRUE }, /* kVK_F12 */
298 { 0, 0, FALSE }, /* 0x70 unused */
299 { VK_F15, 0x66, TRUE }, /* kVK_F15 */
300 { VK_INSERT, 0x52 | 0x100, TRUE }, /* kVK_Help */ /* map to Insert */
301 { VK_HOME, 0x47 | 0x100, TRUE }, /* kVK_Home */
302 { VK_PRIOR, 0x49 | 0x100, TRUE }, /* kVK_PageUp */
303 { VK_DELETE, 0x53 | 0x100, TRUE }, /* kVK_ForwardDelete */
304 { VK_F4, 0x3E, TRUE }, /* kVK_F4 */
305 { VK_END, 0x4F | 0x100, TRUE }, /* kVK_End */
306 { VK_F2, 0x3C, TRUE }, /* kVK_F2 */
307 { VK_NEXT, 0x51 | 0x100, TRUE }, /* kVK_PageDown */
308 { VK_F1, 0x3B, TRUE }, /* kVK_F1 */
309 { VK_LEFT, 0x4B | 0x100, TRUE }, /* kVK_LeftArrow */
310 { VK_RIGHT, 0x4D | 0x100, TRUE }, /* kVK_RightArrow */
311 { VK_DOWN, 0x50 | 0x100, TRUE }, /* kVK_DownArrow */
312 { VK_UP, 0x48 | 0x100, TRUE }, /* kVK_UpArrow */
316 static const struct {
317 DWORD vkey;
318 const char *name;
319 } vkey_names[] = {
320 { VK_ADD, "Num +" },
321 { VK_BACK, "Backspace" },
322 { VK_CAPITAL, "Caps Lock" },
323 { VK_CONTROL, "Ctrl" },
324 { VK_DECIMAL, "Num Del" },
325 { VK_DELETE | 0x100, "Delete" },
326 { VK_DIVIDE | 0x100, "Num /" },
327 { VK_DOWN | 0x100, "Down" },
328 { VK_END | 0x100, "End" },
329 { VK_ESCAPE, "Esc" },
330 { VK_F1, "F1" },
331 { VK_F2, "F2" },
332 { VK_F3, "F3" },
333 { VK_F4, "F4" },
334 { VK_F5, "F5" },
335 { VK_F6, "F6" },
336 { VK_F7, "F7" },
337 { VK_F8, "F8" },
338 { VK_F9, "F9" },
339 { VK_F10, "F10" },
340 { VK_F11, "F11" },
341 { VK_F12, "F12" },
342 { VK_F13, "F13" },
343 { VK_F14, "F14" },
344 { VK_F15, "F15" },
345 { VK_F16, "F16" },
346 { VK_F17, "F17" },
347 { VK_F18, "F18" },
348 { VK_F19, "F19" },
349 { VK_F20, "F20" },
350 { VK_F21, "F21" },
351 { VK_F22, "F22" },
352 { VK_F23, "F23" },
353 { VK_F24, "F24" },
354 { VK_HELP | 0x100, "Help" },
355 { VK_HOME | 0x100, "Home" },
356 { VK_INSERT | 0x100, "Insert" },
357 { VK_LCONTROL, "Ctrl" },
358 { VK_LEFT | 0x100, "Left" },
359 { VK_LMENU, "Alt" },
360 { VK_LSHIFT, "Shift" },
361 { VK_LWIN | 0x100, "Win" },
362 { VK_MENU, "Alt" },
363 { VK_MULTIPLY, "Num *" },
364 { VK_NEXT | 0x100, "Page Down" },
365 { VK_NUMLOCK | 0x100, "Num Lock" },
366 { VK_NUMPAD0, "Num 0" },
367 { VK_NUMPAD1, "Num 1" },
368 { VK_NUMPAD2, "Num 2" },
369 { VK_NUMPAD3, "Num 3" },
370 { VK_NUMPAD4, "Num 4" },
371 { VK_NUMPAD5, "Num 5" },
372 { VK_NUMPAD6, "Num 6" },
373 { VK_NUMPAD7, "Num 7" },
374 { VK_NUMPAD8, "Num 8" },
375 { VK_NUMPAD9, "Num 9" },
376 { VK_OEM_CLEAR, "Num Clear" },
377 { VK_OEM_NEC_EQUAL | 0x100, "Num =" },
378 { VK_PRIOR | 0x100, "Page Up" },
379 { VK_RCONTROL | 0x100, "Right Ctrl" },
380 { VK_RETURN, "Return" },
381 { VK_RETURN | 0x100, "Num Enter" },
382 { VK_RIGHT | 0x100, "Right" },
383 { VK_RMENU | 0x100, "Right Alt" },
384 { VK_RSHIFT, "Right Shift" },
385 { VK_RWIN | 0x100, "Right Win" },
386 { VK_SEPARATOR, "Num ," },
387 { VK_SHIFT, "Shift" },
388 { VK_SPACE, "Space" },
389 { VK_SUBTRACT, "Num -" },
390 { VK_TAB, "Tab" },
391 { VK_UP | 0x100, "Up" },
392 { VK_VOLUME_DOWN | 0x100, "Volume Down" },
393 { VK_VOLUME_MUTE | 0x100, "Mute" },
394 { VK_VOLUME_UP | 0x100, "Volume Up" },
398 static BOOL char_matches_string(WCHAR wchar, UniChar *string, BOOL ignore_diacritics)
400 BOOL ret;
401 CFStringRef s1 = CFStringCreateWithCharactersNoCopy(NULL, (UniChar*)&wchar, 1, kCFAllocatorNull);
402 CFStringRef s2 = CFStringCreateWithCharactersNoCopy(NULL, string, strlenW(string), kCFAllocatorNull);
403 CFStringCompareFlags flags = kCFCompareCaseInsensitive | kCFCompareNonliteral | kCFCompareWidthInsensitive;
404 if (ignore_diacritics)
405 flags |= kCFCompareDiacriticInsensitive;
406 ret = (CFStringCompare(s1, s2, flags) == kCFCompareEqualTo);
407 CFRelease(s1);
408 CFRelease(s2);
409 return ret;
413 /* Filter Apple-specific private-use characters (see NSEvent.h) out of a
414 * string. Returns the length of the string after stripping. */
415 static int strip_apple_private_chars(LPWSTR bufW, int len)
417 int i;
418 for (i = 0; i < len; )
420 if (0xF700 <= bufW[i] && bufW[i] <= 0xF8FF)
422 memmove(&bufW[i], &bufW[i+1], (len - i - 1) * sizeof(bufW[0]));
423 len--;
425 else
426 i++;
428 return len;
432 /***********************************************************************
433 * macdrv_compute_keyboard_layout
435 void macdrv_compute_keyboard_layout(struct macdrv_thread_data *thread_data)
437 int keyc;
438 WCHAR vkey;
439 const UCKeyboardLayout *uchr;
440 const UInt32 modifier_combos[] = {
442 shiftKey >> 8,
443 cmdKey >> 8,
444 (shiftKey | cmdKey) >> 8,
445 optionKey >> 8,
446 (shiftKey | optionKey) >> 8,
448 UniChar map[128][sizeof(modifier_combos) / sizeof(modifier_combos[0])][4 + 1];
449 int combo;
450 BYTE vkey_used[256];
451 int ignore_diacritics;
452 static const struct {
453 WCHAR wchar;
454 DWORD vkey;
455 } symbol_vkeys[] = {
456 { '-', VK_OEM_MINUS },
457 { '+', VK_OEM_PLUS },
458 { '_', VK_OEM_MINUS },
459 { ',', VK_OEM_COMMA },
460 { '.', VK_OEM_PERIOD },
461 { '=', VK_OEM_PLUS },
462 { '>', VK_OEM_PERIOD },
463 { '<', VK_OEM_COMMA },
464 { '|', VK_OEM_5 },
465 { '\\', VK_OEM_5 },
466 { '`', VK_OEM_3 },
467 { '[', VK_OEM_4 },
468 { '~', VK_OEM_3 },
469 { '?', VK_OEM_2 },
470 { ']', VK_OEM_6 },
471 { '/', VK_OEM_2 },
472 { ':', VK_OEM_1 },
473 { '}', VK_OEM_6 },
474 { '{', VK_OEM_4 },
475 { ';', VK_OEM_1 },
476 { '\'', VK_OEM_7 },
477 { ':', VK_OEM_PERIOD },
478 { ';', VK_OEM_COMMA },
479 { '"', VK_OEM_7 },
480 { 0x00B4, VK_OEM_4 }, /* 0x00B4 is ACUTE ACCENT */
481 { '\'', VK_OEM_2 },
482 { 0x00A7, VK_OEM_5 }, /* 0x00A7 is SECTION SIGN */
483 { '*', VK_OEM_PLUS },
484 { 0x00B4, VK_OEM_7 },
485 { '`', VK_OEM_4 },
486 { '[', VK_OEM_6 },
487 { '/', VK_OEM_5 },
488 { '^', VK_OEM_6 },
489 { '*', VK_OEM_2 },
490 { '{', VK_OEM_6 },
491 { '~', VK_OEM_1 },
492 { '?', VK_OEM_PLUS },
493 { '?', VK_OEM_4 },
494 { 0x00B4, VK_OEM_3 },
495 { '?', VK_OEM_COMMA },
496 { '~', VK_OEM_PLUS },
497 { ']', VK_OEM_4 },
498 { '\'', VK_OEM_3 },
499 { 0x00A7, VK_OEM_7 },
501 int i;
503 /* Vkeys that are suitable for assigning to arbitrary keys, organized in
504 contiguous ranges. */
505 static const struct {
506 WORD first, last;
507 } vkey_ranges[] = {
508 { 'A', 'Z' },
509 { '0', '9' },
510 { VK_OEM_1, VK_OEM_3 },
511 { VK_OEM_4, VK_ICO_CLEAR },
512 { 0xe9, 0xf5 },
513 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
514 { VK_F1, VK_F24 },
515 { 0, 0 }
517 int vkey_range;
519 if (!thread_data->keyboard_layout_uchr)
521 ERR("no keyboard layout UCHR data\n");
522 return;
525 memset(thread_data->keyc2vkey, 0, sizeof(thread_data->keyc2vkey));
526 memset(vkey_used, 0, sizeof(vkey_used));
528 for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
530 thread_data->keyc2scan[keyc] = default_map[keyc].scan;
531 if (default_map[keyc].fixed)
533 vkey = default_map[keyc].vkey;
534 thread_data->keyc2vkey[keyc] = vkey;
535 vkey_used[vkey] = 1;
536 TRACE("keyc 0x%04x -> vkey 0x%04x (fixed)\n", keyc, vkey);
540 if (thread_data->iso_keyboard)
542 /* In almost all cases, the Mac key codes indicate a physical key position
543 and this corresponds nicely to Win32 scan codes. However, the Mac key
544 codes differ in one case between ANSI and ISO keyboards. For ANSI
545 keyboards, the key to the left of the digits and above the Tab key
546 produces key code kVK_ANSI_Grave. For ISO keyboards, the key in that
547 some position produces kVK_ISO_Section. The additional key on ISO
548 keyboards, the one to the right of the left Shift key, produces
549 kVK_ANSI_Grave, which is just weird.
551 Since we want the key in that upper left corner to always produce the
552 same scan code (0x29), we need to swap the scan codes of those two
553 Mac key codes for ISO keyboards. */
554 DWORD temp = thread_data->keyc2scan[kVK_ANSI_Grave];
555 thread_data->keyc2scan[kVK_ANSI_Grave] = thread_data->keyc2scan[kVK_ISO_Section];
556 thread_data->keyc2scan[kVK_ISO_Section] = temp;
559 uchr = (const UCKeyboardLayout*)CFDataGetBytePtr(thread_data->keyboard_layout_uchr);
561 /* Using the keyboard layout, build a map of key code + modifiers -> characters. */
562 memset(map, 0, sizeof(map));
563 for (keyc = 0; keyc < sizeof(map) / sizeof(map[0]); keyc++)
565 if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
566 if (thread_data->keyc2vkey[keyc]) continue; /* assigned a fixed vkey */
568 TRACE("keyc 0x%04x: ", keyc);
570 for (combo = 0; combo < sizeof(modifier_combos) / sizeof(modifier_combos[0]); combo++)
572 UInt32 deadKeyState;
573 UniCharCount len;
574 OSStatus status;
576 deadKeyState = 0;
577 status = UCKeyTranslate(uchr, keyc, kUCKeyActionDown, modifier_combos[combo],
578 thread_data->keyboard_type, kUCKeyTranslateNoDeadKeysMask,
579 &deadKeyState, sizeof(map[keyc][combo])/sizeof(map[keyc][combo][0]) - 1,
580 &len, map[keyc][combo]);
581 if (status != noErr)
582 map[keyc][combo][0] = 0;
584 TRACE("%s%s", (combo ? ", " : ""), debugstr_w(map[keyc][combo]));
587 TRACE("\n");
590 /* First try to match key codes to the vkeys for the letters A through Z.
591 Try unmodified first, then with various modifier combinations in succession.
592 On the first pass, try to get a match lacking diacritical marks. On the
593 second pass, accept matches with diacritical marks. */
594 for (ignore_diacritics = 0; ignore_diacritics <= 1; ignore_diacritics++)
596 for (combo = 0; combo < sizeof(modifier_combos) / sizeof(modifier_combos[0]); combo++)
598 for (vkey = 'A'; vkey <= 'Z'; vkey++)
600 if (vkey_used[vkey])
601 continue;
603 for (keyc = 0; keyc < sizeof(map) / sizeof(map[0]); keyc++)
605 if (thread_data->keyc2vkey[keyc] || !map[keyc][combo][0])
606 continue;
608 if (char_matches_string(vkey, map[keyc][combo], ignore_diacritics))
610 thread_data->keyc2vkey[keyc] = vkey;
611 vkey_used[vkey] = 1;
612 TRACE("keyc 0x%04x -> vkey 0x%04x (%s match %s)\n", keyc, vkey,
613 debugstr_wn(&vkey, 1), debugstr_w(map[keyc][combo]));
614 break;
621 /* Next try to match key codes to the vkeys for the digits 0 through 9. */
622 for (combo = 0; combo < sizeof(modifier_combos) / sizeof(modifier_combos[0]); combo++)
624 for (vkey = '0'; vkey <= '9'; vkey++)
626 if (vkey_used[vkey])
627 continue;
629 for (keyc = 0; keyc < sizeof(map) / sizeof(map[0]); keyc++)
631 if (thread_data->keyc2vkey[keyc] || !map[keyc][combo][0])
632 continue;
634 if (char_matches_string(vkey, map[keyc][combo], FALSE))
636 thread_data->keyc2vkey[keyc] = vkey;
637 vkey_used[vkey] = 1;
638 TRACE("keyc 0x%04x -> vkey 0x%04x (%s match %s)\n", keyc, vkey,
639 debugstr_wn(&vkey, 1), debugstr_w(map[keyc][combo]));
640 break;
646 /* Now try to match key codes for certain common punctuation characters to
647 the most common OEM vkeys (e.g. '.' to VK_OEM_PERIOD). */
648 for (i = 0; i < sizeof(symbol_vkeys) / sizeof(symbol_vkeys[0]); i++)
650 vkey = symbol_vkeys[i].vkey;
652 if (vkey_used[vkey])
653 continue;
655 for (combo = 0; combo < sizeof(modifier_combos) / sizeof(modifier_combos[0]); combo++)
657 for (keyc = 0; keyc < sizeof(map) / sizeof(map[0]); keyc++)
659 if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
660 if (thread_data->keyc2vkey[keyc] || !map[keyc][combo][0])
661 continue;
663 if (char_matches_string(symbol_vkeys[i].wchar, map[keyc][combo], FALSE))
665 thread_data->keyc2vkey[keyc] = vkey;
666 vkey_used[vkey] = 1;
667 TRACE("keyc 0x%04x -> vkey 0x%04x (%s match %s)\n", keyc, vkey,
668 debugstr_wn(&symbol_vkeys[i].wchar, 1), debugstr_w(map[keyc][combo]));
669 break;
673 if (vkey_used[vkey])
674 break;
678 /* For those key codes still without a vkey, try to use the default vkey
679 from the default map, if it's still available. */
680 for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
682 DWORD vkey = default_map[keyc].vkey;
684 if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
685 if (thread_data->keyc2vkey[keyc]) continue; /* already assigned */
687 if (!vkey_used[vkey])
689 thread_data->keyc2vkey[keyc] = vkey;
690 vkey_used[vkey] = 1;
691 TRACE("keyc 0x%04x -> vkey 0x%04x (default map)\n", keyc, vkey);
695 /* For any unassigned key codes which would map to a letter in the default
696 map, but whose normal letter vkey wasn't available, try to find a
697 different letter. */
698 vkey = 'A';
699 for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
701 if (default_map[keyc].vkey < 'A' || 'Z' < default_map[keyc].vkey)
702 continue; /* not a letter in ANSI layout */
703 if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
704 if (thread_data->keyc2vkey[keyc]) continue; /* already assigned */
706 while (vkey <= 'Z' && vkey_used[vkey]) vkey++;
707 if (vkey <= 'Z')
709 thread_data->keyc2vkey[keyc] = vkey;
710 vkey_used[vkey] = 1;
711 TRACE("keyc 0x%04x -> vkey 0x%04x (spare letter)\n", keyc, vkey);
713 else
714 break; /* no more unused letter vkeys, so stop trying */
717 /* Same thing but with the digits. */
718 vkey = '0';
719 for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
721 if (default_map[keyc].vkey < '0' || '9' < default_map[keyc].vkey)
722 continue; /* not a digit in ANSI layout */
723 if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
724 if (thread_data->keyc2vkey[keyc]) continue; /* already assigned */
726 while (vkey <= '9' && vkey_used[vkey]) vkey++;
727 if (vkey <= '9')
729 thread_data->keyc2vkey[keyc] = vkey;
730 vkey_used[vkey] = 1;
731 TRACE("keyc 0x%04x -> vkey 0x%04x (spare digit)\n", keyc, vkey);
733 else
734 break; /* no more unused digit vkeys, so stop trying */
737 /* Last chance. Assign any available vkey. */
738 vkey_range = 0;
739 vkey = vkey_ranges[vkey_range].first;
740 for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
742 if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
743 if (thread_data->keyc2vkey[keyc]) continue; /* already assigned */
745 while (vkey && vkey_used[vkey])
747 if (vkey == vkey_ranges[vkey_range].last)
749 vkey_range++;
750 vkey = vkey_ranges[vkey_range].first;
752 else
753 vkey++;
756 if (!vkey)
758 WARN("No more vkeys available!\n");
759 break;
762 thread_data->keyc2vkey[keyc] = vkey;
763 vkey_used[vkey] = 1;
764 TRACE("keyc 0x%04x -> vkey 0x%04x (spare vkey)\n", keyc, vkey);
769 /***********************************************************************
770 * macdrv_send_keyboard_input
772 static void macdrv_send_keyboard_input(HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time)
774 INPUT input;
776 TRACE_(key)("hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags);
778 input.type = INPUT_KEYBOARD;
779 input.ki.wVk = vkey;
780 input.ki.wScan = scan;
781 input.ki.dwFlags = flags;
782 input.ki.time = time;
783 input.ki.dwExtraInfo = 0;
785 __wine_send_input(hwnd, &input);
789 /***********************************************************************
790 * get_async_key_state
792 static BOOL get_async_key_state(BYTE state[256])
794 BOOL ret;
796 SERVER_START_REQ(get_key_state)
798 req->tid = 0;
799 req->key = -1;
800 wine_server_set_reply(req, state, 256);
801 ret = !wine_server_call(req);
803 SERVER_END_REQ;
804 return ret;
808 /***********************************************************************
809 * update_modifier_state
811 static void update_modifier_state(unsigned int modifier, unsigned int modifiers, const BYTE *keystate,
812 WORD vkey, WORD alt_vkey, WORD scan, WORD alt_scan,
813 DWORD event_time, BOOL restore)
815 int key_pressed = (modifiers & modifier) != 0;
816 int vkey_pressed = (keystate[vkey] & 0x80) || (keystate[alt_vkey] & 0x80);
817 DWORD flags;
819 if (key_pressed != vkey_pressed)
821 if (key_pressed)
823 flags = (scan & 0x100) ? KEYEVENTF_EXTENDEDKEY : 0;
824 if (restore)
825 flags |= KEYEVENTF_KEYUP;
827 macdrv_send_keyboard_input(NULL, vkey, scan & 0xff, flags, event_time);
829 else
831 flags = restore ? 0 : KEYEVENTF_KEYUP;
833 if (keystate[vkey] & 0x80)
835 macdrv_send_keyboard_input(NULL, vkey, scan & 0xff,
836 flags | ((scan & 0x100) ? KEYEVENTF_EXTENDEDKEY : 0),
837 event_time);
839 if (keystate[alt_vkey] & 0x80)
841 macdrv_send_keyboard_input(NULL, alt_vkey, alt_scan & 0xff,
842 flags | ((alt_scan & 0x100) ? KEYEVENTF_EXTENDEDKEY : 0),
843 event_time);
850 /***********************************************************************
851 * macdrv_key_event
853 * Handler for KEY_PRESS and KEY_RELEASE events.
855 void macdrv_key_event(HWND hwnd, const macdrv_event *event)
857 struct macdrv_thread_data *thread_data = macdrv_thread_data();
858 WORD vkey, scan;
859 DWORD flags;
861 TRACE_(key)("win %p/%p key %s keycode %hu modifiers 0x%08llx\n",
862 hwnd, event->window, (event->type == KEY_PRESS ? "press" : "release"),
863 event->key.keycode, event->key.modifiers);
865 thread_data->last_modifiers = event->key.modifiers;
867 if (event->key.keycode < sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]))
869 vkey = thread_data->keyc2vkey[event->key.keycode];
870 scan = thread_data->keyc2scan[event->key.keycode];
872 else
873 vkey = scan = 0;
875 TRACE_(key)("keycode %hu converted to vkey 0x%X scan 0x%02x\n",
876 event->key.keycode, vkey, scan);
878 if (!vkey) return;
880 flags = 0;
881 if (event->type == KEY_RELEASE) flags |= KEYEVENTF_KEYUP;
882 if (scan & 0x100) flags |= KEYEVENTF_EXTENDEDKEY;
884 macdrv_send_keyboard_input(hwnd, vkey, scan & 0xff, flags, event->key.time_ms);
888 /***********************************************************************
889 * macdrv_keyboard_changed
891 * Handler for KEYBOARD_CHANGED events.
893 void macdrv_keyboard_changed(const macdrv_event *event)
895 struct macdrv_thread_data *thread_data = macdrv_thread_data();
897 TRACE("new keyboard layout uchr data %p, type %u, iso %d\n", event->keyboard_changed.uchr,
898 event->keyboard_changed.keyboard_type, event->keyboard_changed.iso_keyboard);
900 if (thread_data->keyboard_layout_uchr)
901 CFRelease(thread_data->keyboard_layout_uchr);
902 thread_data->keyboard_layout_uchr = CFDataCreateCopy(NULL, event->keyboard_changed.uchr);
903 thread_data->keyboard_type = event->keyboard_changed.keyboard_type;
904 thread_data->iso_keyboard = event->keyboard_changed.iso_keyboard;
905 thread_data->dead_key_state = 0;
907 macdrv_compute_keyboard_layout(thread_data);
911 /***********************************************************************
912 * macdrv_hotkey_press
914 * Handler for HOTKEY_PRESS events.
916 void macdrv_hotkey_press(const macdrv_event *event)
918 struct macdrv_thread_data *thread_data = macdrv_thread_data();
920 TRACE_(key)("vkey 0x%04x mod_flags 0x%04x keycode 0x%04x time %lu\n",
921 event->hotkey_press.vkey, event->hotkey_press.mod_flags, event->hotkey_press.keycode,
922 event->hotkey_press.time_ms);
924 if (event->hotkey_press.keycode < sizeof(thread_data->keyc2vkey) / sizeof(thread_data->keyc2vkey[0]))
926 WORD scan = thread_data->keyc2scan[event->hotkey_press.keycode];
927 BYTE keystate[256];
928 BOOL got_keystate;
929 DWORD flags;
931 if ((got_keystate = get_async_key_state(keystate)))
933 update_modifier_state(MOD_ALT, event->hotkey_press.mod_flags, keystate, VK_LMENU, VK_RMENU,
934 0x38, 0x138, event->hotkey_press.time_ms, FALSE);
935 update_modifier_state(MOD_CONTROL, event->hotkey_press.mod_flags, keystate, VK_LCONTROL, VK_RCONTROL,
936 0x1D, 0x11D, event->hotkey_press.time_ms, FALSE);
937 update_modifier_state(MOD_SHIFT, event->hotkey_press.mod_flags, keystate, VK_LSHIFT, VK_RSHIFT,
938 0x2A, 0x36, event->hotkey_press.time_ms, FALSE);
939 update_modifier_state(MOD_WIN, event->hotkey_press.mod_flags, keystate, VK_LWIN, VK_RWIN,
940 0x15B, 0x15C, event->hotkey_press.time_ms, FALSE);
943 activate_on_following_focus();
945 flags = (scan & 0x100) ? KEYEVENTF_EXTENDEDKEY : 0;
946 macdrv_send_keyboard_input(NULL, event->hotkey_press.vkey, scan & 0xff,
947 flags, event->key.time_ms);
948 macdrv_send_keyboard_input(NULL, event->hotkey_press.vkey, scan & 0xff,
949 flags | KEYEVENTF_KEYUP, event->key.time_ms);
951 if (got_keystate)
953 update_modifier_state(MOD_ALT, event->hotkey_press.mod_flags, keystate, VK_LMENU, VK_RMENU,
954 0x38, 0x138, event->hotkey_press.time_ms, TRUE);
955 update_modifier_state(MOD_CONTROL, event->hotkey_press.mod_flags, keystate, VK_LCONTROL, VK_RCONTROL,
956 0x1D, 0x11D, event->hotkey_press.time_ms, TRUE);
957 update_modifier_state(MOD_SHIFT, event->hotkey_press.mod_flags, keystate, VK_LSHIFT, VK_RSHIFT,
958 0x2A, 0x36, event->hotkey_press.time_ms, TRUE);
959 update_modifier_state(MOD_WIN, event->hotkey_press.mod_flags, keystate, VK_LWIN, VK_RWIN,
960 0x15B, 0x15C, event->hotkey_press.time_ms, TRUE);
966 /***********************************************************************
967 * get_locale_keyboard_layout
969 static HKL get_locale_keyboard_layout(void)
971 ULONG_PTR layout;
972 LANGID langid;
974 layout = GetUserDefaultLCID();
977 * Microsoft Office expects this value to be something specific
978 * for Japanese and Korean Windows with an IME the value is 0xe001
979 * We should probably check to see if an IME exists and if so then
980 * set this word properly.
982 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
983 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
984 layout |= 0xe001 << 16; /* IME */
985 else
986 layout |= layout << 16;
988 return (HKL)layout;
992 /***********************************************************************
993 * match_keyboard_layout
995 static BOOL match_keyboard_layout(HKL hkl)
997 const DWORD isIME = 0xE0000000;
998 HKL current_hkl = get_locale_keyboard_layout();
1000 /* if the layout is an IME, only match the low word (LCID) */
1001 if (((ULONG_PTR)hkl & isIME) == isIME)
1002 return (LOWORD(hkl) == LOWORD(current_hkl));
1003 else
1004 return (hkl == current_hkl);
1008 /***********************************************************************
1009 * macdrv_process_text_input
1011 BOOL macdrv_process_text_input(UINT vkey, UINT scan, UINT repeat, const BYTE *key_state, void *himc)
1013 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1014 unsigned int flags;
1015 int keyc;
1016 BOOL ret = FALSE;
1018 TRACE("vkey 0x%04x scan 0x%04x repeat %u himc %p\n", vkey, scan, repeat, himc);
1020 flags = thread_data->last_modifiers;
1021 if (key_state[VK_SHIFT] & 0x80)
1022 flags |= NX_SHIFTMASK;
1023 else
1024 flags &= ~(NX_SHIFTMASK | NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK);
1025 if (key_state[VK_CAPITAL] & 0x01)
1026 flags |= NX_ALPHASHIFTMASK;
1027 else
1028 flags &= ~NX_ALPHASHIFTMASK;
1029 if (key_state[VK_CONTROL] & 0x80)
1030 flags |= NX_CONTROLMASK;
1031 else
1032 flags &= ~(NX_CONTROLMASK | NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK);
1033 if (key_state[VK_MENU] & 0x80)
1034 flags |= NX_COMMANDMASK;
1035 else
1036 flags &= ~(NX_COMMANDMASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK);
1038 /* Find the Mac keycode corresponding to the scan code */
1039 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]); keyc++)
1040 if (thread_data->keyc2vkey[keyc] == vkey) break;
1042 if (keyc >= sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]))
1043 goto done;
1045 TRACE("flags 0x%08x keyc 0x%04x\n", flags, keyc);
1047 ret = macdrv_send_text_input_event(((scan & 0x8000) == 0), flags, repeat, keyc, himc);
1049 done:
1050 TRACE(" -> %s\n", ret ? "TRUE" : "FALSE");
1051 return ret;
1055 /***********************************************************************
1056 * ActivateKeyboardLayout (MACDRV.@)
1058 HKL CDECL macdrv_ActivateKeyboardLayout(HKL hkl, UINT flags)
1060 HKL oldHkl = 0;
1061 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
1063 /* FIXME: Use Text Input Services or NSTextInputContext to actually
1064 change the Mac keyboard input source. */
1066 FIXME("hkl %p flags %04x: semi-stub!\n", hkl, flags);
1067 if (flags & KLF_SETFORPROCESS)
1069 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1070 FIXME("KLF_SETFORPROCESS not supported\n");
1071 return 0;
1074 if (flags)
1075 FIXME("flags %x not supported\n",flags);
1077 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
1079 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1080 FIXME("HKL_NEXT and HKL_PREV not supported\n");
1081 return 0;
1084 if (!match_keyboard_layout(hkl))
1086 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1087 FIXME("setting keyboard of different locales not supported\n");
1088 return 0;
1091 oldHkl = thread_data->active_keyboard_layout;
1092 if (!oldHkl) oldHkl = get_locale_keyboard_layout();
1094 thread_data->active_keyboard_layout = hkl;
1096 return oldHkl;
1100 /***********************************************************************
1101 * Beep (MACDRV.@)
1103 void CDECL macdrv_Beep(void)
1105 macdrv_beep();
1109 /***********************************************************************
1110 * GetKeyNameText (MACDRV.@)
1112 INT CDECL macdrv_GetKeyNameText(LONG lparam, LPWSTR buffer, INT size)
1114 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
1115 int scan, keyc;
1117 scan = (lparam >> 16) & 0x1FF;
1118 for (keyc = 0; keyc < sizeof(thread_data->keyc2scan)/sizeof(thread_data->keyc2scan[0]); keyc++)
1120 if (thread_data->keyc2scan[keyc] == scan)
1122 static const WCHAR dead[] = {' ','d','e','a','d',0};
1123 const UCKeyboardLayout *uchr;
1124 UInt32 deadKeyState = 0;
1125 UniCharCount len;
1126 OSStatus status;
1128 uchr = (const UCKeyboardLayout*)CFDataGetBytePtr(thread_data->keyboard_layout_uchr);
1129 status = UCKeyTranslate(uchr, keyc, kUCKeyActionDisplay, 0, thread_data->keyboard_type,
1130 0, &deadKeyState, size - 1, &len, (UniChar*)buffer);
1131 if (status != noErr)
1132 len = 0;
1133 if (len && isgraphW(buffer[0]))
1134 buffer[len] = 0;
1135 else
1137 DWORD vkey = thread_data->keyc2vkey[keyc];
1138 int i;
1140 if (scan & 0x100) vkey |= 0x100;
1142 if (lparam & (1 << 25))
1144 /* Caller doesn't care about distinctions between left and
1145 right keys. */
1146 switch (vkey)
1148 case VK_LSHIFT:
1149 case VK_RSHIFT:
1150 vkey = VK_SHIFT; break;
1151 case VK_LCONTROL:
1152 case VK_RCONTROL:
1153 vkey = VK_CONTROL; break;
1154 case VK_LMENU:
1155 case VK_RMENU:
1156 vkey = VK_MENU; break;
1160 len = 0;
1161 for (i = 0; i < sizeof(vkey_names) / sizeof(vkey_names[0]); i++)
1163 if (vkey_names[i].vkey == vkey)
1165 len = MultiByteToWideChar(CP_UTF8, 0, vkey_names[i].name, -1, buffer, size);
1166 if (len) len--;
1167 break;
1171 if (!len)
1173 static const WCHAR format[] = {'K','e','y',' ','0','x','%','0','2','x',0};
1174 snprintfW(buffer, size, format, vkey);
1175 len = strlenW(buffer);
1179 if (!len)
1180 break;
1182 if (status == noErr && deadKeyState)
1184 lstrcpynW(buffer + len, dead, size - len);
1185 len = strlenW(buffer);
1188 TRACE("lparam 0x%08x -> %s\n", lparam, debugstr_w(buffer));
1189 return len;
1193 WARN("found no name for lparam 0x%08x\n", lparam);
1194 return 0;
1198 /***********************************************************************
1199 * GetKeyboardLayout (MACDRV.@)
1201 HKL CDECL macdrv_GetKeyboardLayout(DWORD thread_id)
1203 if (!thread_id || thread_id == GetCurrentThreadId())
1205 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1206 if (thread_data && thread_data->active_keyboard_layout)
1207 return thread_data->active_keyboard_layout;
1209 else
1210 FIXME("couldn't return keyboard layout for thread %04x\n", thread_id);
1212 /* FIXME: Use TISGetInputSourceProperty() and kTISPropertyInputSourceLanguages
1213 * to get input source language ID string. Use
1214 * CFLocaleGetWindowsLocaleCodeFromLocaleIdentifier() to convert that
1215 * to a Windows locale ID and from there to a layout handle.
1218 return get_locale_keyboard_layout();
1222 /***********************************************************************
1223 * GetKeyboardLayoutName (MACDRV.@)
1225 BOOL CDECL macdrv_GetKeyboardLayoutName(LPWSTR name)
1227 static const WCHAR formatW[] = {'%','0','8','x',0};
1228 DWORD layout;
1230 layout = HandleToUlong(get_locale_keyboard_layout());
1231 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1232 sprintfW(name, formatW, layout);
1233 TRACE("returning %s\n", debugstr_w(name));
1234 return TRUE;
1238 /***********************************************************************
1239 * MapVirtualKeyEx (MACDRV.@)
1241 UINT CDECL macdrv_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
1243 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
1244 UINT ret = 0;
1245 int keyc;
1247 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
1249 switch (wMapType)
1251 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
1252 case MAPVK_VK_TO_VSC_EX:
1253 switch (wCode)
1255 case VK_SHIFT: wCode = VK_LSHIFT; break;
1256 case VK_CONTROL: wCode = VK_LCONTROL; break;
1257 case VK_MENU: wCode = VK_LMENU; break;
1260 /* vkey -> keycode -> scan */
1261 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]); keyc++)
1263 if (thread_data->keyc2vkey[keyc] == wCode)
1265 ret = thread_data->keyc2scan[keyc] & 0xFF;
1266 break;
1269 break;
1271 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
1272 case MAPVK_VSC_TO_VK_EX:
1273 /* scan -> keycode -> vkey */
1274 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]); keyc++)
1275 if ((thread_data->keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1277 ret = thread_data->keyc2vkey[keyc];
1278 /* Only stop if it's not a numpad vkey; otherwise keep
1279 looking for a potential better vkey. */
1280 if (ret && (ret < VK_NUMPAD0 || VK_DIVIDE < ret))
1281 break;
1284 if (wMapType == MAPVK_VSC_TO_VK)
1285 switch (ret)
1287 case VK_LSHIFT:
1288 case VK_RSHIFT:
1289 ret = VK_SHIFT; break;
1290 case VK_LCONTROL:
1291 case VK_RCONTROL:
1292 ret = VK_CONTROL; break;
1293 case VK_LMENU:
1294 case VK_RMENU:
1295 ret = VK_MENU; break;
1298 break;
1300 case MAPVK_VK_TO_CHAR: /* vkey-code to character */
1302 /* vkey -> keycode -> (UCKeyTranslate) wide char */
1303 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1304 const UCKeyboardLayout *uchr;
1305 UniChar s[10];
1306 OSStatus status;
1307 UInt32 deadKeyState;
1308 UniCharCount len;
1309 BOOL deadKey = FALSE;
1311 if ((VK_PRIOR <= wCode && wCode <= VK_HELP) ||
1312 (VK_F1 <= wCode && wCode <= VK_F24))
1313 break;
1315 if (!thread_data || !thread_data->keyboard_layout_uchr)
1317 WARN("No keyboard layout uchr data\n");
1318 break;
1321 uchr = (const UCKeyboardLayout*)CFDataGetBytePtr(thread_data->keyboard_layout_uchr);
1323 /* Find the Mac keycode corresponding to the vkey */
1324 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]); keyc++)
1325 if (thread_data->keyc2vkey[keyc] == wCode) break;
1327 if (keyc >= sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]))
1329 WARN("Unknown virtual key %X\n", wCode);
1330 break;
1333 TRACE("Found keycode %u\n", keyc);
1335 deadKeyState = 0;
1336 status = UCKeyTranslate(uchr, keyc, kUCKeyActionDown, 0,
1337 thread_data->keyboard_type, 0, &deadKeyState,
1338 sizeof(s)/sizeof(s[0]), &len, s);
1339 if (status == noErr && !len && deadKeyState)
1341 deadKey = TRUE;
1342 deadKeyState = 0;
1343 status = UCKeyTranslate(uchr, keyc, kUCKeyActionDown, 0,
1344 thread_data->keyboard_type, kUCKeyTranslateNoDeadKeysMask,
1345 &deadKeyState, sizeof(s)/sizeof(s[0]), &len, s);
1348 if (status == noErr && len)
1349 ret = toupperW(s[0]) | (deadKey ? 0x80000000 : 0);
1351 break;
1353 default: /* reserved */
1354 FIXME("Unknown wMapType %d\n", wMapType);
1355 break;
1358 TRACE("returning 0x%04x\n", ret);
1359 return ret;
1363 /***********************************************************************
1364 * RegisterHotKey (MACDRV.@)
1366 BOOL CDECL macdrv_RegisterHotKey(HWND hwnd, UINT mod_flags, UINT vkey)
1368 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
1369 unsigned int keyc, modifiers = 0;
1370 int ret;
1372 TRACE_(key)("hwnd %p mod_flags 0x%04x vkey 0x%04x\n", hwnd, mod_flags, vkey);
1374 /* Find the Mac keycode corresponding to the vkey */
1375 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey) / sizeof(thread_data->keyc2vkey[0]); keyc++)
1376 if (thread_data->keyc2vkey[keyc] == vkey) break;
1378 if (keyc >= sizeof(thread_data->keyc2vkey) / sizeof(thread_data->keyc2vkey[0]))
1380 WARN_(key)("ignoring unknown virtual key 0x%04x\n", vkey);
1381 return TRUE;
1384 if (mod_flags & MOD_ALT) modifiers |= cmdKey;
1385 if (mod_flags & MOD_CONTROL) modifiers |= controlKey;
1386 if (mod_flags & MOD_SHIFT) modifiers |= shiftKey;
1387 if (mod_flags & MOD_WIN)
1389 WARN_(key)("MOD_WIN not supported; ignoring\n");
1390 return TRUE;
1393 ret = macdrv_register_hot_key(thread_data->queue, vkey, mod_flags, keyc, modifiers);
1394 TRACE_(key)("keyc 0x%04x modifiers 0x%08x -> %d\n", keyc, modifiers, ret);
1396 if (ret == MACDRV_HOTKEY_ALREADY_REGISTERED)
1397 SetLastError(ERROR_HOTKEY_ALREADY_REGISTERED);
1398 else if (ret != MACDRV_HOTKEY_SUCCESS)
1399 SetLastError(ERROR_GEN_FAILURE);
1401 return ret == MACDRV_HOTKEY_SUCCESS;
1405 /***********************************************************************
1406 * ToUnicodeEx (MACDRV.@)
1408 * The ToUnicode function translates the specified virtual-key code and keyboard
1409 * state to the corresponding Windows character or characters.
1411 * If the specified key is a dead key, the return value is negative. Otherwise,
1412 * it is one of the following values:
1413 * Value Meaning
1414 * -1 The specified virtual key is a dead-key. If possible, the
1415 * non-combining form of the dead character is written to bufW.
1416 * 0 The specified virtual key has no translation for the current
1417 * state of the keyboard.
1418 * 1 One Windows character was copied to the buffer.
1419 * 2 or more Multiple characters were copied to the buffer. This usually
1420 * happens when a dead-key character (accent or diacritic) stored
1421 * in the keyboard layout cannot be composed with the specified
1422 * virtual key to form a single character.
1425 INT CDECL macdrv_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
1426 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
1428 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
1429 INT ret = 0;
1430 int keyc;
1431 BOOL is_menu = (flags & 0x1);
1432 OSStatus status;
1433 const UCKeyboardLayout *uchr;
1434 UInt16 keyAction;
1435 UInt32 modifierKeyState;
1436 OptionBits options;
1437 UInt32 deadKeyState, savedDeadKeyState;
1438 UniCharCount len;
1439 BOOL dead = FALSE;
1441 TRACE_(key)("virtKey 0x%04x scanCode 0x%04x lpKeyState %p bufW %p bufW_size %d flags 0x%08x hkl %p\n",
1442 virtKey, scanCode, lpKeyState, bufW, bufW_size, flags, hkl);
1444 if (!virtKey)
1445 goto done;
1447 /* UCKeyTranslate, below, terminates a dead-key sequence if passed a
1448 modifier key press. We want it to effectively ignore modifier key
1449 presses. I think that one isn't supposed to call it at all for modifier
1450 events (e.g. NSFlagsChanged or kEventRawKeyModifiersChanged), since they
1451 are different event types than key up/down events. */
1452 switch (virtKey)
1454 case VK_SHIFT:
1455 case VK_CONTROL:
1456 case VK_MENU:
1457 case VK_CAPITAL:
1458 case VK_LSHIFT:
1459 case VK_RSHIFT:
1460 case VK_LCONTROL:
1461 case VK_RCONTROL:
1462 case VK_LMENU:
1463 case VK_RMENU:
1464 goto done;
1467 /* There are a number of key combinations for which Windows does not
1468 produce characters, but Mac keyboard layouts may. Eat them. Do this
1469 here to avoid the expense of UCKeyTranslate() but also because these
1470 keys shouldn't terminate dead key sequences. */
1471 if ((VK_PRIOR <= virtKey && virtKey <= VK_HELP) || (VK_F1 <= virtKey && virtKey <= VK_F24))
1472 goto done;
1474 /* Shift + <non-digit keypad keys>. */
1475 if ((lpKeyState[VK_SHIFT] & 0x80) && VK_MULTIPLY <= virtKey && virtKey <= VK_DIVIDE)
1476 goto done;
1478 if (lpKeyState[VK_CONTROL] & 0x80)
1480 /* Control-Tab, with or without other modifiers. */
1481 if (virtKey == VK_TAB)
1482 goto done;
1484 /* Control-Shift-<key>, Control-Alt-<key>, and Control-Alt-Shift-<key>
1485 for these keys. */
1486 if ((lpKeyState[VK_SHIFT] & 0x80) || (lpKeyState[VK_MENU] & 0x80))
1488 switch (virtKey)
1490 case VK_CANCEL:
1491 case VK_BACK:
1492 case VK_ESCAPE:
1493 case VK_SPACE:
1494 case VK_RETURN:
1495 goto done;
1500 if (thread_data->keyboard_layout_uchr)
1501 uchr = (const UCKeyboardLayout*)CFDataGetBytePtr(thread_data->keyboard_layout_uchr);
1502 else
1503 uchr = NULL;
1505 keyAction = (scanCode & 0x8000) ? kUCKeyActionUp : kUCKeyActionDown;
1507 modifierKeyState = 0;
1508 if (lpKeyState[VK_SHIFT] & 0x80)
1509 modifierKeyState |= (shiftKey >> 8);
1510 if (lpKeyState[VK_CAPITAL] & 0x01)
1511 modifierKeyState |= (alphaLock >> 8);
1512 if (lpKeyState[VK_CONTROL] & 0x80)
1513 modifierKeyState |= (controlKey >> 8);
1514 if (lpKeyState[VK_MENU] & 0x80)
1515 modifierKeyState |= (cmdKey >> 8);
1516 if (thread_data->last_modifiers & (NX_ALTERNATEMASK | NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK))
1517 modifierKeyState |= (optionKey >> 8);
1519 /* Find the Mac keycode corresponding to the vkey */
1520 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]); keyc++)
1521 if (thread_data->keyc2vkey[keyc] == virtKey) break;
1523 if (keyc >= sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]))
1525 WARN_(key)("Unknown virtual key 0x%04x\n", virtKey);
1526 goto done;
1529 TRACE_(key)("Key code 0x%04x %s, faked modifiers = 0x%04x\n", keyc,
1530 (keyAction == kUCKeyActionDown) ? "pressed" : "released", (unsigned)modifierKeyState);
1532 if (is_menu)
1534 if (keyAction == kUCKeyActionUp)
1535 goto done;
1537 options = kUCKeyTranslateNoDeadKeysMask;
1538 deadKeyState = 0;
1540 else
1542 options = 0;
1543 deadKeyState = thread_data->dead_key_state;
1545 savedDeadKeyState = deadKeyState;
1546 status = UCKeyTranslate(uchr, keyc, keyAction, modifierKeyState,
1547 thread_data->keyboard_type, options, &deadKeyState, bufW_size,
1548 &len, bufW);
1549 if (status != noErr)
1551 ERR_(key)("Couldn't translate keycode 0x%04x, status %ld\n", keyc, status);
1552 goto done;
1554 if (!is_menu)
1556 if (keyAction != kUCKeyActionUp && len > 0 && deadKeyState == thread_data->dead_key_state)
1557 thread_data->dead_key_state = 0;
1558 else
1559 thread_data->dead_key_state = deadKeyState;
1561 if (keyAction == kUCKeyActionUp)
1562 goto done;
1565 if (len == 0 && deadKeyState)
1567 /* Repeat the translation, but disabling dead-key generation to
1568 learn which dead key it was. */
1569 status = UCKeyTranslate(uchr, keyc, keyAction, modifierKeyState,
1570 thread_data->keyboard_type, kUCKeyTranslateNoDeadKeysMask,
1571 &savedDeadKeyState, bufW_size, &len, bufW);
1572 if (status != noErr)
1574 ERR_(key)("Couldn't translate keycode 0x%04x, status %ld\n", keyc, status);
1575 goto done;
1578 dead = TRUE;
1581 if (len > 0)
1582 len = strip_apple_private_chars(bufW, len);
1584 if (dead && len > 0) ret = -1;
1585 else ret = len;
1587 /* Control-Return produces line feed instead of carriage return. */
1588 if (ret > 0 && (lpKeyState[VK_CONTROL] & 0x80) && virtKey == VK_RETURN)
1590 int i;
1591 for (i = 0; i < len; i++)
1592 if (bufW[i] == '\r')
1593 bufW[i] = '\n';
1596 done:
1597 /* Null-terminate the buffer, if there's room. MSDN clearly states that the
1598 caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
1599 if (1 <= ret && ret < bufW_size)
1600 bufW[ret] = 0;
1602 TRACE_(key)("returning %d / %s\n", ret, debugstr_wn(bufW, abs(ret)));
1603 return ret;
1607 /***********************************************************************
1608 * UnregisterHotKey (MACDRV.@)
1610 void CDECL macdrv_UnregisterHotKey(HWND hwnd, UINT modifiers, UINT vkey)
1612 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1614 TRACE_(key)("hwnd %p modifiers 0x%04x vkey 0x%04x\n", hwnd, modifiers, vkey);
1616 if (thread_data)
1617 macdrv_unregister_hot_key(thread_data->queue, vkey, modifiers);
1621 /***********************************************************************
1622 * VkKeyScanEx (MACDRV.@)
1624 * Note: Windows ignores HKL parameter and uses current active layout instead
1626 SHORT CDECL macdrv_VkKeyScanEx(WCHAR wChar, HKL hkl)
1628 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
1629 SHORT ret = -1;
1630 int state;
1631 const UCKeyboardLayout *uchr;
1633 TRACE("%04x, %p\n", wChar, hkl);
1635 uchr = (const UCKeyboardLayout*)CFDataGetBytePtr(thread_data->keyboard_layout_uchr);
1636 if (!uchr)
1638 TRACE("no keyboard layout UCHR data; returning -1\n");
1639 return -1;
1642 for (state = 0; state < 8; state++)
1644 UInt32 modifierKeyState = 0;
1645 int keyc;
1647 if (state & 1)
1648 modifierKeyState |= (shiftKey >> 8);
1649 if ((state & 6) == 6)
1650 modifierKeyState |= (optionKey >> 8);
1651 else
1653 if (state & 2)
1654 modifierKeyState |= (controlKey >> 8);
1655 if (state & 4)
1656 modifierKeyState |= (cmdKey >> 8);
1659 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey) / sizeof(thread_data->keyc2vkey[0]); keyc++)
1661 UInt32 deadKeyState = 0;
1662 UniChar uchar;
1663 UniCharCount len;
1664 OSStatus status;
1666 if (!thread_data->keyc2vkey[keyc]) continue;
1668 status = UCKeyTranslate(uchr, keyc, kUCKeyActionDown, modifierKeyState,
1669 thread_data->keyboard_type, 0, &deadKeyState,
1670 1, &len, &uchar);
1671 if (status == noErr && len == 1 && uchar == wChar)
1673 WORD vkey = thread_data->keyc2vkey[keyc];
1675 ret = vkey | (state << 8);
1676 if ((VK_NUMPAD0 <= vkey && vkey <= VK_DIVIDE) ||
1677 keyc == kVK_ANSI_KeypadClear || keyc == kVK_ANSI_KeypadEnter ||
1678 keyc == kVK_ANSI_KeypadEquals)
1680 /* Keep searching for a non-numpad match, which is preferred. */
1682 else
1683 goto done;
1688 done:
1689 TRACE(" -> 0x%04x\n", ret);
1690 return ret;