diff --git a/sketch/obd2_gauge/XPT2046_TouchscreenSOFTSPI.cpp b/sketch/obd2_gauge/XPT2046_TouchscreenSOFTSPI.cpp index ea78ecc..2b2b575 100644 --- a/sketch/obd2_gauge/XPT2046_TouchscreenSOFTSPI.cpp +++ b/sketch/obd2_gauge/XPT2046_TouchscreenSOFTSPI.cpp @@ -22,8 +22,8 @@ #include "XPT2046_TouchscreenSOFTSPI.h" -#define Z_THRESHOLD 65 -#define Z_THRESHOLD_INT 50 +#define Z_THRESHOLD 180 +#define Z_THRESHOLD_INT 100 #define MSEC_THRESHOLD 3 #define SPI_SETTING SPISettings(2000000, MSBFIRST, SPI_MODE0) diff --git a/sketch/obd2_gauge/obd2_gauge.ino b/sketch/obd2_gauge/obd2_gauge.ino index 3b83b45..96466b1 100644 --- a/sketch/obd2_gauge/obd2_gauge.ino +++ b/sketch/obd2_gauge/obd2_gauge.ino @@ -573,9 +573,10 @@ void loop() { } // SCAN TOUCHSCREEN & BUTTON - // - Single tap on a quadrant in 4-quadrant view: switches to full screen for that quadrant - // - Single tap anywhere in full screen view: returns to 4-quadrant view - // - Long press (> 1s) on screen OR holding selector button: opens configuration menu + // - Double click: switch screen page (Page 0 <-> Page 1) with slide animation + // - Single click: toggle fullscreen for tapped quadrant (or refresh sensors on Tri-Temp) + // - Long press (> 1s): open configuration menu + // - Physical selector button: open configuration menu uint16_t touchX = 0, touchY = 0; bool isTouched = getTouch(&touchX, &touchY); bool btnPressed = (digitalRead(SELECTOR_PIN) == LOW); @@ -590,9 +591,15 @@ void loop() { static uint16_t lastTouchX = 0, lastTouchY = 0; static bool longPressHandled = false; + // Double-tap state machine + static bool waitingForDoubleTap = false; + static uint32_t firstTapReleaseTime = 0; + static uint16_t firstTapX = 0, firstTapY = 0; + if (btnPressed) { delay(50); if (digitalRead(SELECTOR_PIN) == LOW) { + waitingForDoubleTap = false; touchBeep(); configMenu(); waitForTouchRelease(); @@ -608,113 +615,94 @@ void loop() { lastTouchX = touchX; lastTouchY = touchY; longPressHandled = false; - touchBeep(); // Crisp acoustic feedback on touch screen press! } else { - // Keep tracking coordinates while held to ensure stable swipe/quadrant detection lastTouchX = touchX; lastTouchY = touchY; - int16_t liveDeltaX = (int16_t)lastTouchX - (int16_t)touchStartX; - int16_t liveDeltaY = (int16_t)lastTouchY - (int16_t)touchStartY; + // Long press check: finger held stationary for > 1000ms + int16_t currentDistX = abs((int16_t)lastTouchX - (int16_t)touchStartX); + int16_t currentDistY = abs((int16_t)lastTouchY - (int16_t)touchStartY); - // FAST LIVE SWIPE DETECTION: - // Trigger immediately as soon as finger moves >= 28px horizontally (no need to lift or press hard) - if (!longPressHandled) { - if (liveDeltaX < -28 && abs(liveDeltaY) < 85) { - // SWIPE LEFT: Page 0 -> Page 1 (Tri-Temperature Screen) - longPressHandled = true; - if (fullScreenCell != -1) { - fullScreenCell = -1; - } - if (currentScreenPage == 0) { - animateSlideTransition(true); - currentScreenPage = 1; - initScreen(); - } - waitForTouchRelease(); - isTouching = false; - lastActivityTime = millis(); - } else if (liveDeltaX > 28 && abs(liveDeltaY) < 85) { - // SWIPE RIGHT: Page 1 -> Page 0 (4 Quadrants) - longPressHandled = true; - if (fullScreenCell != -1) { - fullScreenCell = -1; - } - if (currentScreenPage == 1) { - animateSlideTransition(false); - currentScreenPage = 0; - initScreen(); - } - waitForTouchRelease(); - isTouching = false; - lastActivityTime = millis(); - } else if ((millis() - touchStartTime > 1000) && abs(liveDeltaX) < 20 && abs(liveDeltaY) < 20) { - // Long press (> 1s) held stationary: Open Config Menu immediately! - longPressHandled = true; - touchBeep(); // Confirmation chirp - configMenu(); - waitForTouchRelease(); - lastActivityTime = millis(); - initScreen(); - isTouching = false; - } + if (!longPressHandled && (millis() - touchStartTime > 1000) && currentDistX < 35 && currentDistY < 35) { + longPressHandled = true; + waitingForDoubleTap = false; + touchBeep(); // Confirmation chirp + configMenu(); + waitForTouchRelease(); + lastActivityTime = millis(); + initScreen(); + isTouching = false; } } } else { - // Touch / button released + // Touch released if (isTouching) { isTouching = false; + uint32_t pressDuration = millis() - touchStartTime; if (!longPressHandled) { - int16_t deltaX = (int16_t)lastTouchX - (int16_t)touchStartX; - int16_t deltaY = (int16_t)lastTouchY - (int16_t)touchStartY; + int16_t deltaX = abs((int16_t)lastTouchX - (int16_t)touchStartX); + int16_t deltaY = abs((int16_t)lastTouchY - (int16_t)touchStartY); - // Quick flick swipe fallback in case finger was lifted very rapidly - if (deltaX < -25 && abs(deltaY) < 85) { - // SWIPE LEFT: Page 0 -> Page 1 (Tri-Temperature Screen) - if (fullScreenCell != -1) { - fullScreenCell = -1; - } - if (currentScreenPage == 0) { - animateSlideTransition(true); - currentScreenPage = 1; - initScreen(); - } - } else if (deltaX > 25 && abs(deltaY) < 85) { - // SWIPE RIGHT: Page 1 -> Page 0 (4 Quadrants) - if (fullScreenCell != -1) { - fullScreenCell = -1; - } - if (currentScreenPage == 1) { - animateSlideTransition(false); - currentScreenPage = 0; - initScreen(); - } - } else { - // Valid TAP detected! - if (currentScreenPage == 0) { - if (fullScreenCell == -1) { - // Switch to full screen for tapped quadrant - int quad = (lastTouchX < 160) ? ((lastTouchY < 120) ? 0 : 2) : ((lastTouchY < 120) ? 1 : 3); - fullScreenCell = quad; - } else { - // Return to 4 quadrants view + // Anti-noise: require at least 30ms of contact and displacement < 40px (clean tap) + if (pressDuration >= 30 && deltaX < 40 && deltaY < 40) { + touchBeep(); // Crisp acoustic feedback on confirmed tap! + + if (waitingForDoubleTap && (millis() - firstTapReleaseTime <= 400)) { + // DOUBLE CLICK DETECTED: Switch Screen Page! + waitingForDoubleTap = false; + + if (fullScreenCell != -1) { fullScreenCell = -1; } - initScreen(); + + if (currentScreenPage == 0) { + animateSlideTransition(true); + currentScreenPage = 1; + initScreen(); + } else { + animateSlideTransition(false); + currentScreenPage = 0; + initScreen(); + } + waitForTouchRelease(); + lastActivityTime = millis(); } else { - // Tap on Tri-Temp screen: immediate sensor refresh - updateTriTempSensors(true); + // First tap of a potential double click: start waiting window + waitingForDoubleTap = true; + firstTapReleaseTime = millis(); + firstTapX = lastTouchX; + firstTapY = lastTouchY; } } - waitForTouchRelease(); // Clear mechanical bounce on release } } + + // Check if double-tap timeout has expired -> execute SINGLE CLICK action! + if (waitingForDoubleTap && (millis() - firstTapReleaseTime > 400)) { + waitingForDoubleTap = false; + + if (currentScreenPage == 0) { + if (fullScreenCell == -1) { + // Switch to full screen for tapped quadrant + int quad = (firstTapX < 160) ? ((firstTapY < 120) ? 0 : 2) : ((firstTapY < 120) ? 1 : 3); + fullScreenCell = quad; + } else { + // Return to 4 quadrants view + fullScreenCell = -1; + } + initScreen(); + } else { + // Tap on Tri-Temp screen: immediate sensor refresh + updateTriTempSensors(true); + } + lastActivityTime = millis(); + } } // AUTO-SLEEP BY INACTIVITY // If auto-sleep is enabled, and screen is not being held, and engine is stopped (RPM <= 300) - if (autoSleepIndex > 0 && !isTouching && !btnPressed && !longPressHandled && currentRpm <= 300.0f) { + if (autoSleepIndex > 0 && !isTouching && !btnPressed && !longPressHandled && !waitingForDoubleTap && currentRpm <= 300.0f) { uint32_t timeoutMs = (uint32_t)AUTO_SLEEP_SEC_TABLE[autoSleepIndex] * 1000UL; if (millis() - lastActivityTime >= timeoutMs) { enterLightSleep(); diff --git a/sketch/obd2_gauge/touchscreen.h b/sketch/obd2_gauge/touchscreen.h index 26541d2..3cf45a9 100644 --- a/sketch/obd2_gauge/touchscreen.h +++ b/sketch/obd2_gauge/touchscreen.h @@ -24,7 +24,7 @@ bool getTouch(uint16_t *x, uint16_t *y) { TS_Point p = ts.getPoint(tsSoftSpi); // Filter noise: require valid touch pressure and coordinates within active screen - if (p.z < 60) return false; + if (p.z < 160) return false; if (p.x < 150 || p.x > 3850 || p.y < 150 || p.y > 3850) return false; int16_t tx = map(p.x, 200, 3700, 0, 320);