feat(touch): add press/release detection with touch-down tracking
This commit is contained in:
@@ -173,11 +173,32 @@ TouchEvent DisplayDriverTFT::readTouch() {
|
|||||||
TouchEvent evt;
|
TouchEvent evt;
|
||||||
uint16_t tx, ty;
|
uint16_t tx, ty;
|
||||||
uint8_t touched = _tft.getTouch(&tx, &ty, 100);
|
uint8_t touched = _tft.getTouch(&tx, &ty, 100);
|
||||||
if(touched) {
|
|
||||||
|
// Detect transitions (press/release)
|
||||||
|
if(touched && !_touchWasPressed) {
|
||||||
|
// Press transition: finger just touched down
|
||||||
evt.pressed = true;
|
evt.pressed = true;
|
||||||
|
_touchDownX = tx;
|
||||||
|
_touchDownY = ty;
|
||||||
|
evt.downX = _touchDownX;
|
||||||
|
evt.downY = _touchDownY;
|
||||||
|
} else if(!touched && _touchWasPressed) {
|
||||||
|
// Release transition: finger just lifted
|
||||||
|
evt.released = true;
|
||||||
|
evt.downX = _touchDownX;
|
||||||
|
evt.downY = _touchDownY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current position if still touched
|
||||||
|
if(touched) {
|
||||||
evt.x = tx;
|
evt.x = tx;
|
||||||
evt.y = ty;
|
evt.y = ty;
|
||||||
|
evt.downX = _touchDownX;
|
||||||
|
evt.downY = _touchDownY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track previous state for next call
|
||||||
|
_touchWasPressed = touched;
|
||||||
return evt;
|
return evt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,4 +32,9 @@ private:
|
|||||||
ScreenID _lastScreen = ScreenID::BOOT;
|
ScreenID _lastScreen = ScreenID::BOOT;
|
||||||
BootStage _lastBootStage = BootStage::SPLASH;
|
BootStage _lastBootStage = BootStage::SPLASH;
|
||||||
bool _needsRedraw = true;
|
bool _needsRedraw = true;
|
||||||
|
|
||||||
|
// Touch tracking for press/release detection
|
||||||
|
bool _touchWasPressed = false;
|
||||||
|
int _touchDownX = -1;
|
||||||
|
int _touchDownY = -1;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,16 +68,36 @@ TouchEvent DisplayDriverGFX::readTouch() {
|
|||||||
int32_t x, y;
|
int32_t x, y;
|
||||||
bool pressed = _gfx->getTouch(&x, &y);
|
bool pressed = _gfx->getTouch(&x, &y);
|
||||||
|
|
||||||
// Only report NEW touches (debounce - ignore held touches)
|
// Detect transitions (press/release)
|
||||||
evt.pressed = pressed && !_lastTouch.pressed;
|
if(pressed && !_lastTouch.pressed) {
|
||||||
|
// Press transition: finger just touched down
|
||||||
|
evt.pressed = true;
|
||||||
|
evt.downX = static_cast<int>(x);
|
||||||
|
evt.downY = static_cast<int>(y);
|
||||||
|
_lastTouch.downX = evt.downX;
|
||||||
|
_lastTouch.downY = evt.downY;
|
||||||
|
} else if(!pressed && _lastTouch.pressed) {
|
||||||
|
// Release transition: finger just lifted
|
||||||
|
evt.released = true;
|
||||||
|
evt.downX = _lastTouch.downX;
|
||||||
|
evt.downY = _lastTouch.downY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current position if still touched
|
||||||
if(pressed) {
|
if(pressed) {
|
||||||
evt.x = static_cast<int>(x);
|
evt.x = static_cast<int>(x);
|
||||||
evt.y = static_cast<int>(y);
|
evt.y = static_cast<int>(y);
|
||||||
|
evt.downX = _lastTouch.downX;
|
||||||
|
evt.downY = _lastTouch.downY;
|
||||||
_pressStartMs = millis();
|
_pressStartMs = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track previous state
|
||||||
_lastTouch.pressed = pressed;
|
_lastTouch.pressed = pressed;
|
||||||
|
if(pressed) {
|
||||||
|
_lastTouch.x = evt.x;
|
||||||
|
_lastTouch.y = evt.y;
|
||||||
|
}
|
||||||
return evt;
|
return evt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ private:
|
|||||||
void drawDashboard(const ScreenState& state);
|
void drawDashboard(const ScreenState& state);
|
||||||
|
|
||||||
// Touch handling
|
// Touch handling
|
||||||
TouchEvent _lastTouch = { false, 0, 0 };
|
TouchEvent _lastTouch = { false, false, 0, 0, -1, -1 };
|
||||||
unsigned long _pressStartMs = 0;
|
unsigned long _pressStartMs = 0;
|
||||||
bool _isHolding = false;
|
bool _isHolding = false;
|
||||||
|
|
||||||
|
|||||||
@@ -143,6 +143,68 @@ public:
|
|||||||
_drv->updateHint(x, y, active);
|
_drv->updateHint(x, y, active);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Show touch feedback - highlights the tile at given coordinates
|
||||||
|
/// Returns true if a valid tile is being touched
|
||||||
|
bool showTouchFeedback(int x, int y) {
|
||||||
|
if(!_drv || _gridCols <= 0) return false;
|
||||||
|
|
||||||
|
// Transform touch coordinates
|
||||||
|
_drv->transformTouch(&x, &y);
|
||||||
|
|
||||||
|
int headerH = 30;
|
||||||
|
if(y < headerH) return false;
|
||||||
|
|
||||||
|
// Calculate which cell
|
||||||
|
int cellW = _drv->width() / _gridCols;
|
||||||
|
int cellH = (_drv->height() - headerH) / _gridRows;
|
||||||
|
|
||||||
|
int col = x / cellW;
|
||||||
|
int row = (y - headerH) / cellH;
|
||||||
|
|
||||||
|
if(col < 0 || col >= _gridCols || row < 0 || row >= _gridRows)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Find which tile is at this position
|
||||||
|
for(int i = 0; i < _tileCount; i++) {
|
||||||
|
const TileLayout& lay = _layouts[i];
|
||||||
|
if(lay.col <= col && col < lay.col + lay.cols &&
|
||||||
|
lay.row <= row && lay.row + lay.rows > row) {
|
||||||
|
// Found the tile - draw highlight via driver
|
||||||
|
_drv->updateHint(lay.x, lay.y, true); // active=true means show feedback
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear touch feedback
|
||||||
|
void clearTouchFeedback() {
|
||||||
|
if(_drv)
|
||||||
|
_drv->updateHint(0, 0, false); // active=false means clear
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if current position is still in same tile as touch-down
|
||||||
|
bool isSameTile(int downX, int downY, int currentX, int currentY) const {
|
||||||
|
if(!_drv || _gridCols <= 0 || downX < 0) return false;
|
||||||
|
|
||||||
|
int dx = downX, dy = downY;
|
||||||
|
int cx = currentX, cy = currentY;
|
||||||
|
|
||||||
|
_drv->transformTouch(&dx, &dy);
|
||||||
|
_drv->transformTouch(&cx, &cy);
|
||||||
|
|
||||||
|
int headerH = 30;
|
||||||
|
int cellW = _drv->width() / _gridCols;
|
||||||
|
int cellH = (_drv->height() - headerH) / _gridRows;
|
||||||
|
|
||||||
|
int downCol = dx / cellW;
|
||||||
|
int downRow = (dy - headerH) / cellH;
|
||||||
|
int curCol = cx / cellW;
|
||||||
|
int curRow = (cy - headerH) / cellH;
|
||||||
|
|
||||||
|
return downCol == curCol && downRow == curRow;
|
||||||
|
}
|
||||||
|
|
||||||
int width() { return _drv ? _drv->width() : 0; }
|
int width() { return _drv ? _drv->width() : 0; }
|
||||||
int height() { return _drv ? _drv->height() : 0; }
|
int height() { return _drv ? _drv->height() : 0; }
|
||||||
|
|
||||||
|
|||||||
@@ -310,9 +310,8 @@ void DoorbellLogic::setScreen(ScreenID s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int DoorbellLogic::handleTouch(const TouchEvent& evt) {
|
int DoorbellLogic::handleTouch(const TouchEvent& evt) {
|
||||||
if(!evt.pressed)
|
// Handle press - show visual feedback
|
||||||
return -1;
|
if(evt.pressed) {
|
||||||
|
|
||||||
// Reset inactivity timer on any touch
|
// Reset inactivity timer on any touch
|
||||||
_lastActivityMs = millis();
|
_lastActivityMs = millis();
|
||||||
|
|
||||||
@@ -322,8 +321,22 @@ int DoorbellLogic::handleTouch(const TouchEvent& evt) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show touch feedback on press
|
||||||
if(_state.screen == ScreenID::DASHBOARD) {
|
if(_state.screen == ScreenID::DASHBOARD) {
|
||||||
TileAction action = _display->handleDashboardTouch(evt.x, evt.y);
|
_display->showTouchFeedback(evt.x, evt.y);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle release - fire action if same tile
|
||||||
|
if(evt.released) {
|
||||||
|
// Clear feedback
|
||||||
|
_display->clearTouchFeedback();
|
||||||
|
|
||||||
|
if(_state.screen == ScreenID::DASHBOARD) {
|
||||||
|
// Only fire action if finger stayed on same tile
|
||||||
|
if(evt.downX >= 0 && _display->isSameTile(evt.downX, evt.downY, evt.x, evt.y)) {
|
||||||
|
TileAction action = _display->handleDashboardTouch(evt.downX, evt.downY);
|
||||||
if(action != TileAction::NONE) {
|
if(action != TileAction::NONE) {
|
||||||
Serial.printf("[DASH] Action: %d\n", (int)action);
|
Serial.printf("[DASH] Action: %d\n", (int)action);
|
||||||
switch(action) {
|
switch(action) {
|
||||||
@@ -345,13 +358,14 @@ int DoorbellLogic::handleTouch(const TouchEvent& evt) {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return (int)action;
|
return (int)action;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(_state.screen == ScreenID::ALERT) {
|
if(_state.screen == ScreenID::ALERT) {
|
||||||
Serial.println("[TOUCH] ALERT tap");
|
Serial.println("[TOUCH] ALERT tap");
|
||||||
return -1;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
#include "ScreenState.h"
|
#include "ScreenState.h"
|
||||||
|
|
||||||
struct TouchEvent {
|
struct TouchEvent {
|
||||||
bool pressed = false;
|
bool pressed = false; // finger just touched down
|
||||||
int x = 0;
|
bool released = false; // finger just lifted (after being pressed)
|
||||||
int y = 0;
|
int x = 0; // current x position
|
||||||
|
int y = 0; // current y position
|
||||||
|
int downX = -1; // x position where touch started
|
||||||
|
int downY = -1; // y position where touch started
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HoldState {
|
struct HoldState {
|
||||||
|
|||||||
Reference in New Issue
Block a user