Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

High resolution scrolling (without feature report parsing) #24423

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/features/pointing_device.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
:::

## 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

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.
Expand Down
19 changes: 19 additions & 0 deletions quantum/pointing_device/pointing_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
# include "mousekey.h"
#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
# error More than one rotation selected. This is not supported.
#endif
Expand Down Expand Up @@ -78,6 +82,9 @@ uint16_t pointing_device_get_shared_cpi(void) {

static report_mouse_t local_mouse_report = {};
static bool pointing_device_force_send = false;
#ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
static uint16_t hires_scroll_resolution;
#endif

extern const pointing_device_driver_t pointing_device_driver;

Expand Down Expand Up @@ -155,6 +162,12 @@ __attribute__((weak)) void pointing_device_init(void) {
# 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_user();
Expand Down Expand Up @@ -502,3 +515,9 @@ __attribute__((weak)) void pointing_device_keycode_handler(uint16_t keycode, boo
pointing_device_send();
}
}

#ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
uint16_t pointing_device_get_hires_scroll_resolution(void) {
return hires_scroll_resolution;
}
#endif
4 changes: 4 additions & 0 deletions quantum/pointing_device/pointing_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,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);
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)
void pointing_device_set_shared_report(report_mouse_t report);
uint16_t pointing_device_get_shared_cpi(void);
Expand Down
24 changes: 24 additions & 0 deletions tmk_core/protocol/usb_descriptor.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,24 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
# endif
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)
HID_RI_USAGE(8, 0x38), // Wheel
# ifndef WHEEL_EXTENDED_REPORT
Expand All @@ -179,6 +197,7 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
HID_RI_REPORT_SIZE(8, 0x10),
# endif
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),

// Horizontal wheel (1 or 2 bytes)
HID_RI_USAGE_PAGE(8, 0x0C),// Consumer
HID_RI_USAGE(16, 0x0238), // AC Pan
Expand All @@ -194,6 +213,11 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
HID_RI_REPORT_SIZE(8, 0x10),
# endif
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),
# ifndef MOUSE_SHARED_EP
Expand Down
20 changes: 20 additions & 0 deletions tmk_core/protocol/usb_descriptor_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,23 @@
#ifndef RAW_USAGE_ID
# define RAW_USAGE_ID 0x61
#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
28 changes: 26 additions & 2 deletions tmk_core/protocol/vusb/vusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,24 @@ const PROGMEM uchar shared_hid_report[] = {
# endif
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)
0x09, 0x38, // Usage (Wheel)
# ifndef WHEEL_EXTENDED_REPORT
Expand All @@ -538,6 +556,7 @@ const PROGMEM uchar shared_hid_report[] = {
0x75, 0x10, // Report Size (16)
# endif
0x81, 0x06, // Input (Data, Variable, Relative)

// Horizontal wheel (1 or 2 bytes)
0x05, 0x0C, // Usage Page (Consumer)
0x0A, 0x38, 0x02, // Usage (AC Pan)
Expand All @@ -553,8 +572,13 @@ const PROGMEM uchar shared_hid_report[] = {
0x75, 0x10, // Report Size (16)
# endif
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

#ifdef EXTRAKEY_ENABLE
Expand Down
Loading