src/video/cocoa/SDL_cocoakeyboard.m
author Sam Lantinga <slouken@libsdl.org>
Tue, 27 Oct 2015 11:17:32 -0700
changeset 9898 0da384bef562
parent 9619 b94b6d0bff0f
child 9915 77cf2d1b7215
permissions -rw-r--r--
Add a new SDL_KEYMAPCHANGED SDL event to abstract notification of keyboard layout or input language changes.
slouken@1931
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9619
     3
  Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
slouken@1931
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1931
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1931
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1931
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@1931
    22
slouken@6044
    23
#if SDL_VIDEO_DRIVER_COCOA
slouken@6044
    24
slouken@1931
    25
#include "SDL_cocoavideo.h"
slouken@1931
    26
slouken@1931
    27
#include "../../events/SDL_keyboard_c.h"
slouken@2305
    28
#include "../../events/scancodes_darwin.h"
slouken@1931
    29
slouken@2268
    30
#include <Carbon/Carbon.h>
slouken@2268
    31
slouken@7191
    32
/*#define DEBUG_IME NSLog */
slouken@6044
    33
#define DEBUG_IME(...)
slouken@1959
    34
slouken@8986
    35
@interface SDLTranslatorResponder : NSView <NSTextInput> {
slouken@3280
    36
    NSString *_markedText;
slouken@3280
    37
    NSRange   _markedRange;
slouken@3280
    38
    NSRange   _selectedRange;
slouken@3280
    39
    SDL_Rect  _inputRect;
slouken@2289
    40
}
slouken@2289
    41
- (void) doCommandBySelector:(SEL)myselector;
slouken@3280
    42
- (void) setInputRect:(SDL_Rect *) rect;
slouken@2289
    43
@end
slouken@2289
    44
slouken@2289
    45
@implementation SDLTranslatorResponder
slouken@3280
    46
slouken@3280
    47
- (void) setInputRect:(SDL_Rect *) rect
slouken@3280
    48
{
slouken@3280
    49
    _inputRect = *rect;
slouken@3280
    50
}
slouken@3280
    51
slouken@3280
    52
- (void) insertText:(id) aString
slouken@3280
    53
{
slouken@3280
    54
    const char *str;
slouken@3280
    55
slouken@3280
    56
    DEBUG_IME(@"insertText: %@", aString);
slouken@3280
    57
slouken@3280
    58
    /* Could be NSString or NSAttributedString, so we have
slouken@3280
    59
     * to test and convert it before return as SDL event */
slouken@8986
    60
    if ([aString isKindOfClass: [NSAttributedString class]]) {
slouken@3280
    61
        str = [[aString string] UTF8String];
slouken@8986
    62
    } else {
slouken@3280
    63
        str = [aString UTF8String];
slouken@8986
    64
    }
slouken@3280
    65
slouken@4465
    66
    SDL_SendKeyboardText(str);
slouken@3280
    67
}
slouken@3280
    68
slouken@3280
    69
- (void) doCommandBySelector:(SEL) myselector
slouken@3280
    70
{
slouken@7191
    71
    /* No need to do anything since we are not using Cocoa
slouken@7191
    72
       selectors to handle special keys, instead we use SDL
slouken@7191
    73
       key events to do the same job.
slouken@7191
    74
    */
slouken@3280
    75
}
slouken@3280
    76
slouken@3280
    77
- (BOOL) hasMarkedText
slouken@3280
    78
{
slouken@3280
    79
    return _markedText != nil;
slouken@3280
    80
}
slouken@3280
    81
slouken@3280
    82
- (NSRange) markedRange
slouken@3280
    83
{
slouken@3280
    84
    return _markedRange;
slouken@3280
    85
}
slouken@3280
    86
slouken@3280
    87
- (NSRange) selectedRange
slouken@3280
    88
{
slouken@3280
    89
    return _selectedRange;
slouken@3280
    90
}
slouken@3280
    91
slouken@3280
    92
- (void) setMarkedText:(id) aString
slouken@3280
    93
         selectedRange:(NSRange) selRange
