Skip to content

Commit

Permalink
Refactor iOS text input activation to better work with hardware keybo…
Browse files Browse the repository at this point in the history
…ards
  • Loading branch information
frenzibyte committed Nov 4, 2024
1 parent d09d2b9 commit da09e82
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 68 deletions.
4 changes: 2 additions & 2 deletions src/video/uikit/SDL_uikitvideo.m
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ static void UIKit_DeleteDevice(SDL_VideoDevice *device)

#ifdef SDL_IPHONE_KEYBOARD
device->HasScreenKeyboardSupport = UIKit_HasScreenKeyboardSupport;
device->ShowScreenKeyboard = UIKit_ShowScreenKeyboard;
device->HideScreenKeyboard = UIKit_HideScreenKeyboard;
device->StartTextInput = UIKit_StartTextInput;
device->StopTextInput = UIKit_StopTextInput;
device->IsScreenKeyboardShown = UIKit_IsScreenKeyboardShown;
device->UpdateTextInputArea = UIKit_UpdateTextInputArea;
#endif
Expand Down
10 changes: 5 additions & 5 deletions src/video/uikit/SDL_uikitviewcontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@
#endif

#ifdef SDL_IPHONE_KEYBOARD
- (void)showKeyboard;
- (void)hideKeyboard;
- (bool)startTextInput;
- (bool)stopTextInput;
- (void)initKeyboard;
- (void)deinitKeyboard;

Expand All @@ -79,7 +79,7 @@

- (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) int keyboardHeight;
#endif
Expand All @@ -88,8 +88,8 @@

#ifdef SDL_IPHONE_KEYBOARD
bool UIKit_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
void UIKit_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
void UIKit_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
bool UIKit_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
bool UIKit_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window);
bool UIKit_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
bool UIKit_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window);
#endif
108 changes: 47 additions & 61 deletions src/video/uikit/SDL_uikitviewcontroller.m
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ @implementation SDL_uikitviewcontroller

#ifdef SDL_IPHONE_KEYBOARD
SDLUITextField *textField;
BOOL showingKeyboard;
BOOL hidingKeyboard;
BOOL rotatingOrientation;
NSString *committedText;
Expand All @@ -97,7 +96,6 @@ - (instancetype)initWithSDLWindow:(SDL_Window *)_window

#ifdef SDL_IPHONE_KEYBOARD
[self initKeyboard];
showingKeyboard = NO;
hidingKeyboard = NO;
rotatingOrientation = NO;
#endif
Expand Down Expand Up @@ -264,7 +262,7 @@ - (BOOL)prefersPointerLocked

@synthesize textInputRect;
@synthesize keyboardHeight;
@synthesize keyboardVisible;
@synthesize textFieldFocused;

// Set ourselves up as a UITextFieldDelegate
- (void)initKeyboard
Expand All @@ -277,18 +275,14 @@ - (void)initKeyboard
committedText = textField.text;

textField.hidden = YES;
keyboardVisible = NO;
textFieldFocused = NO;

NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
#ifndef SDL_PLATFORM_TVOS
[center addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[center addObserver:self
selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[center addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
Expand Down Expand Up @@ -343,8 +337,10 @@ - (void)setView:(UIView *)view

[view addSubview:textField];

if (keyboardVisible) {
[self showKeyboard];
if (textFieldFocused) {
/* 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];
}
}

Expand All @@ -367,9 +363,6 @@ - (void)deinitKeyboard
[center removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
[center removeObserver:self
name:UIKeyboardDidShowNotification
object:nil];
[center removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
Expand All @@ -382,7 +375,7 @@ - (void)deinitKeyboard
object:nil];
}

- (void)setKeyboardProperties:(SDL_PropertiesID) props
- (void)setTextFieldProperties:(SDL_PropertiesID) props
{
textField.secureTextEntry = NO;

Expand Down Expand Up @@ -479,43 +472,36 @@ - (void)setKeyboardProperties:(SDL_PropertiesID) props
}
}

// reveal onscreen virtual keyboard
- (void)showKeyboard
/* requests the SDL text field to become focused and accept text input.
* also shows the onscreen virtual keyboard if no hardware keyboard is attached. */
- (bool)startTextInput
{
if (keyboardVisible) {
return;
textFieldFocused = YES;
if (!textField.window) {
/* textField has not been added to the view yet,
* we will try again when that happens. */
return true;
}

keyboardVisible = YES;
if (textField.window) {
showingKeyboard = YES;
[textField becomeFirstResponder];
}
return [textField becomeFirstResponder];
}

// hide onscreen virtual keyboard
- (void)hideKeyboard
/* requests the SDL text field to lose focus and stop accepting text input.
* also hides the onscreen virtual keyboard if no hardware keyboard is attached. */
- (bool)stopTextInput
{
if (!keyboardVisible) {
return;
textFieldFocused = NO;
if (!textField.window) {
/* textField has not been added to the view yet,
* we will try again when that happens. */
return true;
}

keyboardVisible = NO;
if (textField.window) {
hidingKeyboard = YES;
[textField resignFirstResponder];
}
return [textField resignFirstResponder];
}

- (void)keyboardWillShow:(NSNotification *)notification
{
BOOL shouldStartTextInput = NO;

if (!SDL_TextInputActive(window) && !hidingKeyboard && !rotatingOrientation) {
shouldStartTextInput = YES;
}

showingKeyboard = YES;
#ifndef SDL_PLATFORM_TVOS
CGRect kbrect = [[notification userInfo][UIKeyboardFrameEndUserInfoKey] CGRectValue];

Expand All @@ -526,28 +512,29 @@ - (void)keyboardWillShow:(NSNotification *)notification
[self setKeyboardHeight:(int)kbrect.size.height];
#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);
hidingKeyboard = NO;
}
}

- (void)keyboardDidShow:(NSNotification *)notification
{
showingKeyboard = NO;
}

- (void)keyboardWillHide:(NSNotification *)notification
{
BOOL shouldStopTextInput = NO;

if (SDL_TextInputActive(window) && !showingKeyboard && !rotatingOrientation) {
shouldStopTextInput = YES;
}

hidingKeyboard = YES;
[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);
}
}
Expand Down Expand Up @@ -630,7 +617,6 @@ - (void)updateKeyboard

- (void)setKeyboardHeight:(int)height
{
keyboardVisible = height > 0;
keyboardHeight = height;
[self updateKeyboard];
}
Expand All @@ -651,7 +637,7 @@ - (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRan
- (BOOL)textFieldShouldReturn:(UITextField *)_textField
{
SDL_SendKeyboardKeyAutoRelease(0, SDL_SCANCODE_RETURN);
if (keyboardVisible &&
if (textFieldFocused &&
SDL_GetHintBoolean(SDL_HINT_RETURN_KEY_HIDES_IME, false)) {
SDL_StopTextInput(window);
}
Expand Down Expand Up @@ -682,20 +668,20 @@ bool UIKit_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
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 {
SDL_uikitviewcontroller *vc = GetWindowViewController(window);
[vc setKeyboardProperties:props];
[vc showKeyboard];
[vc setTextFieldProperties:props];
return [vc startTextInput];
}
}

void UIKit_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
bool UIKit_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window)
{
@autoreleasepool {
SDL_uikitviewcontroller *vc = GetWindowViewController(window);
[vc hideKeyboard];
return [vc stopTextInput];
}
}

Expand All @@ -704,7 +690,7 @@ bool UIKit_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window)
@autoreleasepool {
SDL_uikitviewcontroller *vc = GetWindowViewController(window);
if (vc != nil) {
return vc.keyboardVisible;
return vc.textFieldFocused;
}
return false;
}
Expand All @@ -717,7 +703,7 @@ bool UIKit_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window)
if (vc != nil) {
vc.textInputRect = window->text_input_rect;

if (vc.keyboardVisible) {
if (vc.textFieldFocused) {
[vc updateKeyboard];
}
}
Expand Down

0 comments on commit da09e82

Please sign in to comment.