Summary
Scrolling arrives inverted on a macOS client. The macOS emulation backend passes the Wayland axis value straight into CGEvent::new_scroll_event without accounting for the opposite sign convention between the two platforms.
- Wayland (
wl_pointer::Event::Axis): positive = scroll down
- macOS
CGEvent scroll wheel: positive = scroll up
Environment
|
|
| lan-mouse |
0.11.0 |
| server (capture) |
Linux, Hyprland, layer-shell capture backend |
| client (emulation) |
macOS, macos emulation backend |
Where
input-emulation/src/macos.rs, both scroll arms:
PointerEvent::Axis { time: _, axis, value } => {
let value = value as i32;
let (count, wheel1, wheel2, wheel3) = match axis {
0 => (1, value, 0, 0), // vertical
1 => (2, 0, value, 0), // horizontal
...
};
let event = match CGEvent::new_scroll_event(
self.event_source.clone(),
ScrollEventUnit::PIXEL,
count, wheel1, wheel2, wheel3,
) { ... }
}
and the same pattern immediately below in PointerEvent::AxisDiscrete120. Neither negates value, so both paths are affected, not just one.
Reproduction
- Linux server (Hyprland/layer-shell) with a macOS client
- Cross to the macOS client and scroll the wheel
- Content scrolls in the opposite direction to the same gesture on the server
Notes that may save someone else time
- macOS "Natural scrolling" has no effect on this. That preference is applied to real HID devices; synthetic
CGEvents bypass it. So it cannot be worked around from macOS System Settings, in either position.
- The mouse in question emits both
REL_WHEEL and REL_WHEEL_HI_RES, and the inversion is present regardless of which path is taken.
Suggested fix
Negate the value in input-emulation/src/macos.rs for both arms, so the sign conversion lives with the platform whose convention differs.
I'm currently working around it downstream by negating on the capture side instead, which is obviously wrong in general (it would break non-macOS clients, and it will silently double-negate once this is fixed upstream). Happy to open a PR against macos.rs if the approach above looks right to you.
Summary
Scrolling arrives inverted on a macOS client. The macOS emulation backend passes the Wayland axis value straight into
CGEvent::new_scroll_eventwithout accounting for the opposite sign convention between the two platforms.wl_pointer::Event::Axis): positive = scroll downCGEventscroll wheel: positive = scroll upEnvironment
layer-shellcapture backendmacosemulation backendWhere
input-emulation/src/macos.rs, both scroll arms:and the same pattern immediately below in
PointerEvent::AxisDiscrete120. Neither negatesvalue, so both paths are affected, not just one.Reproduction
Notes that may save someone else time
CGEvents bypass it. So it cannot be worked around from macOS System Settings, in either position.REL_WHEELandREL_WHEEL_HI_RES, and the inversion is present regardless of which path is taken.Suggested fix
Negate the value in
input-emulation/src/macos.rsfor both arms, so the sign conversion lives with the platform whose convention differs.I'm currently working around it downstream by negating on the capture side instead, which is obviously wrong in general (it would break non-macOS clients, and it will silently double-negate once this is fixed upstream). Happy to open a PR against
macos.rsif the approach above looks right to you.