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