Here is the whole thing:
/* 4-Way Button: Click, Double-Click, Press+Hold, and Press+Long-Hold Test Sketch
Original Script (1 button for 4 different actions) By Jeff Saltzman
Oct. 13, 2009
Edited for multiple buttons By Mariano Arellano
Sept. 10, 2017
To keep a physical interface as simple as possible, this sketch demonstrates generating four output events from 5 push-buttons.
1) Click: rapid press and release
2) Double-Click: two clicks in quick succession
3) Press and Hold: holding the button down
4) Long Press and Hold: holding the button for a long time
*/
//button quantity (how many buttons you have)
#define BTNQTY 2 //put +1 here, because button 0 in array is null
// Button timing variables
long debounce = 20; // ms debounce period to prevent flickering when pressing or releasing the button
long DCgap = 250; // max ms between clicks for a double click event
long holdTime = 1000; // ms hold period: how long to wait for press+hold event
long longHoldTime = 3000; // ms long hold period: how long to wait for press+hold event
//Actual button pin numbers /0 none /button 1, 2, 3, 4, 5
const uint8_t btn[BTNQTY] = { 0, 2};
//Active Btn
int activebtn;
//Button States
boolean btnstate[BTNQTY];
boolean buttonLast[BTNQTY]; // buffered value of the button's previous state
boolean DCwaiting[BTNQTY]; // whether we're waiting for a double click (down)
boolean DConUp[BTNQTY]; // whether to register a double click on next release, or whether to wait and click
boolean singleOK[BTNQTY]; // whether it's OK to do a single click
long downTime[BTNQTY]; // time the button was pressed down
long upTime[BTNQTY]; // time the button was released
boolean ignoreUp[BTNQTY]; // whether to ignore the button release because the click+hold was triggered
boolean waitForUp[BTNQTY]; // when held, whether to wait for the up event
boolean holdEventPast[BTNQTY]; // whether or not the hold event happened already
boolean longHoldEventPast[BTNQTY];// whether or not the long hold event happened already
//=================================================
#define triggerPin 7
long prevMill = 0;
void setup() {
for (int i = 0; i < BTNQTY; i++) {
pinMode(btn[i], INPUT_PULLUP);
buttonLast[i] = HIGH; // buffered value of the button's previous state
DCwaiting[i] = false; // whether we're waiting for a double click (down)
DConUp[i] = false; // whether to register a double click on next release, or whether to wait and click
singleOK[i] = true; // whether it's OK to do a single click
downTime[i] = -1; // time the button was pressed down
upTime[i] = -1; // time the button was released
ignoreUp[i] = false; // whether to ignore the button release because the click+hold was triggered
waitForUp[i] = false; // when held, whether to wait for the up event
holdEventPast[i] = false; // whether or not the hold event happened already
longHoldEventPast[i] = false;// whether or not the long hold event happened already
}
Serial.begin(9600);
pinMode(triggerPin, OUTPUT); //pin7 Output
}
void loop() {
// Get active button event and act accordingly
checkButtons();
// Serial.print(prevMill);
// Serial.print(" ");
// Serial.println((long)millis() - prevMill);
}
void findMenu(int btn, int event) {
switch (btn) {
case 0:
break;
case 1:
Serial.print("Button ");
Serial.print(btn);
switch (event) {
case 1:
Serial.println(" single press");
prevMill = millis();
triggerBoot(5000);
break;
case 2:
Serial.println(" double press");
break;
case 3:
Serial.println(" hold press");
break;
case 4:
Serial.println(" long press");
break;
}
break;
// case 2:
// Serial.print("Button ");
// Serial.print(btn);
// switch(event){
// case 1:
// Serial.println(" single press");
// break;
// case 2:
// Serial.println(" double press");
// break;
// case 3:
// Serial.println(" hold press");
// break;
// case 4:
// Serial.println(" long press");
// break;
// }
// break;
// case 3:
// Serial.print("Button ");
// Serial.print(btn);
// switch(event){
// case 1:
// Serial.println(" single press");
// break;
// case 2:
// Serial.println(" double press");
// break;
// case 3:
// Serial.println(" hold press");
// break;
// case 4:
// Serial.println(" long press");
// break;
// }
// break;
// case 4:
// Serial.print("Button ");
// Serial.print(btn);
// switch(event){
// case 1:
// Serial.println(" single press");
// break;
// case 2:
// Serial.println(" double press");
// break;
// case 3:
// Serial.println(" hold press");
// break;
// case 4:
// Serial.println(" long press");
// break;
// }
// break;
// case 5:
// Serial.print("Button ");
// Serial.print(btn);
// switch(event){
// case 1:
// Serial.println(" single press");
// break;
// case 2:
// Serial.println(" double press");
// break;
// case 3:
// Serial.println(" hold press");
// break;
// case 4:
// Serial.println(" long press");
// break;
// }
// activebtn = 0;
// break;
}
}
void checkButtons() {
int event = 0;
for (int i = 1; i < BTNQTY; i++) {
btnstate[i] = digitalRead(btn[i]);
if (btnstate[i] == LOW) { //LOW means pressed (i know)
activebtn = i;
break;
}
}
// Button pressed down
if (btnstate[activebtn] == LOW && buttonLast[activebtn] == HIGH && (millis() - upTime[activebtn]) > debounce)
{
downTime[activebtn] = millis();
ignoreUp[activebtn] = false;
waitForUp[activebtn] = false;
singleOK[activebtn] = true;
holdEventPast[activebtn] = false;
longHoldEventPast[activebtn] = false;
if ((millis() - upTime[activebtn]) < DCgap && DConUp[activebtn] == false && DCwaiting[activebtn] == true) DConUp[activebtn] = true;
else DConUp[activebtn] = false;
DCwaiting[activebtn] = false;
}
// Button released
else if (btnstate[activebtn] == HIGH && buttonLast[activebtn] == LOW && (millis() - downTime[activebtn]) > debounce)
{
if (ignoreUp[activebtn] == false)
{
upTime[activebtn] = millis();
if (DConUp[activebtn] == false) DCwaiting[activebtn] = true;
else
{
event = 2;
DConUp[activebtn] = false;
DCwaiting[activebtn] = false;
singleOK[activebtn] = false;
}
}
}
// Test for normal click event: DCgap expired
if ( btnstate[activebtn] == HIGH && (millis() - upTime[activebtn]) >= DCgap && DCwaiting[activebtn] == true && DConUp[activebtn] == false && singleOK[activebtn] == true && event != 2)
{
event = 1;
DCwaiting[activebtn] = false;
}
// Test for hold
if (btnstate[activebtn] == LOW && (millis() - downTime[activebtn]) >= holdTime) {
// Trigger "normal" hold
if (holdEventPast[activebtn] == false)
{
event = 3;
waitForUp[activebtn] = true;
ignoreUp[activebtn] = true;
DConUp[activebtn] = false;
DCwaiting[activebtn] = false;
//downTime = millis();
holdEventPast[activebtn] = true;
}
// Trigger "long" hold
if ((millis() - downTime[activebtn]) >= longHoldTime)
{
if (longHoldEventPast[activebtn] == false)
{
event = 4;
longHoldEventPast[activebtn] = true;
}
}
}
buttonLast[activebtn] = btnstate[activebtn];
if ((activebtn != 0) && (event != 0)) {
findMenu(activebtn, event);
}
}
void triggerBoot (int interval) {
if (((long)millis() - prevMill) >= interval) {
// prevMill = millis(); //stores current value of millis()
digitalWrite(triggerPin, LOW);
prevMill = 0;
}
digitalWrite(triggerPin, HIGH);
}