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