editor.inertialScroll misclassifies high-resolution mouse wheels as touchpads
- 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
Assessment
This issue has not been assessed yet.