summaryrefslogtreecommitdiff
path: root/keyboards/ploopyco/trackball
diff options
context:
space:
mode:
Diffstat (limited to 'keyboards/ploopyco/trackball')
-rw-r--r--keyboards/ploopyco/trackball/config.h69
-rw-r--r--keyboards/ploopyco/trackball/info.json18
-rw-r--r--keyboards/ploopyco/trackball/keymaps/default/keymap.c26
-rw-r--r--keyboards/ploopyco/trackball/keymaps/default/readme.md1
-rw-r--r--keyboards/ploopyco/trackball/keymaps/via/keymap.c26
-rw-r--r--keyboards/ploopyco/trackball/keymaps/via/rules.mk1
-rw-r--r--keyboards/ploopyco/trackball/readme.md68
-rw-r--r--keyboards/ploopyco/trackball/rules.mk30
-rw-r--r--keyboards/ploopyco/trackball/trackball.c237
-rw-r--r--keyboards/ploopyco/trackball/trackball.h40
10 files changed, 516 insertions, 0 deletions
diff --git a/keyboards/ploopyco/trackball/config.h b/keyboards/ploopyco/trackball/config.h
new file mode 100644
index 0000000000..57113d965b
--- /dev/null
+++ b/keyboards/ploopyco/trackball/config.h
@@ -0,0 +1,69 @@
+/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+ * Copyright 2019 Sunjun Kim
+ * Copyright 2020 Ploopy Corporation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "config_common.h"
+
+/* USB Device descriptor parameter */
+#define VENDOR_ID 0x5043
+#define PRODUCT_ID 0x5442
+#define DEVICE_VER 0x0001
+#define MANUFACTURER Ploopyco
+#define PRODUCT Trackball
+
+/* key matrix size */
+#define MATRIX_ROWS 1
+#define MATRIX_COLS 5
+
+/*
+ * Keyboard Matrix Assignments
+ *
+ * Change this to how you wired your keyboard
+ * COLS: AVR pins used for columns, left to right
+ * ROWS: AVR pins used for rows, top to bottom
+ * DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode)
+ * ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
+ *
+ */
+#define DIRECT_PINS { { D4, D2, E6, B5, D7 } }
+
+// These pins are not broken out, and cannot be used normally.
+// They are set as output and pulled high, by default
+#define UNUSED_PINS { D1, D3, B4, B6, B7, D6, C7, F6, F5, F3 }
+
+/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
+#define DEBOUNCE 5
+
+/* define if matrix has ghost (lacks anti-ghosting diodes) */
+//#define MATRIX_HAS_GHOST
+
+/* disable action features */
+//#define NO_ACTION_LAYER
+//#define NO_ACTION_TAPPING
+//#define NO_ACTION_ONESHOT
+#define NO_ACTION_MACRO
+#define NO_ACTION_FUNCTION
+
+/* Much more so than a keyboard, speed matters for a mouse. So we'll go for as high
+ a polling rate as possible. */
+#define USB_POLLING_INTERVAL_MS 1
+
+/* Bootmagic Lite key configuration */
+#define BOOTMAGIC_LITE_ROW 0
+#define BOOTMAGIC_LITE_COLUMN 3
diff --git a/keyboards/ploopyco/trackball/info.json b/keyboards/ploopyco/trackball/info.json
new file mode 100644
index 0000000000..84d512d8dd
--- /dev/null
+++ b/keyboards/ploopyco/trackball/info.json
@@ -0,0 +1,18 @@
+{
+ "keyboard_name": "PloopyCo Trackball",
+ "url": "",
+ "maintainer": "drashna",
+ "width": 8,
+ "height": 3,
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ {"x":0, "y":0, "h":2},
+ {"x":1, "y":0.25, "h":1.5},
+ {"x":2, "y":0, "h":2},
+ {"x":3.5, "y":0, "h":2},
+ {"x":4.5, "y":0, "h":2}
+ ]
+ }
+ }
+}
diff --git a/keyboards/ploopyco/trackball/keymaps/default/keymap.c b/keyboards/ploopyco/trackball/keymaps/default/keymap.c
new file mode 100644
index 0000000000..dc1ad1439f
--- /dev/null
+++ b/keyboards/ploopyco/trackball/keymaps/default/keymap.c
@@ -0,0 +1,26 @@
+/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+ * Copyright 2019 Sunjun Kim
+ * Copyright 2020 Ploopy Corporation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include QMK_KEYBOARD_H
+
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [0] = LAYOUT( /* Base */
+ KC_BTN1, KC_BTN3, KC_BTN2,
+ KC_BTN4, KC_BTN5
+ ),
+};
diff --git a/keyboards/ploopyco/trackball/keymaps/default/readme.md b/keyboards/ploopyco/trackball/keymaps/default/readme.md
new file mode 100644
index 0000000000..f965ef3c32
--- /dev/null
+++ b/keyboards/ploopyco/trackball/keymaps/default/readme.md
@@ -0,0 +1 @@
+# The default keymap for Ploopyco Trackball
diff --git a/keyboards/ploopyco/trackball/keymaps/via/keymap.c b/keyboards/ploopyco/trackball/keymaps/via/keymap.c
new file mode 100644
index 0000000000..dc1ad1439f
--- /dev/null
+++ b/keyboards/ploopyco/trackball/keymaps/via/keymap.c
@@ -0,0 +1,26 @@
+/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+ * Copyright 2019 Sunjun Kim
+ * Copyright 2020 Ploopy Corporation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include QMK_KEYBOARD_H
+
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [0] = LAYOUT( /* Base */
+ KC_BTN1, KC_BTN3, KC_BTN2,
+ KC_BTN4, KC_BTN5
+ ),
+};
diff --git a/keyboards/ploopyco/trackball/keymaps/via/rules.mk b/keyboards/ploopyco/trackball/keymaps/via/rules.mk
new file mode 100644
index 0000000000..1e5b99807c
--- /dev/null
+++ b/keyboards/ploopyco/trackball/keymaps/via/rules.mk
@@ -0,0 +1 @@
+VIA_ENABLE = yes
diff --git a/keyboards/ploopyco/trackball/readme.md b/keyboards/ploopyco/trackball/readme.md
new file mode 100644
index 0000000000..76b9d6a762
--- /dev/null
+++ b/keyboards/ploopyco/trackball/readme.md
@@ -0,0 +1,68 @@
+# Ploopyco Trackball
+
+![Ploopyco Trackball](https://i.redd.it/j7z0y83txps31.jpg)
+
+It's a DIY, QMK Powered Trackball!!!!
+
+Everything works. However the scroll wheel has some issues and acts very odd.
+
+* Keyboard Maintainer: [PloopyCo](https://github.com/ploopyco), [Drashna Jael're](https://github.com/drashna/), [Germ](https://github.com/germ/)
+* Hardware Supported: ATMega32u4 8MHz(3.3v)
+* Hardware Availability: [Store](https://ploopy.co), [GitHub](https://github.com/ploopyco)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make ploopyco/trackball:default:flash
+
+To jump to the bootloader, hold down "Button 4" (immediate right of the trackball)
+
+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).
+
+# Customzing your PloopyCo Trackball
+
+While the defaults are designed so that it can be plugged in and used right away, there are a number of things that you may want to change. Such as adding DPI control, or to use the ball to scroll while holding a button. To allow for this sort of control, there is a callback for both the scroll wheel and the mouse censor.
+
+The default behavior for this is:
+
+```c
+void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v) {
+ mouse_report->h = h;
+ mouse_report->v = v;
+}
+
+void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) {
+ mouse_report->x = x;
+ mouse_report->y = y;
+}
+```
+
+This should allow you to more heavily customize the behavior.
+
+Alternatively, the `process_wheel` and `process_mouse` functions can both be replaced too, to allow for even more functionality.
+
+Additionally, you can change the DPI/CPI or speed of the trackball by calling `pmw_set_cpi` at any time. And tThe default can be changed by adding a define to the keymap's `config.h` file:
+
+ #define PMW_CPI 1600
+
+# Programming QMK-DFU onto the PloopyCo Trackball
+
+If you would rather have DFU on this board, you can use the QMK-DFU bootloader on the device. To do so, you want to run:
+
+ make ploopyco/trackball:default:production
+
+Once you have that, you'll need to [ISP Flash](https://docs.qmk.fm/#/isp_flashing_guide) the chip with the new bootloader hex file created (or the production hex), and set the fuses:
+
+
+| Fuse | Setting |
+|----------|------------------|
+| Low | `0xDF` |
+| High | `0xD8` or `0x98` |
+| Extended | `0xCB` |
+
+Original (Caterina) settings:
+
+| Fuse | Setting |
+|----------|------------------|
+| Low | `0xFF` |
+| High | `0xD8` |
+| Extended | `0xFE` |
diff --git a/keyboards/ploopyco/trackball/rules.mk b/keyboards/ploopyco/trackball/rules.mk
new file mode 100644
index 0000000000..d77431b676
--- /dev/null
+++ b/keyboards/ploopyco/trackball/rules.mk
@@ -0,0 +1,30 @@
+# MCU name
+MCU = atmega32u4
+
+# Processor frequency
+F_CPU = 8000000
+
+# Bootloader selection
+BOOTLOADER = caterina
+
+# Build Options
+# change yes to no to disable
+#
+BOOTMAGIC_ENABLE = lite # Virtual DIP switch configuration
+EXTRAKEY_ENABLE = yes # Audio control and System control
+CONSOLE_ENABLE = yes # Console for debug
+COMMAND_ENABLE = no # Commands for debug and configuration
+# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
+SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
+# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
+NKRO_ENABLE = no # USB Nkey Rollover
+BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
+RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
+UNICODE_ENABLE = no # Unicode
+BLUETOOTH_ENABLE = no # Enable Bluetooth
+AUDIO_ENABLE = no # Audio output
+POINTING_DEVICE_ENABLE = yes
+MOUSEKEY_ENABLE = no # Mouse keys
+
+QUANTUM_LIB_SRC += analog.c spi_master.c
+SRC += pmw3600.c opt_encoder.c
diff --git a/keyboards/ploopyco/trackball/trackball.c b/keyboards/ploopyco/trackball/trackball.c
new file mode 100644
index 0000000000..6a9bffbffe
--- /dev/null
+++ b/keyboards/ploopyco/trackball/trackball.c
@@ -0,0 +1,237 @@
+/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+ * Copyright 2019 Sunjun Kim
+ * Copyright 2020 Ploopy Corporation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include QMK_KEYBOARD_H
+
+#ifndef OPT_DEBOUNCE
+# define OPT_DEBOUNCE 5 // (ms) Time between scroll events
+#endif
+#ifndef SCROLL_BUTT_DEBOUNCE
+# define SCROLL_BUTT_DEBOUNCE 100 // (ms) Time between scroll events
+#endif
+#ifndef OPT_THRES
+# define OPT_THRES 150 // (0-1024) Threshold for actication
+#endif
+#ifndef OPT_SCALE
+# define OPT_SCALE 1 // Multiplier for wheel
+#endif
+
+// TODO: Implement libinput profiles
+// https://wayland.freedesktop.org/libinput/doc/latest/pointer-acceleration.html
+// Compile time accel selection
+// Valid options are ACC_NONE, ACC_LINEAR, ACC_CUSTOM, ACC_QUADRATIC
+
+// Trackball State
+bool is_scroll_clicked = false;
+bool BurstState = false; // init burst state for Trackball module
+uint16_t MotionStart = 0; // Timer for accel, 0 is resting state
+uint16_t lastScroll = 0; // Previous confirmed wheel event
+uint16_t lastMidClick = 0; // Stops scrollwheel from being read if it was pressed
+uint8_t OptLowPin = OPT_ENC1;
+bool debug_encoder = false;
+
+__attribute__((weak)) void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v) {
+ mouse_report->h = h;
+ mouse_report->v = v;
+}
+
+__attribute__((weak)) void process_wheel(report_mouse_t* mouse_report) {
+ // TODO: Replace this with interrupt driven code, polling is S L O W
+ // Lovingly ripped from the Ploopy Source
+
+ // If the mouse wheel was just released, do not scroll.
+ if (timer_elapsed(lastMidClick) < SCROLL_BUTT_DEBOUNCE) {
+ return;
+ }
+
+ // Limit the number of scrolls per unit time.
+ if (timer_elapsed(lastScroll) < OPT_DEBOUNCE) {
+ return;
+ }
+
+ // Don't scroll if the middle button is depressed.
+ if (is_scroll_clicked) {
+#ifndef IGNORE_SCROLL_CLICK
+ return;
+#endif
+ }
+
+ lastScroll = timer_read();
+ uint16_t p1 = adc_read(OPT_ENC1_MUX);
+ uint16_t p2 = adc_read(OPT_ENC2_MUX);
+ if (debug_encoder) dprintf("OPT1: %d, OPT2: %d\n", p1, p2);
+
+ uint8_t dir = opt_encoder_handler(p1, p2);
+
+ if (dir == 0) return;
+ process_wheel_user(mouse_report, mouse_report->h, (int)(mouse_report->v + (dir * OPT_SCALE)));
+}
+
+__attribute__((weak)) void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) {
+ mouse_report->x = x;
+ mouse_report->y = y;
+}
+
+__attribute__((weak)) void process_mouse(report_mouse_t* mouse_report) {
+ report_pmw_t data = pmw_read_burst();
+ if (data.isOnSurface && data.isMotion) {
+ // Reset timer if stopped moving
+ if (!data.isMotion) {
+ if (MotionStart != 0) MotionStart = 0;
+ return;
+ }
+
+ // Set timer if new motion
+ if ((MotionStart == 0) && data.isMotion) {
+ if (debug_mouse) dprintf("Starting motion.\n");
+ MotionStart = timer_read();
+ }
+
+ if (debug_mouse) {
+ dprintf("Delt] d: %d t: %u\n", abs(data.dx) + abs(data.dy), MotionStart);
+ }
+ if (debug_mouse) {
+ dprintf("Pre ] X: %d, Y: %d\n", data.dx, data.dy);
+ }
+#if defined(PROFILE_LINEAR)
+ float scale = float(timer_elaspsed(MotionStart)) / 1000.0;
+ data.dx *= scale;
+ data.dy *= scale;
+#elif defined(PROFILE_INVERSE)
+ // TODO
+#else
+ // no post processing
+#endif
+ // apply multiplier
+ // data.dx *= mouse_multiplier;
+ // data.dy *= mouse_multiplier;
+
+ // Wrap to HID size
+ data.dx = constrain(data.dx, -127, 127);
+ data.dy = constrain(data.dy, -127, 127);
+ if (debug_mouse) dprintf("Cons] X: %d, Y: %d\n", data.dx, data.dy);
+ // dprintf("Elapsed:%u, X: %f Y: %\n", i, pgm_read_byte(firmware_data+i));
+
+ process_mouse_user(mouse_report, data.dx, data.dy);
+ }
+}
+
+bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
+ if (debug_mouse) {
+ dprintf("KL: kc: %u, col: %u, row: %u, pressed: %u\n", keycode, record->event.key.col, record->event.key.row, record->event.pressed);
+ }
+
+ // Update Timer to prevent accidental scrolls
+ if ((record->event.key.col == 2) && (record->event.key.row == 0)) {
+ lastMidClick = timer_read();
+ is_scroll_clicked = record->event.pressed;
+ }
+
+/* If Mousekeys is disabled, then use handle the mouse button
+ * keycodes. This makes things simpler, and allows usage of
+ * the keycodes in a consistent manner. But only do this if
+ * Mousekeys is not enable, so it's not handled twice.
+ */
+#ifndef MOUSEKEY_ENABLE
+ if (IS_MOUSEKEY_BUTTON(keycode)) {
+ report_mouse_t currentReport = pointing_device_get_report();
+ if (record->event.pressed) {
+ if (keycode == KC_MS_BTN1)
+ currentReport.buttons |= MOUSE_BTN1;
+ else if (keycode == KC_MS_BTN2)
+ currentReport.buttons |= MOUSE_BTN2;
+ else if (keycode == KC_MS_BTN3)
+ currentReport.buttons |= MOUSE_BTN3;
+ else if (keycode == KC_MS_BTN4)
+ currentReport.buttons |= MOUSE_BTN4;
+ else if (keycode == KC_MS_BTN5)
+ currentReport.buttons |= MOUSE_BTN5;
+ } else {
+ if (keycode == KC_MS_BTN1)
+ currentReport.buttons &= ~MOUSE_BTN1;
+ else if (keycode == KC_MS_BTN2)
+ currentReport.buttons &= ~MOUSE_BTN2;
+ else if (keycode == KC_MS_BTN3)
+ currentReport.buttons &= ~MOUSE_BTN3;
+ else if (keycode == KC_MS_BTN4)
+ currentReport.buttons &= ~MOUSE_BTN4;
+ else if (keycode == KC_MS_BTN5)
+ currentReport.buttons &= ~MOUSE_BTN5;
+ }
+ pointing_device_set_report(currentReport);
+ }
+#endif
+
+ return process_record_user(keycode, record);
+}
+
+// Hardware Setup
+void keyboard_pre_init_kb(void) {
+ // debug_enable = true;
+ // debug_matrix = true;
+ // debug_mouse = true;
+ // debug_encoder = true;
+
+ setPinInput(OPT_ENC1);
+ setPinInput(OPT_ENC2);
+
+ // This is the debug LED.
+ setPinOutput(F7);
+ writePin(F7, debug_enable);
+
+ /* Ground all output pins connected to ground. This provides additional
+ * pathways to ground. If you're messing with this, know this: driving ANY
+ * of these pins high will cause a short. On the MCU. Ka-blooey.
+ */
+#ifdef UNUSED_PINS
+ const pin_t unused_pins[] = UNUSED_PINS;
+
+ for (uint8_t i = 0; i < (sizeof(unused_pins) / sizeof(pin_t)); i++) {
+ setPinOutput(unused_pins[i]);
+ writePinLow(unused_pins[i]);
+ }
+#endif
+ keyboard_pre_init_user();
+}
+
+void pointing_device_init(void) {
+ // initialize ball sensor
+ pmw_spi_init();
+ // initialize the scroll wheel's optical encoder
+ opt_encoder_init();
+}
+
+bool has_report_changed (report_mouse_t first, report_mouse_t second) {
+ return !(
+ (!first.buttons && first.buttons == second.buttons) &&
+ (!first.x && first.x == second.x) &&
+ (!first.y && first.y == second.y) &&
+ (!first.h && first.h == second.h) &&
+ (!first.v && first.v == second.v) );
+}
+
+void pointing_device_task(void) {
+ report_mouse_t mouse_report = pointing_device_get_report();
+ process_wheel(&mouse_report);
+ process_mouse(&mouse_report);
+
+ pointing_device_set_report(mouse_report);
+ if (has_report_changed(mouse_report, pointing_device_get_report())) {
+ pointing_device_send();
+ }
+}
diff --git a/keyboards/ploopyco/trackball/trackball.h b/keyboards/ploopyco/trackball/trackball.h
new file mode 100644
index 0000000000..959305a07e
--- /dev/null
+++ b/keyboards/ploopyco/trackball/trackball.h
@@ -0,0 +1,40 @@
+/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+ * Copyright 2019 Sunjun Kim
+ * Copyright 2020 Ploopy Corporation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "quantum.h"
+#include "spi_master.h"
+#include "pmw3600.h"
+#include "analog.h"
+#include "opt_encoder.h"
+#include "pointing_device.h"
+
+// Sensor defs
+#define OPT_ENC1 F0
+#define OPT_ENC2 F4
+#define OPT_ENC1_MUX 0
+#define OPT_ENC2_MUX 4
+
+void process_mouse(report_mouse_t* mouse_report);
+void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y);
+void process_wheel(report_mouse_t* mouse_report);
+void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v);
+
+#define LAYOUT(BL, BM, BR, BF, BB) \
+ { {BL, BM, BR, BF, BB}, }