Skip to content

Commit

Permalink
Merge pull request #794 from rightaditya/hires-scroll
Browse files Browse the repository at this point in the history
High-res scrolling support for trackball
  • Loading branch information
mondalaci authored Nov 1, 2024
2 parents f7f12a8 + 084c808 commit 173a828
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 23 deletions.
2 changes: 1 addition & 1 deletion lib/agent
Submodule agent updated 110 files
1 change: 1 addition & 0 deletions right/src/mouse_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@ static void processModuleKineticState(
break;
}
case NavigationMode_Scroll: {
speed *= UsbMouseScrollMultiplier;
if (!moduleConfiguration->scrollAxisLock) {
float xIntegerPart;
float yIntegerPart;
Expand Down
11 changes: 6 additions & 5 deletions right/src/mouse_keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,12 @@ void MouseKeys_ActivateDirectionSigns(uint8_t state) {

static void processMouseKineticState(mouse_kinetic_state_t *kineticState)
{
float initialSpeed = kineticState->intMultiplier * kineticState->initialSpeed;
float acceleration = kineticState->intMultiplier * kineticState->acceleration;
float deceleratedSpeed = kineticState->intMultiplier * kineticState->deceleratedSpeed;
float baseSpeed = kineticState->intMultiplier * kineticState->baseSpeed;
float acceleratedSpeed = kineticState->intMultiplier * kineticState->acceleratedSpeed;
int16_t scrollMultiplier = kineticState->isScroll ? UsbMouseScrollMultiplier : 1;
float initialSpeed = scrollMultiplier * kineticState->intMultiplier * kineticState->initialSpeed;
float acceleration = scrollMultiplier * kineticState->intMultiplier * kineticState->acceleration;
float deceleratedSpeed = scrollMultiplier * kineticState->intMultiplier * kineticState->deceleratedSpeed;
float baseSpeed = scrollMultiplier * kineticState->intMultiplier * kineticState->baseSpeed;
float acceleratedSpeed = scrollMultiplier * kineticState->intMultiplier * kineticState->acceleratedSpeed;

if (!kineticState->wasMoveAction && !ActiveMouseStates[SerializedMouseAction_Decelerate]) {
kineticState->currentSpeed = initialSpeed;
Expand Down
45 changes: 31 additions & 14 deletions right/src/usb_descriptors/usb_descriptor_mouse_report.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
#define USB_MOUSE_REPORT_DESCRIPTOR_MAX_AXIS_PHYSICAL_VALUE 4096
#define USB_MOUSE_REPORT_DESCRIPTOR_BUTTONS 20

#define USB_MOUSE_REPORT_DESCRIPTOR_MIN_RESOLUTION_MULTIPLIER_PHYSICAL_VALUE 1
#define USB_MOUSE_REPORT_DESCRIPTOR_MAX_RESOLUTION_MULTIPLIER_PHYSICAL_VALUE 120

#define USB_MOUSE_REPORT_DESCRIPTOR_BUTTONS_PADDING ((USB_MOUSE_REPORT_DESCRIPTOR_BUTTONS % 8) \
? (8 - (USB_MOUSE_REPORT_DESCRIPTOR_BUTTONS % 8)) \
: 0)
Expand Down Expand Up @@ -57,29 +60,43 @@

HID_RI_COLLECTION(8, HID_RI_COLLECTION_LOGICAL),

// Scroll wheels

// Resolution multiplier for high-res scroll support
// To have a multiplier apply to a wheel, it must be in the
// same logical collection as the wheel, or else there must
// be no logical collections (according to the USB HID spec);
// so to have a single multiplier apply to the two wheels,
// they must be in the same logical collection (or there
// must be no logical collection at all)
HID_RI_USAGE(8, HID_RI_USAGE_GENERIC_DESKTOP_RESOLUTION_MULTIPLIER),
HID_RI_LOGICAL_MINIMUM(8, 0),
HID_RI_LOGICAL_MAXIMUM(8, 1),
HID_RI_PHYSICAL_MINIMUM(8, USB_MOUSE_REPORT_DESCRIPTOR_MIN_RESOLUTION_MULTIPLIER_PHYSICAL_VALUE),
HID_RI_PHYSICAL_MAXIMUM(8, USB_MOUSE_REPORT_DESCRIPTOR_MAX_RESOLUTION_MULTIPLIER_PHYSICAL_VALUE),
HID_RI_REPORT_COUNT(8, 1),
HID_RI_REPORT_SIZE(8, 8),
HID_RI_FEATURE(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),

// Vertical wheel
HID_RI_USAGE(8, HID_RI_USAGE_GENERIC_DESKTOP_WHEEL),
HID_RI_LOGICAL_MINIMUM(8, -127),
HID_RI_LOGICAL_MAXIMUM(8, 127),
HID_RI_PHYSICAL_MINIMUM(16, -127),
HID_RI_PHYSICAL_MAXIMUM(16, 127),
HID_RI_LOGICAL_MINIMUM(16, -32767),
HID_RI_LOGICAL_MAXIMUM(16, 32767),
HID_RI_PHYSICAL_MINIMUM(16, -32767),
HID_RI_PHYSICAL_MAXIMUM(16, 32767),
HID_RI_REPORT_COUNT(8, 1),
HID_RI_REPORT_SIZE(8, 8),
HID_RI_REPORT_SIZE(8, 16),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),

HID_RI_END_COLLECTION(0),

HID_RI_COLLECTION(8, HID_RI_COLLECTION_LOGICAL),

// Horizontal wheel
HID_RI_USAGE_PAGE(8, HID_RI_USAGE_PAGE_CONSUMER),
HID_RI_USAGE(16, HID_RI_USAGE_CONSUMER_AC_PAN),
HID_RI_LOGICAL_MINIMUM(8, -127),
HID_RI_LOGICAL_MAXIMUM(8, 127),
HID_RI_PHYSICAL_MINIMUM(16, -127),
HID_RI_PHYSICAL_MAXIMUM(16, 127),
HID_RI_LOGICAL_MINIMUM(16, -32767),
HID_RI_LOGICAL_MAXIMUM(16, 32767),
HID_RI_PHYSICAL_MINIMUM(16, -32767),
HID_RI_PHYSICAL_MAXIMUM(16, 32767),
HID_RI_REPORT_COUNT(8, 1),
HID_RI_REPORT_SIZE(8, 8),
HID_RI_REPORT_SIZE(8, 16),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),

HID_RI_END_COLLECTION(0),
Expand Down
48 changes: 47 additions & 1 deletion right/src/usb_interfaces/usb_interface_mouse.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
#include "usb_composite_device.h"
#include "usb_report_updater.h"
#include "usb_descriptors/usb_descriptor_mouse_report.h"

static usb_mouse_report_t usbMouseReports[2];
static uint8_t usbMouseFeatBuffer[USB_MOUSE_FEAT_REPORT_LENGTH];
usb_hid_protocol_t usbMouseProtocol;
uint32_t UsbMouseActionCounter;
usb_mouse_report_t* ActiveUsbMouseReport = usbMouseReports;

int16_t UsbMouseScrollMultiplier = USB_MOUSE_REPORT_DESCRIPTOR_MIN_RESOLUTION_MULTIPLIER_PHYSICAL_VALUE;

static usb_mouse_report_t* GetInactiveUsbMouseReport(void)
{
return ActiveUsbMouseReport == usbMouseReports ? usbMouseReports+1 : usbMouseReports;
Expand Down Expand Up @@ -90,17 +94,59 @@ usb_status_t UsbMouseCallback(class_handle_t handle, uint32_t event, void *param

case kUSB_DeviceHidEventGetReport: {
usb_device_hid_report_struct_t *report = (usb_device_hid_report_struct_t*)param;
if (report->reportType == USB_DEVICE_HID_REQUEST_GET_REPORT_TYPE_INPUT && report->reportId == 0 && report->reportLength <= USB_MOUSE_REPORT_LENGTH) {
if (report->reportId != 0) {
error = kStatus_USB_InvalidRequest;
} else if (report->reportType == USB_DEVICE_HID_REQUEST_GET_REPORT_TYPE_INPUT && report->reportLength <= USB_MOUSE_REPORT_LENGTH) {
report->reportBuffer = (void*)ActiveUsbMouseReport;
UsbMouseActionCounter++;
SwitchActiveUsbMouseReport();
error = kStatus_USB_Success;
} else if (report->reportType == USB_DEVICE_HID_REQUEST_GET_REPORT_TYPE_FEATURE) {
usbMouseFeatBuffer[0] = (uint8_t)(UsbMouseScrollMultiplier != USB_MOUSE_REPORT_DESCRIPTOR_MIN_RESOLUTION_MULTIPLIER_PHYSICAL_VALUE);
report->reportBuffer = usbMouseFeatBuffer;
report->reportLength = sizeof(usbMouseFeatBuffer);
error = kStatus_USB_Success;
} else {
error = kStatus_USB_InvalidRequest;
}
break;
}

case kUSB_DeviceHidEventSetReport: {
usb_device_hid_report_struct_t *report = (usb_device_hid_report_struct_t*)param;
if (report->reportType == USB_DEVICE_HID_REQUEST_GET_REPORT_TYPE_FEATURE && report->reportId == 0 && report->reportLength <= sizeof(usbMouseFeatBuffer)) {
// With a single resolution multiplier, this case will never be
// hit on Linux (for multiple resolution multipliers, one value
// will be missing, so would have to be inferred from the
// other(s)). But Windows does use this request properly, so it
// needs to be handled appropriately.
UsbMouseScrollMultiplier = usbMouseFeatBuffer[0] ? USB_MOUSE_REPORT_DESCRIPTOR_MAX_RESOLUTION_MULTIPLIER_PHYSICAL_VALUE : USB_MOUSE_REPORT_DESCRIPTOR_MIN_RESOLUTION_MULTIPLIER_PHYSICAL_VALUE;
error = kStatus_USB_Success;
} else {
error = kStatus_USB_InvalidRequest;
}
break;
}

case kUSB_DeviceHidEventRequestReportBuffer: {
usb_device_hid_report_struct_t *report = (usb_device_hid_report_struct_t*)param;
if (report->reportType == USB_DEVICE_HID_REQUEST_GET_REPORT_TYPE_FEATURE && report->reportId == 0 && report->reportLength <= sizeof(usbMouseFeatBuffer)) {
// The Linux implementation of SetReport when initializing a
// device with a single resolution multiplier value is broken,
// sending an empty report, and as a result the
// kUSB_DeviceHidEventSetReport case above isn't triggered at
// all; but it only sends this report when it detects the
// resolution multiplier, and the intention is to activate the
// feature, so turn high-res mode on here.
UsbMouseScrollMultiplier = USB_MOUSE_REPORT_DESCRIPTOR_MAX_RESOLUTION_MULTIPLIER_PHYSICAL_VALUE;
report->reportBuffer = usbMouseFeatBuffer;
error = kStatus_USB_Success;
} else {
error = kStatus_USB_AllocFail;
}
break;
}

case kUSB_DeviceHidEventSetProtocol: {
uint8_t report = *(uint16_t*)param;
if (report <= 1) {
Expand Down
6 changes: 4 additions & 2 deletions right/src/usb_interfaces/usb_interface_mouse.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define USB_MOUSE_INTERRUPT_IN_INTERVAL 1

#define USB_MOUSE_REPORT_LENGTH (sizeof(usb_mouse_report_t))
#define USB_MOUSE_FEAT_REPORT_LENGTH 1

// Typedefs:

Expand All @@ -31,12 +32,13 @@
uint32_t buttons : 24;
int16_t x;
int16_t y;
int8_t wheelY;
int8_t wheelX;
int16_t wheelY;
int16_t wheelX;
} ATTR_PACKED usb_mouse_report_t;

// Variables:

extern int16_t UsbMouseScrollMultiplier;
extern uint32_t UsbMouseActionCounter;
extern usb_mouse_report_t* ActiveUsbMouseReport;

Expand Down

0 comments on commit 173a828

Please sign in to comment.