Skip to content

Commit

Permalink
cocoa: Check for capslock in -[NSResponder flagsChanged], not with IO…
Browse files Browse the repository at this point in the history
…Kit.

Using IOKit for this pops up a warning at startup on macOS 10.15 ("Catalina"),
asking the user to authorize the app to listen to all keyboard input in the
system, which is unacceptable.

I _think_ we were using IOKit under incorrect presumptions here; the Stack
Overflow link mentioned in it was complaining about not being able to use
flagsChanged to differentiate between left and right mod keys, but that's not
an issue for capslock.

It's also possible this code was trying to deal with capslock changing when
the window didn't have focus, but we handle this elsewhere now, if we didn't
at the time.
  • Loading branch information
icculus committed Jun 26, 2019
1 parent 0beadea commit 57e08c2
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 115 deletions.
113 changes: 0 additions & 113 deletions src/video/cocoa/SDL_cocoakeyboard.m
Expand Up @@ -29,7 +29,6 @@
#include "../../events/scancodes_darwin.h"

#include <Carbon/Carbon.h>
#include <IOKit/hid/IOHIDLib.h>

/*#define DEBUG_IME NSLog */
#define DEBUG_IME(...)
Expand Down Expand Up @@ -187,115 +186,6 @@ - (NSArray *)validAttributesForMarkedText

@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
Expand Down Expand Up @@ -585,8 +475,6 @@ - (NSArray *)validAttributesForMarkedText

data->modifierFlags = [NSEvent modifierFlags];
SDL_ToggleModState(KMOD_CAPS, (data->modifierFlags & NSEventModifierFlagCapsLock) != 0);

InitHIDCallback();
}

void
Expand Down Expand Up @@ -712,7 +600,6 @@ - (NSArray *)validAttributesForMarkedText
void
Cocoa_QuitKeyboard(_THIS)
{
QuitHIDCallback();
}

#endif /* SDL_VIDEO_DRIVER_COCOA */
Expand Down
14 changes: 12 additions & 2 deletions src/video/cocoa/SDL_cocoawindow.m
Expand Up @@ -54,6 +54,9 @@

#define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN)

#ifndef MAC_OS_X_VERSION_10_12
#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask
#endif

@interface SDLWindow : NSWindow <NSDraggingDestination>
/* These are needed for borderless/fullscreen windows */
Expand Down Expand Up @@ -849,14 +852,21 @@ -(NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPr
}
}


/* We'll respond to key events by doing nothing so we don't beep.
/* We'll respond to key events by mostly doing nothing so we don't beep.
* We could handle key messages here, but we lose some in the NSApp dispatch,
* where they get converted to action messages, etc.
*/
- (void)flagsChanged:(NSEvent *)theEvent
{
/*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/

/* Catch capslock in here as a special case:
https://developer.apple.com/library/archive/qa/qa1519/_index.html
Note that technote's check of keyCode doesn't work. At least on the
10.15 beta, capslock comes through here as keycode 255, but it's safe
to send duplicate key events; SDL filters them out quickly in
SDL_SendKeyboardKey(). */
SDL_SendKeyboardKey(([theEvent modifierFlags] & NSEventModifierFlagCapsLock) ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_CAPSLOCK);
}
- (void)keyDown:(NSEvent *)theEvent
{
Expand Down

0 comments on commit 57e08c2

Please sign in to comment.