Handle mouse integer scrolling locally

Do not rely on SDL to expose integer scroll values, as they are not
available in all versions.

It was reimplemented in SDL 3.2.12 by this commit:
<0447c2f3c3>

Refs #6156 <https://github.com/Genymobile/scrcpy/issues/6156>
This commit is contained in:
Romain Vimont 2025-06-29 18:22:46 +02:00
commit 78c4674d97
9 changed files with 49 additions and 16 deletions

View file

@ -166,6 +166,12 @@ sc_hid_buttons_from_buttons_state(uint8_t buttons_state) {
return c; return c;
} }
void
sc_hid_mouse_init(struct sc_hid_mouse *hid) {
hid->residual_hscroll = 0;
hid->residual_vscroll = 0;
}
void void
sc_hid_mouse_generate_input_from_motion(struct sc_hid_input *hid_input, sc_hid_mouse_generate_input_from_motion(struct sc_hid_input *hid_input,
const struct sc_mouse_motion_event *event) { const struct sc_mouse_motion_event *event) {
@ -192,22 +198,37 @@ sc_hid_mouse_generate_input_from_click(struct sc_hid_input *hid_input,
data[4] = 0; // no horizontal scrolling data[4] = 0; // no horizontal scrolling
} }
static int8_t
consume_scroll_integer(float *scroll) {
float value = CLAMP(*scroll, -127, 127);
int8_t consume = value; // truncate towards 0
float residual = value - consume;
*scroll = residual;
return consume;
}
bool bool
sc_hid_mouse_generate_input_from_scroll(struct sc_hid_input *hid_input, sc_hid_mouse_generate_input_from_scroll(struct sc_hid_mouse *hid,
struct sc_hid_input *hid_input,
const struct sc_mouse_scroll_event *event) { const struct sc_mouse_scroll_event *event) {
if (!event->vscroll_int && !event->hscroll_int) { sc_hid_mouse_input_init(hid_input);
// Need a full integral value for HID
hid->residual_hscroll += event->hscroll;
hid->residual_vscroll += event->vscroll;
int8_t hscroll = consume_scroll_integer(&hid->residual_hscroll);
int8_t vscroll = consume_scroll_integer(&hid->residual_vscroll);
if (!hscroll && !vscroll) {
// Not enough scrolling to inject a scroll event
return false; return false;
} }
sc_hid_mouse_input_init(hid_input);
uint8_t *data = hid_input->data; uint8_t *data = hid_input->data;
data[0] = 0; // buttons state irrelevant (and unknown) data[0] = 0; // buttons state irrelevant (and unknown)
data[1] = 0; // no x motion data[1] = 0; // no x motion
data[2] = 0; // no y motion data[2] = 0; // no y motion
data[3] = CLAMP(event->vscroll_int, -127, 127); data[3] = vscroll;
data[4] = CLAMP(event->hscroll_int, -127, 127); data[4] = hscroll;
return true; return true;
} }

View file

@ -8,6 +8,13 @@
#define SC_HID_ID_MOUSE 2 #define SC_HID_ID_MOUSE 2
struct sc_hid_mouse {
float residual_hscroll;
float residual_vscroll;
};
void sc_hid_mouse_init(struct sc_hid_mouse *hid);
void void
sc_hid_mouse_generate_open(struct sc_hid_open *hid_open); sc_hid_mouse_generate_open(struct sc_hid_open *hid_open);
@ -23,7 +30,8 @@ sc_hid_mouse_generate_input_from_click(struct sc_hid_input *hid_input,
const struct sc_mouse_click_event *event); const struct sc_mouse_click_event *event);
bool bool
sc_hid_mouse_generate_input_from_scroll(struct sc_hid_input *hid_input, sc_hid_mouse_generate_input_from_scroll(struct sc_hid_mouse *hid,
struct sc_hid_input *hid_input,
const struct sc_mouse_scroll_event *event); const struct sc_mouse_scroll_event *event);
#endif #endif

View file

@ -393,8 +393,6 @@ struct sc_mouse_scroll_event {
struct sc_position position; struct sc_position position;
float hscroll; float hscroll;
float vscroll; float vscroll;
int32_t hscroll_int;
int32_t vscroll_int;
uint8_t buttons_state; // bitwise-OR of sc_mouse_button values uint8_t buttons_state; // bitwise-OR of sc_mouse_button values
}; };

