~ruther/qmk_firmware

2c5d66987da4c7d5857cab8b09c4f852b4d8e4d9 — QMK Bot 3 years ago b06740c
Format code according to conventions (#15193)

M drivers/qwiic/micro_oled.c => drivers/qwiic/micro_oled.c +1 -1
@@ 149,7 149,7 @@ void micro_oled_init(void) {
#endif

    send_command(MEMORYMODE);
    send_command(0x02);   //  0x02 = 10b, Page addressing mode
    send_command(0x02);  //  0x02 = 10b, Page addressing mode

    send_command(SETCOMPINS);  // 0xDA
    if (LCDHEIGHT > 32) {

M drivers/sensors/adns5050.c => drivers/sensors/adns5050.c +8 -15
@@ 17,7 17,6 @@
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#include "adns5050.h"
#include "wait.h"
#include "debug.h"


@@ 61,13 60,9 @@ void adns_sync(void) {
    writePinHigh(ADNS_CS_PIN);
}

void adns_cs_select(void) {
    writePinLow(ADNS_CS_PIN);
}
void adns_cs_select(void) { writePinLow(ADNS_CS_PIN); }

void adns_cs_deselect(void) {
    writePinHigh(ADNS_CS_PIN);
}
void adns_cs_deselect(void) { writePinHigh(ADNS_CS_PIN); }

uint8_t adns_serial_read(void) {
    setPinInput(ADNS_SDIO_PIN);


@@ 121,7 116,7 @@ uint8_t adns_read_reg(uint8_t reg_addr) {
    // We don't need a minimum tSRAD here. That's because a 4ms wait time is
    // already included in adns_serial_write(), so we're good.
    // See page 10 and 15 of the ADNS spec sheet.
    //wait_us(4);
    // wait_us(4);

    uint8_t byte = adns_serial_read();



@@ 138,7 133,7 @@ uint8_t adns_read_reg(uint8_t reg_addr) {

void adns_write_reg(uint8_t reg_addr, uint8_t data) {
    adns_cs_select();
    adns_serial_write( 0b10000000 | reg_addr );
    adns_serial_write(0b10000000 | reg_addr);
    adns_serial_write(data);
    adns_cs_deselect();
}


@@ 155,7 150,7 @@ report_adns_t adns_read_burst(void) {
    // We don't need a minimum tSRAD here. That's because a 4ms wait time is
    // already included in adns_serial_write(), so we're good.
    // See page 10 and 15 of the ADNS spec sheet.
    //wait_us(4);
    // wait_us(4);

    uint8_t x = adns_serial_read();
    uint8_t y = adns_serial_read();


@@ 180,13 175,11 @@ int8_t convert_twoscomp(uint8_t data) {
}

// Don't forget to use the definitions for CPI in the header file.
void adns_set_cpi(uint8_t cpi) {
    adns_write_reg(REG_MOUSE_CONTROL2, cpi);
}
void adns_set_cpi(uint8_t cpi) { adns_write_reg(REG_MOUSE_CONTROL2, cpi); }

bool adns_check_signature(void) {
    uint8_t pid = adns_read_reg(REG_PRODUCT_ID);
    uint8_t rid = adns_read_reg(REG_REVISION_ID);
    uint8_t pid  = adns_read_reg(REG_PRODUCT_ID);
    uint8_t rid  = adns_read_reg(REG_REVISION_ID);
    uint8_t pid2 = adns_read_reg(REG_PRODUCT_ID2);

    return (pid == 0x12 && rid == 0x01 && pid2 == 0x26);

M drivers/sensors/adns5050.h => drivers/sensors/adns5050.h +9 -9
@@ 67,13 67,13 @@ typedef struct {
// A bunch of functions to implement the ADNS5050-specific serial protocol.
// Note that the "serial.h" driver is insufficient, because it does not
// manually manipulate a serial clock signal.
void adns_init(void);
void adns_sync(void);
uint8_t adns_serial_read(void);
void adns_serial_write(uint8_t data);
uint8_t adns_read_reg(uint8_t reg_addr);
void adns_write_reg(uint8_t reg_addr, uint8_t data);
void          adns_init(void);
void          adns_sync(void);
uint8_t       adns_serial_read(void);
void          adns_serial_write(uint8_t data);
uint8_t       adns_read_reg(uint8_t reg_addr);
void          adns_write_reg(uint8_t reg_addr, uint8_t data);
report_adns_t adns_read_burst(void);
int8_t convert_twoscomp(uint8_t data);
void adns_set_cpi(uint8_t cpi);
bool adns_check_signature(void);
int8_t        convert_twoscomp(uint8_t data);
void          adns_set_cpi(uint8_t cpi);
bool          adns_check_signature(void);

M drivers/sensors/adns9800.c => drivers/sensors/adns9800.c +55 -64
@@ 20,57 20,57 @@
#include "adns9800.h"

// registers
#define REG_Product_ID                           0x00
#define REG_Revision_ID                          0x01
#define REG_Motion                               0x02
#define REG_Delta_X_L                            0x03
#define REG_Delta_X_H                            0x04
#define REG_Delta_Y_L                            0x05
#define REG_Delta_Y_H                            0x06
#define REG_SQUAL                                0x07
#define REG_Pixel_Sum                            0x08
#define REG_Maximum_Pixel                        0x09
#define REG_Minimum_Pixel                        0x0a
#define REG_Shutter_Lower                        0x0b
#define REG_Shutter_Upper                        0x0c
#define REG_Frame_Period_Lower                   0x0d
#define REG_Frame_Period_Upper                   0x0e
#define REG_Configuration_I                      0x0f
#define REG_Configuration_II                     0x10
#define REG_Frame_Capture                        0x12
#define REG_SROM_Enable                          0x13
#define REG_Run_Downshift                        0x14
#define REG_Rest1_Rate                           0x15
#define REG_Rest1_Downshift                      0x16
#define REG_Rest2_Rate                           0x17
#define REG_Rest2_Downshift                      0x18
#define REG_Rest3_Rate                           0x19
#define REG_Frame_Period_Max_Bound_Lower         0x1a
#define REG_Frame_Period_Max_Bound_Upper         0x1b
#define REG_Frame_Period_Min_Bound_Lower         0x1c
#define REG_Frame_Period_Min_Bound_Upper         0x1d
#define REG_Shutter_Max_Bound_Lower              0x1e
#define REG_Shutter_Max_Bound_Upper              0x1f
#define REG_LASER_CTRL0                          0x20
#define REG_Observation                          0x24
#define REG_Data_Out_Lower                       0x25
#define REG_Data_Out_Upper                       0x26
#define REG_SROM_ID                              0x2a
#define REG_Lift_Detection_Thr                   0x2e
#define REG_Configuration_V                      0x2f
#define REG_Configuration_IV                     0x39
#define REG_Power_Up_Reset                       0x3a
#define REG_Shutdown                             0x3b
#define REG_Inverse_Product_ID                   0x3f
#define REG_Motion_Burst                         0x50
#define REG_SROM_Load_Burst                      0x62
#define REG_Pixel_Burst                          0x64
#define REG_Product_ID 0x00
#define REG_Revision_ID 0x01
#define REG_Motion 0x02
#define REG_Delta_X_L 0x03
#define REG_Delta_X_H 0x04
#define REG_Delta_Y_L 0x05
#define REG_Delta_Y_H 0x06
#define REG_SQUAL 0x07
#define REG_Pixel_Sum 0x08
#define REG_Maximum_Pixel 0x09
#define REG_Minimum_Pixel 0x0a
#define REG_Shutter_Lower 0x0b
#define REG_Shutter_Upper 0x0c
#define REG_Frame_Period_Lower 0x0d
#define REG_Frame_Period_Upper 0x0e
#define REG_Configuration_I 0x0f
#define REG_Configuration_II 0x10
#define REG_Frame_Capture 0x12
#define REG_SROM_Enable 0x13
#define REG_Run_Downshift 0x14
#define REG_Rest1_Rate 0x15
#define REG_Rest1_Downshift 0x16
#define REG_Rest2_Rate 0x17
#define REG_Rest2_Downshift 0x18
#define REG_Rest3_Rate 0x19
#define REG_Frame_Period_Max_Bound_Lower 0x1a
#define REG_Frame_Period_Max_Bound_Upper 0x1b
#define REG_Frame_Period_Min_Bound_Lower 0x1c
#define REG_Frame_Period_Min_Bound_Upper 0x1d
#define REG_Shutter_Max_Bound_Lower 0x1e
#define REG_Shutter_Max_Bound_Upper 0x1f
#define REG_LASER_CTRL0 0x20
#define REG_Observation 0x24
#define REG_Data_Out_Lower 0x25
#define REG_Data_Out_Upper 0x26
#define REG_SROM_ID 0x2a
#define REG_Lift_Detection_Thr 0x2e
#define REG_Configuration_V 0x2f
#define REG_Configuration_IV 0x39
#define REG_Power_Up_Reset 0x3a
#define REG_Shutdown 0x3b
#define REG_Inverse_Product_ID 0x3f
#define REG_Motion_Burst 0x50
#define REG_SROM_Load_Burst 0x62
#define REG_Pixel_Burst 0x64

#define ADNS_CLOCK_SPEED 2000000
#define MIN_CPI 200
#define MAX_CPI 8200
#define CPI_STEP 200
#define CLAMP_CPI(value) value < MIN_CPI ? MIN_CPI : value > MAX_CPI ? MAX_CPI : value
#define CLAMP_CPI(value) value<MIN_CPI ? MIN_CPI : value> MAX_CPI ? MAX_CPI : value
#define SPI_MODE 3
#define SPI_DIVISOR (F_CPU / ADNS_CLOCK_SPEED)
#define US_BETWEEN_WRITES 120


@@ 80,12 80,9 @@

extern const uint8_t firmware_data[];

void adns_spi_start(void){
    spi_start(SPI_SS_PIN, false, SPI_MODE, SPI_DIVISOR);
}

void adns_write(uint8_t reg_addr, uint8_t data){
void adns_spi_start(void) { spi_start(SPI_SS_PIN, false, SPI_MODE, SPI_DIVISOR); }

void adns_write(uint8_t reg_addr, uint8_t data) {
    adns_spi_start();
    spi_write(reg_addr | MSB1);
    spi_write(data);


@@ 93,10 90,9 @@ void adns_write(uint8_t reg_addr, uint8_t data){
    wait_us(US_BETWEEN_WRITES);
}

uint8_t adns_read(uint8_t reg_addr){

uint8_t adns_read(uint8_t reg_addr) {
    adns_spi_start();
    spi_write(reg_addr & 0x7f );
    spi_write(reg_addr & 0x7f);
    uint8_t data = spi_read();
    spi_stop();
    wait_us(US_BETWEEN_READS);


@@ 105,7 101,6 @@ uint8_t adns_read(uint8_t reg_addr){
}

void adns_init() {

    setPinOutput(SPI_SS_PIN);

    spi_init();


@@ 144,7 139,7 @@ void adns_init() {

    // send all bytes of the firmware
    unsigned char c;
    for(int i = 0; i < FIRMWARE_LENGTH; i++){
    for (int i = 0; i < FIRMWARE_LENGTH; i++) {
        c = (unsigned char)pgm_read_byte(firmware_data + i);
        spi_write(c);
        wait_us(15);


@@ 161,7 156,7 @@ void adns_init() {

config_adns_t adns_get_config(void) {
    uint8_t config_1 = adns_read(REG_Configuration_I);
    return (config_adns_t){ (config_1 & 0xFF) * CPI_STEP };
    return (config_adns_t){(config_1 & 0xFF) * CPI_STEP};
}

void adns_set_config(config_adns_t config) {


@@ 169,20 164,17 @@ void adns_set_config(config_adns_t config) {
    adns_write(REG_Configuration_I, config_1);
}

static int16_t convertDeltaToInt(uint8_t high, uint8_t low){

static int16_t convertDeltaToInt(uint8_t high, uint8_t low) {
    // join bytes into twos compliment
    uint16_t twos_comp = (high << 8) | low;

    // convert twos comp to int
    if (twos_comp & 0x8000)
        return -1 * (~twos_comp + 1);
    if (twos_comp & 0x8000) return -1 * (~twos_comp + 1);

    return twos_comp;
}

report_adns_t adns_get_report(void) {

    report_adns_t report = {0, 0};

    adns_spi_start();


@@ 194,8 186,7 @@ report_adns_t adns_get_report(void) {

    uint8_t motion = spi_read();

    if(motion & 0x80) {

    if (motion & 0x80) {
        // clear observation register
        spi_read();


M drivers/sensors/adns9800.h => drivers/sensors/adns9800.h +2 -2
@@ 28,8 28,8 @@ typedef struct {
    int16_t y;
} report_adns_t;

void adns_init(void);
void          adns_init(void);
config_adns_t adns_get_config(void);
void adns_set_config(config_adns_t);
void          adns_set_config(config_adns_t);
/* Reads and clears the current delta values on the ADNS sensor */
report_adns_t adns_get_report(void);

M drivers/sensors/pmw3360.c => drivers/sensors/pmw3360.c +48 -48
@@ 23,55 23,55 @@
#include "pmw3360_firmware.h"

// Registers
#define REG_Product_ID                 0x00
#define REG_Revision_ID                0x01
#define REG_Motion                     0x02
#define REG_Delta_X_L                  0x03
#define REG_Delta_X_H                  0x04
#define REG_Delta_Y_L                  0x05
#define REG_Delta_Y_H                  0x06
#define REG_SQUAL                      0x07
#define REG_Raw_Data_Sum               0x08
#define REG_Maximum_Raw_data           0x09
#define REG_Minimum_Raw_data           0x0A
#define REG_Shutter_Lower              0x0B
#define REG_Shutter_Upper              0x0C
#define REG_Control                    0x0D
#define REG_Config1                    0x0F
#define REG_Config2                    0x10
#define REG_Angle_Tune                 0x11
#define REG_Frame_Capture              0x12
#define REG_SROM_Enable                0x13
#define REG_Run_Downshift              0x14
#define REG_Rest1_Rate_Lower           0x15
#define REG_Rest1_Rate_Upper           0x16
#define REG_Rest1_Downshift            0x17
#define REG_Rest2_Rate_Lower           0x18
#define REG_Rest2_Rate_Upper           0x19
#define REG_Rest2_Downshift            0x1A
#define REG_Rest3_Rate_Lower           0x1B
#define REG_Rest3_Rate_Upper           0x1C
#define REG_Observation                0x24
#define REG_Data_Out_Lower             0x25
#define REG_Data_Out_Upper             0x26
#define REG_Raw_Data_Dump              0x29
#define REG_SROM_ID                    0x2A
#define REG_Min_SQ_Run                 0x2B
#define REG_Raw_Data_Threshold         0x2C
#define REG_Config5                    0x2F
#define REG_Power_Up_Reset             0x3A
#define REG_Shutdown                   0x3B
#define REG_Inverse_Product_ID         0x3F
#define REG_LiftCutoff_Tune3           0x41
#define REG_Angle_Snap                 0x42
#define REG_LiftCutoff_Tune1           0x4A
#define REG_Motion_Burst               0x50
#define REG_LiftCutoff_Tune_Timeout    0x58
#define REG_Product_ID 0x00
#define REG_Revision_ID 0x01
#define REG_Motion 0x02
#define REG_Delta_X_L 0x03
#define REG_Delta_X_H 0x04
#define REG_Delta_Y_L 0x05
#define REG_Delta_Y_H 0x06
#define REG_SQUAL 0x07
#define REG_Raw_Data_Sum 0x08
#define REG_Maximum_Raw_data 0x09
#define REG_Minimum_Raw_data 0x0A
#define REG_Shutter_Lower 0x0B
#define REG_Shutter_Upper 0x0C
#define REG_Control 0x0D
#define REG_Config1 0x0F
#define REG_Config2 0x10
#define REG_Angle_Tune 0x11
#define REG_Frame_Capture 0x12
#define REG_SROM_Enable 0x13
#define REG_Run_Downshift 0x14
#define REG_Rest1_Rate_Lower 0x15
#define REG_Rest1_Rate_Upper 0x16
#define REG_Rest1_Downshift 0x17
#define REG_Rest2_Rate_Lower 0x18
#define REG_Rest2_Rate_Upper 0x19
#define REG_Rest2_Downshift 0x1A
#define REG_Rest3_Rate_Lower 0x1B
#define REG_Rest3_Rate_Upper 0x1C
#define REG_Observation 0x24
#define REG_Data_Out_Lower 0x25
#define REG_Data_Out_Upper 0x26
#define REG_Raw_Data_Dump 0x29
#define REG_SROM_ID 0x2A
#define REG_Min_SQ_Run 0x2B
#define REG_Raw_Data_Threshold 0x2C
#define REG_Config5 0x2F
#define REG_Power_Up_Reset 0x3A
#define REG_Shutdown 0x3B
#define REG_Inverse_Product_ID 0x3F
#define REG_LiftCutoff_Tune3 0x41
#define REG_Angle_Snap 0x42
#define REG_LiftCutoff_Tune1 0x4A
#define REG_Motion_Burst 0x50
#define REG_LiftCutoff_Tune_Timeout 0x58
#define REG_LiftCutoff_Tune_Min_Length 0x5A
#define REG_SROM_Load_Burst            0x62
#define REG_Lift_Config                0x63
#define REG_Raw_Data_Burst             0x64
#define REG_LiftCutoff_Tune2           0x65
#define REG_SROM_Load_Burst 0x62
#define REG_Lift_Config 0x63
#define REG_Raw_Data_Burst 0x64
#define REG_LiftCutoff_Tune2 0x65

bool _inBurst = false;


M drivers/sensors/pmw3360.h => drivers/sensors/pmw3360.h +8 -11
@@ 66,20 66,17 @@ typedef struct {
    int8_t  mdy;
} report_pmw_t;



bool spi_start_adv(void);
void spi_stop_adv(void);
bool         spi_start_adv(void);
void         spi_stop_adv(void);
spi_status_t spi_write_adv(uint8_t reg_addr, uint8_t data);
uint8_t spi_read_adv(uint8_t reg_addr);
bool pmw_spi_init(void);
void pmw_set_cpi(uint16_t cpi);
uint16_t pmw_get_cpi(void);
void pmw_upload_firmware(void);
bool pmw_check_signature(void);
uint8_t      spi_read_adv(uint8_t reg_addr);
bool         pmw_spi_init(void);
void         pmw_set_cpi(uint16_t cpi);
uint16_t     pmw_get_cpi(void);
void         pmw_upload_firmware(void);
bool         pmw_check_signature(void);
report_pmw_t pmw_read_burst(void);


#define degToRad(angleInDegrees) ((angleInDegrees)*M_PI / 180.0)
#define radToDeg(angleInRadians) ((angleInRadians)*180.0 / M_PI)
#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))

M keyboards/checkerboards/phoenix45_ortho/keymaps/via/rules.mk => keyboards/checkerboards/phoenix45_ortho/keymaps/via/rules.mk +1 -1
@@ 1,1 1,1 @@
VIA_ENABLE = yes
VIA_ENABLE = yes

M keyboards/sneakbox/ava/info.json => keyboards/sneakbox/ava/info.json +1 -1
@@ 1,4 1,4 @@
{
{
  "keyboard_name": "AVA",
  "url": "https://sneakbox.com",
  "maintainer": "mujimanic",

M platforms/chibios/drivers/analog.c => platforms/chibios/drivers/analog.c +1 -1
@@ 123,7 123,7 @@ static ADCConversionGroup adcConversionGroup = {
    .smpr  = ADC_SAMPLING_RATE,
#elif defined(USE_ADCV2)
#    if !defined(STM32F1XX)
    .cr2 = ADC_CR2_SWSTART,  // F103 seem very unhappy with, F401 seems very unhappy without...
    .cr2   = ADC_CR2_SWSTART,  // F103 seem very unhappy with, F401 seems very unhappy without...
#    endif
    .smpr2 = ADC_SMPR2_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN9(ADC_SAMPLING_RATE),
    .smpr1 = ADC_SMPR1_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN15(ADC_SAMPLING_RATE),

M quantum/action.c => quantum/action.c +45 -38
@@ 782,9 782,10 @@ void register_code(uint8_t code) {
    }
#endif

    else if IS_KEY (code) {
        // TODO: should push command_proc out of this block?
        if (command_proc(code)) return;
    else if
        IS_KEY(code) {
            // TODO: should push command_proc out of this block?
            if (command_proc(code)) return;

#ifndef NO_ACTION_ONESHOT
/* TODO: remove


@@ 801,33 802,35 @@ void register_code(uint8_t code) {
        } else
*/
#endif
        {
            // Force a new key press if the key is already pressed
            // without this, keys with the same keycode, but different
            // modifiers will be reported incorrectly, see issue #1708
            if (is_key_pressed(keyboard_report, code)) {
                del_key(code);
            {
                // Force a new key press if the key is already pressed
                // without this, keys with the same keycode, but different
                // modifiers will be reported incorrectly, see issue #1708
                if (is_key_pressed(keyboard_report, code)) {
                    del_key(code);
                    send_keyboard_report();
                }
                add_key(code);
                send_keyboard_report();
            }
            add_key(code);
        }
    else if
        IS_MOD(code) {
            add_mods(MOD_BIT(code));
            send_keyboard_report();
        }
    } else if IS_MOD (code) {
        add_mods(MOD_BIT(code));
        send_keyboard_report();
    }
#ifdef EXTRAKEY_ENABLE
    else if IS_SYSTEM (code) {
        host_system_send(KEYCODE2SYSTEM(code));
    } else if IS_CONSUMER (code) {
        host_consumer_send(KEYCODE2CONSUMER(code));
    }
    else if
        IS_SYSTEM(code) { host_system_send(KEYCODE2SYSTEM(code)); }
    else if
        IS_CONSUMER(code) { host_consumer_send(KEYCODE2CONSUMER(code)); }
#endif
#ifdef MOUSEKEY_ENABLE
    else if IS_MOUSEKEY (code) {
        mousekey_on(code);
        mousekey_send();
    }
    else if
        IS_MOUSEKEY(code) {
            mousekey_on(code);
            mousekey_send();
        }
#endif
}



@@ 872,22 875,26 @@ void unregister_code(uint8_t code) {
    }
#endif

    else if IS_KEY (code) {
        del_key(code);
        send_keyboard_report();
    } else if IS_MOD (code) {
        del_mods(MOD_BIT(code));
        send_keyboard_report();
    } else if IS_SYSTEM (code) {
        host_system_send(0);
    } else if IS_CONSUMER (code) {
        host_consumer_send(0);
    }
    else if
        IS_KEY(code) {
            del_key(code);
            send_keyboard_report();
        }
    else if
        IS_MOD(code) {
            del_mods(MOD_BIT(code));
            send_keyboard_report();
        }
    else if
        IS_SYSTEM(code) { host_system_send(0); }
    else if
        IS_CONSUMER(code) { host_consumer_send(0); }
#ifdef MOUSEKEY_ENABLE
    else if IS_MOUSEKEY (code) {
        mousekey_off(code);
        mousekey_send();
    }
    else if
        IS_MOUSEKEY(code) {
            mousekey_off(code);
            mousekey_send();
        }
#endif
}


M quantum/action.h => quantum/action.h +1 -1
@@ 88,7 88,7 @@ extern bool disable_action_cache;

/* Code for handling one-handed key modifiers. */
#ifdef SWAP_HANDS_ENABLE
extern bool                   swap_hands;
extern bool           swap_hands;
extern const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS];
#    if (MATRIX_COLS <= 8)
typedef uint8_t swap_state_row_t;

M quantum/action_tapping.c => quantum/action_tapping.c +23 -15
@@ 18,11 18,11 @@
#    define IS_TAPPING_PRESSED() (IS_TAPPING() && tapping_key.event.pressed)
#    define IS_TAPPING_RELEASED() (IS_TAPPING() && !tapping_key.event.pressed)
#    define IS_TAPPING_KEY(k) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (k)))
#ifndef COMBO_ENABLE
#    define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)))
#else
#    define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)) && tapping_key.keycode == r->keycode)
#endif
#    ifndef COMBO_ENABLE
#        define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)))
#    else
#        define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)) && tapping_key.keycode == r->keycode)
#    endif

__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { return TAPPING_TERM; }



@@ 212,11 212,15 @@ bool process_tapping(keyrecord_t *keyp) {
                    if (tapping_key.tap.count > 1) {
                        debug("Tapping: Start new tap with releasing last tap(>1).\n");
                        // unregister key
                        process_record(&(keyrecord_t){.tap = tapping_key.tap, .event.key = tapping_key.event.key, .event.time = event.time, .event.pressed = false,
#ifdef COMBO_ENABLE
                                .keycode = tapping_key.keycode,
#endif
                                });
                        process_record(&(keyrecord_t){
                            .tap           = tapping_key.tap,
                            .event.key     = tapping_key.event.key,
                            .event.time    = event.time,
                            .event.pressed = false,
#    ifdef COMBO_ENABLE
                            .keycode = tapping_key.keycode,
#    endif
                        });
                    } else {
                        debug("Tapping: Start while last tap(1).\n");
                    }


@@ 254,11 258,15 @@ bool process_tapping(keyrecord_t *keyp) {
                    if (tapping_key.tap.count > 1) {
                        debug("Tapping: Start new tap with releasing last timeout tap(>1).\n");
                        // unregister key
                        process_record(&(keyrecord_t){.tap = tapping_key.tap, .event.key = tapping_key.event.key, .event.time = event.time, .event.pressed = false,
#ifdef COMBO_ENABLE
                                .keycode = tapping_key.keycode,
#endif
                                });
                        process_record(&(keyrecord_t){
                            .tap           = tapping_key.tap,
                            .event.key     = tapping_key.event.key,
                            .event.time    = event.time,
                            .event.pressed = false,
#    ifdef COMBO_ENABLE
                            .keycode = tapping_key.keycode,
#    endif
                        });
                    } else {
                        debug("Tapping: Start while last timeout tap(1).\n");
                    }

M quantum/debounce/asym_eager_defer_pk.c => quantum/debounce/asym_eager_defer_pk.c +11 -11
@@ 46,17 46,17 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state.
#define ROW_SHIFTER ((matrix_row_t)1)

typedef struct {
    bool pressed : 1;
    bool    pressed : 1;
    uint8_t time : 7;
} debounce_counter_t;

#if DEBOUNCE > 0
static debounce_counter_t *debounce_counters;
static fast_timer_t last_time;
static bool counters_need_update;
static bool matrix_need_update;
static fast_timer_t        last_time;
static bool                counters_need_update;
static bool                matrix_need_update;

#define DEBOUNCE_ELAPSED 0
#    define DEBOUNCE_ELAPSED 0

static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time);
static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);


@@ 64,7 64,7 @@ static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], ui
// we use num_rows rather than MATRIX_ROWS to support split keyboards
void debounce_init(uint8_t num_rows) {
    debounce_counters = malloc(num_rows * MATRIX_COLS * sizeof(debounce_counter_t));
    int i = 0;
    int i             = 0;
    for (uint8_t r = 0; r < num_rows; r++) {
        for (uint8_t c = 0; c < MATRIX_COLS; c++) {
            debounce_counters[i++].time = DEBOUNCE_ELAPSED;


@@ 81,10 81,10 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool 
    bool updated_last = false;

    if (counters_need_update) {
        fast_timer_t now = timer_read_fast();
        fast_timer_t now          = timer_read_fast();
        fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);

        last_time = now;
        last_time    = now;
        updated_last = true;
        if (elapsed_time > UINT8_MAX) {
            elapsed_time = UINT8_MAX;


@@ 108,7 108,7 @@ static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[],
    debounce_counter_t *debounce_pointer = debounce_counters;

    counters_need_update = false;
    matrix_need_update = false;
    matrix_need_update   = false;

    for (uint8_t row = 0; row < num_rows; row++) {
        for (uint8_t col = 0; col < MATRIX_COLS; col++) {


@@ 146,8 146,8 @@ static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], ui
            if (delta & col_mask) {
                if (debounce_pointer->time == DEBOUNCE_ELAPSED) {
                    debounce_pointer->pressed = (raw[row] & col_mask);
                    debounce_pointer->time = DEBOUNCE;
                    counters_need_update = true;
                    debounce_pointer->time    = DEBOUNCE;
                    counters_need_update      = true;

                    if (debounce_pointer->pressed) {
                        // key-down: eager

M quantum/debounce/sym_defer_g.c => quantum/debounce/sym_defer_g.c +1 -1
@@ 25,7 25,7 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state.
#endif

#if DEBOUNCE > 0
static bool debouncing = false;
static bool         debouncing = false;
static fast_timer_t debouncing_time;

void debounce_init(uint8_t num_rows) {}

M quantum/debounce/sym_defer_pk.c => quantum/debounce/sym_defer_pk.c +3 -3
@@ 49,7 49,7 @@ static debounce_counter_t *debounce_counters;
static fast_timer_t        last_time;
static bool                counters_need_update;

#define DEBOUNCE_ELAPSED 0
#    define DEBOUNCE_ELAPSED 0

static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time);
static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);


@@ 74,10 74,10 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool 
    bool updated_last = false;

    if (counters_need_update) {
        fast_timer_t now = timer_read_fast();
        fast_timer_t now          = timer_read_fast();
        fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);

        last_time = now;
        last_time    = now;
        updated_last = true;
        if (elapsed_time > UINT8_MAX) {
            elapsed_time = UINT8_MAX;

M quantum/debounce/sym_eager_pk.c => quantum/debounce/sym_eager_pk.c +4 -4
@@ 50,7 50,7 @@ static fast_timer_t        last_time;
static bool                counters_need_update;
static bool                matrix_need_update;

#define DEBOUNCE_ELAPSED 0
#    define DEBOUNCE_ELAPSED 0

static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);


@@ 75,10 75,10 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool 
    bool updated_last = false;

    if (counters_need_update) {
        fast_timer_t now = timer_read_fast();
        fast_timer_t now          = timer_read_fast();
        fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);

        last_time = now;
        last_time    = now;
        updated_last = true;
        if (elapsed_time > UINT8_MAX) {
            elapsed_time = UINT8_MAX;


@@ 107,7 107,7 @@ static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) {
        for (uint8_t col = 0; col < MATRIX_COLS; col++) {
            if (*debounce_pointer != DEBOUNCE_ELAPSED) {
                if (*debounce_pointer <= elapsed_time) {
                    *debounce_pointer = DEBOUNCE_ELAPSED;
                    *debounce_pointer  = DEBOUNCE_ELAPSED;
                    matrix_need_update = true;
                } else {
                    *debounce_pointer -= elapsed_time;

M quantum/debounce/sym_eager_pr.c => quantum/debounce/sym_eager_pr.c +4 -4
@@ 49,7 49,7 @@ static debounce_counter_t *debounce_counters;
static fast_timer_t        last_time;
static bool                counters_need_update;

#define DEBOUNCE_ELAPSED 0
#    define DEBOUNCE_ELAPSED 0

static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);


@@ 71,10 71,10 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool 
    bool updated_last = false;

    if (counters_need_update) {
        fast_timer_t now = timer_read_fast();
        fast_timer_t now          = timer_read_fast();
        fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);

        last_time = now;
        last_time    = now;
        updated_last = true;
        if (elapsed_time > UINT8_MAX) {
            elapsed_time = UINT8_MAX;


@@ 102,7 102,7 @@ static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) {
    for (uint8_t row = 0; row < num_rows; row++) {
        if (*debounce_pointer != DEBOUNCE_ELAPSED) {
            if (*debounce_pointer <= elapsed_time) {
                *debounce_pointer = DEBOUNCE_ELAPSED;
                *debounce_pointer  = DEBOUNCE_ELAPSED;
                matrix_need_update = true;
            } else {
                *debounce_pointer -= elapsed_time;

M quantum/debounce/tests/asym_eager_defer_pk_tests.cpp => quantum/debounce/tests/asym_eager_defer_pk_tests.cpp +43 -23
@@ 19,7 19,8 @@
#include "debounce_test_common.h"

TEST_F(DebounceTest, OneKeyShort1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        /* Release key after 1ms delay */
        {1, {{0, 1, UP}}, {}},


@@ 43,7 44,8 @@ TEST_F(DebounceTest, OneKeyShort1) {
}

TEST_F(DebounceTest, OneKeyShort2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        /* Release key after 2ms delay */
        {2, {{0, 1, UP}}, {}},


@@ 58,7 60,8 @@ TEST_F(DebounceTest, OneKeyShort2) {
}

TEST_F(DebounceTest, OneKeyShort3) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        /* Release key after 3ms delay */
        {3, {{0, 1, UP}}, {}},


@@ 73,7 76,8 @@ TEST_F(DebounceTest, OneKeyShort3) {
}

TEST_F(DebounceTest, OneKeyShort4) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        /* Release key after 4ms delay */
        {4, {{0, 1, UP}}, {}},


@@ 88,7 92,8 @@ TEST_F(DebounceTest, OneKeyShort4) {
}

TEST_F(DebounceTest, OneKeyShort5) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Release key after 5ms delay */


@@ 102,7 107,8 @@ TEST_F(DebounceTest, OneKeyShort5) {
}

TEST_F(DebounceTest, OneKeyShort6) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Release key after 6ms delay */


@@ 116,7 122,8 @@ TEST_F(DebounceTest, OneKeyShort6) {
}

TEST_F(DebounceTest, OneKeyShort7) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Release key after 7ms delay */


@@ 130,7 137,8 @@ TEST_F(DebounceTest, OneKeyShort7) {
}

TEST_F(DebounceTest, OneKeyShort8) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        /* Release key after 1ms delay */
        {1, {{0, 1, UP}}, {}},


@@ 145,7 153,8 @@ TEST_F(DebounceTest, OneKeyShort8) {
}

TEST_F(DebounceTest, OneKeyShort9) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        /* Release key after 1ms delay */
        {1, {{0, 1, UP}}, {}},


@@ 159,7 168,8 @@ TEST_F(DebounceTest, OneKeyShort9) {
}

TEST_F(DebounceTest, OneKeyBouncing1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},
        {2, {{0, 1, DOWN}}, {}},


@@ 185,7 195,8 @@ TEST_F(DebounceTest, OneKeyBouncing1) {
}

TEST_F(DebounceTest, OneKeyBouncing2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        /* Change twice in the same time period */
        {1, {{0, 1, UP}}, {}},


@@ 217,7 228,8 @@ TEST_F(DebounceTest, OneKeyBouncing2) {
}

TEST_F(DebounceTest, OneKeyLong) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        {25, {{0, 1, UP}}, {}},


@@ 236,7 248,8 @@ TEST_F(DebounceTest, OneKeyLong) {
}

TEST_F(DebounceTest, TwoKeysShort) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 2, DOWN}}, {{0, 2, DOWN}}},
        /* Release key after 2ms delay */


@@ 249,14 262,14 @@ TEST_F(DebounceTest, TwoKeysShort) {
        {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */
        /* Press key again after 1ms delay */
        {11, {{0, 1, DOWN}}, {{0, 1, DOWN}, {0, 2, UP}}}, /* 5ms+5ms after DOWN at time 0 */
        {12, {{0, 2, DOWN}}, {{0, 2, DOWN}}}, /* 5ms+5ms after DOWN at time 0 */
        {12, {{0, 2, DOWN}}, {{0, 2, DOWN}}},             /* 5ms+5ms after DOWN at time 0 */
    });
    runEvents();
}


TEST_F(DebounceTest, OneKeyDelayedScan1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late, immediately release key */


@@ 269,7 282,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan1) {
}

TEST_F(DebounceTest, OneKeyDelayedScan2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late, immediately release key */


@@ 283,7 297,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan2) {
}

TEST_F(DebounceTest, OneKeyDelayedScan3) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late */


@@ 298,7 313,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan3) {
}

TEST_F(DebounceTest, OneKeyDelayedScan4) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late */


@@ 314,7 330,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan4) {
}

TEST_F(DebounceTest, OneKeyDelayedScan5) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        {5, {{0, 1, UP}}, {}},


@@ 329,7 346,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan5) {
}

TEST_F(DebounceTest, OneKeyDelayedScan6) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        {5, {{0, 1, UP}}, {}},


@@ 345,7 363,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan6) {
}

TEST_F(DebounceTest, OneKeyDelayedScan7) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        {5, {{0, 1, UP}}, {}},


@@ 358,7 377,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan7) {
}

TEST_F(DebounceTest, OneKeyDelayedScan8) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is a bit late */

M quantum/debounce/tests/debounce_test_common.cpp => quantum/debounce/tests/debounce_test_common.cpp +24 -48
@@ 31,9 31,7 @@ void set_time(uint32_t t);
void advance_time(uint32_t ms);
}

void DebounceTest::addEvents(std::initializer_list<DebounceTestEvent> events) {
    events_.insert(events_.end(), events.begin(), events.end());
}
void DebounceTest::addEvents(std::initializer_list<DebounceTestEvent> events) { events_.insert(events_.end(), events.begin(), events.end()); }

void DebounceTest::runEvents() {
    /* Run the test multiple times, from 1kHz to 10kHz scan rate */


@@ 54,7 52,7 @@ void DebounceTest::runEvents() {

void DebounceTest::runEventsInternal() {
    fast_timer_t previous = 0;
    bool first = true;
    bool         first    = true;

    /* Initialise keyboard with start time (offset to avoid testing at 0) and all keys UP */
    debounce_init(MATRIX_ROWS);


@@ 80,7 78,7 @@ void DebounceTest::runEventsInternal() {
            }
        }

        first = false;
        first    = false;
        previous = event.time_;

        /* Prepare input matrix */


@@ 98,12 96,7 @@ void DebounceTest::runEventsInternal() {

        /* Check output matrix has expected change events */
        for (auto &output : event.outputs_) {
            EXPECT_EQ(!!(cooked_matrix_[output.row_] & (1U << output.col_)), directionValue(output.direction_))
                    << "Missing event at " << strTime()
                    << " expected key " << output.row_ << "," << output.col_ << " " << directionLabel(output.direction_)
                    << "\ninput_matrix: changed=" << !event.inputs_.empty() << "\n" << strMatrix(input_matrix_)
                    << "\nexpected_matrix:\n" << strMatrix(output_matrix_)
                    << "\nactual_matrix:\n" << strMatrix(cooked_matrix_);
            EXPECT_EQ(!!(cooked_matrix_[output.row_] & (1U << output.col_)), directionValue(output.direction_)) << "Missing event at " << strTime() << " expected key " << output.row_ << "," << output.col_ << " " << directionLabel(output.direction_) << "\ninput_matrix: changed=" << !event.inputs_.empty() << "\n" << strMatrix(input_matrix_) << "\nexpected_matrix:\n" << strMatrix(output_matrix_) << "\nactual_matrix:\n" << strMatrix(cooked_matrix_);
        }

        /* Check output matrix has no other changes */


@@ 133,27 126,20 @@ void DebounceTest::runDebounce(bool changed) {
    debounce(raw_matrix_, cooked_matrix_, MATRIX_ROWS, changed);

    if (!std::equal(std::begin(input_matrix_), std::end(input_matrix_), std::begin(raw_matrix_))) {
        FAIL() << "Fatal error: debounce() modified raw matrix at " << strTime()
            << "\ninput_matrix: changed=" << changed << "\n" << strMatrix(input_matrix_)
            << "\nraw_matrix:\n" << strMatrix(raw_matrix_);
        FAIL() << "Fatal error: debounce() modified raw matrix at " << strTime() << "\ninput_matrix: changed=" << changed << "\n" << strMatrix(input_matrix_) << "\nraw_matrix:\n" << strMatrix(raw_matrix_);
    }
}

void DebounceTest::checkCookedMatrix(bool changed, const std::string &error_message) {
    if (!std::equal(std::begin(output_matrix_), std::end(output_matrix_), std::begin(cooked_matrix_))) {
        FAIL() << "Unexpected event: " << error_message << " at " << strTime()
            << "\ninput_matrix: changed=" << changed << "\n" << strMatrix(input_matrix_)
            << "\nexpected_matrix:\n" << strMatrix(output_matrix_)
            << "\nactual_matrix:\n" << strMatrix(cooked_matrix_);
        FAIL() << "Unexpected event: " << error_message << " at " << strTime() << "\ninput_matrix: changed=" << changed << "\n" << strMatrix(input_matrix_) << "\nexpected_matrix:\n" << strMatrix(output_matrix_) << "\nactual_matrix:\n" << strMatrix(cooked_matrix_);
    }
}

std::string DebounceTest::strTime() {
    std::stringstream text;

    text << "time " << (timer_read_fast() - time_offset_)
        << " (extra_iterations=" << extra_iterations_
        << ", auto_advance_time=" << auto_advance_time_ << ")";
    text << "time " << (timer_read_fast() - time_offset_) << " (extra_iterations=" << extra_iterations_ << ", auto_advance_time=" << auto_advance_time_ << ")";

    return text.str();
}


@@ 181,49 167,39 @@ std::string DebounceTest::strMatrix(matrix_row_t matrix[]) {

bool DebounceTest::directionValue(Direction direction) {
    switch (direction) {
    case DOWN:
        return true;
        case DOWN:
            return true;

    case UP:
        return false;
        case UP:
            return false;
    }
}

std::string DebounceTest::directionLabel(Direction direction) {
    switch (direction) {
    case DOWN:
        return "DOWN";
        case DOWN:
            return "DOWN";

    case UP:
        return "UP";
        case UP:
            return "UP";
    }
}

/* Modify a matrix and verify that events always specify a change */
void DebounceTest::matrixUpdate(matrix_row_t matrix[], const std::string &name, const MatrixTestEvent &event) {
    ASSERT_NE(!!(matrix[event.row_] & (1U << event.col_)), directionValue(event.direction_))
        << "Test " << name << " at " << strTime()
        << " sets key " << event.row_ << "," << event.col_ << " " << directionLabel(event.direction_)
        << " but it is already " << directionLabel(event.direction_)
        << "\n" << name << "_matrix:\n" << strMatrix(matrix);
    ASSERT_NE(!!(matrix[event.row_] & (1U << event.col_)), directionValue(event.direction_)) << "Test " << name << " at " << strTime() << " sets key " << event.row_ << "," << event.col_ << " " << directionLabel(event.direction_) << " but it is already " << directionLabel(event.direction_) << "\n" << name << "_matrix:\n" << strMatrix(matrix);

    switch (event.direction_) {
    case DOWN:
        matrix[event.row_] |= (1U << event.col_);
        break;
        case DOWN:
            matrix[event.row_] |= (1U << event.col_);
            break;

    case UP:
        matrix[event.row_] &= ~(1U << event.col_);
        break;
        case UP:
            matrix[event.row_] &= ~(1U << event.col_);
            break;
    }
}

DebounceTestEvent::DebounceTestEvent(fast_timer_t time,
        std::initializer_list<MatrixTestEvent> inputs,
        std::initializer_list<MatrixTestEvent> outputs)
        : time_(time), inputs_(inputs), outputs_(outputs) {
}
DebounceTestEvent::DebounceTestEvent(fast_timer_t time, std::initializer_list<MatrixTestEvent> inputs, std::initializer_list<MatrixTestEvent> outputs) : time_(time), inputs_(inputs), outputs_(outputs) {}

MatrixTestEvent::MatrixTestEvent(int row, int col, Direction direction)
        : row_(row), col_(col), direction_(direction) {
}
MatrixTestEvent::MatrixTestEvent(int row, int col, Direction direction) : row_(row), col_(col), direction_(direction) {}

M quantum/debounce/tests/debounce_test_common.h => quantum/debounce/tests/debounce_test_common.h +11 -13
@@ 31,36 31,34 @@ enum Direction {
};

class MatrixTestEvent {
public:
   public:
    MatrixTestEvent(int row, int col, Direction direction);

    const int row_;
    const int col_;
    const int       row_;
    const int       col_;
    const Direction direction_;
};

class DebounceTestEvent {
public:
   public:
    // 0, {{0, 1, DOWN}}, {{0, 1, DOWN}})
    DebounceTestEvent(fast_timer_t time,
        std::initializer_list<MatrixTestEvent> inputs,
        std::initializer_list<MatrixTestEvent> outputs);
    DebounceTestEvent(fast_timer_t time, std::initializer_list<MatrixTestEvent> inputs, std::initializer_list<MatrixTestEvent> outputs);

    const fast_timer_t time_;
    const fast_timer_t               time_;
    const std::list<MatrixTestEvent> inputs_;
    const std::list<MatrixTestEvent> outputs_;
};

class DebounceTest : public ::testing::Test {
protected:
   protected:
    void addEvents(std::initializer_list<DebounceTestEvent> events);
    void runEvents();

    fast_timer_t time_offset_ = 7777;
    bool time_jumps_ = false;
    bool         time_jumps_  = false;

private:
    static bool directionValue(Direction direction);
   private:
    static bool        directionValue(Direction direction);
    static std::string directionLabel(Direction direction);

    void runEventsInternal();


@@ 78,6 76,6 @@ private:
    matrix_row_t cooked_matrix_[MATRIX_ROWS];
    matrix_row_t output_matrix_[MATRIX_ROWS];

    int extra_iterations_;
    int  extra_iterations_;
    bool auto_advance_time_;
};

M quantum/debounce/tests/sym_defer_g_tests.cpp => quantum/debounce/tests/sym_defer_g_tests.cpp +30 -15
@@ 19,7 19,8 @@
#include "debounce_test_common.h"

TEST_F(DebounceTest, OneKeyShort1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        {5, {}, {{0, 1, DOWN}}},


@@ 32,7 33,8 @@ TEST_F(DebounceTest, OneKeyShort1) {
}

TEST_F(DebounceTest, OneKeyShort2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        {5, {}, {{0, 1, DOWN}}},


@@ 45,7 47,8 @@ TEST_F(DebounceTest, OneKeyShort2) {
}

TEST_F(DebounceTest, OneKeyShort3) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        {5, {}, {{0, 1, DOWN}}},


@@ 58,7 61,8 @@ TEST_F(DebounceTest, OneKeyShort3) {
}

TEST_F(DebounceTest, OneKeyTooQuick1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},
        /* Release key exactly on the debounce time */
        {5, {{0, 1, UP}}, {}},


@@ 67,7 71,8 @@ TEST_F(DebounceTest, OneKeyTooQuick1) {
}

TEST_F(DebounceTest, OneKeyTooQuick2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        {5, {}, {{0, 1, DOWN}}},


@@ 80,7 85,8 @@ TEST_F(DebounceTest, OneKeyTooQuick2) {
}

TEST_F(DebounceTest, OneKeyBouncing1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},
        {1, {{0, 1, UP}}, {}},
        {2, {{0, 1, DOWN}}, {}},


@@ 94,7 100,8 @@ TEST_F(DebounceTest, OneKeyBouncing1) {
}

TEST_F(DebounceTest, OneKeyBouncing2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},
        {5, {}, {{0, 1, DOWN}}},
        {6, {{0, 1, UP}}, {}},


@@ 108,7 115,8 @@ TEST_F(DebounceTest, OneKeyBouncing2) {
}

TEST_F(DebounceTest, OneKeyLong) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        {5, {}, {{0, 1, DOWN}}},


@@ 125,7 133,8 @@ TEST_F(DebounceTest, OneKeyLong) {
}

TEST_F(DebounceTest, TwoKeysShort) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},
        {1, {{0, 2, DOWN}}, {}},



@@ 140,7 149,8 @@ TEST_F(DebounceTest, TwoKeysShort) {
}

TEST_F(DebounceTest, TwoKeysSimultaneous1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {}},

        {5, {}, {{0, 1, DOWN}, {0, 2, DOWN}}},


@@ 152,7 162,8 @@ TEST_F(DebounceTest, TwoKeysSimultaneous1) {
}

TEST_F(DebounceTest, TwoKeysSimultaneous2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},
        {1, {{0, 2, DOWN}}, {}},



@@ 167,7 178,8 @@ TEST_F(DebounceTest, TwoKeysSimultaneous2) {
}

TEST_F(DebounceTest, OneKeyDelayedScan1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        /* Processing is very late */


@@ 182,7 194,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan1) {
}

TEST_F(DebounceTest, OneKeyDelayedScan2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        /* Processing is very late */


@@ 197,7 210,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan2) {
}

TEST_F(DebounceTest, OneKeyDelayedScan3) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        /* Release key before debounce expires */


@@ 208,7 222,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan3) {
}

TEST_F(DebounceTest, OneKeyDelayedScan4) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        /* Processing is a bit late */

M quantum/debounce/tests/sym_defer_pk_tests.cpp => quantum/debounce/tests/sym_defer_pk_tests.cpp +30 -15
@@ 19,7 19,8 @@
#include "debounce_test_common.h"

TEST_F(DebounceTest, OneKeyShort1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        {5, {}, {{0, 1, DOWN}}},


@@ 32,7 33,8 @@ TEST_F(DebounceTest, OneKeyShort1) {
}

TEST_F(DebounceTest, OneKeyShort2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        {5, {}, {{0, 1, DOWN}}},


@@ 45,7 47,8 @@ TEST_F(DebounceTest, OneKeyShort2) {
}

TEST_F(DebounceTest, OneKeyShort3) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        {5, {}, {{0, 1, DOWN}}},


@@ 58,7 61,8 @@ TEST_F(DebounceTest, OneKeyShort3) {
}

TEST_F(DebounceTest, OneKeyTooQuick1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},
        /* Release key exactly on the debounce time */
        {5, {{0, 1, UP}}, {}},


@@ 67,7 71,8 @@ TEST_F(DebounceTest, OneKeyTooQuick1) {
}

TEST_F(DebounceTest, OneKeyTooQuick2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        {5, {}, {{0, 1, DOWN}}},


@@ 80,7 85,8 @@ TEST_F(DebounceTest, OneKeyTooQuick2) {
}

TEST_F(DebounceTest, OneKeyBouncing1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},
        {1, {{0, 1, UP}}, {}},
        {2, {{0, 1, DOWN}}, {}},


@@ 94,7 100,8 @@ TEST_F(DebounceTest, OneKeyBouncing1) {
}

TEST_F(DebounceTest, OneKeyBouncing2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},
        {5, {}, {{0, 1, DOWN}}},
        {6, {{0, 1, UP}}, {}},


@@ 108,7 115,8 @@ TEST_F(DebounceTest, OneKeyBouncing2) {
}

TEST_F(DebounceTest, OneKeyLong) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        {5, {}, {{0, 1, DOWN}}},


@@ 125,7 133,8 @@ TEST_F(DebounceTest, OneKeyLong) {
}

TEST_F(DebounceTest, TwoKeysShort) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},
        {1, {{0, 2, DOWN}}, {}},



@@ 142,7 151,8 @@ TEST_F(DebounceTest, TwoKeysShort) {
}

TEST_F(DebounceTest, TwoKeysSimultaneous1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {}},

        {5, {}, {{0, 1, DOWN}, {0, 2, DOWN}}},


@@ 154,7 164,8 @@ TEST_F(DebounceTest, TwoKeysSimultaneous1) {
}

TEST_F(DebounceTest, TwoKeysSimultaneous2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},
        {1, {{0, 2, DOWN}}, {}},



@@ 169,7 180,8 @@ TEST_F(DebounceTest, TwoKeysSimultaneous2) {
}

TEST_F(DebounceTest, OneKeyDelayedScan1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        /* Processing is very late */


@@ 184,7 196,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan1) {
}

TEST_F(DebounceTest, OneKeyDelayedScan2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        /* Processing is very late */


@@ 199,7 212,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan2) {
}

TEST_F(DebounceTest, OneKeyDelayedScan3) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        /* Release key before debounce expires */


@@ 210,7 224,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan3) {
}

TEST_F(DebounceTest, OneKeyDelayedScan4) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {}},

        /* Processing is a bit late */

M quantum/debounce/tests/sym_eager_pk_tests.cpp => quantum/debounce/tests/sym_eager_pk_tests.cpp +32 -16
@@ 19,7 19,8 @@
#include "debounce_test_common.h"

TEST_F(DebounceTest, OneKeyShort1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},



@@ 32,7 33,8 @@ TEST_F(DebounceTest, OneKeyShort1) {
}

TEST_F(DebounceTest, OneKeyShort2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},



@@ 45,7 47,8 @@ TEST_F(DebounceTest, OneKeyShort2) {
}

TEST_F(DebounceTest, OneKeyShort3) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},



@@ 58,7 61,8 @@ TEST_F(DebounceTest, OneKeyShort3) {
}

TEST_F(DebounceTest, OneKeyShort4) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},



@@ 71,7 75,8 @@ TEST_F(DebounceTest, OneKeyShort4) {
}

TEST_F(DebounceTest, OneKeyShort5) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},



@@ 83,7 88,8 @@ TEST_F(DebounceTest, OneKeyShort5) {
}

TEST_F(DebounceTest, OneKeyShort6) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},



@@ 95,7 101,8 @@ TEST_F(DebounceTest, OneKeyShort6) {
}

TEST_F(DebounceTest, OneKeyBouncing1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},
        {2, {{0, 1, DOWN}}, {}},


@@ 110,7 117,8 @@ TEST_F(DebounceTest, OneKeyBouncing1) {
}

TEST_F(DebounceTest, OneKeyBouncing2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        /* Change twice in the same time period */
        {1, {{0, 1, UP}}, {}},


@@ 135,7 143,8 @@ TEST_F(DebounceTest, OneKeyBouncing2) {
}

TEST_F(DebounceTest, OneKeyLong) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        {25, {{0, 1, UP}}, {{0, 1, UP}}},


@@ 146,7 155,8 @@ TEST_F(DebounceTest, OneKeyLong) {
}

TEST_F(DebounceTest, TwoKeysShort) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},
        {2, {{0, 2, DOWN}}, {{0, 2, DOWN}}},


@@ 167,7 177,8 @@ TEST_F(DebounceTest, TwoKeysShort) {
}

TEST_F(DebounceTest, OneKeyDelayedScan1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late but the change will now be accepted */


@@ 178,7 189,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan1) {
}

TEST_F(DebounceTest, OneKeyDelayedScan2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late but the change will now be accepted even with a 1 scan delay */


@@ 190,7 202,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan2) {
}

TEST_F(DebounceTest, OneKeyDelayedScan3) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late but the change will now be accepted even with a 1ms delay */


@@ 202,7 215,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan3) {
}

TEST_F(DebounceTest, OneKeyDelayedScan4) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is a bit late but the change will now be accepted */


@@ 213,7 227,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan4) {
}

TEST_F(DebounceTest, OneKeyDelayedScan5) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late but the change will now be accepted even with a 1 scan delay */


@@ 225,7 240,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan5) {
}

TEST_F(DebounceTest, OneKeyDelayedScan6) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late but the change will now be accepted even with a 1ms delay */

M quantum/debounce/tests/sym_eager_pr_tests.cpp => quantum/debounce/tests/sym_eager_pr_tests.cpp +38 -19
@@ 19,7 19,8 @@
#include "debounce_test_common.h"

TEST_F(DebounceTest, OneKeyShort1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},



@@ 32,7 33,8 @@ TEST_F(DebounceTest, OneKeyShort1) {
}

TEST_F(DebounceTest, OneKeyShort2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},



@@ 45,7 47,8 @@ TEST_F(DebounceTest, OneKeyShort2) {
}

TEST_F(DebounceTest, OneKeyShort3) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},



@@ 58,7 61,8 @@ TEST_F(DebounceTest, OneKeyShort3) {
}

TEST_F(DebounceTest, OneKeyShort4) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},



@@ 71,7 75,8 @@ TEST_F(DebounceTest, OneKeyShort4) {
}

TEST_F(DebounceTest, OneKeyShort5) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},



@@ 83,7 88,8 @@ TEST_F(DebounceTest, OneKeyShort5) {
}

TEST_F(DebounceTest, OneKeyShort6) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},



@@ 95,7 101,8 @@ TEST_F(DebounceTest, OneKeyShort6) {
}

TEST_F(DebounceTest, OneKeyBouncing1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},
        {2, {{0, 1, DOWN}}, {}},


@@ 110,7 117,8 @@ TEST_F(DebounceTest, OneKeyBouncing1) {
}

TEST_F(DebounceTest, OneKeyBouncing2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        /* Change twice in the same time period */
        {1, {{0, 1, UP}}, {}},


@@ 135,7 143,8 @@ TEST_F(DebounceTest, OneKeyBouncing2) {
}

TEST_F(DebounceTest, OneKeyLong) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        {25, {{0, 1, UP}}, {{0, 1, UP}}},


@@ 146,7 155,8 @@ TEST_F(DebounceTest, OneKeyLong) {
}

TEST_F(DebounceTest, TwoRowsShort) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},
        {2, {{2, 0, DOWN}}, {{2, 0, DOWN}}},


@@ 167,7 177,8 @@ TEST_F(DebounceTest, TwoRowsShort) {
}

TEST_F(DebounceTest, TwoKeysOverlap) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
        {1, {{0, 1, UP}}, {}},
        /* Press a second key during the first debounce */


@@ 190,7 201,8 @@ TEST_F(DebounceTest, TwoKeysOverlap) {
}

TEST_F(DebounceTest, TwoKeysSimultaneous1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {{0, 1, DOWN}, {0, 2, DOWN}}},
        {20, {{0, 1, UP}}, {{0, 1, UP}}},
        {21, {{0, 2, UP}}, {}},


@@ 202,7 214,8 @@ TEST_F(DebounceTest, TwoKeysSimultaneous1) {
}

TEST_F(DebounceTest, TwoKeysSimultaneous2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {{0, 1, DOWN}, {0, 2, DOWN}}},
        {20, {{0, 1, UP}, {0, 2, UP}}, {{0, 1, UP}, {0, 2, UP}}},
    });


@@ 210,7 223,8 @@ TEST_F(DebounceTest, TwoKeysSimultaneous2) {
}

TEST_F(DebounceTest, OneKeyDelayedScan1) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late but the change will now be accepted */


@@ 221,7 235,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan1) {
}

TEST_F(DebounceTest, OneKeyDelayedScan2) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late but the change will now be accepted even with a 1 scan delay */


@@ 233,7 248,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan2) {
}

TEST_F(DebounceTest, OneKeyDelayedScan3) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late but the change will now be accepted even with a 1ms delay */


@@ 245,7 261,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan3) {
}

TEST_F(DebounceTest, OneKeyDelayedScan4) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is a bit late but the change will now be accepted */


@@ 256,7 273,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan4) {
}

TEST_F(DebounceTest, OneKeyDelayedScan5) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late but the change will now be accepted even with a 1 scan delay */


@@ 268,7 286,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan5) {
}

TEST_F(DebounceTest, OneKeyDelayedScan6) {
    addEvents({ /* Time, Inputs, Outputs */
    addEvents({
        /* Time, Inputs, Outputs */
        {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},

        /* Processing is very late but the change will now be accepted even with a 1ms delay */

M quantum/keymap_extras/keymap_steno.h => quantum/keymap_extras/keymap_steno.h +1 -2
@@ 74,8 74,7 @@ enum steno_keycodes {
};

#ifdef STENO_COMBINEDMAP
enum steno_combined_keycodes
{
enum steno_combined_keycodes {
    STN_S3 = QK_STENO_COMB,
    STN_TKL,
    STN_PWL,

M quantum/process_keycode/process_combo.c => quantum/process_keycode/process_combo.c +95 -89
@@ 18,10 18,9 @@
#include "process_combo.h"
#include "action_tapping.h"


#ifdef COMBO_COUNT
__attribute__((weak)) combo_t  key_combos[COMBO_COUNT];
uint16_t COMBO_LEN = COMBO_COUNT;
__attribute__((weak)) combo_t key_combos[COMBO_COUNT];
uint16_t                      COMBO_LEN = COMBO_COUNT;
#else
extern combo_t  key_combos[];
extern uint16_t COMBO_LEN;


@@ 46,64 45,86 @@ __attribute__((weak)) bool process_combo_key_release(uint16_t combo_index, combo
#endif

#ifndef COMBO_NO_TIMER
static uint16_t timer                 = 0;
static uint16_t timer = 0;
#endif
static bool     b_combo_enable        = true;  // defaults to enabled
static uint16_t longest_term          = 0;
static bool     b_combo_enable = true;  // defaults to enabled
static uint16_t longest_term   = 0;

typedef struct {
    keyrecord_t record;
    uint16_t combo_index;
    uint16_t keycode;
    uint16_t    combo_index;
    uint16_t    keycode;
} queued_record_t;
static uint8_t key_buffer_size = 0;
static uint8_t         key_buffer_size = 0;
static queued_record_t key_buffer[COMBO_KEY_BUFFER_LENGTH];

typedef struct {
    uint16_t combo_index;
} queued_combo_t;
static uint8_t combo_buffer_write= 0;
static uint8_t combo_buffer_read = 0;
static uint8_t        combo_buffer_write = 0;
static uint8_t        combo_buffer_read  = 0;
static queued_combo_t combo_buffer[COMBO_BUFFER_LENGTH];

#define INCREMENT_MOD(i) i = (i + 1) % COMBO_BUFFER_LENGTH

#define COMBO_KEY_POS ((keypos_t){.col=254, .row=254})

#define COMBO_KEY_POS ((keypos_t){.col = 254, .row = 254})

#ifndef EXTRA_SHORT_COMBOS
/* flags are their own elements in combo_t struct. */
#    define COMBO_ACTIVE(combo)   (combo->active)
#    define COMBO_ACTIVE(combo) (combo->active)
#    define COMBO_DISABLED(combo) (combo->disabled)
#    define COMBO_STATE(combo)    (combo->state)

#    define ACTIVATE_COMBO(combo)    do {combo->active = true;}while(0)
#    define DEACTIVATE_COMBO(combo)  do {combo->active = false;}while(0)
#    define DISABLE_COMBO(combo)     do {combo->disabled = true;}while(0)
#    define RESET_COMBO_STATE(combo) do { \
    combo->disabled = false; \
    combo->state = 0; \
}while(0)
#    define COMBO_STATE(combo) (combo->state)

#    define ACTIVATE_COMBO(combo) \
        do {                      \
            combo->active = true; \
        } while (0)
#    define DEACTIVATE_COMBO(combo) \
        do {                        \
            combo->active = false;  \
        } while (0)
#    define DISABLE_COMBO(combo)    \
        do {                        \
            combo->disabled = true; \
        } while (0)
#    define RESET_COMBO_STATE(combo) \
        do {                         \
            combo->disabled = false; \
            combo->state    = 0;     \
        } while (0)
#else
/* flags are at the two high bits of state. */
#    define COMBO_ACTIVE(combo)   (combo->state & 0x80)
#    define COMBO_ACTIVE(combo) (combo->state & 0x80)
#    define COMBO_DISABLED(combo) (combo->state & 0x40)
#    define COMBO_STATE(combo)    (combo->state & 0x3F)

#    define ACTIVATE_COMBO(combo)    do {combo->state |= 0x80;}while(0)
#    define DEACTIVATE_COMBO(combo)  do {combo->state &= ~0x80;}while(0)
#    define DISABLE_COMBO(combo)     do {combo->state |= 0x40;}while(0)
#    define RESET_COMBO_STATE(combo) do {combo->state &= ~0x7F;}while(0)
#    define COMBO_STATE(combo) (combo->state & 0x3F)

#    define ACTIVATE_COMBO(combo) \
        do {                      \
            combo->state |= 0x80; \
        } while (0)
#    define DEACTIVATE_COMBO(combo) \
        do {                        \
            combo->state &= ~0x80;  \
        } while (0)
#    define DISABLE_COMBO(combo)  \
        do {                      \
            combo->state |= 0x40; \
        } while (0)
#    define RESET_COMBO_STATE(combo) \
        do {                         \
            combo->state &= ~0x7F;   \
        } while (0)
#endif

static inline void release_combo(uint16_t combo_index, combo_t *combo) {
    if (combo->keycode) {
        keyrecord_t record = {
            .event = {
                .key = COMBO_KEY_POS,
                .time = timer_read()|1,
                .pressed = false,
            },
            .event =
                {
                    .key     = COMBO_KEY_POS,
                    .time    = timer_read() | 1,
                    .pressed = false,
                },
            .keycode = combo->keycode,
        };
#ifndef NO_ACTION_TAPPING


@@ 123,18 144,17 @@ static inline bool _get_combo_must_hold(uint16_t combo_index, combo_t *combo) {
#elif defined(COMBO_MUST_HOLD_PER_COMBO)
    return get_combo_must_hold(combo_index, combo);
#elif defined(COMBO_MUST_HOLD_MODS)
    return (KEYCODE_IS_MOD(combo->keycode) ||
            (combo->keycode >= QK_MOMENTARY && combo->keycode <= QK_MOMENTARY_MAX));
    return (KEYCODE_IS_MOD(combo->keycode) || (combo->keycode >= QK_MOMENTARY && combo->keycode <= QK_MOMENTARY_MAX));
#endif
    return false;
}

static inline uint16_t _get_wait_time(uint16_t combo_index, combo_t *combo ) {
static inline uint16_t _get_wait_time(uint16_t combo_index, combo_t *combo) {
    if (_get_combo_must_hold(combo_index, combo)
#ifdef COMBO_MUST_TAP_PER_COMBO
            || get_combo_must_tap(combo_index, combo)
        || get_combo_must_tap(combo_index, combo)
#endif
       ) {
    ) {
        if (longest_term < COMBO_HOLD_TERM) {
            return COMBO_HOLD_TERM;
        }


@@ 144,9 164,8 @@ static inline uint16_t _get_wait_time(uint16_t combo_index, combo_t *combo ) {
}

static inline uint16_t _get_combo_term(uint16_t combo_index, combo_t *combo) {

#if defined(COMBO_TERM_PER_COMBO)
        return get_combo_term(combo_index, combo);
    return get_combo_term(combo_index, combo);
#endif

    return COMBO_TERM;


@@ 154,7 173,7 @@ static inline uint16_t _get_combo_term(uint16_t combo_index, combo_t *combo) {

void clear_combos(void) {
    uint16_t index = 0;
    longest_term = 0;
    longest_term   = 0;
    for (index = 0; index < COMBO_LEN; ++index) {
        combo_t *combo = &key_combos[index];
        if (!COMBO_ACTIVE(combo)) {


@@ 175,7 194,7 @@ static inline void dump_key_buffer(void) {
        key_buffer_next = key_buffer_i + 1;

        queued_record_t *qrecord = &key_buffer[key_buffer_i];
        keyrecord_t *record = &qrecord->record;
        keyrecord_t *    record  = &qrecord->record;

        if (IS_NOEVENT(record->event)) {
            continue;


@@ 185,9 204,9 @@ static inline void dump_key_buffer(void) {
            process_combo_event(qrecord->combo_index, true);
        } else {
#ifndef NO_ACTION_TAPPING
        action_tapping_process(*record);
            action_tapping_process(*record);
#else
        process_record(record);
            process_record(record);
#endif
        }
        record->event.time = 0;


@@ 242,7 261,9 @@ void apply_combo(uint16_t combo_index, combo_t *combo) {
    /* Apply combo's result keycode to the last chord key of the combo and
     * disable the other keys. */

    if (COMBO_DISABLED(combo)) { return; }
    if (COMBO_DISABLED(combo)) {
        return;
    }

    // state to check against so we find the last key of the combo from the buffer
#if defined(EXTRA_EXTRA_LONG_COMBOS)


@@ 254,12 275,11 @@ void apply_combo(uint16_t combo_index, combo_t *combo) {
#endif

    for (uint8_t key_buffer_i = 0; key_buffer_i < key_buffer_size; key_buffer_i++) {

        queued_record_t *qrecord = &key_buffer[key_buffer_i];
        keyrecord_t *record = &qrecord->record;
        uint16_t keycode = qrecord->keycode;
        keyrecord_t *    record  = &qrecord->record;
        uint16_t         keycode = qrecord->keycode;

        uint8_t key_count = 0;
        uint8_t  key_count = 0;
        uint16_t key_index = -1;
        _find_key_index_and_count(combo->keys, keycode, &key_index, &key_count);



@@ 271,7 291,7 @@ void apply_combo(uint16_t combo_index, combo_t *combo) {
        KEY_STATE_DOWN(state, key_index);
        if (ALL_COMBO_KEYS_ARE_DOWN(state, key_count)) {
            // this in the end executes the combo when the key_buffer is dumped.
            record->keycode = combo->keycode;
            record->keycode   = combo->keycode;
            record->event.key = COMBO_KEY_POS;

            qrecord->combo_index = combo_index;


@@ 283,19 303,15 @@ void apply_combo(uint16_t combo_index, combo_t *combo) {
            // by making it a TICK event.
            record->event.time = 0;
        }

    }
    drop_combo_from_buffer(combo_index);
}

static inline void apply_combos(void) {
    // Apply all buffered normal combos.
    for (uint8_t i = combo_buffer_read;
            i != combo_buffer_write;
            INCREMENT_MOD(i)) {

    for (uint8_t i = combo_buffer_read; i != combo_buffer_write; INCREMENT_MOD(i)) {
        queued_combo_t *buffered_combo = &combo_buffer[i];
        combo_t *combo = &key_combos[buffered_combo->combo_index];
        combo_t *       combo          = &key_combos[buffered_combo->combo_index];

#ifdef COMBO_MUST_TAP_PER_COMBO
        if (get_combo_must_tap(buffered_combo->combo_index, combo)) {


@@ 310,15 326,15 @@ static inline void apply_combos(void) {
    clear_combos();
}

combo_t* overlaps(combo_t *combo1, combo_t *combo2) {
combo_t *overlaps(combo_t *combo1, combo_t *combo2) {
    /* Checks if the combos overlap and returns the combo that should be
     * dropped from the combo buffer.
     * The combo that has less keys will be dropped. If they have the same
     * amount of keys, drop combo1. */

    uint8_t idx1 = 0, idx2 = 0;
    uint8_t  idx1 = 0, idx2 = 0;
    uint16_t key1, key2;
    bool overlaps = false;
    bool     overlaps = false;

    while ((key1 = pgm_read_word(&combo1->keys[idx1])) != COMBO_END) {
        idx2 = 0;


@@ 335,7 351,7 @@ combo_t* overlaps(combo_t *combo1, combo_t *combo2) {
}

static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *record, uint16_t combo_index) {
    uint8_t key_count = 0;
    uint8_t  key_count = 0;
    uint16_t key_index = -1;
    _find_key_index_and_count(combo->keys, keycode, &key_index, &key_count);



@@ 369,12 385,9 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *

                // disable readied combos that overlap with this combo
                combo_t *drop = NULL;
                for (uint8_t combo_buffer_i = combo_buffer_read;
                        combo_buffer_i != combo_buffer_write;
                        INCREMENT_MOD(combo_buffer_i)) {

                    queued_combo_t *qcombo = &combo_buffer[combo_buffer_i];
                    combo_t *buffered_combo = &key_combos[qcombo->combo_index];
                for (uint8_t combo_buffer_i = combo_buffer_read; combo_buffer_i != combo_buffer_write; INCREMENT_MOD(combo_buffer_i)) {
                    queued_combo_t *qcombo         = &combo_buffer[combo_buffer_i];
                    combo_t *       buffered_combo = &key_combos[qcombo->combo_index];

                    if ((drop = overlaps(buffered_combo, combo))) {
                        DISABLE_COMBO(drop);


@@ 387,21 400,19 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
                            INCREMENT_MOD(combo_buffer_read);
                        }
                    }

                }

                if (drop != combo) {
                    // save this combo to buffer
                    combo_buffer[combo_buffer_write] = (queued_combo_t){
                        .combo_index=combo_index,
                        .combo_index = combo_index,
                    };
                    INCREMENT_MOD(combo_buffer_write);

                    // get possible longer waiting time for tap-/hold-only combos.
                    longest_term = _get_wait_time(combo_index, combo);
                }
            } // if timer elapsed end

            }  // if timer elapsed end
        }
    } else {
        // chord releases


@@ 416,7 427,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
            else if (get_combo_must_tap(combo_index, combo)) {
                // immediately apply tap-only combo
                apply_combo(combo_index, combo);
                apply_combos(); // also apply other prepared combos and dump key buffer
                apply_combos();  // also apply other prepared combos and dump key buffer
#    ifdef COMBO_PROCESS_KEY_RELEASE
                if (process_combo_key_release(combo_index, combo, key_index, keycode)) {
                    release_combo(combo_index, combo);


@@ 424,10 435,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
#    endif
            }
#endif
        } else if (COMBO_ACTIVE(combo)
                && ONLY_ONE_KEY_IS_DOWN(COMBO_STATE(combo))
                && KEY_NOT_YET_RELEASED(COMBO_STATE(combo), key_index)
                ) {
        } else if (COMBO_ACTIVE(combo) && ONLY_ONE_KEY_IS_DOWN(COMBO_STATE(combo)) && KEY_NOT_YET_RELEASED(COMBO_STATE(combo), key_index)) {
            /* last key released */
            release_combo(combo_index, combo);
            key_is_part_of_combo = true;


@@ 435,9 443,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
#ifdef COMBO_PROCESS_KEY_RELEASE
            process_combo_key_release(combo_index, combo, key_index, keycode);
#endif
        } else if (COMBO_ACTIVE(combo)
                && KEY_NOT_YET_RELEASED(COMBO_STATE(combo), key_index)
                ) {
        } else if (COMBO_ACTIVE(combo) && KEY_NOT_YET_RELEASED(COMBO_STATE(combo), key_index)) {
            /* first or middle key released */
            key_is_part_of_combo = true;



@@ 489,21 495,21 @@ bool process_combo(uint16_t keycode, keyrecord_t *record) {

    if (record->event.pressed && is_combo_key) {
#ifndef COMBO_NO_TIMER
#   ifdef COMBO_STRICT_TIMER
#    ifdef COMBO_STRICT_TIMER
        if (!timer) {
            // timer is set only on the first key
            timer = timer_read();
        }
#   else
#    else
        timer = timer_read();
#   endif
#    endif
#endif

        if (key_buffer_size < COMBO_KEY_BUFFER_LENGTH) {
            key_buffer[key_buffer_size++] = (queued_record_t){
                .record = *record,
                .keycode = keycode,
                .combo_index = -1, // this will be set when applying combos
                .record      = *record,
                .keycode     = keycode,
                .combo_index = -1,  // this will be set when applying combos
            };
        }
    } else {


@@ 532,7 538,7 @@ void combo_task(void) {
        if (combo_buffer_read != combo_buffer_write) {
            apply_combos();
            longest_term = 0;
            timer = 0;
            timer        = 0;
        } else {
            dump_key_buffer();
            timer = 0;


@@ 546,9 552,9 @@ void combo_enable(void) { b_combo_enable = true; }

void combo_disable(void) {
#ifndef COMBO_NO_TIMER
    timer                      = 0;
    timer = 0;
#endif
    b_combo_enable = false;
    b_combo_enable    = false;
    combo_buffer_read = combo_buffer_write;
    clear_combos();
    dump_key_buffer();

M quantum/process_keycode/process_combo.h => quantum/process_keycode/process_combo.h +2 -2
@@ 43,8 43,8 @@ typedef struct {
#ifdef EXTRA_SHORT_COMBOS
    uint8_t state;
#else
    bool disabled;
    bool active;
    bool     disabled;
    bool     active;
#    if defined(EXTRA_EXTRA_LONG_COMBOS)
    uint32_t state;
#    elif defined(EXTRA_LONG_COMBOS)

M quantum/process_keycode/process_steno.c => quantum/process_keycode/process_steno.c +4 -5
@@ 67,7 67,7 @@ static const uint8_t boltmap[64] PROGMEM = {TXB_NUL, TXB_NUM, TXB_NUM, TXB_NUM, 

#ifdef STENO_COMBINEDMAP
/* Used to look up when pressing the middle row key to combine two consonant or vowel keys */
static const uint16_t combinedmap_first[] PROGMEM = {STN_S1, STN_TL, STN_PL, STN_HL, STN_FR, STN_PR, STN_LR, STN_TR, STN_DR, STN_A, STN_E};
static const uint16_t combinedmap_first[] PROGMEM  = {STN_S1, STN_TL, STN_PL, STN_HL, STN_FR, STN_PR, STN_LR, STN_TR, STN_DR, STN_A, STN_E};
static const uint16_t combinedmap_second[] PROGMEM = {STN_S2, STN_KL, STN_WL, STN_RL, STN_RR, STN_BR, STN_GR, STN_SR, STN_ZR, STN_O, STN_U};
#endif



@@ 174,11 174,10 @@ bool process_steno(uint16_t keycode, keyrecord_t *record) {
            return false;

#ifdef STENO_COMBINEDMAP
        case QK_STENO_COMB ... QK_STENO_COMB_MAX:
        {
        case QK_STENO_COMB ... QK_STENO_COMB_MAX: {
            uint8_t result;
            result = process_steno(combinedmap_first[keycode-QK_STENO_COMB], record);
            result &= process_steno(combinedmap_second[keycode-QK_STENO_COMB], record);
            result = process_steno(combinedmap_first[keycode - QK_STENO_COMB], record);
            result &= process_steno(combinedmap_second[keycode - QK_STENO_COMB], record);
            return result;
        }
#endif

M quantum/quantum.c => quantum/quantum.c +6 -5
@@ 145,12 145,13 @@ void reset_keyboard(void) {
/* Convert record into usable keycode via the contained event. */
uint16_t get_record_keycode(keyrecord_t *record, bool update_layer_cache) {
#ifdef COMBO_ENABLE
    if (record->keycode) { return record->keycode; }
    if (record->keycode) {
        return record->keycode;
    }
#endif
    return get_event_keycode(record->event, update_layer_cache);
}


/* Convert event into usable keycode. Checks the layer cache to ensure that it
 * retains the correct keycode after a layer change, if the key is still pressed.
 * "update_layer_cache" is to ensure that it only updates the layer cache when


@@ 179,12 180,12 @@ uint16_t get_event_keycode(keyevent_t event, bool update_layer_cache) {
bool pre_process_record_quantum(keyrecord_t *record) {
    if (!(
#ifdef COMBO_ENABLE
        process_combo(get_record_keycode(record, true), record) &&
            process_combo(get_record_keycode(record, true), record) &&
#endif
        true)) {
            true)) {
        return false;
    }
    return true; // continue processing
    return true;  // continue processing
}

/* Get keycode, and then call keyboard function */

M quantum/quantum_keycodes.h => quantum/quantum_keycodes.h +6 -6
@@ 775,12 775,12 @@ enum quantum_keycodes {
#define CMD_T(kc) LCMD_T(kc)
#define WIN_T(kc) LWIN_T(kc)

#define C_S_T(kc) MT(MOD_LCTL | MOD_LSFT, kc)  // Left Control + Shift e.g. for gnome-terminal
#define MEH_T(kc) MT(MOD_LCTL | MOD_LSFT | MOD_LALT, kc)  // Meh is a less hyper version of the Hyper key -- doesn't include GUI, so just Left Control + Shift + Alt
#define LCAG_T(kc) MT(MOD_LCTL | MOD_LALT | MOD_LGUI, kc)  // Left Control + Alt + GUI
#define RCAG_T(kc) MT(MOD_RCTL | MOD_RALT | MOD_RGUI, kc)  // Right Control + Alt + GUI
#define C_S_T(kc) MT(MOD_LCTL | MOD_LSFT, kc)                         // Left Control + Shift e.g. for gnome-terminal
#define MEH_T(kc) MT(MOD_LCTL | MOD_LSFT | MOD_LALT, kc)              // Meh is a less hyper version of the Hyper key -- doesn't include GUI, so just Left Control + Shift + Alt
#define LCAG_T(kc) MT(MOD_LCTL | MOD_LALT | MOD_LGUI, kc)             // Left Control + Alt + GUI
#define RCAG_T(kc) MT(MOD_RCTL | MOD_RALT | MOD_RGUI, kc)             // Right Control + Alt + GUI
#define HYPR_T(kc) MT(MOD_LCTL | MOD_LSFT | MOD_LALT | MOD_LGUI, kc)  // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/
#define LSG_T(kc) MT(MOD_LSFT | MOD_LGUI, kc)  // Left Shift + GUI
#define LSG_T(kc) MT(MOD_LSFT | MOD_LGUI, kc)                         // Left Shift + GUI
#define SGUI_T(kc) LSG_T(kc)
#define SCMD_T(kc) LSG_T(kc)
#define SWIN_T(kc) LSG_T(kc)


@@ 811,7 811,7 @@ enum quantum_keycodes {

#define UC_M_MA UNICODE_MODE_MAC
#define UNICODE_MODE_OSX UNICODE_MODE_MAC  // Deprecated alias
#define UC_M_OS UNICODE_MODE_MAC  // Deprecated alias
#define UC_M_OS UNICODE_MODE_MAC           // Deprecated alias
#define UC_M_LN UNICODE_MODE_LNX
#define UC_M_WI UNICODE_MODE_WIN
#define UC_M_BS UNICODE_MODE_BSD

M quantum/split_common/transactions.c => quantum/split_common/transactions.c +24 -24
@@ 42,8 42,8 @@
    { &dummy, 0, 0, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), cb }
#define trans_target2initiator_initializer(member) trans_target2initiator_initializer_cb(member, NULL)

#define transport_write(id, data, length)          transport_execute_transaction(id, data, length, NULL, 0)
#define transport_read(id, data, length)           transport_execute_transaction(id, NULL, 0, data, length)
#define transport_write(id, data, length) transport_execute_transaction(id, data, length, NULL, 0)
#define transport_read(id, data, length) transport_execute_transaction(id, NULL, 0, data, length)

#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
// Forward-declare the RPC callback handlers


@@ 157,8 157,8 @@ static void master_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_ro
    memcpy(master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix));
}

#    define TRANSACTIONS_MASTER_MATRIX_MASTER()      TRANSACTION_HANDLER_MASTER(master_matrix)
#    define TRANSACTIONS_MASTER_MATRIX_SLAVE()       TRANSACTION_HANDLER_SLAVE(master_matrix)
#    define TRANSACTIONS_MASTER_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(master_matrix)
#    define TRANSACTIONS_MASTER_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(master_matrix)
#    define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS [PUT_MASTER_MATRIX] = trans_initiator2target_initializer(mmatrix.matrix),

#else  // SPLIT_TRANSPORT_MIRROR


@@ 235,8 235,8 @@ static void sync_timer_handlers_slave(matrix_row_t master_matrix[], matrix_row_t
    }
}

#    define TRANSACTIONS_SYNC_TIMER_MASTER()      TRANSACTION_HANDLER_MASTER(sync_timer)
#    define TRANSACTIONS_SYNC_TIMER_SLAVE()       TRANSACTION_HANDLER_SLAVE(sync_timer)
#    define TRANSACTIONS_SYNC_TIMER_MASTER() TRANSACTION_HANDLER_MASTER(sync_timer)
#    define TRANSACTIONS_SYNC_TIMER_SLAVE() TRANSACTION_HANDLER_SLAVE(sync_timer)
#    define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS [PUT_SYNC_TIMER] = trans_initiator2target_initializer(sync_timer),

#else  // DISABLE_SYNC_TIMER


@@ 300,8 300,8 @@ static void led_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t 
    set_split_host_keyboard_leds(split_shmem->led_state);
}

#    define TRANSACTIONS_LED_STATE_MASTER()      TRANSACTION_HANDLER_MASTER(led_state)
#    define TRANSACTIONS_LED_STATE_SLAVE()       TRANSACTION_HANDLER_SLAVE(led_state)
#    define TRANSACTIONS_LED_STATE_MASTER() TRANSACTION_HANDLER_MASTER(led_state)
#    define TRANSACTIONS_LED_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE(led_state)
#    define TRANSACTIONS_LED_STATE_REGISTRATIONS [PUT_LED_STATE] = trans_initiator2target_initializer(led_state),

#else  // SPLIT_LED_STATE_ENABLE


@@ 357,8 357,8 @@ static void mods_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave
#    endif
}

#    define TRANSACTIONS_MODS_MASTER()      TRANSACTION_HANDLER_MASTER(mods)
#    define TRANSACTIONS_MODS_SLAVE()       TRANSACTION_HANDLER_SLAVE(mods)
#    define TRANSACTIONS_MODS_MASTER() TRANSACTION_HANDLER_MASTER(mods)
#    define TRANSACTIONS_MODS_SLAVE() TRANSACTION_HANDLER_SLAVE(mods)
#    define TRANSACTIONS_MODS_REGISTRATIONS [PUT_MODS] = trans_initiator2target_initializer(mods),

#else  // SPLIT_MODS_ENABLE


@@ 382,8 382,8 @@ static bool backlight_handlers_master(matrix_row_t master_matrix[], matrix_row_t

static void backlight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { backlight_set(split_shmem->backlight_level); }

#    define TRANSACTIONS_BACKLIGHT_MASTER()      TRANSACTION_HANDLER_MASTER(backlight)
#    define TRANSACTIONS_BACKLIGHT_SLAVE()       TRANSACTION_HANDLER_SLAVE(backlight)
#    define TRANSACTIONS_BACKLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(backlight)
#    define TRANSACTIONS_BACKLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(backlight)
#    define TRANSACTIONS_BACKLIGHT_REGISTRATIONS [PUT_BACKLIGHT] = trans_initiator2target_initializer(backlight_level),

#else  // BACKLIGHT_ENABLE


@@ 419,8 419,8 @@ static void rgblight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t s
    }
}

#    define TRANSACTIONS_RGBLIGHT_MASTER()      TRANSACTION_HANDLER_MASTER(rgblight)
#    define TRANSACTIONS_RGBLIGHT_SLAVE()       TRANSACTION_HANDLER_SLAVE(rgblight)
#    define TRANSACTIONS_RGBLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(rgblight)
#    define TRANSACTIONS_RGBLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(rgblight)
#    define TRANSACTIONS_RGBLIGHT_REGISTRATIONS [PUT_RGBLIGHT] = trans_initiator2target_initializer(rgblight_sync),

#else  // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)


@@ 449,8 449,8 @@ static void led_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t
    led_matrix_set_suspend_state(split_shmem->led_matrix_sync.led_suspend_state);
}

#    define TRANSACTIONS_LED_MATRIX_MASTER()      TRANSACTION_HANDLER_MASTER(led_matrix)
#    define TRANSACTIONS_LED_MATRIX_SLAVE()       TRANSACTION_HANDLER_SLAVE(led_matrix)
#    define TRANSACTIONS_LED_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(led_matrix)
#    define TRANSACTIONS_LED_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(led_matrix)
#    define TRANSACTIONS_LED_MATRIX_REGISTRATIONS [PUT_LED_MATRIX] = trans_initiator2target_initializer(led_matrix_sync),

#else  // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)


@@ 479,8 479,8 @@ static void rgb_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t
    rgb_matrix_set_suspend_state(split_shmem->rgb_matrix_sync.rgb_suspend_state);
}

#    define TRANSACTIONS_RGB_MATRIX_MASTER()      TRANSACTION_HANDLER_MASTER(rgb_matrix)
#    define TRANSACTIONS_RGB_MATRIX_SLAVE()       TRANSACTION_HANDLER_SLAVE(rgb_matrix)
#    define TRANSACTIONS_RGB_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(rgb_matrix)
#    define TRANSACTIONS_RGB_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(rgb_matrix)
#    define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS [PUT_RGB_MATRIX] = trans_initiator2target_initializer(rgb_matrix_sync),

#else  // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)


@@ 504,8 504,8 @@ static bool wpm_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave

static void wpm_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { set_current_wpm(split_shmem->current_wpm); }

#    define TRANSACTIONS_WPM_MASTER()      TRANSACTION_HANDLER_MASTER(wpm)
#    define TRANSACTIONS_WPM_SLAVE()       TRANSACTION_HANDLER_SLAVE(wpm)
#    define TRANSACTIONS_WPM_MASTER() TRANSACTION_HANDLER_MASTER(wpm)
#    define TRANSACTIONS_WPM_SLAVE() TRANSACTION_HANDLER_SLAVE(wpm)
#    define TRANSACTIONS_WPM_REGISTRATIONS [PUT_WPM] = trans_initiator2target_initializer(current_wpm),

#else  // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)


@@ 535,8 535,8 @@ static void oled_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave
    }
}

#    define TRANSACTIONS_OLED_MASTER()      TRANSACTION_HANDLER_MASTER(oled)
#    define TRANSACTIONS_OLED_SLAVE()       TRANSACTION_HANDLER_SLAVE(oled)
#    define TRANSACTIONS_OLED_MASTER() TRANSACTION_HANDLER_MASTER(oled)
#    define TRANSACTIONS_OLED_SLAVE() TRANSACTION_HANDLER_SLAVE(oled)
#    define TRANSACTIONS_OLED_REGISTRATIONS [PUT_OLED] = trans_initiator2target_initializer(current_oled_state),

#else  // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)


@@ 566,8 566,8 @@ static void st7565_handlers_slave(matrix_row_t master_matrix[], matrix_row_t sla
    }
}

#    define TRANSACTIONS_ST7565_MASTER()      TRANSACTION_HANDLER_MASTER(st7565)
#    define TRANSACTIONS_ST7565_SLAVE()       TRANSACTION_HANDLER_SLAVE(st7565)
#    define TRANSACTIONS_ST7565_MASTER() TRANSACTION_HANDLER_MASTER(st7565)
#    define TRANSACTIONS_ST7565_SLAVE() TRANSACTION_HANDLER_SLAVE(st7565)
#    define TRANSACTIONS_ST7565_REGISTRATIONS [PUT_ST7565] = trans_initiator2target_initializer(current_st7565_state),

#else  // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)

M tmk_core/common/chibios/sleep_led.c => tmk_core/common/chibios/sleep_led.c +2 -2
@@ 65,7 65,7 @@ void sleep_led_timer_callback(void) {

/* LPTMR clock options */
#    define LPTMR_CLOCK_MCGIRCLK 0 /* 4MHz clock */
#    define LPTMR_CLOCK_LPO 1 /* 1kHz clock */
#    define LPTMR_CLOCK_LPO 1      /* 1kHz clock */
#    define LPTMR_CLOCK_ERCLK32K 2 /* external 32kHz crystal */
#    define LPTMR_CLOCK_OSCERCLK 3 /* output from OSC */



@@ 121,7 121,7 @@ void sleep_led_init(void) {
    MCG->C2 |= MCG_C2_IRCS;  // fast (4MHz) internal ref clock
#        if defined(KL27)    // divide the 8MHz IRC by 2, to have the same MCGIRCLK speed as others
    MCG->MC |= MCG_MC_LIRC_DIV2_DIV2;
#        endif /* KL27 */
#        endif                  /* KL27 */
    MCG->C1 |= MCG_C1_IRCLKEN;  // enable internal ref clock
    //  to work in stop mode, also MCG_C1_IREFSTEN
    //  Divide 4MHz by 2^N (N=6) => 62500 irqs/sec =>

M tmk_core/common/report.c => tmk_core/common/report.c +2 -2
@@ 24,8 24,8 @@
#ifdef RING_BUFFERED_6KRO_REPORT_ENABLE
#    define RO_ADD(a, b) ((a + b) % KEYBOARD_REPORT_KEYS)
#    define RO_SUB(a, b) ((a - b + KEYBOARD_REPORT_KEYS) % KEYBOARD_REPORT_KEYS)
#    define RO_INC(a)    RO_ADD(a, 1)
#    define RO_DEC(a)    RO_SUB(a, 1)
#    define RO_INC(a) RO_ADD(a, 1)
#    define RO_DEC(a) RO_SUB(a, 1)
static int8_t cb_head  = 0;
static int8_t cb_tail  = 0;
static int8_t cb_count = 0;

M tmk_core/protocol/ps2_mouse.c => tmk_core/protocol/ps2_mouse.c +2 -2
@@ 158,8 158,8 @@ static inline void ps2_mouse_convert_report_to_hid(report_mouse_t *mouse_report)

#ifdef PS2_MOUSE_INVERT_BUTTONS
    // swap left & right buttons
    uint8_t needs_left = mouse_report->buttons & PS2_MOUSE_BTN_RIGHT;
    uint8_t needs_right = mouse_report->buttons & PS2_MOUSE_BTN_LEFT;
    uint8_t needs_left    = mouse_report->buttons & PS2_MOUSE_BTN_RIGHT;
    uint8_t needs_right   = mouse_report->buttons & PS2_MOUSE_BTN_LEFT;
    mouse_report->buttons = (mouse_report->buttons & ~(PS2_MOUSE_BTN_MASK)) | (needs_left ? PS2_MOUSE_BTN_LEFT : 0) | (needs_right ? PS2_MOUSE_BTN_RIGHT : 0);
#else
    // remove sign and overflow flags