sxkbd

Firmware for RP2040-based corne split keyboard
git clone https://git.sinitax.com/sinitax/sxkbd
Log | Files | Refs | Submodules | README | LICENSE | sfeed.txt

commit d7c506450be613d6575649218fbcc90a4fabd150
parent e4783bbcc4214416befceb53f6af9ebdfb35ba86
Author: Louis Burda <quent.burda@gmail.com>
Date:   Mon, 19 Dec 2022 17:01:11 +0100

Enable temporary (weak) mods for specific keys and layer switching with mods

Diffstat:
M.gitignore | 1+
Msrc/hid.c | 224++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/hid.h | 4++++
Msrc/keycode.h | 33++++++++++++++++++++++++++-------
Msrc/keymap.c | 48+++++++++++++++++++++++++++++++++++++++++++++---
Msrc/keymap.h | 5+++++
Msrc/keysym.h | 29+++++++++++++++++++----------
Msrc/usb_descriptors.c | 2+-
8 files changed, 236 insertions(+), 110 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -2,3 +2,4 @@ .cache compile_commands.json src/*.pio.h +notes diff --git a/src/hid.c b/src/hid.c @@ -16,14 +16,22 @@ struct layerkey { uint key; }; +struct hid_report { + uint8_t mods; + uint8_t codes[6]; + uint8_t codecnt; +}; + static uint32_t keysyms[KEY_ROWS][KEY_COLS] = { 0 }; static struct layerkey active_stack[16] = { 0 }; static uint active_top = 0; -static uint8_t hid_report_prev[6] = { 0 }; -static uint8_t hid_report[6] = { 0 }; -static uint hid_report_len = 0; +static struct hid_report hid_report_prev; +static struct hid_report hid_report; + +static uint8_t active_weak_mods; +static uint8_t active_mods; static uint64_t bounce_mat[KEY_ROWS][KEY_COLS] = { 0 }; @@ -31,6 +39,7 @@ static bool seen_mat[KEY_ROWS][KEY_COLS]; static void active_pop(uint layer); static void active_push(uint layer, uint key); +static void add_keycode(uint8_t keycode); void active_pop(uint layer) @@ -46,124 +55,149 @@ active_pop(uint layer) void active_push(uint layer, uint key) { + uint i; + if (active_top == ARRLEN(active_stack) - 1) { WARN("Active stack overflow"); return; } + active_top += 1; active_stack[active_top].layer = layer; active_stack[active_top].key = key; + + for (i = 0; i <= active_top; i++) { + INFO("%i. ACTIVE %u %u", i, + active_stack[i].layer, active_stack[i].key); + } } void add_keycode(uint8_t keycode) { - if (hid_report_len >= 6) { + if (hid_report.codecnt >= 6) { WARN("HID report overflow"); return; } - hid_report[hid_report_len] = keycode; - hid_report_len++; + hid_report.codes[hid_report.codecnt] = keycode; + hid_report.codecnt++; } -void -handle_keypress(uint x, uint y) +uint8_t +parse_modifiers(uint32_t keysym) { - uint32_t ksym; - int i; + uint8_t mods; - if (!keymat_prev[y][x]) { - for (i = (int) active_top; i >= 0; i--) { - ksym = keymap_layers[active_stack[i].layer][y][x]; - if (ksym == KC_NO) return; - if (ksym != KC_TRNS) - break; - } - if (i < 0) return; - keysyms[y][x] = ksym; - - if (IS_SWITCH(keysyms[y][x])) { - INFO("LAYER %u", TO_LAYER(keysyms[y][x])); - active_push(TO_LAYER(ksym), y * KEY_COLS + x); - for (i = 0; i <= (int) active_top; i++) { - INFO("%i. ACTIVE %u %u", i, - active_stack[i].layer, active_stack[i].key); - } - } - } + mods = 0; - if (!seen_mat[y][x]) { - if (IS_CTRL(keysyms[y][x])) { - if (IS_RIGHT(keysyms[y][x])) { - add_keycode(KC_RIGHT_CTRL); - } else { - add_keycode(KC_LEFT_CTRL); - } - } + if (IS_LEFT_CTRL(keysym)) + mods |= MOD_BIT(KC_LEFT_CTRL); - if (IS_SHIFT(keysyms[y][x])) { - if (IS_RIGHT(keysyms[y][x])) { - add_keycode(KC_RIGHT_SHIFT); - } else { - add_keycode(KC_LEFT_SHIFT); - } - } + if (IS_RIGHT_CTRL(keysym)) + mods |= MOD_BIT(KC_RIGHT_CTRL); - if (IS_ALT(keysyms[y][x])) { - if (IS_RIGHT(keysyms[y][x])) { - add_keycode(KC_RIGHT_ALT); - } else { - add_keycode(KC_LEFT_ALT); - } - } + if (IS_LEFT_SHIFT(keysym)) + mods |= MOD_BIT(KC_LEFT_SHIFT); - if (IS_GUI(keysyms[y][x])) { - if (IS_RIGHT(keysyms[y][x])) { - add_keycode(KC_RIGHT_GUI); - } else { - add_keycode(KC_LEFT_GUI); - } - } + if (IS_RIGHT_SHIFT(keysym)) + mods |= MOD_BIT(KC_RIGHT_SHIFT); - if (IS_CODE(keysyms[y][x])) { - add_keycode(TO_CODE(keysyms[y][x])); - INFO("CODE %u %u", active_top, keysyms[y][x]); - } + if (IS_LEFT_GUI(keysym)) + mods |= MOD_BIT(KC_LEFT_GUI); + + if (IS_RIGHT_GUI(keysym)) + mods |= MOD_BIT(KC_RIGHT_GUI); + + if (IS_LEFT_ALT(keysym)) + mods |= MOD_BIT(KC_LEFT_ALT); + + if (IS_RIGHT_ALT(keysym)) + mods |= MOD_BIT(KC_RIGHT_ALT); + + return mods; +} + +void +handle_keypress_new(uint x, uint y) +{ + uint32_t ksym; + int i; - seen_mat[y][x] = true; + for (i = (int) active_top; i >= 0; i--) { + ksym = keymap_layers[active_stack[i].layer][y][x]; + if (ksym == KC_NO) return; + if (ksym != KC_TRNS) + break; + } + if (i < 0) return; + keysyms[y][x] = ksym; + + if (IS_SWITCH(keysyms[y][x])) { + active_push(TO_LAYER(keysyms[y][x]), y * KEY_COLS + x); + } else if (IS_USER(keysyms[y][x])) { + process_user_keypress_new(TO_SYM(keysyms[y][x]), x, y); + } else if (IS_KC(keysyms[y][x]) && IS_KEY_KC(TO_KC(keysyms[y][x]))) { + /* FIXME: two keys pressed at the exact same time with + * different weak modifiers will not be reported correctly */ + active_weak_mods = parse_modifiers(keysyms[y][x]); } } void -handle_keyrelease(uint x, uint y) +handle_keypress(uint x, uint y) +{ + if (!keymat_prev[y][x]) + handle_keypress_new(x, y); + + if (seen_mat[y][x]) return; + seen_mat[y][x] = true; + + if (IS_KC(keysyms[y][x]) && IS_KEY_KC(TO_KC(keysyms[y][x]))) { + add_keycode(TO_KC(keysyms[y][x])); + INFO("CODE %u %u", active_top, keysyms[y][x]); + } else if (IS_KC(keysyms[y][x]) && IS_MOD_KC(TO_KC(keysyms[y][x]))) { + active_mods |= MOD_BIT(TO_KC(keysyms[y][x])); + } else if (IS_MOD(keysyms[y][x])) { + active_mods |= parse_modifiers(keysyms[y][x]); + } +} + +void +handle_keyrelease_new(uint x, uint y) { uint i; - if (keymat_prev[y][x]) { - for (i = 1; i <= active_top; i++) { - if (active_stack[i].key == y * KEY_COLS + x) { - active_pop(i); - break; - } + if (IS_USER(keysyms[y][x])) + process_user_keyrelease_new(TO_SYM(keysyms[y][x]), x, y); + + for (i = 1; i <= active_top; i++) { + if (active_stack[i].key == y * KEY_COLS + x) { + active_pop(i); + break; } } } -bool +void +handle_keyrelease(uint x, uint y) +{ + if (keymat_prev[y][x]) + handle_keyrelease_new(x, y); +} + +void update_report(void) { uint64_t now_us; - uint keycnt; uint x, y; - keycnt = 0; now_us = time_us_64(); for (y = 0; y < KEY_ROWS; y++) { for (x = 0; x < KEY_COLS; x++) { if (keymat[y][x] != keymat_prev[y][x]) { if (bounce_mat[y][x] > now_us - 50000) { - WARN("Bouncing prevented %i vs %i", + DEBUG("Bouncing prevented %i vs %i", keymat[y][x], keymat_prev[y][x]); keymat[y][x] = keymat_prev[y][x]; } else { @@ -178,24 +212,16 @@ update_report(void) } } } - - return keycnt > 0; -} - -void -hid_init(void) -{ } bool send_keyboard_report(void) { - uint i; - if (memcmp(hid_report, hid_report_prev, sizeof(hid_report))) { - for (i = 0; i < 6; i++) - INFO("REPORT %u: %u", i, hid_report[i]); - tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, hid_report); - memcpy(hid_report_prev, hid_report, sizeof(hid_report)); + hid_report.mods = active_weak_mods | active_mods; + if (memcmp(&hid_report, &hid_report_prev, sizeof(hid_report))) { + tud_hid_keyboard_report(REPORT_ID_KEYBOARD, + hid_report.mods, hid_report.codes); + memcpy(&hid_report_prev, &hid_report, sizeof(hid_report)); return true; } @@ -262,13 +288,33 @@ tud_hid_report_complete_cb(uint8_t instance, } void +hid_init(void) +{ +} + +void +hid_force_release(uint x, uint y) +{ + handle_keyrelease_new(x, y); + keysyms[y][x] = KC_NO; +} + +void +hid_switch_layer_with_key(uint8_t layer, uint x, uint y) +{ + active_push(layer, y * KEY_COLS + x); + keysyms[y][x] = SW(layer); + seen_mat[y][x] = true; +} + +void hid_task(void) { update_report(); if (tud_hid_ready()) { send_hid_report(REPORT_ID_MIN); - memset(hid_report, 0, sizeof(hid_report)); + memset(&hid_report, 0, sizeof(hid_report)); memset(seen_mat, 0, sizeof(seen_mat)); - hid_report_len = 0; + active_mods = 0; } } diff --git a/src/hid.h b/src/hid.h @@ -1,5 +1,7 @@ #pragma once +#include "keymat.h" + #include <stdbool.h> #include <stdint.h> @@ -12,4 +14,6 @@ enum { }; void hid_init(void); +void hid_force_release(uint x, uint y); +void hid_switch_layer_with_key(uint8_t layer, uint x, uint y); void hid_task(void); diff --git a/src/keycode.h b/src/keycode.h @@ -8,14 +8,14 @@ * or http://www.usb.org/developers/hidpage/Hut1_12v2.pdf (older) */ -#define IS_ERROR(code) (KC_ROLL_OVER <= (code) && (code) <= KC_UNDEFINED) -#define IS_ANY(code) (KC_A <= (code) && (code) <= 0xFF) -#define IS_KEY(code) (KC_A <= (code) && (code) <= KC_EXSEL) -#define IS_MOD(code) (KC_LEFT_CTRL <= (code) && (code) <= KC_RIGHT_GUI) +#define IS_ANY_KC(code) (KC_A <= (code) && (code) <= 0xFF) +#define IS_ERROR_KC(code) (KC_ROLL_OVER <= (code) && (code) <= KC_UNDEFINED) +#define IS_KEY_KC(code) (KC_A <= (code) && (code) <= KC_EXSEL) +#define IS_MOD_KC(code) (KC_LEFT_CTRL <= (code) && (code) <= KC_RIGHT_GUI) -// #define IS_SPECIAL(code) ((0xA5 <= (code) && (code) <= 0xDF) || (0xE8 <= (code) && (code) <= 0xFF)) -// #define IS_SYSTEM(code) (KC_PWR <= (code) && (code) <= KC_WAKE) -// #define IS_CONSUMER(code) (KC_MUTE <= (code) && (code) <= KC_BRID) +#define IS_SPECIAL_KC(code) ((0xA5 <= (code) && (code) <= 0xDF) || (0xE8 <= (code) && (code) <= 0xFF)) +#define IS_SYSTEM_KC(code) (KC_PWR <= (code) && (code) <= KC_WAKE) +#define IS_CONSUMER_KC(code) (KC_MUTE <= (code) && (code) <= KC_BRID) #define IS_MOUSEKEY(code) (KC_MS_UP <= (code) && (code) <= KC_MS_ACCEL2) #define IS_MOUSEKEY_MOVE(code) (KC_MS_UP <= (code) && (code) <= KC_MS_RIGHT) @@ -23,6 +23,25 @@ #define IS_MOUSEKEY_WHEEL(code) (KC_MS_WH_UP <= (code) && (code) <= KC_MS_WH_RIGHT) #define IS_MOUSEKEY_ACCEL(code) (KC_MS_ACCEL0 <= (code) && (code) <= KC_MS_ACCEL2) +#define MOD_BIT(code) (1 << MOD_INDEX(code)) +#define MOD_INDEX(code) ((code) & 0b111) + +#define MOD_MASK_CTRL (MOD_BIT(KC_LEFT_CTRL) | MOD_BIT(KC_RIGHT_CTRL)) +#define MOD_MASK_SHIFT (MOD_BIT(KC_LEFT_SHIFT) | MOD_BIT(KC_RIGHT_SHIFT)) +#define MOD_MASK_ALT (MOD_BIT(KC_LEFT_ALT) | MOD_BIT(KC_RIGHT_ALT)) +#define MOD_MASK_GUI (MOD_BIT(KC_LEFT_GUI) | MOD_BIT(KC_RIGHT_GUI)) +#define MOD_MASK_CS (MOD_MASK_CTRL | MOD_MASK_SHIFT) +#define MOD_MASK_CA (MOD_MASK_CTRL | MOD_MASK_ALT) +#define MOD_MASK_CG (MOD_MASK_CTRL | MOD_MASK_GUI) +#define MOD_MASK_SA (MOD_MASK_SHIFT | MOD_MASK_ALT) +#define MOD_MASK_SG (MOD_MASK_SHIFT | MOD_MASK_GUI) +#define MOD_MASK_AG (MOD_MASK_ALT | MOD_MASK_GUI) +#define MOD_MASK_CSA (MOD_MASK_CTRL | MOD_MASK_SHIFT | MOD_MASK_ALT) +#define MOD_MASK_CSG (MOD_MASK_CTRL | MOD_MASK_SHIFT | MOD_MASK_GUI) +#define MOD_MASK_CAG (MOD_MASK_CTRL | MOD_MASK_ALT | MOD_MASK_GUI) +#define MOD_MASK_SAG (MOD_MASK_SHIFT | MOD_MASK_ALT | MOD_MASK_GUI) +#define MOD_MASK_CSAG (MOD_MASK_CTRL | MOD_MASK_SHIFT | MOD_MASK_ALT | MOD_MASK_GUI) + /* Short names for ease of definition of keymap */ /* Transparent */ diff --git a/src/keymap.c b/src/keymap.c @@ -2,6 +2,7 @@ #include "keycode.h" #include "keysym.h" #include "keysym_de.h" +#include "hid.h" #include "board.h" #include "util.h" @@ -25,9 +26,22 @@ { 0x0, 0x0, 0x0, K83, K82, K81 } \ } +/* KEY INDEX LOOKUP: + * x0y0 , x1y0 , x2y0 , x3y0 , x4y0 , x5y0 , + * x0y1 , x1y1 , x2y1 , x3y1 , x4y1 , x5y1 , + * x0y2 , x1y2 , x2y2 , x3y2 , x4y2 , x5y2 , + * x3y3 , x4y3 , x5y3 , + * + * x5y4 , x4y4 , x3y4 , x2y4 , x1y4 , x0y4 , + * x5y5 , x4y5 , x3y5 , x2y5 , x1y5 , x0y5 , + * x5y6 , x4y6 , x3y6 , x2y6 , x1y6 , x0y6 , + * x5y7 , x4y7 , x3y7 + */ + + #define LAYER_BASE_DE KEYMAP( \ KC_ESC , DE_Q , DE_W , DE_F , DE_P , DE_B , \ - SW(QUIK), DE_A , DE_R , DE_S , DE_T , DE_G , \ + SX(QUSW), DE_A , DE_R , DE_S , DE_T , DE_G , \ KC_LSFT , DE_Z , DE_X , DE_C , DE_D , DE_V , \ KC_LGUI , KC_LALT , SW(SHRT), \ \ @@ -63,7 +77,7 @@ #define LAYER_SHRT_DE KEYMAP( \ _______ , G(KC_1) , G(KC_2) , G(KC_3) , G(KC_4) , G(KC_5) , \ - _______ , A(KC_1) , A(KC_2) , A(KC_3) , A(KC_4) , A(KC_5) , \ + CS(BASE), A(KC_1) , A(KC_2) , A(KC_3) , A(KC_4) , A(KC_5) , \ _______ ,G(KC_TAB),G(DE_DOT), A(DE_B) , A(DE_F) ,A(KC_SPC), \ _______ , _______ , _______ , \ \ @@ -122,7 +136,8 @@ enum { enum { KVM1, - KVM2 + KVM2, + QUSW, }; const uint32_t keymap_layers_de[][KEY_ROWS][KEY_COLS] = { @@ -139,3 +154,30 @@ const uint32_t keymap_layers_de_count = ARRLEN(keymap_layers_de); const uint32_t (*keymap_layers)[KEY_ROWS][KEY_COLS] = keymap_layers_de; uint32_t keymap_layers_count = keymap_layers_de_count; + +void +process_user_keypress_new(uint8_t sym, uint x, uint y) +{ + switch (sym) { + case KVM1: + break; + case KVM2: + break; + case QUSW: + INFO("Handling quick switch %i", keymat[7][3]); + if (keymat[7][3]) { + hid_force_release(3, 7); + hid_switch_layer_with_key(QUIX, x, y); + } else { + hid_switch_layer_with_key(QUIK, x, y); + } + break; + } + +} + +void +process_user_keyrelease_new(uint8_t sym, uint x, uint y) +{ + +} diff --git a/src/keymap.h b/src/keymap.h @@ -2,8 +2,13 @@ #include "keymat.h" +#include "pico/types.h" + #include <stdint.h> +void process_user_keypress_new(uint8_t sym, uint x, uint y); +void process_user_keyrelease_new(uint8_t sym, uint x, uint y); + extern const uint32_t keymap_layers_de[][KEY_ROWS][KEY_COLS]; extern const uint32_t keymap_layers_de_count; diff --git a/src/keysym.h b/src/keysym.h @@ -7,7 +7,7 @@ #define MASK(hi, lo) ((1U << (hi)) - (1U << (lo))) -#define IS_CODE(x) (!((x) & ~MASK(B_TOGGLE, 0))) +#define IS_KC(x) (!((x) & ~MASK(B_TOGGLE, 0))) #define IS_CTRL(x) ((x) & (1 << B_CTRL)) #define IS_SHIFT(x) ((x) & (1 << B_SHIFT)) #define IS_ALT(x) ((x) & (1 << B_ALT)) @@ -15,10 +15,21 @@ #define IS_RIGHT(x) ((x) & (1 << B_RIGHT)) #define IS_TOGGLE(x) ((x) & (1 << B_TOGGLE)) #define IS_SWITCH(x) ((x) & (1 << B_SWITCH)) -#define IS_MODSWT(x) ((x) & (1 << B_MODSWT)) -#define IS_SPECIAL(x) ((x) & (1 << B_SPECIAL)) +#define IS_USER(x) ((x) & (1 << B_USER)) -#define TO_CODE(x) ((x) & 0xFF) +#define IS_LEFT_CTRL(x) (IS_CTRL(x) && !IS_RIGHT(x)) +#define IS_RIGHT_CTRL(x) (IS_CTRL(x) && IS_RIGHT(x)) +#define IS_LEFT_SHIFT(x) (IS_SHIFT(x) && !IS_RIGHT(x)) +#define IS_RIGHT_SHIFT(x) (IS_SHIFT(x) && IS_RIGHT(x)) +#define IS_LEFT_ALT(x) (IS_ALT(x) && !IS_RIGHT(x)) +#define IS_RIGHT_ALT(x) (IS_ALT(x) && IS_RIGHT(x)) +#define IS_LEFT_GUI(x) (IS_GUI(x) && !IS_RIGHT(x)) +#define IS_RIGHT_GUI(x) (IS_GUI(x) && IS_RIGHT(x)) + +#define IS_MOD(x) ((x) & MASK(B_TOGGLE, 8)) + +#define TO_KC(x) ((x) & 0xFF) +#define TO_SYM(x) ((x) & 0xFF) #define TO_LAYER(x) ((x) & 0xFF) #define LCTL(x) ((x) | (1 << B_CTRL)) @@ -32,8 +43,7 @@ #define SW(x) ((x) | (1 << B_SWITCH)) #define TO(x) ((x) | (1 << B_TOGGLE)) -#define MO(x) ((x) | (1 << B_MODSWT)) -#define SX(x) ((x) | (1 << B_SPECIAL)) +#define SX(x) ((x) | (1 << B_USER)) #define LOPT(x) LALT(x) #define LCMD(x) LGUI(x) @@ -47,8 +57,8 @@ #define A(x) LALT(x) #define G(x) LGUI(x) -#define CS(x) C(MO(x)) -#define GS(x) G(MO(x)) +#define CS(x) C(SW(x)) +#define GS(x) G(SW(x)) enum { B_CTRL = 8, @@ -58,7 +68,6 @@ enum { B_RIGHT, B_TOGGLE, B_SWITCH, - B_MODSWT, - B_SPECIAL + B_USER }; diff --git a/src/usb_descriptors.c b/src/usb_descriptors.c @@ -73,7 +73,7 @@ uint8_t const desc_fs_configuration[] = { /* Interface number, string index, protocol, report descriptor len, * EP In address, size & polling interval */ TUD_HID_DESCRIPTOR(ITF_NUM_HID, 5, HID_ITF_PROTOCOL_NONE, - sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 5) + sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 1) }; #if TUD_OPT_HIGH_SPEED