diff options
Diffstat (limited to 'src/hid.c')
| -rw-r--r-- | src/hid.c | 224 |
1 files changed, 135 insertions, 89 deletions
@@ -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; } } |
