diff options
Diffstat (limited to 'quantum/dynamic_macro.h')
| -rw-r--r-- | quantum/dynamic_macro.h | 82 |
1 files changed, 67 insertions, 15 deletions
diff --git a/quantum/dynamic_macro.h b/quantum/dynamic_macro.h index 64093f293..f242405de 100644 --- a/quantum/dynamic_macro.h +++ b/quantum/dynamic_macro.h | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | enum dynamic_macro_keycodes { | 40 | enum dynamic_macro_keycodes { |
| 41 | DYN_REC_START1 = DYNAMIC_MACRO_RANGE, | 41 | DYN_REC_START1 = DYNAMIC_MACRO_RANGE, |
| 42 | DYN_REC_START2, | 42 | DYN_REC_START2, |
| 43 | DYN_REC_STOP, | ||
| 43 | DYN_MACRO_PLAY1, | 44 | DYN_MACRO_PLAY1, |
| 44 | DYN_MACRO_PLAY2, | 45 | DYN_MACRO_PLAY2, |
| 45 | }; | 46 | }; |
| @@ -47,11 +48,22 @@ enum dynamic_macro_keycodes { | |||
| 47 | /* Blink the LEDs to notify the user about some event. */ | 48 | /* Blink the LEDs to notify the user about some event. */ |
| 48 | void dynamic_macro_led_blink(void) | 49 | void dynamic_macro_led_blink(void) |
| 49 | { | 50 | { |
| 51 | #ifdef BACKLIGHT_ENABLE | ||
| 50 | backlight_toggle(); | 52 | backlight_toggle(); |
| 51 | _delay_ms(100); | 53 | _delay_ms(100); |
| 52 | backlight_toggle(); | 54 | backlight_toggle(); |
| 55 | #endif | ||
| 53 | } | 56 | } |
| 54 | 57 | ||
| 58 | /* Convenience macros used for retrieving the debug info. All of them | ||
| 59 | * need a `direction` variable accessible at the call site. | ||
| 60 | */ | ||
| 61 | #define DYNAMIC_MACRO_CURRENT_SLOT() (direction > 0 ? 1 : 2) | ||
| 62 | #define DYNAMIC_MACRO_CURRENT_LENGTH(BEGIN, POINTER) \ | ||
| 63 | ((int)(direction * ((POINTER) - (BEGIN)))) | ||
| 64 | #define DYNAMIC_MACRO_CURRENT_CAPACITY(BEGIN, END2) \ | ||
| 65 | ((int)(direction * ((END2) - (BEGIN)) + 1)) | ||
| 66 | |||
| 55 | /** | 67 | /** |
| 56 | * Start recording of the dynamic macro. | 68 | * Start recording of the dynamic macro. |
| 57 | * | 69 | * |
| @@ -61,6 +73,8 @@ void dynamic_macro_led_blink(void) | |||
| 61 | void dynamic_macro_record_start( | 73 | void dynamic_macro_record_start( |
| 62 | keyrecord_t **macro_pointer, keyrecord_t *macro_buffer) | 74 | keyrecord_t **macro_pointer, keyrecord_t *macro_buffer) |
| 63 | { | 75 | { |
| 76 | dprintln("dynamic macro recording: started"); | ||
| 77 | |||
| 64 | dynamic_macro_led_blink(); | 78 | dynamic_macro_led_blink(); |
| 65 | 79 | ||
| 66 | clear_keyboard(); | 80 | clear_keyboard(); |
| @@ -78,6 +92,8 @@ void dynamic_macro_record_start( | |||
| 78 | void dynamic_macro_play( | 92 | void dynamic_macro_play( |
| 79 | keyrecord_t *macro_buffer, keyrecord_t *macro_end, int8_t direction) | 93 | keyrecord_t *macro_buffer, keyrecord_t *macro_end, int8_t direction) |
| 80 | { | 94 | { |
| 95 | dprintf("dynamic macro: slot %d playback\n", DYNAMIC_MACRO_CURRENT_SLOT()); | ||
| 96 | |||
| 81 | uint32_t saved_layer_state = layer_state; | 97 | uint32_t saved_layer_state = layer_state; |
| 82 | 98 | ||
| 83 | clear_keyboard(); | 99 | clear_keyboard(); |
| @@ -96,35 +112,68 @@ void dynamic_macro_play( | |||
| 96 | /** | 112 | /** |
| 97 | * Record a single key in a dynamic macro. | 113 | * Record a single key in a dynamic macro. |
| 98 | * | 114 | * |
| 115 | * @param macro_buffer[in] The start of the used macro buffer. | ||
| 99 | * @param macro_pointer[in,out] The current buffer position. | 116 | * @param macro_pointer[in,out] The current buffer position. |
| 100 | * @param macro_end2[in] The end of the other macro which shouldn't be overwritten. | 117 | * @param macro2_end[in] The end of the other macro. |
| 101 | * @param direction[in] Either +1 or -1, which way to iterate the buffer. | 118 | * @param direction[in] Either +1 or -1, which way to iterate the buffer. |
| 102 | * @param record[in] The current keypress. | 119 | * @param record[in] The current keypress. |
| 103 | */ | 120 | */ |
| 104 | void dynamic_macro_record_key( | 121 | void dynamic_macro_record_key( |
| 122 | keyrecord_t *macro_buffer, | ||
| 105 | keyrecord_t **macro_pointer, | 123 | keyrecord_t **macro_pointer, |
| 106 | keyrecord_t *macro_end2, | 124 | keyrecord_t *macro2_end, |
| 107 | int8_t direction, | 125 | int8_t direction, |
| 108 | keyrecord_t *record) | 126 | keyrecord_t *record) |
| 109 | { | 127 | { |
| 110 | if (*macro_pointer + direction != macro_end2) { | 128 | /* If we've just started recording, ignore all the key releases. */ |
| 129 | if (!record->event.pressed && *macro_pointer == macro_buffer) { | ||
| 130 | dprintln("dynamic macro: ignoring a leading key-up event"); | ||
| 131 | return; | ||
| 132 | } | ||
| 133 | |||
| 134 | /* The other end of the other macro is the last buffer element it | ||
| 135 | * is safe to use before overwriting the other macro. | ||
| 136 | */ | ||
| 137 | if (*macro_pointer - direction != macro2_end) { | ||
| 111 | **macro_pointer = *record; | 138 | **macro_pointer = *record; |
| 112 | *macro_pointer += direction; | 139 | *macro_pointer += direction; |
| 113 | } else { | 140 | } else { |
| 114 | /* Notify about the end of buffer. The blinks are paired | 141 | dynamic_macro_led_blink(); |
| 115 | * because they should happen on both down and up events. */ | ||
| 116 | backlight_toggle(); | ||
| 117 | } | 142 | } |
| 143 | |||
| 144 | dprintf( | ||
| 145 | "dynamic macro: slot %d length: %d/%d\n", | ||
| 146 | DYNAMIC_MACRO_CURRENT_SLOT(), | ||
| 147 | DYNAMIC_MACRO_CURRENT_LENGTH(macro_buffer, *macro_pointer), | ||
| 148 | DYNAMIC_MACRO_CURRENT_CAPACITY(macro_buffer, macro2_end)); | ||
| 118 | } | 149 | } |
| 119 | 150 | ||
| 120 | /** | 151 | /** |
| 121 | * End recording of the dynamic macro. Essentially just update the | 152 | * End recording of the dynamic macro. Essentially just update the |
| 122 | * pointer to the end of the macro. | 153 | * pointer to the end of the macro. |
| 123 | */ | 154 | */ |
| 124 | void dynamic_macro_record_end(keyrecord_t *macro_pointer, keyrecord_t **macro_end) | 155 | void dynamic_macro_record_end( |
| 156 | keyrecord_t *macro_buffer, | ||
| 157 | keyrecord_t *macro_pointer, | ||
| 158 | int8_t direction, | ||
| 159 | keyrecord_t **macro_end) | ||
| 125 | { | 160 | { |
| 126 | dynamic_macro_led_blink(); | 161 | dynamic_macro_led_blink(); |
| 127 | 162 | ||
| 163 | /* Do not save the keys being held when stopping the recording, | ||
| 164 | * i.e. the keys used to access the layer DYN_REC_STOP is on. | ||
| 165 | */ | ||
| 166 | while (macro_pointer != macro_buffer && | ||
| 167 | (macro_pointer - direction)->event.pressed) { | ||
| 168 | dprintln("dynamic macro: trimming a trailing key-down event"); | ||
| 169 | macro_pointer -= direction; | ||
| 170 | } | ||
| 171 | |||
| 172 | dprintf( | ||
| 173 | "dynamic macro: slot %d saved, length: %d\n", | ||
| 174 | DYNAMIC_MACRO_CURRENT_SLOT(), | ||
| 175 | DYNAMIC_MACRO_CURRENT_LENGTH(macro_buffer, macro_pointer)); | ||
| 176 | |||
| 128 | *macro_end = macro_pointer; | 177 | *macro_end = macro_pointer; |
| 129 | } | 178 | } |
| 130 | 179 | ||
| @@ -152,7 +201,7 @@ bool process_record_dynamic_macro(uint16_t keycode, keyrecord_t *record) | |||
| 152 | * ¯o_buffer macro_end | 201 | * ¯o_buffer macro_end |
| 153 | * v v | 202 | * v v |
| 154 | * +------------------------------------------------------------+ | 203 | * +------------------------------------------------------------+ |
| 155 | * |>>>>>> MACRO1 >>>>>>| |<<<<<<<<<<<<< MACRO2 <<<<<<<<<<<<<| | 204 | * |>>>>>> MACRO1 >>>>>> <<<<<<<<<<<<< MACRO2 <<<<<<<<<<<<<| |
| 156 | * +------------------------------------------------------------+ | 205 | * +------------------------------------------------------------+ |
| 157 | * ^ ^ | 206 | * ^ ^ |
| 158 | * r_macro_end r_macro_buffer | 207 | * r_macro_end r_macro_buffer |
| @@ -209,18 +258,17 @@ bool process_record_dynamic_macro(uint16_t keycode, keyrecord_t *record) | |||
| 209 | } else { | 258 | } else { |
| 210 | /* A macro is being recorded right now. */ | 259 | /* A macro is being recorded right now. */ |
| 211 | switch (keycode) { | 260 | switch (keycode) { |
| 212 | case MO(_DYN): | 261 | case DYN_REC_STOP: |
| 213 | /* Use the layer key used to access the macro recording as | 262 | /* Stop the macro recording. */ |
| 214 | * a stop button. */ | ||
| 215 | if (record->event.pressed) { /* Ignore the initial release | 263 | if (record->event.pressed) { /* Ignore the initial release |
| 216 | * just after the recoding | 264 | * just after the recoding |
| 217 | * starts. */ | 265 | * starts. */ |
| 218 | switch (macro_id) { | 266 | switch (macro_id) { |
| 219 | case 1: | 267 | case 1: |
| 220 | dynamic_macro_record_end(macro_pointer, ¯o_end); | 268 | dynamic_macro_record_end(macro_buffer, macro_pointer, +1, ¯o_end); |
| 221 | break; | 269 | break; |
| 222 | case 2: | 270 | case 2: |
| 223 | dynamic_macro_record_end(macro_pointer, &r_macro_end); | 271 | dynamic_macro_record_end(r_macro_buffer, macro_pointer, -1, &r_macro_end); |
| 224 | break; | 272 | break; |
| 225 | } | 273 | } |
| 226 | macro_id = 0; | 274 | macro_id = 0; |
| @@ -230,10 +278,10 @@ bool process_record_dynamic_macro(uint16_t keycode, keyrecord_t *record) | |||
| 230 | /* Store the key in the macro buffer and process it normally. */ | 278 | /* Store the key in the macro buffer and process it normally. */ |
| 231 | switch (macro_id) { | 279 | switch (macro_id) { |
| 232 | case 1: | 280 | case 1: |
| 233 | dynamic_macro_record_key(¯o_pointer, r_macro_end, +1, record); | 281 | dynamic_macro_record_key(macro_buffer, ¯o_pointer, r_macro_end, +1, record); |
| 234 | break; | 282 | break; |
| 235 | case 2: | 283 | case 2: |
| 236 | dynamic_macro_record_key(¯o_pointer, macro_end, -1, record); | 284 | dynamic_macro_record_key(r_macro_buffer, ¯o_pointer, macro_end, -1, record); |
| 237 | break; | 285 | break; |
| 238 | } | 286 | } |
| 239 | return true; | 287 | return true; |
| @@ -244,4 +292,8 @@ bool process_record_dynamic_macro(uint16_t keycode, keyrecord_t *record) | |||
| 244 | return true; | 292 | return true; |
| 245 | } | 293 | } |
| 246 | 294 | ||
| 295 | #undef DYNAMIC_MACRO_CURRENT_SLOT | ||
| 296 | #undef DYNAMIC_MACRO_CURRENT_LENGTH | ||
| 297 | #undef DYNAMIC_MACRO_CURRENT_CAPACITY | ||
| 298 | |||
| 247 | #endif | 299 | #endif |
