wined3d: Get rid of the offscreenBuffer field in struct wined3d_device.
[wine.git] / dlls / winemac.drv / keyboard.c
blob6680e6b2dc723f910efe03825595e60cf40cf312
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,
179 extern const CFStringRef kTISTypeKeyboardLayout;
181 /* Indexed by Mac virtual keycode values defined above. */
182 static const struct {
183 WORD vkey;
184 WORD scan;
185 BOOL fixed;
186 } default_map[128] = {
187 { 'A', 0x1E, FALSE }, /* kVK_ANSI_A */
188 { 'S', 0x1F, FALSE }, /* kVK_ANSI_S */
189 { 'D', 0x20, FALSE }, /* kVK_ANSI_D */
190 { 'F', 0x21, FALSE }, /* kVK_ANSI_F */
191 { 'H', 0x23, FALSE }, /* kVK_ANSI_H */
192 { 'G', 0x22, FALSE }, /* kVK_ANSI_G */
193 { 'Z', 0x2C, FALSE }, /* kVK_ANSI_Z */
194 { 'X', 0x2D, FALSE }, /* kVK_ANSI_X */
195 { 'C', 0x2E, FALSE }, /* kVK_ANSI_C */
196 { 'V', 0x2F, FALSE }, /* kVK_ANSI_V */
197 { VK_OEM_102, 0x56, TRUE }, /* kVK_ISO_Section */
198 { 'B', 0x30, FALSE }, /* kVK_ANSI_B */
199 { 'Q', 0x10, FALSE }, /* kVK_ANSI_Q */
200 { 'W', 0x11, FALSE }, /* kVK_ANSI_W */
201 { 'E', 0x12, FALSE }, /* kVK_ANSI_E */
202 { 'R', 0x13, FALSE }, /* kVK_ANSI_R */
203 { 'Y', 0x15, FALSE }, /* kVK_ANSI_Y */
204 { 'T', 0x14, FALSE }, /* kVK_ANSI_T */
205 { '1', 0x02, FALSE }, /* kVK_ANSI_1 */
206 { '2', 0x03, FALSE }, /* kVK_ANSI_2 */
207 { '3', 0x04, FALSE }, /* kVK_ANSI_3 */
208 { '4', 0x05, FALSE }, /* kVK_ANSI_4 */
209 { '6', 0x07, FALSE }, /* kVK_ANSI_6 */
210 { '5', 0x06, FALSE }, /* kVK_ANSI_5 */
211 { VK_OEM_PLUS, 0x0D, FALSE }, /* kVK_ANSI_Equal */
212 { '9', 0x0A, FALSE }, /* kVK_ANSI_9 */
213 { '7', 0x08, FALSE }, /* kVK_ANSI_7 */
214 { VK_OEM_MINUS, 0x0C, FALSE }, /* kVK_ANSI_Minus */
215 { '8', 0x09, FALSE }, /* kVK_ANSI_8 */
216 { '0', 0x0B, FALSE }, /* kVK_ANSI_0 */
217 { VK_OEM_6, 0x1B, FALSE }, /* kVK_ANSI_RightBracket */
218 { 'O', 0x18, FALSE }, /* kVK_ANSI_O */
219 { 'U', 0x16, FALSE }, /* kVK_ANSI_U */
220 { VK_OEM_4, 0x1A, FALSE }, /* kVK_ANSI_LeftBracket */
221 { 'I', 0x17, FALSE }, /* kVK_ANSI_I */
222 { 'P', 0x19, FALSE }, /* kVK_ANSI_P */
223 { VK_RETURN, 0x1C, TRUE }, /* kVK_Return */
224 { 'L', 0x26, FALSE }, /* kVK_ANSI_L */
225 { 'J', 0x24, FALSE }, /* kVK_ANSI_J */
226 { VK_OEM_7, 0x28, FALSE }, /* kVK_ANSI_Quote */
227 { 'K', 0x25, FALSE }, /* kVK_ANSI_K */
228 { VK_OEM_1, 0x27, FALSE }, /* kVK_ANSI_Semicolon */
229 { VK_OEM_5, 0x2B, FALSE }, /* kVK_ANSI_Backslash */
230 { VK_OEM_COMMA, 0x33, FALSE }, /* kVK_ANSI_Comma */
231 { VK_OEM_2, 0x35, FALSE }, /* kVK_ANSI_Slash */
232 { 'N', 0x31, FALSE }, /* kVK_ANSI_N */
233 { 'M', 0x32, FALSE }, /* kVK_ANSI_M */
234 { VK_OEM_PERIOD, 0x34, FALSE }, /* kVK_ANSI_Period */
235 { VK_TAB, 0x0F, TRUE }, /* kVK_Tab */
236 { VK_SPACE, 0x39, TRUE }, /* kVK_Space */
237 { VK_OEM_3, 0x29, FALSE }, /* kVK_ANSI_Grave */
238 { VK_BACK, 0x0E, TRUE }, /* kVK_Delete */
239 { 0, 0, FALSE }, /* 0x34 unused */
240 { VK_ESCAPE, 0x01, TRUE }, /* kVK_Escape */
241 { VK_RMENU, 0x38 | 0x100, TRUE }, /* kVK_RightCommand */
242 { VK_LMENU, 0x38, TRUE }, /* kVK_Command */
243 { VK_LSHIFT, 0x2A, TRUE }, /* kVK_Shift */
244 { VK_CAPITAL, 0x3A, TRUE }, /* kVK_CapsLock */
245 { 0, 0, FALSE }, /* kVK_Option */
246 { VK_LCONTROL, 0x1D, TRUE }, /* kVK_Control */
247 { VK_RSHIFT, 0x36, TRUE }, /* kVK_RightShift */
248 { 0, 0, FALSE }, /* kVK_RightOption */
249 { VK_RCONTROL, 0x1D | 0x100, TRUE }, /* kVK_RightControl */
250 { 0, 0, FALSE }, /* kVK_Function */
251 { VK_F17, 0x68, TRUE }, /* kVK_F17 */
252 { VK_DECIMAL, 0x53, TRUE }, /* kVK_ANSI_KeypadDecimal */
253 { 0, 0, FALSE }, /* 0x42 unused */
254 { VK_MULTIPLY, 0x37, TRUE }, /* kVK_ANSI_KeypadMultiply */
255 { 0, 0, FALSE }, /* 0x44 unused */
256 { VK_ADD, 0x4E, TRUE }, /* kVK_ANSI_KeypadPlus */
257 { 0, 0, FALSE }, /* 0x46 unused */
258 { VK_OEM_CLEAR, 0x59, TRUE }, /* kVK_ANSI_KeypadClear */
259 { VK_VOLUME_UP, 0 | 0x100, TRUE }, /* kVK_VolumeUp */
260 { VK_VOLUME_DOWN, 0 | 0x100, TRUE }, /* kVK_VolumeDown */
261 { VK_VOLUME_MUTE, 0 | 0x100, TRUE }, /* kVK_Mute */
262 { VK_DIVIDE, 0x35 | 0x100, TRUE }, /* kVK_ANSI_KeypadDivide */
263 { VK_RETURN, 0x1C | 0x100, TRUE }, /* kVK_ANSI_KeypadEnter */
264 { 0, 0, FALSE }, /* 0x4D unused */
265 { VK_SUBTRACT, 0x4A, TRUE }, /* kVK_ANSI_KeypadMinus */
266 { VK_F18, 0x69, TRUE }, /* kVK_F18 */
267 { VK_F19, 0x6A, TRUE }, /* kVK_F19 */
268 { VK_OEM_NEC_EQUAL, 0x0D | 0x100, TRUE }, /* kVK_ANSI_KeypadEquals */
269 { VK_NUMPAD0, 0x52, TRUE }, /* kVK_ANSI_Keypad0 */
270 { VK_NUMPAD1, 0x4F, TRUE }, /* kVK_ANSI_Keypad1 */
271 { VK_NUMPAD2, 0x50, TRUE }, /* kVK_ANSI_Keypad2 */
272 { VK_NUMPAD3, 0x51, TRUE }, /* kVK_ANSI_Keypad3 */
273 { VK_NUMPAD4, 0x4B, TRUE }, /* kVK_ANSI_Keypad4 */
274 { VK_NUMPAD5, 0x4C, TRUE }, /* kVK_ANSI_Keypad5 */
275 { VK_NUMPAD6, 0x4D, TRUE }, /* kVK_ANSI_Keypad6 */
276 { VK_NUMPAD7, 0x47, TRUE }, /* kVK_ANSI_Keypad7 */
277 { VK_F20, 0x6B, TRUE }, /* kVK_F20 */
278 { VK_NUMPAD8, 0x48, TRUE }, /* kVK_ANSI_Keypad8 */
279 { VK_NUMPAD9, 0x49, TRUE }, /* kVK_ANSI_Keypad9 */
280 { 0xFF, 0x7D, TRUE }, /* kVK_JIS_Yen */
281 { 0xC1, 0x73, TRUE }, /* kVK_JIS_Underscore */
282 { VK_SEPARATOR, 0x7E, TRUE }, /* kVK_JIS_KeypadComma */
283 { VK_F5, 0x3F, TRUE }, /* kVK_F5 */
284 { VK_F6, 0x40, TRUE }, /* kVK_F6 */
285 { VK_F7, 0x41, TRUE }, /* kVK_F7 */
286 { VK_F3, 0x3D, TRUE }, /* kVK_F3 */
287 { VK_F8, 0x42, TRUE }, /* kVK_F8 */
288 { VK_F9, 0x43, TRUE }, /* kVK_F9 */
289 { 0xFF, 0x72, TRUE }, /* kVK_JIS_Eisu */
290 { VK_F11, 0x57, TRUE }, /* kVK_F11 */
291 { VK_OEM_RESET, 0x71, TRUE }, /* kVK_JIS_Kana */
292 { VK_F13, 0x64, TRUE }, /* kVK_F13 */
293 { VK_F16, 0x67, TRUE }, /* kVK_F16 */
294 { VK_F14, 0x65, TRUE }, /* kVK_F14 */
295 { 0, 0, FALSE }, /* 0x6C unused */
296 { VK_F10, 0x44, TRUE }, /* kVK_F10 */
297 { 0, 0, FALSE }, /* 0x6E unused */
298 { VK_F12, 0x58, TRUE }, /* kVK_F12 */
299 { 0, 0, FALSE }, /* 0x70 unused */
300 { VK_F15, 0x66, TRUE }, /* kVK_F15 */
301 { VK_INSERT, 0x52 | 0x100, TRUE }, /* kVK_Help */ /* map to Insert */
302 { VK_HOME, 0x47 | 0x100, TRUE }, /* kVK_Home */
303 { VK_PRIOR, 0x49 | 0x100, TRUE }, /* kVK_PageUp */
304 { VK_DELETE, 0x53 | 0x100, TRUE }, /* kVK_ForwardDelete */
305 { VK_F4, 0x3E, TRUE }, /* kVK_F4 */
306 { VK_END, 0x4F | 0x100, TRUE }, /* kVK_End */
307 { VK_F2, 0x3C, TRUE }, /* kVK_F2 */
308 { VK_NEXT, 0x51 | 0x100, TRUE }, /* kVK_PageDown */
309 { VK_F1, 0x3B, TRUE }, /* kVK_F1 */
310 { VK_LEFT, 0x4B | 0x100, TRUE }, /* kVK_LeftArrow */
311 { VK_RIGHT, 0x4D | 0x100, TRUE }, /* kVK_RightArrow */
312 { VK_DOWN, 0x50 | 0x100, TRUE }, /* kVK_DownArrow */
313 { VK_UP, 0x48 | 0x100, TRUE }, /* kVK_UpArrow */
317 static const struct {
318 DWORD vkey;
319 const char *name;
320 } vkey_names[] = {
321 { VK_ADD, "Num +" },
322 { VK_BACK, "Backspace" },
323 { VK_CAPITAL, "Caps Lock" },
324 { VK_CONTROL, "Ctrl" },
325 { VK_DECIMAL, "Num Del" },
326 { VK_DELETE | 0x100, "Delete" },
327 { VK_DIVIDE | 0x100, "Num /" },
328 { VK_DOWN | 0x100, "Down" },
329 { VK_END | 0x100, "End" },
330 { VK_ESCAPE, "Esc" },
331 { VK_F1, "F1" },
332 { VK_F2, "F2" },
333 { VK_F3, "F3" },
334 { VK_F4, "F4" },
335 { VK_F5, "F5" },
336 { VK_F6, "F6" },
337 { VK_F7, "F7" },
338 { VK_F8, "F8" },
339 { VK_F9, "F9" },
340 { VK_F10, "F10" },
341 { VK_F11, "F11" },
342 { VK_F12, "F12" },
343 { VK_F13, "F13" },
344 { VK_F14, "F14" },
345 { VK_F15, "F15" },
346 { VK_F16, "F16" },
347 { VK_F17, "F17" },
348 { VK_F18, "F18" },
349 { VK_F19, "F19" },
350 { VK_F20, "F20" },
351 { VK_F21, "F21" },
352 { VK_F22, "F22" },
353 { VK_F23, "F23" },
354 { VK_F24, "F24" },
355 { VK_HELP | 0x100, "Help" },
356 { VK_HOME | 0x100, "Home" },
357 { VK_INSERT | 0x100, "Insert" },
358 { VK_LCONTROL, "Ctrl" },
359 { VK_LEFT | 0x100, "Left" },
360 { VK_LMENU, "Alt" },
361 { VK_LSHIFT, "Shift" },
362 { VK_LWIN | 0x100, "Win" },
363 { VK_MENU, "Alt" },
364 { VK_MULTIPLY, "Num *" },
365 { VK_NEXT | 0x100, "Page Down" },
366 { VK_NUMLOCK | 0x100, "Num Lock" },
367 { VK_NUMPAD0, "Num 0" },
368 { VK_NUMPAD1, "Num 1" },
369 { VK_NUMPAD2, "Num 2" },
370 { VK_NUMPAD3, "Num 3" },
371 { VK_NUMPAD4, "Num 4" },
372 { VK_NUMPAD5, "Num 5" },
373 { VK_NUMPAD6, "Num 6" },
374 { VK_NUMPAD7, "Num 7" },
375 { VK_NUMPAD8, "Num 8" },
376 { VK_NUMPAD9, "Num 9" },
377 { VK_OEM_CLEAR, "Num Clear" },
378 { VK_OEM_NEC_EQUAL | 0x100, "Num =" },
379 { VK_PRIOR | 0x100, "Page Up" },
380 { VK_RCONTROL | 0x100, "Right Ctrl" },
381 { VK_RETURN, "Return" },
382 { VK_RETURN | 0x100, "Num Enter" },
383 { VK_RIGHT | 0x100, "Right" },
384 { VK_RMENU | 0x100, "Right Alt" },
385 { VK_RSHIFT, "Right Shift" },
386 { VK_RWIN | 0x100, "Right Win" },
387 { VK_SEPARATOR, "Num ," },
388 { VK_SHIFT, "Shift" },
389 { VK_SPACE, "Space" },
390 { VK_SUBTRACT, "Num -" },
391 { VK_TAB, "Tab" },
392 { VK_UP | 0x100, "Up" },
393 { VK_VOLUME_DOWN | 0x100, "Volume Down" },
394 { VK_VOLUME_MUTE | 0x100, "Mute" },
395 { VK_VOLUME_UP | 0x100, "Volume Up" },
398 HKL CDECL macdrv_GetKeyboardLayout(DWORD);
400 static BOOL char_matches_string(WCHAR wchar, UniChar *string, BOOL ignore_diacritics)
402 BOOL ret;
403 CFStringRef s1 = CFStringCreateWithCharactersNoCopy(NULL, (UniChar*)&wchar, 1, kCFAllocatorNull);
404 CFStringRef s2 = CFStringCreateWithCharactersNoCopy(NULL, string, strlenW(string), kCFAllocatorNull);
405 CFStringCompareFlags flags = kCFCompareCaseInsensitive | kCFCompareNonliteral | kCFCompareWidthInsensitive;
406 if (ignore_diacritics)
407 flags |= kCFCompareDiacriticInsensitive;
408 ret = (CFStringCompare(s1, s2, flags) == kCFCompareEqualTo);
409 CFRelease(s1);
410 CFRelease(s2);
411 return ret;
415 /* Filter Apple-specific private-use characters (see NSEvent.h) out of a
416 * string. Returns the length of the string after stripping. */
417 static int strip_apple_private_chars(LPWSTR bufW, int len)
419 int i;
420 for (i = 0; i < len; )
422 if (0xF700 <= bufW[i] && bufW[i] <= 0xF8FF)
424 memmove(&bufW[i], &bufW[i+1], (len - i - 1) * sizeof(bufW[0]));
425 len--;
427 else
428 i++;
430 return len;
433 static struct list layout_list = LIST_INIT( layout_list );
434 struct layout
436 struct list entry;
437 HKL hkl;
438 TISInputSourceRef input_source;
439 BOOL enabled; /* is the input source enabled - ie displayed in the input source selector UI */
442 static CRITICAL_SECTION layout_list_section;
443 static CRITICAL_SECTION_DEBUG critsect_debug =
445 0, 0, &layout_list_section,
446 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
447 0, 0, { (DWORD_PTR)(__FILE__ ": layout_list_section") }
449 static CRITICAL_SECTION layout_list_section = { &critsect_debug, -1, 0, 0, 0, 0 };
451 int macdrv_layout_list_needs_update = TRUE;
453 static DWORD get_lcid(CFStringRef lang)
455 CFRange range;
456 WCHAR str[10];
458 range.location = 0;
459 range.length = min(CFStringGetLength(lang), sizeof(str) / sizeof(str[0]) - 1);
460 CFStringGetCharacters(lang, range, str);
461 str[range.length] = 0;
462 return LocaleNameToLCID(str, 0);
465 static HKL get_hkl(CFStringRef lang, CFStringRef type)
467 ULONG_PTR lcid = get_lcid(lang);
468 struct layout *layout;
470 /* Look for the last occurrence of this lcid in the list and if
471 present use that value + 0x10000 */
472 LIST_FOR_EACH_ENTRY_REV(layout, &layout_list, struct layout, entry)
474 ULONG_PTR hkl = HandleToUlong(layout->hkl);
476 if (LOWORD(hkl) == lcid)
478 lcid = (hkl & ~0xe0000000) + 0x10000;
479 break;
483 if (!CFEqual(type, kTISTypeKeyboardLayout)) lcid |= 0xe0000000;
485 return (HKL)lcid;
488 /******************************************************************
489 * get_layout_from_source
491 * Must be called while holding the layout_list_section.
492 * Note, returned layout may not currently be enabled.
494 static struct layout *get_layout_from_source(TISInputSourceRef input)
496 struct layout *ret = NULL, *layout;
498 LIST_FOR_EACH_ENTRY(layout, &layout_list, struct layout, entry)
500 if (CFEqual(input, layout->input_source))
502 ret = layout;
503 break;
506 return ret;
509 /***********************************************************************
510 * update_layout_list
512 * Must be called while holding the layout_list_section
514 * If an input source has been disabled (ie. removed from the UI) its
515 * entry remains in the layout list but is marked as such and is not
516 * enumerated by GetKeyboardLayoutList. This is to ensure the
517 * HKL <-> input source mapping is unique.
519 static void update_layout_list(void)
521 CFArrayRef sources;
522 struct layout *layout;
523 int i;
525 if (!InterlockedExchange(&macdrv_layout_list_needs_update, FALSE)) return;
527 sources = macdrv_create_input_source_list();
529 LIST_FOR_EACH_ENTRY(layout, &layout_list, struct layout, entry)
530 layout->enabled = FALSE;
532 for (i = 0; i < CFArrayGetCount(sources); i++)
534 CFDictionaryRef dict = CFArrayGetValueAtIndex(sources, i);
535 TISInputSourceRef input = (TISInputSourceRef)CFDictionaryGetValue(dict, macdrv_input_source_input_key);
536 layout = get_layout_from_source(input);
537 if (!layout)
539 CFStringRef type = CFDictionaryGetValue(dict, macdrv_input_source_type_key);
540 CFStringRef lang = CFDictionaryGetValue(dict, macdrv_input_source_lang_key);
542 layout = HeapAlloc(GetProcessHeap(), 0, sizeof(*layout));
543 layout->input_source = (TISInputSourceRef)CFRetain(input);
544 layout->hkl = get_hkl(lang, type);
546 list_add_tail(&layout_list, &layout->entry);
547 TRACE("adding new layout %p\n", layout->hkl);
549 else
550 TRACE("enabling already existing layout %p\n", layout->hkl);
552 layout->enabled = TRUE;
555 CFRelease(sources);
558 /***********************************************************************
559 * macdrv_get_hkl_from_source
561 * Find the HKL associated with a given input source.
563 HKL macdrv_get_hkl_from_source(TISInputSourceRef input)
565 struct layout *layout;
566 HKL ret = 0;
568 EnterCriticalSection(&layout_list_section);
570 update_layout_list();
571 layout = get_layout_from_source(input);
572 if (layout) ret = layout->hkl;
574 LeaveCriticalSection(&layout_list_section);
576 return ret;
580 /***********************************************************************
581 * macdrv_compute_keyboard_layout
583 void macdrv_compute_keyboard_layout(struct macdrv_thread_data *thread_data)
585 int keyc;
586 WCHAR vkey;
587 const UCKeyboardLayout *uchr;
588 const UInt32 modifier_combos[] = {
590 shiftKey >> 8,
591 cmdKey >> 8,
592 (shiftKey | cmdKey) >> 8,
593 optionKey >> 8,
594 (shiftKey | optionKey) >> 8,
596 UniChar map[128][sizeof(modifier_combos) / sizeof(modifier_combos[0])][4 + 1];
597 int combo;
598 BYTE vkey_used[256];
599 int ignore_diacritics;
600 static const struct {
601 WCHAR wchar;
602 DWORD vkey;
603 } symbol_vkeys[] = {
604 { '-', VK_OEM_MINUS },
605 { '+', VK_OEM_PLUS },
606 { '_', VK_OEM_MINUS },
607 { ',', VK_OEM_COMMA },
608 { '.', VK_OEM_PERIOD },
609 { '=', VK_OEM_PLUS },
610 { '>', VK_OEM_PERIOD },
611 { '<', VK_OEM_COMMA },
612 { '|', VK_OEM_5 },
613 { '\\', VK_OEM_5 },
614 { '`', VK_OEM_3 },
615 { '[', VK_OEM_4 },
616 { '~', VK_OEM_3 },
617 { '?', VK_OEM_2 },
618 { ']', VK_OEM_6 },
619 { '/', VK_OEM_2 },
620 { ':', VK_OEM_1 },
621 { '}', VK_OEM_6 },
622 { '{', VK_OEM_4 },
623 { ';', VK_OEM_1 },
624 { '\'', VK_OEM_7 },
625 { ':', VK_OEM_PERIOD },
626 { ';', VK_OEM_COMMA },
627 { '"', VK_OEM_7 },
628 { 0x00B4, VK_OEM_4 }, /* 0x00B4 is ACUTE ACCENT */
629 { '\'', VK_OEM_2 },
630 { 0x00A7, VK_OEM_5 }, /* 0x00A7 is SECTION SIGN */
631 { '*', VK_OEM_PLUS },
632 { 0x00B4, VK_OEM_7 },
633 { '`', VK_OEM_4 },
634 { '[', VK_OEM_6 },
635 { '/', VK_OEM_5 },
636 { '^', VK_OEM_6 },
637 { '*', VK_OEM_2 },
638 { '{', VK_OEM_6 },
639 { '~', VK_OEM_1 },
640 { '?', VK_OEM_PLUS },
641 { '?', VK_OEM_4 },
642 { 0x00B4, VK_OEM_3 },
643 { '?', VK_OEM_COMMA },
644 { '~', VK_OEM_PLUS },
645 { ']', VK_OEM_4 },
646 { '\'', VK_OEM_3 },
647 { 0x00A7, VK_OEM_7 },
649 int i;
651 /* Vkeys that are suitable for assigning to arbitrary keys, organized in
652 contiguous ranges. */
653 static const struct {
654 WORD first, last;
655 } vkey_ranges[] = {
656 { 'A', 'Z' },
657 { '0', '9' },
658 { VK_OEM_1, VK_OEM_3 },
659 { VK_OEM_4, VK_ICO_CLEAR },
660 { 0xe9, 0xf5 },
661 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
662 { VK_F1, VK_F24 },
663 { 0, 0 }
665 int vkey_range;
667 if (!thread_data->keyboard_layout_uchr)
669 ERR("no keyboard layout UCHR data\n");
670 return;
673 memset(thread_data->keyc2vkey, 0, sizeof(thread_data->keyc2vkey));
674 memset(vkey_used, 0, sizeof(vkey_used));
676 for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
678 thread_data->keyc2scan[keyc] = default_map[keyc].scan;
679 if (default_map[keyc].fixed)
681 vkey = default_map[keyc].vkey;
682 thread_data->keyc2vkey[keyc] = vkey;
683 vkey_used[vkey] = 1;
684 TRACE("keyc 0x%04x -> vkey 0x%04x (fixed)\n", keyc, vkey);
688 if (thread_data->iso_keyboard)
690 /* In almost all cases, the Mac key codes indicate a physical key position
691 and this corresponds nicely to Win32 scan codes. However, the Mac key
692 codes differ in one case between ANSI and ISO keyboards. For ANSI
693 keyboards, the key to the left of the digits and above the Tab key
694 produces key code kVK_ANSI_Grave. For ISO keyboards, the key in that
695 some position produces kVK_ISO_Section. The additional key on ISO
696 keyboards, the one to the right of the left Shift key, produces
697 kVK_ANSI_Grave, which is just weird.
699 Since we want the key in that upper left corner to always produce the
700 same scan code (0x29), we need to swap the scan codes of those two
701 Mac key codes for ISO keyboards. */
702 DWORD temp = thread_data->keyc2scan[kVK_ANSI_Grave];
703 thread_data->keyc2scan[kVK_ANSI_Grave] = thread_data->keyc2scan[kVK_ISO_Section];
704 thread_data->keyc2scan[kVK_ISO_Section] = temp;
707 uchr = (const UCKeyboardLayout*)CFDataGetBytePtr(thread_data->keyboard_layout_uchr);
709 /* Using the keyboard layout, build a map of key code + modifiers -> characters. */
710 memset(map, 0, sizeof(map));
711 for (keyc = 0; keyc < sizeof(map) / sizeof(map[0]); keyc++)
713 if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
714 if (thread_data->keyc2vkey[keyc]) continue; /* assigned a fixed vkey */
716 TRACE("keyc 0x%04x: ", keyc);
718 for (combo = 0; combo < sizeof(modifier_combos) / sizeof(modifier_combos[0]); combo++)
720 UInt32 deadKeyState;
721 UniCharCount len;
722 OSStatus status;
724 deadKeyState = 0;
725 status = UCKeyTranslate(uchr, keyc, kUCKeyActionDown, modifier_combos[combo],
726 thread_data->keyboard_type, kUCKeyTranslateNoDeadKeysMask,
727 &deadKeyState, sizeof(map[keyc][combo])/sizeof(map[keyc][combo][0]) - 1,
728 &len, map[keyc][combo]);
729 if (status != noErr)
730 map[keyc][combo][0] = 0;
732 TRACE("%s%s", (combo ? ", " : ""), debugstr_w(map[keyc][combo]));
735 TRACE("\n");
738 /* First try to match key codes to the vkeys for the letters A through Z.
739 Try unmodified first, then with various modifier combinations in succession.
740 On the first pass, try to get a match lacking diacritical marks. On the
741 second pass, accept matches with diacritical marks. */
742 for (ignore_diacritics = 0; ignore_diacritics <= 1; ignore_diacritics++)
744 for (combo = 0; combo < sizeof(modifier_combos) / sizeof(modifier_combos[0]); combo++)
746 for (vkey = 'A'; vkey <= 'Z'; vkey++)
748 if (vkey_used[vkey])
749 continue;
751 for (keyc = 0; keyc < sizeof(map) / sizeof(map[0]); keyc++)
753 if (thread_data->keyc2vkey[keyc] || !map[keyc][combo][0])
754 continue;
756 if (char_matches_string(vkey, map[keyc][combo], ignore_diacritics))
758 thread_data->keyc2vkey[keyc] = vkey;
759 vkey_used[vkey] = 1;
760 TRACE("keyc 0x%04x -> vkey 0x%04x (%s match %s)\n", keyc, vkey,
761 debugstr_wn(&vkey, 1), debugstr_w(map[keyc][combo]));
762 break;
769 /* Next try to match key codes to the vkeys for the digits 0 through 9. */
770 for (combo = 0; combo < sizeof(modifier_combos) / sizeof(modifier_combos[0]); combo++)
772 for (vkey = '0'; vkey <= '9'; vkey++)
774 if (vkey_used[vkey])
775 continue;
777 for (keyc = 0; keyc < sizeof(map) / sizeof(map[0]); keyc++)
779 if (thread_data->keyc2vkey[keyc] || !map[keyc][combo][0])
780 continue;
782 if (char_matches_string(vkey, map[keyc][combo], FALSE))
784 thread_data->keyc2vkey[keyc] = vkey;
785 vkey_used[vkey] = 1;
786 TRACE("keyc 0x%04x -> vkey 0x%04x (%s match %s)\n", keyc, vkey,
787 debugstr_wn(&vkey, 1), debugstr_w(map[keyc][combo]));
788 break;
794 /* Now try to match key codes for certain common punctuation characters to
795 the most common OEM vkeys (e.g. '.' to VK_OEM_PERIOD). */
796 for (i = 0; i < sizeof(symbol_vkeys) / sizeof(symbol_vkeys[0]); i++)
798 vkey = symbol_vkeys[i].vkey;
800 if (vkey_used[vkey])
801 continue;
803 for (combo = 0; combo < sizeof(modifier_combos) / sizeof(modifier_combos[0]); combo++)
805 for (keyc = 0; keyc < sizeof(map) / sizeof(map[0]); keyc++)
807 if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
808 if (thread_data->keyc2vkey[keyc] || !map[keyc][combo][0])
809 continue;
811 if (char_matches_string(symbol_vkeys[i].wchar, map[keyc][combo], FALSE))
813 thread_data->keyc2vkey[keyc] = vkey;
814 vkey_used[vkey] = 1;
815 TRACE("keyc 0x%04x -> vkey 0x%04x (%s match %s)\n", keyc, vkey,
816 debugstr_wn(&symbol_vkeys[i].wchar, 1), debugstr_w(map[keyc][combo]));
817 break;
821 if (vkey_used[vkey])
822 break;
826 /* For those key codes still without a vkey, try to use the default vkey
827 from the default map, if it's still available. */
828 for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
830 DWORD vkey = default_map[keyc].vkey;
832 if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
833 if (thread_data->keyc2vkey[keyc]) continue; /* already assigned */
835 if (!vkey_used[vkey])
837 thread_data->keyc2vkey[keyc] = vkey;
838 vkey_used[vkey] = 1;
839 TRACE("keyc 0x%04x -> vkey 0x%04x (default map)\n", keyc, vkey);
843 /* For any unassigned key codes which would map to a letter in the default
844 map, but whose normal letter vkey wasn't available, try to find a
845 different letter. */
846 vkey = 'A';
847 for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
849 if (default_map[keyc].vkey < 'A' || 'Z' < default_map[keyc].vkey)
850 continue; /* not a letter in ANSI layout */
851 if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
852 if (thread_data->keyc2vkey[keyc]) continue; /* already assigned */
854 while (vkey <= 'Z' && vkey_used[vkey]) vkey++;
855 if (vkey <= 'Z')
857 thread_data->keyc2vkey[keyc] = vkey;
858 vkey_used[vkey] = 1;
859 TRACE("keyc 0x%04x -> vkey 0x%04x (spare letter)\n", keyc, vkey);
861 else
862 break; /* no more unused letter vkeys, so stop trying */
865 /* Same thing but with the digits. */
866 vkey = '0';
867 for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
869 if (default_map[keyc].vkey < '0' || '9' < default_map[keyc].vkey)
870 continue; /* not a digit in ANSI layout */
871 if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
872 if (thread_data->keyc2vkey[keyc]) continue; /* already assigned */
874 while (vkey <= '9' && vkey_used[vkey]) vkey++;
875 if (vkey <= '9')
877 thread_data->keyc2vkey[keyc] = vkey;
878 vkey_used[vkey] = 1;
879 TRACE("keyc 0x%04x -> vkey 0x%04x (spare digit)\n", keyc, vkey);
881 else
882 break; /* no more unused digit vkeys, so stop trying */
885 /* Last chance. Assign any available vkey. */
886 vkey_range = 0;
887 vkey = vkey_ranges[vkey_range].first;
888 for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
890 if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
891 if (thread_data->keyc2vkey[keyc]) continue; /* already assigned */
893 while (vkey && vkey_used[vkey])
895 if (vkey == vkey_ranges[vkey_range].last)
897 vkey_range++;
898 vkey = vkey_ranges[vkey_range].first;
900 else
901 vkey++;
904 if (!vkey)
906 WARN("No more vkeys available!\n");
907 break;
910 thread_data->keyc2vkey[keyc] = vkey;
911 vkey_used[vkey] = 1;
912 TRACE("keyc 0x%04x -> vkey 0x%04x (spare vkey)\n", keyc, vkey);
917 /***********************************************************************
918 * macdrv_send_keyboard_input
920 static void macdrv_send_keyboard_input(HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time)
922 INPUT input;
924 TRACE_(key)("hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags);
926 input.type = INPUT_KEYBOARD;
927 input.ki.wVk = vkey;
928 input.ki.wScan = scan;
929 input.ki.dwFlags = flags;
930 input.ki.time = time;
931 input.ki.dwExtraInfo = 0;
933 __wine_send_input(hwnd, &input);
937 /***********************************************************************
938 * get_async_key_state
940 static BOOL get_async_key_state(BYTE state[256])
942 BOOL ret;
944 SERVER_START_REQ(get_key_state)
946 req->tid = 0;
947 req->key = -1;
948 wine_server_set_reply(req, state, 256);
949 ret = !wine_server_call(req);
951 SERVER_END_REQ;
952 return ret;
956 /***********************************************************************
957 * update_modifier_state
959 static void update_modifier_state(unsigned int modifier, unsigned int modifiers, const BYTE *keystate,
960 WORD vkey, WORD alt_vkey, WORD scan, WORD alt_scan,
961 DWORD event_time, BOOL restore)
963 int key_pressed = (modifiers & modifier) != 0;
964 int vkey_pressed = (keystate[vkey] & 0x80) || (keystate[alt_vkey] & 0x80);
965 DWORD flags;
967 if (key_pressed != vkey_pressed)
969 if (key_pressed)
971 flags = (scan & 0x100) ? KEYEVENTF_EXTENDEDKEY : 0;
972 if (restore)
973 flags |= KEYEVENTF_KEYUP;
975 macdrv_send_keyboard_input(NULL, vkey, scan & 0xff, flags, event_time);
977 else
979 flags = restore ? 0 : KEYEVENTF_KEYUP;
981 if (keystate[vkey] & 0x80)
983 macdrv_send_keyboard_input(NULL, vkey, scan & 0xff,
984 flags | ((scan & 0x100) ? KEYEVENTF_EXTENDEDKEY : 0),
985 event_time);
987 if (keystate[alt_vkey] & 0x80)
989 macdrv_send_keyboard_input(NULL, alt_vkey, alt_scan & 0xff,
990 flags | ((alt_scan & 0x100) ? KEYEVENTF_EXTENDEDKEY : 0),
991 event_time);
998 /***********************************************************************
999 * macdrv_key_event
1001 * Handler for KEY_PRESS and KEY_RELEASE events.
1003 void macdrv_key_event(HWND hwnd, const macdrv_event *event)
1005 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1006 WORD vkey, scan;
1007 DWORD flags;
1009 TRACE_(key)("win %p/%p key %s keycode %hu modifiers 0x%08llx\n",
1010 hwnd, event->window, (event->type == KEY_PRESS ? "press" : "release"),
1011 event->key.keycode, event->key.modifiers);
1013 thread_data->last_modifiers = event->key.modifiers;
1015 if (event->key.keycode < sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]))
1017 vkey = thread_data->keyc2vkey[event->key.keycode];
1018 scan = thread_data->keyc2scan[event->key.keycode];
1020 else
1021 vkey = scan = 0;
1023 TRACE_(key)("keycode %hu converted to vkey 0x%X scan 0x%02x\n",
1024 event->key.keycode, vkey, scan);
1026 if (!vkey) return;
1028 flags = 0;
1029 if (event->type == KEY_RELEASE) flags |= KEYEVENTF_KEYUP;
1030 if (scan & 0x100) flags |= KEYEVENTF_EXTENDEDKEY;
1032 macdrv_send_keyboard_input(hwnd, vkey, scan & 0xff, flags, event->key.time_ms);
1036 /***********************************************************************
1037 * macdrv_keyboard_changed
1039 * Handler for KEYBOARD_CHANGED events.
1041 void macdrv_keyboard_changed(const macdrv_event *event)
1043 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1045 TRACE("new keyboard layout uchr data %p, type %u, iso %d\n", event->keyboard_changed.uchr,
1046 event->keyboard_changed.keyboard_type, event->keyboard_changed.iso_keyboard);
1048 if (thread_data->keyboard_layout_uchr)
1049 CFRelease(thread_data->keyboard_layout_uchr);
1050 thread_data->keyboard_layout_uchr = CFDataCreateCopy(NULL, event->keyboard_changed.uchr);
1051 thread_data->keyboard_type = event->keyboard_changed.keyboard_type;
1052 thread_data->iso_keyboard = event->keyboard_changed.iso_keyboard;
1053 thread_data->active_keyboard_layout = macdrv_get_hkl_from_source(event->keyboard_changed.input_source);
1054 thread_data->dead_key_state = 0;
1056 macdrv_compute_keyboard_layout(thread_data);
1058 SendMessageW(GetActiveWindow(), WM_CANCELMODE, 0, 0);
1062 /***********************************************************************
1063 * macdrv_hotkey_press
1065 * Handler for HOTKEY_PRESS events.
1067 void macdrv_hotkey_press(const macdrv_event *event)
1069 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1071 TRACE_(key)("vkey 0x%04x mod_flags 0x%04x keycode 0x%04x time %lu\n",
1072 event->hotkey_press.vkey, event->hotkey_press.mod_flags, event->hotkey_press.keycode,
1073 event->hotkey_press.time_ms);
1075 if (event->hotkey_press.keycode < sizeof(thread_data->keyc2vkey) / sizeof(thread_data->keyc2vkey[0]))
1077 WORD scan = thread_data->keyc2scan[event->hotkey_press.keycode];
1078 BYTE keystate[256];
1079 BOOL got_keystate;
1080 DWORD flags;
1082 if ((got_keystate = get_async_key_state(keystate)))
1084 update_modifier_state(MOD_ALT, event->hotkey_press.mod_flags, keystate, VK_LMENU, VK_RMENU,
1085 0x38, 0x138, event->hotkey_press.time_ms, FALSE);
1086 update_modifier_state(MOD_CONTROL, event->hotkey_press.mod_flags, keystate, VK_LCONTROL, VK_RCONTROL,
1087 0x1D, 0x11D, event->hotkey_press.time_ms, FALSE);
1088 update_modifier_state(MOD_SHIFT, event->hotkey_press.mod_flags, keystate, VK_LSHIFT, VK_RSHIFT,
1089 0x2A, 0x36, event->hotkey_press.time_ms, FALSE);
1090 update_modifier_state(MOD_WIN, event->hotkey_press.mod_flags, keystate, VK_LWIN, VK_RWIN,
1091 0x15B, 0x15C, event->hotkey_press.time_ms, FALSE);
1094 activate_on_following_focus();
1096 flags = (scan & 0x100) ? KEYEVENTF_EXTENDEDKEY : 0;
1097 macdrv_send_keyboard_input(NULL, event->hotkey_press.vkey, scan & 0xff,
1098 flags, event->key.time_ms);
1099 macdrv_send_keyboard_input(NULL, event->hotkey_press.vkey, scan & 0xff,
1100 flags | KEYEVENTF_KEYUP, event->key.time_ms);
1102 if (got_keystate)
1104 update_modifier_state(MOD_ALT, event->hotkey_press.mod_flags, keystate, VK_LMENU, VK_RMENU,
1105 0x38, 0x138, event->hotkey_press.time_ms, TRUE);
1106 update_modifier_state(MOD_CONTROL, event->hotkey_press.mod_flags, keystate, VK_LCONTROL, VK_RCONTROL,
1107 0x1D, 0x11D, event->hotkey_press.time_ms, TRUE);
1108 update_modifier_state(MOD_SHIFT, event->hotkey_press.mod_flags, keystate, VK_LSHIFT, VK_RSHIFT,
1109 0x2A, 0x36, event->hotkey_press.time_ms, TRUE);
1110 update_modifier_state(MOD_WIN, event->hotkey_press.mod_flags, keystate, VK_LWIN, VK_RWIN,
1111 0x15B, 0x15C, event->hotkey_press.time_ms, TRUE);
1117 /***********************************************************************
1118 * macdrv_process_text_input
1120 void macdrv_process_text_input(UINT vkey, UINT scan, UINT repeat, const BYTE *key_state, void *himc, int* done)
1122 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1123 unsigned int flags;
1124 int keyc;
1126 TRACE("vkey 0x%04x scan 0x%04x repeat %u himc %p\n", vkey, scan, repeat, himc);
1128 flags = thread_data->last_modifiers;
1129 if (key_state[VK_SHIFT] & 0x80)
1130 flags |= NX_SHIFTMASK;
1131 else
1132 flags &= ~(NX_SHIFTMASK | NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK);
1133 if (key_state[VK_CAPITAL] & 0x01)
1134 flags |= NX_ALPHASHIFTMASK;
1135 else
1136 flags &= ~NX_ALPHASHIFTMASK;
1137 if (key_state[VK_CONTROL] & 0x80)
1138 flags |= NX_CONTROLMASK;
1139 else
1140 flags &= ~(NX_CONTROLMASK | NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK);
1141 if (key_state[VK_MENU] & 0x80)
1142 flags |= NX_COMMANDMASK;
1143 else
1144 flags &= ~(NX_COMMANDMASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK);
1146 /* Find the Mac keycode corresponding to the scan code */
1147 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]); keyc++)
1148 if (thread_data->keyc2vkey[keyc] == vkey) break;
1150 if (keyc >= sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]))
1151 return;
1153 TRACE("flags 0x%08x keyc 0x%04x\n", flags, keyc);
1155 macdrv_send_text_input_event(((scan & 0x8000) == 0), flags, repeat, keyc, himc, done);
1159 /***********************************************************************
1160 * ActivateKeyboardLayout (MACDRV.@)
1162 HKL CDECL macdrv_ActivateKeyboardLayout(HKL hkl, UINT flags)
1164 HKL oldHkl = 0;
1165 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
1166 struct layout *layout;
1168 TRACE("hkl %p flags %04x\n", hkl, flags);
1170 if (flags) FIXME("flags %x not supported\n",flags);
1172 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
1174 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1175 FIXME("HKL_NEXT and HKL_PREV not supported\n");
1176 return 0;
1179 EnterCriticalSection(&layout_list_section);
1180 update_layout_list();
1182 LIST_FOR_EACH_ENTRY(layout, &layout_list, struct layout, entry)
1184 if (layout->hkl == hkl)
1186 if (macdrv_select_input_source(layout->input_source))
1188 oldHkl = thread_data->active_keyboard_layout;
1189 thread_data->active_keyboard_layout = hkl;
1191 break;
1194 LeaveCriticalSection(&layout_list_section);
1196 return oldHkl;
1200 /***********************************************************************
1201 * Beep (MACDRV.@)
1203 void CDECL macdrv_Beep(void)
1205 macdrv_beep();
1209 /***********************************************************************
1210 * GetKeyNameText (MACDRV.@)
1212 INT CDECL macdrv_GetKeyNameText(LONG lparam, LPWSTR buffer, INT size)
1214 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
1215 int scan, keyc;
1217 scan = (lparam >> 16) & 0x1FF;
1218 for (keyc = 0; keyc < sizeof(thread_data->keyc2scan)/sizeof(thread_data->keyc2scan[0]); keyc++)
1220 if (thread_data->keyc2scan[keyc] == scan)
1222 static const WCHAR dead[] = {' ','d','e','a','d',0};
1223 const UCKeyboardLayout *uchr;
1224 UInt32 deadKeyState = 0;
1225 UniCharCount len;
1226 OSStatus status;
1227 DWORD vkey;
1228 int i;
1230 uchr = (const UCKeyboardLayout*)CFDataGetBytePtr(thread_data->keyboard_layout_uchr);
1231 status = UCKeyTranslate(uchr, keyc, kUCKeyActionDisplay, 0, thread_data->keyboard_type,
1232 0, &deadKeyState, size - 1, &len, (UniChar*)buffer);
1233 if (status != noErr)
1234 len = 0;
1235 if (len && isgraphW(buffer[0]))
1236 buffer[len] = 0;
1238 vkey = thread_data->keyc2vkey[keyc];
1239 if (lparam & (1 << 25))
1241 /* Caller doesn't care about distinctions between left and
1242 right keys. */
1243 switch (vkey)
1245 case VK_LSHIFT:
1246 case VK_RSHIFT:
1247 vkey = VK_SHIFT; break;
1248 case VK_LCONTROL:
1249 case VK_RCONTROL:
1250 vkey = VK_CONTROL; break;
1251 case VK_LMENU:
1252 case VK_RMENU:
1253 vkey = VK_MENU; break;
1257 if (scan & 0x100) vkey |= 0x100;
1259 for (i = 0; i < sizeof(vkey_names) / sizeof(vkey_names[0]); i++)
1261 if (vkey_names[i].vkey == vkey)
1263 len = MultiByteToWideChar(CP_UTF8, 0, vkey_names[i].name, -1, buffer, size);
1264 if (len) len--;
1265 break;
1269 if (!len)
1271 static const WCHAR format[] = {'K','e','y',' ','0','x','%','0','2','x',0};
1272 snprintfW(buffer, size, format, vkey);
1273 len = strlenW(buffer);
1276 if (!len)
1277 break;
1279 if (status == noErr && deadKeyState)
1281 lstrcpynW(buffer + len, dead, size - len);
1282 len = strlenW(buffer);
1285 TRACE("lparam 0x%08x -> %s\n", lparam, debugstr_w(buffer));
1286 return len;
1290 WARN("found no name for lparam 0x%08x\n", lparam);
1291 return 0;
1295 /***********************************************************************
1296 * GetKeyboardLayout (MACDRV.@)
1298 HKL CDECL macdrv_GetKeyboardLayout(DWORD thread_id)
1300 if (thread_id && thread_id != GetCurrentThreadId())
1301 FIXME("couldn't return keyboard layout for thread %04x\n", thread_id);
1303 return macdrv_init_thread_data()->active_keyboard_layout;
1307 /***********************************************************************
1308 * GetKeyboardLayoutList (MACDRV.@)
1310 UINT CDECL macdrv_GetKeyboardLayoutList(INT size, HKL *list)
1312 int count = 0;
1313 struct layout *layout;
1315 TRACE("%d, %p\n", size, list);
1317 EnterCriticalSection(&layout_list_section);
1319 update_layout_list();
1321 LIST_FOR_EACH_ENTRY(layout, &layout_list, struct layout, entry)
1323 if (!layout->enabled) continue;
1324 if (list)
1326 if (count >= size) break;
1327 list[count] = layout->hkl;
1328 TRACE("\t%d: %p\n", count, list[count]);
1330 count++;
1332 LeaveCriticalSection(&layout_list_section);
1334 TRACE("returning %d\n", count);
1335 return count;
1338 /***********************************************************************
1339 * GetKeyboardLayoutName (MACDRV.@)
1341 BOOL CDECL macdrv_GetKeyboardLayoutName(LPWSTR name)
1343 static const WCHAR formatW[] = {'%','0','8','x',0};
1344 DWORD layout;
1346 layout = HandleToUlong(macdrv_GetKeyboardLayout(0));
1347 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1348 sprintfW(name, formatW, layout);
1349 TRACE("returning %s\n", debugstr_w(name));
1350 return TRUE;
1354 /***********************************************************************
1355 * MapVirtualKeyEx (MACDRV.@)
1357 UINT CDECL macdrv_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
1359 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
1360 UINT ret = 0;
1361 int keyc;
1363 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
1365 switch (wMapType)
1367 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
1368 case MAPVK_VK_TO_VSC_EX:
1369 switch (wCode)
1371 case VK_SHIFT: wCode = VK_LSHIFT; break;
1372 case VK_CONTROL: wCode = VK_LCONTROL; break;
1373 case VK_MENU: wCode = VK_LMENU; break;
1376 /* vkey -> keycode -> scan */
1377 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]); keyc++)
1379 if (thread_data->keyc2vkey[keyc] == wCode)
1381 ret = thread_data->keyc2scan[keyc] & 0xFF;
1382 break;
1385 break;
1387 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
1388 case MAPVK_VSC_TO_VK_EX:
1389 /* scan -> keycode -> vkey */
1390 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]); keyc++)
1391 if ((thread_data->keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1393 ret = thread_data->keyc2vkey[keyc];
1394 /* Only stop if it's not a numpad vkey; otherwise keep
1395 looking for a potential better vkey. */
1396 if (ret && (ret < VK_NUMPAD0 || VK_DIVIDE < ret))
1397 break;
1400 if (wMapType == MAPVK_VSC_TO_VK)
1401 switch (ret)
1403 case VK_LSHIFT:
1404 case VK_RSHIFT:
1405 ret = VK_SHIFT; break;
1406 case VK_LCONTROL:
1407 case VK_RCONTROL:
1408 ret = VK_CONTROL; break;
1409 case VK_LMENU:
1410 case VK_RMENU:
1411 ret = VK_MENU; break;
1414 break;
1416 case MAPVK_VK_TO_CHAR: /* vkey-code to character */
1418 /* vkey -> keycode -> (UCKeyTranslate) wide char */
1419 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1420 const UCKeyboardLayout *uchr;
1421 UniChar s[10];
1422 OSStatus status;
1423 UInt32 deadKeyState;
1424 UniCharCount len;
1425 BOOL deadKey = FALSE;
1427 if ((VK_PRIOR <= wCode && wCode <= VK_HELP) ||
1428 (VK_F1 <= wCode && wCode <= VK_F24))
1429 break;
1431 if (!thread_data || !thread_data->keyboard_layout_uchr)
1433 WARN("No keyboard layout uchr data\n");
1434 break;
1437 uchr = (const UCKeyboardLayout*)CFDataGetBytePtr(thread_data->keyboard_layout_uchr);
1439 /* Find the Mac keycode corresponding to the vkey */
1440 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]); keyc++)
1441 if (thread_data->keyc2vkey[keyc] == wCode) break;
1443 if (keyc >= sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]))
1445 WARN("Unknown virtual key %X\n", wCode);
1446 break;
1449 TRACE("Found keycode %u\n", keyc);
1451 deadKeyState = 0;
1452 status = UCKeyTranslate(uchr, keyc, kUCKeyActionDown, 0,
1453 thread_data->keyboard_type, 0, &deadKeyState,
1454 sizeof(s)/sizeof(s[0]), &len, s);
1455 if (status == noErr && !len && deadKeyState)
1457 deadKey = TRUE;
1458 deadKeyState = 0;
1459 status = UCKeyTranslate(uchr, keyc, kUCKeyActionDown, 0,
1460 thread_data->keyboard_type, kUCKeyTranslateNoDeadKeysMask,
1461 &deadKeyState, sizeof(s)/sizeof(s[0]), &len, s);
1464 if (status == noErr && len)
1465 ret = toupperW(s[0]) | (deadKey ? 0x80000000 : 0);
1467 break;
1469 default: /* reserved */
1470 FIXME("Unknown wMapType %d\n", wMapType);
1471 break;
1474 TRACE("returning 0x%04x\n", ret);
1475 return ret;
1479 /***********************************************************************
1480 * RegisterHotKey (MACDRV.@)
1482 BOOL CDECL macdrv_RegisterHotKey(HWND hwnd, UINT mod_flags, UINT vkey)
1484 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
1485 unsigned int keyc, modifiers = 0;
1486 int ret;
1488 TRACE_(key)("hwnd %p mod_flags 0x%04x vkey 0x%04x\n", hwnd, mod_flags, vkey);
1490 /* Find the Mac keycode corresponding to the vkey */
1491 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey) / sizeof(thread_data->keyc2vkey[0]); keyc++)
1492 if (thread_data->keyc2vkey[keyc] == vkey) break;
1494 if (keyc >= sizeof(thread_data->keyc2vkey) / sizeof(thread_data->keyc2vkey[0]))
1496 WARN_(key)("ignoring unknown virtual key 0x%04x\n", vkey);
1497 return TRUE;
1500 if (mod_flags & MOD_ALT) modifiers |= cmdKey;
1501 if (mod_flags & MOD_CONTROL) modifiers |= controlKey;
1502 if (mod_flags & MOD_SHIFT) modifiers |= shiftKey;
1503 if (mod_flags & MOD_WIN)
1505 WARN_(key)("MOD_WIN not supported; ignoring\n");
1506 return TRUE;
1509 ret = macdrv_register_hot_key(thread_data->queue, vkey, mod_flags, keyc, modifiers);
1510 TRACE_(key)("keyc 0x%04x modifiers 0x%08x -> %d\n", keyc, modifiers, ret);
1512 if (ret == MACDRV_HOTKEY_ALREADY_REGISTERED)
1513 SetLastError(ERROR_HOTKEY_ALREADY_REGISTERED);
1514 else if (ret != MACDRV_HOTKEY_SUCCESS)
1515 SetLastError(ERROR_GEN_FAILURE);
1517 return ret == MACDRV_HOTKEY_SUCCESS;
1521 /***********************************************************************
1522 * ToUnicodeEx (MACDRV.@)
1524 * The ToUnicode function translates the specified virtual-key code and keyboard
1525 * state to the corresponding Windows character or characters.
1527 * If the specified key is a dead key, the return value is negative. Otherwise,
1528 * it is one of the following values:
1529 * Value Meaning
1530 * -1 The specified virtual key is a dead-key. If possible, the
1531 * non-combining form of the dead character is written to bufW.
1532 * 0 The specified virtual key has no translation for the current
1533 * state of the keyboard.
1534 * 1 One Windows character was copied to the buffer.
1535 * 2 or more Multiple characters were copied to the buffer. This usually
1536 * happens when a dead-key character (accent or diacritic) stored
1537 * in the keyboard layout cannot be composed with the specified
1538 * virtual key to form a single character.
1541 INT CDECL macdrv_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
1542 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
1544 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
1545 INT ret = 0;
1546 int keyc;
1547 BOOL is_menu = (flags & 0x1);
1548 int status;
1549 const UCKeyboardLayout *uchr;
1550 UInt16 keyAction;
1551 UInt32 modifierKeyState;
1552 OptionBits options;
1553 UInt32 deadKeyState, savedDeadKeyState;
1554 UniCharCount len;
1555 BOOL dead = FALSE;
1557 TRACE_(key)("virtKey 0x%04x scanCode 0x%04x lpKeyState %p bufW %p bufW_size %d flags 0x%08x hkl %p\n",
1558 virtKey, scanCode, lpKeyState, bufW, bufW_size, flags, hkl);
1560 if (!virtKey)
1561 goto done;
1563 /* UCKeyTranslate, below, terminates a dead-key sequence if passed a
1564 modifier key press. We want it to effectively ignore modifier key
1565 presses. I think that one isn't supposed to call it at all for modifier
1566 events (e.g. NSFlagsChanged or kEventRawKeyModifiersChanged), since they
1567 are different event types than key up/down events. */
1568 switch (virtKey)
1570 case VK_SHIFT:
1571 case VK_CONTROL:
1572 case VK_MENU:
1573 case VK_CAPITAL:
1574 case VK_LSHIFT:
1575 case VK_RSHIFT:
1576 case VK_LCONTROL:
1577 case VK_RCONTROL:
1578 case VK_LMENU:
1579 case VK_RMENU:
1580 goto done;
1583 /* There are a number of key combinations for which Windows does not
1584 produce characters, but Mac keyboard layouts may. Eat them. Do this
1585 here to avoid the expense of UCKeyTranslate() but also because these
1586 keys shouldn't terminate dead key sequences. */
1587 if ((VK_PRIOR <= virtKey && virtKey <= VK_HELP) || (VK_F1 <= virtKey && virtKey <= VK_F24))
1588 goto done;
1590 /* Shift + <non-digit keypad keys>. */
1591 if ((lpKeyState[VK_SHIFT] & 0x80) && VK_MULTIPLY <= virtKey && virtKey <= VK_DIVIDE)
1592 goto done;
1594 if (lpKeyState[VK_CONTROL] & 0x80)
1596 /* Control-Tab, with or without other modifiers. */
1597 if (virtKey == VK_TAB)
1598 goto done;
1600 /* Control-Shift-<key>, Control-Alt-<key>, and Control-Alt-Shift-<key>
1601 for these keys. */
1602 if ((lpKeyState[VK_SHIFT] & 0x80) || (lpKeyState[VK_MENU] & 0x80))
1604 switch (virtKey)
1606 case VK_CANCEL:
1607 case VK_BACK:
1608 case VK_ESCAPE:
1609 case VK_SPACE:
1610 case VK_RETURN:
1611 goto done;
1616 if (thread_data->keyboard_layout_uchr)
1617 uchr = (const UCKeyboardLayout*)CFDataGetBytePtr(thread_data->keyboard_layout_uchr);
1618 else
1619 uchr = NULL;
1621 keyAction = (scanCode & 0x8000) ? kUCKeyActionUp : kUCKeyActionDown;
1623 modifierKeyState = 0;
1624 if (lpKeyState[VK_SHIFT] & 0x80)
1625 modifierKeyState |= (shiftKey >> 8);
1626 if (lpKeyState[VK_CAPITAL] & 0x01)
1627 modifierKeyState |= (alphaLock >> 8);
1628 if (lpKeyState[VK_CONTROL] & 0x80)
1629 modifierKeyState |= (controlKey >> 8);
1630 if (lpKeyState[VK_MENU] & 0x80)
1631 modifierKeyState |= (cmdKey >> 8);
1632 if (thread_data->last_modifiers & (NX_ALTERNATEMASK | NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK))
1633 modifierKeyState |= (optionKey >> 8);
1635 /* Find the Mac keycode corresponding to the vkey */
1636 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]); keyc++)
1637 if (thread_data->keyc2vkey[keyc] == virtKey) break;
1639 if (keyc >= sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]))
1641 WARN_(key)("Unknown virtual key 0x%04x\n", virtKey);
1642 goto done;
1645 TRACE_(key)("Key code 0x%04x %s, faked modifiers = 0x%04x\n", keyc,
1646 (keyAction == kUCKeyActionDown) ? "pressed" : "released", (unsigned)modifierKeyState);
1648 if (is_menu)
1650 if (keyAction == kUCKeyActionUp)
1651 goto done;
1653 options = kUCKeyTranslateNoDeadKeysMask;
1654 deadKeyState = 0;
1656 else
1658 options = 0;
1659 deadKeyState = thread_data->dead_key_state;
1661 savedDeadKeyState = deadKeyState;
1662 status = UCKeyTranslate(uchr, keyc, keyAction, modifierKeyState,
1663 thread_data->keyboard_type, options, &deadKeyState, bufW_size,
1664 &len, bufW);
1665 if (status != noErr)
1667 ERR_(key)("Couldn't translate keycode 0x%04x, status %d\n", keyc, status);
1668 goto done;
1670 if (!is_menu)
1672 if (keyAction != kUCKeyActionUp && len > 0 && deadKeyState == thread_data->dead_key_state)
1673 thread_data->dead_key_state = 0;
1674 else
1675 thread_data->dead_key_state = deadKeyState;
1677 if (keyAction == kUCKeyActionUp)
1678 goto done;
1681 if (len == 0 && deadKeyState)
1683 /* Repeat the translation, but disabling dead-key generation to
1684 learn which dead key it was. */
1685 status = UCKeyTranslate(uchr, keyc, keyAction, modifierKeyState,
1686 thread_data->keyboard_type, kUCKeyTranslateNoDeadKeysMask,
1687 &savedDeadKeyState, bufW_size, &len, bufW);
1688 if (status != noErr)
1690 ERR_(key)("Couldn't translate keycode 0x%04x, status %d\n", keyc, status);
1691 goto done;
1694 dead = TRUE;
1697 if (len > 0)
1698 len = strip_apple_private_chars(bufW, len);
1700 if (dead && len > 0) ret = -1;
1701 else ret = len;
1703 /* Control-Return produces line feed instead of carriage return. */
1704 if (ret > 0 && (lpKeyState[VK_CONTROL] & 0x80) && virtKey == VK_RETURN)
1706 int i;
1707 for (i = 0; i < len; i++)
1708 if (bufW[i] == '\r')
1709 bufW[i] = '\n';
1712 done:
1713 /* Null-terminate the buffer, if there's room. MSDN clearly states that the
1714 caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
1715 if (1 <= ret && ret < bufW_size)
1716 bufW[ret] = 0;
1718 TRACE_(key)("returning %d / %s\n", ret, debugstr_wn(bufW, abs(ret)));
1719 return ret;
1723 /***********************************************************************
1724 * UnregisterHotKey (MACDRV.@)
1726 void CDECL macdrv_UnregisterHotKey(HWND hwnd, UINT modifiers, UINT vkey)
1728 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1730 TRACE_(key)("hwnd %p modifiers 0x%04x vkey 0x%04x\n", hwnd, modifiers, vkey);
1732 if (thread_data)
1733 macdrv_unregister_hot_key(thread_data->queue, vkey, modifiers);
1737 /***********************************************************************
1738 * VkKeyScanEx (MACDRV.@)
1740 * Note: Windows ignores HKL parameter and uses current active layout instead
1742 SHORT CDECL macdrv_VkKeyScanEx(WCHAR wChar, HKL hkl)
1744 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
1745 SHORT ret = -1;
1746 int state;
1747 const UCKeyboardLayout *uchr;
1749 TRACE("%04x, %p\n", wChar, hkl);
1751 uchr = (const UCKeyboardLayout*)CFDataGetBytePtr(thread_data->keyboard_layout_uchr);
1752 if (!uchr)
1754 TRACE("no keyboard layout UCHR data; returning -1\n");
1755 return -1;
1758 for (state = 0; state < 8; state++)
1760 UInt32 modifierKeyState = 0;
1761 int keyc;
1763 if (state & 1)
1764 modifierKeyState |= (shiftKey >> 8);
1765 if ((state & 6) == 6)
1766 modifierKeyState |= (optionKey >> 8);
1767 else
1769 if (state & 2)
1770 modifierKeyState |= (controlKey >> 8);
1771 if (state & 4)
1772 modifierKeyState |= (cmdKey >> 8);
1775 for (keyc = 0; keyc < sizeof(thread_data->keyc2vkey) / sizeof(thread_data->keyc2vkey[0]); keyc++)
1777 UInt32 deadKeyState = 0;
1778 UniChar uchar;
1779 UniCharCount len;
1780 OSStatus status;
1782 if (!thread_data->keyc2vkey[keyc]) continue;
1784 status = UCKeyTranslate(uchr, keyc, kUCKeyActionDown, modifierKeyState,
1785 thread_data->keyboard_type, 0, &deadKeyState,
1786 1, &len, &uchar);
1787 if (status == noErr && len == 1 && uchar == wChar)
1789 WORD vkey = thread_data->keyc2vkey[keyc];
1791 ret = vkey | (state << 8);
1792 if ((VK_NUMPAD0 <= vkey && vkey <= VK_DIVIDE) ||
1793 keyc == kVK_ANSI_KeypadClear || keyc == kVK_ANSI_KeypadEnter ||
1794 keyc == kVK_ANSI_KeypadEquals)
1796 /* Keep searching for a non-numpad match, which is preferred. */
1798 else
1799 goto done;
1804 done:
1805 TRACE(" -> 0x%04x\n", ret);
1806 return ret;