Added support for press/release hardware keyboard events in iOS 13.4

This commit is contained in:
Sam Lantinga 2020-04-08 19:16:31 -07:00
parent e9c94ac0b3
commit d4f1b520c9
5 changed files with 161 additions and 92 deletions

View File

@ -35,9 +35,9 @@
#undef SDL_PRIs64 #undef SDL_PRIs64
#ifdef __WIN32__ #ifdef __WIN32__
#define SDL_PRIs64 "I64d" #define SDL_PRIs64 "I64d"
#else #else
#define SDL_PRIs64 "lld" #define SDL_PRIs64 "lld"
#endif #endif
/* An arbitrary limit so we don't have unbounded growth */ /* An arbitrary limit so we don't have unbounded growth */
@ -678,10 +678,14 @@ SDL_PumpEvents(void)
{ {
SDL_VideoDevice *_this = SDL_GetVideoDevice(); SDL_VideoDevice *_this = SDL_GetVideoDevice();
/* Release any keys held down from last frame */
SDL_ReleaseAutoReleaseKeys();
/* Get events from the video subsystem */ /* Get events from the video subsystem */
if (_this) { if (_this) {
_this->PumpEvents(_this); _this->PumpEvents(_this);
} }
#if !SDL_JOYSTICK_DISABLED #if !SDL_JOYSTICK_DISABLED
/* Check for joystick state change */ /* Check for joystick state change */
if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) { if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) {

View File

@ -33,6 +33,9 @@
/* Global keyboard information */ /* Global keyboard information */
#define KEYBOARD_HARDWARE 0x01
#define KEYBOARD_AUTORELEASE 0x02
typedef struct SDL_Keyboard SDL_Keyboard; typedef struct SDL_Keyboard SDL_Keyboard;
struct SDL_Keyboard struct SDL_Keyboard
@ -40,8 +43,10 @@ struct SDL_Keyboard
/* Data common to all keyboards */ /* Data common to all keyboards */
SDL_Window *focus; SDL_Window *focus;
Uint16 modstate; Uint16 modstate;
Uint8 keysource[SDL_NUM_SCANCODES];
Uint8 keystate[SDL_NUM_SCANCODES]; Uint8 keystate[SDL_NUM_SCANCODES];
SDL_Keycode keymap[SDL_NUM_SCANCODES]; SDL_Keycode keymap[SDL_NUM_SCANCODES];
SDL_bool autorelease_pending;
}; };
static SDL_Keyboard SDL_keyboard; static SDL_Keyboard SDL_keyboard;
@ -675,19 +680,20 @@ SDL_SetKeyboardFocus(SDL_Window * window)
} }
} }
int static int
SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode) SDL_SendKeyboardKeyInternal(Uint8 source, Uint8 state, SDL_Scancode scancode)
{ {
SDL_Keyboard *keyboard = &SDL_keyboard; SDL_Keyboard *keyboard = &SDL_keyboard;
int posted; int posted;
SDL_Keymod modifier; SDL_Keymod modifier;
SDL_Keycode keycode; SDL_Keycode keycode;
Uint32 type; Uint32 type;
Uint8 repeat; Uint8 repeat = SDL_FALSE;
if (!scancode) { if (scancode == SDL_SCANCODE_UNKNOWN) {
return 0; return 0;
} }
#ifdef DEBUG_KEYBOARD #ifdef DEBUG_KEYBOARD
printf("The '%s' key has been %s\n", SDL_GetScancodeName(scancode), printf("The '%s' key has been %s\n", SDL_GetScancodeName(scancode),
state == SDL_PRESSED ? "pressed" : "released"); state == SDL_PRESSED ? "pressed" : "released");
@ -707,12 +713,20 @@ SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
} }
/* Drop events that don't change state */ /* Drop events that don't change state */
repeat = (state && keyboard->keystate[scancode]); if (state) {
if (keyboard->keystate[scancode] == state && !repeat) { if (keyboard->keystate[scancode]) {
#if 0 if (!(keyboard->keysource[scancode] & source)) {
printf("Keyboard event didn't change state - dropped!\n"); keyboard->keysource[scancode] |= source;
#endif return 0;
return 0; }
repeat = SDL_TRUE;
}
keyboard->keysource[scancode] |= source;
} else {
if (!keyboard->keystate[scancode]) {
return 0;
}
keyboard->keysource[scancode] = 0;
} }
/* Update internal keyboard state */ /* Update internal keyboard state */
@ -720,6 +734,10 @@ SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
keycode = keyboard->keymap[scancode]; keycode = keyboard->keymap[scancode];
if (source == KEYBOARD_AUTORELEASE) {
keyboard->autorelease_pending = SDL_TRUE;
}
/* Update modifiers state if applicable */ /* Update modifiers state if applicable */
switch (keycode) { switch (keycode) {
case SDLK_LCTRL: case SDLK_LCTRL:
@ -785,6 +803,48 @@ SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
return (posted); return (posted);
} }
int
SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
{
return SDL_SendKeyboardKeyInternal(KEYBOARD_HARDWARE, state, scancode);
}
int
SDL_SendKeyboardKeyAutoRelease(SDL_Scancode scancode)
{
return SDL_SendKeyboardKeyInternal(KEYBOARD_AUTORELEASE, SDL_PRESSED, scancode);
}
void
SDL_ReleaseAutoReleaseKeys(void)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
SDL_Scancode scancode;
if (keyboard->autorelease_pending) {
for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES; ++scancode) {
if (keyboard->keysource[scancode] == KEYBOARD_AUTORELEASE) {
SDL_SendKeyboardKeyInternal(KEYBOARD_AUTORELEASE, SDL_RELEASED, scancode);
}
}
keyboard->autorelease_pending = SDL_FALSE;
}
}
SDL_bool
SDL_HardwareKeyboardKeyPressed(void)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
SDL_Scancode scancode;
for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES; ++scancode) {
if ((keyboard->keysource[scancode] & KEYBOARD_HARDWARE) != 0) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
int int
SDL_SendKeyboardText(const char *text) SDL_SendKeyboardText(const char *text)
{ {

View File

@ -49,6 +49,13 @@ extern void SDL_SetKeyboardFocus(SDL_Window * window);
/* Send a keyboard key event */ /* Send a keyboard key event */
extern int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode); extern int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode);
extern int SDL_SendKeyboardKeyAutoRelease(SDL_Scancode scancode);
/* Release all the autorelease keys */
extern void SDL_ReleaseAutoReleaseKeys(void);
/* Return true if any hardware key is pressed */
extern SDL_bool SDL_HardwareKeyboardKeyPressed(void);
/* Send keyboard text input */ /* Send keyboard text input */
extern int SDL_SendKeyboardText(const char *text); extern int SDL_SendKeyboardText(const char *text);

View File

@ -245,61 +245,64 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
} }
#if TARGET_OS_TV || defined(__IPHONE_9_1) #if TARGET_OS_TV || defined(__IPHONE_9_1)
- (SDL_Scancode)scancodeFromPressType:(UIPressType)presstype - (SDL_Scancode)scancodeFromPress:(UIPress*)press
{ {
switch (presstype) { if (press.key != nil) {
case UIPressTypeUpArrow: return (SDL_Scancode)press.key.keyCode;
return SDL_SCANCODE_UP;
case UIPressTypeDownArrow:
return SDL_SCANCODE_DOWN;
case UIPressTypeLeftArrow:
return SDL_SCANCODE_LEFT;
case UIPressTypeRightArrow:
return SDL_SCANCODE_RIGHT;
case UIPressTypeSelect:
/* HIG says: "primary button behavior" */
return SDL_SCANCODE_RETURN;
case UIPressTypeMenu:
/* HIG says: "returns to previous screen" */
return SDL_SCANCODE_ESCAPE;
case UIPressTypePlayPause:
/* HIG says: "secondary button behavior" */
return SDL_SCANCODE_PAUSE;
default:
return SDL_SCANCODE_UNKNOWN;
} }
/* Presses from Apple TV remote */
if (!SDL_AppleTVRemoteOpenedAsJoystick) {
switch (press.type) {
case UIPressTypeUpArrow:
return SDL_SCANCODE_UP;
case UIPressTypeDownArrow:
return SDL_SCANCODE_DOWN;
case UIPressTypeLeftArrow:
return SDL_SCANCODE_LEFT;
case UIPressTypeRightArrow:
return SDL_SCANCODE_RIGHT;
case UIPressTypeSelect:
/* HIG says: "primary button behavior" */
return SDL_SCANCODE_RETURN;
case UIPressTypeMenu:
/* HIG says: "returns to previous screen" */
return SDL_SCANCODE_ESCAPE;
case UIPressTypePlayPause:
/* HIG says: "secondary button behavior" */
return SDL_SCANCODE_PAUSE;
default:
break;
}
}
return SDL_SCANCODE_UNKNOWN;
} }
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event - (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{ {
if (!SDL_AppleTVRemoteOpenedAsJoystick) { for (UIPress *press in presses) {
for (UIPress *press in presses) { SDL_Scancode scancode = [self scancodeFromPress:press];
SDL_Scancode scancode = [self scancodeFromPressType:press.type]; SDL_SendKeyboardKey(SDL_PRESSED, scancode);
SDL_SendKeyboardKey(SDL_PRESSED, scancode); }
}
}
[super pressesBegan:presses withEvent:event]; [super pressesBegan:presses withEvent:event];
} }
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event - (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{ {
if (!SDL_AppleTVRemoteOpenedAsJoystick) { for (UIPress *press in presses) {
for (UIPress *press in presses) { SDL_Scancode scancode = [self scancodeFromPress:press];
SDL_Scancode scancode = [self scancodeFromPressType:press.type]; SDL_SendKeyboardKey(SDL_RELEASED, scancode);
SDL_SendKeyboardKey(SDL_RELEASED, scancode); }
}
}
[super pressesEnded:presses withEvent:event]; [super pressesEnded:presses withEvent:event];
} }
- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event - (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{ {
if (!SDL_AppleTVRemoteOpenedAsJoystick) { for (UIPress *press in presses) {
for (UIPress *press in presses) { SDL_Scancode scancode = [self scancodeFromPress:press];
SDL_Scancode scancode = [self scancodeFromPressType:press.type]; SDL_SendKeyboardKey(SDL_RELEASED, scancode);
SDL_SendKeyboardKey(SDL_RELEASED, scancode); }
}
}
[super pressesCancelled:presses withEvent:event]; [super pressesCancelled:presses withEvent:event];
} }
@ -320,20 +323,16 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
* which better maps to swipe gestures. */ * which better maps to swipe gestures. */
switch (gesture.direction) { switch (gesture.direction) {
case UISwipeGestureRecognizerDirectionUp: case UISwipeGestureRecognizerDirectionUp:
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_UP); SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_UP);
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_UP);
break; break;
case UISwipeGestureRecognizerDirectionDown: case UISwipeGestureRecognizerDirectionDown:
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_DOWN); SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_DOWN);
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_DOWN);
break; break;
case UISwipeGestureRecognizerDirectionLeft: case UISwipeGestureRecognizerDirectionLeft:
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LEFT); SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_LEFT);
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LEFT);
break; break;
case UISwipeGestureRecognizerDirectionRight: case UISwipeGestureRecognizerDirectionRight:
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RIGHT); SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_RIGHT);
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RIGHT);
break; break;
} }
} }

