#include <mechButton.h>
class CounterButton : public mechButton {
public:
CounterButton(int inPin) : mechButton(inPin) {
longPressMs = 600; // Delay before scrolling starts (600ms)
startIntervalMs = 250; // Initial slow scroll speed (4 steps/sec)
maxSpeedIntervalMs = 30; // Fastest scroll speed speed (33 steps/sec)
accelerationRate = 25; // How many ms to shave off the interval per repeat step
currentIntervalMs = startIntervalMs;
isPressed = false;
longPressTriggered = false;
pressTime = 0;
lastRepeatTime = 0;
callbackAction = NULL;
}
void setActionCallback(void (*func)(void)) { callbackAction = func; }
void setLongPressDuration(unsigned long ms) { longPressMs = ms; }
void update() {
bool currentlyPressed = !trueFalse();
// 1. Initial Press Down
if (currentlyPressed && !isPressed) {
isPressed = true;
longPressTriggered = false;
currentIntervalMs = startIntervalMs; // Reset speed back to slow
pressTime = millis();
if (callbackAction) callbackAction();
}
// 2. Finger Released
else if (!currentlyPressed && isPressed) {
isPressed = false;
}
// 3. Continuous Hold Timing Engine
if (isPressed) {
unsigned long currentMillis = millis();
unsigned long heldDuration = currentMillis - pressTime;
if (!longPressTriggered) {
// Wait for initial long press delay
if (heldDuration >= longPressMs) {
longPressTriggered = true;
lastRepeatTime = currentMillis;
if (callbackAction) callbackAction();
}
} else {
// Dynamic Auto-Repeat with acceleration
if (currentMillis - lastRepeatTime >= currentIntervalMs) {
lastRepeatTime = currentMillis;
// Accelerate: Shave time off the interval until hitting top speed
if (currentIntervalMs > maxSpeedIntervalMs) {
if (currentIntervalMs - accelerationRate < maxSpeedIntervalMs) {
currentIntervalMs = maxSpeedIntervalMs; // Clamp to max speed
} else {
currentIntervalMs -= accelerationRate; // Speed up
}
}
if (callbackAction) callbackAction();
}
}
}
}
private:
unsigned long longPressMs;
unsigned long startIntervalMs;
unsigned long currentIntervalMs;
unsigned long maxSpeedIntervalMs;
unsigned long accelerationRate;
unsigned long pressTime;
unsigned long lastRepeatTime;
bool isPressed;
bool longPressTriggered;
void (*callbackAction)(void);
};
// Global Configuration
int globalCounter = 0;
const int MIN_VAL = 0; // Absolute minimum boundary
const int MAX_VAL = 3599; // Absolute maximum boundary
CounterButton btnUp(3);
CounterButton btnDown(2);
void setup() {
Serial.begin(9600);
btnUp.setActionCallback(incrementCounter);
btnDown.setActionCallback(decrementCounter);
Serial.print("Initial Counter: ");
Serial.println(globalCounter);
}
void loop() {
idle();
btnUp.update();
btnDown.update();
}
// Increment Action with safety bounds
void incrementCounter() {
if (globalCounter < MAX_VAL) {
globalCounter++;
printCounter();
} else {
Serial.println("Counter reached MAXIMUM limit!");
}
}
// Decrement Action with safety bounds
void decrementCounter() {
if (globalCounter > MIN_VAL) {
globalCounter--;
printCounter();
} else {
Serial.println("Counter reached MINIMUM limit!");
}
}
void printCounter() {
Serial.print("Counter: ");
Serial.println(globalCounter);
}