Refactor iOS text input activation to better work with hardware keyboards

This commit is contained in:
Salman Alshamrani 2024-11-03 23:12:27 -05:00 committed by Sam Lantinga
parent 72895a6994
commit 5d09656afa
3 changed files with 54 additions and 68 deletions

View file

@ -97,8 +97,8 @@ static SDL_VideoDevice *UIKit_CreateDevice(void)
#ifdef SDL_IPHONE_KEYBOARD #ifdef SDL_IPHONE_KEYBOARD
device->HasScreenKeyboardSupport = UIKit_HasScreenKeyboardSupport; device->HasScreenKeyboardSupport = UIKit_HasScreenKeyboardSupport;
device->ShowScreenKeyboard = UIKit_ShowScreenKeyboard; device->StartTextInput = UIKit_StartTextInput;
device->HideScreenKeyboard = UIKit_HideScreenKeyboard; device->StopTextInput = UIKit_StopTextInput;
device->IsScreenKeyboardShown = UIKit_IsScreenKeyboardShown; device->IsScreenKeyboardShown = UIKit_IsScreenKeyboardShown;
device->UpdateTextInputArea = UIKit_UpdateTextInputArea; device->UpdateTextInputArea = UIKit_UpdateTextInputArea;
#endif #endif

View file

@ -69,8 +69,8 @@
#endif #endif
#ifdef SDL_IPHONE_KEYBOARD #ifdef SDL_IPHONE_KEYBOARD
- (void)showKeyboard; - (bool)startTextInput;
- (void)hideKeyboard; - (bool)stopTextInput;
- (void)initKeyboard; - (void)initKeyboard;
- (void)deinitKeyboard; - (void)deinitKeyboard;
@ -79,7 +79,7 @@
- (void)updateKeyboard; - (void)updateKeyboard;
@property(nonatomic, assign, getter=isKeyboardVisible) BOOL keyboardVisible; @property(nonatomic, assign, getter=isTextFieldFocused) BOOL textFieldFocused;
@property(nonatomic, assign) SDL_Rect textInputRect; @property(nonatomic, assign) SDL_Rect textInputRect;
@property(nonatomic, assign) int keyboardHeight; @property(nonatomic, assign) int keyboardHeight;
#endif #endif
@ -88,8 +88,8 @@
#ifdef SDL_IPHONE_KEYBOARD #ifdef SDL_IPHONE_KEYBOARD
bool UIKit_HasScreenKeyboardSupport(SDL_VideoDevice *_this); bool UIKit_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
void UIKit_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props); bool UIKit_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
void UIKit_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window); bool UIKit_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window);
bool UIKit_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window); bool UIKit_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
bool UIKit_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window); bool UIKit_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window);
#endif #endif

View file

