src/video/cocoa/SDL_cocoakeyboard.m
author Sam Lantinga <slouken@libsdl.org>
Thu, 07 Feb 2008 15:31:09 +0000
changeset 2305 fbe8ff44c519
parent 2304 50f58ce12497
child 2859 99210400e8b9
permissions -rw-r--r--
First pass of new SDL scancode concept for X11.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 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 
    32 #ifndef NX_DEVICERCTLKEYMASK
    33     #define NX_DEVICELCTLKEYMASK    0x00000001
    34 #endif
    35 #ifndef NX_DEVICELSHIFTKEYMASK
    36     #define NX_DEVICELSHIFTKEYMASK  0x00000002
    37 #endif
    38 #ifndef NX_DEVICERSHIFTKEYMASK
    39     #define NX_DEVICERSHIFTKEYMASK  0x00000004
    40 #endif
    41 #ifndef NX_DEVICELCMDKEYMASK
    42     #define NX_DEVICELCMDKEYMASK    0x00000008
    43 #endif
    44 #ifndef NX_DEVICERCMDKEYMASK
    45     #define NX_DEVICERCMDKEYMASK    0x00000010
    46 #endif
    47 #ifndef NX_DEVICELALTKEYMASK
    48     #define NX_DEVICELALTKEYMASK    0x00000020
    49 #endif
    50 #ifndef NX_DEVICERALTKEYMASK
    51     #define NX_DEVICERALTKEYMASK    0x00000040
    52 #endif
    53 #ifndef NX_DEVICERCTLKEYMASK
    54     #define NX_DEVICERCTLKEYMASK    0x00002000
    55 #endif
    56 
    57 @interface SDLTranslatorResponder : NSTextView
    58 {
    59 }
    60 - (void) doCommandBySelector:(SEL)myselector;
    61 @end
    62 
    63 @implementation SDLTranslatorResponder
    64 - (void) doCommandBySelector:(SEL) myselector {}
    65 @end
    66 
    67 /* This is the original behavior, before support was added for 
    68  * differentiating between left and right versions of the keys.
    69  */
    70 static void
    71 DoUnsidedModifiers(int keyboard, unsigned short scancode,
    72                    unsigned int oldMods, unsigned int newMods)
    73 {
    74     const int mapping[] = {
    75         SDL_SCANCODE_CAPSLOCK,
    76         SDL_SCANCODE_LSHIFT,
    77         SDL_SCANCODE_LCTRL,
    78         SDL_SCANCODE_LALT,
    79         SDL_SCANCODE_LGUI
    80     };
    81     unsigned int i, bit;
    82 
    83     /* Iterate through the bits, testing each against the current modifiers */
    84     for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
    85         unsigned int oldMask, newMask;
    86 
    87         oldMask = oldMods & bit;
    88         newMask = newMods & bit;
    89 
    90         if (oldMask && oldMask != newMask) {        /* modifier up event */
    91             /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
    92             if (bit == NSAlphaShiftKeyMask) {
    93                 SDL_SendKeyboardKey(keyboard, SDL_PRESSED, mapping[i]);
    94             }
    95             SDL_SendKeyboardKey(keyboard, SDL_RELEASED, mapping[i]);
    96         } else if (newMask && oldMask != newMask) { /* modifier down event */
    97             SDL_SendKeyboardKey(keyboard, SDL_PRESSED, mapping[i]);
    98             /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
    99             if (bit == NSAlphaShiftKeyMask) {
   100                 SDL_SendKeyboardKey(keyboard, SDL_RELEASED, mapping[i]);
   101             }
   102         }
   103     }
   104 }
   105 
   106 /* This is a helper function for HandleModifierSide. This 
   107  * function reverts back to behavior before the distinction between
   108  * sides was made.
   109  */
   110 static void
   111 HandleNonDeviceModifier(int keyboard,
   112                         unsigned int device_independent_mask,
   113                         unsigned int oldMods,
   114                         unsigned int newMods,
   115                         SDL_scancode scancode)
   116 {
   117     unsigned int oldMask, newMask;
   118     
   119     /* Isolate just the bits we care about in the depedent bits so we can 
   120      * figure out what changed
   121      */ 
   122     oldMask = oldMods & device_independent_mask;
   123     newMask = newMods & device_independent_mask;
   124     
   125     if (oldMask && oldMask != newMask) {
   126         SDL_SendKeyboardKey(keyboard, SDL_RELEASED, scancode);
   127     } else if (newMask && oldMask != newMask) {
   128         SDL_SendKeyboardKey(keyboard, SDL_PRESSED, scancode);
   129     }
   130 }
   131 
   132 /* This is a helper function for HandleModifierSide. 
   133  * This function sets the actual SDL_PrivateKeyboard event.
   134  */
   135 static void
   136 HandleModifierOneSide(int keyboard,
   137                       unsigned int oldMods, unsigned int newMods,
   138                       SDL_scancode scancode, 
   139                       unsigned int sided_device_dependent_mask)
   140 {
   141     unsigned int old_dep_mask, new_dep_mask;
   142 
   143     /* Isolate just the bits we care about in the depedent bits so we can 
   144      * figure out what changed
   145      */ 
   146     old_dep_mask = oldMods & sided_device_dependent_mask;
   147     new_dep_mask = newMods & sided_device_dependent_mask;
   148 
   149     /* We now know that this side bit flipped. But we don't know if
   150      * it went pressed to released or released to pressed, so we must 
   151      * find out which it is.
   152      */
   153     if (new_dep_mask && old_dep_mask != new_dep_mask) {
   154         SDL_SendKeyboardKey(keyboard, SDL_PRESSED, scancode);
   155     } else {
   156         SDL_SendKeyboardKey(keyboard, SDL_RELEASED, scancode);
   157     }
   158 }
   159 
   160 /* This is a helper function for DoSidedModifiers.
   161  * This function will figure out if the modifier key is the left or right side, 
   162  * e.g. left-shift vs right-shift. 
   163  */
   164 static void
   165 HandleModifierSide(int keyboard,
   166                    int device_independent_mask, 
   167                    unsigned int oldMods, unsigned int newMods, 
   168                    SDL_scancode left_scancode, 
   169                    SDL_scancode right_scancode,
   170                    unsigned int left_device_dependent_mask, 
   171                    unsigned int right_device_dependent_mask)
   172 {
   173     unsigned int device_dependent_mask = (left_device_dependent_mask |
   174                                          right_device_dependent_mask);
   175     unsigned int diff_mod;
   176     
   177     /* On the basis that the device independent mask is set, but there are 
   178      * no device dependent flags set, we'll assume that we can't detect this 
   179      * keyboard and revert to the unsided behavior.
   180      */
   181     if ((device_dependent_mask & newMods) == 0) {
   182         /* Revert to the old behavior */
   183         HandleNonDeviceModifier(keyboard, device_independent_mask, oldMods, newMods, left_scancode);
   184         return;
   185     }
   186 
   187     /* XOR the previous state against the new state to see if there's a change */
   188     diff_mod = (device_dependent_mask & oldMods) ^
   189                (device_dependent_mask & newMods);
   190     if (diff_mod) {
   191         /* A change in state was found. Isolate the left and right bits 
   192          * to handle them separately just in case the values can simulataneously
   193          * change or if the bits don't both exist.
   194          */
   195         if (left_device_dependent_mask & diff_mod) {
   196             HandleModifierOneSide(keyboard, oldMods, newMods, left_scancode, left_device_dependent_mask);
   197         }
   198         if (right_device_dependent_mask & diff_mod) {
   199             HandleModifierOneSide(keyboard, oldMods, newMods, right_scancode, right_device_dependent_mask);
   200         }
   201     }
   202 }
   203    
   204 /* This is a helper function for DoSidedModifiers.
   205  * This function will release a key press in the case that 
   206  * it is clear that the modifier has been released (i.e. one side 
   207  * can't still be down).
   208  */
   209 static void
   210 ReleaseModifierSide(int keyboard,
   211                     unsigned int device_independent_mask, 
   212                     unsigned int oldMods, unsigned int newMods,
   213                     SDL_scancode left_scancode, 
   214                     SDL_scancode right_scancode,
   215                     unsigned int left_device_dependent_mask, 
   216                     unsigned int right_device_dependent_mask)
   217 {
   218     unsigned int device_dependent_mask = (left_device_dependent_mask |
   219                                           right_device_dependent_mask);
   220 
   221     /* On the basis that the device independent mask is set, but there are 
   222      * no device dependent flags set, we'll assume that we can't detect this 
   223      * keyboard and revert to the unsided behavior.
   224      */
   225     if ((device_dependent_mask & oldMods) == 0) {
   226         /* In this case, we can't detect the keyboard, so use the left side 
   227          * to represent both, and release it. 
   228          */
   229         SDL_SendKeyboardKey(keyboard, SDL_RELEASED, left_scancode);
   230         return;
   231     }
   232 
   233     /* 
   234      * This could have been done in an if-else case because at this point,
   235      * we know that all keys have been released when calling this function. 
   236      * But I'm being paranoid so I want to handle each separately,
   237      * so I hope this doesn't cause other problems.
   238      */
   239     if ( left_device_dependent_mask & oldMods ) {
   240         SDL_SendKeyboardKey(keyboard, SDL_RELEASED, left_scancode);
   241     }
   242     if ( right_device_dependent_mask & oldMods ) {
   243         SDL_SendKeyboardKey(keyboard, SDL_RELEASED, right_scancode);
   244     }
   245 }
   246 
   247 /* This is a helper function for DoSidedModifiers.
   248  * This function handles the CapsLock case.
   249  */
   250 static void
   251 HandleCapsLock(int keyboard, unsigned short scancode,
   252                unsigned int oldMods, unsigned int newMods)
   253 {
   254     unsigned int oldMask, newMask;
   255     
   256     oldMask = oldMods & NSAlphaShiftKeyMask;
   257     newMask = newMods & NSAlphaShiftKeyMask;
   258 
   259     if (oldMask != newMask) {
   260         SDL_SendKeyboardKey(keyboard, SDL_PRESSED, SDL_SCANCODE_CAPSLOCK);
   261         SDL_SendKeyboardKey(keyboard, SDL_RELEASED, SDL_SCANCODE_CAPSLOCK);
   262     }
   263 
   264     oldMask = oldMods & NSNumericPadKeyMask;
   265     newMask = newMods & NSNumericPadKeyMask;
   266 
   267     if (oldMask != newMask) {
   268         SDL_SendKeyboardKey(keyboard, SDL_PRESSED, SDL_SCANCODE_NUMLOCKCLEAR);
   269         SDL_SendKeyboardKey(keyboard, SDL_RELEASED, SDL_SCANCODE_NUMLOCKCLEAR);
   270     }
   271 }
   272 
   273 /* This function will handle the modifier keys and also determine the 
   274  * correct side of the key.
   275  */
   276 static void
   277 DoSidedModifiers(int keyboard, unsigned short scancode,
   278                  unsigned int oldMods, unsigned int newMods)
   279 {
   280 	/* Set up arrays for the key syms for the left and right side. */
   281     const SDL_scancode left_mapping[]  = {
   282         SDL_SCANCODE_LSHIFT,
   283         SDL_SCANCODE_LCTRL,
   284         SDL_SCANCODE_LALT,
   285         SDL_SCANCODE_LGUI
   286     };
   287     const SDL_scancode right_mapping[] = {
   288         SDL_SCANCODE_RSHIFT,
   289         SDL_SCANCODE_RCTRL,
   290         SDL_SCANCODE_RALT,
   291         SDL_SCANCODE_RGUI
   292     };
   293 	/* Set up arrays for the device dependent masks with indices that 
   294      * correspond to the _mapping arrays 
   295      */
   296     const unsigned int left_device_mapping[]  = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK };
   297     const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK };
   298 
   299     unsigned int i, bit;
   300 
   301     /* Handle CAPSLOCK separately because it doesn't have a left/right side */
   302     HandleCapsLock(keyboard, scancode, oldMods, newMods);
   303 
   304     /* Iterate through the bits, testing each against the old modifiers */
   305     for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
   306         unsigned int oldMask, newMask;
   307 		
   308         oldMask = oldMods & bit;
   309         newMask = newMods & bit;
   310 		
   311         /* If the bit is set, we must always examine it because the left
   312          * and right side keys may alternate or both may be pressed.
   313          */
   314         if (newMask) {
   315             HandleModifierSide(keyboard, bit, oldMods, newMods,
   316                                left_mapping[i], right_mapping[i],
   317                                left_device_mapping[i], right_device_mapping[i]);
   318         }
   319         /* If the state changed from pressed to unpressed, we must examine
   320             * the device dependent bits to release the correct keys.
   321             */
   322         else if (oldMask && oldMask != newMask) {
   323             ReleaseModifierSide(keyboard, bit, oldMods, newMods,
   324                               left_mapping[i], right_mapping[i],
   325                               left_device_mapping[i], right_device_mapping[i]);
   326         }
   327     }
   328 }
   329 
   330 static void
   331 HandleModifiers(_THIS, unsigned short scancode, unsigned int modifierFlags)
   332 {
   333     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   334 
   335     if (modifierFlags == data->modifierFlags) {
   336     	return;
   337     }
   338 
   339     /* 
   340      * Starting with Panther (10.3.0), the ability to distinguish between 
   341      * left side and right side modifiers is available.
   342      */
   343     if (data->osversion >= 0x1030) {
   344         DoSidedModifiers(data->keyboard, scancode, data->modifierFlags, modifierFlags);
   345     } else {
   346         DoUnsidedModifiers(data->keyboard, scancode, data->modifierFlags, modifierFlags);
   347     }
   348     data->modifierFlags = modifierFlags;
   349 }
   350 
   351 static void
   352 UpdateKeymap(SDL_VideoData *data)
   353 {
   354     KeyboardLayoutRef key_layout;
   355     const void *chr_data;
   356     int i;
   357     SDL_scancode scancode;
   358     SDLKey keymap[SDL_NUM_SCANCODES];
   359 
   360     /* See if the keymap needs to be updated */
   361     KLGetCurrentKeyboardLayout(&key_layout);
   362     if (key_layout == data->key_layout) {
   363         return;
   364     }
   365     data->key_layout = key_layout;
   366 
   367     SDL_GetDefaultKeymap(keymap);
   368 
   369     /* Try Unicode data first (preferred as of Mac OS X 10.5) */
   370     KLGetKeyboardLayoutProperty(key_layout, kKLuchrData, &chr_data);
   371     if (chr_data) {
   372         UInt32 keyboard_type = LMGetKbdType();
   373         OSStatus err;
   374 
   375         for (i = 0; i < SDL_arraysize(darwin_scancode_table); i++) {
   376             UniChar s[8];
   377             UniCharCount len;
   378             UInt32 dead_key_state;
   379 
   380             /* Make sure this scancode is a valid character scancode */
   381             scancode = darwin_scancode_table[i];
   382             if (scancode == SDL_SCANCODE_UNKNOWN ||
   383                 (keymap[scancode] & SDLK_SCANCODE_MASK)) {
   384                 continue;
   385             }
   386 
   387             dead_key_state = 0;
   388             err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
   389                                   0, keyboard_type,
   390                                   kUCKeyTranslateNoDeadKeysMask,
   391                                   &dead_key_state, 8, &len, s);
   392             if (err != noErr)
   393                 continue;
   394 
   395             if (len > 0 && s[0] != 0x10) {
   396                 keymap[scancode] = s[0];
   397             }
   398         }
   399         SDL_SetKeymap(data->keyboard, 0, keymap, SDL_NUM_SCANCODES);
   400         return;
   401     }
   402 
   403     /* Fall back to older style key map data */
   404     KLGetKeyboardLayoutProperty(key_layout, kKLKCHRData, &chr_data);
   405     if (chr_data) {
   406         for (i = 0; i < 128; i++) {
   407             UInt32 c, state = 0;
   408 
   409             /* Make sure this scancode is a valid character scancode */
   410             scancode = darwin_scancode_table[i];
   411             if (scancode == SDL_SCANCODE_UNKNOWN ||
   412                 (keymap[scancode] & SDLK_SCANCODE_MASK)) {
   413                 continue;
   414             }
   415 
   416             c = KeyTranslate (chr_data, i, &state) & 255;
   417             if (state) {
   418                 /* Dead key, process key up */
   419                 c = KeyTranslate (chr_data, i | 128, &state) & 255;
   420             }
   421 
   422             if (c != 0 && c != 0x10) {
   423                 /* MacRoman to Unicode table, taken from X.org sources */
   424                 static const unsigned short macroman_table[128] = {
   425                     0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
   426                     0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
   427                     0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
   428                     0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
   429                     0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
   430                     0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
   431                     0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
   432                     0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
   433                     0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
   434                     0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
   435                     0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
   436                     0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
   437                     0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
   438                     0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
   439                     0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
   440                     0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7,
   441                 };
   442 
   443                 if (c >= 128) {
   444                     c = macroman_table[c - 128];
   445                 }
   446                 keymap[scancode] = c;
   447             }
   448         }
   449         SDL_SetKeymap(data->keyboard, 0, keymap, SDL_NUM_SCANCODES);
   450         return;
   451     }
   452 }
   453 
   454 void
   455 Cocoa_InitKeyboard(_THIS)
   456 {
   457     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   458     SDL_Keyboard keyboard;
   459     NSAutoreleasePool *pool;
   460 
   461     pool = [[NSAutoreleasePool alloc] init];
   462     data->fieldEdit = [[SDLTranslatorResponder alloc] initWithFrame:NSMakeRect(0.0, 0.0, 0.0, 0.0)];
   463     [pool release];
   464     
   465     SDL_zero(keyboard);
   466     data->keyboard = SDL_AddKeyboard(&keyboard, -1);
   467     UpdateKeymap(data);
   468     
   469     /* Set our own names for the platform-dependent but layout-independent keys */
   470     /* This key is NumLock on the MacBook keyboard. :) */
   471     /*SDL_SetScancodeName(SDL_SCANCODE_NUMLOCKCLEAR, "Clear");*/
   472     SDL_SetScancodeName(SDL_SCANCODE_LALT, "Left Option");
   473     SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Command");
   474     SDL_SetScancodeName(SDL_SCANCODE_RALT, "Right Option");
   475     SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Command");
   476 }
   477 
   478 void
   479 Cocoa_HandleKeyEvent(_THIS, NSEvent *event)
   480 {
   481     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   482     unsigned short scancode = [event keyCode];
   483     SDL_scancode code;
   484     const char *text;
   485 
   486     if ((scancode == 10 || scancode == 50) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) {
   487         /* see comments in SDL_cocoakeys.h */
   488         scancode = 60 - scancode;
   489     }
   490     if (scancode < SDL_arraysize(darwin_scancode_table)) {
   491         code = darwin_scancode_table[scancode];
   492     }
   493     else {
   494         /* Hmm, does this ever happen?  If so, need to extend the keymap... */
   495         code = SDL_SCANCODE_UNKNOWN;
   496     }
   497 
   498     switch ([event type]) {
   499     case NSKeyDown:
   500         if (![event isARepeat]) {
   501             /* See if we need to rebuild the keyboard layout */
   502             UpdateKeymap(data);
   503 
   504             SDL_SendKeyboardKey(data->keyboard, SDL_PRESSED, code);
   505 #if 1
   506             if (code == SDL_SCANCODE_UNKNOWN) {
   507                 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);
   508             }
   509 #endif
   510         }
   511         if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
   512             /* 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. */
   513             [data->fieldEdit interpretKeyEvents:[NSArray arrayWithObject:event]];
   514             text = [[event characters] UTF8String];
   515             if(text && *text) {
   516                 SDL_SendKeyboardText(data->keyboard, text);
   517                 [data->fieldEdit setString:@""];
   518             }
   519         }
   520         break;
   521     case NSKeyUp:
   522         SDL_SendKeyboardKey(data->keyboard, SDL_RELEASED, code);
   523         break;
   524     case NSFlagsChanged:
   525         /* FIXME CW 2007-08-14: check if this whole mess that takes up half of this file is really necessary */
   526         HandleModifiers(_this, scancode, [event modifierFlags]);
   527         break;
   528     default: /* just to avoid compiler warnings */
   529         break;
   530     }
   531 }
   532 
   533 void
   534 Cocoa_QuitKeyboard(_THIS)
   535 {
   536     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   537     NSAutoreleasePool *pool;
   538 
   539     SDL_DelKeyboard(data->keyboard);
   540 
   541     pool = [[NSAutoreleasePool alloc] init];
   542     [data->fieldEdit release];
   543     [pool release];
   544 }
   545 
   546 /* vi: set ts=4 sw=4 expandtab: */