microsoft / microsoft/vscode

editor.inertialScroll misclassifies high-resolution mouse wheels as touchpads

Open
#325,859 1 comment 1 reaction 1 assignee Claimed by @alexdima View on GitHub
Dominant language
TypeScript
Stars
193k
Forks
42.4k
PR merge metrics
PR metrics pending

Description

Does this issue occur when all extensions are disabled?: Yes

- VS Code Version: current main, 1.129.0 (`e2c0ad9ffc1`)
- OS Version: NixOS 26.11, Linux 7.1.3, GNOME Wayland
- Input device: Logitech MX Master with high-resolution scrolling

Steps to Reproduce:

1. Set `"editor.inertialScroll": true`.
2. Scroll an editor using a high-resolution mouse wheel.
3. Stop moving the wheel.

Expected: scrolling stops with the physical wheel.

Actual: VS Code classifies the wheel as touchpad-like and adds synthetic inertia.

A representative physical-wheel gesture produces fractional deltas such as:

```text
-0.533333, -0.2, -0.2, ..., -0.133333, -0.2
```

`MouseWheelClassifier` treats non-integral deltas as touchpad evidence. Its modulo check also clamps sub-unit values to `1`, so repeated values such as `0.2` are not recognized as physical-wheel input.

## Technical details

1. Why Wayland is different and requires a synthetic scrolling in the first place?

TL;DR: MacOS and Windows implement kinetic scrolling by synthesizing fake scroll events on the OS level. Wayland, instead, relies on the app to implement inertia on receiving `wl_pointer.axis_stop`. Chromium does this natively, but only for native overflow elements (that's why some panels in vscode have proper scrolling).

See also: #201937, #244034 and #205122.

2. A general heuristic for telling apart a touchpad and a hi-res scrolling wheel is impossible to implement by definition.

3. A possible solution could be using proper native scrollable areas, but this would affect scrollbar rendering, scroll state, nested scrolling, and existing `ScrollableElement` contracts.
Note: just avoiding `preventDefault()` (see https://github.com/microsoft/vscode/issues/201937#issuecomment-1911613531) wouldn't be enough.

4. A possible solution could be handling proper fling events from Electron (`gestureFlingStart` and `gestureFlingCancel`), but they're main process only.

## Side note

The current emulated inertia has other problems:
1. It's uses a ~60Hz timer, so on high refresh rate displays it looks laggy.
2. It doesn't handle the [hold gesture](https://wayland.freedesktop.org/libinput/doc/latest/gestures.html#hold-gestures) for cancelling the scrolling.
3. It's only implemented for the editor, so e.g. the Explorer sidebar doesn't have kinetic scrolling.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.