Add Post Processing to process_record (#4892)
* Improve process_record system Code based on @colinta's * Rename and better handle functions * Fix incorrect function call to process_record_user * Add documentation for post_process_record * Add both get_event_keycode and get_record_keycode functions And add some comments about these functions * Update code format * Cleanup merge artifacts
This commit is contained in:
		@@ -88,6 +88,46 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Advanced Macros
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In addition to the `process_record_user()` function, is the `post_process_record_user()` function. This runs after `process_record` and can be used to do things after a keystroke has been sent.  This is useful if you want to have a key pressed before and released after a normal key, for instance. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In this example, we modify most normal keypresses so that `F22` is pressed before the keystroke is normally sent, and release it __only after__ it's been released.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					static uint8_t f22_tracker;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool process_record_user(uint16_t keycode, keyrecord_t *record) {
 | 
				
			||||||
 | 
					  switch (keycode) {
 | 
				
			||||||
 | 
					    case KC_A ... KC_F21: //notice how it skips over F22
 | 
				
			||||||
 | 
					    case KC_F23 ... KC_EXSEL: //exsel is the last one before the modifier keys
 | 
				
			||||||
 | 
					      if (record->event.pressed) {
 | 
				
			||||||
 | 
					        register_code(KC_F22); //this means to send F22 down
 | 
				
			||||||
 | 
					        f22_tracker++;
 | 
				
			||||||
 | 
					        register_code(keycode);
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void post_process_record_user(uint16_t keycode, keyrecord_t *record) {
 | 
				
			||||||
 | 
					  switch (keycode) {
 | 
				
			||||||
 | 
					    case KC_A ... KC_F21: //notice how it skips over F22
 | 
				
			||||||
 | 
					    case KC_F23 ... KC_EXSEL: //exsel is the last one before the modifier keys
 | 
				
			||||||
 | 
					      if (!record->event.pressed) {
 | 
				
			||||||
 | 
					        f22_tracker--;
 | 
				
			||||||
 | 
					        if (!f22_tracker) {
 | 
				
			||||||
 | 
					            unregister_code(KC_F22); //this means to send F22 up
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### TAP, DOWN and UP
 | 
					### TAP, DOWN and UP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You may want to use keys in your macros that you can't write down, such as `Ctrl` or `Home`.
 | 
					You may want to use keys in your macros that you can't write down, such as `Ctrl` or `Home`.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -162,6 +162,15 @@ The `process_record()` function itself is deceptively simple, but hidden within
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
At any step during this chain of events a function (such as `process_record_kb()`) can `return false` to halt all further processing.
 | 
					At any step during this chain of events a function (such as `process_record_kb()`) can `return false` to halt all further processing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					After this is called, `post_process_record()` is called, which can be used to handle additional cleanup that needs to be run after the keycode is normally handled. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* [`void post_process_record(keyrecord_t *record)`]()
 | 
				
			||||||
 | 
					  * [`void post_process_record_quantum(keyrecord_t *record)`]()
 | 
				
			||||||
 | 
					    * [Map this record to a keycode]()
 | 
				
			||||||
 | 
					    * [`void post_process_clicky(uint16_t keycode, keyrecord_t *record)`]()
 | 
				
			||||||
 | 
					    * [`void post_process_record_kb(uint16_t keycode, keyrecord_t *record)`]()
 | 
				
			||||||
 | 
					      * [`void post_process_record_user(uint16_t keycode, keyrecord_t *record)`]()
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
<!--
 | 
					<!--
 | 
				
			||||||
#### Mouse Handling
 | 
					#### Mouse Handling
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -120,6 +120,14 @@ __attribute__((weak)) bool process_record_kb(uint16_t keycode, keyrecord_t *reco
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
__attribute__((weak)) bool process_record_user(uint16_t keycode, keyrecord_t *record) { return true; }
 | 
					__attribute__((weak)) bool process_record_user(uint16_t keycode, keyrecord_t *record) { return true; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__attribute__ ((weak))
 | 
				
			||||||
 | 
					void post_process_record_kb(uint16_t keycode, keyrecord_t *record) {
 | 
				
			||||||
 | 
					  post_process_record_user(keycode, record);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__attribute__ ((weak))
 | 
				
			||||||
 | 
					void post_process_record_user(uint16_t keycode, keyrecord_t *record) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void reset_keyboard(void) {
 | 
					void reset_keyboard(void) {
 | 
				
			||||||
    clear_keyboard();
 | 
					    clear_keyboard();
 | 
				
			||||||
#if defined(MIDI_ENABLE) && defined(MIDI_BASIC)
 | 
					#if defined(MIDI_ENABLE) && defined(MIDI_BASIC)
 | 
				
			||||||
@@ -172,9 +180,15 @@ uint16_t get_event_keycode(keyevent_t event) {
 | 
				
			|||||||
        return keymap_key_to_keycode(layer_switch_get_layer(event.key), event.key);
 | 
					        return keymap_key_to_keycode(layer_switch_get_layer(event.key), event.key);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Main keycode processing function. Hands off handling to other functions,
 | 
					/* Get keycode, and then call keyboard function */
 | 
				
			||||||
 * then processes internal Quantum keycodes, then processes ACTIONs.
 | 
					void post_process_record_quantum(keyrecord_t *record) {
 | 
				
			||||||
 */
 | 
					  uint16_t keycode = get_record_keycode(record);
 | 
				
			||||||
 | 
					  post_process_record_kb(keycode, record);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Core keycode function, hands off handling to other functions,
 | 
				
			||||||
 | 
					    then processes internal quantum keycodes, and then processes
 | 
				
			||||||
 | 
					    ACTIONs.                                                      */
 | 
				
			||||||
bool process_record_quantum(keyrecord_t *record) {
 | 
					bool process_record_quantum(keyrecord_t *record) {
 | 
				
			||||||
    uint16_t keycode = get_record_keycode(record);
 | 
					    uint16_t keycode = get_record_keycode(record);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -257,6 +257,8 @@ uint16_t get_event_keycode(keyevent_t event);
 | 
				
			|||||||
bool     process_action_kb(keyrecord_t *record);
 | 
					bool     process_action_kb(keyrecord_t *record);
 | 
				
			||||||
bool     process_record_kb(uint16_t keycode, keyrecord_t *record);
 | 
					bool     process_record_kb(uint16_t keycode, keyrecord_t *record);
 | 
				
			||||||
bool     process_record_user(uint16_t keycode, keyrecord_t *record);
 | 
					bool     process_record_user(uint16_t keycode, keyrecord_t *record);
 | 
				
			||||||
 | 
					void     post_process_record_kb(uint16_t keycode, keyrecord_t *record);
 | 
				
			||||||
 | 
					void     post_process_record_user(uint16_t keycode, keyrecord_t *record);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef BOOTMAGIC_LITE_COLUMN
 | 
					#ifndef BOOTMAGIC_LITE_COLUMN
 | 
				
			||||||
#    define BOOTMAGIC_LITE_COLUMN 0
 | 
					#    define BOOTMAGIC_LITE_COLUMN 0
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -151,6 +151,8 @@ void process_record_nocache(keyrecord_t *record) { process_record(record); }
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
__attribute__((weak)) bool process_record_quantum(keyrecord_t *record) { return true; }
 | 
					__attribute__((weak)) bool process_record_quantum(keyrecord_t *record) { return true; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__attribute__((weak)) void post_process_record_quantum(keyrecord_t *record) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef NO_ACTION_TAPPING
 | 
					#ifndef NO_ACTION_TAPPING
 | 
				
			||||||
/** \brief Allows for handling tap-hold actions immediately instead of waiting for TAPPING_TERM or another keypress.
 | 
					/** \brief Allows for handling tap-hold actions immediately instead of waiting for TAPPING_TERM or another keypress.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -185,6 +187,11 @@ void process_record(keyrecord_t *record) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (!process_record_quantum(record)) return;
 | 
					    if (!process_record_quantum(record)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    process_record_handler(record);
 | 
				
			||||||
 | 
					    post_process_record_quantum(record);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void process_record_handler(keyrecord_t *record) {
 | 
				
			||||||
    action_t action = store_or_get_action(record->event.pressed, record->event.key);
 | 
					    action_t action = store_or_get_action(record->event.pressed, record->event.key);
 | 
				
			||||||
    dprint("ACTION: ");
 | 
					    dprint("ACTION: ");
 | 
				
			||||||
    debug_action(action);
 | 
					    debug_action(action);
 | 
				
			||||||
@@ -988,7 +995,6 @@ bool is_tap_action(action_t action) {
 | 
				
			|||||||
 * FIXME: Needs documentation.
 | 
					 * FIXME: Needs documentation.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void debug_event(keyevent_t event) { dprintf("%04X%c(%u)", (event.key.row << 8 | event.key.col), (event.pressed ? 'd' : 'u'), event.time); }
 | 
					void debug_event(keyevent_t event) { dprintf("%04X%c(%u)", (event.key.row << 8 | event.key.col), (event.pressed ? 'd' : 'u'), event.time); }
 | 
				
			||||||
 | 
					 | 
				
			||||||
/** \brief Debug print (FIXME: Needs better description)
 | 
					/** \brief Debug print (FIXME: Needs better description)
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * FIXME: Needs documentation.
 | 
					 * FIXME: Needs documentation.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -84,6 +84,8 @@ void process_hand_swap(keyevent_t *record);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void process_record_nocache(keyrecord_t *record);
 | 
					void process_record_nocache(keyrecord_t *record);
 | 
				
			||||||
void process_record(keyrecord_t *record);
 | 
					void process_record(keyrecord_t *record);
 | 
				
			||||||
 | 
					void process_record_handler(keyrecord_t *record);
 | 
				
			||||||
 | 
					void post_process_record_quantum(keyrecord_t *record);
 | 
				
			||||||
void process_action(keyrecord_t *record, action_t action);
 | 
					void process_action(keyrecord_t *record, action_t action);
 | 
				
			||||||
void register_code(uint8_t code);
 | 
					void register_code(uint8_t code);
 | 
				
			||||||
void unregister_code(uint8_t code);
 | 
					void unregister_code(uint8_t code);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user