at master 12 kB view raw
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 * &macro_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, &macro_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(&macro_pointer, macro_buffer, +1); 277 macro_id = 1; 278 return false; 279 case QK_DYNAMIC_MACRO_RECORD_START_2: 280 dynamic_macro_record_start(&macro_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, &macro_pointer, r_macro_end, +1, record); 316 break; 317 case 2: 318 dynamic_macro_record_key(r_macro_buffer, &macro_pointer, macro_end, -1, record); 319 break; 320 } 321 } 322 return true; 323 break; 324 } 325 } 326 327 return true; 328}