1
0
Эх сурвалжийг харах

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

Sam Lantinga 5 жил өмнө
parent
commit
d4f1b520c9

+ 6 - 2
src/events/SDL_events.c

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

+ 70 - 10
src/events/SDL_keyboard.c

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

+ 7 - 0
src/events/SDL_keyboard_c.h

@@ -49,6 +49,13 @@ extern void SDL_SetKeyboardFocus(SDL_Window * window);
 
 /* Send a keyboard key event */
 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 */
 extern int SDL_SendKeyboardText(const char *text);

+ 46 - 47
src/video/uikit/SDL_uikitview.m

@@ -245,61 +245,64 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
 }
 
 #if TARGET_OS_TV || defined(__IPHONE_9_1)
-- (SDL_Scancode)scancodeFromPressType:(UIPressType)presstype
+- (SDL_Scancode)scancodeFromPress:(UIPress*)press
 {
-    switch (presstype) {
-    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:
-        return SDL_SCANCODE_UNKNOWN;
+    if (press.key != nil) {
+        return (SDL_Scancode)press.key.keyCode;
     }
+
+	/* 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
 {
-    if (!SDL_AppleTVRemoteOpenedAsJoystick) {
-        for (UIPress *press in presses) {
-            SDL_Scancode scancode = [self scancodeFromPressType:press.type];
-            SDL_SendKeyboardKey(SDL_PRESSED, scancode);
-        }
-    }
+	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
 {
-    if (!SDL_AppleTVRemoteOpenedAsJoystick) {
-        for (UIPress *press in presses) {
-            SDL_Scancode scancode = [self scancodeFromPressType:press.type];
-            SDL_SendKeyboardKey(SDL_RELEASED, scancode);
-        }
-    }
+	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
 {
-    if (!SDL_AppleTVRemoteOpenedAsJoystick) {
-        for (UIPress *press in presses) {
-            SDL_Scancode scancode = [self scancodeFromPressType:press.type];
-            SDL_SendKeyboardKey(SDL_RELEASED, scancode);
-        }
-    }
+	for (UIPress *press in presses) {
+		SDL_Scancode scancode = [self scancodeFromPress:press];
+		SDL_SendKeyboardKey(SDL_RELEASED, scancode);
+	}
     [super pressesCancelled:presses withEvent:event];
 }
 
@@ -320,20 +323,16 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
              * which better maps to swipe gestures. */
             switch (gesture.direction) {
             case UISwipeGestureRecognizerDirectionUp:
-                SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_UP);
-                SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_UP);
+                SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_UP);
                 break;
             case UISwipeGestureRecognizerDirectionDown:
-                SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_DOWN);
-                SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_DOWN);
+                SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_DOWN);
                 break;
             case UISwipeGestureRecognizerDirectionLeft:
-                SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LEFT);
-                SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LEFT);
+                SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_LEFT);
                 break;
             case UISwipeGestureRecognizerDirectionRight:
-                SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RIGHT);
-                SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RIGHT);
+                SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_RIGHT);
                 break;
             }
         }

+ 36 - 37
src/video/uikit/SDL_uikitviewcontroller.m

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