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 
     24 struct layerkey {
     25 	uint layer;
     26 	uint key;
     27 };
     28 
     29 struct hid_keyboard_report {
     30 	uint8_t mods, weak_mods;
     31 	uint8_t codes[HID_REPORT_CODES];
     32 	uint8_t cnt;
     33 };
     34 
     35 struct hid_mouse_report {
     36 	uint8_t btns;
     37 	int8_t x, y;
     38 	int8_t v, h;
     39 };
     40 
     41 struct hid_consumer_report {
     42 	uint16_t code;
     43 };
     44 
     45 struct hid_system_report {
     46 	uint16_t code;
     47 };
     48 
     49 struct 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 
     56 static uint32_t keysyms[KEY_ROWS][KEY_COLS] = { 0 };
     57 
     58 static struct layerkey active_layers[16] = { 0 };
     59 static uint active_layers_top = 0;
     60 
     61 static struct hid_keyboard_report keyboard_report_prev = { 0 };
     62 static struct hid_keyboard_report keyboard_report = { 0 };
     63 
     64 static struct hid_mouse_report mouse_report_prev = { 0 };
     65 static struct hid_mouse_report mouse_report = { 0 };
     66 
     67 static struct hid_consumer_report consumer_report_prev = { 0 };
     68 static struct hid_consumer_report consumer_report = { 0 };
     69 
     70 static struct hid_system_report system_report_prev = { 0 };
     71 static struct hid_system_report system_report = { 0 };
     72 
     73 static struct hid_gamepad_report gamepad_report_prev = { 0 };
     74 static struct hid_gamepad_report gamepad_report = { 0 };
     75 
     76 static uint8_t active_weak_mods = 0;
     77 static uint8_t active_mods = 0;
     78 
     79 static bool seen_mat[KEY_ROWS][KEY_COLS] = { 0 };
     80 
     81 static uint32_t macro_held_stack[MACRO_HOLD_MAX] = { 0 };
     82 static uint macro_held_cnt = 0;
     83 
     84 static bool macro_running = false;
     85 
     86 /* TODO replace these two with stack method primitives (added to util) */
     87 
     88 static void active_layers_reset(void);
     89 static void active_layers_pop(uint layer);
     90 static void active_layers_push(uint layer, uint key);
     91 
     92 static void macro_held_reset(void);
     93 static void macro_held_pop(uint32_t keysym);
     94 static void macro_held_push(uint32_t keysym);
     95 static bool macro_held_find(uint32_t keysym);
     96 
     97 static void add_keycode(uint8_t keycode);
     98 
     99 /* TODO: add static prototypes */
    100 
    101 void
    102 active_layers_reset(void)
    103 {
    104 	active_layers_top = 0;
    105 }
    106 
    107 bool
    108 active_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 
    120 void
    121 active_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 
    131 void
    132 active_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 
    151 void
    152 macro_held_reset(void)
    153 {
    154 	macro_held_cnt = 0;
    155 }
    156 
    157 void
    158 macro_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 
    171 void
    172 macro_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 
    183 bool
    184 macro_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 
    196 void
    197 add_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 
    208 uint8_t
    209 parse_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 
    242 uint32_t
    243 determine_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 
    258 void
    259 process_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 
    282 void
    283 process_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 
    299 void
    300 process_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 
    315 void
    316 process_keyup(uint32_t keysym, uint x, uint y)
    317 {
    318 }
    319 
    320 void
    321 process_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 
    337 void
    338 update_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 
    351 bool
    352 update_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 
    359 bool
    360 update_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 
    378 bool
    379 send_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 
    410 bool
    411 send_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 
    432 bool
    433 send_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 
    453 bool
    454 send_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 
    473 bool
    474 send_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 
    495 bool
    496 send_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 
    512 void
    513 send_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 
    523 bool
    524 hid_ready()
    525 {
    526 	return tud_hid_n_ready(INST_HID_KBD)
    527 		&& tud_hid_n_ready(INST_HID_MISC);
    528 }
    529 
    530 void
    531 tud_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 
    542 void
    543 tud_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 
    550 void
    551 hid_init(void)
    552 {
    553 }
    554 
    555 void
    556 hid_force_release(uint x, uint y)
    557 {
    558 	process_keyrelease(keysyms[y][x], x, y);
    559 	keysyms[y][x] = KC_NO;
    560 }
    561 
    562 void
    563 hid_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 
    570 void
    571 hid_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 
    641 void
    642 hid_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