#include <Arduino.h> #include <AceButton.h> #include <Keyboard.h> #include <HID.h> #include <FastLED.h> // Microsoft PowerToys default: Win + Shift + A const char HOTKEY_1 = KEY_LEFT_GUI; const char HOTKEY_2 = KEY_LEFT_SHIFT; const char HOTKEY_3 = 'a'; #define BUTTON_PIN 2 #define LED_PIN 3 #define NUM_LEDS 4 #define MIN_BRIGHTNESS 32 #define MAX_BRIGHTNESS 255 #define DOUBLECLICK_DELAY 400 using namespace ace_button; AceButton button(BUTTON_PIN); CRGB leds[NUM_LEDS]; bool muted = false; bool ptt = false; void sendHotkey() { Keyboard.press(HOTKEY_1); Keyboard.press(HOTKEY_2); Keyboard.press(HOTKEY_3); Keyboard.releaseAll(); } void handleEvent(AceButton * /* button */, uint8_t eventType, uint8_t buttonState) { switch (eventType) { case AceButton::kEventDoubleClicked: if (muted) { muted = false; Serial.println("Toggle: unmuted"); } else { muted = true; Serial.println("Toggle: muted"); } sendHotkey(); break; case AceButton::kEventLongPressed: if (muted) { muted = false; Serial.println("PTT: unmuted"); } else { muted = true; Serial.println("PTT: muted"); } ptt = true; sendHotkey(); break; case AceButton::AceButton::kEventLongReleased: if (muted) { muted = false; Serial.println("PTT: unmuted"); } else { muted = true; Serial.println("PTT: muted"); } ptt = false; sendHotkey(); break; } } void setupPins() { pinMode(LED_BUILTIN_TX, INPUT); // switch off builtin TX LED pinMode(LED_BUILTIN_RX, INPUT); // switch off builtin RX LED pinMode(BUTTON_PIN, INPUT_PULLUP); } void setupButton() { ButtonConfig *buttonConfig = button.getButtonConfig(); buttonConfig->setEventHandler(handleEvent); buttonConfig->setFeature(ButtonConfig::kFeatureDoubleClick); buttonConfig->setFeature(ButtonConfig::kFeatureLongPress); buttonConfig->setFeature(ButtonConfig::kFeatureSuppressAfterLongPress); buttonConfig->setDoubleClickDelay(DOUBLECLICK_DELAY); buttonConfig->setLongPressDelay(DOUBLECLICK_DELAY + 1); } void setupLEDs() { FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS); FastLED.setBrightness(MAX_BRIGHTNESS); for (size_t i = 0; i < 3; i++) { for (size_t i = 0; i < NUM_LEDS; i++) { leds[i] = CRGB::Blue; FastLED.show(); delay(100); leds[i] = CRGB::Black; FastLED.show(); } } } void setup() { Serial.begin(115200); delay(500); Keyboard.begin(); setupPins(); setupButton(); setupLEDs(); Serial.flush(); Serial.println(); Serial.println("Ultimute ready!"); Serial.println(); } void checkButton() { static unsigned long prev = millis(); unsigned long now = millis(); if (now - prev > 5) { button.check(); prev = now; } } void handleButtonState() { if (muted) { FastLED.setBrightness(MIN_BRIGHTNESS); fill_solid(leds, NUM_LEDS, CRGB::Green); } else { FastLED.setBrightness(MAX_BRIGHTNESS); fill_solid(leds, NUM_LEDS, CRGB::Red); } if (ptt) { float breath = (exp(sin(millis() / 250.0 * PI)) - 0.36787944) * 108.0; breath = map(breath, 0, 255, MIN_BRIGHTNESS, MAX_BRIGHTNESS); FastLED.setBrightness(breath); } } void loop() { checkButton(); handleButtonState(); FastLED.show(); }