1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#if SDL_VIDEO_DRIVER_COCOA 24 25#include "SDL_cocoavideo.h" 26 27#include "../../events/SDL_events_c.h" 28#include "../../events/SDL_keyboard_c.h" 29#include "../../events/scancodes_darwin.h" 30 31#include <Carbon/Carbon.h> 32#include <IOKit/hid/IOHIDLib.h> 33 34/*#define DEBUG_IME NSLog */ 35#define DEBUG_IME(...) 36 37@interface SDLTranslatorResponder : NSView <NSTextInputClient> { 38 NSString *_markedText; 39 NSRange _markedRange; 40 NSRange _selectedRange; 41 SDL_Rect _inputRect; 42} 43- (void)doCommandBySelector:(SEL)myselector; 44- (void)setInputRect:(SDL_Rect *)rect; 45@end 46 47@implementation SDLTranslatorResponder 48 49- (void)setInputRect:(SDL_Rect *)rect 50{ 51 _inputRect = *rect; 52} 53 54- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange 55{ 56 /* TODO: Make use of replacementRange? */ 57 58 const char *str; 59 60 DEBUG_IME(@"insertText: %@", aString); 61 62 /* Could be NSString or NSAttributedString, so we have 63 * to test and convert it before return as SDL event */ 64 if ([aString isKindOfClass: [NSAttributedString class]]) { 65 str = [[aString string] UTF8String]; 66 } else { 67 str = [aString UTF8String]; 68 } 69 70 SDL_SendKeyboardText(str); 71} 72 73- (void)doCommandBySelector:(SEL)myselector 74{ 75 /* No need to do anything since we are not using Cocoa 76 selectors to handle special keys, instead we use SDL 77 key events to do the same job. 78 */ 79} 80 81- (BOOL)hasMarkedText 82{ 83 return _markedText != nil; 84} 85 86- (NSRange)markedRange 87{ 88 return _markedRange; 89} 90 91- (NSRange)selectedRange 92{ 93 return _selectedRange; 94} 95 96- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange; 97{ 98 if ([aString isKindOfClass:[NSAttributedString class]]) { 99 aString = [aString string]; 100 } 101 102 if ([aString length] == 0) { 103 [self unmarkText]; 104 return; 105 } 106 107 if (_markedText != aString) { 108 [_markedText release]; 109 _markedText = [aString retain]; 110 } 111 112 _selectedRange = selectedRange; 113 _markedRange = NSMakeRange(0, [aString length]); 114 115 SDL_SendEditingText([aString UTF8String], 116 (int) selectedRange.location, (int) selectedRange.length); 117 118 DEBUG_IME(@"setMarkedText: %@, (%d, %d)", _markedText, 119 selRange.location, selRange.length); 120} 121 122- (void)unmarkText 123{ 124 [_markedText release]; 125 _markedText = nil; 126 127 SDL_SendEditingText("", 0, 0); 128} 129 130- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange; 131{ 132 NSWindow *window = [self window]; 133 NSRect contentRect = [window contentRectForFrameRect:[window frame]]; 134 float windowHeight = contentRect.size.height; 135 NSRect rect = NSMakeRect(_inputRect.x, windowHeight - _inputRect.y - _inputRect.h, 136 _inputRect.w, _inputRect.h); 137 138 if (actualRange) { 139 *actualRange = aRange; 140 } 141 142 DEBUG_IME(@"firstRectForCharacterRange: (%d, %d): windowHeight = %g, rect = %@", 143 aRange.location, aRange.length, windowHeight, 144 NSStringFromRect(rect)); 145 146 if ([window respondsToSelector:@selector(convertRectToScreen:)]) { 147 rect = [window convertRectToScreen:rect]; 148 } else { 149 rect.origin = [window convertBaseToScreen:rect.origin]; 150 } 151 152 return rect; 153} 154 155- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange; 156{ 157 DEBUG_IME(@"attributedSubstringFromRange: (%d, %d)", aRange.location, aRange.length); 158 return nil; 159} 160 161- (NSInteger)conversationIdentifier 162{ 163 return (NSInteger) self; 164} 165 166/* This method returns the index for character that is 167 * nearest to thePoint. thPoint is in screen coordinate system. 168 */ 169- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint 170{ 171 DEBUG_IME(@"characterIndexForPoint: (%g, %g)", thePoint.x, thePoint.y); 172 return 0; 173} 174 175/* This method is the key to attribute extension. 176 * We could add new attributes through this method. 177 * NSInputServer examines the return value of this 178 * method & constructs appropriate attributed string. 179 */ 180- (NSArray *)validAttributesForMarkedText 181{ 182 return [NSArray array]; 183} 184 185@end 186 187/*------------------------------------------------------------------------------ 188Set up a HID callback to properly detect Caps Lock up/down events. 189Derived from: 190http://stackoverflow.com/questions/7190852/using-iohidmanager-to-get-modifier-key-events 191*/ 192 193static IOHIDManagerRef s_hidManager = NULL; 194 195static void 196HIDCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) 197{ 198 if (context != s_hidManager) { 199 /* An old callback, ignore it (related to bug 2157 below) */ 200 return; 201 } 202 203 IOHIDElementRef elem = IOHIDValueGetElement(value); 204 if (IOHIDElementGetUsagePage(elem) != kHIDPage_KeyboardOrKeypad 205 || IOHIDElementGetUsage(elem) != kHIDUsage_KeyboardCapsLock) { 206 return; 207 } 208 CFIndex pressed = IOHIDValueGetIntegerValue(value); 209 SDL_SendKeyboardKey(pressed ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_CAPSLOCK); 210} 211 212static CFDictionaryRef 213CreateHIDDeviceMatchingDictionary(UInt32 usagePage, UInt32 usage) 214{ 215 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 216 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 217 if (dict) { 218 CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usagePage); 219 if (number) { 220 CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), number); 221 CFRelease(number); 222 number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); 223 if (number) { 224 CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), number); 225 CFRelease(number); 226 return dict; 227 } 228 } 229 CFRelease(dict); 230 } 231 return NULL; 232} 233 234static void 235QuitHIDCallback() 236{ 237 if (!s_hidManager) { 238 return; 239 } 240 241#if 0 /* Releasing here causes a crash on Mac OS X 10.10 and earlier, 242 * so just leak it for now. See bug 2157 for details. 243 */ 244 IOHIDManagerUnscheduleFromRunLoop(s_hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 245 IOHIDManagerRegisterInputValueCallback(s_hidManager, NULL, NULL); 246 IOHIDManagerClose(s_hidManager, 0); 247 248 CFRelease(s_hidManager); 249#endif 250 s_hidManager = NULL; 251} 252 253static void 254InitHIDCallback() 255{ 256 s_hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); 257 if (!s_hidManager) { 258 return; 259 } 260 CFDictionaryRef keyboard = NULL, keypad = NULL; 261 CFArrayRef matches = NULL; 262 keyboard = CreateHIDDeviceMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard); 263 if (!keyboard) { 264 goto fail; 265 } 266 keypad = CreateHIDDeviceMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Keypad); 267 if (!keypad) { 268 goto fail; 269 } 270 CFDictionaryRef matchesList[] = { keyboard, keypad }; 271 matches = CFArrayCreate(kCFAllocatorDefault, (const void **)matchesList, 2, NULL); 272 if (!matches) { 273 goto fail; 274 } 275 IOHIDManagerSetDeviceMatchingMultiple(s_hidManager, matches); 276 IOHIDManagerRegisterInputValueCallback(s_hidManager, HIDCallback, s_hidManager); 277 IOHIDManagerScheduleWithRunLoop(s_hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode); 278 if (IOHIDManagerOpen(s_hidManager, kIOHIDOptionsTypeNone) == kIOReturnSuccess) { 279 goto cleanup; 280 } 281 282fail: 283 QuitHIDCallback(); 284 285cleanup: 286 if (matches) { 287 CFRelease(matches); 288 } 289 if (keypad) { 290 CFRelease(keypad); 291 } 292 if (keyboard) { 293 CFRelease(keyboard); 294 } 295} 296 297/* This is a helper function for HandleModifierSide. This 298 * function reverts back to behavior before the distinction between 299 * sides was made. 300 */ 301static void 302HandleNonDeviceModifier(unsigned int device_independent_mask, 303 unsigned int oldMods, 304 unsigned int newMods, 305 SDL_Scancode scancode) 306{ 307 unsigned int oldMask, newMask; 308 309 /* Isolate just the bits we care about in the depedent bits so we can 310 * figure out what changed 311 */ 312 oldMask = oldMods & device_independent_mask; 313 newMask = newMods & device_independent_mask; 314 315 if (oldMask && oldMask != newMask) { 316 SDL_SendKeyboardKey(SDL_RELEASED, scancode); 317 } else if (newMask && oldMask != newMask) { 318 SDL_SendKeyboardKey(SDL_PRESSED, scancode); 319 } 320} 321 322/* This is a helper function for HandleModifierSide. 323 * This function sets the actual SDL_PrivateKeyboard event. 324 */ 325static void 326HandleModifierOneSide(unsigned int oldMods, unsigned int newMods, 327 SDL_Scancode scancode, 328 unsigned int sided_device_dependent_mask) 329{ 330 unsigned int old_dep_mask, new_dep_mask; 331 332 /* Isolate just the bits we care about in the depedent bits so we can 333 * figure out what changed 334 */ 335 old_dep_mask = oldMods & sided_device_dependent_mask; 336 new_dep_mask = newMods & sided_device_dependent_mask; 337 338 /* We now know that this side bit flipped. But we don't know if 339 * it went pressed to released or released to pressed, so we must 340 * find out which it is. 341 */ 342 if (new_dep_mask && old_dep_mask != new_dep_mask) { 343 SDL_SendKeyboardKey(SDL_PRESSED, scancode); 344 } else { 345 SDL_SendKeyboardKey(SDL_RELEASED, scancode); 346 } 347} 348 349/* This is a helper function for DoSidedModifiers. 350 * This function will figure out if the modifier key is the left or right side, 351 * e.g. left-shift vs right-shift. 352 */ 353static void 354HandleModifierSide(int device_independent_mask, 355 unsigned int oldMods, unsigned int newMods, 356 SDL_Scancode left_scancode, 357 SDL_Scancode right_scancode, 358 unsigned int left_device_dependent_mask, 359 unsigned int right_device_dependent_mask) 360{ 361 unsigned int device_dependent_mask = (left_device_dependent_mask | 362 right_device_dependent_mask); 363 unsigned int diff_mod; 364 365 /* On the basis that the device independent mask is set, but there are 366 * no device dependent flags set, we'll assume that we can't detect this 367 * keyboard and revert to the unsided behavior. 368 */ 369 if ((device_dependent_mask & newMods) == 0) { 370 /* Revert to the old behavior */ 371 HandleNonDeviceModifier(device_independent_mask, oldMods, newMods, left_scancode); 372 return; 373 } 374 375 /* XOR the previous state against the new state to see if there's a change */ 376 diff_mod = (device_dependent_mask & oldMods) ^ 377 (device_dependent_mask & newMods); 378 if (diff_mod) { 379 /* A change in state was found. Isolate the left and right bits 380 * to handle them separately just in case the values can simulataneously 381 * change or if the bits don't both exist. 382 */ 383 if (left_device_dependent_mask & diff_mod) { 384 HandleModifierOneSide(oldMods, newMods, left_scancode, left_device_dependent_mask); 385 } 386 if (right_device_dependent_mask & diff_mod) { 387 HandleModifierOneSide(oldMods, newMods, right_scancode, right_device_dependent_mask); 388 } 389 } 390} 391 392/* This is a helper function for DoSidedModifiers. 393 * This function will release a key press in the case that 394 * it is clear that the modifier has been released (i.e. one side 395 * can't still be down). 396 */ 397static void 398ReleaseModifierSide(unsigned int device_independent_mask, 399 unsigned int oldMods, unsigned int newMods, 400 SDL_Scancode left_scancode, 401 SDL_Scancode right_scancode, 402 unsigned int left_device_dependent_mask, 403 unsigned int right_device_dependent_mask) 404{ 405 unsigned int device_dependent_mask = (left_device_dependent_mask | 406 right_device_dependent_mask); 407 408 /* On the basis that the device independent mask is set, but there are 409 * no device dependent flags set, we'll assume that we can't detect this 410 * keyboard and revert to the unsided behavior. 411 */ 412 if ((device_dependent_mask & oldMods) == 0) { 413 /* In this case, we can't detect the keyboard, so use the left side 414 * to represent both, and release it. 415 */ 416 SDL_SendKeyboardKey(SDL_RELEASED, left_scancode); 417 return; 418 } 419 420 /* 421 * This could have been done in an if-else case because at this point, 422 * we know that all keys have been released when calling this function. 423 * But I'm being paranoid so I want to handle each separately, 424 * so I hope this doesn't cause other problems. 425 */ 426 if ( left_device_dependent_mask & oldMods ) { 427 SDL_SendKeyboardKey(SDL_RELEASED, left_scancode); 428 } 429 if ( right_device_dependent_mask & oldMods ) { 430 SDL_SendKeyboardKey(SDL_RELEASED, right_scancode); 431 } 432} 433 434/* This function will handle the modifier keys and also determine the 435 * correct side of the key. 436 */ 437static void 438DoSidedModifiers(unsigned short scancode, 439 unsigned int oldMods, unsigned int newMods) 440{ 441 /* Set up arrays for the key syms for the left and right side. */ 442 const SDL_Scancode left_mapping[] = { 443 SDL_SCANCODE_LSHIFT, 444 SDL_SCANCODE_LCTRL, 445 SDL_SCANCODE_LALT, 446 SDL_SCANCODE_LGUI 447 }; 448 const SDL_Scancode right_mapping[] = { 449 SDL_SCANCODE_RSHIFT, 450 SDL_SCANCODE_RCTRL, 451 SDL_SCANCODE_RALT, 452 SDL_SCANCODE_RGUI 453 }; 454 /* Set up arrays for the device dependent masks with indices that 455 * correspond to the _mapping arrays 456 */ 457 const unsigned int left_device_mapping[] = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK }; 458 const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK }; 459 460 unsigned int i, bit; 461 462 /* Iterate through the bits, testing each against the old modifiers */ 463 for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) { 464 unsigned int oldMask, newMask; 465 466 oldMask = oldMods & bit; 467 newMask = newMods & bit; 468 469 /* If the bit is set, we must always examine it because the left 470 * and right side keys may alternate or both may be pressed. 471 */ 472 if (newMask) { 473 HandleModifierSide(bit, oldMods, newMods, 474 left_mapping[i], right_mapping[i], 475 left_device_mapping[i], right_device_mapping[i]); 476 } 477 /* If the state changed from pressed to unpressed, we must examine 478 * the device dependent bits to release the correct keys. 479 */ 480 else if (oldMask && oldMask != newMask) { 481 ReleaseModifierSide(bit, oldMods, newMods, 482 left_mapping[i], right_mapping[i], 483 left_device_mapping[i], right_device_mapping[i]); 484 } 485 } 486} 487 488static void 489HandleModifiers(_THIS, unsigned short scancode, unsigned int modifierFlags) 490{ 491 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 492 493 if (modifierFlags == data->modifierFlags) { 494 return; 495 } 496 497 DoSidedModifiers(scancode, data->modifierFlags, modifierFlags); 498 data->modifierFlags = modifierFlags; 499} 500 501static void 502UpdateKeymap(SDL_VideoData *data, SDL_bool send_event) 503{ 504 TISInputSourceRef key_layout; 505 const void *chr_data; 506 int i; 507 SDL_Scancode scancode; 508 SDL_Keycode keymap[SDL_NUM_SCANCODES]; 509 510 /* See if the keymap needs to be updated */ 511 key_layout = TISCopyCurrentKeyboardLayoutInputSource(); 512 if (key_layout == data->key_layout) { 513 return; 514 } 515 data->key_layout = key_layout; 516 517 SDL_GetDefaultKeymap(keymap); 518 519 /* Try Unicode data first */ 520 CFDataRef uchrDataRef = TISGetInputSourceProperty(key_layout, kTISPropertyUnicodeKeyLayoutData); 521 if (uchrDataRef) { 522 chr_data = CFDataGetBytePtr(uchrDataRef); 523 } else { 524 goto cleanup; 525 } 526 527 if (chr_data) { 528 UInt32 keyboard_type = LMGetKbdType(); 529 OSStatus err; 530 531 for (i = 0; i < SDL_arraysize(darwin_scancode_table); i++) { 532 UniChar s[8]; 533 UniCharCount len; 534 UInt32 dead_key_state; 535 536 /* Make sure this scancode is a valid character scancode */ 537 scancode = darwin_scancode_table[i]; 538 if (scancode == SDL_SCANCODE_UNKNOWN || 539 (keymap[scancode] & SDLK_SCANCODE_MASK)) { 540 continue; 541 } 542 543 dead_key_state = 0; 544 err = UCKeyTranslate ((UCKeyboardLayout *) chr_data, 545 i, kUCKeyActionDown, 546 0, keyboard_type, 547 kUCKeyTranslateNoDeadKeysMask, 548 &dead_key_state, 8, &len, s); 549 if (err != noErr) { 550 continue; 551 } 552 553 if (len > 0 && s[0] != 0x10) { 554 keymap[scancode] = s[0]; 555 } 556 } 557 SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES); 558 if (send_event) { 559 SDL_SendKeymapChangedEvent(); 560 } 561 return; 562 } 563 564cleanup: 565 CFRelease(key_layout); 566} 567 568void 569Cocoa_InitKeyboard(_THIS) 570{ 571 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 572 573 UpdateKeymap(data, SDL_FALSE); 574 575 /* Set our own names for the platform-dependent but layout-independent keys */ 576 /* This key is NumLock on the MacBook keyboard. :) */ 577 /*SDL_SetScancodeName(SDL_SCANCODE_NUMLOCKCLEAR, "Clear");*/ 578 SDL_SetScancodeName(SDL_SCANCODE_LALT, "Left Option"); 579 SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Command"); 580 SDL_SetScancodeName(SDL_SCANCODE_RALT, "Right Option"); 581 SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Command"); 582 583 data->modifierFlags = [NSEvent modifierFlags]; 584 SDL_ToggleModState(KMOD_CAPS, (data->modifierFlags & NSAlphaShiftKeyMask) != 0); 585 586 InitHIDCallback(); 587} 588 589void 590Cocoa_StartTextInput(_THIS) 591{ @autoreleasepool 592{ 593 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 594 SDL_Window *window = SDL_GetKeyboardFocus(); 595 NSWindow *nswindow = nil; 596 if (window) { 597 nswindow = ((SDL_WindowData*)window->driverdata)->nswindow; 598 } 599 600 NSView *parentView = [nswindow contentView]; 601 602 /* We only keep one field editor per process, since only the front most 603 * window can receive text input events, so it make no sense to keep more 604 * than one copy. When we switched to another window and requesting for 605 * text input, simply remove the field editor from its superview then add 606 * it to the front most window's content view */ 607 if (!data->fieldEdit) { 608 data->fieldEdit = 609 [[SDLTranslatorResponder alloc] initWithFrame: NSMakeRect(0.0, 0.0, 0.0, 0.0)]; 610 } 611 612 if (![[data->fieldEdit superview] isEqual:parentView]) { 613 /* DEBUG_IME(@"add fieldEdit to window contentView"); */ 614 [data->fieldEdit removeFromSuperview]; 615 [parentView addSubview: data->fieldEdit]; 616 [nswindow makeFirstResponder: data->fieldEdit]; 617 } 618}} 619 620void 621Cocoa_StopTextInput(_THIS) 622{ @autoreleasepool 623{ 624 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 625 626 if (data && data->fieldEdit) { 627 [data->fieldEdit removeFromSuperview]; 628 [data->fieldEdit release]; 629 data->fieldEdit = nil; 630 } 631}} 632 633void 634Cocoa_SetTextInputRect(_THIS, SDL_Rect *rect) 635{ 636 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 637 638 if (!rect) { 639 SDL_InvalidParamError("rect"); 640 return; 641 } 642 643 [data->fieldEdit setInputRect:rect]; 644} 645 646void 647Cocoa_HandleKeyEvent(_THIS, NSEvent *event) 648{ 649 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 650 if (!data) { 651 return; /* can happen when returning from fullscreen Space on shutdown */ 652 } 653 654 unsigned short scancode = [event keyCode]; 655 SDL_Scancode code; 656#if 0 657 const char *text; 658#endif 659 660 if ((scancode == 10 || scancode == 50) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) { 661 /* see comments in SDL_cocoakeys.h */ 662 scancode = 60 - scancode; 663 } 664 665 if (scancode < SDL_arraysize(darwin_scancode_table)) { 666 code = darwin_scancode_table[scancode]; 667 } else { 668 /* Hmm, does this ever happen? If so, need to extend the keymap... */ 669 code = SDL_SCANCODE_UNKNOWN; 670 } 671 672 switch ([event type]) { 673 case NSKeyDown: 674 if (![event isARepeat]) { 675 /* See if we need to rebuild the keyboard layout */ 676 UpdateKeymap(data, SDL_TRUE); 677 } 678 679 SDL_SendKeyboardKey(SDL_PRESSED, code); 680#if 1 681 if (code == SDL_SCANCODE_UNKNOWN) { 682 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); 683 } 684#endif 685 if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) { 686 /* FIXME CW 2007-08-16: only send those events to the field editor for which we actually want text events, not e.g. esc or function keys. Arrow keys in particular seem to produce crashes sometimes. */ 687 [data->fieldEdit interpretKeyEvents:[NSArray arrayWithObject:event]]; 688#if 0 689 text = [[event characters] UTF8String]; 690 if(text && *text) { 691 SDL_SendKeyboardText(text); 692 [data->fieldEdit setString:@""]; 693 } 694#endif 695 } 696 break; 697 case NSKeyUp: 698 SDL_SendKeyboardKey(SDL_RELEASED, code); 699 break; 700 case NSFlagsChanged: 701 /* FIXME CW 2007-08-14: check if this whole mess that takes up half of this file is really necessary */ 702 HandleModifiers(_this, scancode, [event modifierFlags]); 703 break; 704 default: /* just to avoid compiler warnings */ 705 break; 706 } 707} 708 709void 710Cocoa_QuitKeyboard(_THIS) 711{ 712 QuitHIDCallback(); 713} 714 715#endif /* SDL_VIDEO_DRIVER_COCOA */ 716 717/* vi: set ts=4 sw=4 expandtab: */ 718