Merge pull request #19161 from hrydgard/basic-ios-keyboard

Add basic soft-keyboard support on iOS
This commit is contained in:
Henrik Rydgård 2024-05-20 19:36:28 +02:00 committed by GitHub
commit b00b4fb70b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 101 additions and 21 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -108,7 +108,9 @@ public:
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 @@ private:
bool hasPopupOrigin_ = false;
Point popupOrigin_;
float offsetY_ = 0.0f;
bool alignTop_ = false;
bool hasDropShadow_ = true;
};

View File

@ -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()));

View File

@ -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();

View File

@ -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

View File

@ -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 @@ extern float g_safeInsetBottom;
}
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self hideKeyboard];
}
- (void)viewDidLoad {
[super viewDidLoad];
[[DisplayManager shared] setupDisplayListener];
@ -763,6 +768,55 @@ void stopLocation() {
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)

View File

@ -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: