src/video/cocoa/SDL_cocoakeyboard.m
author Sam Lantinga <slouken@libsdl.org>
Thu, 15 Apr 2010 22:27:01 -0700
changeset 4435 e953700da4ca
parent 4434 5c64052fb476
child 4436 d3c193100522
permissions -rw-r--r--
Minor cleanup on Jiang's patch
     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(_keyboard, [aString UTF8String],
   144                         selRange.location, selRange.length);
   145 
   146     DEBUG_IME(@"setMarkedText: %@, (%d, %d)", _markedText,
   147           selRange.location, selRange.length);
   148 }
   149 
   150 - (void) unmarkText
   151 {
   152     [_markedText release];
   153     _markedText = nil;
   154 }
   155 
   156 - (NSRect) firstRectForCharacterRange: (NSRange) theRange
   157 {
   158     float windowHeight = [[self window] frame].size.height;
   159     NSRect rect = NSMakeRect(_inputRect.x, windowHeight - _inputRect.y - _inputRect.h,
   160                              _inputRect.w, _inputRect.h);
   161 
   162     DEBUG_IME(@"firstRectForCharacterRange: (%d, %d): windowHeight = %g, rect = %@",
   163             theRange.location, theRange.length, windowHeight,
   164             NSStringFromRect(rect));
   165     rect.origin = [[self window] convertBaseToScreen: rect.origin];
   166 
   167     return rect;
   168 }
   169 
   170 - (NSAttributedString *) attributedSubstringFromRange: (NSRange) theRange
   171 {
   172     DEBUG_IME(@"attributedSubstringFromRange: (%d, %d)", theRange.location, theRange.length);
   173     return nil;
   174 }
   175 
   176 /* Needs long instead of NSInteger for compilation on Mac OS X 10.4 */
   177 - (long) conversationIdentifier
   178 {
   179     return (long) self;
   180 }
   181 
   182 // This method returns the index for character that is 
   183 // nearest to thePoint.  thPoint is in screen coordinate system.
   184 - (NSUInteger) characterIndexForPoint:(NSPoint) thePoint
   185 {
   186     DEBUG_IME(@"characterIndexForPoint: (%g, %g)", thePoint.x, thePoint.y);
   187     return 0;
   188 }
   189 
   190 // This method is the key to attribute extension. 
   191 // We could add new attributes through this method.
   192 // NSInputServer examines the return value of this
   193 // method & constructs appropriate attributed string.
   194 - (NSArray *) validAttributesForMarkedText
   195 {
   196     return [NSArray array];
   197 }
   198 
   199 @end
   200 
   201 /* This is the original behavior, before support was added for 
   202  * differentiating between left and right versions of the keys.
   203  */
   204 static void
   205 DoUnsidedModifiers(int keyboard, unsigned short scancode,
   206                    unsigned int oldMods, unsigned int newMods)
   207 {
   208     const int mapping[] = {
   209         SDL_SCANCODE_CAPSLOCK,
   210         SDL_SCANCODE_LSHIFT,
   211         SDL_SCANCODE_LCTRL,
   212         SDL_SCANCODE_LALT,
   213         SDL_SCANCODE_LGUI
   214     };
   215     unsigned int i, bit;
   216 
   217     /* Iterate through the bits, testing each against the current modifiers */
   218     for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
   219         unsigned int oldMask, newMask;
   220 
   221         oldMask = oldMods & bit;
   222         newMask = newMods & bit;
   223 
   224         if (oldMask && oldMask != newMask) {        /* modifier up event */
   225             /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
   226             if (bit == NSAlphaShiftKeyMask) {
   227                 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, mapping[i]);
   228             }
   229             SDL_SendKeyboardKey(keyboard, SDL_RELEASED, mapping[i]);
   230         } else if (newMask && oldMask != newMask) { /* modifier down event */
   231             SDL_SendKeyboardKey(keyboard, SDL_PRESSED, mapping[i]);
   232             /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
   233             if (bit == NSAlphaShiftKeyMask) {
   234                 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, mapping[i]);
   235             }
   236         }
   237     }
   238 }
   239 
   240 /* This is a helper function for HandleModifierSide. This 
   241  * function reverts back to behavior before the distinction between
   242  * sides was made.
   243  */
   244 static void
   245 HandleNonDeviceModifier(int keyboard,
   246                         unsigned int device_independent_mask,
   247                         unsigned int oldMods,
   248                         unsigned int newMods,
   249                         SDL_scancode scancode)
   250 {
   251     unsigned int oldMask, newMask;
   252     
   253     /* Isolate just the bits we care about in the depedent bits so we can 
   254      * figure out what changed
   255      */ 
   256     oldMask = oldMods & device_independent_mask;
   257     newMask = newMods & device_independent_mask;
   258     
   259     if (oldMask && oldMask != newMask) {
   260         SDL_SendKeyboardKey(keyboard, SDL_RELEASED, scancode);
   261     } else if (newMask && oldMask != newMask) {
   262         SDL_SendKeyboardKey(keyboard, SDL_PRESSED, scancode);
   263     }
   264 }
   265 
   266 /* This is a helper function for HandleModifierSide. 
   267  * This function sets the actual SDL_PrivateKeyboard event.
   268  */
   269 static void
   270 HandleModifierOneSide(int keyboard,
   271                       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(keyboard, SDL_PRESSED, scancode);
   289     } else {
   290         SDL_SendKeyboardKey(keyboard, 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 keyboard,
   300                    int device_independent_mask, 
   301                    unsigned int oldMods, unsigned int newMods, 
   302                    SDL_scancode left_scancode, 
   303                    SDL_scancode right_scancode,
   304                    unsigned int left_device_dependent_mask, 
   305                    unsigned int right_device_dependent_mask)
   306 {
   307     unsigned int device_dependent_mask = (left_device_dependent_mask |
   308                                          right_device_dependent_mask);
   309     unsigned int diff_mod;
   310     
   311     /* On the basis that the device independent mask is set, but there are 
   312      * no device dependent flags set, we'll assume that we can't detect this 
   313      * keyboard and revert to the unsided behavior.
   314      */
   315     if ((device_dependent_mask & newMods) == 0) {
   316         /* Revert to the old behavior */
   317         HandleNonDeviceModifier(keyboard, device_independent_mask, oldMods, newMods, left_scancode);
   318         return;
   319     }
   320 
   321     /* XOR the previous state against the new state to see if there's a change */
   322     diff_mod = (device_dependent_mask & oldMods) ^
   323                (device_dependent_mask & newMods);
   324     if (diff_mod) {
   325         /* A change in state was found. Isolate the left and right bits 
   326          * to handle them separately just in case the values can simulataneously
   327          * change or if the bits don't both exist.
   328          */
   329         if (left_device_dependent_mask & diff_mod) {
   330             HandleModifierOneSide(keyboard, oldMods, newMods, left_scancode, left_device_dependent_mask);
   331         }
   332         if (right_device_dependent_mask & diff_mod) {
   333             HandleModifierOneSide(keyboard, oldMods, newMods, right_scancode, right_device_dependent_mask);
   334         }
   335     }
   336 }
   337    
   338 /* This is a helper function for DoSidedModifiers.
   339  * This function will release a key press in the case that 
   340  * it is clear that the modifier has been released (i.e. one side 
   341  * can't still be down).
   342  */
   343 static void
   344 ReleaseModifierSide(int keyboard,
   345                     unsigned int device_independent_mask, 
   346                     unsigned int oldMods, unsigned int newMods,
   347                     SDL_scancode left_scancode, 
   348                     SDL_scancode right_scancode,
   349                     unsigned int left_device_dependent_mask, 
   350                     unsigned int right_device_dependent_mask)
   351 {
   352     unsigned int device_dependent_mask = (left_device_dependent_mask |
   353                                           right_device_dependent_mask);
   354 
   355     /* On the basis that the device independent mask is set, but there are 
   356      * no device dependent flags set, we'll assume that we can't detect this 
   357      * keyboard and revert to the unsided behavior.
   358      */
   359     if ((device_dependent_mask & oldMods) == 0) {
   360         /* In this case, we can't detect the keyboard, so use the left side 
   361          * to represent both, and release it. 
   362          */
   363         SDL_SendKeyboardKey(keyboard, SDL_RELEASED, left_scancode);
   364         return;
   365     }
   366 
   367     /* 
   368      * This could have been done in an if-else case because at this point,
   369      * we know that all keys have been released when calling this function. 
   370      * But I'm being paranoid so I want to handle each separately,
   371      * so I hope this doesn't cause other problems.
   372      */
   373     if ( left_device_dependent_mask & oldMods ) {
   374         SDL_SendKeyboardKey(keyboard, SDL_RELEASED, left_scancode);
   375     }
   376     if ( right_device_dependent_mask & oldMods ) {
   377         SDL_SendKeyboardKey(keyboard, SDL_RELEASED, right_scancode);
   378     }
   379 }
   380 
   381 /* This is a helper function for DoSidedModifiers.
   382  * This function handles the CapsLock case.
   383  */
   384 static void
   385 HandleCapsLock(int keyboard, unsigned short scancode,
   386                unsigned int oldMods, unsigned int newMods)
   387 {
   388     unsigned int oldMask, newMask;
   389     
   390     oldMask = oldMods & NSAlphaShiftKeyMask;
   391     newMask = newMods & NSAlphaShiftKeyMask;
   392 
   393     if (oldMask != newMask) {
   394         SDL_SendKeyboardKey(keyboard, SDL_PRESSED, SDL_SCANCODE_CAPSLOCK);
   395         SDL_SendKeyboardKey(keyboard, SDL_RELEASED, SDL_SCANCODE_CAPSLOCK);
   396     }
   397 
   398     oldMask = oldMods & NSNumericPadKeyMask;
   399     newMask = newMods & NSNumericPadKeyMask;
   400 
   401     if (oldMask != newMask) {
   402         SDL_SendKeyboardKey(keyboard, SDL_PRESSED, SDL_SCANCODE_NUMLOCKCLEAR);
   403         SDL_SendKeyboardKey(keyboard, SDL_RELEASED, SDL_SCANCODE_NUMLOCKCLEAR);
   404     }
   405 }
   406 
   407 /* This function will handle the modifier keys and also determine the 
   408  * correct side of the key.
   409  */
   410 static void
   411 DoSidedModifiers(int keyboard, unsigned short scancode,
   412                  unsigned int oldMods, unsigned int newMods)
   413 {
   414 	/* Set up arrays for the key syms for the left and right side. */
   415     const SDL_scancode left_mapping[]  = {
   416         SDL_SCANCODE_LSHIFT,
   417         SDL_SCANCODE_LCTRL,
   418         SDL_SCANCODE_LALT,
   419         SDL_SCANCODE_LGUI
   420     };
   421     const SDL_scancode right_mapping[] = {
   422         SDL_SCANCODE_RSHIFT,
   423         SDL_SCANCODE_RCTRL,
   424         SDL_SCANCODE_RALT,
   425         SDL_SCANCODE_RGUI
   426     };
   427 	/* Set up arrays for the device dependent masks with indices that 
   428      * correspond to the _mapping arrays 
   429      */
   430     const unsigned int left_device_mapping[]  = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK };
   431     const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK };
   432 
   433     unsigned int i, bit;
   434 
   435     /* Handle CAPSLOCK separately because it doesn't have a left/right side */
   436     HandleCapsLock(keyboard, scancode, oldMods, newMods);
   437 
   438     /* Iterate through the bits, testing each against the old modifiers */
   439     for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
   440         unsigned int oldMask, newMask;
   441 		
   442         oldMask = oldMods & bit;
   443         newMask = newMods & bit;
   444 		
   445         /* If the bit is set, we must always examine it because the left
   446          * and right side keys may alternate or both may be pressed.
   447          */
   448         if (newMask) {
   449             HandleModifierSide(keyboard, bit, oldMods, newMods,
   450                                left_mapping[i], right_mapping[i],
   451                                left_device_mapping[i], right_device_mapping[i]);
   452         }
   453         /* If the state changed from pressed to unpressed, we must examine
   454             * the device dependent bits to release the correct keys.
   455             */
   456         else if (oldMask && oldMask != newMask) {
   457             ReleaseModifierSide(keyboard, bit, oldMods, newMods,
   458                               left_mapping[i], right_mapping[i],
   459                               left_device_mapping[i], right_device_mapping[i]);
   460         }
   461     }
   462 }
   463 
   464 static void
   465 HandleModifiers(_THIS, unsigned short scancode, unsigned int modifierFlags)
   466 {
   467     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   468 
   469     if (modifierFlags == data->modifierFlags) {
   470     	return;
   471     }
   472 
   473     /* 
   474      * Starting with Panther (10.3.0), the ability to distinguish between 
   475      * left side and right side modifiers is available.
   476      */
   477     if (data->osversion >= 0x1030) {
   478         DoSidedModifiers(data->keyboard, scancode, data->modifierFlags, modifierFlags);
   479     } else {
   480         DoUnsidedModifiers(data->keyboard, scancode, data->modifierFlags, modifierFlags);
   481     }
   482     data->modifierFlags = modifierFlags;
   483 }
   484 
   485 static void
   486 UpdateKeymap(SDL_VideoData *data)
   487 {
   488 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
   489     TISInputSourceRef key_layout;
   490 #else
   491     KeyboardLayoutRef key_layout;
   492 #endif
   493     const void *chr_data;
   494     int i;
   495     SDL_scancode scancode;
   496     SDLKey keymap[SDL_NUM_SCANCODES];
   497 
   498     /* See if the keymap needs to be updated */
   499 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
   500     key_layout = TISCopyCurrentKeyboardLayoutInputSource();
   501 #else
   502     KLGetCurrentKeyboardLayout(&key_layout);
   503 #endif
   504     if (key_layout == data->key_layout) {
   505         return;
   506     }
   507     data->key_layout = key_layout;
   508 
   509     SDL_GetDefaultKeymap(keymap);
   510 
   511     /* Try Unicode data first (preferred as of Mac OS X 10.5) */
   512 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
   513     CFDataRef uchrDataRef = TISGetInputSourceProperty(key_layout, kTISPropertyUnicodeKeyLayoutData);
   514     if (uchrDataRef)
   515         chr_data = CFDataGetBytePtr(uchrDataRef);
   516     else
   517         goto cleanup;
   518 #else
   519     KLGetKeyboardLayoutProperty(key_layout, kKLuchrData, &chr_data);
   520 #endif
   521     if (chr_data) {
   522         UInt32 keyboard_type = LMGetKbdType();
   523         OSStatus err;
   524 
   525         for (i = 0; i < SDL_arraysize(darwin_scancode_table); i++) {
   526             UniChar s[8];
   527             UniCharCount len;
   528             UInt32 dead_key_state;
   529 
   530             /* Make sure this scancode is a valid character scancode */
   531             scancode = darwin_scancode_table[i];
   532             if (scancode == SDL_SCANCODE_UNKNOWN ||
   533                 (keymap[scancode] & SDLK_SCANCODE_MASK)) {
   534                 continue;
   535             }
   536 
   537             dead_key_state = 0;
   538             err = UCKeyTranslate ((UCKeyboardLayout *) chr_data,
   539                                   i, kUCKeyActionDown,
   540                                   0, keyboard_type,
   541                                   kUCKeyTranslateNoDeadKeysMask,
   542                                   &dead_key_state, 8, &len, s);
   543             if (err != noErr)
   544                 continue;
   545 
   546             if (len > 0 && s[0] != 0x10) {
   547                 keymap[scancode] = s[0];
   548             }
   549         }
   550         SDL_SetKeymap(data->keyboard, 0, keymap, SDL_NUM_SCANCODES);
   551         return;
   552     }
   553 
   554 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
   555 cleanup:
   556     CFRelease(key_layout);
   557 #else
   558     /* Fall back to older style key map data */
   559     KLGetKeyboardLayoutProperty(key_layout, kKLKCHRData, &chr_data);
   560     if (chr_data) {
   561         for (i = 0; i < 128; i++) {
   562             UInt32 c, state = 0;
   563 
   564             /* Make sure this scancode is a valid character scancode */
   565             scancode = darwin_scancode_table[i];
   566             if (scancode == SDL_SCANCODE_UNKNOWN ||
   567                 (keymap[scancode] & SDLK_SCANCODE_MASK)) {
   568                 continue;
   569             }
   570 
   571             c = KeyTranslate (chr_data, i, &state) & 255;
   572             if (state) {
   573                 /* Dead key, process key up */
   574                 c = KeyTranslate (chr_data, i | 128, &state) & 255;
   575             }
   576 
   577             if (c != 0 && c != 0x10) {
   578                 /* MacRoman to Unicode table, taken from X.org sources */
   579                 static const unsigned short macroman_table[128] = {
   580                     0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
   581                     0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
   582                     0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
   583                     0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
   584                     0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
   585                     0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
   586                     0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
   587                     0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
   588                     0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
   589                     0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
   590                     0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
   591                     0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
   592                     0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
   593                     0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
   594                     0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
   595                     0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7,
   596                 };
   597 
   598                 if (c >= 128) {
   599                     c = macroman_table[c - 128];
   600                 }
   601                 keymap[scancode] = c;
   602             }
   603         }
   604         SDL_SetKeymap(data->keyboard, 0, keymap, SDL_NUM_SCANCODES);
   605         return;
   606     }
   607 #endif
   608 }
   609 
   610 void
   611 Cocoa_InitKeyboard(_THIS)
   612 {
   613     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   614     SDL_Keyboard keyboard;
   615 
   616     SDL_zero(keyboard);
   617     data->keyboard = SDL_AddKeyboard(&keyboard, -1);
   618     UpdateKeymap(data);
   619     
   620     /* Set our own names for the platform-dependent but layout-independent keys */
   621     /* This key is NumLock on the MacBook keyboard. :) */
   622     /*SDL_SetScancodeName(SDL_SCANCODE_NUMLOCKCLEAR, "Clear");*/
   623     SDL_SetScancodeName(SDL_SCANCODE_LALT, "Left Option");
   624     SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Command");
   625     SDL_SetScancodeName(SDL_SCANCODE_RALT, "Right Option");
   626     SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Command");
   627 }
   628 
   629 void
   630 Cocoa_StartTextInput(_THIS)
   631 {
   632     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   633     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   634     NSView *parentView = [[NSApp keyWindow] contentView];
   635 
   636     /* We only keep one field editor per process, since only the front most
   637      * window can receive text input events, so it make no sense to keep more
   638      * than one copy. When we switched to another window and requesting for
   639      * text input, simply remove the field editor from its superview then add
   640      * it to the front most window's content view */
   641     if (!data->fieldEdit) {
   642         data->fieldEdit =
   643             [[SDLTranslatorResponder alloc] initWithFrame: NSMakeRect(0.0, 0.0, 0.0, 0.0)];
   644     }
   645 
   646     [data->fieldEdit setKeyboard: data->keyboard];
   647 
   648     if (![[data->fieldEdit superview] isEqual: parentView])
   649     {
   650         // DEBUG_IME(@"add fieldEdit to window contentView");
   651         [data->fieldEdit removeFromSuperview];
   652         [parentView addSubview: data->fieldEdit];
   653         [[NSApp keyWindow] makeFirstResponder: data->fieldEdit];
   654     }
   655 
   656     [pool release];
   657 }
   658 
   659 void
   660 Cocoa_StopTextInput(_THIS)
   661 {
   662     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   663 
   664     if (data && data->fieldEdit) {
   665         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   666         [data->fieldEdit removeFromSuperview];
   667         [data->fieldEdit release];
   668         data->fieldEdit = nil;
   669         [pool release];
   670     }
   671 }
   672 
   673 void
   674 Cocoa_SetTextInputRect(_THIS, SDL_Rect *rect)
   675 {
   676     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   677 
   678     [data->fieldEdit setInputRect: rect];
   679 }
   680 
   681 void
   682 Cocoa_HandleKeyEvent(_THIS, NSEvent *event)
   683 {
   684     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   685     unsigned short scancode = [event keyCode];
   686     SDL_scancode code;
   687     const char *text;
   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             SDL_SendKeyboardKey(data->keyboard, SDL_PRESSED, code);
   708 #if 1
   709             if (code == SDL_SCANCODE_UNKNOWN) {
   710                 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);
   711             }
   712 #endif
   713         }
   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(data->keyboard, text);
   721                 [data->fieldEdit setString:@""];
   722             }
   723 #endif
   724         }
   725         break;
   726     case NSKeyUp:
   727         SDL_SendKeyboardKey(data->keyboard, 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     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   742     NSAutoreleasePool *pool;
   743 
   744     SDL_DelKeyboard(data->keyboard);
   745 }
   746 
   747 /* vi: set ts=4 sw=4 expandtab: */