|
#include <Keyboard.h> |
|
#include <FastLED.h> |
|
|
|
#define LED_PIN 18 // GPIO 18 |
|
#define NUM_LEDS 3 |
|
|
|
// From left to right, when the USB ports are on top and right |
|
#define KEY1 14 // "Ctrl", GPIO 14 |
|
#define KEY2 13 // "C", GPIO 13 |
|
#define KEY3 12 // "V", GPIO 12 |
|
|
|
#define FLAG_KEY1 0 |
|
#define FLAG_KEY2 1 |
|
#define FLAG_KEY3 2 |
|
|
|
// PC uses Control, Mac uses Command |
|
// Pick one: |
|
#define META_KEY KEY_LEFT_CTRL // For PC |
|
// #define META_KEY KEY_LEFT_GUI // For Mac |
|
|
|
#define DELAY_BETWEEN_KEY_PRESS 10 |
|
|
|
CRGB leds[NUM_LEDS]; |
|
int flag[NUM_LEDS]; |
|
|
|
// For debounce |
|
int keys[] = {KEY1, KEY2, KEY3}; |
|
unsigned long debounceDelay = 10; |
|
int buttonState[NUM_LEDS]; |
|
int lastButtonState[NUM_LEDS]; |
|
unsigned long lastDebounceTime[NUM_LEDS]; |
|
|
|
// Reboot into firmware upload mode programmatically |
|
// source: |
|
// https://forums.raspberrypi.com/viewtopic.php?t=328795 |
|
// https://forums.raspberrypi.com/viewtopic.php?t=326333 |
|
static void wait_and_reboot() { |
|
#if configUSE_IDLE_HOOK // if there's an IDLE hook, it's because it is used to kick the watchdog |
|
__asm volatile(" cpsid i "); |
|
while (true) {}; // reboot should happen here when watchdog times out |
|
#else |
|
watchdog_reboot(0, 0, 25); |
|
#endif |
|
} |
|
|
|
void setup() { |
|
// make pins input and turn on the pull-up resistor so they go high unless |
|
// connected to ground: |
|
pinMode(KEY1, INPUT_PULLUP); |
|
pinMode(KEY2, INPUT_PULLUP); |
|
pinMode(KEY3, INPUT_PULLUP); |
|
|
|
// init debounce vars |
|
for (int i = 0; i < NUM_LEDS; i++) { |
|
buttonState[i] = HIGH; // unpressed is High |
|
lastButtonState[i] = HIGH; // unpressed is High |
|
lastDebounceTime[i] = 0; |
|
} |
|
|
|
FastLED.addLeds<WS2812, LED_PIN, RGB>(leds, NUM_LEDS); |
|
|
|
// Indicate code loaded |
|
for (int i = 0; i < 3; i++) { |
|
for (int j = 0; j < NUM_LEDS; j++) { |
|
leds[j] = CRGB(255, 255, 255); |
|
} |
|
FastLED.show(); |
|
delay(100); |
|
|
|
for (int j = 0; j < NUM_LEDS; j++) { |
|
leds[j] = CRGB(0, 0, 0); |
|
} |
|
FastLED.show(); |
|
delay(200); |
|
} |
|
|
|
Keyboard.begin(); |
|
} |
|
|
|
void handle_keys_with_debounce(uint8_t keysDef[NUM_LEDS][2]) { |
|
int reading; |
|
|
|
for (int i = 0; i < NUM_LEDS; i++) { |
|
reading = digitalRead(keys[i]); |
|
|
|
if (reading != lastButtonState[i]) { |
|
lastDebounceTime[i] = millis(); |
|
} |
|
|
|
if ((millis() - lastDebounceTime[i]) > debounceDelay) { |
|
if (reading != buttonState[i]) { |
|
buttonState[i] = reading; |
|
|
|
if (reading == LOW) { |
|
for (int j = 0; j < sizeof(keysDef[i]); j++) { |
|
if (keysDef[i][j] != 0) { |
|
Keyboard.press(keysDef[i][j]); |
|
} |
|
} |
|
flag[i] = 1; |
|
} else { |
|
Keyboard.releaseAll(); |
|
flag[i] = 0; |
|
} |
|
} |
|
} |
|
|
|
lastButtonState[i] = reading; |
|
} |
|
} |
|
|
|
void led_mode_all() { |
|
for (int i = 0; i < NUM_LEDS; i++) { |
|
leds[i] = CRGB(flag[FLAG_KEY1] * 255, flag[FLAG_KEY2] * 255, flag[FLAG_KEY3] * 255); |
|
} |
|
} |
|
|
|
void led_mode_only_one() { |
|
leds[0] = CRGB(flag[FLAG_KEY1] * 255, 0, 0); |
|
leds[1] = CRGB(0, flag[FLAG_KEY2] * 255, 0); |
|
leds[2] = CRGB(0, 0, flag[FLAG_KEY3] * 255); |
|
} |
|
|
|
void loop() { |
|
uint8_t mode_control_c_v[NUM_LEDS][2] = { |
|
{META_KEY, 0}, |
|
{'c', 0}, |
|
{'v', 0} |
|
}; |
|
|
|
uint8_t mode_copy_paste_cut[NUM_LEDS][2] = { |
|
{META_KEY, 'c'}, |
|
{META_KEY, 'v'}, |
|
{META_KEY, 'x'} |
|
}; |
|
|
|
uint8_t mode_do_nothing[NUM_LEDS][2] = { |
|
{0, 0}, |
|
{0, 0}, |
|
{0, 0} |
|
}; |
|
|
|
// choose one mode |
|
handle_keys_with_debounce(mode_copy_paste_cut); |
|
|
|
led_mode_all(); |
|
// led_mode_only_one(); |
|
FastLED.show(); |
|
delay(5); |
|
|
|
// Since the BOOT button is not easy to reach without take the board out, |
|
// here we checks if ALL three keys are pressed we will enter firmware upload mode |
|
if (flag[FLAG_KEY1] && flag[FLAG_KEY2] && flag[FLAG_KEY3]) { |
|
multicore_reset_core1(); |
|
reset_usb_boot(0, 0); |
|
reset_usb_boot(0, 0); |
|
} |
|
} |