~ruther/qmk_firmware

5117dff6a26aec4eca04fb9787b4f428884739bc — Drashna Jaelre 5 years ago e5d34fd
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
M docs/feature_macros.md => docs/feature_macros.md +40 -0
@@ 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

You may want to use keys in your macros that you can't write down, such as `Ctrl` or `Home`.

M docs/understanding_qmk.md => docs/understanding_qmk.md +9 -0
@@ 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.

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


M quantum/quantum.c => quantum/quantum.c +17 -3
@@ 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))
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) {
    clear_keyboard();
#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);
}

/* Main keycode processing function. Hands off handling to other functions,
 * then processes internal Quantum keycodes, then processes ACTIONs.
 */
/* Get keycode, and then call keyboard function */
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) {
    uint16_t keycode = get_record_keycode(record);


M quantum/quantum.h => quantum/quantum.h +2 -0
@@ 257,6 257,8 @@ uint16_t get_event_keycode(keyevent_t event);
bool     process_action_kb(keyrecord_t *record);
bool     process_record_kb(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
#    define BOOTMAGIC_LITE_COLUMN 0

M tmk_core/common/action.c => tmk_core/common/action.c +7 -1
@@ 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)) void post_process_record_quantum(keyrecord_t *record) {}

#ifndef NO_ACTION_TAPPING
/** \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;

    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);
    dprint("ACTION: ");
    debug_action(action);


@@ 988,7 995,6 @@ bool is_tap_action(action_t action) {
 * 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); }

/** \brief Debug print (FIXME: Needs better description)
 *
 * FIXME: Needs documentation.

M tmk_core/common/action.h => tmk_core/common/action.h +2 -0
@@ 84,6 84,8 @@ void process_hand_swap(keyevent_t *record);

void process_record_nocache(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 register_code(uint8_t code);
void unregister_code(uint8_t code);