Added support for low latency mouse and keyboard handling in iOS 14
The mouse support in iOS 14.0 has a bug with accumulating duplicate mouse deltas that won't be fixed until iOS 14.1, so we don't enable it until then.
parent
d9aea0c3a0
commit
a3a0ef7527
|
@ -25,6 +25,14 @@
|
|||
|
||||
extern void UIKit_PumpEvents(_THIS);
|
||||
|
||||
extern void SDL_InitGCKeyboard(void);
|
||||
extern SDL_bool SDL_HasGCKeyboard(void);
|
||||
extern void SDL_QuitGCKeyboard(void);
|
||||
|
||||
extern void SDL_InitGCMouse(void);
|
||||
extern SDL_bool SDL_HasGCMouse(void);
|
||||
extern void SDL_QuitGCMouse(void);
|
||||
|
||||
#endif /* SDL_uikitevents_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -30,6 +30,13 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if (__IPHONE_OS_VERSION_MAX_ALLOWED >= 140000) || (__APPLETV_OS_VERSION_MAX_ALLOWED >= 140000) || (__MAC_OS_VERSION_MAX_ALLOWED > 1500000)
|
||||
#import <GameController/GameController.h>
|
||||
|
||||
#define ENABLE_GCKEYBOARD
|
||||
#define ENABLE_GCMOUSE
|
||||
#endif
|
||||
|
||||
static BOOL UIKit_EventPumpEnabled = YES;
|
||||
|
||||
void
|
||||
|
@ -70,6 +77,247 @@ UIKit_PumpEvents(_THIS)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_GCKEYBOARD
|
||||
|
||||
static SDL_bool keyboard_connected = SDL_FALSE;
|
||||
static id keyboard_connect_observer = nil;
|
||||
static id keyboard_disconnect_observer = nil;
|
||||
|
||||
static void OnGCKeyboardConnected(GCKeyboard *keyboard) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0))
|
||||
{
|
||||
keyboard_connected = SDL_TRUE;
|
||||
keyboard.keyboardInput.keyChangedHandler = ^(GCKeyboardInput *keyboard, GCControllerButtonInput *key, GCKeyCode keyCode, BOOL pressed)
|
||||
{
|
||||
SDL_SendKeyboardKey(pressed ? SDL_PRESSED : SDL_RELEASED, (SDL_Scancode)keyCode);
|
||||
};
|
||||
}
|
||||
|
||||
static void OnGCKeyboardDisconnected(GCKeyboard *keyboard) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0))
|
||||
{
|
||||
keyboard.keyboardInput.keyChangedHandler = nil;
|
||||
keyboard_connected = SDL_FALSE;
|
||||
}
|
||||
|
||||
void SDL_InitGCKeyboard(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (@available(iOS 14.0, tvOS 14.0, *)) {
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
|
||||
keyboard_connect_observer = [center addObserverForName:GCKeyboardDidConnectNotification
|
||||
object:nil
|
||||
queue:nil
|
||||
usingBlock:^(NSNotification *note) {
|
||||
GCKeyboard *keyboard = note.object;
|
||||
OnGCKeyboardConnected(keyboard);
|
||||
}];
|
||||
|
||||
keyboard_disconnect_observer = [center addObserverForName:GCKeyboardDidDisconnectNotification
|
||||
object:nil
|
||||
queue:nil
|
||||
usingBlock:^(NSNotification *note) {
|
||||
GCKeyboard *keyboard = note.object;
|
||||
OnGCKeyboardDisconnected(keyboard);
|
||||
}];
|
||||
|
||||
if (GCKeyboard.coalescedKeyboard != nil) {
|
||||
OnGCKeyboardConnected(GCKeyboard.coalescedKeyboard);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_bool SDL_HasGCKeyboard(void)
|
||||
{
|
||||
return keyboard_connected;
|
||||
}
|
||||
|
||||
void SDL_QuitGCKeyboard(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (@available(iOS 14.0, tvOS 14.0, *)) {
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
|
||||
if (keyboard_connect_observer) {
|
||||
[center removeObserver:keyboard_connect_observer name:GCKeyboardDidConnectNotification object:nil];
|
||||
keyboard_connect_observer = nil;
|
||||
}
|
||||
|
||||
if (keyboard_disconnect_observer) {
|
||||
[center removeObserver:keyboard_disconnect_observer name:GCKeyboardDidDisconnectNotification object:nil];
|
||||
keyboard_disconnect_observer = nil;
|
||||
}
|
||||
|
||||
if (GCKeyboard.coalescedKeyboard != nil) {
|
||||
OnGCKeyboardDisconnected(GCKeyboard.coalescedKeyboard);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void SDL_InitGCKeyboard(void)
|
||||
{
|
||||
}
|
||||
|
||||
SDL_bool SDL_HasGCKeyboard(void)
|
||||
{
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
void SDL_QuitGCKeyboard(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* ENABLE_GCKEYBOARD */
|
||||
|
||||
|
||||
#ifdef ENABLE_GCMOUSE
|
||||
|
||||
static int mice_connected = 0;
|
||||
static id mouse_connect_observer = nil;
|
||||
static id mouse_disconnect_observer = nil;
|
||||
|
||||
static int SetGCMouseRelativeMode(SDL_bool enabled)
|
||||
{
|
||||
/* We'll always send relative motion and we can't warp, so nothing to do here */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void OnGCMouseButtonChanged(SDL_MouseID mouseID, Uint8 button, BOOL pressed)
|
||||
{
|
||||
SDL_SendMouseButton(SDL_GetMouseFocus(), mouseID, pressed ? SDL_PRESSED : SDL_RELEASED, button);
|
||||
}
|
||||
|
||||
static void OnGCMouseConnected(GCMouse *mouse) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0))
|
||||
{
|
||||
SDL_MouseID mouseID = mice_connected;
|
||||
|
||||
mouse.mouseInput.leftButton.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
|
||||
{
|
||||
OnGCMouseButtonChanged(mouseID, SDL_BUTTON_LEFT, pressed);
|
||||
};
|
||||
mouse.mouseInput.middleButton.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
|
||||
{
|
||||
OnGCMouseButtonChanged(mouseID, SDL_BUTTON_MIDDLE, pressed);
|
||||
};
|
||||
mouse.mouseInput.rightButton.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
|
||||
{
|
||||
OnGCMouseButtonChanged(mouseID, SDL_BUTTON_RIGHT, pressed);
|
||||
};
|
||||
|
||||
int auxiliary_button = SDL_BUTTON_X1;
|
||||
for (GCControllerButtonInput *button in mouse.mouseInput.auxiliaryButtons) {
|
||||
button.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
|
||||
{
|
||||
OnGCMouseButtonChanged(mouseID, auxiliary_button, pressed);
|
||||
};
|
||||
++auxiliary_button;
|
||||
}
|
||||
|
||||
mouse.mouseInput.mouseMovedHandler = ^(GCMouseInput *mouse, float deltaX, float deltaY)
|
||||
{
|
||||
SDL_SendMouseMotion(SDL_GetMouseFocus(), mouseID, SDL_TRUE, (int)deltaX, -(int)deltaY);
|
||||
};
|
||||
|
||||
++mice_connected;
|
||||
}
|
||||
|
||||
static void OnGCMouseDisconnected(GCMouse *mouse) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0))
|
||||
{
|
||||
--mice_connected;
|
||||
|
||||
mouse.mouseInput.mouseMovedHandler = nil;
|
||||
|
||||
mouse.mouseInput.leftButton.pressedChangedHandler = nil;
|
||||
mouse.mouseInput.middleButton.pressedChangedHandler = nil;
|
||||
mouse.mouseInput.rightButton.pressedChangedHandler = nil;
|
||||
|
||||
for (GCControllerButtonInput *button in mouse.mouseInput.auxiliaryButtons) {
|
||||
button.pressedChangedHandler = nil;
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_InitGCMouse(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
/* There is a bug where mouse accumulates duplicate deltas over time in iOS 14.0 */
|
||||
if (@available(iOS 14.1, tvOS 14.1, *)) {
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
|
||||
mouse_connect_observer = [center addObserverForName:GCMouseDidConnectNotification
|
||||
object:nil
|
||||
queue:nil
|
||||
usingBlock:^(NSNotification *note) {
|
||||
GCMouse *mouse = note.object;
|
||||
OnGCMouseConnected(mouse);
|
||||
}];
|
||||
|
||||
mouse_disconnect_observer = [center addObserverForName:GCMouseDidDisconnectNotification
|
||||
object:nil
|
||||
queue:nil
|
||||
usingBlock:^(NSNotification *note) {
|
||||
GCMouse *mouse = note.object;
|
||||
OnGCMouseDisconnected(mouse);
|
||||
}];
|
||||
|
||||
for (GCMouse *mouse in [GCMouse mice]) {
|
||||
OnGCMouseConnected(mouse);
|
||||
}
|
||||
|
||||
SDL_GetMouse()->SetRelativeMouseMode = SetGCMouseRelativeMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_bool SDL_HasGCMouse(void)
|
||||
{
|
||||
return (mice_connected > 0);
|
||||
}
|
||||
|
||||
void SDL_QuitGCMouse(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (@available(iOS 14.0, tvOS 14.0, *)) {
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
|
||||
if (mouse_connect_observer) {
|
||||
[center removeObserver:mouse_connect_observer name:GCMouseDidConnectNotification object:nil];
|
||||
mouse_connect_observer = nil;
|
||||
}
|
||||
|
||||
if (mouse_disconnect_observer) {
|
||||
[center removeObserver:mouse_disconnect_observer name:GCMouseDidDisconnectNotification object:nil];
|
||||
mouse_disconnect_observer = nil;
|
||||
}
|
||||
|
||||
for (GCMouse *mouse in [GCMouse mice]) {
|
||||
OnGCMouseDisconnected(mouse);
|
||||
}
|
||||
|
||||
SDL_GetMouse()->SetRelativeMouseMode = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void SDL_InitGCMouse(void)
|
||||
{
|
||||
}
|
||||
|
||||
SDL_bool SDL_HasGCMouse(void)
|
||||
{
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
void SDL_QuitGCMouse(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* ENABLE_GCMOUSE */
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_UIKIT */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -158,12 +158,19 @@ UIKit_VideoInit(_THIS)
|
|||
if (UIKit_InitModes(_this) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_InitGCKeyboard();
|
||||
SDL_InitGCMouse();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_VideoQuit(_THIS)
|
||||
{
|
||||
SDL_QuitGCKeyboard();
|
||||
SDL_QuitGCMouse();
|
||||
|
||||
UIKit_QuitModes(_this);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,9 +29,10 @@
|
|||
#include "../../events/SDL_touch_c.h"
|
||||
#include "../../events/SDL_events_c.h"
|
||||
|
||||
#import "SDL_uikitappdelegate.h"
|
||||
#import "SDL_uikitmodes.h"
|
||||
#import "SDL_uikitwindow.h"
|
||||
#include "SDL_uikitappdelegate.h"
|
||||
#include "SDL_uikitevents.h"
|
||||
#include "SDL_uikitmodes.h"
|
||||
#include "SDL_uikitwindow.h"
|
||||
|
||||
/* The maximum number of mouse buttons we support */
|
||||
#define MAX_MOUSE_BUTTONS 5
|
||||
|
@ -159,7 +160,7 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
|
|||
|
||||
#if !TARGET_OS_TV && defined(__IPHONE_13_4)
|
||||
- (UIPointerRegion *)pointerInteraction:(UIPointerInteraction *)interaction regionForRequest:(UIPointerRegionRequest *)request defaultRegion:(UIPointerRegion *)defaultRegion API_AVAILABLE(ios(13.4)){
|
||||
if (request != nil) {
|
||||
if (request != nil && !SDL_HasGCMouse()) {
|
||||
CGPoint origin = self.bounds.origin;
|
||||
CGPoint point = request.location;
|
||||
|
||||
|
@ -236,27 +237,29 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
|
|||
#if !TARGET_OS_TV && defined(__IPHONE_13_4)
|
||||
if (@available(iOS 13.4, *)) {
|
||||
if (touch.type == UITouchTypeIndirectPointer) {
|
||||
int i;
|
||||
if (!SDL_HasGCMouse()) {
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= MAX_MOUSE_BUTTONS; ++i) {
|
||||
if (event.buttonMask & SDL_BUTTON(i)) {
|
||||
Uint8 button;
|
||||
for (i = 1; i <= MAX_MOUSE_BUTTONS; ++i) {
|
||||
if ((event.buttonMask & SDL_BUTTON(i)) != 0) {
|
||||
Uint8 button;
|
||||
|
||||
switch (i) {
|
||||
case 1:
|
||||
button = SDL_BUTTON_LEFT;
|
||||
break;
|
||||
case 2:
|
||||
button = SDL_BUTTON_RIGHT;
|
||||
break;
|
||||
case 3:
|
||||
button = SDL_BUTTON_MIDDLE;
|
||||
break;
|
||||
default:
|
||||
button = (Uint8)i;
|
||||
break;
|
||||
switch (i) {
|
||||
case 1:
|
||||
button = SDL_BUTTON_LEFT;
|
||||
break;
|
||||
case 2:
|
||||
button = SDL_BUTTON_RIGHT;
|
||||
break;
|
||||
case 3:
|
||||
button = SDL_BUTTON_MIDDLE;
|
||||
break;
|
||||
default:
|
||||
button = (Uint8)i;
|
||||
break;
|
||||
}
|
||||
SDL_SendMouseButton(sdlwindow, 0, SDL_PRESSED, button);
|
||||
}
|
||||
SDL_SendMouseButton(sdlwindow, 0, SDL_PRESSED, button);
|
||||
}
|
||||
}
|
||||
handled = YES;
|
||||
|
@ -289,27 +292,29 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
|
|||
#if !TARGET_OS_TV && defined(__IPHONE_13_4)
|
||||
if (@available(iOS 13.4, *)) {
|
||||
if (touch.type == UITouchTypeIndirectPointer) {
|
||||
int i;
|
||||
if (!SDL_HasGCMouse()) {
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= MAX_MOUSE_BUTTONS; ++i) {
|
||||
if (!(event.buttonMask & SDL_BUTTON(i))) {
|
||||
Uint8 button;
|
||||
for (i = 1; i <= MAX_MOUSE_BUTTONS; ++i) {
|
||||
if ((event.buttonMask & SDL_BUTTON(i)) != 0) {
|
||||
Uint8 button;
|
||||
|
||||
switch (i) {
|
||||
case 1:
|
||||
button = SDL_BUTTON_LEFT;
|
||||
break;
|
||||
case 2:
|
||||
button = SDL_BUTTON_RIGHT;
|
||||
break;
|
||||
case 3:
|
||||
button = SDL_BUTTON_MIDDLE;
|
||||
break;
|
||||
default:
|
||||
button = (Uint8)i;
|
||||
break;
|
||||
switch (i) {
|
||||
case 1:
|
||||
button = SDL_BUTTON_LEFT;
|
||||
break;
|
||||
case 2:
|
||||
button = SDL_BUTTON_RIGHT;
|
||||
break;
|
||||
case 3:
|
||||
button = SDL_BUTTON_MIDDLE;
|
||||
break;
|
||||
default:
|
||||
button = (Uint8)i;
|
||||
break;
|
||||
}
|
||||
SDL_SendMouseButton(sdlwindow, 0, SDL_RELEASED, button);
|
||||
}
|
||||
SDL_SendMouseButton(sdlwindow, 0, SDL_RELEASED, button);
|
||||
}
|
||||
}
|
||||
handled = YES;
|
||||
|
@ -411,27 +416,33 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
|
|||
|
||||
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
|
||||
{
|
||||
for (UIPress *press in presses) {
|
||||
SDL_Scancode scancode = [self scancodeFromPress:press];
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, scancode);
|
||||
if (!SDL_HasGCKeyboard()) {
|
||||
for (UIPress *press in presses) {
|
||||
SDL_Scancode scancode = [self scancodeFromPress:press];
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, scancode);
|
||||
}
|
||||
}
|
||||
[super pressesBegan:presses withEvent:event];
|
||||
}
|
||||
|
||||
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
|
||||
{
|
||||
for (UIPress *press in presses) {
|
||||
SDL_Scancode scancode = [self scancodeFromPress:press];
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
|
||||
if (!SDL_HasGCKeyboard()) {
|
||||
for (UIPress *press in presses) {
|
||||
SDL_Scancode scancode = [self scancodeFromPress:press];
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
|
||||
}
|
||||
}
|
||||
[super pressesEnded:presses withEvent:event];
|
||||
}
|
||||
|
||||
- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
|
||||
{
|
||||
for (UIPress *press in presses) {
|
||||
SDL_Scancode scancode = [self scancodeFromPress:press];
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
|
||||
if (!SDL_HasGCKeyboard()) {
|
||||
for (UIPress *press in presses) {
|
||||
SDL_Scancode scancode = [self scancodeFromPress:press];
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
|
||||
}
|
||||
}
|
||||
[super pressesCancelled:presses withEvent:event];
|
||||
}
|
||||
|
|
|
@ -430,7 +430,7 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
|
|||
}
|
||||
|
||||
if (mod & KMOD_SHIFT) {
|
||||
/* If character uses shift, press shift down */
|
||||
/* If character uses shift, press shift */
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
|
||||
}
|
||||
|
||||
|
@ -439,7 +439,7 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
|
|||
SDL_SendKeyboardKey(SDL_RELEASED, code);
|
||||
|
||||
if (mod & KMOD_SHIFT) {
|
||||
/* If character uses shift, press shift back up */
|
||||
/* If character uses shift, release shift */
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue