High resolution scrolling (without feature report parsing) (#24423)

* hires scrolling without feature report parsing

* fix valid range for exponent

* fix incorrect minimum exponent value documentation
This commit is contained in:
eynsai 2025-04-22 18:04:31 -04:00 committed by GitHub
parent 83818d1d6f
commit 7a2cd0fa96
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 119 additions and 2 deletions

View File

@ -419,6 +419,32 @@ The `POINTING_DEVICE_CS_PIN`, `POINTING_DEVICE_SDIO_PIN`, and `POINTING_DEVICE_S
Any pointing device with a lift/contact status can integrate inertial cursor feature into its driver, controlled by `POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE`. e.g. PMW3360 can use Lift_Stat from Motion register. Note that `POINTING_DEVICE_MOTION_PIN` cannot be used with this feature; continuous polling of `get_report()` is needed to generate glide reports. Any pointing device with a lift/contact status can integrate inertial cursor feature into its driver, controlled by `POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE`. e.g. PMW3360 can use Lift_Stat from Motion register. Note that `POINTING_DEVICE_MOTION_PIN` cannot be used with this feature; continuous polling of `get_report()` is needed to generate glide reports.
::: :::
## High Resolution Scrolling
| Setting | Description | Default |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `POINTING_DEVICE_HIRES_SCROLL_ENABLE` | (Optional) Enables high resolution scrolling. | _not defined_ |
| `POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER`| (Optional) Resolution mutiplier value used by high resolution scrolling. Must be between 1 and 127, inclusive. | `120` |
| `POINTING_DEVICE_HIRES_SCROLL_EXPONENT` | (Optional) Resolution exponent value used by high resolution scrolling. Must be between 0 and 127, inclusive. | `0` |
The `POINTING_DEVICE_HIRES_SCROLL_ENABLE` setting enables smooth and continuous scrolling when using trackballs or high-end encoders as mouse wheels (as opposed to the typical stepped behavior of most mouse wheels).
This works by adding a resolution multiplier to the HID descriptor for mouse wheel reports, causing the host computer to interpret each wheel tick sent by the keyboard as a fraction of a normal wheel tick.
The resolution multiplier is set to `1 / (POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER * (10 ^ POINTING_DEVICE_HIRES_SCROLL_EXPONENT))`, which is `1 / 120` by default.
If even smoother scrolling than provided by this default value is desired, first try using `#define POINTING_DEVICE_HIRES_SCROLL_EXPONENT 1` which will result in a multiplier of `1 / 1200`.
The function `pointing_device_get_hires_scroll_resolution()` can be called to get the pre-computed resolution multiplier value as a `uint16_t`.
::: warning
High resolution scrolling usually results in larger and/or more frequent mouse reports. This can result in overflow errors and overloading of the host computer's input buffer.
To deal with these issues, define `WHEEL_EXTENDED_REPORT` and throttle the rate at which mouse reports are sent.
:::
::: warning
Many programs, especially those that implement their own smoothing for scrolling, don't work well when they receive simultaneous vertical and horizontal wheel inputs (e.g. from high resolution drag-scroll using a trackball).
These programs typically implement their smoothing in a way that assumes the user will only scroll in one axis at a time, resulting in slow or jittery motion when trying to scroll at an angle.
This can be addressed by snapping scrolling to one axis at a time.
:::
## Split Keyboard Configuration ## Split Keyboard Configuration
The following configuration options are only available when using `SPLIT_POINTING_ENABLE` see [data sync options](split_keyboard#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. The following configuration options are only available when using `SPLIT_POINTING_ENABLE` see [data sync options](split_keyboard#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.

View File

@ -25,6 +25,10 @@
# include "mousekey.h" # include "mousekey.h"
#endif #endif
#ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
# include "usb_descriptor_common.h"
#endif
#if (defined(POINTING_DEVICE_ROTATION_90) + defined(POINTING_DEVICE_ROTATION_180) + defined(POINTING_DEVICE_ROTATION_270)) > 1 #if (defined(POINTING_DEVICE_ROTATION_90) + defined(POINTING_DEVICE_ROTATION_180) + defined(POINTING_DEVICE_ROTATION_270)) > 1
# error More than one rotation selected. This is not supported. # error More than one rotation selected. This is not supported.
#endif #endif
@ -78,6 +82,9 @@ uint16_t pointing_device_get_shared_cpi(void) {
static report_mouse_t local_mouse_report = {}; static report_mouse_t local_mouse_report = {};
static bool pointing_device_force_send = false; static bool pointing_device_force_send = false;
#ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
static uint16_t hires_scroll_resolution;
#endif
#define POINTING_DEVICE_DRIVER_CONCAT(name) name##_pointing_device_driver #define POINTING_DEVICE_DRIVER_CONCAT(name) name##_pointing_device_driver
#define POINTING_DEVICE_DRIVER(name) POINTING_DEVICE_DRIVER_CONCAT(name) #define POINTING_DEVICE_DRIVER(name) POINTING_DEVICE_DRIVER_CONCAT(name)
@ -176,6 +183,12 @@ __attribute__((weak)) void pointing_device_init(void) {
# endif # endif
#endif #endif
} }
#ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
hires_scroll_resolution = POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER;
for (int i = 0; i < POINTING_DEVICE_HIRES_SCROLL_EXPONENT; i++) {
hires_scroll_resolution *= 10;
}
#endif
pointing_device_init_kb(); pointing_device_init_kb();
pointing_device_init_user(); pointing_device_init_user();
@ -523,3 +536,9 @@ __attribute__((weak)) void pointing_device_keycode_handler(uint16_t keycode, boo
pointing_device_send(); pointing_device_send();
} }
} }
#ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
uint16_t pointing_device_get_hires_scroll_resolution(void) {
return hires_scroll_resolution;
}
#endif

View File

@ -122,6 +122,10 @@ uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, poi
report_mouse_t pointing_device_adjust_by_defines(report_mouse_t mouse_report); report_mouse_t pointing_device_adjust_by_defines(report_mouse_t mouse_report);
void pointing_device_keycode_handler(uint16_t keycode, bool pressed); void pointing_device_keycode_handler(uint16_t keycode, bool pressed);
#ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
uint16_t pointing_device_get_hires_scroll_resolution(void);
#endif
#if defined(SPLIT_POINTING_ENABLE) #if defined(SPLIT_POINTING_ENABLE)
void pointing_device_set_shared_report(report_mouse_t report); void pointing_device_set_shared_report(report_mouse_t report);
uint16_t pointing_device_get_shared_cpi(void); uint16_t pointing_device_get_shared_cpi(void);

View File

@ -165,6 +165,24 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
# endif # endif
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE), HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),
# ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
HID_RI_COLLECTION(8, 0x02),
// Feature report and padding (1 byte)
HID_RI_USAGE(8, 0x48), // Resolution Multiplier
HID_RI_REPORT_COUNT(8, 0x01),
HID_RI_REPORT_SIZE(8, 0x02),
HID_RI_LOGICAL_MINIMUM(8, 0x00),
HID_RI_LOGICAL_MAXIMUM(8, 0x01),
HID_RI_PHYSICAL_MINIMUM(8, 1),
HID_RI_PHYSICAL_MAXIMUM(8, POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER),
HID_RI_UNIT_EXPONENT(8, POINTING_DEVICE_HIRES_SCROLL_EXPONENT),
HID_RI_FEATURE(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
HID_RI_PHYSICAL_MINIMUM(8, 0x00),
HID_RI_PHYSICAL_MAXIMUM(8, 0x00),
HID_RI_REPORT_SIZE(8, 0x06),
HID_RI_FEATURE(8, HID_IOF_CONSTANT),
# endif
// Vertical wheel (1 or 2 bytes) // Vertical wheel (1 or 2 bytes)
HID_RI_USAGE(8, 0x38), // Wheel HID_RI_USAGE(8, 0x38), // Wheel
# ifndef WHEEL_EXTENDED_REPORT # ifndef WHEEL_EXTENDED_REPORT
@ -179,6 +197,7 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
HID_RI_REPORT_SIZE(8, 0x10), HID_RI_REPORT_SIZE(8, 0x10),
# endif # endif
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE), HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),
// Horizontal wheel (1 or 2 bytes) // Horizontal wheel (1 or 2 bytes)
HID_RI_USAGE_PAGE(8, 0x0C),// Consumer HID_RI_USAGE_PAGE(8, 0x0C),// Consumer
HID_RI_USAGE(16, 0x0238), // AC Pan HID_RI_USAGE(16, 0x0238), // AC Pan
@ -194,6 +213,11 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
HID_RI_REPORT_SIZE(8, 0x10), HID_RI_REPORT_SIZE(8, 0x10),
# endif # endif
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE), HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),
# ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
HID_RI_END_COLLECTION(0),
# endif
HID_RI_END_COLLECTION(0), HID_RI_END_COLLECTION(0),
HID_RI_END_COLLECTION(0), HID_RI_END_COLLECTION(0),
# ifndef MOUSE_SHARED_EP # ifndef MOUSE_SHARED_EP

View File

@ -32,3 +32,23 @@
#ifndef RAW_USAGE_ID #ifndef RAW_USAGE_ID
# define RAW_USAGE_ID 0x61 # define RAW_USAGE_ID 0x61
#endif #endif
/////////////////////
// Hires Scroll Defaults
#ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
# ifdef POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER
# if POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER > 127 || POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER < 1
# error "POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER must be between 1 and 127, inclusive!"
# endif
# else
# define POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER 120
# endif
# ifdef POINTING_DEVICE_HIRES_SCROLL_EXPONENT
# if POINTING_DEVICE_HIRES_SCROLL_EXPONENT > 127 || POINTING_DEVICE_HIRES_SCROLL_EXPONENT < 0
# error "POINTING_DEVICE_HIRES_SCROLL_EXPONENT must be between 0 and 127, inclusive!"
# endif
# else
# define POINTING_DEVICE_HIRES_SCROLL_EXPONENT 0
# endif
#endif

View File

@ -520,6 +520,24 @@ const PROGMEM uchar shared_hid_report[] = {
# endif # endif
0x81, 0x06, // Input (Data, Variable, Relative) 0x81, 0x06, // Input (Data, Variable, Relative)
# ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
// Feature report and padding (1 byte)
0xA1, 0x02, // Collection (Logical)
0x09, 0x48, // Usage (Resolution Multiplier)
0x95, 0x01, // Report Count (1)
0x75, 0x02, // Report Size (2)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x35, 0x01, // Physical Minimum (1)
0x45, POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER, // Physical Maximum (POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER)
0x55, POINTING_DEVICE_HIRES_SCROLL_EXPONENT, // Unit Exponent (POINTING_DEVICE_HIRES_SCROLL_EXPONENT)
0xB1, 0x02, // Feature (Data, Variable, Absolute)
0x35, 0x00, // Physical Minimum (0)
0x45, 0x00, // Physical Maximum (0)
0x75, 0x06, // Report Size (6)
0xB1, 0x03, // Feature (Constant)
# endif
// Vertical wheel (1 or 2 bytes) // Vertical wheel (1 or 2 bytes)
0x09, 0x38, // Usage (Wheel) 0x09, 0x38, // Usage (Wheel)
# ifndef WHEEL_EXTENDED_REPORT # ifndef WHEEL_EXTENDED_REPORT
@ -534,6 +552,7 @@ const PROGMEM uchar shared_hid_report[] = {
0x75, 0x10, // Report Size (16) 0x75, 0x10, // Report Size (16)
# endif # endif
0x81, 0x06, // Input (Data, Variable, Relative) 0x81, 0x06, // Input (Data, Variable, Relative)
// Horizontal wheel (1 or 2 bytes) // Horizontal wheel (1 or 2 bytes)
0x05, 0x0C, // Usage Page (Consumer) 0x05, 0x0C, // Usage Page (Consumer)
0x0A, 0x38, 0x02, // Usage (AC Pan) 0x0A, 0x38, 0x02, // Usage (AC Pan)
@ -549,8 +568,13 @@ const PROGMEM uchar shared_hid_report[] = {
0x75, 0x10, // Report Size (16) 0x75, 0x10, // Report Size (16)
# endif # endif
0x81, 0x06, // Input (Data, Variable, Relative) 0x81, 0x06, // Input (Data, Variable, Relative)
0xC0, // End Collection
0xC0, // End Collection # ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
0xC0, // End Collection
# endif
0xC0, // End Collection
0xC0, // End Collection
#endif #endif
#ifdef EXTRAKEY_ENABLE #ifdef EXTRAKEY_ENABLE