Refactor iOS text input activation to better work with hardware keyboards
Description
Text input in SDL's iOS implementation is directly activated by requesting the hidden UITextField to become first responder. Once it becomes first responder, a software keyboard is shown if there are no hardware keyboard is attached, and textFieldTextDidChange events are raised whenever text is inputted by a hardware/software keyboard.
SDL has been doing the becomeFirstResponder/resignFirstResponder calls in the ShowScreenKeyboard/HideScreenKeyboard path. These paths are controlled by the AutoShowingScreenKeyboard() function, which returns false when a hardware keyboard is attached (unless the SDL_HINT_ENABLE_SCREEN_KEYBOARD hint is set to 1), therefore the text fields never become first responder and no text input is allowed by hardware keyboard regardless of whether SDL_StartTextInput is called.
This is unexpected behaviour, the text field become/resign first responder calls should not be in the ShowScreenKeyboard/HideScreenKeyboard path, they should instead be in the StartTextInput/StopTextInput path, which makes more sense given what the logic actually does (make the text field first responder / focused to receive text input).
Therefore, I've refactored the flow surrounding text input activation to do as proposed above.
I've also rewritten part of the logic of activating/deactivating text input in the keyboardWillShow/keyboardWillHide events so that it's clear why text input is stopped/started. As far as I can understand, text input should be stopped when the keyboard is hidden by user's request, unless one of these conditions are true:
- text input was never activated in the first place.
- a hardware keyboard is attached, as the user can still input text by the hardware keyboard (also when a hardware keyboard is connected while a software keyboard is present, the software keyboard automatically hides and
keyboardWillHideis raised) - the device changes orientation, which can sometimes invoke a series of
keyboardWillHide/keyboardWillShowcalls: text input should remain activated in this case.
Also, if a keyboardWillShow transition is subsequently invoked before a keyboardDidHide call, this indicates that the hide has been interrupted with a show, and in that case we want to bring back text input.
One might ask why checkKeys still works with hardware keyboard despite the above, and the answer to that is that the program calls SDL_StartTextInput before the hardware keyboard is added by the GCKeyboard event flow. I've confirmed this by checking the state of SDL_HasKeyboard() when the function is called in the test app, and it returned false. I've changed the test to not start text input immediately, but if that is bad then I can revert that.
Also, worthy of note that iOS simulator does not send GCKeyboardDidConnect/GCKeyboardDidDisconnect notifications whenever a hardware keyboard is attached/detached by Shift+Cmd+K or the "Connect Hardware keyboard" menu item, and GCKeyboard.coalescedKeyboard is always not null/nil. Therefore it's impossible to test the "text input deactivates when user hides keyboard" behaviour on iOS simulator, due to SDL_HasKeyboard() always being true.
Existing Issue(s)
- Resolves https://github.com/libsdl-org/SDL/issues/9624
- May (resolve) https://github.com/libsdl-org/SDL/issues/6465, I cannot reproduce the issues encountered there.
This generally sounds good to me, but if you can revert the checkkeys change that would be great. You can always make that change locally, but the checkkeys program is specifically designed to test text input, so we want that enabled at start.
Absolutely, I thought it's fine either way since you can start text input by right-clicking the app, but I guess there can be situations where the environment is limited.
Can you do git rebase -i origin and drop those two commits?
@frenzibyte, what's the current state of this PR? Are there pieces that we can split out and commit separately if that makes sense?
This PR is ready for review. I have included https://github.com/libsdl-org/SDL/pull/11406/commits/f4d81f2296a23d6f4695fc74142388ccfdb5418b in this PR to fix the concern raised in https://github.com/libsdl-org/SDL/pull/11406#discussion_r1827286984. I can split it out to a separate PR but I thought it doesn't have to be as the commit has pretty small diff.
Merged, thanks!