src/video/cocoa/SDL_cocoakeyboard.m
author Sam Lantinga <slouken@libsdl.org>
Tue, 19 Jan 2010 07:28:51 +0000
changeset 3683 4c5ab6841fdc
parent 3676 1ab77e93a6c9
child 4434 5c64052fb476
permissions -rw-r--r--
From: Jjgod Jiang
Date: Mon, 18 Jan 2010 17:46:35 +0800
Subject: [PATCH] Polish text input handling for Mac OS X

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