View File

@ -317,8 +317,7 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
} }
if (scancode != SDL_SCANCODE_UNKNOWN) { if (scancode != SDL_SCANCODE_UNKNOWN) {
SDL_SendKeyboardKey(SDL_PRESSED, scancode); SDL_SendKeyboardKeyAutoRelease(scancode);
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
} }
} }
@ -342,7 +341,7 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {} [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {}
completion:^(id<UIViewControllerTransitionCoordinatorContext> context) { completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
self->rotatingOrientation = NO; self->rotatingOrientation = NO;
}]; }];
} }
#else #else
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
@ -411,36 +410,38 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
{ {
NSUInteger len = changeText.length; NSUInteger len = changeText.length;
if (len > 0) { if (len > 0) {
/* Go through all the characters in the string we've been sent and if (!SDL_HardwareKeyboardKeyPressed()) {
* convert them to key presses */ /* Go through all the characters in the string we've been sent and
int i; * convert them to key presses */
for (i = 0; i < len; i++) { int i;
unichar c = [changeText characterAtIndex:i]; for (i = 0; i < len; i++) {
SDL_Scancode code; unichar c = [changeText characterAtIndex:i];
Uint16 mod; SDL_Scancode code;
Uint16 mod;
if (c < 127) { if (c < 127) {
/* Figure out the SDL_Scancode and SDL_keymod for this unichar */ /* Figure out the SDL_Scancode and SDL_keymod for this unichar */
code = unicharToUIKeyInfoTable[c].code; code = unicharToUIKeyInfoTable[c].code;
mod = unicharToUIKeyInfoTable[c].mod; mod = unicharToUIKeyInfoTable[c].mod;
} else { } else {
/* We only deal with ASCII right now */ /* We only deal with ASCII right now */
code = SDL_SCANCODE_UNKNOWN; code = SDL_SCANCODE_UNKNOWN;
mod = 0; mod = 0;
} }
if (mod & KMOD_SHIFT) { if (mod & KMOD_SHIFT) {
/* If character uses shift, press shift down */ /* If character uses shift, press shift down */
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT); SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
} }
/* send a keydown and keyup even for the character */ /* send a keydown and keyup even for the character */
SDL_SendKeyboardKey(SDL_PRESSED, code); SDL_SendKeyboardKey(SDL_PRESSED, code);
SDL_SendKeyboardKey(SDL_RELEASED, code); SDL_SendKeyboardKey(SDL_RELEASED, code);
if (mod & KMOD_SHIFT) { if (mod & KMOD_SHIFT) {
/* If character uses shift, press shift back up */ /* If character uses shift, press shift back up */
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT); SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
}
} }
} }
SDL_SendKeyboardText([changeText UTF8String]); SDL_SendKeyboardText([changeText UTF8String]);
@ -491,8 +492,7 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
changeText = nil; changeText = nil;
if (textField.markedTextRange == nil) { if (textField.markedTextRange == nil) {
/* it wants to replace text with nothing, ie a delete */ /* it wants to replace text with nothing, ie a delete */
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE); SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_BACKSPACE);
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
} }
if (textField.text.length < 16) { if (textField.text.length < 16) {
textField.text = obligateForBackspace; textField.text = obligateForBackspace;
@ -506,8 +506,7 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
/* Terminates the editing session */ /* Terminates the editing session */
- (BOOL)textFieldShouldReturn:(UITextField*)_textField - (BOOL)textFieldShouldReturn:(UITextField*)_textField
{ {
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN); SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_RETURN);
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
if (keyboardVisible && if (keyboardVisible &&
SDL_GetHintBoolean(SDL_HINT_RETURN_KEY_HIDES_IME, SDL_FALSE)) { SDL_GetHintBoolean(SDL_HINT_RETURN_KEY_HIDES_IME, SDL_FALSE)) {
SDL_StopTextInput(); SDL_StopTextInput();