slouken@3280
    94
{
slouken@8986
    95
    if ([aString isKindOfClass: [NSAttributedString class]]) {
slouken@3280
    96
        aString = [aString string];
slouken@8986
    97
    }
slouken@3280
    98
slouken@8986
    99
    if ([aString length] == 0) {
slouken@3280
   100
        [self unmarkText];
slouken@3280
   101
        return;
slouken@3280
   102
    }
slouken@3280
   103
slouken@8986
   104
    if (_markedText != aString) {
slouken@3280
   105
        [_markedText release];
slouken@3280
   106
        _markedText = [aString retain];
slouken@3280
   107
    }
slouken@3280
   108
slouken@3280
   109
    _selectedRange = selRange;
slouken@3280
   110
    _markedRange = NSMakeRange(0, [aString length]);
slouken@3280
   111
slouken@4465
   112
    SDL_SendEditingText([aString UTF8String],
slouken@4434
   113
                        selRange.location, selRange.length);
slouken@3280
   114
slouken@3280
   115
    DEBUG_IME(@"setMarkedText: %@, (%d, %d)", _markedText,
slouken@3280
   116
          selRange.location, selRange.length);
slouken@3280
   117
}
slouken@3280
   118
slouken@3280
   119
- (void) unmarkText
slouken@3280
   120
{
slouken@3280
   121
    [_markedText release];
slouken@3280
   122
    _markedText = nil;
gzjjgod@4637
   123
gzjjgod@4637
   124
    SDL_SendEditingText("", 0, 0);
slouken@3280
   125
}
slouken@3280
   126
slouken@3280
   127
- (NSRect) firstRectForCharacterRange: (NSRange) theRange
slouken@3280
   128
{
slouken@4436
   129
    NSWindow *window = [self window];
slouken@4436
   130
    NSRect contentRect = [window contentRectForFrameRect: [window frame]];
slouken@4436
   131
    float windowHeight = contentRect.size.height;
slouken@3280
   132
    NSRect rect = NSMakeRect(_inputRect.x, windowHeight - _inputRect.y - _inputRect.h,
slouken@3280
   133
                             _inputRect.w, _inputRect.h);
slouken@3280
   134
slouken@3280
   135
    DEBUG_IME(@"firstRectForCharacterRange: (%d, %d): windowHeight = %g, rect = %@",
slouken@3280
   136
            theRange.location, theRange.length, windowHeight,
slouken@3280
   137
            NSStringFromRect(rect));
slouken@3280
   138
    rect.origin = [[self window] convertBaseToScreen: rect.origin];
slouken@3280
   139
slouken@3280
   140
    return rect;
slouken@3280
   141
}
slouken@3280
   142
slouken@3280
   143
- (NSAttributedString *) attributedSubstringFromRange: (NSRange) theRange
slouken@3280
   144
{
slouken@3280
   145
    DEBUG_IME(@"attributedSubstringFromRange: (%d, %d)", theRange.location, theRange.length);
slouken@3280
   146
    return nil;
slouken@3280
   147
}
slouken@3280
   148
slouken@4925
   149
- (NSInteger) conversationIdentifier
slouken@3280
   150
{
jorgen@7507
   151
    return (NSInteger) self;
slouken@3280
   152
}
slouken@3280
   153
slouken@7191
   154
/* This method returns the index for character that is
slouken@7191
   155
 * nearest to thePoint.  thPoint is in screen coordinate system.
slouken@7191
   156
 */
slouken@3280
   157
- (NSUInteger) characterIndexForPoint:(NSPoint) thePoint
slouken@3280
   158
{
slouken@3280
   159
    DEBUG_IME(@"characterIndexForPoint: (%g, %g)", thePoint.x, thePoint.y);
slouken@3280
   160
    return 0;
slouken@3280
   161
}
slouken@3280
   162
slouken@7191
   163
/* This method is the key to attribute extension.
slouken@7191
   164
 * We could add new attributes through this method.
slouken@7191
   165
 * NSInputServer examines the return value of this
slouken@7191
   166
 * method & constructs appropriate attributed string.
slouken@7191
   167
 */
slouken@3280
   168
- (NSArray *) validAttributesForMarkedText
slouken@3280
   169
{
slouken@3280
   170
    return [NSArray array];
slouken@3280
   171
}
slouken@3280
   172
slouken@2289
   173
@end
slouken@2289
   174
slouken@7191
   175
/* This is a helper function for HandleModifierSide. This
slouken@1959
   176
 * function reverts back to behavior before the distinction between
slouken@1959
   177
 * sides was made.
slouken@1959
   178
 */
slouken@1959
   179
static void
slouken@4465
   180
HandleNonDeviceModifier(unsigned int device_independent_mask,
slouken@1959
   181
                        unsigned int oldMods,
slouken@1959
   182
                        unsigned int newMods,
slouken@5218
   183
                        SDL_Scancode scancode)
slouken@1959
   184
{
slouken@1959
   185
    unsigned int oldMask, newMask;
slouken@7191
   186
slouken@7191
   187
    /* Isolate just the bits we care about in the depedent bits so we can
slouken@1959
   188
     * figure out what changed
slouken@7191
   189
     */
slouken@1959
   190
    oldMask = oldMods & device_independent_mask;
slouken@1959
   191
    newMask = newMods & device_independent_mask;
slouken@7191
   192
slouken@1959
   193
    if (oldMask && oldMask != newMask) {
slouken@4465
   194
        SDL_SendKeyboardKey(SDL_RELEASED, scancode);
slouken@1959
   195
    } else if (newMask && oldMask != newMask) {
slouken@4465
   196
        SDL_SendKeyboardKey(SDL_PRESSED, scancode);
slouken@1959
   197
    }
slouken@1959
   198
}
slouken@1959
   199
slouken@7191
   200
/* This is a helper function for HandleModifierSide.
slouken@1959
   201
 * This function sets the actual SDL_PrivateKeyboard event.
slouken@1959
   202
 */
slouken@1959
   203
static void
slouken@4465
   204
HandleModifierOneSide(unsigned int oldMods, unsigned int newMods,
slouken@7191
   205
                      SDL_Scancode scancode,
slouken@1959
   206
                      unsigned int sided_device_dependent_mask)
slouken@1959
   207
{
slouken@1959
   208
    unsigned int old_dep_mask, new_dep_mask;
slouken@1959
   209
slouken@7191
   210
    /* Isolate just the bits we care about in the depedent bits so we can
slouken@1959
   211
     * figure out what changed
slouken@7191
   212
     */
slouken@1959
   213
    old_dep_mask = oldMods & sided_device_dependent_mask;
slouken@1959
   214
    new_dep_mask = newMods & sided_device_dependent_mask;
slouken@1959
   215
slouken@1959
   216
    /* We now know that this side bit flipped. But we don't know if
slouken@7191
   217
     * it went pressed to released or released to pressed, so we must
slouken@1959
   218
     * find out which it is.
slouken@1959
   219
     */
slouken@1959
   220
    if (new_dep_mask && old_dep_mask != new_dep_mask) {
slouken@4465
   221
        SDL_SendKeyboardKey(SDL_PRESSED, scancode);
slouken@1959
   222
    } else {
slouken@4465
   223
        SDL_SendKeyboardKey(SDL_RELEASED, scancode);
slouken@1959
   224
    }
slouken@1959
   225
}
slouken@1959
   226
slouken@1959
   227
/* This is a helper function for DoSidedModifiers.
slouken@7191
   228
 * This function will figure out if the modifier key is the left or right side,
slouken@7191
   229
 * e.g. left-shift vs right-shift.
slouken@1959
   230
 */
slouken@1959
   231
static void
slouken@7191
   232
HandleModifierSide(int device_independent_mask,
slouken@7191
   233
                   unsigned int oldMods, unsigned int newMods,
slouken@7191
   234
                   SDL_Scancode left_scancode,
slouken@5218
   235
                   SDL_Scancode right_scancode,
slouken@7191
   236
                   unsigned int left_device_dependent_mask,
slouken@1959
   237
                   unsigned int right_device_dependent_mask)
