PPSSPP UI: Implement password masking in popup text inputs

This commit is contained in:
Henrik Rydgård 2024-09-26 10:58:58 +02:00
parent f020d1d815
commit 1b158940ac
8 changed files with 27 additions and 10 deletions

View file

@ -528,7 +528,7 @@ EventReturn PopupTextInputChoice::HandleClick(EventParams &e) {
// Choose method depending on platform capabilities. // Choose method depending on platform capabilities.
if (System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_DIALOG)) { 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); *value_ = StripSpaces(enteredValue);
EventParams params{}; EventParams params{};
OnChange.Trigger(params); OnChange.Trigger(params);
@ -537,6 +537,7 @@ EventReturn PopupTextInputChoice::HandleClick(EventParams &e) {
} }
TextEditPopupScreen *popupScreen = new TextEditPopupScreen(value_, placeHolder_, ChopTitle(text_), maxLen_); TextEditPopupScreen *popupScreen = new TextEditPopupScreen(value_, placeHolder_, ChopTitle(text_), maxLen_);
popupScreen->SetPasswordMasking(passwordMasking_);
if (System_GetPropertyBool(SYSPROP_KEYBOARD_IS_SOFT)) { if (System_GetPropertyBool(SYSPROP_KEYBOARD_IS_SOFT)) {
popupScreen->SetAlignTop(true); popupScreen->SetAlignTop(true);
} }
@ -570,6 +571,7 @@ void TextEditPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
edit_ = new TextEdit(textEditValue_, Title(), placeholder_, new LinearLayoutParams(1.0f)); edit_ = new TextEdit(textEditValue_, Title(), placeholder_, new LinearLayoutParams(1.0f));
edit_->SetMaxLen(maxLen_); edit_->SetMaxLen(maxLen_);
edit_->SetTextColor(dc.theme->popupStyle.fgColor); edit_->SetTextColor(dc.theme->popupStyle.fgColor);
edit_->SetPasswordMasking(passwordMasking_);
lin->Add(edit_); lin->Add(edit_);
UI::SetFocusedView(edit_); UI::SetFocusedView(edit_);
@ -628,7 +630,7 @@ void AbstractChoiceWithValueDisplay::Draw(UIContext &dc) {
std::string valueText = ValueText(); std::string valueText = ValueText();
if (passwordDisplay_) { if (passwordMasking_) {
// Replace all characters with stars. // Replace all characters with stars.
memset(&valueText[0], '*', valueText.size()); memset(&valueText[0], '*', valueText.size());
} }

View file

@ -150,6 +150,10 @@ public:
const char *tag() const override { return "TextEditPopup"; } const char *tag() const override { return "TextEditPopup"; }
void SetPasswordMasking(bool masking) {
passwordMasking_ = masking;
}
Event OnChange; Event OnChange;
private: private:
@ -159,6 +163,7 @@ private:
std::string textEditValue_; std::string textEditValue_;
std::string placeholder_; std::string placeholder_;
int maxLen_; int maxLen_;
bool passwordMasking_ = false;
}; };
struct ContextMenuItem { struct ContextMenuItem {

View file

@ -1142,18 +1142,25 @@ void TextEdit::Draw(UIContext &dc) {
Bounds textBounds = bounds_; Bounds textBounds = bounds_;
textBounds.x = textX - scrollPos_; textBounds.x = textX - scrollPos_;
std::string textToDisplay = text_;
if (passwordMasking_) {
for (int i = 0; i < textToDisplay.size(); i++) {
textToDisplay[i] = '*';
}
}
if (text_.empty()) { if (text_.empty()) {
if (placeholderText_.size()) { if (placeholderText_.size()) {
uint32_t c = textColor & 0x50FFFFFF; uint32_t c = textColor & 0x50FFFFFF;
dc.DrawTextRect(placeholderText_, bounds_, c, ALIGN_CENTER); dc.DrawTextRect(placeholderText_, bounds_, c, ALIGN_CENTER);
} }
} else { } else {
dc.DrawTextRect(text_, textBounds, textColor, ALIGN_VCENTER | ALIGN_LEFT | align_); dc.DrawTextRect(textToDisplay, textBounds, textColor, ALIGN_VCENTER | ALIGN_LEFT | align_);
} }
if (HasFocus()) { if (HasFocus()) {
// Hack to find the caret position. Might want to find a better way... // 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_; float caretX = w - scrollPos_;
if (caretX > bounds_.w) { if (caretX > bounds_.w) {
scrollPos_ += caretX - bounds_.w; scrollPos_ += caretX - bounds_.w;

View file

@ -825,14 +825,14 @@ public:
void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override; void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override;
void SetPasswordDisplay() { void SetPasswordDisplay() {
passwordDisplay_ = true; passwordMasking_ = true;
} }
protected: protected:
virtual std::string ValueText() const = 0; virtual std::string ValueText() const = 0;
float CalculateValueScale(const UIContext &dc, std::string_view valueText, float availWidth) const; float CalculateValueScale(const UIContext &dc, std::string_view valueText, float availWidth) const;
bool passwordDisplay_ = false; bool passwordMasking_ = false;
}; };
class ChoiceWithCallbackValueDisplay : public AbstractChoiceWithValueDisplay { class ChoiceWithCallbackValueDisplay : public AbstractChoiceWithValueDisplay {
@ -1026,6 +1026,9 @@ public:
const std::string &GetText() const { return text_; } const std::string &GetText() const { return text_; }
void SetMaxLen(size_t maxLen) { maxLen_ = maxLen; } void SetMaxLen(size_t maxLen) { maxLen_ = maxLen; }
void SetTextAlign(int align) { align_ = align; } // Only really useful for setting FLAG_DYNAMIC_ASCII 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 FocusChanged(int focusFlags) override;
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override;
@ -1050,6 +1053,7 @@ private:
int scrollPos_ = 0; int scrollPos_ = 0;
size_t maxLen_; size_t maxLen_;
bool ctrlDown_ = false; // TODO: Make some global mechanism for this. bool ctrlDown_ = false; // TODO: Make some global mechanism for this.
bool passwordMasking_ = false;
int align_ = 0; int align_ = 0;
// TODO: Selections // TODO: Selections
}; };

View file

@ -97,7 +97,7 @@ UI::EventReturn ChatMenu::OnSubmit(UI::EventParams &e) {
sendChat(chat); sendChat(chat);
#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) || PPSSPP_PLATFORM(IOS) #elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH) || PPSSPP_PLATFORM(IOS)
auto n = GetI18NCategory(I18NCat::NETWORKING); 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); sendChat(value);
}); });
#endif #endif

View file

@ -1546,7 +1546,7 @@ bool NativeSaveSecret(std::string_view nameOfSecret, std::string_view data) {
if (data.empty() && File::Exists(path)) { if (data.empty() && File::Exists(path)) {
return File::Delete(path); return File::Delete(path);
} else if (!File::WriteDataToFile(false, data.data(), data.size(), 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 false;
} }
return true; return true;

View file

@ -296,7 +296,7 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup)
Achievements::Logout(); Achievements::Logout();
return UI::EVENT_DONE; 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 { 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")); std::string title = StringFromFormat("RetroAchievements: %s", di->T_cstr("Log in"));
System_AskUsernamePassword(GetRequesterToken(), title, [](const std::string &value, int) { System_AskUsernamePassword(GetRequesterToken(), title, [](const std::string &value, int) {

View file

@ -1120,7 +1120,6 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
PushCommand("copy_to_clipboard", param1); PushCommand("copy_to_clipboard", param1);
return true; return true;
case SystemRequestType::INPUT_TEXT_MODAL: case SystemRequestType::INPUT_TEXT_MODAL:
case SystemRequestType::INPUT_PASSWORD_MODAL:
{ {
std::string serialized = StringFromFormat("%d:@:%s:@:%s", requestId, param1.c_str(), param2.c_str()); std::string serialized = StringFromFormat("%d:@:%s:@:%s", requestId, param1.c_str(), param2.c_str());
PushCommand("inputbox", serialized.c_str()); PushCommand("inputbox", serialized.c_str());