@ -80,7 +80,6 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
#ifdef SDL_IPHONE_KEYBOARD #ifdef SDL_IPHONE_KEYBOARD
SDLUITextField *textField; SDLUITextField *textField;
BOOL showingKeyboard;
BOOL hidingKeyboard; BOOL hidingKeyboard;
BOOL rotatingOrientation; BOOL rotatingOrientation;
NSString *committedText; NSString *committedText;
@ -97,7 +96,6 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
#ifdef SDL_IPHONE_KEYBOARD #ifdef SDL_IPHONE_KEYBOARD
[self initKeyboard]; [self initKeyboard];
showingKeyboard = NO;
hidingKeyboard = NO; hidingKeyboard = NO;
rotatingOrientation = NO; rotatingOrientation = NO;
#endif #endif
@ -264,7 +262,7 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
@synthesize textInputRect; @synthesize textInputRect;
@synthesize keyboardHeight; @synthesize keyboardHeight;
@synthesize keyboardVisible; @synthesize textFieldFocused;
// Set ourselves up as a UITextFieldDelegate // Set ourselves up as a UITextFieldDelegate
- (void)initKeyboard - (void)initKeyboard
@ -277,7 +275,7 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
committedText = textField.text; committedText = textField.text;
textField.hidden = YES; textField.hidden = YES;
keyboardVisible = NO; textFieldFocused = NO;
NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
#ifndef SDL_PLATFORM_TVOS #ifndef SDL_PLATFORM_TVOS
@ -285,10 +283,6 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
selector:@selector(keyboardWillShow:) selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification name:UIKeyboardWillShowNotification
object:nil]; object:nil];
[center addObserver:self
selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[center addObserver:self [center addObserver:self
selector:@selector(keyboardWillHide:) selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification name:UIKeyboardWillHideNotification
@ -343,8 +337,10 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
[view addSubview:textField]; [view addSubview:textField];
if (keyboardVisible) { if (textFieldFocused) {
[self showKeyboard]; /* startTextInput has been called before the text field was added to the view,
* call it again for the text field to actually become first responder. */
[self startTextInput];
} }
} }
@ -367,9 +363,6 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
[center removeObserver:self [center removeObserver:self
name:UIKeyboardWillShowNotification name:UIKeyboardWillShowNotification
object:nil]; object:nil];
[center removeObserver:self
name:UIKeyboardDidShowNotification
object:nil];
[center removeObserver:self [center removeObserver:self
name:UIKeyboardWillHideNotification name:UIKeyboardWillHideNotification
object:nil]; object:nil];
@ -382,7 +375,7 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
object:nil]; object:nil];
} }
- (void)setKeyboardProperties:(SDL_PropertiesID) props - (void)setTextFieldProperties:(SDL_PropertiesID) props
{ {
textField.secureTextEntry = NO; textField.secureTextEntry = NO;
@ -479,43 +472,36 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
} }
} }
// reveal onscreen virtual keyboard /* requests the SDL text field to become focused and accept text input.
- (void)showKeyboard * also shows the onscreen virtual keyboard if no hardware keyboard is attached. */
- (bool)startTextInput
{ {
if (keyboardVisible) { textFieldFocused = YES;
return; if (!textField.window) {
/* textField has not been added to the view yet,
* we will try again when that happens. */
return true;
} }
keyboardVisible = YES; return [textField becomeFirstResponder];
if (textField.window) {
showingKeyboard = YES;
[textField becomeFirstResponder];
}
} }
// hide onscreen virtual keyboard /* requests the SDL text field to lose focus and stop accepting text input.
- (void)hideKeyboard * also hides the onscreen virtual keyboard if no hardware keyboard is attached. */
- (bool)stopTextInput
{ {
if (!keyboardVisible) { textFieldFocused = NO;
return; if (!textField.window) {
/* textField has not been added to the view yet,
* we will try again when that happens. */
return true;
} }
keyboardVisible = NO; return [textField resignFirstResponder];
if (textField.window) {
hidingKeyboard = YES;
[textField resignFirstResponder];
}
} }
- (void)keyboardWillShow:(NSNotification *)notification - (void)keyboardWillShow:(NSNotification *)notification
{ {
BOOL shouldStartTextInput = NO;
if (!SDL_TextInputActive(window) && !hidingKeyboard && !rotatingOrientation) {
shouldStartTextInput = YES;
}
showingKeyboard = YES;
#ifndef SDL_PLATFORM_TVOS #ifndef SDL_PLATFORM_TVOS
CGRect kbrect = [[notification userInfo][UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGRect kbrect = [[notification userInfo][UIKeyboardFrameEndUserInfoKey] CGRectValue];
@ -526,28 +512,29 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
[self setKeyboardHeight:(int)kbrect.size.height]; [self setKeyboardHeight:(int)kbrect.size.height];
#endif #endif
if (shouldStartTextInput) { /* A keyboard hide transition has been interrupted with a show (keyboardWillHide has been called but keyboardDidHide didn't).
* since text input was stopped by the hide, we have to start it again. */
if (hidingKeyboard) {
SDL_StartTextInput(window); SDL_StartTextInput(window);
hidingKeyboard = NO;
} }
} }
- (void)keyboardDidShow:(NSNotification *)notification
{
showingKeyboard = NO;
}
- (void)keyboardWillHide:(NSNotification *)notification - (void)keyboardWillHide:(NSNotification *)notification
{ {
BOOL shouldStopTextInput = NO;
if (SDL_TextInputActive(window) && !showingKeyboard && !rotatingOrientation) {
shouldStopTextInput = YES;
}
hidingKeyboard = YES; hidingKeyboard = YES;
[self setKeyboardHeight:0]; [self setKeyboardHeight:0];
if (shouldStopTextInput) { /* When the user dismisses the software keyboard by the "hide" button in the bottom right corner,
* we want to reflect that on SDL_TextInputActive by calling SDL_StopTextInput...on certain conditions */
if (SDL_TextInputActive(window)
/* keyboardWillHide gets called when a hardware keyboard is attached,
* keep text input state active if hiding while there is a hardware keyboard.
* if the hardware keyboard gets detached, the software keyboard will appear anyway. */
&& !SDL_HasKeyboard()
/* When the device changes orientation, a sequence of hide and show transitions are triggered.
* keep text input state active in this case. */
&& !rotatingOrientation) {
SDL_StopTextInput(window); SDL_StopTextInput(window);
} }
} }
@ -630,7 +617,6 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
- (void)setKeyboardHeight:(int)height - (void)setKeyboardHeight:(int)height
{ {
keyboardVisible = height > 0;
keyboardHeight = height; keyboardHeight = height;
[self updateKeyboard]; [self updateKeyboard];
} }
@ -651,7 +637,7 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
- (BOOL)textFieldShouldReturn:(UITextField *)_textField - (BOOL)textFieldShouldReturn:(UITextField *)_textField
{ {
SDL_SendKeyboardKeyAutoRelease(0, SDL_SCANCODE_RETURN); SDL_SendKeyboardKeyAutoRelease(0, SDL_SCANCODE_RETURN);
if (keyboardVisible && if (textFieldFocused &&
SDL_GetHintBoolean(SDL_HINT_RETURN_KEY_HIDES_IME, false)) { SDL_GetHintBoolean(SDL_HINT_RETURN_KEY_HIDES_IME, false)) {
SDL_StopTextInput(window); SDL_StopTextInput(window);
} }
@ -682,20 +668,20 @@ bool UIKit_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
return true; return true;
} }
void UIKit_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props) bool UIKit_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{ {
@autoreleasepool { @autoreleasepool {
SDL_uikitviewcontroller *vc = GetWindowViewController(window); SDL_uikitviewcontroller *vc = GetWindowViewController(window);
[vc setKeyboardProperties:props]; [vc setTextFieldProperties:props];
[vc showKeyboard]; return [vc startTextInput];
} }
} }
void UIKit_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window) bool UIKit_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window)
{ {
@autoreleasepool { @autoreleasepool {
SDL_uikitviewcontroller *vc = GetWindowViewController(window); SDL_uikitviewcontroller *vc = GetWindowViewController(window);
[vc hideKeyboard]; return [vc stopTextInput];
} }
} }
@ -704,7 +690,7 @@ bool UIKit_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window)
@autoreleasepool { @autoreleasepool {
SDL_uikitviewcontroller *vc = GetWindowViewController(window); SDL_uikitviewcontroller *vc = GetWindowViewController(window);
if (vc != nil) { if (vc != nil) {
return vc.keyboardVisible; return vc.textFieldFocused;
} }
return false; return false;
} }
@ -717,7 +703,7 @@ bool UIKit_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window)
if (vc != nil) { if (vc != nil) {
vc.textInputRect = window->text_input_rect; vc.textInputRect = window->text_input_rect;
if (vc.keyboardVisible) { if (vc.textFieldFocused) {
[vc updateKeyboard]; [vc updateKeyboard];
} }
} }