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_size_;
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() {
uint16_t pos = storage_base_;
@ -118,92 +91,29 @@ void DynamicMacros::updateDynamicMacroCache() {
}
// public
void DynamicMacros::play(uint8_t macro_id) {
macro_t macro = MACRO_ACTION_END;
uint8_t interval = 0;
uint16_t pos;
Key key;
pos = storage_base_ + map_[macro_id];
void DynamicMacros::setup(uint16_t storage_size) {
Macros::readMacroByte = &DynamicMacros::readMacroByte;
while (true) {
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;
reserve_storage(storage_size);
}
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:
key.setFlags(0);
key.setKeyCode(Runtime.storage().read(pos++));
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: {
while (true) {
key.setFlags(0);
key.setKeyCode(pgm_read_byte(pos++));
if (key == Key_NoKey)
break;
tap(key);
delay(interval);
uint8_t DynamicMacros::readMacroByteFromEEPROM(const macro_t *ptr, uint8_t source) {
int idx = (int)*(ptr++);
return Runtime.storage().read(idx);
}
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);
uint8_t DynamicMacros::readMacroByte(const macro_t *ptr, uint8_t source) {
if (source == MACRO_SOURCE_PROGMEM) {
return Macros::readMacroByteFromPROGMEM(ptr, source);
} else {
return readMacroByteFromEEPROM(ptr, source);
}
break;
}
case MACRO_ACTION_END:
default:
return;
}
void DynamicMacros::play(uint8_t macro_id) {
uint16_t pos = storage_base_ + map_[macro_id];
delay(interval);
}
::Macros.play((const macro_t *)&pos, MACRO_SOURCE_EEPROM);
}
bool isDynamicMacrosKey(Key key) {
@ -220,9 +130,7 @@ EventHandlerResult DynamicMacros::onKeyEvent(KeyEvent &event) {
uint8_t macro_id = event.key.getRaw() - ranges::DYNAMIC_MACRO_FIRST;
play(macro_id);
} else {
for (Key key : active_macro_keys_) {
release(key);
}
::Macros.release(event.key);
}
return EventHandlerResult::EVENT_CONSUMED;

@ -18,13 +18,11 @@
#include "kaleidoscope/Runtime.h"
#include <Kaleidoscope-EEPROM-Settings.h>
#include <Kaleidoscope-Macros.h>
#include <Kaleidoscope-Ranges.h>
#include "kaleidoscope/plugin/Macros/MacroSteps.h"
#define DM(n) Key(kaleidoscope::ranges::DYNAMIC_MACRO_FIRST + n)
#define MAX_CONCURRENT_DYNAMIC_MACRO_KEYS 8
#define MACRO_SOURCE_EEPROM 1
namespace kaleidoscope {
namespace plugin {
@ -36,18 +34,18 @@ class DynamicMacros : public kaleidoscope::Plugin {
EventHandlerResult onFocusEvent(const char *command);
static void reserve_storage(uint16_t size);
static void setup(uint16_t storage_size);
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:
static uint16_t storage_base_;
static uint16_t storage_size_;
static uint16_t map_[31];
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

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

@ -92,6 +92,8 @@ struct MacroKeyEvent {
#define MAX_CONCURRENT_MACRO_KEYS 8
#endif
#define MACRO_SOURCE_PROGMEM 0
namespace kaleidoscope {
namespace plugin {
@ -126,7 +128,14 @@ class Macros : public kaleidoscope::Plugin {
void tap(Key key) const;
/// 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
// `char*` (string) arguments, in the form of a list of strings stored in

Loading…
Cancel
Save