src/video/cocoa/SDL_cocoakeyboard.m
author Sam Lantinga <slouken@libsdl.org>
Mon, 11 Feb 2013 17:39:52 -0800
changeset 6848 478ecc8a58b3
parent 6832 156e608ec4ef
child 6885 700f1b25f77f
permissions -rw-r--r--
Backed out use of @autorelease keyword for now, since it's not supported by older Xcode versions.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_COCOA
    24 
    25 #include "SDL_cocoavideo.h"
    26 
    27 #include "../../events/SDL_keyboard_c.h"
    28 #include "../../events/scancodes_darwin.h"
    29 
    30 #include <Carbon/Carbon.h>
    31 
    32 //#define DEBUG_IME NSLog
    33 #define DEBUG_IME(...)
    34 
    35 #ifndef NX_DEVICERCTLKEYMASK
    36     #define NX_DEVICELCTLKEYMASK    0x00000001
    37 #endif
    38 #ifndef NX_DEVICELSHIFTKEYMASK
    39     #define NX_DEVICELSHIFTKEYMASK  0x00000002
    40 #endif
    41 #ifndef NX_DEVICERSHIFTKEYMASK
    42     #define NX_DEVICERSHIFTKEYMASK  0x00000004
    43 #endif
    44 #ifndef NX_DEVICELCMDKEYMASK
    45     #define NX_DEVICELCMDKEYMASK    0x00000008
    46 #endif
    47 #ifndef NX_DEVICERCMDKEYMASK
    48     #define NX_DEVICERCMDKEYMASK    0x00000010
    49 #endif
    50 #ifndef NX_DEVICELALTKEYMASK
    51     #define NX_DEVICELALTKEYMASK    0x00000020
    52 #endif
    53 #ifndef NX_DEVICERALTKEYMASK
    54     #define NX_DEVICERALTKEYMASK    0x00000040
    55 #endif
    56 #ifndef NX_DEVICERCTLKEYMASK
    57     #define NX_DEVICERCTLKEYMASK    0x00002000
    58 #endif
    59 
    60 @interface SDLTranslatorResponder : NSView <NSTextInput>
    61 {
    62     NSString *_markedText;
    63     NSRange   _markedRange;
    64     NSRange   _selectedRange;
    65     SDL_Rect  _inputRect;
    66 }
    67 - (void) doCommandBySelector:(SEL)myselector;
    68 - (void) setInputRect:(SDL_Rect *) rect;
    69 @end
    70 
    71 @implementation SDLTranslatorResponder
    72 
    73 - (void) setInputRect:(SDL_Rect *) rect
    74 {
    75     _inputRect = *rect;
    76 }
    77 
    78 - (void) insertText:(id) aString
    79 {
    80     const char *str;
    81 
    82     DEBUG_IME(@"insertText: %@", aString);
    83 
    84     /* Could be NSString or NSAttributedString, so we have
    85      * to test and convert it before return as SDL event */
    86     if ([aString isKindOfClass: [NSAttributedString class]])
    87         str = [[aString string] UTF8String];
    88     else
    89         str = [aString UTF8String];
    90 
    91     SDL_SendKeyboardText(str);
    92 }
    93 
    94 - (void) doCommandBySelector:(SEL) myselector
    95 {
    96     // No need to do anything since we are not using Cocoa
    97     // selectors to handle special keys, instead we use SDL
    98     // key events to do the same job.
    99 }
   100 
   101 - (BOOL) hasMarkedText
   102 {
   103     return _markedText != nil;
   104 }
   105 
   106 - (NSRange) markedRange
   107 {
   108     return _markedRange;
   109 }
   110 
   111 - (NSRange) selectedRange
   112 {
   113     return _selectedRange;
   114 }
   115 
   116 - (void) setMarkedText:(id) aString
   117          selectedRange:(NSRange) selRange
   118 {
   119     if ([aString isKindOfClass: [NSAttributedString class]])
   120         aString = [aString string];
   121 
   122     if ([aString length] == 0)
   123     {
   124         [self unmarkText];
   125         return;
   126     }
   127 
   128     if (_markedText != aString)
   129     {
   130         [_markedText release];
   131         _markedText = [aString retain];
   132     }
   133 
   134     _selectedRange = selRange;
   135     _markedRange = NSMakeRange(0, [aString length]);
   136 
   137     SDL_SendEditingText([aString UTF8String],
   138                         selRange.location, selRange.length);
   139 
   140     DEBUG_IME(@"setMarkedText: %@, (%d, %d)", _markedText,
   141           selRange.location, selRange.length);
   142 }
   143 
   144 - (void) unmarkText
   145 {
   146     [_markedText release];
   147     _markedText = nil;
   148 
   149     SDL_SendEditingText("", 0, 0);
   150 }
   151 
   152 - (NSRect) firstRectForCharacterRange: (NSRange) theRange
   153 {
   154     NSWindow *window = [self window];
   155     NSRect contentRect = [window contentRectForFrameRect: [window frame]];
   156     float windowHeight = contentRect.size.height;
   157     NSRect rect = NSMakeRect(_inputRect.x, windowHeight - _inputRect.y - _inputRect.h,
   158                              _inputRect.w, _inputRect.h);
   159 
   160     DEBUG_IME(@"firstRectForCharacterRange: (%d, %d): windowHeight = %g, rect = %@",
   161             theRange.location, theRange.length, windowHeight,
   162             NSStringFromRect(rect));
   163     rect.origin = [[self window] convertBaseToScreen: rect.origin];
   164 
   165     return rect;
   166 }
   167 
   168 - (NSAttributedString *) attributedSubstringFromRange: (NSRange) theRange
   169 {
   170     DEBUG_IME(@"attributedSubstringFromRange: (%d, %d)", theRange.location, theRange.length);
   171     return nil;
   172 }
   173 
   174 /* Needs long instead of NSInteger for compilation on Mac OS X 10.4 */
   175 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
   176 - (long) conversationIdentifier
   177 #else
   178 - (NSInteger) conversationIdentifier
   179 #endif
   180 {
   181     return (long) self;
   182 }
   183 
   184 // This method returns the index for character that is 
   185 // nearest to thePoint.  thPoint is in screen coordinate system.
   186 - (NSUInteger) characterIndexForPoint:(NSPoint) thePoint
   187 {
   188     DEBUG_IME(@"characterIndexForPoint: (%g, %g)", thePoint.x, thePoint.y);
   189     return 0;
   190 }
   191 
   192 // This method is the key to attribute extension. 
   193 // We could add new attributes through this method.
   194 // NSInputServer examines the return value of this
   195 // method & constructs appropriate attributed string.
   196 - (NSArray *) validAttributesForMarkedText
   197 {
   198     return [NSArray array];
   199 }
   200 
   201 @end
   202 
   203 /* This is the original behavior, before support was added for 
   204  * differentiating between left and right versions of the keys.
   205  */
   206 static void
   207 DoUnsidedModifiers(unsigned short scancode,
   208                    unsigned int oldMods, unsigned int newMods)
   209 {
   210     const int mapping[] = {
   211         SDL_SCANCODE_CAPSLOCK,
   212         SDL_SCANCODE_LSHIFT,
   213         SDL_SCANCODE_LCTRL,
   214         SDL_SCANCODE_LALT,
   215         SDL_SCANCODE_LGUI
   216     };
   217     unsigned int i, bit;
   218 
   219     /* Iterate through the bits, testing each against the current modifiers */
   220     for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
   221         unsigned int oldMask, newMask;
   222 
   223         oldMask = oldMods & bit;
   224         newMask = newMods & bit;
   225 
   226         if (oldMask && oldMask != newMask) {        /* modifier up event */
   227             /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
   228             if (bit == NSAlphaShiftKeyMask) {
   229                 SDL_SendKeyboardKey(SDL_PRESSED, mapping[i]);
   230             }
   231             SDL_SendKeyboardKey(SDL_RELEASED, mapping[i]);
   232         } else if (newMask && oldMask != newMask) { /* modifier down event */
   233             SDL_SendKeyboardKey(SDL_PRESSED, mapping[i]);
   234             /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
   235             if (bit == NSAlphaShiftKeyMask) {
   236                 SDL_SendKeyboardKey(SDL_RELEASED, mapping[i]);
   237             }
   238         }
   239     }
   240 }
   241 
   242 /* This is a helper function for HandleModifierSide. This 
   243  * function reverts back to behavior before the distinction between
   244  * sides was made.
   245  */
   246 static void
   247 HandleNonDeviceModifier(unsigned int device_independent_mask,
   248                         unsigned int oldMods,
   249                         unsigned int newMods,
   250                         SDL_Scancode scancode)
   251 {
   252     unsigned int oldMask, newMask;
   253     
   254     /* Isolate just the bits we care about in the depedent bits so we can 
   255      * figure out what changed
   256      */ 
   257     oldMask = oldMods & device_independent_mask;
   258     newMask = newMods & device_independent_mask;
   259     
   260     if (oldMask && oldMask != newMask) {
   261         SDL_SendKeyboardKey(SDL_RELEASED, scancode);
   262     } else if (newMask && oldMask != newMask) {
   263         SDL_SendKeyboardKey(SDL_PRESSED, scancode);
   264     }
   265 }
   266 
   267 /* This is a helper function for HandleModifierSide. 
   268  * This function sets the actual SDL_PrivateKeyboard event.
   269  */
   270 static void
   271 HandleModifierOneSide(unsigned int oldMods, unsigned int newMods,
   272                       SDL_Scancode scancode, 
   273                       unsigned int sided_device_dependent_mask)
   274 {
   275     unsigned int old_dep_mask, new_dep_mask;
   276 
   277     /* Isolate just the bits we care about in the depedent bits so we can 
   278      * figure out what changed
   279      */ 
   280     old_dep_mask = oldMods & sided_device_dependent_mask;
   281     new_dep_mask = newMods & sided_device_dependent_mask;
   282 
   283     /* We now know that this side bit flipped. But we don't know if
   284      * it went pressed to released or released to pressed, so we must 
   285      * find out which it is.
   286      */
   287     if (new_dep_mask && old_dep_mask != new_dep_mask) {
   288         SDL_SendKeyboardKey(SDL_PRESSED, scancode);
   289     } else {
   290         SDL_SendKeyboardKey(SDL_RELEASED, scancode);
   291     }
   292 }
   293 
   294 /* This is a helper function for DoSidedModifiers.
   295  * This function will figure out if the modifier key is the left or right side, 
   296  * e.g. left-shift vs right-shift. 
   297  */
   298 static void
   299 HandleModifierSide(int device_independent_mask, 
   300                    unsigned int oldMods, unsigned int newMods, 
   301                    SDL_Scancode left_scancode, 
   302                    SDL_Scancode right_scancode,
   303                    unsigned int left_device_dependent_mask, 
   304                    unsigned int right_device_dependent_mask)
   305 {
   306     unsigned int device_dependent_mask = (left_device_dependent_mask |
   307                                          right_device_dependent_mask);
   308     unsigned int diff_mod;
   309     
   310     /* On the basis that the device independent mask is set, but there are 
   311      * no device dependent flags set, we'll assume that we can't detect this 
   312      * keyboard and revert to the unsided behavior.
   313      */
   314     if ((device_dependent_mask & newMods) == 0) {
   315         /* Revert to the old behavior */
   316         HandleNonDeviceModifier(device_independent_mask, oldMods, newMods, left_scancode);
   317         return;
   318     }
   319 
   320     /* XOR the previous state against the new state to see if there's a change */
   321     diff_mod = (device_dependent_mask & oldMods) ^
   322                (device_dependent_mask & newMods);
   323     if (diff_mod) {
   324         /* A change in state was found. Isolate the left and right bits 
   325          * to handle them separately just in case the values can simulataneously
   326          * change or if the bits don't both exist.
   327          */
   328         if (left_device_dependent_mask & diff_mod) {
   329             HandleModifierOneSide(oldMods, newMods, left_scancode, left_device_dependent_mask);
   330         }
   331         if (right_device_dependent_mask & diff_mod) {
   332             HandleModifierOneSide(oldMods, newMods, right_scancode, right_device_dependent_mask);
   333         }
   334     }
   335 }
   336    
   337 /* This is a helper function for DoSidedModifiers.
   338  * This function will release a key press in the case that 
   339  * it is clear that the modifier has been released (i.e. one side 
   340  * can't still be down).
   341  */
   342 static void
   343 ReleaseModifierSide(unsigned int device_independent_mask, 
   344                     unsigned int oldMods, unsigned int newMods,
   345                     SDL_Scancode left_scancode, 
   346                     SDL_Scancode right_scancode,
   347                     unsigned int left_device_dependent_mask, 
   348                     unsigned int right_device_dependent_mask)
   349 {
   350     unsigned int device_dependent_mask = (left_device_dependent_mask |
   351                                           right_device_dependent_mask);
   352 
   353     /* On the basis that the device independent mask is set, but there are 
   354      * no device dependent flags set, we'll assume that we can't detect this 
   355      * keyboard and revert to the unsided behavior.
   356      */
   357     if ((device_dependent_mask & oldMods) == 0) {
   358         /* In this case, we can't detect the keyboard, so use the left side 
   359          * to represent both, and release it. 
   360          */
   361         SDL_SendKeyboardKey(SDL_RELEASED, left_scancode);
   362         return;
   363     }
   364 
   365     /* 
   366      * This could have been done in an if-else case because at this point,
   367      * we know that all keys have been released when calling this function. 
   368      * But I'm being paranoid so I want to handle each separately,
   369      * so I hope this doesn't cause other problems.
   370      */
   371     if ( left_device_dependent_mask & oldMods ) {
   372         SDL_SendKeyboardKey(SDL_RELEASED, left_scancode);
   373     }
   374     if ( right_device_dependent_mask & oldMods ) {
   375         SDL_SendKeyboardKey(SDL_RELEASED, right_scancode);
   376     }
   377 }
   378 
   379 /* This is a helper function for DoSidedModifiers.
   380  * This function handles the CapsLock case.
   381  */
   382 static void
   383 HandleCapsLock(unsigned short scancode,
   384                unsigned int oldMods, unsigned int newMods)
   385 {
   386     unsigned int oldMask, newMask;
   387     
   388     oldMask = oldMods & NSAlphaShiftKeyMask;
   389     newMask = newMods & NSAlphaShiftKeyMask;
   390 
   391     if (oldMask != newMask) {
   392         SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_CAPSLOCK);
   393         SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_CAPSLOCK);
   394     }
   395 
   396     oldMask = oldMods & NSNumericPadKeyMask;
   397     newMask = newMods & NSNumericPadKeyMask;
   398 
   399     if (oldMask != newMask) {
   400         SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_NUMLOCKCLEAR);
   401         SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_NUMLOCKCLEAR);
   402     }
   403 }
   404 
   405 /* This function will handle the modifier keys and also determine the 
   406  * correct side of the key.
   407  */
   408 static void
   409 DoSidedModifiers(unsigned short scancode,
   410                  unsigned int oldMods, unsigned int newMods)
   411 {
   412 	/* Set up arrays for the key syms for the left and right side. */
   413     const SDL_Scancode left_mapping[]  = {
   414         SDL_SCANCODE_LSHIFT,
   415         SDL_SCANCODE_LCTRL,
   416         SDL_SCANCODE_LALT,
   417         SDL_SCANCODE_LGUI
   418     };
   419     const SDL_Scancode right_mapping[] = {
   420         SDL_SCANCODE_RSHIFT,
   421         SDL_SCANCODE_RCTRL,
   422         SDL_SCANCODE_RALT,
   423         SDL_SCANCODE_RGUI
   424     };
   425 	/* Set up arrays for the device dependent masks with indices that 
   426      * correspond to the _mapping arrays 
   427      */
   428     const unsigned int left_device_mapping[]  = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK };
   429     const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK };
   430 
   431     unsigned int i, bit;
   432 
   433     /* Handle CAPSLOCK separately because it doesn't have a left/right side */
   434     HandleCapsLock(scancode, oldMods, newMods);
   435 
   436     /* Iterate through the bits, testing each against the old modifiers */
   437     for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
   438         unsigned int oldMask, newMask;
   439 		
   440         oldMask = oldMods & bit;
   441         newMask = newMods & bit;
   442 		
   443         /* If the bit is set, we must always examine it because the left
   444          * and right side keys may alternate or both may be pressed.
   445          */
   446         if (newMask) {
   447             HandleModifierSide(bit, oldMods, newMods,
   448                                left_mapping[i], right_mapping[i],
   449                                left_device_mapping[i], right_device_mapping[i]);
   450         }
   451         /* If the state changed from pressed to unpressed, we must examine
   452             * the device dependent bits to release the correct keys.
   453             */
   454         else if (oldMask && oldMask != newMask) {
   455             ReleaseModifierSide(bit, oldMods, newMods,
   456                               left_mapping[i], right_mapping[i],
   457                               left_device_mapping[i], right_device_mapping[i]);
   458         }
   459     }
   460 }
   461 
   462 static void
   463 HandleModifiers(_THIS, unsigned short scancode, unsigned int modifierFlags)
   464 {
   465     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   466 
   467     if (modifierFlags == data->modifierFlags) {
   468     	return;
   469     }
   470 
   471     /* 
   472      * Starting with Panther (10.3.0), the ability to distinguish between 
   473      * left side and right side modifiers is available.
   474      */
   475     if (data->osversion >= 0x1030) {
   476         DoSidedModifiers(scancode, data->modifierFlags, modifierFlags);
   477     } else {
   478         DoUnsidedModifiers(scancode, data->modifierFlags, modifierFlags);
   479     }
   480     data->modifierFlags = modifierFlags;
   481 }
   482 
   483 static void
   484 UpdateKeymap(SDL_VideoData *data)
   485 {
   486 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
   487     TISInputSourceRef key_layout;
   488 #else
   489     KeyboardLayoutRef key_layout;
   490 #endif
   491     const void *chr_data;
   492     int i;
   493     SDL_Scancode scancode;
   494     SDL_Keycode keymap[SDL_NUM_SCANCODES];
   495 
   496     /* See if the keymap needs to be updated */
   497 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
   498     key_layout = TISCopyCurrentKeyboardLayoutInputSource();
   499 #else
   500     KLGetCurrentKeyboardLayout(&key_layout);
   501 #endif
   502     if (key_layout == data->key_layout) {
   503         return;
   504     }
   505     data->key_layout = key_layout;
   506 
   507     SDL_GetDefaultKeymap(keymap);
   508 
   509     /* Try Unicode data first (preferred as of Mac OS X 10.5) */
   510 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
   511     CFDataRef uchrDataRef = TISGetInputSourceProperty(key_layout, kTISPropertyUnicodeKeyLayoutData);
   512     if (uchrDataRef)
   513         chr_data = CFDataGetBytePtr(uchrDataRef);
   514     else
   515         goto cleanup;
   516 #else
   517     KLGetKeyboardLayoutProperty(key_layout, kKLuchrData, &chr_data);
   518 #endif
   519     if (chr_data) {
   520         UInt32 keyboard_type = LMGetKbdType();
   521         OSStatus err;
   522 
   523         for (i = 0; i < SDL_arraysize(darwin_scancode_table); i++) {
   524             UniChar s[8];
   525             UniCharCount len;
   526             UInt32 dead_key_state;
   527 
   528             /* Make sure this scancode is a valid character scancode */
   529             scancode = darwin_scancode_table[i];
   530             if (scancode == SDL_SCANCODE_UNKNOWN ||
   531                 (keymap[scancode] & SDLK_SCANCODE_MASK)) {
   532                 continue;
   533             }
   534 
   535             dead_key_state = 0;
   536             err = UCKeyTranslate ((UCKeyboardLayout *) chr_data,
   537                                   i, kUCKeyActionDown,
   538                                   0, keyboard_type,
   539                                   kUCKeyTranslateNoDeadKeysMask,
   540                                   &dead_key_state, 8, &len, s);
   541             if (err != noErr)
   542                 continue;
   543 
   544             if (len > 0 && s[0] != 0x10) {
   545                 keymap[scancode] = s[0];
   546             }
   547         }
   548         SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
   549         return;
   550     }
   551 
   552 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
   553 cleanup:
   554     CFRelease(key_layout);
   555 #else
   556     /* Fall back to older style key map data */
   557     KLGetKeyboardLayoutProperty(key_layout, kKLKCHRData, &chr_data);
   558     if (chr_data) {
   559         for (i = 0; i < 128; i++) {
   560             UInt32 c, state = 0;
   561 
   562             /* Make sure this scancode is a valid character scancode */
   563             scancode = darwin_scancode_table[i];
   564             if (scancode == SDL_SCANCODE_UNKNOWN ||
   565                 (keymap[scancode] & SDLK_SCANCODE_MASK)) {
   566                 continue;
   567             }
   568 
   569             c = KeyTranslate (chr_data, i, &state) & 255;
   570             if (state) {
   571                 /* Dead key, process key up */
   572                 c = KeyTranslate (chr_data, i | 128, &state) & 255;
   573             }
   574 
   575             if (c != 0 && c != 0x10) {
   576                 /* MacRoman to Unicode table, taken from X.org sources */
   577                 static const unsigned short macroman_table[128] = {
   578                     0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
   579                     0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
   580                     0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
   581                     0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
   582                     0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
   583                     0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
   584                     0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
   585                     0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
   586                     0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
   587                     0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
   588                     0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
   589                     0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
   590                     0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
   591                     0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
   592                     0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
   593                     0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7,
   594                 };
   595 
   596                 if (c >= 128) {
   597                     c = macroman_table[c - 128];
   598                 }
   599                 keymap[scancode] = c;
   600             }
   601         }
   602         SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
   603         return;
   604     }
   605 #endif
   606 }
   607 
   608 void
   609 Cocoa_InitKeyboard(_THIS)
   610 {
   611     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   612 
   613     UpdateKeymap(data);
   614     
   615     /* Set our own names for the platform-dependent but layout-independent keys */
   616     /* This key is NumLock on the MacBook keyboard. :) */
   617     /*SDL_SetScancodeName(SDL_SCANCODE_NUMLOCKCLEAR, "Clear");*/
   618     SDL_SetScancodeName(SDL_SCANCODE_LALT, "Left Option");
   619     SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Command");
   620     SDL_SetScancodeName(SDL_SCANCODE_RALT, "Right Option");
   621     SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Command");
   622 }
   623 
   624 void
   625 Cocoa_StartTextInput(_THIS)
   626 {
   627     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   628     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   629     NSView *parentView = [[NSApp keyWindow] contentView];
   630 
   631     /* We only keep one field editor per process, since only the front most
   632      * window can receive text input events, so it make no sense to keep more
   633      * than one copy. When we switched to another window and requesting for
   634      * text input, simply remove the field editor from its superview then add
   635      * it to the front most window's content view */
   636     if (!data->fieldEdit) {
   637         data->fieldEdit =
   638             [[SDLTranslatorResponder alloc] initWithFrame: NSMakeRect(0.0, 0.0, 0.0, 0.0)];
   639     }
   640 
   641     if (![[data->fieldEdit superview] isEqual: parentView])
   642     {
   643         // DEBUG_IME(@"add fieldEdit to window contentView");
   644         [data->fieldEdit removeFromSuperview];
   645         [parentView addSubview: data->fieldEdit];
   646         [[NSApp keyWindow] makeFirstResponder: data->fieldEdit];
   647     }
   648 
   649     [pool release];
   650 }
   651 
   652 void
   653 Cocoa_StopTextInput(_THIS)
   654 {
   655     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   656 
   657     if (data && data->fieldEdit) {
   658         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   659         [data->fieldEdit removeFromSuperview];
   660         [data->fieldEdit release];
   661         data->fieldEdit = nil;
   662         [pool release];
   663     }
   664 }
   665 
   666 void
   667 Cocoa_SetTextInputRect(_THIS, SDL_Rect *rect)
   668 {
   669     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   670 
   671     if (!rect) {
   672 	SDL_InvalidParamError("rect");
   673 	return;
   674     }
   675 
   676     [data->fieldEdit setInputRect: rect];
   677 }
   678 
   679 void
   680 Cocoa_HandleKeyEvent(_THIS, NSEvent *event)
   681 {
   682     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   683     unsigned short scancode = [event keyCode];
   684     SDL_Scancode code;
   685 #if 0
   686     const char *text;
   687 #endif
   688 
   689     if ((scancode == 10 || scancode == 50) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) {
   690         /* see comments in SDL_cocoakeys.h */
   691         scancode = 60 - scancode;
   692     }
   693     if (scancode < SDL_arraysize(darwin_scancode_table)) {
   694         code = darwin_scancode_table[scancode];
   695     }
   696     else {
   697         /* Hmm, does this ever happen?  If so, need to extend the keymap... */
   698         code = SDL_SCANCODE_UNKNOWN;
   699     }
   700 
   701     switch ([event type]) {
   702     case NSKeyDown:
   703         if (![event isARepeat]) {
   704             /* See if we need to rebuild the keyboard layout */
   705             UpdateKeymap(data);
   706         }
   707 
   708         SDL_SendKeyboardKey(SDL_PRESSED, code);
   709 #if 1
   710         if (code == SDL_SCANCODE_UNKNOWN) {
   711             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);
   712         }
   713 #endif
   714         if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
   715             /* 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. */
   716             [data->fieldEdit interpretKeyEvents:[NSArray arrayWithObject:event]];
   717 #if 0
   718             text = [[event characters] UTF8String];
   719             if(text && *text) {
   720                 SDL_SendKeyboardText(text);
   721                 [data->fieldEdit setString:@""];
   722             }
   723 #endif
   724         }
   725         break;
   726     case NSKeyUp:
   727         SDL_SendKeyboardKey(SDL_RELEASED, code);
   728         break;
   729     case NSFlagsChanged:
   730         /* FIXME CW 2007-08-14: check if this whole mess that takes up half of this file is really necessary */
   731         HandleModifiers(_this, scancode, [event modifierFlags]);
   732         break;
   733     default: /* just to avoid compiler warnings */
   734         break;
   735     }
   736 }
   737 
   738 void
   739 Cocoa_QuitKeyboard(_THIS)
   740 {
   741 }
   742 
   743 #endif /* SDL_VIDEO_DRIVER_COCOA */
   744 
   745 /* vi: set ts=4 sw=4 expandtab: */