Macros: Make it possible to read macros from sources other than PROGMEM

Instead of the `Macros` plugin reading from progmem unconditionally, allow one
to override a function (similar to how we can override `Layer.getKey()`), and
use that function to read macro data.

This allows `DynamicMacros` to re-use most of `Macros`, and not reimplement all
of it. The only remaining duplication is `updateDynamicMacroCache()`, which
walks the storage to build a macro index->offset map, and as such, needs to be
able to parse macros.

Signed-off-by: Gergely Nagy <algernon@keyboard.io>
pull/1094/head
Gergely Nagy 3 years ago
parent d6b7d7d4c8
commit 46038df07e
No known key found for this signature in database
GPG Key ID: AC1E90BAC433F68F

@ -25,33 +25,6 @@ namespace plugin {
uint16_t DynamicMacros::storage_base_; uint16_t DynamicMacros::storage_base_;
uint16_t DynamicMacros::storage_size_; uint16_t DynamicMacros::storage_size_;
uint16_t DynamicMacros::map_[]; uint16_t DynamicMacros::map_[];
Key DynamicMacros::active_macro_keys_[];
// =============================================================================
// It might be possible to use Macros instead of reproducing it
void DynamicMacros::press(Key key) {
Runtime.handleKeyEvent(KeyEvent(KeyAddr::none(), IS_PRESSED | INJECTED, key));
for (Key &mkey : active_macro_keys_) {
if (mkey == Key_NoKey) {
mkey = key;
break;
}
}
}
void DynamicMacros::release(Key key) {
for (Key &mkey : active_macro_keys_) {
if (mkey == key) {
mkey = Key_NoKey;
}
}
Runtime.handleKeyEvent(KeyEvent(KeyAddr::none(), WAS_PRESSED | INJECTED, key));
}
void DynamicMacros::tap(Key key) {
Runtime.handleKeyEvent(KeyEvent(KeyAddr::none(), IS_PRESSED | INJECTED, key));
Runtime.handleKeyEvent(KeyEvent(KeyAddr::none(), WAS_PRESSED | INJECTED, key));
}
void DynamicMacros::updateDynamicMacroCache() { void DynamicMacros::updateDynamicMacroCache() {
uint16_t pos = storage_base_; uint16_t pos = storage_base_;
@ -118,92 +91,29 @@ void DynamicMacros::updateDynamicMacroCache() {
} }
// public // public
void DynamicMacros::play(uint8_t macro_id) { void DynamicMacros::setup(uint16_t storage_size) {
macro_t macro = MACRO_ACTION_END; Macros::readMacroByte = &DynamicMacros::readMacroByte;
uint8_t interval = 0;
uint16_t pos;
Key key;
pos = storage_base_ + map_[macro_id];
while (true) { reserve_storage(storage_size);
switch (macro = Runtime.storage().read(pos++)) { }
case MACRO_ACTION_STEP_EXPLICIT_REPORT:
case MACRO_ACTION_STEP_IMPLICIT_REPORT:
case MACRO_ACTION_STEP_SEND_REPORT:
break;
case MACRO_ACTION_STEP_INTERVAL:
interval = Runtime.storage().read(pos++);
break;
case MACRO_ACTION_STEP_WAIT: {
uint8_t wait = Runtime.storage().read(pos++);
delay(wait);
break;
}
case MACRO_ACTION_STEP_KEYDOWN:
key.setFlags(Runtime.storage().read(pos++));
key.setKeyCode(Runtime.storage().read(pos++));
press(key);
break;
case MACRO_ACTION_STEP_KEYUP:
key.setFlags(Runtime.storage().read(pos++));
key.setKeyCode(Runtime.storage().read(pos++));
release(key);
break;
case MACRO_ACTION_STEP_TAP:
key.setFlags(Runtime.storage().read(pos++));
key.setKeyCode(Runtime.storage().read(pos++));
tap(key);
break;
case MACRO_ACTION_STEP_KEYCODEDOWN: uint8_t DynamicMacros::readMacroByteFromEEPROM(const macro_t *ptr, uint8_t source) {
key.setFlags(0); int idx = (int)*(ptr++);
key.setKeyCode(Runtime.storage().read(pos++)); return Runtime.storage().read(idx);
press(key); }
break;
case MACRO_ACTION_STEP_KEYCODEUP:
key.setFlags(0);
key.setKeyCode(Runtime.storage().read(pos++));
release(key);
break;
case MACRO_ACTION_STEP_TAPCODE:
key.setFlags(0);
key.setKeyCode(Runtime.storage().read(pos++));
tap(key);
break;
case MACRO_ACTION_STEP_TAP_SEQUENCE: { uint8_t DynamicMacros::readMacroByte(const macro_t *ptr, uint8_t source) {
while (true) { if (source == MACRO_SOURCE_PROGMEM) {
key.setFlags(0); return Macros::readMacroByteFromPROGMEM(ptr, source);
key.setKeyCode(pgm_read_byte(pos++)); } else {
if (key == Key_NoKey) return readMacroByteFromEEPROM(ptr, source);
break;
tap(key);
delay(interval);
}
break;
}
case MACRO_ACTION_STEP_TAP_CODE_SEQUENCE: {
while (true) {
key.setFlags(0);
key.setKeyCode(pgm_read_byte(pos++));
if (key.getKeyCode() == 0)
break;
tap(key);
delay(interval);
}
break;
} }
}
case MACRO_ACTION_END: void DynamicMacros::play(uint8_t macro_id) {
default: uint16_t pos = storage_base_ + map_[macro_id];
return;
}
delay(interval); ::Macros.play((const macro_t *)&pos, MACRO_SOURCE_EEPROM);
}
} }
bool isDynamicMacrosKey(Key key) { bool isDynamicMacrosKey(Key key) {
@ -220,9 +130,7 @@ EventHandlerResult DynamicMacros::onKeyEvent(KeyEvent &event) {
uint8_t macro_id = event.key.getRaw() - ranges::DYNAMIC_MACRO_FIRST; uint8_t macro_id = event.key.getRaw() - ranges::DYNAMIC_MACRO_FIRST;
play(macro_id); play(macro_id);
} else { } else {
for (Key key : active_macro_keys_) { ::Macros.release(event.key);
release(key);
}
} }
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;

@ -18,13 +18,11 @@
#include "kaleidoscope/Runtime.h" #include "kaleidoscope/Runtime.h"
#include <Kaleidoscope-EEPROM-Settings.h> #include <Kaleidoscope-EEPROM-Settings.h>
#include <Kaleidoscope-Macros.h>
#include <Kaleidoscope-Ranges.h> #include <Kaleidoscope-Ranges.h>
#include "kaleidoscope/plugin/Macros/MacroSteps.h"
#define DM(n) Key(kaleidoscope::ranges::DYNAMIC_MACRO_FIRST + n) #define DM(n) Key(kaleidoscope::ranges::DYNAMIC_MACRO_FIRST + n)
#define MACRO_SOURCE_EEPROM 1
#define MAX_CONCURRENT_DYNAMIC_MACRO_KEYS 8
namespace kaleidoscope { namespace kaleidoscope {
namespace plugin { namespace plugin {
@ -36,18 +34,18 @@ class DynamicMacros : public kaleidoscope::Plugin {
EventHandlerResult onFocusEvent(const char *command); EventHandlerResult onFocusEvent(const char *command);
static void reserve_storage(uint16_t size); static void reserve_storage(uint16_t size);
static void setup(uint16_t storage_size);
void play(uint8_t seq_id); void play(uint8_t seq_id);
static uint8_t readMacroByteFromEEPROM(const macro_t *ptr, uint8_t source);
static uint8_t readMacroByte(const macro_t *ptr, uint8_t source);
private: private:
static uint16_t storage_base_; static uint16_t storage_base_;
static uint16_t storage_size_; static uint16_t storage_size_;
static uint16_t map_[31]; static uint16_t map_[31];
static void updateDynamicMacroCache(); static void updateDynamicMacroCache();
static Key active_macro_keys_[MAX_CONCURRENT_DYNAMIC_MACRO_KEYS];
static void press(Key key);
static void release(Key key);
static void tap(Key key);
}; };
} // namespace plugin } // namespace plugin

@ -52,6 +52,7 @@ constexpr uint8_t release_state = WAS_PRESSED | INJECTED;
// Initialized to zeroes (i.e. `Key_NoKey`) // Initialized to zeroes (i.e. `Key_NoKey`)
Key Macros::active_macro_keys_[]; Key Macros::active_macro_keys_[];
Macros::readMacroByteFunction Macros::readMacroByte = &Macros::readMacroByteFromPROGMEM;
#ifndef NDEPRECATED #ifndef NDEPRECATED
#pragma GCC diagnostic push #pragma GCC diagnostic push
@ -106,7 +107,7 @@ void Macros::tap(Key key) const {
Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), release_state, key}); Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), release_state, key});
} }
void Macros::play(const macro_t *macro_p) { void Macros::play(const macro_t *macro_p, uint8_t source) {
macro_t macro = MACRO_ACTION_END; macro_t macro = MACRO_ACTION_END;
uint8_t interval = 0; uint8_t interval = 0;
Key key; Key key;
@ -115,7 +116,7 @@ void Macros::play(const macro_t *macro_p) {
return; return;
while (true) { while (true) {
switch (macro = pgm_read_byte(macro_p++)) { switch (macro = readMacroByte(macro_p, source)) {
// These are unlikely to be useful now that we have KeyEvent. I think the // These are unlikely to be useful now that we have KeyEvent. I think the
// whole `explicit_report` came about as a result of scan-order bugs. // whole `explicit_report` came about as a result of scan-order bugs.
case MACRO_ACTION_STEP_EXPLICIT_REPORT: case MACRO_ACTION_STEP_EXPLICIT_REPORT:
@ -126,50 +127,50 @@ void Macros::play(const macro_t *macro_p) {
// Timing // Timing
case MACRO_ACTION_STEP_INTERVAL: case MACRO_ACTION_STEP_INTERVAL:
interval = pgm_read_byte(macro_p++); interval = readMacroByte(macro_p, source);
break; break;
case MACRO_ACTION_STEP_WAIT: { case MACRO_ACTION_STEP_WAIT: {
uint8_t wait = pgm_read_byte(macro_p++); uint8_t wait = readMacroByte(macro_p, source);
delay(wait); delay(wait);
break; break;
} }
case MACRO_ACTION_STEP_KEYDOWN: case MACRO_ACTION_STEP_KEYDOWN:
key.setFlags(pgm_read_byte(macro_p++)); key.setFlags(readMacroByte(macro_p, source));
key.setKeyCode(pgm_read_byte(macro_p++)); key.setKeyCode(readMacroByte(macro_p, source));
press(key); press(key);
break; break;
case MACRO_ACTION_STEP_KEYUP: case MACRO_ACTION_STEP_KEYUP:
key.setFlags(pgm_read_byte(macro_p++)); key.setFlags(readMacroByte(macro_p, source));
key.setKeyCode(pgm_read_byte(macro_p++)); key.setKeyCode(readMacroByte(macro_p, source));
release(key); release(key);
break; break;
case MACRO_ACTION_STEP_TAP: case MACRO_ACTION_STEP_TAP:
key.setFlags(pgm_read_byte(macro_p++)); key.setFlags(readMacroByte(macro_p, source));
key.setKeyCode(pgm_read_byte(macro_p++)); key.setKeyCode(readMacroByte(macro_p, source));
tap(key); tap(key);
break; break;
case MACRO_ACTION_STEP_KEYCODEDOWN: case MACRO_ACTION_STEP_KEYCODEDOWN:
key.setFlags(0); key.setFlags(0);
key.setKeyCode(pgm_read_byte(macro_p++)); key.setKeyCode(readMacroByte(macro_p, source));
press(key); press(key);
break; break;
case MACRO_ACTION_STEP_KEYCODEUP: case MACRO_ACTION_STEP_KEYCODEUP:
key.setFlags(0); key.setFlags(0);
key.setKeyCode(pgm_read_byte(macro_p++)); key.setKeyCode(readMacroByte(macro_p, source));
release(key); release(key);
break; break;
case MACRO_ACTION_STEP_TAPCODE: case MACRO_ACTION_STEP_TAPCODE:
key.setFlags(0); key.setFlags(0);
key.setKeyCode(pgm_read_byte(macro_p++)); key.setKeyCode(readMacroByte(macro_p, source));
tap(key); tap(key);
break; break;
case MACRO_ACTION_STEP_TAP_SEQUENCE: { case MACRO_ACTION_STEP_TAP_SEQUENCE: {
while (true) { while (true) {
key.setFlags(0); key.setFlags(0);
key.setKeyCode(pgm_read_byte(macro_p++)); key.setKeyCode(readMacroByte(macro_p, source));
if (key == Key_NoKey) if (key == Key_NoKey)
break; break;
tap(key); tap(key);
@ -180,7 +181,7 @@ void Macros::play(const macro_t *macro_p) {
case MACRO_ACTION_STEP_TAP_CODE_SEQUENCE: { case MACRO_ACTION_STEP_TAP_CODE_SEQUENCE: {
while (true) { while (true) {
key.setFlags(0); key.setFlags(0);
key.setKeyCode(pgm_read_byte(macro_p++)); key.setKeyCode(readMacroByte(macro_p, source));
if (key.getKeyCode() == 0) if (key.getKeyCode() == 0)
break; break;
tap(key); tap(key);

@ -92,6 +92,8 @@ struct MacroKeyEvent {
#define MAX_CONCURRENT_MACRO_KEYS 8 #define MAX_CONCURRENT_MACRO_KEYS 8
#endif #endif
#define MACRO_SOURCE_PROGMEM 0
namespace kaleidoscope { namespace kaleidoscope {
namespace plugin { namespace plugin {
@ -126,7 +128,14 @@ class Macros : public kaleidoscope::Plugin {
void tap(Key key) const; void tap(Key key) const;
/// Play a macro sequence of key events /// Play a macro sequence of key events
void play(const macro_t* macro_ptr); void play(const macro_t* macro_ptr, uint8_t source = MACRO_SOURCE_PROGMEM);
typedef uint8_t (*readMacroByteFunction)(const macro_t *ptr, uint8_t source);
static readMacroByteFunction readMacroByte;
static uint8_t readMacroByteFromPROGMEM(const macro_t *ptr, uint8_t source) {
return pgm_read_byte(ptr++);
}
// Templates provide a `type()` function that takes a variable number of // Templates provide a `type()` function that takes a variable number of
// `char*` (string) arguments, in the form of a list of strings stored in // `char*` (string) arguments, in the form of a list of strings stored in

Loading…
Cancel
Save