slouken@1959
   238
{
slouken@1959
   239
    unsigned int device_dependent_mask = (left_device_dependent_mask |
slouken@1959
   240
                                         right_device_dependent_mask);
slouken@1959
   241
    unsigned int diff_mod;
slouken@7191
   242
slouken@7191
   243
    /* On the basis that the device independent mask is set, but there are
slouken@7191
   244
     * no device dependent flags set, we'll assume that we can't detect this
slouken@1959
   245
     * keyboard and revert to the unsided behavior.
slouken@1959
   246
     */
slouken@1959
   247
    if ((device_dependent_mask & newMods) == 0) {
slouken@1959
   248
        /* Revert to the old behavior */
slouken@4465
   249
        HandleNonDeviceModifier(device_independent_mask, oldMods, newMods, left_scancode);
slouken@1959
   250
        return;
slouken@1959
   251
    }
slouken@1959
   252
slouken@1959
   253
    /* XOR the previous state against the new state to see if there's a change */
slouken@1959
   254
    diff_mod = (device_dependent_mask & oldMods) ^
slouken@1959
   255
               (device_dependent_mask & newMods);
slouken@1959
   256
    if (diff_mod) {
slouken@7191
   257
        /* A change in state was found. Isolate the left and right bits
slouken@1959
   258
         * to handle them separately just in case the values can simulataneously
slouken@1959
   259
         * change or if the bits don't both exist.
slouken@1959
   260
         */
slouken@1959
   261
        if (left_device_dependent_mask & diff_mod) {
slouken@4465
   262
            HandleModifierOneSide(oldMods, newMods, left_scancode, left_device_dependent_mask);
slouken@1959
   263
        }
slouken@1959
   264
        if (right_device_dependent_mask & diff_mod) {
slouken@4465
   265
            HandleModifierOneSide(oldMods, newMods, right_scancode, right_device_dependent_mask);
slouken@1959
   266
        }
slouken@1959
   267
    }
slouken@1959
   268
}
slouken@7191
   269
slouken@1959
   270
/* This is a helper function for DoSidedModifiers.
slouken@7191
   271
 * This function will release a key press in the case that
slouken@7191
   272
 * it is clear that the modifier has been released (i.e. one side
slouken@1959
   273
 * can't still be down).
slouken@1959
   274
 */
slouken@1959
   275
static void
slouken@7191
   276
ReleaseModifierSide(unsigned int device_independent_mask,
slouken@1959
   277
                    unsigned int oldMods, unsigned int newMods,
slouken@7191
   278
                    SDL_Scancode left_scancode,
slouken@5218
   279
                    SDL_Scancode right_scancode,
slouken@7191
   280
                    unsigned int left_device_dependent_mask,
slouken@1959
   281
                    unsigned int right_device_dependent_mask)
slouken@1959
   282
{
slouken@1959
   283
    unsigned int device_dependent_mask = (left_device_dependent_mask |
slouken@1959
   284
                                          right_device_dependent_mask);
slouken@1959
   285
slouken@7191
   286
    /* On the basis that the device independent mask is set, but there are
slouken@7191
   287
     * no device dependent flags set, we'll assume that we can't detect this
slouken@1959
   288
     * keyboard and revert to the unsided behavior.
slouken@1959
   289
     */
slouken@1959
   290
    if ((device_dependent_mask & oldMods) == 0) {
slouken@7191
   291
        /* In this case, we can't detect the keyboard, so use the left side
slouken@7191
   292
         * to represent both, and release it.
slouken@1959
   293
         */
slouken@4465
   294
        SDL_SendKeyboardKey(SDL_RELEASED, left_scancode);
slouken@1959
   295
        return;
slouken@1959
   296
    }
slouken@1959
   297
slouken@7191
   298
    /*
slouken@1959
   299
     * This could have been done in an if-else case because at this point,
slouken@7191
   300
     * we know that all keys have been released when calling this function.
slouken@1959
   301
     * But I'm being paranoid so I want to handle each separately,
slouken@1959
   302
     * so I hope this doesn't cause other problems.
slouken@1959
   303
     */
slouken@1959
   304
    if ( left_device_dependent_mask & oldMods ) {
slouken@4465
   305
        SDL_SendKeyboardKey(SDL_RELEASED, left_scancode);
slouken@1959
   306
    }
slouken@1959
   307
    if ( right_device_dependent_mask & oldMods ) {
slouken@4465
   308
        SDL_SendKeyboardKey(SDL_RELEASED, right_scancode);
slouken@1959
   309
    }
slouken@1959
   310
}
slouken@1959
   311
slouken@1959
   312
/* This is a helper function for DoSidedModifiers.
slouken@1959
   313
 * This function handles the CapsLock case.
slouken@1959
   314
 */
slouken@1959
   315
static void
slouken@4465
   316
HandleCapsLock(unsigned short scancode,
slouken@1959
   317
               unsigned int oldMods, unsigned int newMods)
slouken@1959
   318
{
slouken@1959
   319
    unsigned int oldMask, newMask;
slouken@7191
   320
slouken@1959
   321
    oldMask = oldMods & NSAlphaShiftKeyMask;
slouken@1959
   322
    newMask = newMods & NSAlphaShiftKeyMask;
slouken@1959
   323
slouken@1959
   324
    if (oldMask != newMask) {
slouken@4465
   325
        SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_CAPSLOCK);
slouken@4465
   326
        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_CAPSLOCK);
slouken@1959
   327
    }
slouken@1959
   328
}
slouken@1959
   329
slouken@7191
   330
/* This function will handle the modifier keys and also determine the
slouken@1959
   331
 * correct side of the key.
slouken@1959
   332
 */
slouken@1959
   333
static void
slouken@4465
   334
DoSidedModifiers(unsigned short scancode,
slouken@1959
   335
                 unsigned int oldMods, unsigned int newMods)
slouken@1959
   336
{
slouken@7191
   337
    /* Set up arrays for the key syms for the left and right side. */
slouken@5218
   338
    const SDL_Scancode left_mapping[]  = {
slouken@2303
   339
        SDL_SCANCODE_LSHIFT,
slouken@2303
   340
        SDL_SCANCODE_LCTRL,
slouken@2303
   341
        SDL_SCANCODE_LALT,
slouken@2303
   342
        SDL_SCANCODE_LGUI
slouken@2303
   343
    };
slouken@5218
   344
    const SDL_Scancode right_mapping[] = {
slouken@2303
   345
        SDL_SCANCODE_RSHIFT,
slouken@2303
   346
        SDL_SCANCODE_RCTRL,
slouken@2303
   347
        SDL_SCANCODE_RALT,
slouken@2303
   348
        SDL_SCANCODE_RGUI
slouken@2303
   349
    };
slouken@7191
   350
    /* Set up arrays for the device dependent masks with indices that
slouken@7191
   351
     * correspond to the _mapping arrays
slouken@1959
   352
     */
slouken@1959
   353
    const unsigned int left_device_mapping[]  = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK };
slouken@1959
   354
    const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK };
slouken@1959
   355
slouken@1959
   356
    unsigned int i, bit;
slouken@1959
   357
slouken@1959
   358
    /* Handle CAPSLOCK separately because it doesn't have a left/right side */
slouken@4465
   359
    HandleCapsLock(scancode, oldMods, newMods);
slouken@1959
   360
slouken@1959
   361
    /* Iterate through the bits, testing each against the old modifiers */
slouken@1959
   362
    for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
slouken@1959
   363
        unsigned int oldMask, newMask;
slouken@7191
   364
slouken@1959
   365
        oldMask = oldMods & bit;
slouken@1959
   366
        newMask = newMods & bit;
slouken@7191
   367
slouken@1959
   368
        /* If the bit is set, we must always examine it because the left
slouken@1959
   369
         * and right side keys may alternate or both may be pressed.
slouken@1959
   370
         */
slouken@1959
   371
        if (newMask) {
slouken@4465
   372
            HandleModifierSide(bit, oldMods, newMods,
slouken@1959
   373
                               left_mapping[i], right_mapping[i],
slouken@1959
   374
                               left_device_mapping[i], right_device_mapping[i]);
slouken@1959
   375
        }
slouken@1959
   376
        /* If the state changed from pressed to unpressed, we must examine
slouken@1959
   377
            * the device dependent bits to release the correct keys.
slouken@1959
   378
            */
