diff options
Diffstat (limited to 'Source/3rdParty/SDL2/src/video/cocoa/SDL_cocoakeyboard.m')
-rw-r--r-- | Source/3rdParty/SDL2/src/video/cocoa/SDL_cocoakeyboard.m | 720 |
1 files changed, 0 insertions, 720 deletions
diff --git a/Source/3rdParty/SDL2/src/video/cocoa/SDL_cocoakeyboard.m b/Source/3rdParty/SDL2/src/video/cocoa/SDL_cocoakeyboard.m deleted file mode 100644 index 8436047..0000000 --- a/Source/3rdParty/SDL2/src/video/cocoa/SDL_cocoakeyboard.m +++ /dev/null @@ -1,720 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "../../SDL_internal.h" - -#if SDL_VIDEO_DRIVER_COCOA - -#include "SDL_cocoavideo.h" - -#include "../../events/SDL_events_c.h" -#include "../../events/SDL_keyboard_c.h" -#include "../../events/scancodes_darwin.h" - -#include <Carbon/Carbon.h> -#include <IOKit/hid/IOHIDLib.h> - -/*#define DEBUG_IME NSLog */ -#define DEBUG_IME(...) - -@interface SDLTranslatorResponder : NSView <NSTextInputClient> { - NSString *_markedText; - NSRange _markedRange; - NSRange _selectedRange; - SDL_Rect _inputRect; -} -- (void)doCommandBySelector:(SEL)myselector; -- (void)setInputRect:(SDL_Rect *)rect; -@end - -@implementation SDLTranslatorResponder - -- (void)setInputRect:(SDL_Rect *)rect -{ - _inputRect = *rect; -} - -- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange -{ - /* TODO: Make use of replacementRange? */ - - const char *str; - - DEBUG_IME(@"insertText: %@", aString); - - /* Could be NSString or NSAttributedString, so we have - * to test and convert it before return as SDL event */ - if ([aString isKindOfClass: [NSAttributedString class]]) { - str = [[aString string] UTF8String]; - } else { - str = [aString UTF8String]; - } - - SDL_SendKeyboardText(str); -} - -- (void)doCommandBySelector:(SEL)myselector -{ - /* No need to do anything since we are not using Cocoa - selectors to handle special keys, instead we use SDL - key events to do the same job. - */ -} - -- (BOOL)hasMarkedText -{ - return _markedText != nil; -} - -- (NSRange)markedRange -{ - return _markedRange; -} - -- (NSRange)selectedRange -{ - return _selectedRange; -} - -- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange -{ - if ([aString isKindOfClass:[NSAttributedString class]]) { - aString = [aString string]; - } - - if ([aString length] == 0) { - [self unmarkText]; - return; - } - - if (_markedText != aString) { - [_markedText release]; - _markedText = [aString retain]; - } - - _selectedRange = selectedRange; - _markedRange = NSMakeRange(0, [aString length]); - - SDL_SendEditingText([aString UTF8String], - (int) selectedRange.location, (int) selectedRange.length); - - DEBUG_IME(@"setMarkedText: %@, (%d, %d)", _markedText, - selRange.location, selRange.length); -} - -- (void)unmarkText -{ - [_markedText release]; - _markedText = nil; - - SDL_SendEditingText("", 0, 0); -} - -- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange -{ - NSWindow *window = [self window]; - NSRect contentRect = [window contentRectForFrameRect:[window frame]]; - float windowHeight = contentRect.size.height; - NSRect rect = NSMakeRect(_inputRect.x, windowHeight - _inputRect.y - _inputRect.h, - _inputRect.w, _inputRect.h); - - if (actualRange) { - *actualRange = aRange; - } - - DEBUG_IME(@"firstRectForCharacterRange: (%d, %d): windowHeight = %g, rect = %@", - aRange.location, aRange.length, windowHeight, - NSStringFromRect(rect)); - -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 - if (![window respondsToSelector:@selector(convertRectToScreen:)]) { - rect.origin = [window convertBaseToScreen:rect.origin]; - } else -#endif - { - rect = [window convertRectToScreen:rect]; - } - - return rect; -} - -- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange -{ - DEBUG_IME(@"attributedSubstringFromRange: (%d, %d)", aRange.location, aRange.length); - return nil; -} - -- (NSInteger)conversationIdentifier -{ - return (NSInteger) self; -} - -/* This method returns the index for character that is - * nearest to thePoint. thPoint is in screen coordinate system. - */ -- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint -{ - DEBUG_IME(@"characterIndexForPoint: (%g, %g)", thePoint.x, thePoint.y); - return 0; -} - -/* This method is the key to attribute extension. - * We could add new attributes through this method. - * NSInputServer examines the return value of this - * method & constructs appropriate attributed string. - */ -- (NSArray *)validAttributesForMarkedText -{ - return [NSArray array]; -} - -@end - -/*------------------------------------------------------------------------------ -Set up a HID callback to properly detect Caps Lock up/down events. -Derived from: -http://stackoverflow.com/questions/7190852/using-iohidmanager-to-get-modifier-key-events -*/ - -static IOHIDManagerRef s_hidManager = NULL; - -static void -HIDCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) -{ - if (context != s_hidManager) { - /* An old callback, ignore it (related to bug 2157 below) */ - return; - } - - IOHIDElementRef elem = IOHIDValueGetElement(value); - if (IOHIDElementGetUsagePage(elem) != kHIDPage_KeyboardOrKeypad - || IOHIDElementGetUsage(elem) != kHIDUsage_KeyboardCapsLock) { - return; - } - CFIndex pressed = IOHIDValueGetIntegerValue(value); - SDL_SendKeyboardKey(pressed ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_CAPSLOCK); -} - -static CFDictionaryRef -CreateHIDDeviceMatchingDictionary(UInt32 usagePage, UInt32 usage) -{ - CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (dict) { - CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usagePage); - if (number) { - CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), number); - CFRelease(number); - number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); - if (number) { - CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), number); - CFRelease(number); - return dict; - } - } - CFRelease(dict); - } - return NULL; -} - -static void -QuitHIDCallback() -{ - if (!s_hidManager) { - return; - } - -#if 0 /* Releasing here causes a crash on Mac OS X 10.10 and earlier, - * so just leak it for now. See bug 2157 for details. - */ - IOHIDManagerUnscheduleFromRunLoop(s_hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - IOHIDManagerRegisterInputValueCallback(s_hidManager, NULL, NULL); - IOHIDManagerClose(s_hidManager, 0); - - CFRelease(s_hidManager); -#endif - s_hidManager = NULL; -} - -static void -InitHIDCallback() -{ - s_hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); - if (!s_hidManager) { - return; - } - CFDictionaryRef keyboard = NULL, keypad = NULL; - CFArrayRef matches = NULL; - keyboard = CreateHIDDeviceMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard); - if (!keyboard) { - goto fail; - } - keypad = CreateHIDDeviceMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Keypad); - if (!keypad) { - goto fail; - } - CFDictionaryRef matchesList[] = { keyboard, keypad }; - matches = CFArrayCreate(kCFAllocatorDefault, (const void **)matchesList, 2, NULL); - if (!matches) { - goto fail; - } - IOHIDManagerSetDeviceMatchingMultiple(s_hidManager, matches); - IOHIDManagerRegisterInputValueCallback(s_hidManager, HIDCallback, s_hidManager); - IOHIDManagerScheduleWithRunLoop(s_hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode); - if (IOHIDManagerOpen(s_hidManager, kIOHIDOptionsTypeNone) == kIOReturnSuccess) { - goto cleanup; - } - -fail: - QuitHIDCallback(); - -cleanup: - if (matches) { - CFRelease(matches); - } - if (keypad) { - CFRelease(keypad); - } - if (keyboard) { - CFRelease(keyboard); - } -} - -/* This is a helper function for HandleModifierSide. This - * function reverts back to behavior before the distinction between - * sides was made. - */ -static void -HandleNonDeviceModifier(unsigned int device_independent_mask, - unsigned int oldMods, - unsigned int newMods, - SDL_Scancode scancode) -{ - 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(SDL_RELEASED, scancode); - } else if (newMask && oldMask != newMask) { - SDL_SendKeyboardKey(SDL_PRESSED, scancode); - } -} - -/* This is a helper function for HandleModifierSide. - * This function sets the actual SDL_PrivateKeyboard event. - */ -static void -HandleModifierOneSide(unsigned int oldMods, unsigned int newMods, - SDL_Scancode scancode, - 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(SDL_PRESSED, scancode); - } else { - SDL_SendKeyboardKey(SDL_RELEASED, scancode); - } -} - -/* 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 device_independent_mask, - unsigned int oldMods, unsigned int newMods, - SDL_Scancode left_scancode, - SDL_Scancode right_scancode, - 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(device_independent_mask, oldMods, newMods, left_scancode); - 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(oldMods, newMods, left_scancode, left_device_dependent_mask); - } - if (right_device_dependent_mask & diff_mod) { - HandleModifierOneSide(oldMods, newMods, right_scancode, 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(unsigned int device_independent_mask, - unsigned int oldMods, unsigned int newMods, - SDL_Scancode left_scancode, - SDL_Scancode right_scancode, - 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(SDL_RELEASED, left_scancode); - 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(SDL_RELEASED, left_scancode); - } - if ( right_device_dependent_mask & oldMods ) { - SDL_SendKeyboardKey(SDL_RELEASED, right_scancode); - } -} - -/* This function will handle the modifier keys and also determine the - * correct side of the key. - */ -static void -DoSidedModifiers(unsigned short scancode, - unsigned int oldMods, unsigned int newMods) -{ - /* Set up arrays for the key syms for the left and right side. */ - const SDL_Scancode left_mapping[] = { - SDL_SCANCODE_LSHIFT, - SDL_SCANCODE_LCTRL, - SDL_SCANCODE_LALT, - SDL_SCANCODE_LGUI - }; - const SDL_Scancode right_mapping[] = { - SDL_SCANCODE_RSHIFT, - SDL_SCANCODE_RCTRL, - SDL_SCANCODE_RALT, - SDL_SCANCODE_RGUI - }; - /* 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; - - /* Iterate through the bits, testing each against the old modifiers */ - for (i = 0, bit = NSEventModifierFlagShift; bit <= NSEventModifierFlagCommand; 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(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(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; - } - - DoSidedModifiers(scancode, data->modifierFlags, modifierFlags); - data->modifierFlags = modifierFlags; -} - -static void -UpdateKeymap(SDL_VideoData *data, SDL_bool send_event) -{ - TISInputSourceRef key_layout; - const void *chr_data; - int i; - SDL_Scancode scancode; - SDL_Keycode keymap[SDL_NUM_SCANCODES]; - - /* See if the keymap needs to be updated */ - key_layout = TISCopyCurrentKeyboardLayoutInputSource(); - if (key_layout == data->key_layout) { - return; - } - data->key_layout = key_layout; - - SDL_GetDefaultKeymap(keymap); - - /* Try Unicode data first */ - CFDataRef uchrDataRef = TISGetInputSourceProperty(key_layout, kTISPropertyUnicodeKeyLayoutData); - if (uchrDataRef) { - chr_data = CFDataGetBytePtr(uchrDataRef); - } else { - goto cleanup; - } - - if (chr_data) { - UInt32 keyboard_type = LMGetKbdType(); - OSStatus err; - - for (i = 0; i < SDL_arraysize(darwin_scancode_table); i++) { - UniChar s[8]; - UniCharCount len; - UInt32 dead_key_state; - - /* Make sure this scancode is a valid character scancode */ - scancode = darwin_scancode_table[i]; - if (scancode == SDL_SCANCODE_UNKNOWN || - (keymap[scancode] & SDLK_SCANCODE_MASK)) { - continue; - } - - dead_key_state = 0; - err = UCKeyTranslate ((UCKeyboardLayout *) chr_data, - i, kUCKeyActionDown, - 0, keyboard_type, - kUCKeyTranslateNoDeadKeysMask, - &dead_key_state, 8, &len, s); - if (err != noErr) { - continue; - } - - if (len > 0 && s[0] != 0x10) { - keymap[scancode] = s[0]; - } - } - SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES); - if (send_event) { - SDL_SendKeymapChangedEvent(); - } - return; - } - -cleanup: - CFRelease(key_layout); -} - -void -Cocoa_InitKeyboard(_THIS) -{ - SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; - - UpdateKeymap(data, SDL_FALSE); - - /* Set our own names for the platform-dependent but layout-independent keys */ - /* This key is NumLock on the MacBook keyboard. :) */ - /*SDL_SetScancodeName(SDL_SCANCODE_NUMLOCKCLEAR, "Clear");*/ - SDL_SetScancodeName(SDL_SCANCODE_LALT, "Left Option"); - SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Command"); - SDL_SetScancodeName(SDL_SCANCODE_RALT, "Right Option"); - SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Command"); - - data->modifierFlags = [NSEvent modifierFlags]; - SDL_ToggleModState(KMOD_CAPS, (data->modifierFlags & NSEventModifierFlagCapsLock) != 0); - - InitHIDCallback(); -} - -void -Cocoa_StartTextInput(_THIS) -{ @autoreleasepool -{ - SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; - SDL_Window *window = SDL_GetKeyboardFocus(); - NSWindow *nswindow = nil; - if (window) { - nswindow = ((SDL_WindowData*)window->driverdata)->nswindow; - } - - NSView *parentView = [nswindow contentView]; - - /* We only keep one field editor per process, since only the front most - * window can receive text input events, so it make no sense to keep more - * than one copy. When we switched to another window and requesting for - * text input, simply remove the field editor from its superview then add - * it to the front most window's content view */ - if (!data->fieldEdit) { - data->fieldEdit = - [[SDLTranslatorResponder alloc] initWithFrame: NSMakeRect(0.0, 0.0, 0.0, 0.0)]; - } - - if (![[data->fieldEdit superview] isEqual:parentView]) { - /* DEBUG_IME(@"add fieldEdit to window contentView"); */ - [data->fieldEdit removeFromSuperview]; - [parentView addSubview: data->fieldEdit]; - [nswindow makeFirstResponder: data->fieldEdit]; - } -}} - -void -Cocoa_StopTextInput(_THIS) -{ @autoreleasepool -{ - SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; - - if (data && data->fieldEdit) { - [data->fieldEdit removeFromSuperview]; - [data->fieldEdit release]; - data->fieldEdit = nil; - } -}} - -void -Cocoa_SetTextInputRect(_THIS, SDL_Rect *rect) -{ - SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; - - if (!rect) { - SDL_InvalidParamError("rect"); - return; - } - - [data->fieldEdit setInputRect:rect]; -} - -void -Cocoa_HandleKeyEvent(_THIS, NSEvent *event) -{ - SDL_VideoData *data = _this ? ((SDL_VideoData *) _this->driverdata) : NULL; - if (!data) { - return; /* can happen when returning from fullscreen Space on shutdown */ - } - - unsigned short scancode = [event keyCode]; - SDL_Scancode code; -#if 0 - const char *text; -#endif - - if ((scancode == 10 || scancode == 50) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) { - /* see comments in SDL_cocoakeys.h */ - scancode = 60 - scancode; - } - - if (scancode < SDL_arraysize(darwin_scancode_table)) { - code = darwin_scancode_table[scancode]; - } else { - /* Hmm, does this ever happen? If so, need to extend the keymap... */ - code = SDL_SCANCODE_UNKNOWN; - } - - switch ([event type]) { - case NSEventTypeKeyDown: - if (![event isARepeat]) { - /* See if we need to rebuild the keyboard layout */ - UpdateKeymap(data, SDL_TRUE); - } - - SDL_SendKeyboardKey(SDL_PRESSED, code); -#if 1 - if (code == SDL_SCANCODE_UNKNOWN) { - fprintf(stderr, "The key you just pressed is not recognized by SDL. To help get this fixed, report this to the SDL forums/mailing list <https://discourse.libsdl.org/> or to Christian Walther <cwalther@gmx.ch>. Mac virtual key code is %d.\n", scancode); - } -#endif - if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) { - /* 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. */ - [data->fieldEdit interpretKeyEvents:[NSArray arrayWithObject:event]]; -#if 0 - text = [[event characters] UTF8String]; - if(text && *text) { - SDL_SendKeyboardText(text); - [data->fieldEdit setString:@""]; - } -#endif - } - break; - case NSEventTypeKeyUp: - SDL_SendKeyboardKey(SDL_RELEASED, code); - break; - case NSEventTypeFlagsChanged: - /* FIXME CW 2007-08-14: check if this whole mess that takes up half of this file is really necessary */ - HandleModifiers(_this, scancode, [event modifierFlags]); - break; - default: /* just to avoid compiler warnings */ - break; - } -} - -void -Cocoa_QuitKeyboard(_THIS) -{ - QuitHIDCallback(); -} - -#endif /* SDL_VIDEO_DRIVER_COCOA */ - -/* vi: set ts=4 sw=4 expandtab: */ |