View file

@ -903,8 +903,6 @@ sc_input_manager_process_mouse_wheel(struct sc_input_manager *im,
.hscroll = event->x, .hscroll = event->x,
.vscroll = event->y, .vscroll = event->y,
#endif #endif
.hscroll_int = event->x,
.vscroll_int = event->y,
.buttons_state = im->mouse_buttons_state, .buttons_state = im->mouse_buttons_state,
}; };

View file

@ -55,7 +55,8 @@ sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
struct sc_mouse_uhid *mouse = DOWNCAST(mp); struct sc_mouse_uhid *mouse = DOWNCAST(mp);
struct sc_hid_input hid_input; struct sc_hid_input hid_input;
if (!sc_hid_mouse_generate_input_from_scroll(&hid_input, event)) { if (!sc_hid_mouse_generate_input_from_scroll(&mouse->hid, &hid_input,
event)) {
return; return;
} }
@ -65,6 +66,8 @@ sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
bool bool
sc_mouse_uhid_init(struct sc_mouse_uhid *mouse, sc_mouse_uhid_init(struct sc_mouse_uhid *mouse,
struct sc_controller *controller) { struct sc_controller *controller) {
sc_hid_mouse_init(&mouse->hid);
mouse->controller = controller; mouse->controller = controller;
static const struct sc_mouse_processor_ops ops = { static const struct sc_mouse_processor_ops ops = {

View file

@ -4,11 +4,13 @@
#include <stdbool.h> #include <stdbool.h>
#include "controller.h" #include "controller.h"
#include "hid/hid_mouse.h"
#include "trait/mouse_processor.h" #include "trait/mouse_processor.h"
struct sc_mouse_uhid { struct sc_mouse_uhid {
struct sc_mouse_processor mouse_processor; // mouse processor trait struct sc_mouse_processor mouse_processor; // mouse processor trait
struct sc_hid_mouse hid;
struct sc_controller *controller; struct sc_controller *controller;
}; };

View file

@ -42,7 +42,8 @@ sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
struct sc_mouse_aoa *mouse = DOWNCAST(mp); struct sc_mouse_aoa *mouse = DOWNCAST(mp);
struct sc_hid_input hid_input; struct sc_hid_input hid_input;
if (!sc_hid_mouse_generate_input_from_scroll(&hid_input, event)) { if (!sc_hid_mouse_generate_input_from_scroll(&mouse->hid, &hid_input,
event)) {
return; return;
} }
@ -64,6 +65,8 @@ sc_mouse_aoa_init(struct sc_mouse_aoa *mouse, struct sc_aoa *aoa) {
return false; return false;
} }
sc_hid_mouse_init(&mouse->hid);
static const struct sc_mouse_processor_ops ops = { static const struct sc_mouse_processor_ops ops = {
.process_mouse_motion = sc_mouse_processor_process_mouse_motion, .process_mouse_motion = sc_mouse_processor_process_mouse_motion,
.process_mouse_click = sc_mouse_processor_process_mouse_click, .process_mouse_click = sc_mouse_processor_process_mouse_click,

View file

@ -6,11 +6,13 @@
#include <stdbool.h> #include <stdbool.h>
#include "usb/aoa_hid.h" #include "usb/aoa_hid.h"
#include "hid/hid_mouse.h"
#include "trait/mouse_processor.h" #include "trait/mouse_processor.h"
struct sc_mouse_aoa { struct sc_mouse_aoa {
struct sc_mouse_processor mouse_processor; // mouse processor trait struct sc_mouse_processor mouse_processor; // mouse processor trait
struct sc_hid_mouse hid;
struct sc_aoa *aoa; struct sc_aoa *aoa;
}; };

View file

@ -171,8 +171,6 @@ sc_screen_otg_process_mouse_wheel(struct sc_screen_otg *screen,
.hscroll = event->x, .hscroll = event->x,
.vscroll = event->y, .vscroll = event->y,
#endif #endif
.hscroll_int = event->x,
.vscroll_int = event->y,
.buttons_state = sc_mouse_buttons_state_from_sdl(sdl_buttons_state), .buttons_state = sc_mouse_buttons_state_from_sdl(sdl_buttons_state),
}; };