diff options
| author | Dasky <32983009+daskygit@users.noreply.github.com> | 2021-12-27 01:05:51 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-12-27 12:05:51 +1100 |
| commit | 7f7364c55912879baaff8fafca550d02f17b4d44 (patch) | |
| tree | 8afd414f6b202a126632a8c047dcf200312c78ff | |
| parent | 76a673233c8cb3d97130a6dece364c24b29f5fd7 (diff) | |
[Core] Split support for pointing devices. (#15304)
* Draft implementation
* formatting
* fix combined buttons
* remove pimoroni throttle
* sync pointing on a throttle loop with checksum
* no longer used
* doh
Co-authored-by: Drashna Jaelre <drashna@live.com>
* switch pimoroni to a cpi equivalent
* add cpi support
* allow user modification of seperate mouse reports
* a little tidy up
* add *_RIGHT defines.
* docs
* doxygen comments
* basic changelog
* clean up pimoroni
* small doc fixes
* Update docs/feature_pointing_device.md
Co-authored-by: Drashna Jaelre <drashna@live.com>
* performance tweak if side has usb
* Don't run init funtions on wrong side
* renamed some variables for consistency
* fix pimoroni typos
* Clamp instead of OR
* Promote combined values to uint16_t
* Update pointing_device.c
Co-authored-by: Drashna Jaelre <drashna@live.com>
Co-authored-by: Nick Brassel <nick@tzarc.org>
| -rw-r--r-- | docs/ChangeLog/20220226/PR15304.md | 13 | ||||
| -rw-r--r-- | docs/feature_pointing_device.md | 116 | ||||
| -rw-r--r-- | docs/feature_split_keyboard.md | 8 | ||||
| -rw-r--r-- | drivers/sensors/pimoroni_trackball.c | 22 | ||||
| -rw-r--r-- | drivers/sensors/pimoroni_trackball.h | 9 | ||||
| -rw-r--r-- | quantum/pointing_device.c | 389 | ||||
| -rw-r--r-- | quantum/pointing_device.h | 13 | ||||
| -rw-r--r-- | quantum/pointing_device_drivers.c | 24 | ||||
| -rw-r--r-- | quantum/split_common/transaction_id_define.h | 6 | ||||
| -rw-r--r-- | quantum/split_common/transactions.c | 79 | ||||
| -rw-r--r-- | quantum/split_common/transport.h | 13 |
11 files changed, 626 insertions, 66 deletions
diff --git a/docs/ChangeLog/20220226/PR15304.md b/docs/ChangeLog/20220226/PR15304.md new file mode 100644 index 0000000000..3cdb40db10 --- /dev/null +++ b/docs/ChangeLog/20220226/PR15304.md | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | ### Split Common core now supports Pointing Devices ([#15304](https://github.com/qmk/qmk_firmware/pull/15304)) | ||
| 2 | |||
| 3 | Pointing devices can now be shared across a split keyboard with support for a single pointing device or a pointing device on each side. | ||
| 4 | |||
| 5 | This feature can be enabled with `#define SPLIT_POINTING_ENABLE` and one of the following options: | ||
| 6 | |||
| 7 | | Setting | Description | | ||
| 8 | |---------------------------|------------------------------------| | ||
| 9 | |`POINTING_DEVICE_LEFT` | Pointing device on the left side | | ||
| 10 | |`POINTING_DEVICE_RIGHT` | Pointing device on the right side | | ||
| 11 | |`POINTING_DEVICE_COMBINED` | Pointing device on both sides | | ||
| 12 | |||
| 13 | See the [Pointing Device](../feature_pointing_device.md) documentation for further configuration options. | ||
diff --git a/docs/feature_pointing_device.md b/docs/feature_pointing_device.md index 5aef9bea27..f8de92f3b4 100644 --- a/docs/feature_pointing_device.md +++ b/docs/feature_pointing_device.md | |||
| @@ -127,11 +127,10 @@ The Pimoroni Trackball module is a I2C based breakout board with an RGB enable t | |||
| 127 | | Setting | Description | Default | | 127 | | Setting | Description | Default | |
| 128 | |-------------------------------------|------------------------------------------------------------------------------------|---------| | 128 | |-------------------------------------|------------------------------------------------------------------------------------|---------| |
| 129 | |`PIMORONI_TRACKBALL_ADDRESS` | (Required) Sets the I2C Address for the Pimoroni Trackball. | `0x0A` | | 129 | |`PIMORONI_TRACKBALL_ADDRESS` | (Required) Sets the I2C Address for the Pimoroni Trackball. | `0x0A` | |
| 130 | |`PIMORONI_TRACKBALL_TIMEOUT` | (Optional) The timeout for i2c communication with the trackpad in milliseconds. | `100` | | 130 | |`PIMORONI_TRACKBALL_TIMEOUT` | (Optional) The timeout for i2c communication with the trackball in milliseconds. | `100` | |
| 131 | |`PIMORONI_TRACKBALL_INTERVAL_MS` | (Optional) The update/read interval for the sensor in milliseconds. | `8` | | ||
| 132 | |`PIMORONI_TRACKBALL_SCALE` | (Optional) The multiplier used to generate reports from the sensor. | `5` | | 131 | |`PIMORONI_TRACKBALL_SCALE` | (Optional) The multiplier used to generate reports from the sensor. | `5` | |
| 133 | |`PIMORONI_TRACKBALL_DEBOUNCE_CYCLES` | (Optional) The number of scan cycles used for debouncing on the ball press. | `20` | | 132 | |`PIMORONI_TRACKBALL_DEBOUNCE_CYCLES` | (Optional) The number of scan cycles used for debouncing on the ball press. | `20` | |
| 134 | |`PIMORONI_TRACKBALL_ERROR_COUNT` | (Optional) Specifies the number of read/write errors until the sensor is disabled. | `10` | | 133 | |`PIMORONI_TRACKBALL_ERROR_COUNT` | (Optional) Specifies the number of read/write errors until the sensor is disabled. | `10` | |
| 135 | 134 | ||
| 136 | ### PMW 3360 Sensor | 135 | ### PMW 3360 Sensor |
| 137 | 136 | ||
| @@ -171,14 +170,35 @@ void pointing_device_driver_set_cpi(uint16_t cpi) {} | |||
| 171 | 170 | ||
| 172 | ## Common Configuration | 171 | ## Common Configuration |
| 173 | 172 | ||
| 174 | | Setting | Description | Default | | 173 | | Setting | Description | Default | |
| 175 | |-------------------------------|-----------------------------------------------------------------------|---------------| | 174 | |----------------------------------|-----------------------------------------------------------------------|-------------------| |
| 176 | |`POINTING_DEVICE_ROTATION_90` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ | | 175 | |`POINTING_DEVICE_ROTATION_90` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ | |
| 177 | |`POINTING_DEVICE_ROTATION_180` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ | | 176 | |`POINTING_DEVICE_ROTATION_180` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ | |
| 178 | |`POINTING_DEVICE_ROTATION_270` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ | | 177 | |`POINTING_DEVICE_ROTATION_270` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ | |
| 179 | |`POINTING_DEVICE_INVERT_X` | (Optional) Inverts the X axis report. | _not defined_ | | 178 | |`POINTING_DEVICE_INVERT_X` | (Optional) Inverts the X axis report. | _not defined_ | |
| 180 | |`POINTING_DEVICE_INVERT_Y` | (Optional) Inverts the Y axis report. | _not defined_ | | 179 | |`POINTING_DEVICE_INVERT_Y` | (Optional) Inverts the Y axis report. | _not defined_ | |
| 181 | |`POINTING_DEVICE_MOTION_PIN` | (Optional) If supported, will only read from sensor if pin is active. | _not defined_ | | 180 | |`POINTING_DEVICE_MOTION_PIN` | (Optional) If supported, will only read from sensor if pin is active. | _not defined_ | |
| 181 | |`POINTING_DEVICE_TASK_THROTTLE_MS` | (Optional) Limits the frequency that the sensor is polled for motion. | _not defined_ | | ||
| 182 | |||
| 183 | !> When using `SPLIT_POINTING_ENABLE` the `POINTING_DEVICE_MOTION_PIN` functionality is not supported and would recommend `POINTING_DEVICE_TASK_THROTTLE_MS` be set to `1`. Increasing this value will increase transport performance at the cost of possible mouse responsiveness. | ||
| 184 | |||
| 185 | |||
| 186 | ## Split Keyboard Configuration | ||
| 187 | |||
| 188 | The following configuration options are only available when using `SPLIT_POINTING_ENABLE` see [data sync options](feature_split_keyboard.md?id=data-sync-options). The rotation and invert `*_RIGHT` options are only used with `POINTING_DEVICE_COMBINED`. If using `POINTING_DEVICE_LEFT` or `POINTING_DEVICE_RIGHT` use the common configuration above to configure your pointing device. | ||
| 189 | |||
| 190 | | Setting | Description | Default | | ||
| 191 | |----------------------------------------|-----------------------------------------------------------------------|---------------| | ||
| 192 | |`POINTING_DEVICE_LEFT` | Pointing device on the left side (Required - pick one only) | _not defined_ | | ||
| 193 | |`POINTING_DEVICE_RIGHT` | Pointing device on the right side (Required - pick one only) | _not defined_ | | ||
| 194 | |`POINTING_DEVICE_COMBINED` | Pointing device on both sides (Required - pick one only) | _not defined_ | | ||
| 195 | |`POINTING_DEVICE_ROTATION_90_RIGHT` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ | | ||
| 196 | |`POINTING_DEVICE_ROTATION_180_RIGHT` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ | | ||
| 197 | |`POINTING_DEVICE_ROTATION_270_RIGHT` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ | | ||
| 198 | |`POINTING_DEVICE_INVERT_X_RIGHT` | (Optional) Inverts the X axis report. | _not defined_ | | ||
| 199 | |`POINTING_DEVICE_INVERT_Y_RIGHT` | (Optional) Inverts the Y axis report. | _not defined_ | | ||
| 200 | |||
| 201 | !> If there is a `_RIGHT` configuration option or callback, the [common configuration](feature_pointing_device.md?id=common-configuration) option will work for the left. For correct left/right detection you should setup a [handedness option](feature_split_keyboard?id=setting-handedness), `EE_HANDS` is usually a good option for an existing board that doesn't do handedness by hardware. | ||
| 182 | 202 | ||
| 183 | 203 | ||
| 184 | ## Callbacks and Functions | 204 | ## Callbacks and Functions |
| @@ -196,6 +216,21 @@ void pointing_device_driver_set_cpi(uint16_t cpi) {} | |||
| 196 | | `pointing_device_set_report(mouse_report)` | Sets the mouse report to the assigned `mouse_report_t` data structured passed to the function. | | 216 | | `pointing_device_set_report(mouse_report)` | Sets the mouse report to the assigned `mouse_report_t` data structured passed to the function. | |
| 197 | | `pointing_device_send(void)` | Sends the current mouse report to the host system. Function can be replaced. | | 217 | | `pointing_device_send(void)` | Sends the current mouse report to the host system. Function can be replaced. | |
| 198 | | `has_mouse_report_changed(old, new)` | Compares the old and new `mouse_report_t` data and returns true only if it has changed. | | 218 | | `has_mouse_report_changed(old, new)` | Compares the old and new `mouse_report_t` data and returns true only if it has changed. | |
| 219 | | `pointing_device_adjust_by_defines(mouse_report)` | Applies rotations and invert configurations to a raw mouse report. | | ||
| 220 | |||
| 221 | |||
| 222 | ## Split Keyboard Callbacks and Functions | ||
| 223 | |||
| 224 | The combined functions below are only available when using `SPLIT_POINTING_ENABLE` and `POINTING_DEVICE_COMBINED`. The 2 callbacks `pointing_device_task_combined_*` replace the single sided equivalents above. See the [combined pointing devices example](feature_pointing_device.md?id=combined-pointing-devices) | ||
| 225 | |||
| 226 | | Function | Description | | ||
| 227 | |-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------| | ||
| 228 | | `pointing_device_set_shared_report(mouse_report)` | Sets the shared mouse report to the assigned `mouse_report_t` data structured passed to the function. | | ||
| 229 | | `pointing_device_set_cpi_on_side(bool, uint16_t)` | Sets the CPI/DPI of one side, if supported. Passing `true` will set the left and `false` the right` | | ||
| 230 | | `pointing_device_combine_reports(left_report, right_report)` | Returns a combined mouse_report of left_report and right_report (as a `mouse_report_t` data structure) | | ||
| 231 | | `pointing_device_task_combined_kb(left_report, right_report)` | Callback, so keyboard code can intercept and modify the data. Returns a combined mouse report. | | ||
| 232 | | `pointing_device_task_combined_user(left_report, right_report)` | Callback, so user code can intercept and modify. Returns a combined mouse report using `pointing_device_combine_reports` | | ||
| 233 | | `pointing_device_adjust_by_defines_right(mouse_report)` | Applies right side rotations and invert configurations to a raw mouse report. | | ||
| 199 | 234 | ||
| 200 | 235 | ||
| 201 | # Manipulating Mouse Reports | 236 | # Manipulating Mouse Reports |
| @@ -242,3 +277,62 @@ case MS_SPECIAL: | |||
| 242 | ``` | 277 | ``` |
| 243 | 278 | ||
| 244 | Recall that the mouse report is set to zero (except the buttons) whenever it is sent, so the scrolling would only occur once in each case. | 279 | Recall that the mouse report is set to zero (except the buttons) whenever it is sent, so the scrolling would only occur once in each case. |
| 280 | |||
| 281 | ## Split Examples | ||
| 282 | |||
| 283 | The following examples make use the `SPLIT_POINTING_ENABLE` functionality and show how to manipulate the mouse report for a scrolling mode. | ||
| 284 | |||
| 285 | ### Single Pointing Device | ||
| 286 | |||
| 287 | The following example will work with either `POINTING_DEVICE_LEFT` or `POINTING_DEVICE_RIGHT` and enables scrolling mode while on a particular layer. | ||
| 288 | |||
| 289 | ```c | ||
| 290 | |||
| 291 | static bool scrolling_mode = false; | ||
| 292 | |||
| 293 | layer_state_t layer_state_set_user(layer_state_t state) { | ||
| 294 | switch (get_highest_layer(state)) { | ||
| 295 | case _RAISE: // If we're on the _RAISE layer enable scrolling mode | ||
| 296 | scrolling_mode = true; | ||
| 297 | pointing_device_set_cpi(2000); | ||
| 298 | break; | ||
| 299 | default: | ||
| 300 | if (scrolling_mode) { // check if we were scrolling before and set disable if so | ||
| 301 | scrolling_mode = false; | ||
| 302 | pointing_device_set_cpi(8000); | ||
| 303 | } | ||
| 304 | break; | ||
| 305 | } | ||
| 306 | return state; | ||
| 307 | } | ||
| 308 | |||
| 309 | report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) { | ||
| 310 | if (scrolling_mode) { | ||
| 311 | mouse_report.h = mouse_report.x; | ||
| 312 | mouse_report.v = mouse_report.y; | ||
| 313 | mouse_report.x = 0; | ||
| 314 | mouse_report.y = 0; | ||
| 315 | } | ||
| 316 | return mouse_report; | ||
| 317 | } | ||
| 318 | |||
| 319 | ``` | ||
| 320 | |||
| 321 | ### Combined Pointing Devices | ||
| 322 | |||
| 323 | The following example requires `POINTING_DEVICE_COMBINED` and sets the left side pointing device to scroll only. | ||
| 324 | |||
| 325 | ```c | ||
| 326 | void keyboard_post_init_user(void) { | ||
| 327 | pointing_device_set_cpi_on_side(true, 1000); //Set cpi on left side to a low value for slower scrolling. | ||
| 328 | pointing_device_set_cpi_on_side(false, 8000); //Set cpi on right side to a reasonable value for mousing. | ||
| 329 | } | ||
| 330 | |||
| 331 | report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report) { | ||
| 332 | left_report.h = left_report.x; | ||
| 333 | left_report.v = left_report.y; | ||
| 334 | left_report.x = 0; | ||
| 335 | left_report.y = 0; | ||
| 336 | return pointing_device_combine_reports(left_report, right_report); | ||
| 337 | } | ||
| 338 | ``` | ||
diff --git a/docs/feature_split_keyboard.md b/docs/feature_split_keyboard.md index c8ba18beeb..b51593308e 100644 --- a/docs/feature_split_keyboard.md +++ b/docs/feature_split_keyboard.md | |||
| @@ -266,6 +266,14 @@ This enables transmitting the current OLED on/off status to the slave side of th | |||
| 266 | 266 | ||
| 267 | This enables transmitting the current ST7565 on/off status to the slave side of the split keyboard. The purpose of this feature is to support state (on/off state only) syncing. | 267 | This enables transmitting the current ST7565 on/off status to the slave side of the split keyboard. The purpose of this feature is to support state (on/off state only) syncing. |
| 268 | 268 | ||
| 269 | ```c | ||
| 270 | #define SPLIT_POINTING_ENABLE | ||
| 271 | ``` | ||
| 272 | |||
| 273 | This enables transmitting the pointing device status to the master side of the split keyboard. The purpose of this feature is to enable use pointing devices on the slave side. | ||
| 274 | |||
| 275 | !> There is additional required configuration for `SPLIT_POINTING_ENABLE` outlined in the [pointing device documentation](feature_pointing_device.md?id=split-keyboard-configuration). | ||
| 276 | |||
| 269 | ### Custom data sync between sides :id=custom-data-sync | 277 | ### Custom data sync between sides :id=custom-data-sync |
| 270 | 278 | ||
| 271 | QMK's split transport allows for arbitrary data transactions at both the keyboard and user levels. This is modelled on a remote procedure call, with the master invoking a function on the slave side, with the ability to send data from master to slave, process it slave side, and send data back from slave to master. | 279 | QMK's split transport allows for arbitrary data transactions at both the keyboard and user levels. This is modelled on a remote procedure call, with the master invoking a function on the slave side, with the ability to send data from master to slave, process it slave side, and send data back from slave to master. |
diff --git a/drivers/sensors/pimoroni_trackball.c b/drivers/sensors/pimoroni_trackball.c index 7d390056ea..2867e763bc 100644 --- a/drivers/sensors/pimoroni_trackball.c +++ b/drivers/sensors/pimoroni_trackball.c | |||
| @@ -33,8 +33,24 @@ | |||
| 33 | 33 | ||
| 34 | static uint16_t precision = 128; | 34 | static uint16_t precision = 128; |
| 35 | 35 | ||
| 36 | float pimoroni_trackball_get_precision(void) { return ((float)precision / 128); } | 36 | uint16_t pimoroni_trackball_get_cpi(void) { return (precision * 125); } |
| 37 | void pimoroni_trackball_set_precision(float floatprecision) { precision = (floatprecision * 128); } | 37 | /** |
| 38 | * @brief Sets the scaling value for pimoroni trackball | ||
| 39 | * | ||
| 40 | * Sets a scaling value for pimoroni trackball to allow runtime adjustment. This isn't used by the sensor and is an | ||
| 41 | * approximation so the functions are consistent across drivers. | ||
| 42 | * | ||
| 43 | * NOTE: This rounds down to the nearest number divisable by 125 that's a positive integer, values below 125 are clamped to 125. | ||
| 44 | * | ||
| 45 | * @param cpi uint16_t | ||
| 46 | */ | ||
| 47 | void pimoroni_trackball_set_cpi(uint16_t cpi) { | ||
| 48 | if (cpi < 249) { | ||
| 49 | precision = 1; | ||
| 50 | } else { | ||
| 51 | precision = (cpi - (cpi % 125)) / 125; | ||
| 52 | } | ||
| 53 | } | ||
| 38 | 54 | ||
| 39 | void pimoroni_trackball_set_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { | 55 | void pimoroni_trackball_set_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { |
| 40 | uint8_t data[4] = {r, g, b, w}; | 56 | uint8_t data[4] = {r, g, b, w}; |
| @@ -60,7 +76,7 @@ i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data) { | |||
| 60 | return status; | 76 | return status; |
| 61 | } | 77 | } |
| 62 | 78 | ||
| 63 | __attribute__((weak)) void pimironi_trackball_device_init(void) { | 79 | __attribute__((weak)) void pimoroni_trackball_device_init(void) { |
| 64 | i2c_init(); | 80 | i2c_init(); |
| 65 | pimoroni_trackball_set_rgbw(0x00, 0x00, 0x00, 0x00); | 81 | pimoroni_trackball_set_rgbw(0x00, 0x00, 0x00, 0x00); |
| 66 | } | 82 | } |
diff --git a/drivers/sensors/pimoroni_trackball.h b/drivers/sensors/pimoroni_trackball.h index 59ee8724ba..e20ee748a7 100644 --- a/drivers/sensors/pimoroni_trackball.h +++ b/drivers/sensors/pimoroni_trackball.h | |||
| @@ -23,9 +23,6 @@ | |||
| 23 | #ifndef PIMORONI_TRACKBALL_ADDRESS | 23 | #ifndef PIMORONI_TRACKBALL_ADDRESS |
| 24 | # define PIMORONI_TRACKBALL_ADDRESS 0x0A | 24 | # define PIMORONI_TRACKBALL_ADDRESS 0x0A |
| 25 | #endif | 25 | #endif |
| 26 | #ifndef PIMORONI_TRACKBALL_INTERVAL_MS | ||
| 27 | # define PIMORONI_TRACKBALL_INTERVAL_MS 8 | ||
| 28 | #endif | ||
| 29 | #ifndef PIMORONI_TRACKBALL_SCALE | 26 | #ifndef PIMORONI_TRACKBALL_SCALE |
| 30 | # define PIMORONI_TRACKBALL_SCALE 5 | 27 | # define PIMORONI_TRACKBALL_SCALE 5 |
| 31 | #endif | 28 | #endif |
| @@ -52,10 +49,10 @@ typedef struct { | |||
| 52 | uint8_t click; | 49 | uint8_t click; |
| 53 | } pimoroni_data_t; | 50 | } pimoroni_data_t; |
| 54 | 51 | ||
| 55 | void pimironi_trackball_device_init(void); | 52 | void pimoroni_trackball_device_init(void); |
| 56 | void pimoroni_trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white); | 53 | void pimoroni_trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white); |
| 57 | int16_t pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale); | 54 | int16_t pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale); |
| 58 | void pimoroni_trackball_adapt_values(int8_t* mouse, int16_t* offset); | 55 | void pimoroni_trackball_adapt_values(int8_t* mouse, int16_t* offset); |
| 59 | float pimoroni_trackball_get_precision(void); | 56 | uint16_t pimoroni_trackball_get_cpi(void); |
| 60 | void pimoroni_trackball_set_precision(float precision); | 57 | void pimoroni_trackball_set_cpi(uint16_t cpi); |
| 61 | i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data); | 58 | i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data); |
diff --git a/quantum/pointing_device.c b/quantum/pointing_device.c index 2fefdb67b6..23d93fa15f 100644 --- a/quantum/pointing_device.c +++ b/quantum/pointing_device.c | |||
| @@ -18,24 +18,105 @@ | |||
| 18 | 18 | ||
| 19 | #include "pointing_device.h" | 19 | #include "pointing_device.h" |
| 20 | #include <string.h> | 20 | #include <string.h> |
| 21 | #include "timer.h" | ||
| 21 | #ifdef MOUSEKEY_ENABLE | 22 | #ifdef MOUSEKEY_ENABLE |
| 22 | # include "mousekey.h" | 23 | # include "mousekey.h" |
| 23 | #endif | 24 | #endif |
| 24 | #if (defined(POINTING_DEVICE_ROTATION_90) + defined(POINTING_DEVICE_ROTATION_180) + defined(POINTING_DEVICE_ROTATION_270)) > 1 | 25 | #if (defined(POINTING_DEVICE_ROTATION_90) + defined(POINTING_DEVICE_ROTATION_180) + defined(POINTING_DEVICE_ROTATION_270)) > 1 |
| 25 | # error More than one rotation selected. This is not supported. | 26 | # error More than one rotation selected. This is not supported. |
| 26 | #endif | 27 | #endif |
| 28 | #if defined(SPLIT_POINTING_ENABLE) | ||
| 29 | # include "transactions.h" | ||
| 30 | # include "keyboard.h" | ||
| 27 | 31 | ||
| 28 | static report_mouse_t mouseReport = {}; | 32 | report_mouse_t shared_mouse_report = {}; |
| 33 | uint16_t shared_cpi = 0; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * @brief Sets the shared mouse report used be pointing device task | ||
| 37 | * | ||
| 38 | * NOTE : Only available when using SPLIT_POINTING_ENABLE | ||
| 39 | * | ||
| 40 | * @param[in] new_mouse_report report_mouse_t | ||
| 41 | */ | ||
| 42 | void pointing_device_set_shared_report(report_mouse_t new_mouse_report) { shared_mouse_report = new_mouse_report; } | ||
| 43 | |||
| 44 | /** | ||
| 45 | * @brief Gets current pointing device CPI if supported | ||
| 46 | * | ||
| 47 | * Gets current cpi of the shared report and returns it as uint16_t | ||
| 48 | * | ||
| 49 | * NOTE : Only available when using SPLIT_POINTING_ENABLE | ||
| 50 | * | ||
| 51 | * @return cpi value as uint16_t | ||
| 52 | */ | ||
| 53 | uint16_t pointing_device_get_shared_cpi(void) { return shared_cpi; } | ||
| 54 | |||
| 55 | # if defined(POINTING_DEVICE_LEFT) | ||
| 56 | # define POINTING_DEVICE_THIS_SIDE is_keyboard_left() | ||
| 57 | # elif defined(POINTING_DEVICE_RIGHT) | ||
| 58 | # define POINTING_DEVICE_THIS_SIDE !is_keyboard_left() | ||
| 59 | # elif defined(POINTING_DEVICE_COMBINED) | ||
| 60 | # define POINTING_DEVICE_THIS_SIDE true | ||
| 61 | # endif | ||
| 62 | |||
| 63 | #endif // defined(SPLIT_POINTING_ENABLE) | ||
| 64 | |||
| 65 | static report_mouse_t local_mouse_report = {}; | ||
| 29 | 66 | ||
| 30 | extern const pointing_device_driver_t pointing_device_driver; | 67 | extern const pointing_device_driver_t pointing_device_driver; |
| 31 | 68 | ||
| 69 | /** | ||
| 70 | * @brief Compares 2 mouse reports for difference and returns result | ||
| 71 | * | ||
| 72 | * @param[in] new report_mouse_t | ||
| 73 | * @param[in] old report_mouse_t | ||
| 74 | * @return bool result | ||
| 75 | */ | ||
| 32 | __attribute__((weak)) bool has_mouse_report_changed(report_mouse_t new, report_mouse_t old) { return memcmp(&new, &old, sizeof(new)); } | 76 | __attribute__((weak)) bool has_mouse_report_changed(report_mouse_t new, report_mouse_t old) { return memcmp(&new, &old, sizeof(new)); } |
| 33 | 77 | ||
| 34 | __attribute__((weak)) void pointing_device_init_kb(void) {} | 78 | /** |
| 35 | __attribute__((weak)) void pointing_device_init_user(void) {} | 79 | * @brief Keyboard level code pointing device initialisation |
| 80 | * | ||
| 81 | */ | ||
| 82 | __attribute__((weak)) void pointing_device_init_kb(void) {} | ||
| 83 | |||
| 84 | /** | ||
| 85 | * @brief User level code pointing device initialisation | ||
| 86 | * | ||
| 87 | */ | ||
| 88 | __attribute__((weak)) void pointing_device_init_user(void) {} | ||
| 89 | |||
| 90 | /** | ||
| 91 | * @brief Weak function allowing for keyboard level mouse report modification | ||
| 92 | * | ||
| 93 | * Takes report_mouse_t struct allowing modification at keyboard level then returns report_mouse_t. | ||
| 94 | * | ||
| 95 | * @param[in] mouse_report report_mouse_t | ||
| 96 | * @return report_mouse_t | ||
| 97 | */ | ||
| 36 | __attribute__((weak)) report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { return pointing_device_task_user(mouse_report); } | 98 | __attribute__((weak)) report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { return pointing_device_task_user(mouse_report); } |
| 99 | |||
| 100 | /** | ||
| 101 | * @brief Weak function allowing for user level mouse report modification | ||
| 102 | * | ||
| 103 | * Takes report_mouse_t struct allowing modification at user level then returns report_mouse_t. | ||
| 104 | * | ||
| 105 | * @param[in] mouse_report report_mouse_t | ||
| 106 | * @return report_mouse_t | ||
| 107 | */ | ||
| 37 | __attribute__((weak)) report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) { return mouse_report; } | 108 | __attribute__((weak)) report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) { return mouse_report; } |
| 38 | 109 | ||
| 110 | /** | ||
| 111 | * @brief Handles pointing device buttons | ||
| 112 | * | ||
| 113 | * Returns modified button bitmask using bool pressed and selected pointing_device_buttons_t button in uint8_t buttons bitmask. | ||
| 114 | * | ||
| 115 | * @param buttons[in] uint8_t bitmask | ||
| 116 | * @param pressed[in] bool | ||
| 117 | * @param button[in] pointing_device_buttons_t value | ||
| 118 | * @return Modified uint8_t bitmask buttons | ||
| 119 | */ | ||
| 39 | __attribute__((weak)) uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button) { | 120 | __attribute__((weak)) uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button) { |
| 40 | if (pressed) { | 121 | if (pressed) { |
| 41 | buttons |= 1 << (button); | 122 | buttons |= 1 << (button); |
| @@ -45,7 +126,17 @@ __attribute__((weak)) uint8_t pointing_device_handle_buttons(uint8_t buttons, bo | |||
| 45 | return buttons; | 126 | return buttons; |
| 46 | } | 127 | } |
| 47 | 128 | ||
| 129 | /** | ||
| 130 | * @brief Initialises pointing device | ||
| 131 | * | ||
| 132 | * Initialises pointing device, perform driver init and optional keyboard/user level code. | ||
| 133 | */ | ||
| 48 | __attribute__((weak)) void pointing_device_init(void) { | 134 | __attribute__((weak)) void pointing_device_init(void) { |
| 135 | #if defined(SPLIT_POINTING_ENABLE) | ||
| 136 | if (!(POINTING_DEVICE_THIS_SIDE)) { | ||
| 137 | return; | ||
| 138 | } | ||
| 139 | #endif | ||
| 49 | pointing_device_driver.init(); | 140 | pointing_device_driver.init(); |
| 50 | #ifdef POINTING_DEVICE_MOTION_PIN | 141 | #ifdef POINTING_DEVICE_MOTION_PIN |
| 51 | setPinInputHigh(POINTING_DEVICE_MOTION_PIN); | 142 | setPinInputHigh(POINTING_DEVICE_MOTION_PIN); |
| @@ -54,67 +145,299 @@ __attribute__((weak)) void pointing_device_init(void) { | |||
| 54 | pointing_device_init_user(); | 145 | pointing_device_init_user(); |
| 55 | } | 146 | } |
| 56 | 147 | ||
| 148 | /** | ||
| 149 | * @brief Sends processed mouse report to host | ||
| 150 | * | ||
| 151 | * This sends the mouse report generated by pointing_device_task if changed since the last report. Once send zeros mouse report except buttons. | ||
| 152 | * | ||
| 153 | */ | ||
| 57 | __attribute__((weak)) void pointing_device_send(void) { | 154 | __attribute__((weak)) void pointing_device_send(void) { |
| 58 | static report_mouse_t old_report = {}; | 155 | static report_mouse_t old_report = {}; |
| 59 | 156 | ||
| 60 | // If you need to do other things, like debugging, this is the place to do it. | 157 | // If you need to do other things, like debugging, this is the place to do it. |
| 61 | if (has_mouse_report_changed(mouseReport, old_report)) { | 158 | if (has_mouse_report_changed(local_mouse_report, old_report)) { |
| 62 | host_mouse_send(&mouseReport); | 159 | host_mouse_send(&local_mouse_report); |
| 63 | } | 160 | } |
| 64 | // send it and 0 it out except for buttons, so those stay until they are explicity over-ridden using update_pointing_device | 161 | // send it and 0 it out except for buttons, so those stay until they are explicity over-ridden using update_pointing_device |
| 65 | mouseReport.x = 0; | 162 | local_mouse_report.x = 0; |
| 66 | mouseReport.y = 0; | 163 | local_mouse_report.y = 0; |
| 67 | mouseReport.v = 0; | 164 | local_mouse_report.v = 0; |
| 68 | mouseReport.h = 0; | 165 | local_mouse_report.h = 0; |
| 69 | 166 | ||
| 70 | memcpy(&old_report, &mouseReport, sizeof(mouseReport)); | 167 | memcpy(&old_report, &local_mouse_report, sizeof(local_mouse_report)); |
| 71 | } | 168 | } |
| 72 | 169 | ||
| 73 | __attribute__((weak)) void pointing_device_task(void) { | 170 | /** |
| 74 | // Gather report info | 171 | * @brief Adjust mouse report by any optional common pointing configuration defines |
| 75 | #ifdef POINTING_DEVICE_MOTION_PIN | 172 | * |
| 76 | if (!readPin(POINTING_DEVICE_MOTION_PIN)) | 173 | * This applies rotation or inversion to the mouse report as selected by the pointing device common configuration defines. |
| 77 | #endif | 174 | * |
| 78 | mouseReport = pointing_device_driver.get_report(mouseReport); | 175 | * @param mouse_report[in] takes a report_mouse_t to be adjusted |
| 79 | 176 | * @return report_mouse_t with adjusted values | |
| 80 | // Support rotation of the sensor data | 177 | */ |
| 178 | report_mouse_t pointing_device_adjust_by_defines(report_mouse_t mouse_report) { | ||
| 179 | // Support rotation of the sensor data | ||
| 81 | #if defined(POINTING_DEVICE_ROTATION_90) || defined(POINTING_DEVICE_ROTATION_180) || defined(POINTING_DEVICE_ROTATION_270) | 180 | #if defined(POINTING_DEVICE_ROTATION_90) || defined(POINTING_DEVICE_ROTATION_180) || defined(POINTING_DEVICE_ROTATION_270) |
| 82 | int8_t x = mouseReport.x, y = mouseReport.y; | 181 | int8_t x = mouse_report.x, y = mouse_report.y; |
| 83 | # if defined(POINTING_DEVICE_ROTATION_90) | 182 | # if defined(POINTING_DEVICE_ROTATION_90) |
| 84 | mouseReport.x = y; | 183 | mouse_report.x = y; |
| 85 | mouseReport.y = -x; | 184 | mouse_report.y = -x; |
| 86 | # elif defined(POINTING_DEVICE_ROTATION_180) | 185 | # elif defined(POINTING_DEVICE_ROTATION_180) |
| 87 | mouseReport.x = -x; | 186 | mouse_report.x = -x; |
| 88 | mouseReport.y = -y; | 187 | mouse_report.y = -y; |
| 89 | # elif defined(POINTING_DEVICE_ROTATION_270) | 188 | # elif defined(POINTING_DEVICE_ROTATION_270) |
| 90 | mouseReport.x = -y; | 189 | mouse_report.x = -y; |
| 91 | mouseReport.y = x; | 190 | mouse_report.y = x; |
| 92 | # else | 191 | # else |
| 93 | # error "How the heck did you get here?!" | 192 | # error "How the heck did you get here?!" |
| 94 | # endif | 193 | # endif |
| 95 | #endif | 194 | #endif |
| 96 | // Support Inverting the X and Y Axises | 195 | // Support Inverting the X and Y Axises |
| 97 | #if defined(POINTING_DEVICE_INVERT_X) | 196 | #if defined(POINTING_DEVICE_INVERT_X) |
| 98 | mouseReport.x = -mouseReport.x; | 197 | mouse_report.x = -mouse_report.x; |
| 99 | #endif | 198 | #endif |
| 100 | #if defined(POINTING_DEVICE_INVERT_Y) | 199 | #if defined(POINTING_DEVICE_INVERT_Y) |
| 101 | mouseReport.y = -mouseReport.y; | 200 | mouse_report.y = -mouse_report.y; |
| 201 | #endif | ||
| 202 | return mouse_report; | ||
| 203 | } | ||
| 204 | |||
| 205 | /** | ||
| 206 | * @brief Retrieves and processes pointing device data. | ||
| 207 | * | ||
| 208 | * This function is part of the keyboard loop and retrieves the mouse report from the pointing device driver. | ||
| 209 | * It applies any optional configuration e.g. rotation or axis inversion and then initiates a send. | ||
| 210 | * | ||
| 211 | */ | ||
| 212 | __attribute__((weak)) void pointing_device_task(void) { | ||
| 213 | #if defined(SPLIT_POINTING_ENABLE) | ||
| 214 | // Don't poll the target side pointing device. | ||
| 215 | if (!is_keyboard_master()) { | ||
| 216 | return; | ||
| 217 | }; | ||
| 218 | #endif | ||
| 219 | |||
| 220 | #if defined(POINTING_DEVICE_TASK_THROTTLE_MS) | ||
| 221 | static uint32_t last_exec = 0; | ||
| 222 | if (timer_elapsed32(last_exec) < POINTING_DEVICE_TASK_THROTTLE_MS) { | ||
| 223 | return; | ||
| 224 | } | ||
| 225 | last_exec = timer_read32(); | ||
| 226 | #else | ||
| 227 | # if defined(SPLIT_POINTING_ENABLE) | ||
| 228 | # pragma message("It's recommended you enable a throttle when sharing pointing devices.") | ||
| 229 | # endif | ||
| 230 | #endif | ||
| 231 | |||
| 232 | // Gather report info | ||
| 233 | #ifdef POINTING_DEVICE_MOTION_PIN | ||
| 234 | # if defined(SPLIT_POINTING_ENABLE) | ||
| 235 | # error POINTING_DEVICE_MOTION_PIN not supported when sharing the pointing device report between sides. | ||
| 236 | # endif | ||
| 237 | if (!readPin(POINTING_DEVICE_MOTION_PIN)) | ||
| 102 | #endif | 238 | #endif |
| 103 | 239 | ||
| 240 | #if defined(SPLIT_POINTING_ENABLE) | ||
| 241 | # if defined(POINTING_DEVICE_COMBINED) | ||
| 242 | static uint8_t old_buttons = 0; | ||
| 243 | local_mouse_report.buttons = old_buttons; | ||
| 244 | local_mouse_report = pointing_device_driver.get_report(local_mouse_report); | ||
| 245 | old_buttons = local_mouse_report.buttons; | ||
| 246 | # elif defined(POINTING_DEVICE_LEFT) || defined(POINTING_DEVICE_RIGHT) | ||
| 247 | local_mouse_report = POINTING_DEVICE_THIS_SIDE ? pointing_device_driver.get_report(local_mouse_report) : shared_mouse_report; | ||
| 248 | # else | ||
| 249 | # error "You need to define the side(s) the pointing device is on. POINTING_DEVICE_COMBINED / POINTING_DEVICE_LEFT / POINTING_DEVICE_RIGHT" | ||
| 250 | # endif | ||
| 251 | #else | ||
| 252 | local_mouse_report = pointing_device_driver.get_report(local_mouse_report); | ||
| 253 | #endif // defined(SPLIT_POINTING_ENABLE) | ||
| 254 | |||
| 104 | // allow kb to intercept and modify report | 255 | // allow kb to intercept and modify report |
| 105 | mouseReport = pointing_device_task_kb(mouseReport); | 256 | #if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED) |
| 257 | if (is_keyboard_left()) { | ||
| 258 | local_mouse_report = pointing_device_adjust_by_defines(local_mouse_report); | ||
| 259 | shared_mouse_report = pointing_device_adjust_by_defines_right(shared_mouse_report); | ||
| 260 | } else { | ||
| 261 | local_mouse_report = pointing_device_adjust_by_defines_right(local_mouse_report); | ||
| 262 | shared_mouse_report = pointing_device_adjust_by_defines(shared_mouse_report); | ||
| 263 | } | ||
| 264 | local_mouse_report = is_keyboard_left() ? pointing_device_task_combined_kb(local_mouse_report, shared_mouse_report) : pointing_device_task_combined_kb(shared_mouse_report, local_mouse_report); | ||
| 265 | #else | ||
| 266 | local_mouse_report = pointing_device_adjust_by_defines(local_mouse_report); | ||
| 267 | local_mouse_report = pointing_device_task_kb(local_mouse_report); | ||
| 268 | #endif | ||
| 106 | // combine with mouse report to ensure that the combined is sent correctly | 269 | // combine with mouse report to ensure that the combined is sent correctly |
| 107 | #ifdef MOUSEKEY_ENABLE | 270 | #ifdef MOUSEKEY_ENABLE |
| 108 | report_mouse_t mousekey_report = mousekey_get_report(); | 271 | report_mouse_t mousekey_report = mousekey_get_report(); |
| 109 | mouseReport.buttons = mouseReport.buttons | mousekey_report.buttons; | 272 | local_mouse_report.buttons = local_mouse_report.buttons | mousekey_report.buttons; |
| 110 | #endif | 273 | #endif |
| 111 | pointing_device_send(); | 274 | pointing_device_send(); |
| 112 | } | 275 | } |
| 113 | 276 | ||
| 114 | report_mouse_t pointing_device_get_report(void) { return mouseReport; } | 277 | /** |
| 278 | * @brief Gets current mouse report used by pointing device task | ||
| 279 | * | ||
| 280 | * @return report_mouse_t | ||
| 281 | */ | ||
| 282 | report_mouse_t pointing_device_get_report(void) { return local_mouse_report; } | ||
| 283 | |||
| 284 | /** | ||
| 285 | * @brief Sets mouse report used be pointing device task | ||
| 286 | * | ||
| 287 | * @param[in] new_mouse_report | ||
| 288 | */ | ||
| 289 | void pointing_device_set_report(report_mouse_t new_mouse_report) { local_mouse_report = new_mouse_report; } | ||
| 290 | |||
| 291 | /** | ||
| 292 | * @brief Gets current pointing device CPI if supported | ||
| 293 | * | ||
| 294 | * Gets current cpi from pointing device driver if supported and returns it as uint16_t | ||
| 295 | * | ||
| 296 | * @return cpi value as uint16_t | ||
| 297 | */ | ||
| 298 | uint16_t pointing_device_get_cpi(void) { | ||
| 299 | #if defined(SPLIT_POINTING_ENABLE) | ||
| 300 | return POINTING_DEVICE_THIS_SIDE ? pointing_device_driver.get_cpi() : shared_cpi; | ||
| 301 | #else | ||
| 302 | return pointing_device_driver.get_cpi(); | ||
| 303 | #endif | ||
| 304 | } | ||
| 115 | 305 | ||
| 116 | void pointing_device_set_report(report_mouse_t newMouseReport) { mouseReport = newMouseReport; } | 306 | /** |
| 307 | * @brief Set pointing device CPI if supported | ||
| 308 | * | ||
| 309 | * Takes a uint16_t value to set pointing device cpi if supported by driver. | ||
| 310 | * | ||
| 311 | * @param[in] cpi uint16_t value. | ||
| 312 | */ | ||
| 313 | void pointing_device_set_cpi(uint16_t cpi) { | ||
| 314 | #if defined(SPLIT_POINTING_ENABLE) | ||
| 315 | if (POINTING_DEVICE_THIS_SIDE) { | ||
| 316 | pointing_device_driver.set_cpi(cpi); | ||
| 317 | } else { | ||
| 318 | shared_cpi = cpi; | ||
| 319 | } | ||
| 320 | #else | ||
| 321 | pointing_device_driver.set_cpi(cpi); | ||
| 322 | #endif | ||
| 323 | } | ||
| 117 | 324 | ||
| 118 | uint16_t pointing_device_get_cpi(void) { return pointing_device_driver.get_cpi(); } | 325 | #if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED) |
| 326 | /** | ||
| 327 | * @brief Set pointing device CPI if supported | ||
| 328 | * | ||
| 329 | * Takes a bool and uint16_t and allows setting cpi for a single side when using 2 pointing devices with a split keyboard. | ||
| 330 | * | ||
| 331 | * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED | ||
| 332 | * | ||
| 333 | * @param[in] left true = left, false = right. | ||
| 334 | * @param[in] cpi uint16_t value. | ||
| 335 | */ | ||
| 336 | void pointing_device_set_cpi_on_side(bool left, uint16_t cpi) { | ||
| 337 | bool local = (is_keyboard_left() & left) ? true : false; | ||
| 338 | if (local) { | ||
| 339 | pointing_device_driver.set_cpi(cpi); | ||
| 340 | } else { | ||
| 341 | shared_cpi = cpi; | ||
| 342 | } | ||
| 343 | } | ||
| 119 | 344 | ||
| 120 | void pointing_device_set_cpi(uint16_t cpi) { pointing_device_driver.set_cpi(cpi); } | 345 | /** |
| 346 | * @brief clamps int16_t to int8_t | ||
| 347 | * | ||
| 348 | * @param[in] int16_t value | ||
| 349 | * @return int8_t clamped value | ||
| 350 | */ | ||
| 351 | static inline int8_t pointing_device_movement_clamp(int16_t value) { | ||
| 352 | if (value < INT8_MIN) { | ||
| 353 | return INT8_MIN; | ||
| 354 | } else if (value > INT8_MAX) { | ||
| 355 | return INT8_MAX; | ||
| 356 | } else { | ||
| 357 | return value; | ||
| 358 | } | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * @brief combines 2 mouse reports and returns 2 | ||
| 363 | * | ||
| 364 | * Combines 2 report_mouse_t structs, clamping movement values to int8_t and ignores report_id then returns the resulting report_mouse_t struct. | ||
| 365 | * | ||
| 366 | * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED | ||
| 367 | * | ||
| 368 | * @param[in] left_report left report_mouse_t | ||
| 369 | * @param[in] right_report right report_mouse_t | ||
| 370 | * @return combined report_mouse_t of left_report and right_report | ||
| 371 | */ | ||
| 372 | report_mouse_t pointing_device_combine_reports(report_mouse_t left_report, report_mouse_t right_report) { | ||
| 373 | left_report.x = pointing_device_movement_clamp((int16_t)left_report.x + right_report.x); | ||
| 374 | left_report.y = pointing_device_movement_clamp((int16_t)left_report.y + right_report.y); | ||
| 375 | left_report.h = pointing_device_movement_clamp((int16_t)left_report.h + right_report.h); | ||
| 376 | left_report.v = pointing_device_movement_clamp((int16_t)left_report.v + right_report.v); | ||
| 377 | left_report.buttons |= right_report.buttons; | ||
| 378 | return left_report; | ||
| 379 | } | ||
| 380 | |||
| 381 | /** | ||
| 382 | * @brief Adjust mouse report by any optional right pointing configuration defines | ||
| 383 | * | ||
| 384 | * This applies rotation or inversion to the mouse report as selected by the pointing device common configuration defines. | ||
| 385 | * | ||
| 386 | * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED | ||
| 387 | * | ||
| 388 | * @param[in] mouse_report report_mouse_t to be adjusted | ||
| 389 | * @return report_mouse_t with adjusted values | ||
| 390 | */ | ||
| 391 | report_mouse_t pointing_device_adjust_by_defines_right(report_mouse_t mouse_report) { | ||
| 392 | // Support rotation of the sensor data | ||
| 393 | # if defined(POINTING_DEVICE_ROTATION_90_RIGHT) || defined(POINTING_DEVICE_ROTATION_RIGHT) || defined(POINTING_DEVICE_ROTATION_RIGHT) | ||
| 394 | int8_t x = mouse_report.x, y = mouse_report.y; | ||
| 395 | # if defined(POINTING_DEVICE_ROTATION_90_RIGHT) | ||
| 396 | mouse_report.x = y; | ||
| 397 | mouse_report.y = -x; | ||
| 398 | # elif defined(POINTING_DEVICE_ROTATION_180_RIGHT) | ||
| 399 | mouse_report.x = -x; | ||
| 400 | mouse_report.y = -y; | ||
| 401 | # elif defined(POINTING_DEVICE_ROTATION_270_RIGHT) | ||
| 402 | mouse_report.x = -y; | ||
| 403 | mouse_report.y = x; | ||
| 404 | # else | ||
| 405 | # error "How the heck did you get here?!" | ||
| 406 | # endif | ||
| 407 | # endif | ||
| 408 | // Support Inverting the X and Y Axises | ||
| 409 | # if defined(POINTING_DEVICE_INVERT_X_RIGHT) | ||
| 410 | mouse_report.x = -mouse_report.x; | ||
| 411 | # endif | ||
| 412 | # if defined(POINTING_DEVICE_INVERT_Y_RIGHT) | ||
| 413 | mouse_report.y = -mouse_report.y; | ||
| 414 | # endif | ||
| 415 | return mouse_report; | ||
| 416 | } | ||
| 417 | |||
| 418 | /** | ||
| 419 | * @brief Weak function allowing for keyboard level mouse report modification | ||
| 420 | * | ||
| 421 | * Takes 2 report_mouse_t structs allowing individual modification of sides at keyboard level then returns pointing_device_task_combined_user. | ||
| 422 | * | ||
| 423 | * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED | ||
| 424 | * | ||
| 425 | * @param[in] left_report report_mouse_t | ||
| 426 | * @param[in] right_report report_mouse_t | ||
| 427 | * @return pointing_device_task_combined_user(left_report, right_report) by default | ||
| 428 | */ | ||
| 429 | __attribute__((weak)) report_mouse_t pointing_device_task_combined_kb(report_mouse_t left_report, report_mouse_t right_report) { return pointing_device_task_combined_user(left_report, right_report); } | ||
| 430 | |||
| 431 | /** | ||
| 432 | * @brief Weak function allowing for user level mouse report modification | ||
| 433 | * | ||
| 434 | * Takes 2 report_mouse_t structs allowing individual modification of sides at user level then returns pointing_device_combine_reports. | ||
| 435 | * | ||
| 436 | * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED | ||
| 437 | * | ||
| 438 | * @param[in] left_report report_mouse_t | ||
| 439 | * @param[in] right_report report_mouse_t | ||
| 440 | * @return pointing_device_combine_reports(left_report, right_report) by default | ||
| 441 | */ | ||
| 442 | __attribute__((weak)) report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report) { return pointing_device_combine_reports(left_report, right_report); } | ||
| 443 | #endif | ||
diff --git a/quantum/pointing_device.h b/quantum/pointing_device.h index 5106c26660..78398d8999 100644 --- a/quantum/pointing_device.h +++ b/quantum/pointing_device.h | |||
| @@ -86,3 +86,16 @@ void pointing_device_init_user(void); | |||
| 86 | report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report); | 86 | report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report); |
| 87 | report_mouse_t pointing_device_task_user(report_mouse_t mouse_report); | 87 | report_mouse_t pointing_device_task_user(report_mouse_t mouse_report); |
| 88 | uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button); | 88 | uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button); |
| 89 | report_mouse_t pointing_device_adjust_by_defines(report_mouse_t mouse_report); | ||
| 90 | |||
| 91 | #if defined(SPLIT_POINTING_ENABLE) | ||
| 92 | void pointing_device_set_shared_report(report_mouse_t report); | ||
| 93 | uint16_t pointing_device_get_shared_cpi(void); | ||
| 94 | # if defined(POINTING_DEVICE_COMBINED) | ||
| 95 | void pointing_device_set_cpi_on_side(bool left, uint16_t cpi); | ||
| 96 | report_mouse_t pointing_device_combine_reports(report_mouse_t left_report, report_mouse_t right_report); | ||
| 97 | report_mouse_t pointing_device_task_combined_kb(report_mouse_t left_report, report_mouse_t right_report); | ||
| 98 | report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report); | ||
| 99 | report_mouse_t pointing_device_adjust_by_defines_right(report_mouse_t mouse_report); | ||
| 100 | # endif //defined(POINTING_DEVICE_COMBINED) | ||
| 101 | #endif //defined(SPLIT_POINTING_ENABLE) | ||
diff --git a/quantum/pointing_device_drivers.c b/quantum/pointing_device_drivers.c index 9ad5e76ba6..0852a0bea7 100644 --- a/quantum/pointing_device_drivers.c +++ b/quantum/pointing_device_drivers.c | |||
| @@ -165,14 +165,13 @@ const pointing_device_driver_t pointing_device_driver = { | |||
| 165 | // clang-format on | 165 | // clang-format on |
| 166 | 166 | ||
| 167 | #elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball) | 167 | #elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball) |
| 168 | report_mouse_t pimorono_trackball_get_report(report_mouse_t mouse_report) { | 168 | report_mouse_t pimoroni_trackball_get_report(report_mouse_t mouse_report) { |
| 169 | static fast_timer_t throttle = 0; | 169 | static uint16_t debounce = 0; |
| 170 | static uint16_t debounce = 0; | 170 | static uint8_t error_count = 0; |
| 171 | static uint8_t error_count = 0; | 171 | pimoroni_data_t pimoroni_data = {0}; |
| 172 | pimoroni_data_t pimoroni_data = {0}; | 172 | static int16_t x_offset = 0, y_offset = 0; |
| 173 | static int16_t x_offset = 0, y_offset = 0; | 173 | |
| 174 | 174 | if (error_count < PIMORONI_TRACKBALL_ERROR_COUNT) { | |
| 175 | if (error_count < PIMORONI_TRACKBALL_ERROR_COUNT && timer_elapsed_fast(throttle) >= PIMORONI_TRACKBALL_INTERVAL_MS) { | ||
| 176 | i2c_status_t status = read_pimoroni_trackball(&pimoroni_data); | 175 | i2c_status_t status = read_pimoroni_trackball(&pimoroni_data); |
| 177 | 176 | ||
| 178 | if (status == I2C_STATUS_SUCCESS) { | 177 | if (status == I2C_STATUS_SUCCESS) { |
| @@ -195,17 +194,16 @@ report_mouse_t pimorono_trackball_get_report(report_mouse_t mouse_report) { | |||
| 195 | } else { | 194 | } else { |
| 196 | error_count++; | 195 | error_count++; |
| 197 | } | 196 | } |
| 198 | throttle = timer_read_fast(); | ||
| 199 | } | 197 | } |
| 200 | return mouse_report; | 198 | return mouse_report; |
| 201 | } | 199 | } |
| 202 | 200 | ||
| 203 | // clang-format off | 201 | // clang-format off |
| 204 | const pointing_device_driver_t pointing_device_driver = { | 202 | const pointing_device_driver_t pointing_device_driver = { |
| 205 | .init = pimironi_trackball_device_init, | 203 | .init = pimoroni_trackball_device_init, |
| 206 | .get_report = pimorono_trackball_get_report, | 204 | .get_report = pimoroni_trackball_get_report, |
| 207 | .set_cpi = NULL, | 205 | .set_cpi = pimoroni_trackball_set_cpi, |
| 208 | .get_cpi = NULL | 206 | .get_cpi = pimoroni_trackball_get_cpi |
| 209 | }; | 207 | }; |
| 210 | // clang-format on | 208 | // clang-format on |
| 211 | #elif defined(POINTING_DEVICE_DRIVER_pmw3360) | 209 | #elif defined(POINTING_DEVICE_DRIVER_pmw3360) |
diff --git a/quantum/split_common/transaction_id_define.h b/quantum/split_common/transaction_id_define.h index 535bc21aea..aa71c3621e 100644 --- a/quantum/split_common/transaction_id_define.h +++ b/quantum/split_common/transaction_id_define.h | |||
| @@ -78,6 +78,12 @@ enum serial_transaction_id { | |||
| 78 | PUT_ST7565, | 78 | PUT_ST7565, |
| 79 | #endif // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE) | 79 | #endif // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE) |
| 80 | 80 | ||
| 81 | #if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) | ||
| 82 | GET_POINTING_CHECKSUM, | ||
| 83 | GET_POINTING_DATA, | ||
| 84 | PUT_POINTING_CPI, | ||
| 85 | #endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) | ||
| 86 | |||
| 81 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | 87 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) |
| 82 | PUT_RPC_INFO, | 88 | PUT_RPC_INFO, |
| 83 | PUT_RPC_REQ_DATA, | 89 | PUT_RPC_REQ_DATA, |
diff --git a/quantum/split_common/transactions.c b/quantum/split_common/transactions.c index 3ff87710e7..9622acb377 100644 --- a/quantum/split_common/transactions.c +++ b/quantum/split_common/transactions.c | |||
| @@ -579,6 +579,82 @@ static void st7565_handlers_slave(matrix_row_t master_matrix[], matrix_row_t sla | |||
| 579 | #endif // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE) | 579 | #endif // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE) |
| 580 | 580 | ||
| 581 | //////////////////////////////////////////////////// | 581 | //////////////////////////////////////////////////// |
| 582 | // POINTING | ||
| 583 | |||
| 584 | #if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) | ||
| 585 | |||
| 586 | static bool pointing_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 587 | # if defined(POINTING_DEVICE_LEFT) | ||
| 588 | if (is_keyboard_left()) { | ||
| 589 | return true; | ||
| 590 | } | ||
| 591 | # elif defined(POINTING_DEVICE_RIGHT) | ||
| 592 | if (!is_keyboard_left()) { | ||
| 593 | return true; | ||
| 594 | } | ||
| 595 | # endif | ||
| 596 | static uint32_t last_update = 0; | ||
| 597 | static uint16_t last_cpi = 0; | ||
| 598 | report_mouse_t temp_state; | ||
| 599 | uint16_t temp_cpi; | ||
| 600 | bool okay = read_if_checksum_mismatch(GET_POINTING_CHECKSUM, GET_POINTING_DATA, &last_update, &temp_state, &split_shmem->pointing.report, sizeof(temp_state)); | ||
| 601 | if (okay) pointing_device_set_shared_report(temp_state); | ||
| 602 | temp_cpi = pointing_device_get_shared_cpi(); | ||
| 603 | if (temp_cpi && memcmp(&last_cpi, &temp_cpi, sizeof(temp_cpi)) != 0) { | ||
| 604 | memcpy(&split_shmem->pointing.cpi, &temp_cpi, sizeof(temp_cpi)); | ||
| 605 | okay = transport_write(PUT_POINTING_CPI, &split_shmem->pointing.cpi, sizeof(split_shmem->pointing.cpi)); | ||
| 606 | if (okay) { | ||
| 607 | last_cpi = temp_cpi; | ||
| 608 | } | ||
| 609 | } | ||
| 610 | return okay; | ||
| 611 | } | ||
| 612 | |||
| 613 | extern const pointing_device_driver_t pointing_device_driver; | ||
| 614 | |||
| 615 | static void pointing_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 616 | # if defined(POINTING_DEVICE_LEFT) | ||
| 617 | if (!is_keyboard_left()) { | ||
| 618 | return; | ||
| 619 | } | ||
| 620 | # elif defined(POINTING_DEVICE_RIGHT) | ||
| 621 | if (is_keyboard_left()) { | ||
| 622 | return; | ||
| 623 | } | ||
| 624 | # endif | ||
| 625 | report_mouse_t temp_report; | ||
| 626 | uint16_t temp_cpi; | ||
| 627 | # ifdef POINTING_DEVICE_TASK_THROTTLE_MS | ||
| 628 | static uint32_t last_exec = 0; | ||
| 629 | if (timer_elapsed32(last_exec) < POINTING_DEVICE_TASK_THROTTLE_MS) { | ||
| 630 | return; | ||
| 631 | } | ||
| 632 | last_exec = timer_read32(); | ||
| 633 | # endif | ||
| 634 | temp_cpi = pointing_device_driver.get_cpi(); | ||
| 635 | if (split_shmem->pointing.cpi && memcmp(&split_shmem->pointing.cpi, &temp_cpi, sizeof(temp_cpi)) != 0) { | ||
| 636 | pointing_device_driver.set_cpi(split_shmem->pointing.cpi); | ||
| 637 | } | ||
| 638 | memset(&temp_report, 0, sizeof(temp_report)); | ||
| 639 | temp_report = pointing_device_driver.get_report(temp_report); | ||
| 640 | memcpy(&split_shmem->pointing.report, &temp_report, sizeof(temp_report)); | ||
| 641 | // Now update the checksum given that the pointing has been written to | ||
| 642 | split_shmem->pointing.checksum = crc8(&temp_report, sizeof(temp_report)); | ||
| 643 | } | ||
| 644 | |||
| 645 | # define TRANSACTIONS_POINTING_MASTER() TRANSACTION_HANDLER_MASTER(pointing) | ||
| 646 | # define TRANSACTIONS_POINTING_SLAVE() TRANSACTION_HANDLER_SLAVE(pointing) | ||
| 647 | # define TRANSACTIONS_POINTING_REGISTRATIONS [GET_POINTING_CHECKSUM] = trans_target2initiator_initializer(pointing.checksum), [GET_POINTING_DATA] = trans_target2initiator_initializer(pointing.report), [PUT_POINTING_CPI] = trans_initiator2target_initializer(pointing.cpi), | ||
| 648 | |||
| 649 | #else // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) | ||
| 650 | |||
| 651 | # define TRANSACTIONS_POINTING_MASTER() | ||
| 652 | # define TRANSACTIONS_POINTING_SLAVE() | ||
| 653 | # define TRANSACTIONS_POINTING_REGISTRATIONS | ||
| 654 | |||
| 655 | #endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) | ||
| 656 | |||
| 657 | //////////////////////////////////////////////////// | ||
| 582 | 658 | ||
| 583 | uint8_t dummy; | 659 | uint8_t dummy; |
| 584 | split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = { | 660 | split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = { |
| @@ -604,6 +680,7 @@ split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = { | |||
| 604 | TRANSACTIONS_WPM_REGISTRATIONS | 680 | TRANSACTIONS_WPM_REGISTRATIONS |
| 605 | TRANSACTIONS_OLED_REGISTRATIONS | 681 | TRANSACTIONS_OLED_REGISTRATIONS |
| 606 | TRANSACTIONS_ST7565_REGISTRATIONS | 682 | TRANSACTIONS_ST7565_REGISTRATIONS |
| 683 | TRANSACTIONS_POINTING_REGISTRATIONS | ||
| 607 | // clang-format on | 684 | // clang-format on |
| 608 | 685 | ||
| 609 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | 686 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) |
| @@ -629,6 +706,7 @@ bool transactions_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix | |||
| 629 | TRANSACTIONS_WPM_MASTER(); | 706 | TRANSACTIONS_WPM_MASTER(); |
| 630 | TRANSACTIONS_OLED_MASTER(); | 707 | TRANSACTIONS_OLED_MASTER(); |
| 631 | TRANSACTIONS_ST7565_MASTER(); | 708 | TRANSACTIONS_ST7565_MASTER(); |
| 709 | TRANSACTIONS_POINTING_MASTER(); | ||
| 632 | return true; | 710 | return true; |
| 633 | } | 711 | } |
| 634 | 712 | ||
| @@ -647,6 +725,7 @@ void transactions_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[ | |||
| 647 | TRANSACTIONS_WPM_SLAVE(); | 725 | TRANSACTIONS_WPM_SLAVE(); |
| 648 | TRANSACTIONS_OLED_SLAVE(); | 726 | TRANSACTIONS_OLED_SLAVE(); |
| 649 | TRANSACTIONS_ST7565_SLAVE(); | 727 | TRANSACTIONS_ST7565_SLAVE(); |
| 728 | TRANSACTIONS_POINTING_SLAVE(); | ||
| 650 | } | 729 | } |
| 651 | 730 | ||
| 652 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | 731 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) |
diff --git a/quantum/split_common/transport.h b/quantum/split_common/transport.h index 1d4f6ed0cd..31b804908b 100644 --- a/quantum/split_common/transport.h +++ b/quantum/split_common/transport.h | |||
| @@ -106,6 +106,15 @@ typedef struct _split_mods_sync_t { | |||
| 106 | } split_mods_sync_t; | 106 | } split_mods_sync_t; |
| 107 | #endif // SPLIT_MODS_ENABLE | 107 | #endif // SPLIT_MODS_ENABLE |
| 108 | 108 | ||
| 109 | #if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) | ||
| 110 | # include "pointing_device.h" | ||
| 111 | typedef struct _split_slave_pointing_sync_t { | ||
| 112 | uint8_t checksum; | ||
| 113 | report_mouse_t report; | ||
| 114 | uint16_t cpi; | ||
| 115 | } split_slave_pointing_sync_t; | ||
| 116 | #endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) | ||
| 117 | |||
| 109 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | 118 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) |
| 110 | typedef struct _rpc_sync_info_t { | 119 | typedef struct _rpc_sync_info_t { |
| 111 | int8_t transaction_id; | 120 | int8_t transaction_id; |
| @@ -173,6 +182,10 @@ typedef struct _split_shared_memory_t { | |||
| 173 | uint8_t current_st7565_state; | 182 | uint8_t current_st7565_state; |
| 174 | #endif // ST7565_ENABLE(OLED_ENABLE) && defined(SPLIT_ST7565_ENABLE) | 183 | #endif // ST7565_ENABLE(OLED_ENABLE) && defined(SPLIT_ST7565_ENABLE) |
| 175 | 184 | ||
| 185 | #if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) | ||
| 186 | split_slave_pointing_sync_t pointing; | ||
| 187 | #endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) | ||
| 188 | |||
| 176 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | 189 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) |
| 177 | rpc_sync_info_t rpc_info; | 190 | rpc_sync_info_t rpc_info; |
| 178 | uint8_t rpc_m2s_buffer[RPC_M2S_BUFFER_SIZE]; | 191 | uint8_t rpc_m2s_buffer[RPC_M2S_BUFFER_SIZE]; |
