sxkbd

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

hid.c (13385B)


      1#include "hid.h"
      2
      3#include "led.h"
      4#include "split.h"
      5#include "keymat.h"
      6#include "keysym.h"
      7#include "keymap.h"
      8
      9#include "class/hid/hid.h"
     10#include "keysym/consumer.h"
     11#include "hid/keyboard.h"
     12#include "hardware/timer.h"
     13#include "bsp/board.h"
     14#include "pico/types.h"
     15
     16#include <stdbool.h>
     17#include <string.h>
     18
     19#define HID_REPORT_CODES 6
     20
     21#define MACRO_X 0
     22#define MACRO_Y 7
     23
     24struct layerkey {
     25	uint layer;
     26	uint key;
     27};
     28
     29struct hid_keyboard_report {
     30	uint8_t mods, weak_mods;
     31	uint8_t codes[HID_REPORT_CODES];
     32	uint8_t cnt;
     33};
     34
     35struct hid_mouse_report {
     36	uint8_t btns;
     37	int8_t x, y;
     38	int8_t v, h;
     39};
     40
     41struct hid_consumer_report {
     42	uint16_t code;
     43};
     44
     45struct hid_system_report {
     46	uint16_t code;
     47};
     48
     49struct hid_gamepad_report {
     50	int8_t x, y, z;
     51	int8_t rx, ry, rz;
     52	uint8_t hat;
     53	uint32_t btns;
     54};
     55
     56static uint32_t keysyms[KEY_ROWS][KEY_COLS] = { 0 };
     57
     58static struct layerkey active_layers[16] = { 0 };
     59static uint active_layers_top = 0;
     60
     61static struct hid_keyboard_report keyboard_report_prev = { 0 };
     62static struct hid_keyboard_report keyboard_report = { 0 };
     63
     64static struct hid_mouse_report mouse_report_prev = { 0 };
     65static struct hid_mouse_report mouse_report = { 0 };
     66
     67static struct hid_consumer_report consumer_report_prev = { 0 };
     68static struct hid_consumer_report consumer_report = { 0 };
     69
     70static struct hid_system_report system_report_prev = { 0 };
     71static struct hid_system_report system_report = { 0 };
     72
     73static struct hid_gamepad_report gamepad_report_prev = { 0 };
     74static struct hid_gamepad_report gamepad_report = { 0 };
     75
     76static uint8_t active_weak_mods = 0;
     77static uint8_t active_mods = 0;
     78
     79static bool seen_mat[KEY_ROWS][KEY_COLS] = { 0 };
     80
     81static uint32_t macro_held_stack[MACRO_HOLD_MAX] = { 0 };
     82static uint macro_held_cnt = 0;
     83
     84static bool macro_running = false;
     85
     86/* TODO replace these two with stack method primitives (added to util) */
     87
     88static void active_layers_reset(void);
     89static void active_layers_pop(uint layer);
     90static void active_layers_push(uint layer, uint key);
     91
     92static void macro_held_reset(void);
     93static void macro_held_pop(uint32_t keysym);
     94static void macro_held_push(uint32_t keysym);
     95static bool macro_held_find(uint32_t keysym);
     96
     97static void add_keycode(uint8_t keycode);
     98
     99/* TODO: add static prototypes */
    100
    101void
    102active_layers_reset(void)
    103{
    104	active_layers_top = 0;
    105}
    106
    107bool
    108active_layers_find(uint layer)
    109{
    110	uint i;
    111
    112	for (i = 0; i <= active_layers_top; i++) {
    113		if (active_layers[i].layer == layer)
    114			return true;
    115	}
    116
    117	return false;
    118}
    119
    120void
    121active_layers_pop(uint layer)
    122{
    123	uint i;
    124
    125	for (i = layer + 1; i <= active_layers_top; i++)
    126		active_layers[i-1] = active_layers[i];
    127	if (layer <= active_layers_top)
    128		active_layers_top--;
    129}
    130
    131void
    132active_layers_push(uint layer, uint key)
    133{
    134	uint i;
    135
    136	if (active_layers_top == ARRLEN(active_layers) - 1) {
    137		WARN(LOG_KEYMAP, "Active stack overflow");
    138		return;
    139	}
    140
    141	active_layers_top += 1;
    142	active_layers[active_layers_top].layer = layer;
    143	active_layers[active_layers_top].key = key;
    144
    145	for (i = 0; i <= active_layers_top; i++) {
    146		DEBUG(LOG_KEYMAP, "%i. ACTIVE %u %u", i,
    147			active_layers[i].layer, active_layers[i].key);
    148	}
    149}
    150
    151void
    152macro_held_reset(void)
    153{
    154	macro_held_cnt = 0;
    155}
    156
    157void
    158macro_held_pop(uint32_t keysym)
    159{
    160	uint i, cnt;
    161
    162	for (i = cnt = 0; i < macro_held_cnt; i++) {
    163		if (macro_held_stack[i] != keysym) {
    164			macro_held_stack[cnt] = macro_held_stack[i];
    165			cnt++;
    166		}
    167	}
    168	macro_held_cnt = cnt;
    169}
    170
    171void
    172macro_held_push(uint32_t keysym)
    173{
    174	if (macro_held_cnt == MACRO_HOLD_MAX) {
    175		WARN(LOG_KEYMAP, "Macro held keys overflow");
    176		return;
    177	}
    178
    179	macro_held_stack[macro_held_cnt] = keysym;
    180	macro_held_cnt++;
    181}
    182
    183bool
    184macro_held_find(uint32_t keysym)
    185{
    186	uint i;
    187
    188	for (i = 0; i < macro_held_cnt; i++) {
    189		if (macro_held_stack[i] == keysym)
    190			return true;
    191	}
    192
    193	return false;
    194}
    195
    196void
    197add_keycode(uint8_t keycode)
    198{
    199	if (keyboard_report.cnt >= 6) {
    200		WARN(LOG_HID, "HID report overflow");
    201		return;
    202	}
    203
    204	keyboard_report.codes[keyboard_report.cnt] = keycode;
    205	keyboard_report.cnt++;
    206}
    207
    208uint8_t
    209parse_modifiers(uint32_t keysym)
    210{
    211	uint8_t mods;
    212
    213	mods = 0;
    214
    215	if (IS_LEFT_CTRL(keysym))
    216		mods |= MOD_BIT(KC_LEFT_CTRL);
    217
    218	if (IS_RIGHT_CTRL(keysym))
    219		mods |= MOD_BIT(KC_RIGHT_CTRL);
    220
    221	if (IS_LEFT_SHIFT(keysym))
    222		mods |= MOD_BIT(KC_LEFT_SHIFT);
    223
    224	if (IS_RIGHT_SHIFT(keysym))
    225		mods |= MOD_BIT(KC_RIGHT_SHIFT);
    226
    227	if (IS_LEFT_GUI(keysym))
    228		mods |= MOD_BIT(KC_LEFT_GUI);
    229
    230	if (IS_RIGHT_GUI(keysym))
    231		mods |= MOD_BIT(KC_RIGHT_GUI);
    232
    233	if (IS_LEFT_ALT(keysym))
    234		mods |= MOD_BIT(KC_LEFT_ALT);
    235
    236	if (IS_RIGHT_ALT(keysym))
    237		mods |= MOD_BIT(KC_RIGHT_ALT);
    238
    239	return mods;
    240}
    241
    242uint32_t
    243determine_keysym(uint x, uint y)
    244{
    245	uint32_t keysym;
    246	int i;
    247
    248	keysym = KC_NO;
    249	for (i = (int) active_layers_top; i >= 0; i--) {
    250		keysym = keymap_layers[active_layers[i].layer][y][x];
    251		if (keysym != KC_TRNS && keysym != KC_NO)
    252			break;
    253	}
    254
    255	return keysym;
    256}
    257
    258void
    259process_keypress(uint32_t keysym, uint x, uint y)
    260{
    261	if (IS_SWITCH(keysym)) {
    262		active_layers_push(TO_LAYER(keysym), y * KEY_COLS + x);
    263	} else if (IS_TOGGLE(keysym)) {
    264		if (active_layers_find(TO_LAYER(keysym)))
    265			active_layers_pop(TO_LAYER(keysym));
    266		else
    267			active_layers_push(TO_LAYER(keysym), y * KEY_COLS + x);
    268	} else if (IS_REBASE(keysym)) {
    269		active_layers_reset();
    270		active_layers[0].layer = TO_LAYER(keysym);
    271	} else if (IS_USER(keysym)) {
    272		process_user_keypress(TO_USER(keysym), x, y);
    273	} else if (IS_KC(keysym) && IS_KEY_KC(TO_KC(keysym))) {
    274		/* FIXME: two keys pressed at the exact same time with
    275		 * different weak modifiers will not be reported correctly */
    276		active_weak_mods = parse_modifiers(keysym);
    277	} else if (IS_CONSUMER(keysym)) {
    278		consumer_report.code = keysym_to_consumer(keysym);
    279	}
    280}
    281
    282void
    283process_keydown(uint32_t keysym, uint x, uint y)
    284{
    285	if (x != MACRO_X || y != MACRO_Y) {
    286		if (seen_mat[y][x]) return;
    287		seen_mat[y][x] = true;
    288	}
    289
    290	if (IS_KC(keysym) && IS_KEY_KC(TO_KC(keysym))) {
    291		add_keycode(TO_KC(keysym));
    292	} else if (IS_KC(keysym) && IS_MOD_KC(TO_KC(keysym))) {
    293		active_mods |= MOD_BIT(TO_KC(keysym));
    294	} else if (IS_SWITCH(keysym) && IS_MOD(keysym)) {
    295		active_mods |= parse_modifiers(keysym);
    296	}
    297}
    298
    299void
    300process_keyrelease(uint32_t keysym, uint x, uint y)
    301{
    302	uint i;
    303
    304	if (IS_USER(keysym))
    305		process_user_keyrelease(TO_USER(keysym), x, y);
    306
    307	for (i = 1; i <= active_layers_top; i++) {
    308		if (active_layers[i].key == y * KEY_COLS + x) {
    309			active_layers_pop(i);
    310			break;
    311		}
    312	}
    313}
    314
    315void
    316process_keyup(uint32_t keysym, uint x, uint y)
    317{
    318}
    319
    320void
    321process_key(uint x, uint y, uint64_t now_us)
    322{
    323	if (keymat[y][x] && !keymat_prev[y][x])
    324		keysyms[y][x] = determine_keysym(x, y);
    325
    326	if (keymat[y][x]) {
    327		if (!keymat_prev[y][x])
    328			process_keypress(keysyms[y][x], x, y);
    329		process_keydown(keysyms[y][x], x, y);
    330	} else {
    331		if (keymat_prev[y][x])
    332			process_keyrelease(keysyms[y][x], x, y);
    333		process_keyup(keysyms[y][x], x, y);
    334	}
    335}
    336
    337void
    338update_report(void)
    339{
    340	uint64_t now_us;
    341	uint x, y;
    342
    343	now_us = time_us_64();
    344	for (y = 0; y < KEY_ROWS; y++) {
    345		for (x = 0; x < KEY_COLS; x++) {
    346			process_key(x, y, now_us);
    347		}
    348	}
    349}
    350
    351bool
    352update_keyboard_report(struct hid_keyboard_report *new,
    353	struct hid_keyboard_report *old)
    354{
    355	return new->mods != old->mods
    356		|| memcmp(new->codes, old->codes, HID_REPORT_CODES);
    357}
    358
    359bool
    360update_weak_mods(struct hid_keyboard_report *new,
    361	struct hid_keyboard_report *old)
    362{
    363	int i, k;
    364
    365	/* only need weak modes if new keycode added */
    366	for (i = 0; i < new->cnt; i++) {
    367		for (k = 0; k < old->cnt; k++) {
    368			if (new->codes[i] != old->codes[k])
    369				break;
    370		}
    371		if (k == old->cnt)
    372			return true;
    373	}
    374
    375	return false;
    376}
    377
    378bool
    379send_keyboard_report(void)
    380{
    381	bool sent;
    382
    383	sent = false;
    384
    385	keyboard_report.mods = active_mods;
    386	if (update_weak_mods(&keyboard_report, &keyboard_report_prev))
    387		keyboard_report.weak_mods = active_weak_mods;
    388
    389	if (update_keyboard_report(&keyboard_report, &keyboard_report_prev)) {
    390		tud_hid_n_keyboard_report(INST_HID_KBD, REPORT_ID_NONE,
    391			keyboard_report.mods | keyboard_report.weak_mods,
    392			keyboard_report.codes);
    393		memcpy(&keyboard_report_prev, &keyboard_report,
    394			sizeof(keyboard_report));
    395		sent = true;
    396
    397		active_weak_mods = 0;
    398	}
    399
    400	active_mods = 0;
    401
    402	memset(keyboard_report.codes, 0, HID_REPORT_CODES);
    403	keyboard_report.cnt = 0;
    404
    405	memset(seen_mat, 0, sizeof(seen_mat));
    406
    407	return sent;
    408}
    409
    410bool
    411send_mouse_report(void)
    412{
    413	bool sent;
    414
    415	sent = false;
    416	if (memcmp(&mouse_report, &mouse_report_prev,
    417			sizeof(mouse_report))) {
    418		tud_hid_n_mouse_report(INST_HID_MISC,
    419			REPORT_ID_MOUSE, mouse_report.btns,
    420			mouse_report.x, mouse_report.y,
    421			mouse_report.h, mouse_report.v);
    422		memcpy(&mouse_report_prev, &mouse_report,
    423			sizeof(mouse_report));
    424		sent = true;
    425	}
    426
    427	memset(&mouse_report, 0, sizeof(mouse_report));
    428
    429	return sent;
    430}
    431
    432bool
    433send_consumer_report(void)
    434{
    435	bool sent;
    436
    437	sent = false;
    438	if (memcmp(&consumer_report, &consumer_report_prev,
    439			sizeof(consumer_report))) {
    440		INFO(LOG_HID, "CONSUMER SEND");
    441		tud_hid_n_report(INST_HID_MISC, REPORT_ID_CONSUMER,
    442			&consumer_report.code, 2);
    443		memcpy(&consumer_report_prev, &consumer_report,
    444			sizeof(consumer_report));
    445		return true;
    446	}
    447
    448	memset(&consumer_report, 0, sizeof(consumer_report));
    449
    450	return sent;
    451}
    452
    453bool
    454send_system_report(void)
    455{
    456	bool sent;
    457
    458	sent = false;
    459	if (memcmp(&system_report, &system_report_prev,
    460			sizeof(system_report))) {
    461		tud_hid_n_report(INST_HID_MISC, REPORT_ID_SYSTEM,
    462			&system_report.code, 2);
    463		memcpy(&system_report_prev, &system_report,
    464			sizeof(system_report));
    465		sent = true;
    466	}
    467
    468	memset(&system_report, 0, sizeof(system_report));
    469
    470	return sent;
    471}
    472
    473bool
    474send_gamepad_report(void)
    475{
    476	bool sent;
    477
    478	sent = false;
    479	if (memcmp(&gamepad_report, &gamepad_report_prev,
    480			sizeof(gamepad_report))) {
    481		tud_hid_n_gamepad_report(INST_HID_MISC, REPORT_ID_GAMEPAD,
    482			gamepad_report.x, gamepad_report.y, gamepad_report.z,
    483			gamepad_report.rz, gamepad_report.rx, gamepad_report.ry,
    484			gamepad_report.hat, gamepad_report.btns);
    485		memcpy(&gamepad_report_prev, &gamepad_report,
    486			sizeof(gamepad_report));
    487		sent = true;
    488	}
    489
    490	memset(&gamepad_report, 0, sizeof(gamepad_report));
    491
    492	return sent;
    493}
    494
    495bool
    496send_hid_report(int id)
    497{
    498	switch (id) {
    499	case REPORT_ID_MOUSE:
    500		return send_mouse_report();
    501	case REPORT_ID_CONSUMER:
    502		return send_consumer_report();
    503	case REPORT_ID_SYSTEM:
    504		return send_system_report();
    505	case REPORT_ID_GAMEPAD:
    506		return send_gamepad_report();
    507	}
    508
    509	return false;
    510}
    511
    512void
    513send_next_hid_report(uint8_t min)
    514{
    515	uint8_t id;
    516
    517	for (id = min; id < REPORT_ID_MAX; id++) {
    518		if (send_hid_report(id))
    519			break;
    520	}
    521}
    522
    523bool
    524hid_ready()
    525{
    526	return tud_hid_n_ready(INST_HID_KBD)
    527		&& tud_hid_n_ready(INST_HID_MISC);
    528}
    529
    530void
    531tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol)
    532{
    533	if (protocol == HID_PROTOCOL_BOOT) {
    534		led_rgb = SOFT_YELLOW;
    535	} else {
    536		led_rgb = SOFT_PURPLE;
    537	}
    538	led_mode = LED_ON;
    539	led_reset = true;
    540}
    541
    542void
    543tud_hid_report_complete_cb(uint8_t instance,
    544	uint8_t const *report, uint8_t len)
    545{
    546	if (report[0] >= REPORT_ID_MIN)
    547		send_next_hid_report(report[0] + 1);
    548}
    549
    550void
    551hid_init(void)
    552{
    553}
    554
    555void
    556hid_force_release(uint x, uint y)
    557{
    558	process_keyrelease(keysyms[y][x], x, y);
    559	keysyms[y][x] = KC_NO;
    560}
    561
    562void
    563hid_switch_layer_with_key(uint8_t layer, uint x, uint y)
    564{
    565	active_layers_push(layer, y * KEY_COLS + x);
    566	keysyms[y][x] = SW(layer);
    567	seen_mat[y][x] = true;
    568}
    569
    570void
    571hid_send_macro(const uint32_t *keysyms, uint cnt)
    572{
    573	static const uint mx = MACRO_X, my = MACRO_Y;
    574	struct hid_keyboard_report tmp;
    575	uint32_t start_ms;
    576	uint i, k;
    577
    578	/* NOTE: layer switching is not supported for macros (not needed),
    579	 * to preserve the current layers we reference a key which is not
    580	 * in-use to prevent accidentally unmapping layers on release */
    581
    582	macro_held_reset();
    583
    584	active_mods = 0;
    585	active_weak_mods = 0;
    586	macro_running = true;
    587	memset(&keyboard_report, 0, sizeof(keyboard_report));
    588	memset(&keyboard_report_prev, 0, sizeof(keyboard_report));
    589	memset(&seen_mat, 0, sizeof(seen_mat));
    590	while (!hid_ready()) tud_task();
    591
    592	for (i = 0; i < cnt; i++) {
    593		if (IS_MACRO_DELAY(keysyms[i])) {
    594			start_ms = board_millis();
    595			while (board_millis() - start_ms < TO_DELAY(keysyms[i]))
    596				tud_task();
    597			continue;
    598		}
    599
    600		memset(&keyboard_report, 0, sizeof(keyboard_report));
    601
    602		if (IS_MACRO_RELEASE(keysyms[i]))
    603			macro_held_pop(TO_SYM(keysyms[i]));
    604
    605		for (k = 0; k < i; k++) {
    606			if (!IS_MACRO_HOLD(keysyms[k]))
    607				continue;
    608			if (macro_held_find(TO_SYM(keysyms[k])))
    609				process_keydown(TO_SYM(keysyms[k]), mx, my);
    610		}
    611
    612		if (IS_MACRO_PRESS(keysyms[i])) {
    613			keyboard_report.mods = active_weak_mods | active_mods;
    614			memcpy(&tmp, &keyboard_report, sizeof(keyboard_report));
    615			process_keypress(TO_SYM(keysyms[i]), mx, my);
    616			process_keydown(TO_SYM(keysyms[i]), mx, my);
    617		} else if (IS_MACRO_HOLD(keysyms[i])) {
    618			macro_held_push(TO_SYM(keysyms[i]));
    619		} else if (IS_MACRO_RELEASE(keysyms[i])) {
    620			process_keyrelease(TO_SYM(keysyms[i]), mx, my);
    621			process_keyup(TO_SYM(keysyms[i]), mx, my);
    622		}
    623
    624		send_keyboard_report();
    625		while (!hid_ready()) tud_task();
    626
    627		if (IS_MACRO_PRESS(keysyms[i])) {
    628			memcpy(&keyboard_report, &tmp, sizeof(keyboard_report));
    629			send_keyboard_report();
    630			while (!hid_ready()) tud_task();
    631		}
    632	}
    633
    634	memset(&keyboard_report, 0, sizeof(keyboard_report));
    635	send_keyboard_report();
    636	while (!hid_ready()) tud_task();
    637
    638	macro_running = false;
    639}
    640
    641void
    642hid_task(void)
    643{
    644	update_report();
    645	if (tud_hid_n_ready(INST_HID_KBD))
    646		send_keyboard_report();
    647	if (tud_hid_n_ready(INST_HID_MISC))
    648		send_next_hid_report(REPORT_ID_MIN);
    649}
    650