#pragma once
#pragma message "Dynamic Macros is now a core feature. See updated documentation to see how to configure it: https:
#include "action_layer.h"
#ifndef DYNAMIC_MACRO_SIZE
# define DYNAMIC_MACRO_SIZE 128
#endif
void dynamic_macro_led_blink(void) {
#ifdef BACKLIGHT_ENABLE
backlight_toggle();
wait_ms(100);
backlight_toggle();
#endif
}
#define DYNAMIC_MACRO_CURRENT_SLOT() (direction > 0 ? 1 : 2)
#define DYNAMIC_MACRO_CURRENT_LENGTH(BEGIN, POINTER) ((int)(direction * ((POINTER) - (BEGIN))))
#define DYNAMIC_MACRO_CURRENT_CAPACITY(BEGIN, END2) ((int)(direction * ((END2) - (BEGIN)) + 1))
void dynamic_macro_record_start(keyrecord_t **macro_pointer, keyrecord_t *macro_buffer) {
dprintln("dynamic macro recording: started");
dynamic_macro_led_blink();
clear_keyboard();
layer_clear();
*macro_pointer = macro_buffer;
}
void dynamic_macro_play(keyrecord_t *macro_buffer, keyrecord_t *macro_end, int8_t direction) {
dprintf("dynamic macro: slot %d playback\n", DYNAMIC_MACRO_CURRENT_SLOT());
uint32_t saved_layer_state = layer_state;
clear_keyboard();
layer_clear();
while (macro_buffer != macro_end) {
process_record(macro_buffer);
macro_buffer += direction;
}
clear_keyboard();
layer_state = saved_layer_state;
}
void dynamic_macro_record_key(keyrecord_t *macro_buffer, keyrecord_t **macro_pointer, keyrecord_t *macro2_end, int8_t direction, keyrecord_t *record) {
if (!record->event.pressed && *macro_pointer == macro_buffer) {
dprintln("dynamic macro: ignoring a leading key-up event");
return;
}
if (*macro_pointer - direction != macro2_end) {
**macro_pointer = *record;
*macro_pointer += direction;
} else {
dynamic_macro_led_blink();
}
dprintf("dynamic macro: slot %d length: %d/%d\n", DYNAMIC_MACRO_CURRENT_SLOT(), DYNAMIC_MACRO_CURRENT_LENGTH(macro_buffer, *macro_pointer), DYNAMIC_MACRO_CURRENT_CAPACITY(macro_buffer, macro2_end));
}
void dynamic_macro_record_end(keyrecord_t *macro_buffer, keyrecord_t *macro_pointer, int8_t direction, keyrecord_t **macro_end) {
dynamic_macro_led_blink();
while (macro_pointer != macro_buffer && (macro_pointer - direction)->event.pressed) {
dprintln("dynamic macro: trimming a trailing key-down event");
macro_pointer -= direction;
}
dprintf("dynamic macro: slot %d saved, length: %d\n", DYNAMIC_MACRO_CURRENT_SLOT(), DYNAMIC_MACRO_CURRENT_LENGTH(macro_buffer, macro_pointer));
*macro_end = macro_pointer;
}
bool process_record_dynamic_macro(uint16_t keycode, keyrecord_t *record) {
static keyrecord_t macro_buffer[DYNAMIC_MACRO_SIZE];
static keyrecord_t *macro_end = macro_buffer;
static keyrecord_t *const r_macro_buffer = macro_buffer + DYNAMIC_MACRO_SIZE - 1;
static keyrecord_t *r_macro_end = r_macro_buffer;
static keyrecord_t *macro_pointer = NULL;
static uint8_t macro_id = 0;
if (macro_id == 0) {
if (!record->event.pressed) {
switch (keycode) {
case DYN_REC_START1:
dynamic_macro_record_start(¯o_pointer, macro_buffer);
macro_id = 1;
return false;
case DYN_REC_START2:
dynamic_macro_record_start(¯o_pointer, r_macro_buffer);
macro_id = 2;
return false;
case DYN_MACRO_PLAY1:
dynamic_macro_play(macro_buffer, macro_end, +1);
return false;
case DYN_MACRO_PLAY2:
dynamic_macro_play(r_macro_buffer, r_macro_end, -1);
return false;
}
}
} else {
switch (keycode) {
case DYN_REC_STOP:
if (record->event.pressed) {
switch (macro_id) {
case 1:
dynamic_macro_record_end(macro_buffer, macro_pointer, +1, ¯o_end);
break;
case 2:
dynamic_macro_record_end(r_macro_buffer, macro_pointer, -1, &r_macro_end);
break;
}
macro_id = 0;
}
return false;
case DYN_MACRO_PLAY1:
case DYN_MACRO_PLAY2:
dprintln("dynamic macro: ignoring macro play key while recording");
return false;
default:
switch (macro_id) {
case 1:
dynamic_macro_record_key(macro_buffer, ¯o_pointer, r_macro_end, +1, record);
break;
case 2:
dynamic_macro_record_key(r_macro_buffer, ¯o_pointer, macro_end, -1, record);
break;
}
return true;
break;
}
}
return true;
}
#undef DYNAMIC_MACRO_CURRENT_SLOT
#undef DYNAMIC_MACRO_CURRENT_LENGTH
#undef DYNAMIC_MACRO_CURRENT_CAPACITY