Skip to content

Commit

Permalink
Merge pull request #19161 from hrydgard/basic-ios-keyboard
Browse files Browse the repository at this point in the history
Add basic soft-keyboard support on iOS
  • Loading branch information
hrydgard authored May 20, 2024
2 parents e829ac8 + 835aa02 commit b00b4fb
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 21 deletions.
1 change: 1 addition & 0 deletions Common/System/System.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions Common/UI/PopupScreens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
18 changes: 12 additions & 6 deletions Common/UI/UIScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
5 changes: 4 additions & 1 deletion Common/UI/UIScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down Expand Up @@ -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
Expand Up @@ -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 {
Expand Down Expand Up @@ -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()));
Expand Down
2 changes: 0 additions & 2 deletions UI/RetroAchievementScreens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
4 changes: 3 additions & 1 deletion ios/ViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
56 changes: 55 additions & 1 deletion ios/ViewController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -179,6 +179,11 @@ - (void)viewSafeAreaInsetsDidChange {
}
}

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

- (void)viewDidLoad {
[super viewDidLoad];
[[DisplayManager shared] setupDisplayListener];
Expand Down Expand Up @@ -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)
Expand Down
22 changes: 22 additions & 0 deletions ios/main.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit b00b4fb

Please sign in to comment.