cocoa: Check for capslock in -[NSResponder flagsChanged], not with IOKit.

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.
This commit is contained in:
Ryan C. Gordon 2019-06-26 13:21:43 -04:00
parent 0beadea574
commit 57e08c27ef
2 changed files with 12 additions and 115 deletions

View File

@ -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(...)
@ -187,115 +186,6 @@
@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
@ -585,8 +475,6 @@ Cocoa_InitKeyboard(_THIS)
data->modifierFlags = [NSEvent modifierFlags];
SDL_ToggleModState(KMOD_CAPS, (data->modifierFlags & NSEventModifierFlagCapsLock) != 0);
InitHIDCallback();
}
void
@ -712,7 +600,6 @@ Cocoa_HandleKeyEvent(_THIS, NSEvent *event)
void
Cocoa_QuitKeyboard(_THIS)
{
QuitHIDCallback();
}
#endif /* SDL_VIDEO_DRIVER_COCOA */

View File

@ -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 */
@ -849,14 +852,21 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
}
}
/* 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
{