From f78880692f544fd7257f15b68aa785774fc13f5f Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 30 Jul 2006 05:18:33 +0000 Subject: [PATCH] Implemented Cocoa key event handling. --- src/events/SDL_keyboard.c | 3 +- src/video/cocoa/SDL_cocoaevents.m | 19 +- src/video/cocoa/SDL_cocoakeyboard.m | 507 ++++++++++++++++++++++++++++ src/video/cocoa/SDL_cocoakeys.h | 141 ++++++++ src/video/cocoa/SDL_cocoavideo.h | 4 + src/video/cocoa/SDL_cocoavideo.m | 3 + src/video/cocoa/SDL_cocoawindow.m | 64 +++- 7 files changed, 717 insertions(+), 24 deletions(-) create mode 100644 src/video/cocoa/SDL_cocoakeys.h diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c index aff822d78..77f878923 100644 --- a/src/events/SDL_keyboard.c +++ b/src/events/SDL_keyboard.c @@ -654,6 +654,7 @@ SDL_SendKeyboardKey(int index, Uint8 state, Uint8 scancode, SDLKey key) event.key.keysym.mod = modstate; event.key.keysym.unicode = 0; event.key.windowID = keyboard->focus; + /* FIXME: This doesn't make sense anymore... */ /* * jk 991215 - Added */ @@ -688,7 +689,7 @@ SDL_SendKeyboardText(int index, const char *text) event.text.type = SDL_TEXTINPUT; event.text.which = (Uint8) index; SDL_strlcpy(event.text.text, text, SDL_arraysize(event.text.text)); - event.key.windowID = keyboard->focus; + event.text.windowID = keyboard->focus; posted = (SDL_PushEvent(&event) > 0); } return (posted); diff --git a/src/video/cocoa/SDL_cocoaevents.m b/src/video/cocoa/SDL_cocoaevents.m index 6207eab8b..1f5b02f7c 100644 --- a/src/video/cocoa/SDL_cocoaevents.m +++ b/src/video/cocoa/SDL_cocoaevents.m @@ -89,9 +89,9 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Hide " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; + [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@/*"h"*/""]; - menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; + menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@/*"h"*/""]; [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; @@ -99,7 +99,7 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Quit " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; + [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@/*"q"*/""]; /* Put menu into the menubar */ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; @@ -116,7 +116,7 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; /* "Minimize" item */ - menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; + menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@/*"m"*/""]; [windowMenu addItem:menuItem]; [menuItem release]; @@ -169,7 +169,16 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende if ( event == nil ) { break; } - [NSApp sendEvent:event]; + switch ([event type]) { + case NSKeyDown: + case NSKeyUp: + case NSFlagsChanged: + Cocoa_HandleKeyEvent(_this, event); + /* Fall through to pass event to NSApp */ + default: + [NSApp sendEvent:event]; + break; + } } [pool release]; } diff --git a/src/video/cocoa/SDL_cocoakeyboard.m b/src/video/cocoa/SDL_cocoakeyboard.m index 406763df0..84097b2f9 100644 --- a/src/video/cocoa/SDL_cocoakeyboard.m +++ b/src/video/cocoa/SDL_cocoakeyboard.m @@ -22,19 +22,526 @@ #include "SDL_config.h" #include "SDL_cocoavideo.h" +#include "SDL_cocoakeys.h" #include "../../events/SDL_keyboard_c.h" + +#ifndef NX_DEVICERCTLKEYMASK + #define NX_DEVICELCTLKEYMASK 0x00000001 +#endif +#ifndef NX_DEVICELSHIFTKEYMASK + #define NX_DEVICELSHIFTKEYMASK 0x00000002 +#endif +#ifndef NX_DEVICERSHIFTKEYMASK + #define NX_DEVICERSHIFTKEYMASK 0x00000004 +#endif +#ifndef NX_DEVICELCMDKEYMASK + #define NX_DEVICELCMDKEYMASK 0x00000008 +#endif +#ifndef NX_DEVICERCMDKEYMASK + #define NX_DEVICERCMDKEYMASK 0x00000010 +#endif +#ifndef NX_DEVICELALTKEYMASK + #define NX_DEVICELALTKEYMASK 0x00000020 +#endif +#ifndef NX_DEVICERALTKEYMASK + #define NX_DEVICERALTKEYMASK 0x00000040 +#endif +#ifndef NX_DEVICERCTLKEYMASK + #define NX_DEVICERCTLKEYMASK 0x00002000 +#endif + +static void +InitKeymap (SDLKey *keymap) +{ + const void *KCHRPtr; + UInt32 state; + UInt32 value; + int i; + + for ( i=0; i<256; ++i ) + keymap[i] = SDLK_UNKNOWN; + + /* This keymap is almost exactly the same as the OS 9 one */ + keymap[KEY_ESCAPE] = SDLK_ESCAPE; + keymap[KEY_F1] = SDLK_F1; + keymap[KEY_F2] = SDLK_F2; + keymap[KEY_F3] = SDLK_F3; + keymap[KEY_F4] = SDLK_F4; + keymap[KEY_F5] = SDLK_F5; + keymap[KEY_F6] = SDLK_F6; + keymap[KEY_F7] = SDLK_F7; + keymap[KEY_F8] = SDLK_F8; + keymap[KEY_F9] = SDLK_F9; + keymap[KEY_F10] = SDLK_F10; + keymap[KEY_F11] = SDLK_F11; + keymap[KEY_F12] = SDLK_F12; + keymap[KEY_PRINT] = SDLK_PRINT; + keymap[KEY_SCROLLOCK] = SDLK_SCROLLOCK; + keymap[KEY_PAUSE] = SDLK_PAUSE; + keymap[KEY_POWER] = SDLK_POWER; + keymap[KEY_BACKQUOTE] = SDLK_BACKQUOTE; + keymap[KEY_1] = SDLK_1; + keymap[KEY_2] = SDLK_2; + keymap[KEY_3] = SDLK_3; + keymap[KEY_4] = SDLK_4; + keymap[KEY_5] = SDLK_5; + keymap[KEY_6] = SDLK_6; + keymap[KEY_7] = SDLK_7; + keymap[KEY_8] = SDLK_8; + keymap[KEY_9] = SDLK_9; + keymap[KEY_0] = SDLK_0; + keymap[KEY_MINUS] = SDLK_MINUS; + keymap[KEY_EQUALS] = SDLK_EQUALS; + keymap[KEY_BACKSPACE] = SDLK_BACKSPACE; + keymap[KEY_INSERT] = SDLK_INSERT; + keymap[KEY_HOME] = SDLK_HOME; + keymap[KEY_PAGEUP] = SDLK_PAGEUP; + keymap[KEY_NUMLOCK] = SDLK_NUMLOCK; + keymap[KEY_KP_EQUALS] = SDLK_KP_EQUALS; + keymap[KEY_KP_DIVIDE] = SDLK_KP_DIVIDE; + keymap[KEY_KP_MULTIPLY] = SDLK_KP_MULTIPLY; + keymap[KEY_TAB] = SDLK_TAB; + keymap[KEY_q] = SDLK_q; + keymap[KEY_w] = SDLK_w; + keymap[KEY_e] = SDLK_e; + keymap[KEY_r] = SDLK_r; + keymap[KEY_t] = SDLK_t; + keymap[KEY_y] = SDLK_y; + keymap[KEY_u] = SDLK_u; + keymap[KEY_i] = SDLK_i; + keymap[KEY_o] = SDLK_o; + keymap[KEY_p] = SDLK_p; + keymap[KEY_LEFTBRACKET] = SDLK_LEFTBRACKET; + keymap[KEY_RIGHTBRACKET] = SDLK_RIGHTBRACKET; + keymap[KEY_BACKSLASH] = SDLK_BACKSLASH; + keymap[KEY_DELETE] = SDLK_DELETE; + keymap[KEY_END] = SDLK_END; + keymap[KEY_PAGEDOWN] = SDLK_PAGEDOWN; + keymap[KEY_KP7] = SDLK_KP7; + keymap[KEY_KP8] = SDLK_KP8; + keymap[KEY_KP9] = SDLK_KP9; + keymap[KEY_KP_MINUS] = SDLK_KP_MINUS; + keymap[KEY_CAPSLOCK] = SDLK_CAPSLOCK; + keymap[KEY_a] = SDLK_a; + keymap[KEY_s] = SDLK_s; + keymap[KEY_d] = SDLK_d; + keymap[KEY_f] = SDLK_f; + keymap[KEY_g] = SDLK_g; + keymap[KEY_h] = SDLK_h; + keymap[KEY_j] = SDLK_j; + keymap[KEY_k] = SDLK_k; + keymap[KEY_l] = SDLK_l; + keymap[KEY_SEMICOLON] = SDLK_SEMICOLON; + keymap[KEY_QUOTE] = SDLK_QUOTE; + keymap[KEY_RETURN] = SDLK_RETURN; + keymap[KEY_KP4] = SDLK_KP4; + keymap[KEY_KP5] = SDLK_KP5; + keymap[KEY_KP6] = SDLK_KP6; + keymap[KEY_KP_PLUS] = SDLK_KP_PLUS; + keymap[KEY_LSHIFT] = SDLK_LSHIFT; + keymap[KEY_RSHIFT] = SDLK_RSHIFT; + keymap[KEY_z] = SDLK_z; + keymap[KEY_x] = SDLK_x; + keymap[KEY_c] = SDLK_c; + keymap[KEY_v] = SDLK_v; + keymap[KEY_b] = SDLK_b; + keymap[KEY_n] = SDLK_n; + keymap[KEY_m] = SDLK_m; + keymap[KEY_COMMA] = SDLK_COMMA; + keymap[KEY_PERIOD] = SDLK_PERIOD; + keymap[KEY_SLASH] = SDLK_SLASH; + keymap[KEY_UP] = SDLK_UP; + keymap[KEY_KP1] = SDLK_KP1; + keymap[KEY_KP2] = SDLK_KP2; + keymap[KEY_KP3] = SDLK_KP3; + keymap[KEY_KP_ENTER] = SDLK_KP_ENTER; + keymap[KEY_LCTRL] = SDLK_LCTRL; + keymap[KEY_LALT] = SDLK_LALT; + keymap[KEY_LMETA] = SDLK_LMETA; + keymap[KEY_RCTRL] = SDLK_RCTRL; + keymap[KEY_RALT] = SDLK_RALT; + keymap[KEY_RMETA] = SDLK_RMETA; + keymap[KEY_SPACE] = SDLK_SPACE; + keymap[KEY_LEFT] = SDLK_LEFT; + keymap[KEY_DOWN] = SDLK_DOWN; + keymap[KEY_RIGHT] = SDLK_RIGHT; + keymap[KEY_KP0] = SDLK_KP0; + keymap[KEY_KP_PERIOD] = SDLK_KP_PERIOD; + keymap[KEY_IBOOK_ENTER] = SDLK_KP_ENTER; + keymap[KEY_IBOOK_RIGHT] = SDLK_RIGHT; + keymap[KEY_IBOOK_DOWN] = SDLK_DOWN; + keymap[KEY_IBOOK_UP] = SDLK_UP; + keymap[KEY_IBOOK_LEFT] = SDLK_LEFT; + + /* + Up there we setup a static scancode->keysym map. However, it will not + work very well on international keyboard. Hence we now query Mac OS X + for its own keymap to adjust our own mapping table. However, this is + basically only useful for ascii char keys. This is also the reason + why we keep the static table, too. + */ + + /* Get a pointer to the systems cached KCHR */ + KCHRPtr = (void *)GetScriptManagerVariable(smKCHRCache); + if (KCHRPtr) { + /* Loop over all 127 possible scan codes */ + for (i = 0; i < 0x7F; i++) { + /* We pretend a clean start to begin with (i.e. no dead keys active */ + state = 0; + + /* Now translate the key code to a key value */ + value = KeyTranslate(KCHRPtr, i, &state) & 0xff; + + /* If the state become 0, it was a dead key. We need to translate again, + passing in the new state, to get the actual key value */ + if (state != 0) + value = KeyTranslate(KCHRPtr, i, &state) & 0xff; + + /* Now we should have a latin1 value, which are SDL keysyms */ + if (value >= 32 && value <= 255) { + keymap[i] = value; + } + } + } + + /* + The keypad codes are re-setup here, because the loop above cannot + distinguish between a key on the keypad and a regular key. We maybe + could get around this problem in another fashion: NSEvent's flags + include a "NSNumericPadKeyMask" bit; we could check that and modify + the symbol we return on the fly. However, this flag seems to exhibit + some weird behaviour related to the num lock key + */ + keymap[KEY_KP0] = SDLK_KP0; + keymap[KEY_KP1] = SDLK_KP1; + keymap[KEY_KP2] = SDLK_KP2; + keymap[KEY_KP3] = SDLK_KP3; + keymap[KEY_KP4] = SDLK_KP4; + keymap[KEY_KP5] = SDLK_KP5; + keymap[KEY_KP6] = SDLK_KP6; + keymap[KEY_KP7] = SDLK_KP7; + keymap[KEY_KP8] = SDLK_KP8; + keymap[KEY_KP9] = SDLK_KP9; + keymap[KEY_KP_MINUS] = SDLK_KP_MINUS; + keymap[KEY_KP_PLUS] = SDLK_KP_PLUS; + keymap[KEY_KP_PERIOD] = SDLK_KP_PERIOD; + keymap[KEY_KP_EQUALS] = SDLK_KP_EQUALS; + keymap[KEY_KP_DIVIDE] = SDLK_KP_DIVIDE; + keymap[KEY_KP_MULTIPLY] = SDLK_KP_MULTIPLY; + keymap[KEY_KP_ENTER] = SDLK_KP_ENTER; +} + +/* This is the original behavior, before support was added for + * differentiating between left and right versions of the keys. + */ +static void +DoUnsidedModifiers(int keyboard, unsigned short scancode, + unsigned int oldMods, unsigned int newMods) +{ + const int mapping[] = { SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA }; + unsigned int i, bit; + + /* Iterate through the bits, testing each against the current modifiers */ + for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) { + unsigned int oldMask, newMask; + + oldMask = oldMods & bit; + newMask = newMods & bit; + + if (oldMask && oldMask != newMask) { /* modifier up event */ + /* If this was Caps Lock, we need some additional voodoo to make SDL happy */ + if (bit == NSAlphaShiftKeyMask) { + SDL_SendKeyboardKey(keyboard, SDL_PRESSED, (Uint8)scancode, mapping[i]); + } + SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, mapping[i]); + } else if (newMask && oldMask != newMask) { /* modifier down event */ + SDL_SendKeyboardKey(keyboard, SDL_PRESSED, (Uint8)scancode, mapping[i]); + /* If this was Caps Lock, we need some additional voodoo to make SDL happy */ + if (bit == NSAlphaShiftKeyMask) { + SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, mapping[i]); + } + } + } +} + +/* This is a helper function for HandleModifierSide. This + * function reverts back to behavior before the distinction between + * sides was made. + */ +static void +HandleNonDeviceModifier(int keyboard, unsigned short scancode, + unsigned int device_independent_mask, + unsigned int oldMods, + unsigned int newMods, + SDLKey key_sym) +{ + unsigned int oldMask, newMask; + + /* Isolate just the bits we care about in the depedent bits so we can + * figure out what changed + */ + oldMask = oldMods & device_independent_mask; + newMask = newMods & device_independent_mask; + + if (oldMask && oldMask != newMask) { + SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, key_sym); + } else if (newMask && oldMask != newMask) { + SDL_SendKeyboardKey(keyboard, SDL_PRESSED, (Uint8)scancode, key_sym); + } +} + +/* This is a helper function for HandleModifierSide. + * This function sets the actual SDL_PrivateKeyboard event. + */ +static void +HandleModifierOneSide(int keyboard, unsigned short scancode, + unsigned int oldMods, unsigned int newMods, + SDLKey key_sym, + unsigned int sided_device_dependent_mask) +{ + unsigned int old_dep_mask, new_dep_mask; + + /* Isolate just the bits we care about in the depedent bits so we can + * figure out what changed + */ + old_dep_mask = oldMods & sided_device_dependent_mask; + new_dep_mask = newMods & sided_device_dependent_mask; + + /* We now know that this side bit flipped. But we don't know if + * it went pressed to released or released to pressed, so we must + * find out which it is. + */ + if (new_dep_mask && old_dep_mask != new_dep_mask) { + SDL_SendKeyboardKey(keyboard, SDL_PRESSED, (Uint8)scancode, key_sym); + } else { + SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, key_sym); + } +} + +/* This is a helper function for DoSidedModifiers. + * This function will figure out if the modifier key is the left or right side, + * e.g. left-shift vs right-shift. + */ +static void +HandleModifierSide(int keyboard, unsigned short scancode, + int device_independent_mask, + unsigned int oldMods, unsigned int newMods, + SDLKey left_key_sym, + SDLKey right_key_sym, + unsigned int left_device_dependent_mask, + unsigned int right_device_dependent_mask) +{ + unsigned int device_dependent_mask = (left_device_dependent_mask | + right_device_dependent_mask); + unsigned int diff_mod; + + /* On the basis that the device independent mask is set, but there are + * no device dependent flags set, we'll assume that we can't detect this + * keyboard and revert to the unsided behavior. + */ + if ((device_dependent_mask & newMods) == 0) { + /* Revert to the old behavior */ + HandleNonDeviceModifier(keyboard, scancode, device_independent_mask, oldMods, newMods, left_key_sym); + return; + } + + /* XOR the previous state against the new state to see if there's a change */ + diff_mod = (device_dependent_mask & oldMods) ^ + (device_dependent_mask & newMods); + if (diff_mod) { + /* A change in state was found. Isolate the left and right bits + * to handle them separately just in case the values can simulataneously + * change or if the bits don't both exist. + */ + if (left_device_dependent_mask & diff_mod) { + HandleModifierOneSide(keyboard, scancode, oldMods, newMods, left_key_sym, left_device_dependent_mask); + } + if (right_device_dependent_mask & diff_mod) { + HandleModifierOneSide(keyboard, scancode, oldMods, newMods, right_key_sym, right_device_dependent_mask); + } + } +} + +/* This is a helper function for DoSidedModifiers. + * This function will release a key press in the case that + * it is clear that the modifier has been released (i.e. one side + * can't still be down). + */ +static void +ReleaseModifierSide(int keyboard, unsigned short scancode, + unsigned int device_independent_mask, + unsigned int oldMods, unsigned int newMods, + SDLKey left_key_sym, + SDLKey right_key_sym, + unsigned int left_device_dependent_mask, + unsigned int right_device_dependent_mask) +{ + unsigned int device_dependent_mask = (left_device_dependent_mask | + right_device_dependent_mask); + + /* On the basis that the device independent mask is set, but there are + * no device dependent flags set, we'll assume that we can't detect this + * keyboard and revert to the unsided behavior. + */ + if ((device_dependent_mask & oldMods) == 0) { + /* In this case, we can't detect the keyboard, so use the left side + * to represent both, and release it. + */ + SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, left_key_sym); + return; + } + + /* + * This could have been done in an if-else case because at this point, + * we know that all keys have been released when calling this function. + * But I'm being paranoid so I want to handle each separately, + * so I hope this doesn't cause other problems. + */ + if ( left_device_dependent_mask & oldMods ) { + SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, left_key_sym); + } + if ( right_device_dependent_mask & oldMods ) { + SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, right_key_sym); + } +} + +/* This is a helper function for DoSidedModifiers. + * This function handles the CapsLock case. + */ +static void +HandleCapsLock(int keyboard, unsigned short scancode, + unsigned int oldMods, unsigned int newMods) +{ + unsigned int oldMask, newMask; + + oldMask = oldMods & NSAlphaShiftKeyMask; + newMask = newMods & NSAlphaShiftKeyMask; + + if (oldMask != newMask) { + SDL_SendKeyboardKey(keyboard, SDL_PRESSED, (Uint8)scancode, SDLK_CAPSLOCK); + SDL_SendKeyboardKey(keyboard, SDL_RELEASED, (Uint8)scancode, SDLK_CAPSLOCK); + } +} + +/* This function will handle the modifier keys and also determine the + * correct side of the key. + */ +static void +DoSidedModifiers(int keyboard, unsigned short scancode, + unsigned int oldMods, unsigned int newMods) +{ + /* Set up arrays for the key syms for the left and right side. */ + const SDLKey left_mapping[] = { SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA }; + const SDLKey right_mapping[] = { SDLK_RSHIFT, SDLK_RCTRL, SDLK_RALT, SDLK_RMETA }; + /* Set up arrays for the device dependent masks with indices that + * correspond to the _mapping arrays + */ + const unsigned int left_device_mapping[] = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK }; + const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK }; + + unsigned int i, bit; + + /* Handle CAPSLOCK separately because it doesn't have a left/right side */ + HandleCapsLock(keyboard, scancode, oldMods, newMods); + + /* Iterate through the bits, testing each against the old modifiers */ + for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) { + unsigned int oldMask, newMask; + + oldMask = oldMods & bit; + newMask = newMods & bit; + + /* If the bit is set, we must always examine it because the left + * and right side keys may alternate or both may be pressed. + */ + if (newMask) { + HandleModifierSide(keyboard, scancode, bit, oldMods, newMods, + left_mapping[i], right_mapping[i], + left_device_mapping[i], right_device_mapping[i]); + } + /* If the state changed from pressed to unpressed, we must examine + * the device dependent bits to release the correct keys. + */ + else if (oldMask && oldMask != newMask) { + ReleaseModifierSide(keyboard, scancode, bit, oldMods, newMods, + left_mapping[i], right_mapping[i], + left_device_mapping[i], right_device_mapping[i]); + } + } +} + +static void +HandleModifiers(_THIS, unsigned short scancode, unsigned int modifierFlags) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + + if (modifierFlags == data->modifierFlags) { + return; + } + + /* + * Starting with Panther (10.3.0), the ability to distinguish between + * left side and right side modifiers is available. + */ + if (data->osversion >= 0x1030) { + DoSidedModifiers(data->keyboard, scancode, data->modifierFlags, modifierFlags); + } else { + DoUnsidedModifiers(data->keyboard, scancode, data->modifierFlags, modifierFlags); + } + data->modifierFlags = modifierFlags; +} + void Cocoa_InitKeyboard(_THIS) { SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; SDL_Keyboard keyboard; + InitKeymap(data->keymap); + SDL_zero(keyboard); data->keyboard = SDL_AddKeyboard(&keyboard, -1); } +void +Cocoa_HandleKeyEvent(_THIS, NSEvent *event) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + unsigned short scancode = [event keyCode]; + const char *text; + + if (scancode >= 256) { + /* Hmm, does this ever happen? If so, need to extend the keymap... */ + return; + } + + switch ([event type]) { + case NSKeyDown: + if ([event isARepeat]) { + break; + } +printf("NSKeyDown: %x, %x\n", scancode, [event modifierFlags]); + SDL_SendKeyboardKey(data->keyboard, SDL_PRESSED, (Uint8)scancode, + data->keymap[scancode]); + text = [[event characters] UTF8String]; + if(text && *text) { + SDL_SendKeyboardText(data->keyboard, text); + } + break; + case NSKeyUp: +printf("NSKeyUp: %x, %x\n", scancode, [event modifierFlags]); + SDL_SendKeyboardKey(data->keyboard, SDL_RELEASED, (Uint8)scancode, + data->keymap[scancode]); + break; + case NSFlagsChanged: +printf("NSFlagsChanged: %x, %x\n", scancode, [event modifierFlags]); + HandleModifiers(_this, scancode, [event modifierFlags]); + break; + } +} + void Cocoa_QuitKeyboard(_THIS) { diff --git a/src/video/cocoa/SDL_cocoakeys.h b/src/video/cocoa/SDL_cocoakeys.h new file mode 100644 index 000000000..3d45d6563 --- /dev/null +++ b/src/video/cocoa/SDL_cocoakeys.h @@ -0,0 +1,141 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2006 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* These are the Macintosh key scancode constants -- from Inside Macintosh */ + +#define KEY_ESCAPE 0x35 +#define KEY_F1 0x7A +#define KEY_F2 0x78 +#define KEY_F3 0x63 +#define KEY_F4 0x76 +#define KEY_F5 0x60 +#define KEY_F6 0x61 +#define KEY_F7 0x62 +#define KEY_F8 0x64 +#define KEY_F9 0x65 +#define KEY_F10 0x6D +#define KEY_F11 0x67 +#define KEY_F12 0x6F +#define KEY_PRINT 0x69 +#define KEY_SCROLLOCK 0x6B +#define KEY_PAUSE 0x71 +#define KEY_POWER 0x7F +#define KEY_BACKQUOTE 0x32 +#define KEY_1 0x12 +#define KEY_2 0x13 +#define KEY_3 0x14 +#define KEY_4 0x15 +#define KEY_5 0x17 +#define KEY_6 0x16 +#define KEY_7 0x1A +#define KEY_8 0x1C +#define KEY_9 0x19 +#define KEY_0 0x1D +#define KEY_MINUS 0x1B +#define KEY_EQUALS 0x18 +#define KEY_BACKSPACE 0x33 +#define KEY_INSERT 0x72 +#define KEY_HOME 0x73 +#define KEY_PAGEUP 0x74 +#define KEY_NUMLOCK 0x47 +#define KEY_KP_EQUALS 0x51 +#define KEY_KP_DIVIDE 0x4B +#define KEY_KP_MULTIPLY 0x43 +#define KEY_TAB 0x30 +#define KEY_q 0x0C +#define KEY_w 0x0D +#define KEY_e 0x0E +#define KEY_r 0x0F +#define KEY_t 0x11 +#define KEY_y 0x10 +#define KEY_u 0x20 +#define KEY_i 0x22 +#define KEY_o 0x1F +#define KEY_p 0x23 +#define KEY_LEFTBRACKET 0x21 +#define KEY_RIGHTBRACKET 0x1E +#define KEY_BACKSLASH 0x2A +#define KEY_DELETE 0x75 +#define KEY_END 0x77 +#define KEY_PAGEDOWN 0x79 +#define KEY_KP7 0x59 +#define KEY_KP8 0x5B +#define KEY_KP9 0x5C +#define KEY_KP_MINUS 0x4E +#define KEY_CAPSLOCK 0x39 +#define KEY_a 0x00 +#define KEY_s 0x01 +#define KEY_d 0x02 +#define KEY_f 0x03 +#define KEY_g 0x05 +#define KEY_h 0x04 +#define KEY_j 0x26 +#define KEY_k 0x28 +#define KEY_l 0x25 +#define KEY_SEMICOLON 0x29 +#define KEY_QUOTE 0x27 +#define KEY_RETURN 0x24 +#define KEY_KP4 0x56 +#define KEY_KP5 0x57 +#define KEY_KP6 0x58 +#define KEY_KP_PLUS 0x45 +#define KEY_LSHIFT 0x38 +#define KEY_z 0x06 +#define KEY_x 0x07 +#define KEY_c 0x08 +#define KEY_v 0x09 +#define KEY_b 0x0B +#define KEY_n 0x2D +#define KEY_m 0x2E +#define KEY_COMMA 0x2B +#define KEY_PERIOD 0x2F +#define KEY_SLASH 0x2C +#if 1 /* Panther now defines right side keys */ +#define KEY_RSHIFT 0x3C +#endif +#define KEY_UP 0x7E +#define KEY_KP1 0x53 +#define KEY_KP2 0x54 +#define KEY_KP3 0x55 +#define KEY_KP_ENTER 0x4C +#define KEY_LCTRL 0x3B +#define KEY_LALT 0x3A +#define KEY_LMETA 0x37 +#define KEY_SPACE 0x31 +#if 1 /* Panther now defines right side keys */ +#define KEY_RMETA 0x36 +#define KEY_RALT 0x3D +#define KEY_RCTRL 0x3E +#endif +#define KEY_LEFT 0x7B +#define KEY_DOWN 0x7D +#define KEY_RIGHT 0x7C +#define KEY_KP0 0x52 +#define KEY_KP_PERIOD 0x41 + +/* Wierd, these keys are on my iBook under Mac OS X */ +#define KEY_IBOOK_ENTER 0x34 +#define KEY_IBOOK_LEFT 0x3B +#define KEY_IBOOK_RIGHT 0x3C +#define KEY_IBOOK_DOWN 0x3D +#define KEY_IBOOK_UP 0x3E diff --git a/src/video/cocoa/SDL_cocoavideo.h b/src/video/cocoa/SDL_cocoavideo.h index cd94dc7ab..730d41b69 100644 --- a/src/video/cocoa/SDL_cocoavideo.h +++ b/src/video/cocoa/SDL_cocoavideo.h @@ -27,6 +27,7 @@ #include #include +#include "SDL_keysym.h" #include "../SDL_sysvideo.h" #include "SDL_cocoaevents.h" @@ -40,6 +41,9 @@ typedef struct SDL_VideoData { + SInt32 osversion; + SDLKey keymap[256]; + unsigned int modifierFlags; int mouse; int keyboard; } SDL_VideoData; diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m index e0eb6041b..49ff4462b 100644 --- a/src/video/cocoa/SDL_cocoavideo.m +++ b/src/video/cocoa/SDL_cocoavideo.m @@ -66,6 +66,9 @@ } device->driverdata = data; + /* Find out what version of Mac OS X we're running */ + Gestalt(gestaltSystemVersion, &data->osversion); + /* Set the function pointers */ device->VideoInit = Cocoa_VideoInit; device->VideoQuit = Cocoa_VideoQuit; diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index dfcc17f26..d5ae998ab 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -148,49 +148,67 @@ - (void)windowDidUnhide:(NSNotification *)aNotification - (void)mouseDown:(NSEvent *)theEvent { int index; + int button; index = _data->videodata->mouse; - SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_LEFT); + switch ([theEvent buttonNumber]) { + case 0: + button = SDL_BUTTON_LEFT; + break; + case 1: + button = SDL_BUTTON_RIGHT; + break; + case 2: + button = SDL_BUTTON_MIDDLE; + break; + default: + button = [theEvent buttonNumber]; + break; + } + SDL_SendMouseButton(index, SDL_PRESSED, button); } - (void)rightMouseDown:(NSEvent *)theEvent { - int index; - - index = _data->videodata->mouse; - SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_RIGHT); + [self mouseDown:theEvent]; } - (void)otherMouseDown:(NSEvent *)theEvent { - int index; - - index = _data->videodata->mouse; - SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_MIDDLE); + [self mouseDown:theEvent]; } - (void)mouseUp:(NSEvent *)theEvent { int index; + int button; index = _data->videodata->mouse; - SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_LEFT); + switch ([theEvent buttonNumber]) { + case 0: + button = SDL_BUTTON_LEFT; + break; + case 1: + button = SDL_BUTTON_RIGHT; + break; + case 2: + button = SDL_BUTTON_MIDDLE; + break; + default: + button = [theEvent buttonNumber]; + break; + } + SDL_SendMouseButton(index, SDL_RELEASED, button); } - (void)rightMouseUp:(NSEvent *)theEvent { - int index; - - index = _data->videodata->mouse; - SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_RIGHT); + [self mouseUp:theEvent]; } - (void)otherMouseUp:(NSEvent *)theEvent { - int index; - - index = _data->videodata->mouse; - SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_MIDDLE); + [self mouseUp:theEvent]; } - (void)mouseMoved:(NSEvent *)theEvent @@ -238,11 +256,21 @@ - (void)scrollWheel:(NSEvent *)theEvent - (void)keyDown:(NSEvent *)theEvent { + int index; + + index = _data->videodata->keyboard; fprintf(stderr, "keyDown\n"); + const char *text = [[theEvent characters] UTF8String]; + if(text && *text) { + SDL_SendKeyboardText(index, text); + } } - (void)keyUp:(NSEvent *)theEvent { + int index; + + index = _data->videodata->keyboard; fprintf(stderr, "keyUp\n"); }