Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic soft-keyboard support on iOS #19161

Merged
merged 1 commit into from
May 20, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Common/System/System.h
Original file line number Diff line number Diff line change
@@ -142,6 +142,7 @@ enum SystemProperty {
SYSPROP_HAS_IMAGE_BROWSER,
SYSPROP_HAS_BACK_BUTTON,
SYSPROP_HAS_KEYBOARD,
SYSPROP_KEYBOARD_IS_SOFT,
SYSPROP_HAS_ACCELEROMETER, // Used to enable/disable tilt input settings
SYSPROP_HAS_OPEN_DIRECTORY,
SYSPROP_HAS_LOGIN_DIALOG,
3 changes: 3 additions & 0 deletions Common/UI/PopupScreens.cpp
Original file line number Diff line number Diff line change
@@ -537,6 +537,9 @@ EventReturn PopupTextInputChoice::HandleClick(EventParams &e) {
}

TextEditPopupScreen *popupScreen = new TextEditPopupScreen(value_, placeHolder_, ChopTitle(text_), maxLen_);
if (System_GetPropertyBool(SYSPROP_KEYBOARD_IS_SOFT)) {
popupScreen->SetAlignTop(true);
}
popupScreen->OnChange.Handle(this, &PopupTextInputChoice::HandleChange);
if (e.v)
popupScreen->SetPopupOrigin(e.v);
18 changes: 12 additions & 6 deletions Common/UI/UIScreen.cpp
Original file line number Diff line number Diff line change
@@ -385,10 +385,6 @@ void PopupScreen::SetPopupOrigin(const UI::View *view) {
popupOrigin_ = view->GetBounds().Center();
}

void PopupScreen::SetPopupOffset(float y) {
offsetY_ = y;
}

void PopupScreen::TriggerFinish(DialogResult result) {
if (CanComplete(result)) {
ignoreInput_ = true;
@@ -411,8 +407,18 @@ void PopupScreen::CreateViews() {

float yres = screenManager()->getUIContext()->GetBounds().h;

box_ = new LinearLayout(ORIENT_VERTICAL,
new AnchorLayoutParams(PopupWidth(), FillVertical() ? yres - 30 : WRAP_CONTENT, dc.GetBounds().centerX(), dc.GetBounds().centerY() + offsetY_, NONE, NONE, true));
AnchorLayoutParams *anchorParams;
if (!alignTop_) {
// Standard centering etc.
anchorParams = new AnchorLayoutParams(PopupWidth(), FillVertical() ? yres - 30 : WRAP_CONTENT,
dc.GetBounds().centerX(), dc.GetBounds().centerY() + offsetY_, NONE, NONE, true);
} else {
// Top-aligned, for dialogs where we need to pop a keyboard below.
anchorParams = new AnchorLayoutParams(PopupWidth(), FillVertical() ? yres - 30 : WRAP_CONTENT,
NONE, 0, NONE, NONE, false);
}

box_ = new LinearLayout(ORIENT_VERTICAL, anchorParams);

root_->Add(box_);
box_->SetBG(dc.theme->popupStyle.background);
5 changes: 4 additions & 1 deletion Common/UI/UIScreen.h
Original file line number Diff line number Diff line change
@@ -108,7 +108,9 @@ class PopupScreen : public UIDialogScreen {
void TriggerFinish(DialogResult result) override;

void SetPopupOrigin(const UI::View *view);
void SetPopupOffset(float y);
void SetPopupOffset(float y) { offsetY_ = y; }

void SetAlignTop(bool alignTop) { alignTop_ = alignTop; }

void SetHasDropShadow(bool has) { hasDropShadow_ = has; }

@@ -144,6 +146,7 @@ class PopupScreen : public UIDialogScreen {
bool hasPopupOrigin_ = false;
Point popupOrigin_;
float offsetY_ = 0.0f;
bool alignTop_ = false;

bool hasDropShadow_ = true;
};
11 changes: 1 addition & 10 deletions UI/GameSettingsScreen.cpp
Original file line number Diff line number Diff line change
@@ -970,14 +970,7 @@ void GameSettingsScreen::CreateToolsSettings(UI::ViewGroup *tools) {

tools->Add(new ItemHeader(ms->T("Tools")));

bool showRetroAchievements = true;
#if PPSSPP_PLATFORM(IOS_APP_STORE)
// Hide RetroAchievements login (unless the user has specified a login via the ini file).
// A non-working login won't pass App Store review.
if (g_Config.sAchievementsUserName.empty()) {
showRetroAchievements = false;
}
#endif
const bool showRetroAchievements = true;
if (showRetroAchievements) {
auto retro = tools->Add(new Choice(sy->T("RetroAchievements")));
retro->OnClick.Add([=](UI::EventParams &) -> UI::EventReturn {
@@ -1231,9 +1224,7 @@ void GameSettingsScreen::CreateSystemSettings(UI::ViewGroup *systemSettings) {
systemSettings->Add(new PopupMultiChoice(&g_Config.iLanguage, psps->T("Game language"), defaultLanguages, -1, ARRAY_SIZE(defaultLanguages), I18NCat::PSPSETTINGS, screenManager()));
static const char *models[] = { "PSP-1000", "PSP-2000/3000" };
systemSettings->Add(new PopupMultiChoice(&g_Config.iPSPModel, sy->T("PSP Model"), models, 0, ARRAY_SIZE(models), I18NCat::SYSTEM, screenManager()))->SetEnabled(!PSP_IsInited());
#if !PPSSPP_PLATFORM(IOS_APP_STORE)
systemSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.sNickName, sy->T("Change Nickname"), "", 32, screenManager()));
#endif
systemSettings->Add(new CheckBox(&g_Config.bDayLightSavings, sy->T("Day Light Saving")));
static const char *dateFormat[] = { "YYYYMMDD", "MMDDYYYY", "DDMMYYYY" };
systemSettings->Add(new PopupMultiChoice(&g_Config.iDateFormat, sy->T("Date Format"), dateFormat, 0, ARRAY_SIZE(dateFormat), I18NCat::SYSTEM, screenManager()));
2 changes: 0 additions & 2 deletions UI/RetroAchievementScreens.cpp
Original file line number Diff line number Diff line change
@@ -308,8 +308,6 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup)
return UI::EVENT_DONE;
});
} else {
// TODO: For text input on iOS, look into https://stackoverflow.com/questions/7253477/how-to-display-the-iphone-ipad-keyboard-over-a-full-screen-opengl-es-app

// Hack up a temporary quick login-form-ish-thing
viewGroup->Add(new PopupTextInputChoice(GetRequesterToken(), &username_, di->T("Username"), "", 128, screenManager()));
viewGroup->Add(new PopupTextInputChoice(GetRequesterToken(), &password_, di->T("Password"), "", 128, screenManager()))->SetPasswordDisplay();
4 changes: 3 additions & 1 deletion ios/ViewController.h
Original file line number Diff line number Diff line change
@@ -10,10 +10,12 @@
#import "LocationHelper.h"

@interface ViewController : GLKViewController <iCadeEventDelegate,
LocationHandlerDelegate, CameraFrameDelegate, UIGestureRecognizerDelegate>
LocationHandlerDelegate, CameraFrameDelegate, UIGestureRecognizerDelegate, UIKeyInput>

- (void)shareText:(NSString *)text;
- (void)shutdown;
- (void)hideKeyboard;
- (void)showKeyboard;

@end

56 changes: 55 additions & 1 deletion ios/ViewController.mm
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@
#include "Common/GPU/thin3d_create.h"
#include "Common/GPU/OpenGL/GLRenderManager.h"
#include "Common/GPU/OpenGL/GLFeatures.h"

#include "Common/Data/Encoding/Utf8.h"
#include "Common/System/Display.h"
#include "Common/System/System.h"
#include "Common/System/OSD.h"
@@ -179,6 +179,11 @@ - (void)viewSafeAreaInsetsDidChange {
}
}

- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self hideKeyboard];
}

- (void)viewDidLoad {
[super viewDidLoad];
[[DisplayManager shared] setupDisplayListener];
@@ -763,6 +768,55 @@ -(void) SetGpsDataIOS:(CLLocation *)newLocation {
0 /* bearing */);
}

// The below is inspired by https://stackoverflow.com/questions/7253477/how-to-display-the-iphone-ipad-keyboard-over-a-full-screen-opengl-es-app
// It's a bit limited but good enough.

-(void) deleteBackward {
KeyInput input{};
input.deviceId = DEVICE_ID_KEYBOARD;
input.flags = KEY_DOWN | KEY_UP;
input.keyCode = NKCODE_DEL;
NativeKey(input);
INFO_LOG(SYSTEM, "Backspace");
}

-(BOOL) hasText
{
return YES;
}

-(void) insertText:(NSString *)text
{
std::string str = std::string([text UTF8String]);
INFO_LOG(SYSTEM, "Chars: %s", str.c_str());
UTF8 chars(str);
while (!chars.end()) {
uint32_t codePoint = chars.next();
KeyInput input{};
input.deviceId = DEVICE_ID_KEYBOARD;
input.flags = KEY_CHAR;
input.unicodeChar = codePoint;
NativeKey(input);
}
}

-(BOOL) canBecomeFirstResponder
{
return YES;
}

-(void) showKeyboard {
dispatch_async(dispatch_get_main_queue(), ^{
[self becomeFirstResponder];
});
}

-(void) hideKeyboard {
dispatch_async(dispatch_get_main_queue(), ^{
[self resignFirstResponder];
});
}

@end

void System_LaunchUrl(LaunchUrlType urlType, char const* url)
22 changes: 22 additions & 0 deletions ios/main.mm
Original file line number Diff line number Diff line change
@@ -349,6 +349,11 @@ bool System_GetPropertyBool(SystemProperty prop) {
return false;
case SYSPROP_HAS_ACCELEROMETER:
return true;
case SYSPROP_HAS_KEYBOARD:
return true;
case SYSPROP_KEYBOARD_IS_SOFT:
// If a hardware keyboard is connected, and we add support, we could return false here.
return true;
case SYSPROP_APP_GOLD:
#ifdef GOLD
return true;
@@ -437,6 +442,23 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
[sharedViewController shareText:text];
return true;
}
case SystemRequestType::NOTIFY_UI_EVENT:
{
switch ((UIEventNotification)param3) {
case UIEventNotification::POPUP_CLOSED:
[sharedViewController hideKeyboard];
break;
case UIEventNotification::TEXT_GOTFOCUS:
[sharedViewController showKeyboard];
break;
case UIEventNotification::TEXT_LOSTFOCUS:
[sharedViewController hideKeyboard];
break;
default:
break;
}
return true;
}
/*
// Not 100% sure the threading is right
case SystemRequestType::COPY_TO_CLIPBOARD: