mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-10-09 11:16:39 +00:00
feat: Add password input for screen unlock
This commit is contained in:
@@ -63,3 +63,15 @@ Fully autonomous, independent of Auto-lock and of any key combo:
|
||||
|
||||
- **Magnet near (cover closed)** — locks and blanks the display immediately, no wake grace.
|
||||
- **Magnet away (cover opened)** — unlocks and wakes the display right away.
|
||||
|
||||
---
|
||||
|
||||
### Lock-screen password
|
||||
|
||||
Enable **LockPass** in **Settings › Display** to require a password when unlocking the device.
|
||||
|
||||
Upon enabling the setting the keyboard will show, requiring you to submit a new password.
|
||||
Attempting to unlock the device will then require the same password to be typed and submitted to reach the home screen.
|
||||
Submitting an incorrect password clears the keyboard input.
|
||||
|
||||
Disabling the setting clears the stored password and allows an instant unlock again.
|
||||
|
||||
@@ -2212,6 +2212,73 @@ void UITask::syncLockToHome() {
|
||||
if (home) static_cast<HomeScreen*>(home)->setLocked(_locked);
|
||||
}
|
||||
|
||||
bool UITask::passwordLockEnabled() const {
|
||||
// Is lock_screen_password setting not empty?
|
||||
return _node_prefs && _node_prefs->lock_screen_password[0] != '\0';
|
||||
}
|
||||
|
||||
void UITask::beginUnlockPrompt() {
|
||||
_unlock_kb = true; // Track that keyboard is visible and is waiting for input
|
||||
int max_len = _node_prefs ? (int)sizeof(_node_prefs->lock_screen_password) - 1 : 32;
|
||||
_kb.begin("", max_len);
|
||||
_kb.clearPlaceholders();
|
||||
_lock_wake_until = millis() + 5000; // keep the display on while typing
|
||||
_next_refresh = 0;
|
||||
}
|
||||
|
||||
void UITask::cancelUnlockPrompt() {
|
||||
_unlock_kb = false;
|
||||
_next_refresh = 100;
|
||||
}
|
||||
|
||||
void UITask::handleUnlockKey(char c) {
|
||||
auto res = _kb.handleInput(c);
|
||||
if (res == KeyboardWidget::DONE) { // Process input on submit
|
||||
if (_node_prefs && strcmp(_kb.buf, _node_prefs->lock_screen_password) == 0) {
|
||||
// Match: Unlock
|
||||
_unlock_kb = false;
|
||||
_locked = false;
|
||||
if (_display && !_display->isOn()) _display->turnOn();
|
||||
uint32_t aoff = autoOffMillis();
|
||||
if (aoff > 0) _auto_off = millis() + aoff;
|
||||
syncLockToHome();
|
||||
} else {
|
||||
// Invalid: Clear input and reset keyboard
|
||||
_kb.len = 0;
|
||||
_kb.buf[0] = '\0';
|
||||
_kb.cursor_pos = 0;
|
||||
_kb.page = _kb.row = _kb.col = 0;
|
||||
_kb.caps = _kb.caps_lock = false;
|
||||
_next_refresh = 0;
|
||||
}
|
||||
} else if (res == KeyboardWidget::CANCELLED) {
|
||||
cancelUnlockPrompt();
|
||||
}
|
||||
_lock_wake_until = millis() + 5000; // keep the display on while typing
|
||||
}
|
||||
|
||||
void UITask::toggleLock() {
|
||||
if (_unlock_kb) {
|
||||
cancelUnlockPrompt();
|
||||
return;
|
||||
}
|
||||
if (_locked) {
|
||||
if (passwordLockEnabled()) { // Prompt for password
|
||||
beginUnlockPrompt();
|
||||
} else { // ...or unlock instantly
|
||||
_locked = false;
|
||||
if (_display && !_display->isOn()) _display->turnOn();
|
||||
uint32_t aoff = autoOffMillis();
|
||||
if (aoff > 0) _auto_off = millis() + aoff;
|
||||
}
|
||||
} else { // Device is currently unlocked -> lock it
|
||||
_locked = true;
|
||||
_lock_wake_until = millis() + 2000; // Briefly show lockscreen before blanking
|
||||
}
|
||||
syncLockToHome();
|
||||
_next_refresh = 0;
|
||||
}
|
||||
|
||||
bool UITask::savePrefsIfDirty(bool& dirty) {
|
||||
if (!dirty) return false;
|
||||
the_mesh.savePrefs();
|
||||
@@ -2561,15 +2628,7 @@ void UITask::pollCardKB() {
|
||||
// two-key combo, so it doesn't need the physical combo's extra 3x
|
||||
// repetition to guard against accidental triggering.
|
||||
if (_display && !_display->isOn()) _display->turnOn();
|
||||
_locked = !_locked;
|
||||
if (_locked) {
|
||||
_lock_wake_until = millis() + 2000;
|
||||
} else {
|
||||
uint32_t aoff = autoOffMillis();
|
||||
if (aoff > 0) _auto_off = millis() + aoff;
|
||||
}
|
||||
syncLockToHome();
|
||||
_next_refresh = 0;
|
||||
toggleLock();
|
||||
return;
|
||||
} else if (raw >= 0x80 && raw <= 0xAF) { // Fn+<letter> -- open its accent popup
|
||||
char base = CARDKB_FN_BASE[raw - 0x80];
|
||||
@@ -2623,6 +2682,7 @@ void UITask::pollHallSensor() {
|
||||
_hall_magnet_present = present;
|
||||
|
||||
if (present) { // cover closed
|
||||
cancelUnlockPrompt(); // a cover can't be over the password prompt
|
||||
_locked = true;
|
||||
syncLockToHome();
|
||||
_lock_wake_until = 0;
|
||||
@@ -2663,15 +2723,7 @@ void UITask::loop() {
|
||||
if (_lock_seq_count >= 3) {
|
||||
_lock_seq_count = 0;
|
||||
_lock_seq_used = true; // suppress Back release click
|
||||
_locked = !_locked;
|
||||
if (_locked) {
|
||||
_lock_wake_until = millis() + 2000;
|
||||
} else {
|
||||
if (_display && !_display->isOn()) _display->turnOn();
|
||||
uint32_t aoff = autoOffMillis();
|
||||
if (aoff > 0) _auto_off = millis() + aoff;
|
||||
}
|
||||
syncLockToHome();
|
||||
toggleLock();
|
||||
}
|
||||
// eat the Enter — don't pass to curr
|
||||
} else {
|
||||
@@ -2864,7 +2916,12 @@ void UITask::loop() {
|
||||
}
|
||||
|
||||
if (_kq_head != _kq_tail) {
|
||||
if (!_locked && curr) {
|
||||
if (_unlock_kb) {
|
||||
// Lock-screen password keyboard: Consume every key press
|
||||
char k;
|
||||
while (dequeueKey(k)) handleUnlockKey(k);
|
||||
_next_refresh = 100; // redraw immediately after key press
|
||||
} else if (!_locked && curr) {
|
||||
// Apply the whole queued burst, then redraw once — N taps captured during
|
||||
// a blocking refresh become N navigation steps at the cost of one refresh.
|
||||
char k;
|
||||
@@ -2901,8 +2958,22 @@ void UITask::loop() {
|
||||
tickClockTools();
|
||||
|
||||
if (_display != NULL && _display->isOn()) {
|
||||
if (_locked && (int32_t)(millis() - _lock_wake_until) >= 0) {
|
||||
// Lock-screen password prompt
|
||||
if (_locked && _unlock_kb && (int32_t)(millis() - _lock_wake_until) >= 0) {
|
||||
cancelUnlockPrompt(); // Cancel unlock attempt on idle
|
||||
_next_refresh = 0;
|
||||
}
|
||||
if (_locked && !_unlock_kb && (int32_t)(millis() - _lock_wake_until) >= 0) {
|
||||
_display->turnOff();
|
||||
} else if (_locked && _unlock_kb && millis() >= _next_refresh) {
|
||||
// While the prompt is up the password keyboard replaces the lockscreen view
|
||||
_display->startFrame();
|
||||
_kb.beginFrame();
|
||||
int delay_millis = _kb.render(*_display);
|
||||
// Alert overlay on top // TODO: Is this necessary here?
|
||||
// if (millis() < _alert_expiry) renderAlertOverlay();
|
||||
_display->endFrame();
|
||||
_next_refresh = millis() + delay_millis;
|
||||
} else if (_locked && millis() >= _next_refresh && home) {
|
||||
_display->startFrame();
|
||||
home->render(*_display);
|
||||
@@ -2950,6 +3021,7 @@ void UITask::loop() {
|
||||
digitalWrite(PIN_LED, LOW); // turn off status LED with display to save power
|
||||
#endif
|
||||
if (_node_prefs && _node_prefs->auto_lock) {
|
||||
cancelUnlockPrompt(); // idle-lock isn't a password prompt
|
||||
_locked = true;
|
||||
_lock_wake_until = 0;
|
||||
syncLockToHome();
|
||||
|
||||
@@ -58,6 +58,8 @@ class UITask : public AbstractUITask {
|
||||
int _lock_seq_count; // Enter presses while Back held (lock/unlock sequence)
|
||||
unsigned long _lock_seq_ms; // millis() of last lock-sequence press (for timeout)
|
||||
bool _lock_seq_used; // true = suppress next back_btn CLICK (post-sequence release)
|
||||
// True while the lock screen shows the on-screen keyboard and waits for submission
|
||||
bool _unlock_kb = false;
|
||||
char _alert[80];
|
||||
char _notif_mel_buf[220]; // persistent RTTTL buffer for custom notification melodies
|
||||
// Persistent RTTTL buffer for the bot !buzz command (see botBuzz()) -- sized
|
||||
@@ -288,6 +290,15 @@ private:
|
||||
// dedicated lock-screen code path in loop().
|
||||
void syncLockToHome();
|
||||
|
||||
// Whether a lockscreen password is set
|
||||
bool passwordLockEnabled() const;
|
||||
// Handles (un)locking and requesting password input when one is set
|
||||
void toggleLock();
|
||||
void beginUnlockPrompt();
|
||||
void cancelUnlockPrompt();
|
||||
// Handles shortcuts during lockscreen password input
|
||||
void handleUnlockKey(char c);
|
||||
|
||||
// Centred alert overlay (the showAlert() box). Wraps long text to up to
|
||||
// three lines inside the box instead of letting it overflow the border.
|
||||
// Shared by the normal render path and the lock screen (so a ringing
|
||||
@@ -566,7 +577,7 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isBuzzerQuiet() {
|
||||
bool isBuzzerQuiet() {
|
||||
#ifdef PIN_BUZZER
|
||||
return buzzer.isQuiet();
|
||||
#else
|
||||
|
||||
Reference in New Issue
Block a user