slouken@1959
   379
        else if (oldMask && oldMask != newMask) {
slouken@4465
   380
            ReleaseModifierSide(bit, oldMods, newMods,
slouken@1959
   381
                              left_mapping[i], right_mapping[i],
slouken@1959
   382
                              left_device_mapping[i], right_device_mapping[i]);
slouken@1959
   383
        }
slouken@1959
   384
    }
slouken@1959
   385
}
slouken@1959
   386
slouken@1959
   387
static void
slouken@1959
   388
HandleModifiers(_THIS, unsigned short scancode, unsigned int modifierFlags)
slouken@1959
   389
{
slouken@1959
   390
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
slouken@1959
   391
slouken@1959
   392
    if (modifierFlags == data->modifierFlags) {
slouken@7191
   393
        return;
slouken@1959
   394
    }
slouken@1959
   395
slouken@7947
   396
    DoSidedModifiers(scancode, data->modifierFlags, modifierFlags);
slouken@1959
   397
    data->modifierFlags = modifierFlags;
slouken@1959
   398
}
slouken@1959
   399
slouken@2303
   400
static void
slouken@9898
   401
UpdateKeymap(SDL_VideoData *data, SDL_bool send_event)
slouken@2303
   402
{
slouken@3247
   403
    TISInputSourceRef key_layout;
slouken@2303
   404
    const void *chr_data;
slouken@2303
   405
    int i;
slouken@5218
   406
    SDL_Scancode scancode;
slouken@5220
   407
    SDL_Keycode keymap[SDL_NUM_SCANCODES];
slouken@2303
   408
slouken@2303
   409
    /* See if the keymap needs to be updated */
slouken@3247
   410
    key_layout = TISCopyCurrentKeyboardLayoutInputSource();
slouken@2303
   411
    if (key_layout == data->key_layout) {
slouken@2303
   412
        return;
slouken@2303
   413
    }
slouken@2303
   414
    data->key_layout = key_layout;
slouken@2303
   415
slouken@2303
   416
    SDL_GetDefaultKeymap(keymap);
slouken@2303
   417
jorgen@7507
   418
    /* Try Unicode data first */
slouken@3247
   419
    CFDataRef uchrDataRef = TISGetInputSourceProperty(key_layout, kTISPropertyUnicodeKeyLayoutData);
slouken@8986
   420
    if (uchrDataRef) {
slouken@3247
   421
        chr_data = CFDataGetBytePtr(uchrDataRef);
slouken@8986
   422
    } else {
slouken@3247
   423
        goto cleanup;
slouken@8986
   424
    }
jorgen@7507
   425
slouken@2303
   426
    if (chr_data) {
slouken@2303
   427
        UInt32 keyboard_type = LMGetKbdType();
slouken@2303
   428
        OSStatus err;
slouken@2303
   429
slouken@2305
   430
        for (i = 0; i < SDL_arraysize(darwin_scancode_table); i++) {
slouken@2303
   431
            UniChar s[8];
slouken@2303
   432
            UniCharCount len;
slouken@2303
   433
            UInt32 dead_key_state;
slouken@2303
   434
slouken@2303
   435
            /* Make sure this scancode is a valid character scancode */
slouken@2305
   436
            scancode = darwin_scancode_table[i];
slouken@2303
   437
            if (scancode == SDL_SCANCODE_UNKNOWN ||
slouken@2303
   438
                (keymap[scancode] & SDLK_SCANCODE_MASK)) {
slouken@2303
   439
                continue;
slouken@2303
   440
            }
slouken@2303
   441
slouken@2303
   442
            dead_key_state = 0;
slouken@3247
   443
            err = UCKeyTranslate ((UCKeyboardLayout *) chr_data,
slouken@3247
   444
                                  i, kUCKeyActionDown,
slouken@2303
   445
                                  0, keyboard_type,
slouken@2303
   446
                                  kUCKeyTranslateNoDeadKeysMask,
slouken@2303
   447
                                  &dead_key_state, 8, &len, s);
slouken@8986
   448
            if (err != noErr) {
slouken@2303
   449
                continue;
slouken@8986
   450
            }
slouken@2303
   451
slouken@2303
   452
            if (len > 0 && s[0] != 0x10) {
slouken@2303
   453
                keymap[scancode] = s[0];
slouken@2303
   454
            }
slouken@2303
   455
        }
slouken@4465
   456
        SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
slouken@9898
   457
        if (send_event) {
slouken@9898
   458
            SDL_SendKeymapChangedEvent();
slouken@9898
   459
        }
slouken@2303
   460
        return;
slouken@2303
   461
    }
slouken@2303
   462
slouken@3247
   463
cleanup:
slouken@3247
   464
    CFRelease(key_layout);
slouken@2303
   465
}
slouken@2303
   466
