process_dynamic_macro.c
11241 bytes
1/* Copyright 2016 Jack Humbert
2 * Copyright 2019 Drashna Jael're (@drashna, aka Christopher Courtney)
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/* Author: Wojciech Siewierski < wojciech dot siewierski at onet dot pl > */
19#include "process_dynamic_macro.h"
20#include <stddef.h>
21#include "action_layer.h"
22#include "keycodes.h"
23#include "debug.h"
24#include "wait.h"
25
26#ifdef BACKLIGHT_ENABLE
27# include "backlight.h"
28#endif
29
30// default feedback method
31void dynamic_macro_led_blink(void) {
32#ifdef BACKLIGHT_ENABLE
33 backlight_toggle();
34 wait_ms(100);
35 backlight_toggle();
36#endif
37}
38
39/* User hooks for Dynamic Macros */
40
41__attribute__((weak)) bool dynamic_macro_record_start_kb(int8_t direction) {
42 return dynamic_macro_record_start_user(direction);
43}
44
45__attribute__((weak)) bool dynamic_macro_record_start_user(int8_t direction) {
46 dynamic_macro_led_blink();
47 return true;
48}
49
50__attribute__((weak)) bool dynamic_macro_play_kb(int8_t direction) {
51 return dynamic_macro_play_user(direction);
52}
53
54__attribute__((weak)) bool dynamic_macro_play_user(int8_t direction) {
55 dynamic_macro_led_blink();
56 return true;
57}
58
59__attribute__((weak)) bool dynamic_macro_record_key_kb(int8_t direction, keyrecord_t *record) {
60 return dynamic_macro_record_key_user(direction, record);
61}
62
63__attribute__((weak)) bool dynamic_macro_record_key_user(int8_t direction, keyrecord_t *record) {
64 dynamic_macro_led_blink();
65 return true;
66}
67
68__attribute__((weak)) bool dynamic_macro_record_end_kb(int8_t direction) {
69 return dynamic_macro_record_end_user(direction);
70}
71
72__attribute__((weak)) bool dynamic_macro_record_end_user(int8_t direction) {
73 dynamic_macro_led_blink();
74 return true;
75}
76
77__attribute__((weak)) bool dynamic_macro_valid_key_kb(uint16_t keycode, keyrecord_t *record) {
78 return dynamic_macro_valid_key_user(keycode, record);
79}
80
81__attribute__((weak)) bool dynamic_macro_valid_key_user(uint16_t keycode, keyrecord_t *record) {
82 return true;
83}
84
85/* Convenience macros used for retrieving the debug info. All of them
86 * need a `direction` variable accessible at the call site.
87 */
88#define DYNAMIC_MACRO_CURRENT_SLOT() (direction > 0 ? 1 : 2)
89#define DYNAMIC_MACRO_CURRENT_LENGTH(BEGIN, POINTER) ((int)(direction * ((POINTER) - (BEGIN))))
90#define DYNAMIC_MACRO_CURRENT_CAPACITY(BEGIN, END2) ((int)(direction * ((END2) - (BEGIN)) + 1))
91
92/**
93 * Start recording of the dynamic macro.
94 *
95 * @param[out] macro_pointer The new macro buffer iterator.
96 * @param[in] macro_buffer The macro buffer used to initialize macro_pointer.
97 */
98void dynamic_macro_record_start(keyrecord_t **macro_pointer, keyrecord_t *macro_buffer, int8_t direction) {
99 dprintln("dynamic macro recording: started");
100
101 dynamic_macro_record_start_kb(direction);
102
103 clear_keyboard();
104 layer_clear();
105 *macro_pointer = macro_buffer;
106}
107
108/**
109 * Play the dynamic macro.
110 *
111 * @param macro_buffer[in] The beginning of the macro buffer being played.
112 * @param macro_end[in] The element after the last macro buffer element.
113 * @param direction[in] Either +1 or -1, which way to iterate the buffer.
114 */
115void dynamic_macro_play(keyrecord_t *macro_buffer, keyrecord_t *macro_end, int8_t direction) {
116 dprintf("dynamic macro: slot %d playback\n", DYNAMIC_MACRO_CURRENT_SLOT());
117
118 layer_state_t saved_layer_state = layer_state;
119
120 clear_keyboard();
121 layer_clear();
122
123 while (macro_buffer != macro_end) {
124 process_record(macro_buffer);
125 macro_buffer += direction;
126#ifdef DYNAMIC_MACRO_DELAY
127 wait_ms(DYNAMIC_MACRO_DELAY);
128#endif
129 }
130
131 clear_keyboard();
132
133 layer_state_set(saved_layer_state);
134
135 dynamic_macro_play_kb(direction);
136}
137
138/**
139 * Record a single key in a dynamic macro.
140 *
141 * @param macro_buffer[in] The start of the used macro buffer.
142 * @param macro_pointer[in,out] The current buffer position.
143 * @param macro2_end[in] The end of the other macro.
144 * @param direction[in] Either +1 or -1, which way to iterate the buffer.
145 * @param record[in] The current keypress.
146 */
147void dynamic_macro_record_key(keyrecord_t *macro_buffer, keyrecord_t **macro_pointer, keyrecord_t *macro2_end, int8_t direction, keyrecord_t *record) {
148 /* If we've just started recording, ignore all the key releases. */
149 if (!record->event.pressed && *macro_pointer == macro_buffer) {
150 dprintln("dynamic macro: ignoring a leading key-up event");
151 return;
152 }
153
154 /* The other end of the other macro is the last buffer element it
155 * is safe to use before overwriting the other macro.
156 */
157 if (*macro_pointer - direction != macro2_end) {
158 **macro_pointer = *record;
159 *macro_pointer += direction;
160 }
161 dynamic_macro_record_key_kb(direction, record);
162
163 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));
164}
165
166/**
167 * End recording of the dynamic macro. Essentially just update the
168 * pointer to the end of the macro.
169 */
170void dynamic_macro_record_end(keyrecord_t *macro_buffer, keyrecord_t *macro_pointer, int8_t direction, keyrecord_t **macro_end) {
171 dynamic_macro_record_end_kb(direction);
172
173 /* Do not save the keys being held when stopping the recording,
174 * i.e. the keys used to access the layer DM_RSTP is on.
175 */
176 while (macro_pointer != macro_buffer && (macro_pointer - direction)->event.pressed) {
177 dprintln("dynamic macro: trimming a trailing key-down event");
178 macro_pointer -= direction;
179 }
180
181 dprintf("dynamic macro: slot %d saved, length: %d\n", DYNAMIC_MACRO_CURRENT_SLOT(), DYNAMIC_MACRO_CURRENT_LENGTH(macro_buffer, macro_pointer));
182
183 *macro_end = macro_pointer;
184}
185
186/* Both macros use the same buffer but read/write on different
187 * ends of it.
188 *
189 * Macro1 is written left-to-right starting from the beginning of
190 * the buffer.
191 *
192 * Macro2 is written right-to-left starting from the end of the
193 * buffer.
194 *
195 * ¯o_buffer macro_end
196 * v v
197 * +------------------------------------------------------------+
198 * |>>>>>> MACRO1 >>>>>> <<<<<<<<<<<<< MACRO2 <<<<<<<<<<<<<|
199 * +------------------------------------------------------------+
200 * ^ ^
201 * r_macro_end r_macro_buffer
202 *
203 * During the recording when one macro encounters the end of the
204 * other macro, the recording is stopped. Apart from this, there
205 * are no arbitrary limits for the macros' length in relation to
206 * each other: for example one can either have two medium sized
207 * macros or one long macro and one short macro. Or even one empty
208 * and one using the whole buffer.
209 */
210static keyrecord_t macro_buffer[DYNAMIC_MACRO_SIZE];
211
212/* Pointer to the first buffer element after the first macro.
213 * Initially points to the very beginning of the buffer since the
214 * macro is empty. */
215static keyrecord_t *macro_end = macro_buffer;
216
217/* The other end of the macro buffer. Serves as the beginning of
218 * the second macro. */
219static keyrecord_t *const r_macro_buffer = macro_buffer + DYNAMIC_MACRO_SIZE - 1;
220
221/* Like macro_end but for the second macro. */
222static keyrecord_t *r_macro_end = macro_buffer + DYNAMIC_MACRO_SIZE - 1;
223
224/* A persistent pointer to the current macro position (iterator)
225 * used during the recording. */
226static keyrecord_t *macro_pointer = NULL;
227
228/* 0 - no macro is being recorded right now
229 * 1,2 - either macro 1 or 2 is being recorded */
230static uint8_t macro_id = 0;
231
232/**
233 * If a dynamic macro is currently being recorded, stop recording.
234 */
235void dynamic_macro_stop_recording(void) {
236 switch (macro_id) {
237 case 1:
238 dynamic_macro_record_end(macro_buffer, macro_pointer, +1, ¯o_end);
239 break;
240 case 2:
241 dynamic_macro_record_end(r_macro_buffer, macro_pointer, -1, &r_macro_end);
242 break;
243 }
244 macro_id = 0;
245}
246
247/* Handle the key events related to the dynamic macros.
248 */
249bool process_dynamic_macro(uint16_t keycode, keyrecord_t *record) {
250 if (macro_id == 0) {
251 /* No macro recording in progress. */
252 if (!record->event.pressed) {
253 switch (keycode) {
254 case QK_DYNAMIC_MACRO_RECORD_START_1:
255 dynamic_macro_record_start(¯o_pointer, macro_buffer, +1);
256 macro_id = 1;
257 return false;
258 case QK_DYNAMIC_MACRO_RECORD_START_2:
259 dynamic_macro_record_start(¯o_pointer, r_macro_buffer, -1);
260 macro_id = 2;
261 return false;
262 case QK_DYNAMIC_MACRO_PLAY_1:
263 dynamic_macro_play(macro_buffer, macro_end, +1);
264 return false;
265 case QK_DYNAMIC_MACRO_PLAY_2:
266 dynamic_macro_play(r_macro_buffer, r_macro_end, -1);
267 return false;
268 }
269 }
270 } else {
271 /* A macro is being recorded right now. */
272 switch (keycode) {
273 case QK_DYNAMIC_MACRO_RECORD_START_1:
274 case QK_DYNAMIC_MACRO_RECORD_START_2:
275 case QK_DYNAMIC_MACRO_RECORD_STOP:
276 /* Stop the macro recording. */
277 if (record->event.pressed ^ (keycode != QK_DYNAMIC_MACRO_RECORD_STOP)) { /* Ignore the initial release
278 * just after the recording
279 * starts for DM_RSTP. */
280 dynamic_macro_stop_recording();
281 }
282 return false;
283#ifdef DYNAMIC_MACRO_NO_NESTING
284 case QK_DYNAMIC_MACRO_PLAY_1:
285 case QK_DYNAMIC_MACRO_PLAY_2:
286 dprintln("dynamic macro: ignoring macro play key while recording");
287 return false;
288#endif
289 default:
290 if (dynamic_macro_valid_key_kb(keycode, record)) {
291 /* Store the key in the macro buffer and process it normally. */
292 switch (macro_id) {
293 case 1:
294 dynamic_macro_record_key(macro_buffer, ¯o_pointer, r_macro_end, +1, record);
295 break;
296 case 2:
297 dynamic_macro_record_key(r_macro_buffer, ¯o_pointer, macro_end, -1, record);
298 break;
299 }
300 }
301 return true;
302 break;
303 }
304 }
305
306 return true;
307}