From 32df69ea809e88863dfeb68bc6389f15d0e3fb5e Mon Sep 17 00:00:00 2001 From: jpirnay Date: Sun, 12 Apr 2026 23:16:47 +0200 Subject: [PATCH] Add show/hide feature for passwords --- src/activities/util/KeyboardEntryActivity.cpp | 87 ++++++++++++++----- src/activities/util/KeyboardEntryActivity.h | 5 +- 2 files changed, 71 insertions(+), 21 deletions(-) diff --git a/src/activities/util/KeyboardEntryActivity.cpp b/src/activities/util/KeyboardEntryActivity.cpp index 44b46232..724a55cd 100644 --- a/src/activities/util/KeyboardEntryActivity.cpp +++ b/src/activities/util/KeyboardEntryActivity.cpp @@ -2,6 +2,8 @@ #include +#include + #include "MappedInputManager.h" #include "components/UITheme.h" #include "fontIds.h" @@ -19,6 +21,8 @@ int KeyboardEntryActivity::getContentRowCount() const { return ABC_ROWS; } int KeyboardEntryActivity::getTotalRowCount() const { return getContentRowCount() + 1; } +int KeyboardEntryActivity::getBottomKeyCount() const { return isPassword ? 6 : 5; } + bool KeyboardEntryActivity::isBottomRow(const int row) const { return row == getContentRowCount(); } char KeyboardEntryActivity::getSelectedChar() const { @@ -54,9 +58,43 @@ bool KeyboardEntryActivity::insertChar(char c) { return true; } +SpecialKeyType KeyboardEntryActivity::getBottomSpecialKey(int index) const { + if (isPassword) { + switch (index) { + case 0: + return SpecShift; + case 1: + return SpecMode; + case 2: + return SpecReveal; + case 3: + return SpecSpace; + case 4: + return SpecDel; + case 5: + default: + return SpecOk; + } + } + + switch (index) { + case 0: + return SpecShift; + case 1: + return SpecMode; + case 2: + return SpecSpace; + case 3: + return SpecDel; + case 4: + default: + return SpecOk; + } +} + bool KeyboardEntryActivity::handleKeyPress() { if (isBottomRow(selectedRow)) { - switch (static_cast(selectedCol)) { + switch (getBottomSpecialKey(selectedCol)) { case SpecShift: if (symMode) return true; shiftState = (shiftState + 1) % 2; @@ -66,12 +104,16 @@ bool KeyboardEntryActivity::handleKeyPress() { int maxRow = getTotalRowCount() - 1; if (selectedRow > maxRow) selectedRow = maxRow; if (isBottomRow(selectedRow)) { - if (selectedCol >= BOTTOM_KEY_COUNT) selectedCol = BOTTOM_KEY_COUNT - 1; + int bottomCount = getBottomKeyCount(); + if (selectedCol >= bottomCount) selectedCol = bottomCount - 1; } else { if (selectedCol >= COLS) selectedCol = COLS - 1; } return true; } + case SpecReveal: + passwordVisible = !passwordVisible; + return true; case SpecSpace: return insertChar(' '); case SpecDel: @@ -97,11 +139,11 @@ void KeyboardEntryActivity::loop() { bool wasBottom = isBottomRow(selectedRow); selectedRow = ButtonNavigator::previousIndex(selectedRow, totalRows); if (wasBottom && !isBottomRow(selectedRow)) { - selectedCol = selectedCol * 2; + selectedCol = selectedCol * COLS / getBottomKeyCount(); } else if (!wasBottom && isBottomRow(selectedRow)) { - selectedCol = selectedCol / 2; + selectedCol = selectedCol * getBottomKeyCount() / COLS; } - int maxCol = isBottomRow(selectedRow) ? BOTTOM_KEY_COUNT - 1 : COLS - 1; + int maxCol = isBottomRow(selectedRow) ? getBottomKeyCount() - 1 : COLS - 1; if (selectedCol > maxCol) selectedCol = maxCol; requestUpdate(); }); @@ -110,23 +152,23 @@ void KeyboardEntryActivity::loop() { bool wasBottom = isBottomRow(selectedRow); selectedRow = ButtonNavigator::nextIndex(selectedRow, totalRows); if (wasBottom && !isBottomRow(selectedRow)) { - selectedCol = selectedCol * 2; + selectedCol = selectedCol * COLS / getBottomKeyCount(); } else if (!wasBottom && isBottomRow(selectedRow)) { - selectedCol = selectedCol / 2; + selectedCol = selectedCol * getBottomKeyCount() / COLS; } - int maxCol = isBottomRow(selectedRow) ? BOTTOM_KEY_COUNT - 1 : COLS - 1; + int maxCol = isBottomRow(selectedRow) ? getBottomKeyCount() - 1 : COLS - 1; if (selectedCol > maxCol) selectedCol = maxCol; requestUpdate(); }); buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Left}, [this] { - int maxCol = isBottomRow(selectedRow) ? BOTTOM_KEY_COUNT - 1 : COLS - 1; + int maxCol = isBottomRow(selectedRow) ? getBottomKeyCount() - 1 : COLS - 1; selectedCol = ButtonNavigator::previousIndex(selectedCol, maxCol + 1); requestUpdate(); }); buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Right}, [this] { - int maxCol = isBottomRow(selectedRow) ? BOTTOM_KEY_COUNT - 1 : COLS - 1; + int maxCol = isBottomRow(selectedRow) ? getBottomKeyCount() - 1 : COLS - 1; selectedCol = ButtonNavigator::nextIndex(selectedCol, maxCol + 1); requestUpdate(); }); @@ -178,7 +220,7 @@ void KeyboardEntryActivity::render(RenderLock&&) { int inputHeight = 0; std::string displayText; - if (isPassword) { + if (isPassword && !passwordVisible) { displayText = std::string(text.length(), '*'); } else { displayText = text; @@ -255,22 +297,27 @@ void KeyboardEntryActivity::render(RenderLock&&) { const int bottomRowY = keyboardStartY + contentRows * (keyHeight + keySpacing) + bottomRowGap; const int bkSpacing = metrics.keyboardBottomKeySpacing; const int contentTotalWidth = COLS * keyWidth + (COLS - 1) * keySpacing; - const int bottomKeyWidth = (contentTotalWidth - (BOTTOM_KEY_COUNT - 1) * bkSpacing) / BOTTOM_KEY_COUNT; + const int bottomKeyCount = getBottomKeyCount(); + const int bottomKeyWidth = (contentTotalWidth - (bottomKeyCount - 1) * bkSpacing) / bottomKeyCount; const bool bottomSelected = isBottomRow(selectedRow); struct BottomKeyInfo { KeyboardKeyType themeType; const char* label; }; - const BottomKeyInfo bottomKeys[BOTTOM_KEY_COUNT] = { - {KeyboardKeyType::Shift, symMode ? shiftString[0] : shiftString[shiftState]}, - {KeyboardKeyType::Mode, symMode ? "abc" : "#@!"}, - {KeyboardKeyType::Space, nullptr}, - {KeyboardKeyType::Del, nullptr}, - {KeyboardKeyType::Ok, tr(STR_OK_BUTTON)}, - }; - for (int i = 0; i < BOTTOM_KEY_COUNT; i++) { + std::vector bottomKeys; + bottomKeys.reserve(6); + bottomKeys.push_back({KeyboardKeyType::Shift, symMode ? shiftString[0] : shiftString[shiftState]}); + bottomKeys.push_back({KeyboardKeyType::Mode, symMode ? "abc" : "#@!"}); + if (isPassword) { + bottomKeys.push_back({KeyboardKeyType::Normal, passwordVisible ? tr(STR_HIDE) : tr(STR_SHOW)}); + } + bottomKeys.push_back({KeyboardKeyType::Space, nullptr}); + bottomKeys.push_back({KeyboardKeyType::Del, nullptr}); + bottomKeys.push_back({KeyboardKeyType::Ok, tr(STR_OK_BUTTON)}); + + for (int i = 0; i < bottomKeyCount; i++) { const int keyX = leftMargin + i * (bottomKeyWidth + bkSpacing); const bool isSelected = bottomSelected && i == selectedCol; diff --git a/src/activities/util/KeyboardEntryActivity.h b/src/activities/util/KeyboardEntryActivity.h index 19da1950..89409f11 100644 --- a/src/activities/util/KeyboardEntryActivity.h +++ b/src/activities/util/KeyboardEntryActivity.h @@ -14,7 +14,7 @@ struct KeyDef { char secondary; }; -enum SpecialKeyType { SpecShift, SpecMode, SpecSpace, SpecDel, SpecOk }; +enum SpecialKeyType { SpecShift, SpecMode, SpecReveal, SpecSpace, SpecDel, SpecOk }; class KeyboardEntryActivity : public Activity { public: @@ -37,6 +37,7 @@ class KeyboardEntryActivity : public Activity { std::string text; size_t maxLength; bool isPassword; + bool passwordVisible = false; ButtonNavigator buttonNavigator; @@ -147,6 +148,8 @@ class KeyboardEntryActivity : public Activity { int getContentRowCount() const; int getTotalRowCount() const; + int getBottomKeyCount() const; + SpecialKeyType getBottomSpecialKey(int index) const; bool isBottomRow(int row) const; char getSelectedChar() const; char getAlternativeChar() const;