slouken@1931
   467
void
slouken@1931
   468
Cocoa_InitKeyboard(_THIS)
slouken@1931
   469
{
slouken@1931
   470
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
slouken@1931
   471
slouken@9898
   472
    UpdateKeymap(data, SDL_FALSE);
slouken@7191
   473
slouken@2268
   474
    /* Set our own names for the platform-dependent but layout-independent keys */
slouken@2303
   475
    /* This key is NumLock on the MacBook keyboard. :) */
slouken@2303
   476
    /*SDL_SetScancodeName(SDL_SCANCODE_NUMLOCKCLEAR, "Clear");*/
slouken@2303
   477
    SDL_SetScancodeName(SDL_SCANCODE_LALT, "Left Option");
slouken@2303
   478
    SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Command");
slouken@2303
   479
    SDL_SetScancodeName(SDL_SCANCODE_RALT, "Right Option");
slouken@2303
   480
    SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Command");
slouken@1931
   481
}
slouken@1931
   482
slouken@1931
   483
void
slouken@3280
   484
Cocoa_StartTextInput(_THIS)
slouken@9087
   485
{ @autoreleasepool
slouken@3280
   486
{
slouken@3280
   487
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
jorgen@8141
   488
    SDL_Window *window = SDL_GetKeyboardFocus();
jorgen@8141
   489
    NSWindow *nswindow = nil;
slouken@8986
   490
    if (window) {
jorgen@8141
   491
        nswindow = ((SDL_WindowData*)window->driverdata)->nswindow;
slouken@8986
   492
    }
jorgen@8141
   493
jorgen@8141
   494
    NSView *parentView = [nswindow contentView];
slouken@3280
   495
slouken@6848
   496
    /* We only keep one field editor per process, since only the front most
slouken@6848
   497
     * window can receive text input events, so it make no sense to keep more
slouken@6848
   498
     * than one copy. When we switched to another window and requesting for
slouken@6848
   499
     * text input, simply remove the field editor from its superview then add
slouken@6848
   500
     * it to the front most window's content view */
slouken@6848
   501
    if (!data->fieldEdit) {
slouken@6848
   502
        data->fieldEdit =
slouken@6848
   503
            [[SDLTranslatorResponder alloc] initWithFrame: NSMakeRect(0.0, 0.0, 0.0, 0.0)];
slouken@6848
   504
    }
alexey@6832
   505
slouken@8986
   506
    if (![[data->fieldEdit superview] isEqual: parentView]) {
slouken@7191
   507
        /* DEBUG_IME(@"add fieldEdit to window contentView"); */
slouken@6848
   508
        [data->fieldEdit removeFromSuperview];
slouken@6848
   509
        [parentView addSubview: data->fieldEdit];
jorgen@8141
   510
        [nswindow makeFirstResponder: data->fieldEdit];
slouken@4435
   511
    }
slouken@9087
   512
}}
slouken@3280
   513
slouken@3280
   514
void
slouken@3280
   515
Cocoa_StopTextInput(_THIS)
slouken@9087
   516
{ @autoreleasepool
slouken@3280
   517
{
slouken@3280
   518
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
slouken@3280
   519
slouken@3683
   520
    if (data && data->fieldEdit) {
slouken@6848
   521
        [data->fieldEdit removeFromSuperview];
slouken@6848
   522
        [data->fieldEdit release];
slouken@6848
   523
        data->fieldEdit = nil;
slouken@3683
   524
    }
slouken@9087
   525
}}
slouken@3280
   526
slouken@3280
   527
void
slouken@3280
   528
