keyboard stuff
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#ifdef DYNAMIC_MACRO_KEEP_ORIGINAL_LAYER_STATE
93static layer_state_t dm1_layer_state;
94static layer_state_t dm2_layer_state;
95#endif
96
97/**
98 * Start recording of the dynamic macro.
99 *
100 * @param[out] macro_pointer The new macro buffer iterator.
101 * @param[in] macro_buffer The macro buffer used to initialize macro_pointer.
102 */
103void dynamic_macro_record_start(keyrecord_t **macro_pointer, keyrecord_t *macro_buffer, int8_t direction) {
104 dprintln("dynamic macro recording: started");
105
106 dynamic_macro_record_start_kb(direction);
107
108#ifdef DYNAMIC_MACRO_KEEP_ORIGINAL_LAYER_STATE
109 if (direction == 1) {
110 dm1_layer_state = layer_state;
111 } else if (direction == -1) {
112 dm2_layer_state = layer_state;
113 }
114#else
115 layer_clear();
116#endif
117 clear_keyboard();
118 *macro_pointer = macro_buffer;
119}
120
121/**
122 * Play the dynamic macro.
123 *
124 * @param macro_buffer[in] The beginning of the macro buffer being played.
125 * @param macro_end[in] The element after the last macro buffer element.
126 * @param direction[in] Either +1 or -1, which way to iterate the buffer.
127 */
128void dynamic_macro_play(keyrecord_t *macro_buffer, keyrecord_t *macro_end, int8_t direction) {
129 dprintf("dynamic macro: slot %d playback\n", DYNAMIC_MACRO_CURRENT_SLOT());
130
131 layer_state_t saved_layer_state = layer_state;
132
133 clear_keyboard();
134#ifdef DYNAMIC_MACRO_KEEP_ORIGINAL_LAYER_STATE
135 if (direction == 1) {
136 layer_state_set(dm1_layer_state);
137 } else if (direction == -1) {
138 layer_state_set(dm2_layer_state);
139 }
140#else
141 layer_clear();
142#endif
143
144 while (macro_buffer != macro_end) {
145 process_record(macro_buffer);
146 macro_buffer += direction;
147#ifdef DYNAMIC_MACRO_DELAY
148 wait_ms(DYNAMIC_MACRO_DELAY);
149#endif
150 }
151
152 clear_keyboard();
153
154 layer_state_set(saved_layer_state);
155
156 dynamic_macro_play_kb(direction);
157}
158
159/**
160 * Record a single key in a dynamic macro.
161 *
162 * @param macro_buffer[in] The start of the used macro buffer.
163 * @param macro_pointer[in,out] The current buffer position.
164 * @param macro2_end[in] The end of the other macro.
165 * @param direction[in] Either +1 or -1, which way to iterate the buffer.
166 * @param record[in] The current keypress.
167 */
168void dynamic_macro_record_key(keyrecord_t *macro_buffer, keyrecord_t **macro_pointer, keyrecord_t *macro2_end, int8_t direction, keyrecord_t *record) {
169 /* If we've just started recording, ignore all the key releases. */
170 if (!record->event.pressed && *macro_pointer == macro_buffer) {
171 dprintln("dynamic macro: ignoring a leading key-up event");
172 return;
173 }
174
175 /* The other end of the other macro is the last buffer element it
176 * is safe to use before overwriting the other macro.
177 */
178 if (*macro_pointer - direction != macro2_end) {
179 **macro_pointer = *record;
180 *macro_pointer += direction;
181 }
182 dynamic_macro_record_key_kb(direction, record);
183
184 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));
185}
186
187/**
188 * End recording of the dynamic macro. Essentially just update the
189 * pointer to the end of the macro.
190 */
191void dynamic_macro_record_end(keyrecord_t *macro_buffer, keyrecord_t *macro_pointer, int8_t direction, keyrecord_t **macro_end) {
192 dynamic_macro_record_end_kb(direction);
193
194 /* Do not save the keys being held when stopping the recording,
195 * i.e. the keys used to access the layer DM_RSTP is on.
196 */
197 while (macro_pointer != macro_buffer && (macro_pointer - direction)->event.pressed) {
198 dprintln("dynamic macro: trimming a trailing key-down event");
199 macro_pointer -= direction;
200 }
201
202 dprintf("dynamic macro: slot %d saved, length: %d\n", DYNAMIC_MACRO_CURRENT_SLOT(), DYNAMIC_MACRO_CURRENT_LENGTH(macro_buffer, macro_pointer));
203
204 *macro_end = macro_pointer;
205}
206
207/* Both macros use the same buffer but read/write on different
208 * ends of it.
209 *
210 * Macro1 is written left-to-right starting from the beginning of
211 * the buffer.
212 *
213 * Macro2 is written right-to-left starting from the end of the
214 * buffer.
215 *
216 * ¯o_buffer macro_end
217 * v v
218 * +------------------------------------------------------------+
219 * |>>>>>> MACRO1 >>>>>> <<<<<<<<<<<<< MACRO2 <<<<<<<<<<<<<|
220 * +------------------------------------------------------------+
221 * ^ ^
222 * r_macro_end r_macro_buffer
223 *
224 * During the recording when one macro encounters the end of the
225 * other macro, the recording is stopped. Apart from this, there
226 * are no arbitrary limits for the macros' length in relation to
227 * each other: for example one can either have two medium sized
228 * macros or one long macro and one short macro. Or even one empty
229 * and one using the whole buffer.
230 */
231static keyrecord_t macro_buffer[DYNAMIC_MACRO_SIZE];
232
233/* Pointer to the first buffer element after the first macro.
234 * Initially points to the very beginning of the buffer since the
235 * macro is empty. */
236static keyrecord_t *macro_end = macro_buffer;
237
238/* The other end of the macro buffer. Serves as the beginning of
239 * the second macro. */
240static keyrecord_t *const r_macro_buffer = macro_buffer + DYNAMIC_MACRO_SIZE - 1;
241
242/* Like macro_end but for the second macro. */
243static keyrecord_t *r_macro_end = macro_buffer + DYNAMIC_MACRO_SIZE - 1;
244
245/* A persistent pointer to the current macro position (iterator)
246 * used during the recording. */
247static keyrecord_t *macro_pointer = NULL;
248
249/* 0 - no macro is being recorded right now
250 * 1,2 - either macro 1 or 2 is being recorded */
251static uint8_t macro_id = 0;
252
253/**
254 * If a dynamic macro is currently being recorded, stop recording.
255 */
256void dynamic_macro_stop_recording(void) {
257 switch (macro_id) {
258 case 1:
259 dynamic_macro_record_end(macro_buffer, macro_pointer, +1, ¯o_end);
260 break;
261 case 2:
262 dynamic_macro_record_end(r_macro_buffer, macro_pointer, -1, &r_macro_end);
263 break;
264 }
265 macro_id = 0;
266}
267
268/* Handle the key events related to the dynamic macros.
269 */
270bool process_dynamic_macro(uint16_t keycode, keyrecord_t *record) {
271 if (macro_id == 0) {
272 /* No macro recording in progress. */
273 if (!record->event.pressed) {
274 switch (keycode) {
275 case QK_DYNAMIC_MACRO_RECORD_START_1:
276 dynamic_macro_record_start(¯o_pointer, macro_buffer, +1);
277 macro_id = 1;
278 return false;
279 case QK_DYNAMIC_MACRO_RECORD_START_2:
280 dynamic_macro_record_start(¯o_pointer, r_macro_buffer, -1);
281 macro_id = 2;
282 return false;
283 case QK_DYNAMIC_MACRO_PLAY_1:
284 dynamic_macro_play(macro_buffer, macro_end, +1);
285 return false;
286 case QK_DYNAMIC_MACRO_PLAY_2:
287 dynamic_macro_play(r_macro_buffer, r_macro_end, -1);
288 return false;
289 }
290 }
291 } else {
292 /* A macro is being recorded right now. */
293 switch (keycode) {
294 case QK_DYNAMIC_MACRO_RECORD_START_1:
295 case QK_DYNAMIC_MACRO_RECORD_START_2:
296 case QK_DYNAMIC_MACRO_RECORD_STOP:
297 /* Stop the macro recording. */
298 if (record->event.pressed ^ (keycode != QK_DYNAMIC_MACRO_RECORD_STOP)) { /* Ignore the initial release
299 * just after the recording
300 * starts for DM_RSTP. */
301 dynamic_macro_stop_recording();
302 }
303 return false;
304#ifdef DYNAMIC_MACRO_NO_NESTING
305 case QK_DYNAMIC_MACRO_PLAY_1:
306 case QK_DYNAMIC_MACRO_PLAY_2:
307 dprintln("dynamic macro: ignoring macro play key while recording");
308 return false;
309#endif
310 default:
311 if (dynamic_macro_valid_key_kb(keycode, record)) {
312 /* Store the key in the macro buffer and process it normally. */
313 switch (macro_id) {
314 case 1:
315 dynamic_macro_record_key(macro_buffer, ¯o_pointer, r_macro_end, +1, record);
316 break;
317 case 2:
318 dynamic_macro_record_key(r_macro_buffer, ¯o_pointer, macro_end, -1, record);
319 break;
320 }
321 }
322 return true;
323 break;
324 }
325 }
326
327 return true;
328}