Skip to content

Commit c0b549f

Browse files
committed
Make XI2 scroll offset type detection more robust
Since we have to use heuristics, lets at least collect stats for a few events before deciding.
1 parent 99639f1 commit c0b549f

3 files changed

Lines changed: 37 additions & 15 deletions

File tree

glfw/x11_init.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,12 @@ read_xi_scroll_devices(void) {
216216
if (_glfw.x11.xi.num_scroll_devices >= arraysz(_glfw.x11.xi.scroll_devices)) continue;
217217
d = &_glfw.x11.xi.scroll_devices[_glfw.x11.xi.num_scroll_devices++];
218218
*d = (XIScrollDevice){
219-
.is_highres=is_highres, .is_finger_based=is_finger_based, .deviceid=device->deviceid, .sourceid=scroll->sourceid,
219+
.is_finger_based=is_finger_based, .deviceid=device->deviceid, .sourceid=scroll->sourceid,
220220
};
221+
if (is_highres) {
222+
d->type_detected = true;
223+
d->offset_type = GLFW_SCROLL_OFFEST_HIGHRES;
224+
}
221225
memcpy(d->name, device->name, MIN(sizeof(d->name)-1, strlen(device->name)));
222226
}
223227
if (d->num_valuators >= arraysz(d->valuators)) continue;

glfw/x11_platform.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,14 @@ typedef struct XIScrollValuator {
239239
} XIScrollValuator;
240240

241241
typedef struct XIScrollDevice {
242-
bool is_highres;
243242
bool is_finger_based;
243+
bool type_detected;
244244
int deviceid, sourceid;
245245
XIScrollValuator valuators[8];
246246
unsigned num_valuators;
247247
char name[32];
248+
unsigned num_events;
249+
GLFWOffsetType offset_type;
248250
} XIScrollDevice;
249251

250252
typedef struct XdndSelectionRequest {

glfw/x11_window.c

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,6 +1415,11 @@ handle_mouse_move_event(_GLFWwindow *window, const int x, const int y) {
14151415
window->x11.lastCursorPosY = y;
14161416
}
14171417

1418+
static bool
1419+
number_has_fractional_part(double x) {
1420+
return fabs(x - round(x)) >= 1e-6;
1421+
}
1422+
14181423
static void
14191424
handle_xi_motion_event(_GLFWwindow *window, XIDeviceEvent *de) {
14201425
XIScrollDevice *d = NULL;
@@ -1442,24 +1447,35 @@ handle_xi_motion_event(_GLFWwindow *window, XIDeviceEvent *de) {
14421447
scroll_valuator_found = true;
14431448
double delta = value - v->value;
14441449
v->value = value;
1445-
if (v->is_vertical) delta *= -1;
1450+
delta *= -1;
14461451
double *off = v->is_vertical ? &yOffset : &xOffset;
14471452
*off = delta;
1448-
if (!d->is_highres) {
1449-
if (v->increment == 120.) type = GLFW_SCROLL_OFFEST_V120;
1450-
else {
1451-
// XInput2 has no reliable way to distinguish high res scroll devices so we
1452-
// assume that if fractional values are seen it must be high res. Sigh, Linux, the
1453-
// land of truly wondrous wonders. See https://github.com/kovidgoyal/kitty/issues/9649
1454-
double int_part; bool delta_is_fractional = modf(delta, &int_part) != 0.;
1455-
if (delta_is_fractional) d->is_highres = true;
1456-
else {
1457-
type = GLFW_SCROLL_OFFSET_LINES;
1458-
if (v->increment != 0) *off /= v->increment;
1453+
d->num_events++;
1454+
if (!d->type_detected) {
1455+
if (v->increment == 120.) {
1456+
d->type_detected = true;
1457+
d->offset_type = GLFW_SCROLL_OFFEST_V120;
1458+
} else {
1459+
bool delta_is_fractional = number_has_fractional_part(delta);
1460+
if (delta_is_fractional) {
1461+
if (fabs(delta * 120 - round(delta * 120)) < 0.01) {
1462+
d->type_detected = d->num_events > 2;
1463+
d->offset_type = GLFW_SCROLL_OFFEST_V120;
1464+
} else {
1465+
d->type_detected = true;
1466+
d->offset_type = GLFW_SCROLL_OFFEST_HIGHRES;
1467+
}
1468+
} else {
1469+
d->type_detected = d->num_events > 2;
1470+
d->offset_type = GLFW_SCROLL_OFFSET_LINES;
14591471
}
14601472
}
14611473
}
1474+
if (d->offset_type == GLFW_SCROLL_OFFSET_LINES) {
1475+
if (v->increment != 0) *off /= v->increment;
1476+
}
14621477
}
1478+
type = d->offset_type;
14631479
if (xOffset != 0 || yOffset != 0) {
14641480
// Get keyboard modifiers
14651481
int mods = translateState(de->mods.effective);
@@ -1473,7 +1489,7 @@ handle_xi_motion_event(_GLFWwindow *window, XIDeviceEvent *de) {
14731489
};
14741490

14751491
// For high-resolution, finger-based scrolling, use timer-based momentum scrolling
1476-
if (d->is_highres && d->is_finger_based && type == GLFW_SCROLL_OFFEST_HIGHRES) {
1492+
if (d->is_finger_based && type == GLFW_SCROLL_OFFEST_HIGHRES) {
14771493
// Reset the timer on each scroll event
14781494
x11_cancel_momentum_scroll_timer();
14791495

0 commit comments

Comments
 (0)