From 44f5de357c9ed3458590e5e13402a4c5b2e8921d Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sat, 26 Nov 2016 08:45:29 +0100 Subject: [PATCH] Implement a way to do simple macros The main thing here is `Macros_::play`, which takes a list of bytes from PROGMEM, and plays a macro. The array is always a command, followed by arguments, and the size of the argument depends on the command: key presses and releases take a 16-bit argument, and the event is injected into the event handler flow. Waiting and interval change take a 8-bit time. Helpers are provided to make it a little bit easier to construct a macro. Of course, the `macroAction` method may do any other side effects, and is not restricted to returning a sequence of commands. Fixes #5. Signed-off-by: Gergely Nagy --- .../KeyboardioFirmware/KeyboardioFirmware.ino | 9 +++- .../src/Keyboardio-Macros.cpp | 47 +++++++++++++++++-- .../Keyboardio-Macros/src/Keyboardio-Macros.h | 19 ++------ .../Keyboardio-Macros/src/MacroKeyDefs.h | 15 ++++++ libraries/Keyboardio-Macros/src/MacroSteps.h | 22 +++++++++ 5 files changed, 94 insertions(+), 18 deletions(-) create mode 100644 libraries/Keyboardio-Macros/src/MacroKeyDefs.h create mode 100644 libraries/Keyboardio-Macros/src/MacroSteps.h diff --git a/examples/KeyboardioFirmware/KeyboardioFirmware.ino b/examples/KeyboardioFirmware/KeyboardioFirmware.ino index 9bec056d..6cf5ebfb 100644 --- a/examples/KeyboardioFirmware/KeyboardioFirmware.ino +++ b/examples/KeyboardioFirmware/KeyboardioFirmware.ino @@ -40,10 +40,17 @@ static LEDChaseEffect chaseEffect; static LEDNumlock numLockEffect (NUMPAD_KEYMAP); -void macroAction(uint8_t macroIndex, uint8_t keyState) { +const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) { if (macroIndex == 1 && key_toggled_on(keyState)) { Serial.print("Keyboard.IO keyboard driver v0.00"); + return MACRO(I(25), + D(LShift), T(M), U(LShift), T(O), T(D), T(E), T(L), + T(Space), + W(100), + T(0), T(1), + END); } + return MACRO_NONE; } void setup() { diff --git a/libraries/Keyboardio-Macros/src/Keyboardio-Macros.cpp b/libraries/Keyboardio-Macros/src/Keyboardio-Macros.cpp index b492d8eb..0014e07c 100644 --- a/libraries/Keyboardio-Macros/src/Keyboardio-Macros.cpp +++ b/libraries/Keyboardio-Macros/src/Keyboardio-Macros.cpp @@ -1,15 +1,56 @@ #include "Keyboardio-Macros.h" __attribute__((weak)) -void -macroAction(uint8_t macroIndex, uint8_t keyState) { +const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) { + return MACRO_NONE; +} + +void Macros_::play(const macro_t *macro_p) { + macro_t macro = END; + uint8_t interval = 0; + Key key; + + if (!macro_p) + return; + + while (true) { + switch (macro = pgm_read_byte(macro_p++)) { + case MACRO_ACTION_STEP_INTERVAL: + interval = pgm_read_byte(macro_p++); + break; + case MACRO_ACTION_STEP_WAIT: { + uint8_t wait = pgm_read_byte(macro_p++); + delay(wait); + break; + } + case MACRO_ACTION_STEP_KEYDOWN: + key.flags = pgm_read_byte(macro_p++); + key.rawKey = pgm_read_byte(macro_p++); + handle_key_event(key, 255, 255, IS_PRESSED | INJECTED); + Keyboard.sendReport(); + break; + case MACRO_ACTION_STEP_KEYUP: + key.flags = pgm_read_byte(macro_p++); + key.rawKey = pgm_read_byte(macro_p++); + handle_key_event(key, 255, 255, WAS_PRESSED | INJECTED); + Keyboard.sendReport(); + break; + case END: + default: + return; + } + + delay(interval); + } } static bool handleMacroEvent(Key mappedKey, byte row, byte col, uint8_t keyState) { if (!(mappedKey.flags & (SYNTHETIC|IS_MACRO))) return false; - macroAction(mappedKey.rawKey, keyState); + const macro_t *m = macroAction(mappedKey.rawKey, keyState); + + Macros.play(m); return true; } diff --git a/libraries/Keyboardio-Macros/src/Keyboardio-Macros.h b/libraries/Keyboardio-Macros/src/Keyboardio-Macros.h index df209872..6717ee4e 100644 --- a/libraries/Keyboardio-Macros/src/Keyboardio-Macros.h +++ b/libraries/Keyboardio-Macros/src/Keyboardio-Macros.h @@ -2,25 +2,16 @@ #include -#define IS_MACRO B00000001 +#include "MacroKeyDefs.h" +#include "MacroSteps.h" -#define M(n) (Key){ KEY_FLAGS|SYNTHETIC|IS_MACRO, n} -#define Key_macroKey1 M(1) -#define Key_macroKey2 M(2) -#define Key_macroKey3 M(3) -#define Key_macroKey4 M(4) -#define Key_macroKey5 M(5) -#define Key_macroKey6 M(6) -#define Key_macroKey7 M(7) -#define Key_macroKey8 M(8) -#define Key_macroKey9 M(9) -#define Key_macroKey10 M(10) - -void macroAction(uint8_t macroIndex, uint8_t keyState); +const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState); class Macros_ { public: Macros_(void); + + void play(const macro_t *macro_p); }; extern Macros_ Macros; diff --git a/libraries/Keyboardio-Macros/src/MacroKeyDefs.h b/libraries/Keyboardio-Macros/src/MacroKeyDefs.h new file mode 100644 index 00000000..9efa9481 --- /dev/null +++ b/libraries/Keyboardio-Macros/src/MacroKeyDefs.h @@ -0,0 +1,15 @@ +#pragma once + +#define IS_MACRO B00000001 + +#define M(n) (Key){ KEY_FLAGS|SYNTHETIC|IS_MACRO, n} +#define Key_macroKey1 M(1) +#define Key_macroKey2 M(2) +#define Key_macroKey3 M(3) +#define Key_macroKey4 M(4) +#define Key_macroKey5 M(5) +#define Key_macroKey6 M(6) +#define Key_macroKey7 M(7) +#define Key_macroKey8 M(8) +#define Key_macroKey9 M(9) +#define Key_macroKey10 M(10) diff --git a/libraries/Keyboardio-Macros/src/MacroSteps.h b/libraries/Keyboardio-Macros/src/MacroSteps.h new file mode 100644 index 00000000..c2107c7d --- /dev/null +++ b/libraries/Keyboardio-Macros/src/MacroSteps.h @@ -0,0 +1,22 @@ +#pragma once + +typedef enum { + MACRO_ACTION_END, + + MACRO_ACTION_STEP_INTERVAL, + MACRO_ACTION_STEP_WAIT, + MACRO_ACTION_STEP_KEYDOWN, + MACRO_ACTION_STEP_KEYUP, +} MacroActionStepType; + +typedef uint8_t macro_t; + +#define MACRO_NONE 0 +#define MACRO(...) ({static const macro_t __m[] PROGMEM = { __VA_ARGS__ }; &__m[0]; }) + +#define I(n) MACRO_ACTION_STEP_INTERVAL, n +#define W(n) MACRO_ACTION_STEP_WAIT, n +#define D(k) MACRO_ACTION_STEP_KEYDOWN, (Key_ ## k).raw +#define U(k) MACRO_ACTION_STEP_KEYUP, (Key_ ## k).raw +#define T(k) D(k), U(k) +#define END MACRO_ACTION_END