aboutsummaryrefslogtreecommitdiffstats
path: root/src/hid.c
diff options
context:
space:
mode:
authorLouis Burda <quent.burda@gmail.com>2022-12-19 17:01:11 +0100
committerLouis Burda <quent.burda@gmail.com>2022-12-19 17:01:11 +0100
commitd7c506450be613d6575649218fbcc90a4fabd150 (patch)
tree72319f85b7bce6842d30e495bb06270c81850c33 /src/hid.c
parente4783bbcc4214416befceb53f6af9ebdfb35ba86 (diff)
downloadsxkbd-d7c506450be613d6575649218fbcc90a4fabd150.tar.gz
sxkbd-d7c506450be613d6575649218fbcc90a4fabd150.zip
Enable temporary (weak) mods for specific keys and layer switching with mods
Diffstat (limited to 'src/hid.c')
-rw-r--r--src/hid.c224
1 files changed, 135 insertions, 89 deletions
diff --git a/src/hid.c b/src/hid.c
index e322292..d4fdb7c 100644
--- 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;
}
}