Cocoa_SetTextInputRect(_THIS, SDL_Rect *rect)
slouken@3280
   529
{
slouken@3280
   530
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
slouken@3280
   531
aschiffler@6808
   532
    if (!rect) {
slouken@8986
   533
        SDL_InvalidParamError("rect");
slouken@8986
   534
        return;
aschiffler@6808
   535
    }
aschiffler@6808
   536
slouken@3280
   537
    [data->fieldEdit setInputRect: rect];
slouken@3280
   538
}
slouken@3280
   539
slouken@3280
   540
void
slouken@1959
   541
Cocoa_HandleKeyEvent(_THIS, NSEvent *event)
slouken@1959
   542
{
slouken@1959
   543
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
icculus@8862
   544
    if (!data) {
icculus@8862
   545
        return;  /* can happen when returning from fullscreen Space on shutdown */
icculus@8862
   546
    }
icculus@8862
   547
slouken@1959
   548
    unsigned short scancode = [event keyCode];
slouken@5218
   549
    SDL_Scancode code;
slouken@4465
   550
#if 0
slouken@1959
   551
    const char *text;
slouken@4465
   552
#endif
slouken@1959
   553
slouken@2268
   554
    if ((scancode == 10 || scancode == 50) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) {
slouken@2268
   555
        /* see comments in SDL_cocoakeys.h */
slouken@2268
   556
        scancode = 60 - scancode;
slouken@2268
   557
    }
slouken@8986
   558
slouken@2305
   559
    if (scancode < SDL_arraysize(darwin_scancode_table)) {
slouken@2305
   560
        code = darwin_scancode_table[scancode];
slouken@8986
   561
    } else {
slouken@1959
   562
        /* Hmm, does this ever happen?  If so, need to extend the keymap... */
slouken@2303
   563
        code = SDL_SCANCODE_UNKNOWN;
slouken@1959
   564
    }
slouken@1959
   565
slouken@1959
   566
    switch ([event type]) {
slouken@1959
   567
    case NSKeyDown:
slouken@2129
   568
        if (![event isARepeat]) {
slouken@2303
   569
            /* See if we need to rebuild the keyboard layout */
slouken@9898
   570
            UpdateKeymap(data, SDL_TRUE);
slouken@4673
   571
        }
slouken@2303
   572
slouken@4673
   573
        SDL_SendKeyboardKey(SDL_PRESSED, code);
slouken@2268
   574
#if 1
slouken@4673
   575
        if (code == SDL_SCANCODE_UNKNOWN) {
slouken@4673
   576
            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@4673
   577
        }
slouken@2268
   578
#endif
slouken@2129
   579
        if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
slouken@2268
   580
            /* 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
   581
            [data->fieldEdit interpretKeyEvents:[NSArray arrayWithObject:event]];
slouken@3280
   582
#if 0
slouken@2129
   583
            text = [[event characters] UTF8String];
slouken@2129
   584
            if(text && *text) {
slouken@4465
   585
                SDL_SendKeyboardText(text);
slouken@2273
   586
                [data->fieldEdit setString:@""];
slouken@2129
   587
            }
slouken@3280
   588
#endif
slouken@1959
   589
        }
slouken@1959
   590
        break;
slouken@1959
   591
    case NSKeyUp:
slouken@4465
   592
        SDL_SendKeyboardKey(SDL_RELEASED, code);
slouken@1959
   593
        break;
slouken@1959
   594
    case NSFlagsChanged:
slouken@2268
   595
        /* FIXME CW 2007-08-14: check if this whole mess that takes up half of this file is really necessary */
slouken@1959
   596
        HandleModifiers(_this, scancode, [event modifierFlags]);
slouken@1959
   597
        break;
slouken@2268
   598
    default: /* just to avoid compiler warnings */
slouken@2268
   599
        break;
slouken@2268
   600
    }
slouken@2268
   601
}
slouken@2268
   602
slouken@1959
   603
void
slouken@1931
   604
Cocoa_QuitKeyboard(_THIS)
slouken@1931
   605
{
slouken@1931
   606
}
slouken@1931
   607
slouken@6044
   608
#endif /* SDL_VIDEO_DRIVER_COCOA */
slouken@6044
   609
slouken@1931
   610
/* vi: set ts=4 sw=4 expandtab: */