From 1b158940ac8107981f90f43c4543effa7b691c8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 26 Sep 2024 10:58:58 +0200 Subject: [PATCH] PPSSPP UI: Implement password masking in popup text inputs --- Common/UI/PopupScreens.cpp | 6 ++++-- Common/UI/PopupScreens.h | 5 +++++ Common/UI/View.cpp | 11 +++++++++-- Common/UI/View.h | 8 ++++++-- UI/ChatScreen.cpp | 2 +- UI/NativeApp.cpp | 2 +- UI/RetroAchievementScreens.cpp | 2 +- android/jni/app-android.cpp | 1 - 8 files changed, 27 insertions(+), 10 deletions(-) diff --git a/Common/UI/PopupScreens.cpp b/Common/UI/PopupScreens.cpp index acc9c90372..02c2fd1856 100644 --- a/Common/UI/PopupScreens.cpp +++ b/Common/UI/PopupScreens.cpp @@ -528,7 +528,7 @@ EventReturn PopupTextInputChoice::HandleClick(EventParams &e) { // Choose method depending on platform capabilities. if (System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_DIALOG)) { - System_InputBoxGetString(token_, text_, *value_, passwordDisplay_, [=](const std::string &enteredValue, int) { + System_InputBoxGetString(token_, text_, *value_, passwordMasking_, [=](const std::string &enteredValue, int) { *value_ = StripSpaces(enteredValue); EventParams params{}; OnChange.Trigger(params); @@ -537,6 +537,7 @@ EventReturn PopupTextInputChoice::HandleClick(EventParams &e) { } TextEditPopupScreen *popupScreen = new TextEditPopupScreen(value_, placeHolder_, ChopTitle(text_), maxLen_); + popupScreen->SetPasswordMasking(passwordMasking_); if (System_GetPropertyBool(SYSPROP_KEYBOARD_IS_SOFT)) { popupScreen->SetAlignTop(true); } @@ -570,6 +571,7 @@ void TextEditPopupScreen::CreatePopupContents(UI::ViewGroup *parent) { edit_ = new TextEdit(textEditValue_, Title(), placeholder_, new LinearLayoutParams(1.0f)); edit_->SetMaxLen(maxLen_); edit_->SetTextColor(dc.theme->popupStyle.fgColor); + edit_->SetPasswordMasking(passwordMasking_); lin->Add(edit_); UI::SetFocusedView(edit_); @@ -628,7 +630,7 @@ void AbstractChoiceWithValueDisplay::Draw(UIContext &dc) { std::string valueText = ValueText(); - if (passwordDisplay_) { + if (passwordMasking_) { // Replace all characters with stars. memset(&valueText[0], '*', valueText.size()); } diff --git a/Common/UI/PopupScreens.h b/Common/UI/PopupScreens.h index 1eab264abf..73d130eda8 100644 --- a/Common/UI/PopupScreens.h +++ b/Common/UI/PopupScreens.h @@ -150,6 +150,10 @@ public: const char *tag() const override { return "TextEditPopup"; } + void SetPasswordMasking(bool masking) { + passwordMasking_ = masking; + } + Event OnChange; private: @@ -159,6 +163,7 @@ private: std::string textEditValue_; std::string placeholder_; int maxLen_; + bool passwordMasking_ = false; }; struct ContextMenuItem { diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 8075c4cdae..7a65c477ee 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -1142,18 +1142,25 @@ void TextEdit::Draw(UIContext &dc) { Bounds textBounds = bounds_; textBounds.x = textX - scrollPos_; + std::string textToDisplay = text_; + if (passwordMasking_) { + for (int i = 0; i < textToDisplay.size(); i++) { + textToDisplay[i] = '*'; + } + } + if (text_.empty()) { if (placeholderText_.size()) { uint32_t c = textColor & 0x50FFFFFF; dc.DrawTextRect(placeholderText_, bounds_, c, ALIGN_CENTER); } } else { - dc.DrawTextRect(text_, textBounds, textColor, ALIGN_VCENTER | ALIGN_LEFT | align_); + dc.DrawTextRect(textToDisplay, textBounds, textColor, ALIGN_VCENTER | ALIGN_LEFT | align_); } if (HasFocus()) { // Hack to find the caret position. Might want to find a better way... - dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.substr(0, caret_), &w, &h, ALIGN_VCENTER | ALIGN_LEFT | align_); + dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, textToDisplay.substr(0, caret_), &w, &h, ALIGN_VCENTER | ALIGN_LEFT | align_); float caretX = w - scrollPos_; if (caretX > bounds_.w) { scrollPos_ += caretX - bounds_.w; diff --git a/Common/UI/View.h b/Common/UI/View.h index e38c0fc819..814735d57f 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -825,14 +825,14 @@ public: void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override; void SetPasswordDisplay() { - passwordDisplay_ = true; + passwordMasking_ = true; } protected: virtual std::string ValueText() const = 0; float CalculateValueScale(const UIContext &dc, std::string_view valueText, float availWidth) const; - bool passwordDisplay_ = false; + bool passwordMasking_ = false; }; class ChoiceWithCallbackValueDisplay : public AbstractChoiceWithValueDisplay { @@ -1026,6 +1026,9 @@ public: const std::string &GetText() const { return text_; } void SetMaxLen(size_t maxLen) { maxLen_ = maxLen; } void SetTextAlign(int align) { align_ = align; } // Only really useful for setting FLAG_DYNAMIC_ASCII + void SetPasswordMasking(bool masking) { + passwordMasking_ = masking; + } void FocusChanged(int focusFlags) override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; @@ -1050,6 +1053,7 @@ private: int scrollPos_ = 0; size_t maxLen_; bool ctrlDown_ = false; // TODO: Make some global mechanism for this. + bool passwordMasking_ = false; int align_ = 0; // TODO: Selections }; diff --git a/UI/ChatScreen.cpp b/UI/ChatScreen.cpp index 7c0a107719..3445767c77 100644 --- a/UI/ChatScreen.cpp +++ b/UI/ChatScreen.cpp @@ -97,7 +97,7 @@ UI::EventReturn ChatMenu::OnSubmit(UI::EventParams &e) { sendChat(chat); #elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) || PPSSPP_PLATFORM(IOS) auto n = GetI18NCategory(I18NCat::NETWORKING); - System_InputBoxGetString(token_, n->T("Chat"), "", [](const std::string &value, int) { + System_InputBoxGetString(token_, n->T("Chat"), "", false, [](const std::string &value, int) { sendChat(value); }); #endif diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 96a53ea7ac..272ff35e16 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1546,7 +1546,7 @@ bool NativeSaveSecret(std::string_view nameOfSecret, std::string_view data) { if (data.empty() && File::Exists(path)) { return File::Delete(path); } else if (!File::WriteDataToFile(false, data.data(), data.size(), path)) { - WARN_LOG(Log::System, "Failed to write secret '%s' to path '%s'", nameOfSecret, path.c_str()); + WARN_LOG(Log::System, "Failed to write secret '%.*s' to path '%s'", (int)nameOfSecret.size(), nameOfSecret.data(), path.c_str()); return false; } return true; diff --git a/UI/RetroAchievementScreens.cpp b/UI/RetroAchievementScreens.cpp index 810d6757e0..d7022ef567 100644 --- a/UI/RetroAchievementScreens.cpp +++ b/UI/RetroAchievementScreens.cpp @@ -296,7 +296,7 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup) Achievements::Logout(); return UI::EVENT_DONE; }); - } else if (false && System_GetPropertyBool(SYSPROP_HAS_LOGIN_DIALOG)) { + } else if (System_GetPropertyBool(SYSPROP_HAS_LOGIN_DIALOG)) { viewGroup->Add(new Choice(di->T("Log in")))->OnClick.Add([=](UI::EventParams &) -> UI::EventReturn { std::string title = StringFromFormat("RetroAchievements: %s", di->T_cstr("Log in")); System_AskUsernamePassword(GetRequesterToken(), title, [](const std::string &value, int) { diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 1f5ca52f92..1011e599c5 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -1120,7 +1120,6 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string PushCommand("copy_to_clipboard", param1); return true; case SystemRequestType::INPUT_TEXT_MODAL: - case SystemRequestType::INPUT_PASSWORD_MODAL: { std::string serialized = StringFromFormat("%d:@:%s:@:%s", requestId, param1.c_str(), param2.c_str()); PushCommand("inputbox", serialized.c_str());