src/video/cocoa/SDL_cocoakeyboard.m
author Ryan C. Gordon
Mon, 23 Jan 2017 12:06:10 -0500
changeset 10837 c2f241c2f6ad
parent 10737 3406a0f8b041
child 10986 b93491afe676
permissions -rw-r--r--
audio: Fix same bug as last commit, but for _mm_bslli_si128 vs _mm_slli_si128.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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 /*------------------------------------------------------------------------------
   188 Set up a HID callback to properly detect Caps Lock up/down events.
   189 Derived from:
   190 http://stackoverflow.com/questions/7190852/using-iohidmanager-to-get-modifier-key-events
   191 */
   192 
   193 static IOHIDManagerRef s_hidManager = NULL;
   194 
   195 static void
   196 HIDCallback(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 
   212 static CFDictionaryRef
   213 CreateHIDDeviceMatchingDictionary(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 
   234 static void
   235 QuitHIDCallback()
   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 
   253 static void
   254 InitHIDCallback()
   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 
   282 fail:
   283     QuitHIDCallback();
   284 
   285 cleanup:
   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  */
   301 static void
   302 HandleNonDeviceModifier(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  */
   325 static void
   326 HandleModifierOneSide(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  */
   353 static void
   354 HandleModifierSide(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  */
   397 static void
   398 ReleaseModifierSide(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  */
   437 static void
   438 DoSidedModifiers(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 
   488 static void
   489 HandleModifiers(_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 
   501 static void
   502 UpdateKeymap(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 
   564 cleanup:
   565     CFRelease(key_layout);
   566 }
   567 
   568 void
   569 Cocoa_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 
   589 void
   590 Cocoa_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 
   620 void
   621 Cocoa_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 
   633 void
   634 Cocoa_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 
   646 void
   647 Cocoa_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 
   709 void
   710 Cocoa_QuitKeyboard(_THIS)
   711 {
   712     QuitHIDCallback();
   713 }
   714 
   715 #endif /* SDL_VIDEO_DRIVER_COCOA */
   716 
   717 /* vi: set ts=4 sw=4 expandtab: */