From 55f3092d7218165b7888161aa632ac9dfe635fda Mon Sep 17 00:00:00 2001 From: Edward Hesketh Date: Sun, 3 Nov 2024 17:13:45 +0000 Subject: [PATCH] feat: add split keyboard functionality TODO: add tests, fix bugs, etc. --- CMakeLists.txt | 1 + include/squirrel_consumer.h | 5 ++++- include/squirrel_init.h | 5 ++--- include/squirrel_keyboard.h | 8 ++++++++ include/squirrel_split.h | 11 +++++++++++ src/squirrel_consumer.c | 9 ++++++++- src/squirrel_keyboard.c | 22 ++++++++++++++++++++-- src/squirrel_split.c | 27 +++++++++++++++++++++++++++ 8 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 include/squirrel_split.h create mode 100644 src/squirrel_split.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 49ad721..351f1b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,6 +81,7 @@ add_library(squirrel STATIC src/squirrel_consumer.c src/squirrel_init.c src/squirrel_keymap.c + src/squirrel_split.c ) target_include_directories(squirrel PRIVATE include) diff --git a/include/squirrel_consumer.h b/include/squirrel_consumer.h index 1f576ef..0ef62fe 100644 --- a/include/squirrel_consumer.h +++ b/include/squirrel_consumer.h @@ -17,5 +17,8 @@ void consumer_activate_consumer_code(uint16_t consumer_code); void consumer_deactivate_consumer_code(uint16_t consumer_code); // consumer_get_consumer_code returns the currently active consumer code. uint16_t consumer_get_consumer_code(); - +// consumer_get_local_consumer_code returns the currently active consumer code +// without considering any remote boards. This is only useful in split +// keyboards. +uint16_t consumer_get_local_consumer_code(); #endif diff --git a/include/squirrel_init.h b/include/squirrel_init.h index 4c1eb76..3cd30ef 100644 --- a/include/squirrel_init.h +++ b/include/squirrel_init.h @@ -1,5 +1,4 @@ -#ifndef SQUIRREL_INIT_H -#define SQUIRREL_INIT_H +#pragma once + enum squirrel_error squirrel_init(void); // Initialize the keyboard with the total number of keys. -#endif diff --git a/include/squirrel_keyboard.h b/include/squirrel_keyboard.h index 2ef14e3..5296891 100644 --- a/include/squirrel_keyboard.h +++ b/include/squirrel_keyboard.h @@ -16,6 +16,10 @@ void keyboard_deactivate_keycode(uint8_t keycode); // keycodes. 6 is the maximum number of keycodes that can be sent over USB HID. // If there are no keycodes, the function will return false. bool keyboard_get_keycodes(uint8_t (*active_keycodes)[6]); +// keyboard_get_local_keycodes populates the provided array with the first 6 +// active keycodes without considering the input of other connected boards. This +// is only useful for split keyboards. +void keyboard_get_local_keycodes(uint8_t (*active_keycodes)[6]); // keyboard_activate_modifier marks the provided modifier as active. void keyboard_activate_modifier(uint8_t modifier); @@ -23,5 +27,9 @@ void keyboard_activate_modifier(uint8_t modifier); void keyboard_deactivate_modifier(uint8_t modifier); // keyboard_get_modifiers returns a bitfield of active modifiers. uint8_t keyboard_get_modifiers(); +// keyboard_get_local_modifiers returns a bitfield of active modifiers without +// considering the input of other connected boards. This is only useful for +// split keyboards. +uint8_t keyboard_get_local_modifiers(); #endif diff --git a/include/squirrel_split.h b/include/squirrel_split.h new file mode 100644 index 0000000..0efda97 --- /dev/null +++ b/include/squirrel_split.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +// get_packet takes a pointer to a 9-byte array and fills it with the data for +// the packet to be sent. +void get_packet(uint8_t (*packet)[9]); + +extern uint8_t remote_keycodes[6]; +extern uint8_t remote_modifiers; +extern uint16_t remote_consumer_code; diff --git a/src/squirrel_consumer.c b/src/squirrel_consumer.c index cdc9bf4..dbeb1f8 100644 --- a/src/squirrel_consumer.c +++ b/src/squirrel_consumer.c @@ -1,4 +1,5 @@ #include "squirrel_consumer.h" +#include "squirrel_split.h" #include uint16_t consumer_code = 0; @@ -9,4 +10,10 @@ void consumer_deactivate_consumer_code(uint16_t code) { consumer_code = 0; } } -uint16_t consumer_get_consumer_code() { return consumer_code; } +uint16_t consumer_get_consumer_code() { + if (consumer_code != 0) { + return consumer_code; + } + return remote_consumer_code; +} +uint16_t consumer_get_local_consumer_code() { return consumer_code; } diff --git a/src/squirrel_keyboard.c b/src/squirrel_keyboard.c index 59f0b55..a85f14d 100644 --- a/src/squirrel_keyboard.c +++ b/src/squirrel_keyboard.c @@ -1,6 +1,8 @@ #include "squirrel_keyboard.h" +#include "squirrel_split.h" #include #include +#include bool keyboard_keycodes[256] = {false}; uint8_t keyboard_modifiers = 0; @@ -12,9 +14,10 @@ void keyboard_deactivate_keycode(uint8_t keycode) { keyboard_keycodes[keycode] = false; } bool keyboard_get_keycodes(uint8_t (*active_keycodes)[6]) { + memset(*active_keycodes, 0, 6); uint8_t active_keycodes_index = 0; for (int i = 0; (i <= 0xFF) && active_keycodes_index < 6; i++) { - if (!keyboard_keycodes[i]) { + if (!keyboard_keycodes[i] && !remote_keycodes[i]) { continue; } (*active_keycodes)[active_keycodes_index] = i; @@ -23,10 +26,25 @@ bool keyboard_get_keycodes(uint8_t (*active_keycodes)[6]) { return active_keycodes_index != 0; } +void keyboard_get_local_keycodes(uint8_t (*active_keycodes)[6]) { + memset(*active_keycodes, 0, 6); + uint8_t active_keycodes_index = 0; + for (int i = 0; (i <= 0xFF) && active_keycodes_index < 6; i++) { + if (!keyboard_keycodes[i]) { + continue; + } + (*active_keycodes)[active_keycodes_index] = i; + active_keycodes_index++; + } +} + void keyboard_activate_modifier(uint8_t modifier) { keyboard_modifiers |= modifier; } void keyboard_deactivate_modifier(uint8_t modifier) { keyboard_modifiers &= ~modifier; } -uint8_t keyboard_get_modifiers() { return keyboard_modifiers; } +uint8_t keyboard_get_modifiers() { + return keyboard_modifiers | remote_modifiers; +} +uint8_t keyboard_get_local_modifiers() { return keyboard_modifiers; } diff --git a/src/squirrel_split.c b/src/squirrel_split.c new file mode 100644 index 0000000..4b75a69 --- /dev/null +++ b/src/squirrel_split.c @@ -0,0 +1,27 @@ +#include "squirrel_split.h" +#include "squirrel.h" +#include "squirrel_consumer.h" +#include "squirrel_keyboard.h" +#include +#include + +void get_packet(uint8_t (*packet)[9]) { + memset(*packet, 0, 9); + uint8_t local_keycodes[6] = {0}; + keyboard_get_local_keycodes(&local_keycodes); + memcpy(packet, local_keycodes, 6); // 0th to 5th byte + (*packet)[6] = keyboard_get_local_modifiers(); // 6th byte + uint16_t consumer = consumer_get_local_consumer_code(); + (*packet)[7] = consumer & 0xFF; // 7th byte + (*packet)[8] = consumer >> 8; // 8th byte +} + +uint8_t remote_keycodes[6] = {0}; +uint8_t remote_modifiers = 0; +uint16_t remote_consumer_code = 0; + +void process_packet(uint8_t (*packet)[9]) { + memcpy(remote_keycodes, *packet, 6); // 0th to 5th byte + remote_modifiers = (*packet)[6]; // 6th byte + remote_consumer_code = (*packet)[7] | ((*packet)[8] << 8); // 7th and 8th byte +}