comparison src/video/cocoa/SDL_cocoakeyboard.m @ 2303:d87417504c75

First pass implementation of new SDL scancode concept, as discussed with Christian Walther. Currently only implemented on Mac OS X for sanity checking purposes.
author Sam Lantinga <slouken@libsdl.org>
date Tue, 05 Feb 2008 07:19:23 +0000
parents f629d566ec6b
children 50f58ce12497
comparison
equal deleted inserted replaced
2302:7ae1c419b626 2303:d87417504c75
69 */ 69 */
70 static void 70 static void
71 DoUnsidedModifiers(int keyboard, unsigned short scancode, 71 DoUnsidedModifiers(int keyboard, unsigned short scancode,
72 unsigned int oldMods, unsigned int newMods) 72 unsigned int oldMods, unsigned int newMods)
73 { 73 {
74 const int mapping[] = { SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA }; 74 const int mapping[] = {
75 SDL_SCANCODE_CAPSLOCK,
76 SDL_SCANCODE_LSHIFT,
77 SDL_SCANCODE_LCTRL,
78 SDL_SCANCODE_LALT,
79 SDL_SCANCODE_LGUI
80 };
75 unsigned int i, bit; 81 unsigned int i, bit;
76 82
77 /* Iterate through the bits, testing each against the current modifiers */ 83 /* Iterate through the bits, testing each against the current modifiers */
78 for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) { 84 for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
79 unsigned int oldMask, newMask; 85 unsigned int oldMask, newMask;
82 newMask = newMods & bit; 88 newMask = newMods & bit;
83 89
84 if (oldMask && oldMask != newMask) { /* modifier up event */ 90 if (oldMask && oldMask != newMask) { /* modifier up event */
85 /* If this was Caps Lock, we need some additional voodoo to make SDL happy */ 91 /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
86 if (bit == NSAlphaShiftKeyMask) { 92 if (bit == NSAlphaShiftKeyMask) {
87 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, (Uint8)scancode, mapping[i]); 93 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, mapping[i]);
88 } 94 }
89 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, mapping[i]); 95 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, mapping[i]);
90 } else if (newMask && oldMask != newMask) { /* modifier down event */ 96 } else if (newMask && oldMask != newMask) { /* modifier down event */
91 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, (Uint8)scancode, mapping[i]); 97 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, mapping[i]);
92 /* If this was Caps Lock, we need some additional voodoo to make SDL happy */ 98 /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
93 if (bit == NSAlphaShiftKeyMask) { 99 if (bit == NSAlphaShiftKeyMask) {
94 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, mapping[i]); 100 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, mapping[i]);
95 } 101 }
96 } 102 }
97 } 103 }
98 } 104 }
99 105
100 /* This is a helper function for HandleModifierSide. This 106 /* This is a helper function for HandleModifierSide. This
101 * function reverts back to behavior before the distinction between 107 * function reverts back to behavior before the distinction between
102 * sides was made. 108 * sides was made.
103 */ 109 */
104 static void 110 static void
105 HandleNonDeviceModifier(int keyboard, unsigned short scancode, 111 HandleNonDeviceModifier(int keyboard,
106 unsigned int device_independent_mask, 112 unsigned int device_independent_mask,
107 unsigned int oldMods, 113 unsigned int oldMods,
108 unsigned int newMods, 114 unsigned int newMods,
109 SDLKey key_sym) 115 SDL_scancode scancode)
110 { 116 {
111 unsigned int oldMask, newMask; 117 unsigned int oldMask, newMask;
112 118
113 /* Isolate just the bits we care about in the depedent bits so we can 119 /* Isolate just the bits we care about in the depedent bits so we can
114 * figure out what changed 120 * figure out what changed
115 */ 121 */
116 oldMask = oldMods & device_independent_mask; 122 oldMask = oldMods & device_independent_mask;
117 newMask = newMods & device_independent_mask; 123 newMask = newMods & device_independent_mask;
118 124
119 if (oldMask && oldMask != newMask) { 125 if (oldMask && oldMask != newMask) {
120 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, key_sym); 126 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, scancode);
121 } else if (newMask && oldMask != newMask) { 127 } else if (newMask && oldMask != newMask) {
122 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, (Uint8)scancode, key_sym); 128 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, scancode);
123 } 129 }
124 } 130 }
125 131
126 /* This is a helper function for HandleModifierSide. 132 /* This is a helper function for HandleModifierSide.
127 * This function sets the actual SDL_PrivateKeyboard event. 133 * This function sets the actual SDL_PrivateKeyboard event.
128 */ 134 */
129 static void 135 static void
130 HandleModifierOneSide(int keyboard, unsigned short scancode, 136 HandleModifierOneSide(int keyboard,
131 unsigned int oldMods, unsigned int newMods, 137 unsigned int oldMods, unsigned int newMods,
132 SDLKey key_sym, 138 SDL_scancode scancode,
133 unsigned int sided_device_dependent_mask) 139 unsigned int sided_device_dependent_mask)
134 { 140 {
135 unsigned int old_dep_mask, new_dep_mask; 141 unsigned int old_dep_mask, new_dep_mask;
136 142
137 /* Isolate just the bits we care about in the depedent bits so we can 143 /* Isolate just the bits we care about in the depedent bits so we can
143 /* We now know that this side bit flipped. But we don't know if 149 /* We now know that this side bit flipped. But we don't know if
144 * it went pressed to released or released to pressed, so we must 150 * it went pressed to released or released to pressed, so we must
145 * find out which it is. 151 * find out which it is.
146 */ 152 */
147 if (new_dep_mask && old_dep_mask != new_dep_mask) { 153 if (new_dep_mask && old_dep_mask != new_dep_mask) {
148 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, (Uint8)scancode, key_sym); 154 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, scancode);
149 } else { 155 } else {
150 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, key_sym); 156 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, scancode);
151 } 157 }
152 } 158 }
153 159
154 /* This is a helper function for DoSidedModifiers. 160 /* This is a helper function for DoSidedModifiers.
155 * This function will figure out if the modifier key is the left or right side, 161 * This function will figure out if the modifier key is the left or right side,
156 * e.g. left-shift vs right-shift. 162 * e.g. left-shift vs right-shift.
157 */ 163 */
158 static void 164 static void
159 HandleModifierSide(int keyboard, unsigned short scancode, 165 HandleModifierSide(int keyboard,
160 int device_independent_mask, 166 int device_independent_mask,
161 unsigned int oldMods, unsigned int newMods, 167 unsigned int oldMods, unsigned int newMods,
162 SDLKey left_key_sym, 168 SDL_scancode left_scancode,
163 SDLKey right_key_sym, 169 SDL_scancode right_scancode,
164 unsigned int left_device_dependent_mask, 170 unsigned int left_device_dependent_mask,
165 unsigned int right_device_dependent_mask) 171 unsigned int right_device_dependent_mask)
166 { 172 {
167 unsigned int device_dependent_mask = (left_device_dependent_mask | 173 unsigned int device_dependent_mask = (left_device_dependent_mask |
168 right_device_dependent_mask); 174 right_device_dependent_mask);
172 * no device dependent flags set, we'll assume that we can't detect this 178 * no device dependent flags set, we'll assume that we can't detect this
173 * keyboard and revert to the unsided behavior. 179 * keyboard and revert to the unsided behavior.
174 */ 180 */
175 if ((device_dependent_mask & newMods) == 0) { 181 if ((device_dependent_mask & newMods) == 0) {
176 /* Revert to the old behavior */ 182 /* Revert to the old behavior */
177 HandleNonDeviceModifier(keyboard, scancode, device_independent_mask, oldMods, newMods, left_key_sym); 183 HandleNonDeviceModifier(keyboard, device_independent_mask, oldMods, newMods, left_scancode);
178 return; 184 return;
179 } 185 }
180 186
181 /* XOR the previous state against the new state to see if there's a change */ 187 /* XOR the previous state against the new state to see if there's a change */
182 diff_mod = (device_dependent_mask & oldMods) ^ 188 diff_mod = (device_dependent_mask & oldMods) ^
185 /* A change in state was found. Isolate the left and right bits 191 /* A change in state was found. Isolate the left and right bits
186 * to handle them separately just in case the values can simulataneously 192 * to handle them separately just in case the values can simulataneously
187 * change or if the bits don't both exist. 193 * change or if the bits don't both exist.
188 */ 194 */
189 if (left_device_dependent_mask & diff_mod) { 195 if (left_device_dependent_mask & diff_mod) {
190 HandleModifierOneSide(keyboard, scancode, oldMods, newMods, left_key_sym, left_device_dependent_mask); 196 HandleModifierOneSide(keyboard, oldMods, newMods, left_scancode, left_device_dependent_mask);
191 } 197 }
192 if (right_device_dependent_mask & diff_mod) { 198 if (right_device_dependent_mask & diff_mod) {
193 HandleModifierOneSide(keyboard, scancode, oldMods, newMods, right_key_sym, right_device_dependent_mask); 199 HandleModifierOneSide(keyboard, oldMods, newMods, right_scancode, right_device_dependent_mask);
194 } 200 }
195 } 201 }
196 } 202 }
197 203
198 /* This is a helper function for DoSidedModifiers. 204 /* This is a helper function for DoSidedModifiers.
199 * This function will release a key press in the case that 205 * This function will release a key press in the case that
200 * it is clear that the modifier has been released (i.e. one side 206 * it is clear that the modifier has been released (i.e. one side
201 * can't still be down). 207 * can't still be down).
202 */ 208 */
203 static void 209 static void
204 ReleaseModifierSide(int keyboard, unsigned short scancode, 210 ReleaseModifierSide(int keyboard,
205 unsigned int device_independent_mask, 211 unsigned int device_independent_mask,
206 unsigned int oldMods, unsigned int newMods, 212 unsigned int oldMods, unsigned int newMods,
207 SDLKey left_key_sym, 213 SDL_scancode left_scancode,
208 SDLKey right_key_sym, 214 SDL_scancode right_scancode,
209 unsigned int left_device_dependent_mask, 215 unsigned int left_device_dependent_mask,
210 unsigned int right_device_dependent_mask) 216 unsigned int right_device_dependent_mask)
211 { 217 {
212 unsigned int device_dependent_mask = (left_device_dependent_mask | 218 unsigned int device_dependent_mask = (left_device_dependent_mask |
213 right_device_dependent_mask); 219 right_device_dependent_mask);
218 */ 224 */
219 if ((device_dependent_mask & oldMods) == 0) { 225 if ((device_dependent_mask & oldMods) == 0) {
220 /* In this case, we can't detect the keyboard, so use the left side 226 /* In this case, we can't detect the keyboard, so use the left side
221 * to represent both, and release it. 227 * to represent both, and release it.
222 */ 228 */
223 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, left_key_sym); 229 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, left_scancode);
224 return; 230 return;
225 } 231 }
226 232
227 /* 233 /*
228 * This could have been done in an if-else case because at this point, 234 * This could have been done in an if-else case because at this point,
229 * we know that all keys have been released when calling this function. 235 * we know that all keys have been released when calling this function.
230 * But I'm being paranoid so I want to handle each separately, 236 * But I'm being paranoid so I want to handle each separately,
231 * so I hope this doesn't cause other problems. 237 * so I hope this doesn't cause other problems.
232 */ 238 */
233 if ( left_device_dependent_mask & oldMods ) { 239 if ( left_device_dependent_mask & oldMods ) {
234 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, left_key_sym); 240 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, left_scancode);
235 } 241 }
236 if ( right_device_dependent_mask & oldMods ) { 242 if ( right_device_dependent_mask & oldMods ) {
237 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, right_key_sym); 243 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, right_scancode);
238 } 244 }
239 } 245 }
240 246
241 /* This is a helper function for DoSidedModifiers. 247 /* This is a helper function for DoSidedModifiers.
242 * This function handles the CapsLock case. 248 * This function handles the CapsLock case.
249 255
250 oldMask = oldMods & NSAlphaShiftKeyMask; 256 oldMask = oldMods & NSAlphaShiftKeyMask;
251 newMask = newMods & NSAlphaShiftKeyMask; 257 newMask = newMods & NSAlphaShiftKeyMask;
252 258
253 if (oldMask != newMask) { 259 if (oldMask != newMask) {
254 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, (Uint8)scancode, SDLK_CAPSLOCK); 260 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, SDL_SCANCODE_CAPSLOCK);
255 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, SDLK_CAPSLOCK); 261 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, SDL_SCANCODE_CAPSLOCK);
256 } 262 }
257 263
258 oldMask = oldMods & NSNumericPadKeyMask; 264 oldMask = oldMods & NSNumericPadKeyMask;
259 newMask = newMods & NSNumericPadKeyMask; 265 newMask = newMods & NSNumericPadKeyMask;
260 266
261 if (oldMask != newMask) { 267 if (oldMask != newMask) {
262 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, (Uint8)scancode, SDLK_KP_NUMLOCKCLEAR); 268 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, SDL_SCANCODE_NUMLOCKCLEAR);
263 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, SDLK_KP_NUMLOCKCLEAR); 269 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, SDL_SCANCODE_NUMLOCKCLEAR);
264 } 270 }
265 } 271 }
266 272
267 /* This function will handle the modifier keys and also determine the 273 /* This function will handle the modifier keys and also determine the
268 * correct side of the key. 274 * correct side of the key.
270 static void 276 static void
271 DoSidedModifiers(int keyboard, unsigned short scancode, 277 DoSidedModifiers(int keyboard, unsigned short scancode,
272 unsigned int oldMods, unsigned int newMods) 278 unsigned int oldMods, unsigned int newMods)
273 { 279 {
274 /* Set up arrays for the key syms for the left and right side. */ 280 /* Set up arrays for the key syms for the left and right side. */
275 const SDLKey left_mapping[] = { SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA }; 281 const SDL_scancode left_mapping[] = {
276 const SDLKey right_mapping[] = { SDLK_RSHIFT, SDLK_RCTRL, SDLK_RALT, SDLK_RMETA }; 282 SDL_SCANCODE_LSHIFT,
283 SDL_SCANCODE_LCTRL,
284 SDL_SCANCODE_LALT,
285 SDL_SCANCODE_LGUI
286 };
287 const SDL_scancode right_mapping[] = {
288 SDL_SCANCODE_RSHIFT,
289 SDL_SCANCODE_RCTRL,
290 SDL_SCANCODE_RALT,
291 SDL_SCANCODE_RGUI
292 };
277 /* Set up arrays for the device dependent masks with indices that 293 /* Set up arrays for the device dependent masks with indices that
278 * correspond to the _mapping arrays 294 * correspond to the _mapping arrays
279 */ 295 */
280 const unsigned int left_device_mapping[] = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK }; 296 const unsigned int left_device_mapping[] = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK };
281 const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK }; 297 const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK };
294 310
295 /* If the bit is set, we must always examine it because the left 311 /* If the bit is set, we must always examine it because the left
296 * and right side keys may alternate or both may be pressed. 312 * and right side keys may alternate or both may be pressed.
297 */ 313 */
298 if (newMask) { 314 if (newMask) {
299 HandleModifierSide(keyboard, scancode, bit, oldMods, newMods, 315 HandleModifierSide(keyboard, bit, oldMods, newMods,
300 left_mapping[i], right_mapping[i], 316 left_mapping[i], right_mapping[i],
301 left_device_mapping[i], right_device_mapping[i]); 317 left_device_mapping[i], right_device_mapping[i]);
302 } 318 }
303 /* If the state changed from pressed to unpressed, we must examine 319 /* If the state changed from pressed to unpressed, we must examine
304 * the device dependent bits to release the correct keys. 320 * the device dependent bits to release the correct keys.
305 */ 321 */
306 else if (oldMask && oldMask != newMask) { 322 else if (oldMask && oldMask != newMask) {
307 ReleaseModifierSide(keyboard, scancode, bit, oldMods, newMods, 323 ReleaseModifierSide(keyboard, bit, oldMods, newMods,
308 left_mapping[i], right_mapping[i], 324 left_mapping[i], right_mapping[i],
309 left_device_mapping[i], right_device_mapping[i]); 325 left_device_mapping[i], right_device_mapping[i]);
310 } 326 }
311 } 327 }
312 } 328 }
330 DoUnsidedModifiers(data->keyboard, scancode, data->modifierFlags, modifierFlags); 346 DoUnsidedModifiers(data->keyboard, scancode, data->modifierFlags, modifierFlags);
331 } 347 }
332 data->modifierFlags = modifierFlags; 348 data->modifierFlags = modifierFlags;
333 } 349 }
334 350
351 static void
352 UpdateKeymap(SDL_VideoData *data)
353 {
354 KeyboardLayoutRef key_layout;
355 const void *chr_data;
356 int i;
357 SDL_scancode scancode;
358 SDLKey keymap[SDL_NUM_SCANCODES];
359
360 /* See if the keymap needs to be updated */
361 KLGetCurrentKeyboardLayout(&key_layout);
362 if (key_layout == data->key_layout) {
363 return;
364 }
365 data->key_layout = key_layout;
366
367 SDL_GetDefaultKeymap(keymap);
368
369 /* Try Unicode data first (preferred as of Mac OS X 10.5) */
370 KLGetKeyboardLayoutProperty(key_layout, kKLuchrData, &chr_data);
371 if (chr_data) {
372 UInt32 keyboard_type = LMGetKbdType();
373 OSStatus err;
374
375 for (i = 0; i < SDL_arraysize(scancode_table); i++) {
376 UniChar s[8];
377 UniCharCount len;
378 UInt32 dead_key_state;
379
380 /* Make sure this scancode is a valid character scancode */
381 scancode = scancode_table[i];
382 if (scancode == SDL_SCANCODE_UNKNOWN ||
383 (keymap[scancode] & SDLK_SCANCODE_MASK)) {
384 continue;
385 }
386
387 dead_key_state = 0;
388 err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
389 0, keyboard_type,
390 kUCKeyTranslateNoDeadKeysMask,
391 &dead_key_state, 8, &len, s);
392 if (err != noErr)
393 continue;
394
395 if (len > 0 && s[0] != 0x10) {
396 keymap[scancode] = s[0];
397 }
398 }
399 SDL_SetKeymap(data->keyboard, 0, keymap, SDL_NUM_SCANCODES);
400 return;
401 }
402
403 /* Fall back to older style key map data */
404 KLGetKeyboardLayoutProperty(key_layout, kKLKCHRData, &chr_data);
405 if (chr_data) {
406 for (i = 0; i < 128; i++) {
407 UInt32 c, state = 0;
408
409 /* Make sure this scancode is a valid character scancode */
410 scancode = scancode_table[i];
411 if (scancode == SDL_SCANCODE_UNKNOWN ||
412 (keymap[scancode] & SDLK_SCANCODE_MASK)) {
413 continue;
414 }
415
416 c = KeyTranslate (chr_data, i, &state);
417 if (state) {
418 /* Dead key, process key up */
419 c = KeyTranslate (chr_data, i | 128, &state);
420 }
421
422 if (c != 0 && c != 0x10 && c < 256) {
423 /* MacRoman to Unicode table, taken from X.org sources */
424 static const unsigned short macroman_table[128] = {
425 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
426 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
427 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
428 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
429 0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
430 0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
431 0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
432 0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
433 0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
434 0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
435 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
436 0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
437 0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
438 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
439 0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
440 0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7,
441 };
442
443 if (c >= 128) {
444 c = macroman_table[c - 128];
445 }
446 keymap[scancode] = c;
447 }
448 }
449 SDL_SetKeymap(data->keyboard, 0, keymap, SDL_NUM_SCANCODES);
450 return;
451 }
452 }
453
335 void 454 void
336 Cocoa_InitKeyboard(_THIS) 455 Cocoa_InitKeyboard(_THIS)
337 { 456 {
338 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 457 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
339 SDL_Keyboard keyboard; 458 SDL_Keyboard keyboard;
343 data->fieldEdit = [[SDLTranslatorResponder alloc] initWithFrame:NSMakeRect(0.0, 0.0, 0.0, 0.0)]; 462 data->fieldEdit = [[SDLTranslatorResponder alloc] initWithFrame:NSMakeRect(0.0, 0.0, 0.0, 0.0)];
344 [pool release]; 463 [pool release];
345 464
346 SDL_zero(keyboard); 465 SDL_zero(keyboard);
347 data->keyboard = SDL_AddKeyboard(&keyboard, -1); 466 data->keyboard = SDL_AddKeyboard(&keyboard, -1);
467 UpdateKeymap(data);
348 468
349 /* Set our own names for the platform-dependent but layout-independent keys */ 469 /* Set our own names for the platform-dependent but layout-independent keys */
350 SDL_SetKeyName(SDLK_KP_NUMLOCKCLEAR, "clear"); 470 /* This key is NumLock on the MacBook keyboard. :) */
351 SDL_SetKeyName(SDLK_LALT, "left option"); 471 /*SDL_SetScancodeName(SDL_SCANCODE_NUMLOCKCLEAR, "Clear");*/
352 SDL_SetKeyName(SDLK_LMETA, "left command"); 472 SDL_SetScancodeName(SDL_SCANCODE_LALT, "Left Option");
353 SDL_SetKeyName(SDLK_RALT, "right option"); 473 SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Command");
354 SDL_SetKeyName(SDLK_RMETA, "right command"); 474 SDL_SetScancodeName(SDL_SCANCODE_RALT, "Right Option");
475 SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Command");
355 } 476 }
356 477
357 void 478 void
358 Cocoa_HandleKeyEvent(_THIS, NSEvent *event) 479 Cocoa_HandleKeyEvent(_THIS, NSEvent *event)
359 { 480 {
360 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 481 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
361 unsigned short scancode = [event keyCode]; 482 unsigned short scancode = [event keyCode];
362 SDLKey physicalKey; 483 SDL_scancode code;
363 const char *text; 484 const char *text;
364 485
365 if ((scancode == 10 || scancode == 50) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) { 486 if ((scancode == 10 || scancode == 50) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) {
366 /* see comments in SDL_cocoakeys.h */ 487 /* see comments in SDL_cocoakeys.h */
367 scancode = 60 - scancode; 488 scancode = 60 - scancode;
368 } 489 }
369 if (scancode < SDL_arraysize(macToSDLKey)) { 490 if (scancode < SDL_arraysize(scancode_table)) {
370 physicalKey = macToSDLKey[scancode]; 491 code = scancode_table[scancode];
371 } 492 }
372 else { 493 else {
373 /* Hmm, does this ever happen? If so, need to extend the keymap... */ 494 /* Hmm, does this ever happen? If so, need to extend the keymap... */
374 physicalKey = SDLK_UNKNOWN; 495 code = SDL_SCANCODE_UNKNOWN;
375 } 496 }
376 497
377 switch ([event type]) { 498 switch ([event type]) {
378 case NSKeyDown: 499 case NSKeyDown:
379 if (![event isARepeat]) { 500 if (![event isARepeat]) {
380 SDL_SendKeyboardKey(data->keyboard, SDL_PRESSED, (Uint8)scancode, physicalKey); 501 /* See if we need to rebuild the keyboard layout */
502 UpdateKeymap(data);
503
504 SDL_SendKeyboardKey(data->keyboard, SDL_PRESSED, code);
381 #if 1 505 #if 1
382 if (physicalKey == SDLK_UNKNOWN) { 506 if (code == SDL_SCANCODE_UNKNOWN) {
383 fprintf(stderr, "The key you just pressed is not recognized by SDL. To help get this fixed, report this to the SDL mailing list <sdl@libsdl.org> or to Christian Walther <cwalther@gmx.ch>. Mac virtual key code is %d.\n", scancode); 507 fprintf(stderr, "The key you just pressed is not recognized by SDL. To help get this fixed, report this to the SDL mailing list <sdl@libsdl.org> or to Christian Walther <cwalther@gmx.ch>. Mac virtual key code is %d.\n", scancode);
384 } 508 }
385 #endif 509 #endif
386 } 510 }
387 if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) { 511 if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
393 [data->fieldEdit setString:@""]; 517 [data->fieldEdit setString:@""];
394 } 518 }
395 } 519 }
396 break; 520 break;
397 case NSKeyUp: 521 case NSKeyUp:
398 SDL_SendKeyboardKey(data->keyboard, SDL_RELEASED, (Uint8)scancode, physicalKey); 522 SDL_SendKeyboardKey(data->keyboard, SDL_RELEASED, code);
399 break; 523 break;
400 case NSFlagsChanged: 524 case NSFlagsChanged:
401 /* FIXME CW 2007-08-14: check if this whole mess that takes up half of this file is really necessary */ 525 /* FIXME CW 2007-08-14: check if this whole mess that takes up half of this file is really necessary */
402 HandleModifiers(_this, scancode, [event modifierFlags]); 526 HandleModifiers(_this, scancode, [event modifierFlags]);
403 break; 527 break;
404 default: /* just to avoid compiler warnings */ 528 default: /* just to avoid compiler warnings */
405 break; 529 break;
406 } 530 }
407 } 531 }
408 532
409 SDLKey
410 Cocoa_GetLayoutKey(_THIS, SDLKey physicalKey)
411 {
412 switch (physicalKey) {
413 /* Many of these keys would generate a character in the translation by keyboard layout, but an inappropriate one, so we catch them before. */
414 case SDLK_UNKNOWN:
415 case SDLK_RETURN:
416 case SDLK_ESCAPE:
417 case SDLK_BACKSPACE:
418 case SDLK_TAB:
419 case SDLK_SPACE:
420 case SDLK_CAPSLOCK:
421 case SDLK_F1:
422 case SDLK_F2:
423 case SDLK_F3:
424 case SDLK_F4:
425 case SDLK_F5:
426 case SDLK_F6:
427 case SDLK_F7:
428 case SDLK_F8:
429 case SDLK_F9:
430 case SDLK_F10:
431 case SDLK_F11:
432 case SDLK_F12:
433 case SDLK_PRINTSCREEN:
434 case SDLK_SCROLLLOCK:
435 case SDLK_PAUSE:
436 case SDLK_INSERT:
437 case SDLK_HOME:
438 case SDLK_PAGEUP:
439 case SDLK_DELETE:
440 case SDLK_END:
441 case SDLK_PAGEDOWN:
442 case SDLK_RIGHT:
443 case SDLK_LEFT:
444 case SDLK_DOWN:
445 case SDLK_UP:
446 case SDLK_KP_NUMLOCKCLEAR:
447 case SDLK_KP_ENTER:
448 case SDLK_APPLICATION:
449 case SDLK_POWER:
450 case SDLK_F13:
451 case SDLK_F14:
452 case SDLK_F15:
453 case SDLK_F16:
454 case SDLK_LCTRL:
455 case SDLK_LSHIFT:
456 case SDLK_LALT:
457 case SDLK_LMETA:
458 case SDLK_RCTRL:
459 case SDLK_RSHIFT:
460 case SDLK_RALT:
461 case SDLK_RMETA:
462 return physicalKey;
463
464 /* For the rest, we try the translation first. */
465 default: {
466 UInt16 vkey = 0;
467 KeyboardLayoutRef layout;
468 KeyboardLayoutKind kind;
469 UInt32 keyboardType = LMGetKbdType();
470
471 /* Look up pkey to get a Mac virtual key code - linear search isn't terribly efficient, this might have to be optimized. */
472 while (vkey < 128 && physicalKey != macToSDLKey[vkey]) vkey++;
473 if (vkey == 128) return physicalKey;
474 if ((vkey == 10 || vkey == 50) && KBGetLayoutType(keyboardType) == kKeyboardISO) vkey = 60 - vkey; /* see comments in SDL_cocoakeys.h */
475
476 if (KLGetCurrentKeyboardLayout(&layout) != noErr) return physicalKey;
477 if (KLGetKeyboardLayoutProperty(layout, kKLKind, (const void **)&kind) != noErr) return physicalKey;
478 if (kind == kKLKCHRuchrKind || kind == kKLuchrKind) {
479 UniChar utf16String[4];
480 UInt32 deadKeyState = 0;
481 UniCharCount actualStringLength;
482 const UCKeyboardLayout *uchrData;
483
484 if (KLGetKeyboardLayoutProperty(layout, kKLuchrData, (const void **)&uchrData) != noErr) return physicalKey;
485 if (UCKeyTranslate(uchrData, vkey, kUCKeyActionDisplay, 0, keyboardType, 0, &deadKeyState, 4, &actualStringLength, utf16String) != noErr) return physicalKey;
486 /* kUCKeyActionDisplay (instead of kUCKeyActionDown) seems to take care of dead keys, so no need to check for that case and simulate a second key press */
487
488 if (actualStringLength == 0) return physicalKey;
489
490 /* Decode the first character from UTF-16. I'm not sure if this is appropriate for keyboard layouts that generate more than 1 character, or if we would have to use SDL_KEY_LAYOUT_SPECIAL_BIT in that case. */
491 if (utf16String[0] < 0xD800 || utf16String[0] > 0xDFFF) {
492 return utf16String[0];
493 }
494 else if (utf16String[0] > 0xDBFF || utf16String[1] < 0xDC00 || utf16String[1] > 0xDFFF) {
495 /* invalid UTF-16 */
496 return physicalKey;
497 }
498 else {
499 return (((utf16String[0] & 0x3FF) << 10) | (utf16String[1] & 0x3FF)) + 0x10000;
500 }
501 }
502 else { /* kind == kKLKCHRKind */
503 const void *kchrData;
504 UInt32 state = 0;
505 UInt8 charCode;
506 SInt32 scriptCode;
507 TextEncoding keyboardEncoding;
508 CFStringRef conversionString;
509 UniChar codepoint;
510
511 if (KLGetKeyboardLayoutProperty(layout, kKLKCHRData, &kchrData) != noErr) return physicalKey;
512 charCode = KeyTranslate(kchrData, vkey, &state) & 0xFF; /* Actually returns a UInt32 containing two character codes (and two 'reserved' bytes), but we're only interested in the second (or only) one */
513 if (charCode == 0) {
514 /* It's a dead key, so simulate a second key press */
515 charCode = KeyTranslate(kchrData, vkey, &state) & 0xFF;
516 /* Still zero? Give up. */
517 if (charCode == 0) return physicalKey;
518 }
519 if (KLGetKeyboardLayoutProperty(layout, kKLGroupIdentifier, (const void **)&scriptCode) != noErr) return physicalKey; /* That the group identifier is actually a script code is not documented, but confirmed here: <http://lists.apple.com/archives/carbon-dev/2005/Jan/msg00533.html> */
520 if (UpgradeScriptInfoToTextEncoding(scriptCode, kTextLanguageDontCare, kTextRegionDontCare, NULL, &keyboardEncoding) != noErr) return physicalKey;
521
522 conversionString = CFStringCreateWithBytes(kCFAllocatorDefault, &charCode, 1, keyboardEncoding, FALSE);
523 codepoint = CFStringGetCharacterAtIndex(conversionString, 0);
524 CFRelease(conversionString);
525 return codepoint;
526 }
527 }
528 }
529 }
530
531 void 533 void
532 Cocoa_QuitKeyboard(_THIS) 534 Cocoa_QuitKeyboard(_THIS)
533 { 535 {
534 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 536 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
535 NSAutoreleasePool *pool; 537 NSAutoreleasePool *pool;