Add touch tap gesture for back navigation

Implements a reusable touch tap gesture in the top-left corner that maps to the Back button. The gesture is automatically integrated into wasPressed/wasReleased for Back button, making it available across all screens without per-activity code. Also fixes low-power CPU frequency floor to 80 MHz on PSRAM boards to prevent SD write and PSRAM instability caused by APB clock dropping below safe threshold.
This commit is contained in:
Justin Mitchell
2026-06-08 14:01:30 -04:00
parent 38ad4f9036
commit c308520f9c
5 changed files with 44 additions and 3 deletions
+2
View File
@@ -231,6 +231,8 @@ unsigned long HalGPIO::getHeldTime() const { return inputMgr.getHeldTime(); }
unsigned long HalGPIO::getPowerButtonHeldTime() const { return inputMgr.getPowerButtonHeldTime(); }
bool HalGPIO::wasTouchTap(float& nx, float& ny) const { return inputMgr.wasTouchTap(nx, ny); }
void HalGPIO::startDeepSleep() {
// Ensure that the power button has been released to avoid immediately turning back on if you're holding it
while (inputMgr.isPressed(BTN_POWER)) {
+5
View File
@@ -72,6 +72,11 @@ class HalGPIO {
unsigned long getHeldTime() const;
unsigned long getPowerButtonHeldTime() const;
// Touch: one-shot tap with the release position normalized 0..1 in the panel's
// native orientation. Returns false on non-touch devices. (Reusable gesture
// primitive; see MappedInputManager for the top-left = Back mapping.)
bool wasTouchTap(float& nx, float& ny) const;
// Setup wake up GPIO and enter deep sleep
void startDeepSleep();
+10 -1
View File
@@ -28,7 +28,16 @@ class HalPowerManager {
SemaphoreHandle_t modeMutex = nullptr; // Protect access to currentLockMode
public:
static constexpr int LOW_POWER_FREQ = 10; // MHz
// On PSRAM boards (classic ESP32 / M5Paper) the APB clock follows the CPU below
// 80 MHz, and APB clocks both the SD SPI bus and the 80 MHz PSRAM (which holds
// the framebuffer). Dropping to 10 MHz breaks SD writes and PSRAM, so floor the
// low-power CPU at 80 MHz (APB stays pinned at 80 for CPU 80/160/240, so power
// still drops from the 240 MHz default while SD/PSRAM stay stable).
#if defined(BOARD_HAS_PSRAM)
static constexpr int LOW_POWER_FREQ = 80; // MHz (APB-safe floor for PSRAM/SD)
#else
static constexpr int LOW_POWER_FREQ = 10; // MHz
#endif
static constexpr unsigned long IDLE_POWER_SAVING_MS = 3000; // ms
static constexpr unsigned long BATTERY_POLL_MS = 1500; // ms
+22 -2
View File
@@ -54,9 +54,29 @@ bool MappedInputManager::mapButton(const Button button, bool (HalGPIO::*fn)(uint
return false;
}
bool MappedInputManager::wasPressed(const Button button) const { return mapButton(button, &HalGPIO::wasPressed); }
// Top-left corner of the panel (panel-native, normalized). Generous so it's easy
// to hit; v1 is not yet orientation-mapped (see wasBackGesture NOTE in header).
static constexpr float BACK_GESTURE_FRAC_X = 0.22f;
static constexpr float BACK_GESTURE_FRAC_Y = 0.12f;
bool MappedInputManager::wasReleased(const Button button) const { return mapButton(button, &HalGPIO::wasReleased); }
bool MappedInputManager::wasBackGesture() const {
float nx = 0.0f, ny = 0.0f;
if (!gpio.wasTouchTap(nx, ny)) return false;
return nx <= BACK_GESTURE_FRAC_X && ny <= BACK_GESTURE_FRAC_Y;
}
bool MappedInputManager::wasPressed(const Button button) const {
// A top-left tap fires on the release frame; expose it on Back's press edge too
// so menus that act on wasPressed(Back) also respond. Deliberately NOT folded
// into isPressed, so a quick tap never satisfies the readers' long-press-home.
if (button == Button::Back && wasBackGesture()) return true;
return mapButton(button, &HalGPIO::wasPressed);
}
bool MappedInputManager::wasReleased(const Button button) const {
if (button == Button::Back && wasBackGesture()) return true;
return mapButton(button, &HalGPIO::wasReleased);
}
bool MappedInputManager::isPressed(const Button button) const { return mapButton(button, &HalGPIO::isPressed); }
+5
View File
@@ -19,6 +19,11 @@ class MappedInputManager {
bool wasPressed(Button button) const;
bool wasReleased(Button button) const;
bool isPressed(Button button) const;
// Reusable touch "back" gesture: a tap released in the top-left corner. Folded
// into Back's press/release edges, so every screen gets it with no per-activity
// code and no coordinates passed. False on non-touch devices.
// NOTE: v1 uses panel-native coordinates (not yet orientation-mapped).
bool wasBackGesture() const;
bool wasAnyPressed() const;
bool wasAnyReleased() const;
unsigned long getHeldTime() const;