summaryrefslogtreecommitdiffstats
path: root/keyboards
diff options
context:
space:
mode:
authorChristopher Hoage <iam@chrishoage.com>2023-03-10 21:33:52 -0800
committerGitHub <noreply@github.com>2023-03-10 22:33:52 -0700
commit96b0baa230fb0672a68d1f75ba58613526fef0e7 (patch)
tree213d1bcfd434d410ad68046b31b0e2397a6ead13 /keyboards
parentdbd1d3cba111dabf3b2d322a3681039cf46603f7 (diff)
[Keyboard] Add Spleeb default and custom firmware (#19481)
Co-authored-by: jack <0x6a73@protonmail.com>
Diffstat (limited to 'keyboards')
-rw-r--r--keyboards/spleeb/config.h36
-rw-r--r--keyboards/spleeb/info.json124
-rw-r--r--keyboards/spleeb/keymaps/chrishoage/config.h15
-rw-r--r--keyboards/spleeb/keymaps/chrishoage/keymap.c127
-rw-r--r--keyboards/spleeb/keymaps/chrishoage/rules.mk11
-rw-r--r--keyboards/spleeb/keymaps/default/keymap.c33
-rw-r--r--keyboards/spleeb/lib/glcdfont.c233
-rw-r--r--keyboards/spleeb/mcuconf.h9
-rw-r--r--keyboards/spleeb/readme.md109
-rw-r--r--keyboards/spleeb/rules.mk1
-rw-r--r--keyboards/spleeb/spleeb.c544
-rw-r--r--keyboards/spleeb/spleeb.h149
12 files changed, 1391 insertions, 0 deletions
diff --git a/keyboards/spleeb/config.h b/keyboards/spleeb/config.h
new file mode 100644
index 0000000000..72a09e89c9
--- /dev/null
+++ b/keyboards/spleeb/config.h
@@ -0,0 +1,36 @@
+// Copyright 2022 Chris Hoage (@chrishoage)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+// Auto mouse layer makes use of the Cirque touchdown indicator which requires
+// the touch sensor to be on the master side
+#define MASTER_RIGHT
+
+// Sync later, led, and mod state for use on OLED on slave side
+#define SPLIT_LAYER_STATE_ENABLE
+#define SPLIT_LED_STATE_ENABLE
+#define SPLIT_MODS_ENABLE
+// Transport dpi and enc mode for display on oled
+#define SPLIT_TRANSACTION_IDS_KB RPC_ID_KB_CONFIG_SYNC
+
+#ifdef POINTING_DEVICE_ENABLE
+# define POINTING_DEVICE_AUTO_MOUSE_ENABLE
+// Absolute mode allows for z/touchdown triggering of auto mouse layer with out
+// moving finger
+# define CIRQUE_PINNACLE_POSITION_MODE CIRQUE_PINNACLE_ABSOLUTE_MODE
+# define POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE
+#endif // POINTING_DEVICE_ENABLE
+
+#define I2C_DRIVER I2CD1
+#define I2C1_SDA_PIN GP16
+#define I2C1_SCL_PIN GP17
+
+#ifdef OLED_ENABLE
+# define OLED_DISPLAY_128X64
+# define OLED_FONT_H "./lib/glcdfont.c"
+#endif // OLED_ENABLE
+
+#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET
+#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED GP17
+#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 1000U
diff --git a/keyboards/spleeb/info.json b/keyboards/spleeb/info.json
new file mode 100644
index 0000000000..0af488135d
--- /dev/null
+++ b/keyboards/spleeb/info.json
@@ -0,0 +1,124 @@
+{
+ "manufacturer": "Chris Hoage",
+ "keyboard_name": "spleeb",
+ "maintainer": "chrishoage",
+ "bootloader": "rp2040",
+ "diode_direction": "COL2ROW",
+ "encoder": {
+ "enabled": true,
+ "rotary": [
+ {
+ "pin_a": "GP4",
+ "pin_b": "GP21",
+ "resolution": 2
+ }
+ ]
+ },
+ "features": {
+ "nkro": true
+ },
+ "matrix_pins": {
+ "cols": ["GP23", "GP20", "GP22", "GP26", "GP27", "GP28", "GP29"],
+ "rows": ["GP5", "GP6", "GP7", "GP8", "GP9"]
+ },
+ "processor": "RP2040",
+ "board": "QMK_PM2040",
+ "secure": {
+ "idle_timeout": 60000,
+ "unlock_sequence": [
+ [5, 0],
+ [5, 1]
+ ],
+ "unlock_timeout": 5000
+ },
+ "split": {
+ "enabled": true,
+ "soft_serial_pin": "GP1",
+ "encoder": {
+ "right": {
+ "rotary": [
+ {
+ "pin_a": "GP21",
+ "pin_b": "GP4"
+ }
+ ]
+ }
+ }
+ },
+ "url": "https://github.com/chrishoage/spleeb",
+ "usb": {
+ "device_version": "0.0.1",
+ "pid": "0x4242",
+ "vid": "0xFEED"
+ },
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ { "matrix": [0, 0], "x": 0, "y": 0.6 },
+ { "matrix": [0, 1], "x": 1, "y": 0.6 },
+ { "matrix": [0, 2], "x": 2, "y": 0.2 },
+ { "matrix": [0, 3], "x": 3, "y": 0 },
+ { "matrix": [0, 4], "x": 4, "y": 0.2 },
+ { "matrix": [0, 5], "x": 5, "y": 0.4 },
+ { "matrix": [0, 6], "x": 6, "y": 0.9 },
+ { "matrix": [5, 6], "x": 9.75, "y": 0.9 },
+ { "matrix": [5, 5], "x": 10.75, "y": 0.4 },
+ { "matrix": [5, 4], "x": 11.75, "y": 0.2 },
+ { "matrix": [5, 3], "x": 12.75, "y": 0 },
+ { "matrix": [5, 2], "x": 13.75, "y": 0.2 },
+ { "matrix": [5, 1], "x": 14.75, "y": 0.6 },
+ { "matrix": [5, 0], "x": 15.75, "y": 0.6 },
+ { "matrix": [1, 0], "x": 0, "y": 1.6 },
+ { "matrix": [1, 1], "x": 1, "y": 1.6 },
+ { "matrix": [1, 2], "x": 2, "y": 1.2 },
+ { "matrix": [1, 3], "x": 3, "y": 1 },
+ { "matrix": [1, 4], "x": 4, "y": 1.2 },
+ { "matrix": [1, 5], "x": 5, "y": 1.4 },
+ { "matrix": [1, 6], "x": 6, "y": 1.9 },
+ { "matrix": [6, 6], "x": 9.75, "y": 1.9 },
+ { "matrix": [6, 5], "x": 10.75, "y": 1.4 },
+ { "matrix": [6, 4], "x": 11.75, "y": 1.2 },
+ { "matrix": [6, 3], "x": 12.75, "y": 1 },
+ { "matrix": [6, 2], "x": 13.75, "y": 1.2 },
+ { "matrix": [6, 1], "x": 14.75, "y": 1.6 },
+ { "matrix": [6, 0], "x": 15.75, "y": 1.6 },
+ { "matrix": [2, 0], "x": 0, "y": 2.6 },
+ { "matrix": [2, 1], "x": 1, "y": 2.6 },
+ { "matrix": [2, 2], "x": 2, "y": 2.2 },
+ { "matrix": [2, 3], "x": 3, "y": 2 },
+ { "matrix": [2, 4], "x": 4, "y": 2.2 },
+ { "matrix": [2, 5], "x": 5, "y": 2.4 },
+ { "matrix": [2, 6], "x": 6, "y": 2.9 },
+ { "matrix": [7, 6], "x": 9.75, "y": 2.9 },
+ { "matrix": [7, 5], "x": 10.75, "y": 2.4 },
+ { "matrix": [7, 4], "x": 11.75, "y": 2.2 },
+ { "matrix": [7, 3], "x": 12.75, "y": 2 },
+ { "matrix": [7, 2], "x": 13.75, "y": 2.2 },
+ { "matrix": [7, 1], "x": 14.75, "y": 2.6 },
+ { "matrix": [7, 0], "x": 15.75, "y": 2.6 },
+ { "matrix": [3, 1], "x": 1, "y": 3.6 },
+ { "matrix": [3, 2], "x": 2, "y": 3.2 },
+ { "matrix": [3, 3], "x": 3, "y": 3 },
+ { "matrix": [3, 4], "x": 4, "y": 3.2 },
+ { "matrix": [3, 5], "x": 5, "y": 3.4 },
+ { "matrix": [3, 6], "x": 7.2, "y": 3.15 },
+ { "matrix": [8, 6], "x": 8.6, "y": 3.15 },
+ { "matrix": [8, 5], "x": 10.75, "y": 3.4 },
+ { "matrix": [8, 4], "x": 11.75, "y": 3.2 },
+ { "matrix": [8, 3], "x": 12.75, "y": 3 },
+ { "matrix": [8, 2], "x": 13.75, "y": 3.2 },
+ { "matrix": [8, 1], "x": 14.75, "y": 3.6 },
+ { "matrix": [4, 2], "x": 3, "y": 4.45 },
+ { "matrix": [4, 3], "x": 4, "y": 4.45 },
+ { "matrix": [4, 4], "x": -0.15, "y": 4.65 },
+ { "h": 1.25, "matrix": [4, 5], "x": 0.85, "y": 4.4 },
+ { "h": 1.25, "matrix": [4, 6], "x": 1.85, "y": 4.4 },
+ { "h": 1.25, "matrix": [9, 6], "x": -3.1, "y": 4.6 },
+ { "h": 1.25, "matrix": [9, 5], "x": -2.1, "y": 4.6 },
+ { "matrix": [9, 4], "x": -1.1, "y": 4.85 },
+ { "matrix": [9, 3], "x": 11.75, "y": 4.45 },
+ { "matrix": [9, 2], "x": 12.75, "y": 4.45 }
+ ]
+ }
+ }
+}
diff --git a/keyboards/spleeb/keymaps/chrishoage/config.h b/keyboards/spleeb/keymaps/chrishoage/config.h
new file mode 100644
index 0000000000..0ac75d3041
--- /dev/null
+++ b/keyboards/spleeb/keymaps/chrishoage/config.h
@@ -0,0 +1,15 @@
+// Copyright 2022 Chris Hoage (@chrishoage)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#define AUTO_MOUSE_TIME 250
+
+#define CIRQUE_PINNACLE_DIAMETER_MM 35
+#define POINTING_DEVICE_ROTATION_180
+
+#define SPLEEB_DRAGSCROLL_REVERSE_X
+#define SPLEEB_ENCODER_MODE_MAP_ENABLE
+
+#define BOOTMAGIC_LITE_ROW 5
+#define BOOTMAGIC_LITE_COLUMN 6
diff --git a/keyboards/spleeb/keymaps/chrishoage/keymap.c b/keyboards/spleeb/keymaps/chrishoage/keymap.c
new file mode 100644
index 0000000000..2650c1aebf
--- /dev/null
+++ b/keyboards/spleeb/keymaps/chrishoage/keymap.c
@@ -0,0 +1,127 @@
+// Copyright 2022 Chris Hoage (@chrishoage)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+// Double tap TD(0) to enter bootloader
+static void enter_qk_boot(qk_tap_dance_state_t *state, void *user_data) {
+ if (state->count >= 2) {
+ reset_keyboard();
+ reset_tap_dance(state);
+ }
+}
+
+enum SpleebLayer { _BASE = 0, _FN, _MOUSE };
+
+qk_tap_dance_action_t tap_dance_actions[] = {[0] = ACTION_TAP_DANCE_FN(enter_qk_boot)};
+
+// clang-format off
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+ [_BASE] = LAYOUT(
+ KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_ESC, KC_BSPC, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSLS,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_MINS, KC_EQL, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_QUOT,
+ KC_LSFT, KC_A, KC_S, KC_D, KC_F, KC_G, KC_LBRC, KC_RBRC, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_RSFT,
+ KC_Z, KC_X, KC_C, KC_V, KC_B, KC_MUTE, ENC_STR, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH,
+ KC_LCTL, KC_LALT, KC_LGUI, KC_ENT, MO(1), MO(1), KC_SPC, KC_RGUI, KC_RALT, KC_RCTL
+ ),
+
+ [_FN] = LAYOUT(
+ KC_PAUS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_ESC, KC_DEL, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_PSCR,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_HOME, KC_PGDN, KC_PGUP, KC_END, KC_TRNS, KC_TRNS,
+ KC_CAPS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, KC_TRNS, QK_RBT,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, ENC_STL, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, TD(0),
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_SPC, KC_TRNS, KC_TRNS, KC_ENT, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [_MOUSE] = LAYOUT(
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ DRGSCRL, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, SNIPING, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_BTN3, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_BTN1, KC_BTN2, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+};
+// clang-format on
+
+bool encoder_update_user(uint8_t index, bool clockwise) {
+ if (get_mods() & MOD_MASK_GUI) {
+ // When GUI is held trigger [ ] to move workspaces
+ tap_code(clockwise ? KC_RBRC : KC_LBRC);
+ return false;
+ }
+
+ if (get_mods() & MOD_MASK_CTRL) {
+ // When CTRL is hled trigger page up/down to move tabs (Firefox, VSCode)
+ tap_code(clockwise ? KC_PGDN : KC_PGUP);
+ return false;
+ }
+
+ if (get_mods() & MOD_MASK_ALT) {
+ // When ALT is held trigger up/down to move line up/down
+ tap_code(clockwise ? KC_DOWN : KC_UP);
+ return false;
+ }
+
+ // Defer to encoder_update_kb to trigger spleeb_encoder_mode_trigger
+ return true;
+}
+
+enum spleeb_enc_mode {
+ DEF_DPI,
+ SNP_DPI,
+ VOL,
+ SEL,
+};
+
+void spleeb_encoder_mode_trigger(uint8_t mode, bool clockwise) {
+ dprintf("spleeb_encoder_mode_trigger m: %u, c: %u\n", mode, clockwise);
+ switch (mode) {
+ case DEF_DPI:
+ spleeb_cycle_pointer_default_dpi(clockwise);
+ break;
+ case SNP_DPI:
+ spleeb_cycle_pointer_sniping_dpi(clockwise);
+ break;
+ case VOL:
+ tap_code(clockwise ? KC_VOLU : KC_VOLD);
+ break;
+ case SEL: {
+ bool is_shift = get_mods() & MOD_MASK_SHIFT;
+ uint16_t dir = clockwise ? KC_RIGHT : KC_LEFT;
+ if (is_shift) {
+ tap_code(dir);
+ } else {
+ tap_code16(LSFT(LCTL(dir)));
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+const char *spleeb_encoder_mode_string(uint8_t mode) {
+ switch (mode) {
+ case DEF_DPI:
+ return "df dpi";
+ case SNP_DPI:
+ return "sn dpi";
+ case VOL:
+ return "volume";
+ case SEL:
+ return "select";
+ }
+
+ return get_u8_str(mode, ' ');
+}
+
+void pointing_device_init_user(void) {
+ set_auto_mouse_layer(_MOUSE);
+}
+
+const spleeb_enc_mode_t spleeb_encoder_mode_map[NUM_ENCODERS][SPLEEB_ENCODER_MODE_COUNT] = {
+ [0] = {SPLEEB_ENC_MODE(VOL), SPLEEB_ENC_MODE(SEL)},
+ [1] = {SPLEEB_ENC_MODE(DEF_DPI), SPLEEB_ENC_MODE(SNP_DPI), SPLEEB_ENC_MODE(SEL)},
+};
diff --git a/keyboards/spleeb/keymaps/chrishoage/rules.mk b/keyboards/spleeb/keymaps/chrishoage/rules.mk
new file mode 100644
index 0000000000..117c55fd8b
--- /dev/null
+++ b/keyboards/spleeb/keymaps/chrishoage/rules.mk
@@ -0,0 +1,11 @@
+TAP_DANCE_ENABLE = yes
+BOOTMAGIC_ENABLE = yes
+MOUSEKEY_ENABLE = yes
+EXTRAKEY_ENABLE = yes
+ENCODER_ENABLE = yes
+
+POINTING_DEVICE_ENABLE = yes
+POINTING_DEVICE_DRIVER = cirque_pinnacle_i2c
+
+OLED_ENABLE = yes
+OLED_DRIVER = SSD1306
diff --git a/keyboards/spleeb/keymaps/default/keymap.c b/keyboards/spleeb/keymaps/default/keymap.c
new file mode 100644
index 0000000000..dca49efd34
--- /dev/null
+++ b/keyboards/spleeb/keymaps/default/keymap.c
@@ -0,0 +1,33 @@
+// Copyright 2022 Chris Hoage (@chrishoage)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+// clang-format off
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+ [0] = LAYOUT(
+ KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_ESC, KC_BSPC, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSLS,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_MINS, KC_EQL, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_QUOT,
+ KC_LSFT, KC_A, KC_S, KC_D, KC_F, KC_G, KC_LBRC, KC_RBRC, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_RSFT,
+ KC_Z, KC_X, KC_C, KC_V, KC_B, KC_NO, KC_NO, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH,
+ KC_LCTL, KC_LALT, KC_LGUI, KC_ENT, MO(1), MO(1), KC_SPC, KC_RGUI, KC_RALT, KC_RCTL
+ ),
+
+ [1] = LAYOUT(
+ KC_PAUS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_ESC, KC_DEL, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_PSCR,
+ KC_LCAP, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_HOME, KC_PGDN, KC_PGUP, KC_END, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_SPC, KC_TRNS, KC_TRNS, KC_ENT, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [2] = LAYOUT(
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+};
+// clang-format on
diff --git a/keyboards/spleeb/lib/glcdfont.c b/keyboards/spleeb/lib/glcdfont.c
new file mode 100644
index 0000000000..5a7fcdaee2
--- /dev/null
+++ b/keyboards/spleeb/lib/glcdfont.c
@@ -0,0 +1,233 @@
+// Copyright 2022 Chris Hoage (@chrishoage)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "progmem.h"
+
+// clang-format off
+static const unsigned char PROGMEM font[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x00,
+ 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x00,
+ 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x00,
+ 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x00,
+ 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x00,
+ 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00,
+ 0x00, 0x18, 0x3C, 0x18, 0x00, 0x00,
+ 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00,
+ 0x00, 0x18, 0x24, 0x18, 0x00, 0x00,
+ 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x00,
+ 0x30, 0x48, 0x3A, 0x06, 0x0E, 0x00,
+ 0x26, 0x29, 0x79, 0x29, 0x26, 0x00,
+ 0x40, 0x7F, 0x05, 0x05, 0x07, 0x00,
+ 0x40, 0x7F, 0x05, 0x25, 0x3F, 0x00,
+ 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x00,
+ 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 0x00,
+ 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x00,
+ 0x14, 0x22, 0x7F, 0x22, 0x14, 0x00,
+ 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x00,
+ 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00,
+ 0x00, 0x66, 0x89, 0x95, 0x6A, 0x00,
+ 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
+ 0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x00,
+ 0x08, 0x04, 0x7E, 0x04, 0x08, 0x00,
+ 0x10, 0x20, 0x7E, 0x20, 0x10, 0x00,
+ 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00,
+ 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00,
+ 0x1E, 0x10, 0x10, 0x10, 0x10, 0x00,
+ 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x00,
+ 0x30, 0x38, 0x3E, 0x38, 0x30, 0x00,
+ 0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00,
+ 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
+ 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00,
+ 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00,
+ 0x23, 0x13, 0x08, 0x64, 0x62, 0x00,
+ 0x36, 0x49, 0x56, 0x20, 0x50, 0x00,
+ 0x00, 0x08, 0x07, 0x03, 0x00, 0x00,
+ 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00,
+ 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00,
+ 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00,
+ 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00,
+ 0x00, 0x80, 0x70, 0x30, 0x00, 0x00,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
+ 0x00, 0x00, 0x60, 0x60, 0x00, 0x00,
+ 0x20, 0x10, 0x08, 0x04, 0x02, 0x00,
+ 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00,
+ 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00,
+ 0x72, 0x49, 0x49, 0x49, 0x46, 0x00,
+ 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00,
+ 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00,
+ 0x27, 0x45, 0x45, 0x45, 0x39, 0x00,
+ 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00,
+ 0x41, 0x21, 0x11, 0x09, 0x07, 0x00,
+ 0x36, 0x49, 0x49, 0x49, 0x36, 0x00,
+ 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00,
+ 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x40, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x14, 0x22, 0x41, 0x00,
+ 0x14, 0x14, 0x14, 0x14, 0x14, 0x00,
+ 0x00, 0x41, 0x22, 0x14, 0x08, 0x00,
+ 0x02, 0x01, 0x59, 0x09, 0x06, 0x00,
+ 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00,
+ 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00,
+ 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00,
+ 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00,
+ 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00,
+ 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00,
+ 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00,
+ 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00,
+ 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00,
+ 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00,
+ 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00,
+ 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00,
+ 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00,
+ 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00,
+ 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00,
+ 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00,
+ 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00,
+ 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00,
+ 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00,
+ 0x26, 0x49, 0x49, 0x49, 0x32, 0x00,
+ 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00,
+ 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00,
+ 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00,
+ 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00,
+ 0x63, 0x14, 0x08, 0x14, 0x63, 0x00,
+ 0x03, 0x04, 0x78, 0x04, 0x03, 0x00,
+ 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00,
+ 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00,
+ 0x02, 0x04, 0x08, 0x10, 0x20, 0x00,
+ 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00,
+ 0x04, 0x02, 0x01, 0x02, 0x04, 0x00,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00,
+ 0x00, 0x03, 0x07, 0x08, 0x00, 0x00,
+ 0x20, 0x54, 0x54, 0x78, 0x40, 0x00,
+ 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00,
+ 0x38, 0x44, 0x44, 0x44, 0x20, 0x00,
+ 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00,
+ 0x38, 0x54, 0x54, 0x54, 0x18, 0x00,
+ 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00,
+ 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00,
+ 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00,
+ 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00,
+ 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00,
+ 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00,
+ 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00,
+ 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00,
+ 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00,
+ 0x38, 0x44, 0x44, 0x44, 0x38, 0x00,
+ 0xFC, 0x18, 0x24, 0x24, 0x18, 0x00,
+ 0x18, 0x24, 0x24, 0x18, 0xFC, 0x00,
+ 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00,
+ 0x48, 0x54, 0x54, 0x54, 0x24, 0x00,
+ 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00,
+ 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00,
+ 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00,
+ 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00,
+ 0x44, 0x28, 0x10, 0x28, 0x44, 0x00,
+ 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00,
+ 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00,
+ 0x00, 0x08, 0x36, 0x41, 0x00, 0x00,
+ 0x00, 0x00, 0x77, 0x00, 0x00, 0x00,
+ 0x00, 0x41, 0x36, 0x08, 0x00, 0x00,
+ 0x02, 0x01, 0x02, 0x04, 0x02, 0x00,
+ 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xE0, 0xF0, 0xF0, 0xF0, 0xE0, 0xEC,
+ 0xEE, 0xF7, 0xF3, 0x70, 0x20, 0x00,
+ 0x7C, 0x7C, 0x7C, 0x7E, 0x00, 0x7E,
+ 0x7E, 0x7E, 0x7F, 0x7F, 0x7F, 0x00,
+ 0x00, 0x80, 0xC0, 0xE0, 0x7E, 0x5B,
+ 0x4F, 0x5B, 0xFE, 0xC0, 0x00, 0x00,
+ 0xC0, 0x00, 0xDC, 0xD7, 0xDE, 0xDE,
+ 0xDE, 0xD7, 0xDC, 0x00, 0xC0, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0xFA, 0xA1,
+ 0xFA, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x1F, 0x3F, 0x7F, 0x7F, 0x7F,
+ 0x7F, 0x7F, 0x3F, 0x1E, 0x0C, 0x00,
+ 0x1F, 0x1F, 0x1F, 0x3F, 0x00, 0x3F,
+ 0x3F, 0x3F, 0x7F, 0x7F, 0x7F, 0x00,
+ 0x30, 0x7B, 0x7F, 0x78, 0x30, 0x20,
+ 0x20, 0x30, 0x78, 0x7F, 0x3B, 0x00,
+ 0x03, 0x00, 0x0F, 0x7F, 0x0F, 0x0F,
+ 0x0F, 0x7F, 0x0F, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0xFC, 0x87, 0x95,
+ 0xB5, 0x87, 0xFC, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xBB, 0x81,
+ 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x9B, 0xAD, 0xAD,
+ 0xAD, 0xB3, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xDD, 0xBD, 0xB5,
+ 0xB5, 0xC9, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xE1, 0xEF, 0xEF,
+ 0x81, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x91, 0xB5, 0xB5,
+ 0xB5, 0x85, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x81, 0xB5, 0xB5,
+ 0xB5, 0x85, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x74, 0x42,
+ 0x74, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x18, 0x0C, 0x06,
+ 0x0C, 0x18, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x04, 0x08, 0x10,
+ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00,
+ 0x00, 0x00, 0xE7, 0xA5, 0xFF, 0x24,
+ 0x24, 0xFF, 0xA5, 0xE7, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+// clang-format on
diff --git a/keyboards/spleeb/mcuconf.h b/keyboards/spleeb/mcuconf.h
new file mode 100644
index 0000000000..30b20fdcbd
--- /dev/null
+++ b/keyboards/spleeb/mcuconf.h
@@ -0,0 +1,9 @@
+// Copyright 2022 Chris Hoage (@chrishoage)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include_next <mcuconf.h>
+
+#undef RP_I2C_USE_I2C0
+#define RP_I2C_USE_I2C0 TRUE
diff --git a/keyboards/spleeb/readme.md b/keyboards/spleeb/readme.md
new file mode 100644
index 0000000000..0b42352e29
--- /dev/null
+++ b/keyboards/spleeb/readme.md
@@ -0,0 +1,109 @@
+# spleeb
+
+![spleeb](https://i.imgur.com/2rmZa6Mh.jpg)
+
+A 5x7 split keyboard that has support for rotary encoders, an oled and a Ciruqe touchpad
+
+* Keyboard Maintainer: [Chris Hoage](https://github.com/chrishoage)
+* Hardware Supported: Spleeb PCB with a rp2040 MCU (Blok, Elite Pi, etc)
+* Hardware Availability: [https://github.com/chrishoage/spleeb](https://github.com/chrishoage/spleeb)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make spleeb:default
+
+Flashing example for this keyboard:
+
+ make spleeb:default:flash
+
+See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
+
+## Encoder Mode Map
+
+Spleeb firmware has support for an encoder mode map similar to the native encoder map in QMK. The difference is the encoder mode map allows one to change behavior or the encoders independently of the layers. In your keymap.c file you can include something the following:
+
+```c
+enum spleeb_enc_mode {
+ DEF_DPI,
+ SNP_DPI,
+ VOL,
+ SEL,
+};
+
+void spleeb_encoder_mode_trigger(uint8_t mode, bool clockwise) {
+ dprintf("spleeb_encoder_mode_trigger m: %u, c: %u\n", mode, clockwise);
+ switch (mode) {
+ case DEF_DPI:
+ spleeb_cycle_pointer_default_dpi(clockwise);
+ break;
+ case SNP_DPI:
+ spleeb_cycle_pointer_sniping_dpi(clockwise);
+ break;
+ case VOL:
+ tap_code(clockwise ? KC_VOLU : KC_VOLD);
+ break;
+ case SEL:
+ bool is_shift = get_mods() & MOD_MASK_SHIFT;
+ uint16_t dir = clockwise ? KC_RIGHT : KC_LEFT;
+ if (is_shift) {
+ tap_code(dir);
+ } else {
+ tap_code16(LSFT(LCTL(dir)));
+ }
+
+ default:
+ break;
+ }
+}
+
+const char *spleeb_encoder_mode_string(uint8_t mode) {
+ switch (mode) {
+ case DEF_DPI:
+ return "df dpi";
+ case SNP_DPI:
+ return "sn dpi";
+ case VOL:
+ return "volume";
+ case SEL:
+ return "select";
+ }
+
+ return get_u8_str(mode, ' ');
+}
+
+void pointing_device_init_user(void) {
+ set_auto_mouse_layer(_MOUSE);
+}
+
+const spleeb_enc_mode_t spleeb_encoder_mode_map[NUM_ENCODERS][SPLEEB_ENCODER_MODE_COUNT] = {
+ [0] = {SPLEEB_ENC_MODE(VOL), SPLEEB_ENC_MODE(SEL)},
+ [1] = {SPLEEB_ENC_MODE(DEF_DPI), SPLEEB_ENC_MODE(SNP_DPI), SPLEEB_ENC_MODE(SEL)},
+};
+```
+
+This will enable 4 encoder modes. On the left side there will be modes for volume control and text selection. On the right side there will be three modes to allow controlling the DPI of the Cirque trackpad and also text selection.
+
+## Custom Keycodes
+
+This firmware defines the following custom keycodes for use in keymap.c. Depending on your defines the pointing or encoder specific keymaps will not be included.
+
+```c
+#define DF_MOD POINTER_DEFAULT_DPI_FORWARD
+#define DF_RMOD POINTER_DEFAULT_DPI_REVERSE
+#define SP_MOD POINTER_SNIPING_DPI_FORWARD
+#define SP_RMOD POINTER_SNIPING_DPI_REVERSE
+#define SNIPING SNIPING_MODE
+#define SNP_TOG SNIPING_MODE_TOGGLE
+#define DRGSCRL DRAGSCROLL_MODE
+#define DRG_TOG DRAGSCROLL_MODE_TOGGLE
+#define ENC_STL ENC_MODE_STEP_LEFT
+#define ENC_STR ENC_MODE_STEP_RIGHT
+```
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
+* **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead
+* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
diff --git a/keyboards/spleeb/rules.mk b/keyboards/spleeb/rules.mk
new file mode 100644
index 0000000000..161ec22b16
--- /dev/null
+++ b/keyboards/spleeb/rules.mk
@@ -0,0 +1 @@
+SERIAL_DRIVER = vendor
diff --git a/keyboards/spleeb/spleeb.c b/keyboards/spleeb/spleeb.c
new file mode 100644
index 0000000000..658f30df75
--- /dev/null
+++ b/keyboards/spleeb/spleeb.c
@@ -0,0 +1,544 @@
+// Copyright 2022 Chris Hoage (@chrishoage)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "spleeb.h"
+#include "transactions.h"
+
+#ifdef CONSOLE_ENABLE
+# include "print.h"
+#endif // CONSOLE_ENABLE
+
+#if defined(POINTING_DEVICE_ENABLE) || defined(SPLEEB_ENCODER_MODE_MAP_ENABLE)
+typedef union {
+ uint16_t raw;
+ struct {
+ uint8_t pointer_default_dpi : 4; // 16 steps available.
+ uint8_t pointer_sniping_dpi : 2; // 4 steps available.
+ uint8_t enc_modes[NUM_ENCODERS];
+ bool is_dragscroll_enabled : 1;
+ bool is_sniping_enabled : 1;
+ } __attribute__((packed));
+} spleeb_config_t;
+
+static spleeb_config_t g_spleeb_config = {0};
+
+/**
+ * \brief Set the value of `config` from EEPROM.
+ *
+ * Note that `is_dragscroll_enabled` and `is_sniping_enabled` are purposefully
+ * ignored since we do not want to persist this state to memory. In practice,
+ * this state is always written to maximize write-performances. Therefore, we
+ * explicitly set them to `false` in this function.
+ */
+static void read_spleeb_config_from_eeprom(spleeb_config_t* config) {
+ config->raw = eeconfig_read_kb() & 0xffff;
+ config->is_dragscroll_enabled = false;
+ config->is_sniping_enabled = false;
+}
+
+/**
+ * \brief Save the value of `config` to eeprom.
+ *
+ * Note that all values are written verbatim, including whether drag-scroll
+ * and/or sniper mode are enabled. `read_spleeb_config_from_eeprom(…)`
+ * resets these 2 values to `false` since it does not make sense to persist
+ * these across reboots of the board.
+ */
+static void write_spleeb_config_to_eeprom(spleeb_config_t* config) {
+ eeconfig_update_kb(config->raw);
+}
+
+void eeconfig_init_kb(void) {
+ g_spleeb_config.raw = 0;
+ g_spleeb_config.pointer_default_dpi = 4;
+
+# ifdef SPLEEB_ENCODER_MODE_MAP_ENABLE
+ for (size_t i = 0; i < NUM_ENCODERS; i++) {
+ if (spleeb_encoder_mode_map[i][0].initalized) {
+ spleeb_enc_mode_t* first_enc_mode = &spleeb_encoder_mode_map[i][0];
+ g_spleeb_config.enc_modes[i] = first_enc_mode->mode;
+ }
+ }
+# endif // SPLEEB_ENCODER_MODE_MAP_ENABLE
+
+ write_spleeb_config_to_eeprom(&g_spleeb_config);
+ eeconfig_init_user();
+}
+
+void matrix_init_kb(void) {
+ read_spleeb_config_from_eeprom(&g_spleeb_config);
+ matrix_init_user();
+}
+
+void spleeb_config_sync_handler(uint8_t initiator2target_buffer_size, const void* initiator2target_buffer, uint8_t target2initiator_buffer_size, void* target2initiator_buffer) {
+ if (initiator2target_buffer_size == sizeof(g_spleeb_config)) {
+ memcpy(&g_spleeb_config, initiator2target_buffer, sizeof(g_spleeb_config));
+ }
+}
+
+void keyboard_post_init_kb(void) {
+ transaction_register_rpc(RPC_ID_KB_CONFIG_SYNC, spleeb_config_sync_handler);
+ keyboard_post_init_user();
+}
+
+void housekeeping_task_kb(void) {
+ if (is_keyboard_master()) {
+ // Keep track of the last state, so that we can tell if we need to propagate to slave.
+ static spleeb_config_t last_spleeb_config = {0};
+ static uint32_t last_sync = 0;
+ bool needs_sync = false;
+
+ // Check if the state values are different.
+ if (memcmp(&g_spleeb_config, &last_spleeb_config, sizeof(g_spleeb_config))) {
+ needs_sync = true;
+ memcpy(&last_spleeb_config, &g_spleeb_config, sizeof(g_spleeb_config));
+ }
+ // Send to slave every 500ms regardless of state change.
+ if (timer_elapsed32(last_sync) > 500) {
+ needs_sync = true;
+ }
+
+ // Perform the sync if requested.
+ if (needs_sync) {
+ if (transaction_rpc_send(RPC_ID_KB_CONFIG_SYNC, sizeof(g_spleeb_config), &g_spleeb_config)) {
+ last_sync = timer_read32();
+ }
+ }
+ }
+ // No need to invoke the user-specific callback, as