Skip to content

Instantly share code, notes, and snippets.

@partlyhuman
Last active March 12, 2024 19:21
Show Gist options
  • Save partlyhuman/84b3c332570cb6bc810407a901f57f60 to your computer and use it in GitHub Desktop.
Save partlyhuman/84b3c332570cb6bc810407a901f57f60 to your computer and use it in GitHub Desktop.
Power/media button for arcade cabinet
//
// Connect a rotary encoder to pins 2, 3, 4
// Made for a MAME cabinet to act as a volume controller
// Adds additional functions when encoder button depressed
//
// Arduino libraries required:
// EncoderTool https://www.arduino.cc/reference/en/libraries/encodertool/
// HID-Project https://www.arduino.cc/reference/en/libraries/hid-project/
//
#include <HID-Project.h>
#include <EncoderTool.h>
#define DEBUG
using namespace EncoderTool;
PolledEncoder encoder;
volatile bool button_down = false;
volatile unsigned long up_time = 0;
volatile unsigned long down_time = 0;
volatile int presses = 0;
const unsigned long POWER_OFF_HOLD_MS = 2000;
const unsigned long DOUBLE_PRESS_CANCEL_MS = 250;
void onEncoder(int position, int delta) {
Consumer.write(delta > 0 ? MEDIA_VOLUME_UP : MEDIA_VOLUME_DOWN);
}
void onButtonChanged(signed char state) {
button_down = state == LOW;
if (button_down) {
down_time = millis();
} else {
up_time = millis();
presses++;
}
}
void onButtonSequence(int num) {
#ifdef DEBUG
Serial.print("Acting on multi tap ");
Serial.print(num);
Serial.println();
#endif
switch (num) {
case 2:
Keyboard.press(KEY_ESC);
Keyboard.releaseAll();
break;
case 3:
Keyboard.press(KEY_LEFT_ALT);
Keyboard.press(KEY_F4);
Keyboard.releaseAll();
break;
}
}
void onButtonHold() {
#ifdef DEBUG
Serial.println("LONG PRESS!");
#endif
// Don't interpret this as a click in any way
button_down = false;
presses = -1;
System.write(SYSTEM_POWER_DOWN);
// Keyboard.press(CONSUMER_POWER);
// Keyboard.releaseAll();
}
void setup() {
#ifdef DEBUG
Serial.begin(9600);
#endif
Keyboard.begin();
Consumer.begin();
System.begin();
encoder.begin(3, 2, 4);
encoder.attachCallback(onEncoder);
encoder.attachButtonCallback(onButtonChanged);
}
void loop() {
encoder.tick();
if (button_down && millis() > down_time + POWER_OFF_HOLD_MS) {
// Detect long-held button (still down)
onButtonHold();
}
if (!button_down && presses > 0 && millis() > up_time + DOUBLE_PRESS_CANCEL_MS) {
// Send accumulated multi-clicks or if just one, cancel multi-click
onButtonSequence(presses);
presses = 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment