You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -620,9 +620,10 @@ Go; only the final injection primitive differs:
620
620
| Linux Wayland KDE | libei via `org.freedesktop.portal.RemoteDesktop`|
621
621
| Windows |`SendInput` / `SetCursorPos`|
622
622
623
-
**The one behavioral difference:** Windows `ScrollAtCursor` ignores `deltaX`, so
624
-
horizontal scrolling is a no-op there. Everything else behaves the same on all
625
-
three platforms.
623
+
Scrolling behaves the same on all three platforms, both axes included: Windows
624
+
posts `MOUSEEVENTF_HWHEEL` for the horizontal component, with the sign flipped
625
+
because Win32 reads a positive horizontal notch as right where Neru, macOS and
626
+
X11 read it as left.
626
627
627
628
**Modifiers on a scroll** reach the injection primitive by two different routes,
628
629
because only one of the primitives has a field for them. macOS stamps
@@ -1105,8 +1106,6 @@ green in every cell while an option means nothing, which is exactly how
1105
1106
|`smooth_scroll.duration_per_pixel`| option | ✅ | ✅ | ❌ | the Windows scroll is injected in one step; macOS and Linux animate it, and on X11 the steps are whole wheel notches because X has no smaller scroll to send |
1106
1107
|`hide_cursor`| action | ✅ | ❌ | ❌ | a Wayland client may not hide another client's cursor, and the blessed Linux stack is Wayland; Windows has no equivalent either |
1107
1108
|`show_cursor`| action | ✅ | ❌ | ❌ | a Wayland client may not hide another client's cursor, and the blessed Linux stack is Wayland; Windows has no equivalent either |
1108
-
|`scroll_left`| action | ✅ | ✅ | ❌ | the Windows wheel event carries no horizontal delta, so a sideways scroll injects nothing |
1109
-
|`scroll_right`| action | ✅ | ✅ | ❌ | the Windows wheel event carries no horizontal delta, so a sideways scroll injects nothing |
1110
1109
|`feed`| action | ✅ | ✅ | ❌ | Windows has no key-injection path yet, so the key it would post is never sent; the key_feed capability reports stub to match |
1111
1110
1112
1111
<!-- END GENERATED PLATFORM SUPPORT -->
@@ -1208,12 +1207,11 @@ working, which is exactly why the build exists.
1208
1207
it stays declared everywhere and is tracked as this entry instead
1209
1208
4. Smooth cursor and smooth scroll animation — not implemented
1210
1209
5. Modifier passthrough and `PostModifierEvent` — no-ops
Copy file name to clipboardExpand all lines: internal/adapter/platform/AGENTS.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@ The One Rule (root `AGENTS.md`) is enforced here hardest: non-darwin-tagged code
5
5
-**Start at `profile.go`** — source of truth for each subsystem's backend family and whether a backend needs CGO (a per-backend decision, not per-OS).
6
6
-**File slots** — use the existing slot, never invent layout: `*_darwin.go`, `*_windows.go`, `*_linux.go`, `*_other.go` (non-target fallback), `*_linux_common.go`, `*_linux_x11.go`, `*_linux_wayland.go`, `*_linux_wayland_<compositor>.go`. Inside a directory that is already one platform (`platform/linux/`, `overlay/linux/`, …) the OS token is dropped, because the directory carries it: `system_x11_cgo.go`, not `system_linux_x11_cgo.go`. `docs/CROSS_PLATFORM.md` ("File Layout Rules") owns the table and what each slot holds today; `internal/architecture/platform_slots_test.go` is what fails.
7
7
-**Factory** — `factory.go` + build-tagged siblings are the only place that picks a `ports.SystemPort`. Linux adds a runtime axis: `backend_linux.go` detects the live compositor (wlroots / KDE / GNOME / other) and owns what is named after it — `IsWayland`, the `display_server` label; never probe the compositor elsewhere, ask `DetectLinuxBackend`. `internal/architecture/compositor_detector_test.go` pins that by confining the desktop-identity variables (`XDG_CURRENT_DESKTOP`, `XDG_SESSION_TYPE`, …) to that file. The wlroots socket trio (`SWAYSOCK`, `NIRI_SOCKET`, `HYPRLAND_INSTANCE_SIGNATURE`) answers a question the backend enum cannot — which compositor CLI to shell out to — so it stays readable, but only downstream of the backend and never as a way to decide it; `internal/architecture/compositor_socket_test.go` pins that and lists the files entitled to read it.
8
-
- **Stubs are loud** — return `derrors.CodeNotSupported`, never a silent no-op, whenever the signature has an error to carry it. A `bool` answer has none, and `true` is not a silent no-op: `SystemPort.CheckScreenCapturePermission` and `platform.CheckAccessibilityPermissions` report "this platform has no such gate" where there is none, which `ports/system.go` specifies — and where there *is* one they report it, so that bool is a live consent state on macOS and on Linux's `wayland-kde`, whose portal ScreenCast grant is the only way to read a KWin screen — making them loud would re-prompt forever for a consent that is already granted. Contract tests pin the loudness per subsystem, not for every stub in the tree; each lives beside the stub it pins as `*stub_contract*_test.go`. The ones that exist are `platform/linux/system_stub_contract_test.go`, `overlay/linux/stub_contract_test.go`, `eventtap/linux/global_hotkey_stub_contract_nocgo_test.go`, `vision/adapter_stub_contract_other_test.go` and its Linux and Windows siblings `vision/adapter_stub_contract_linux_test.go` and `vision/adapter_stub_contract_windows_test.go` (the port is implemented there, so those files pin the *shape* of every answer rather than a refusal — capture and recognition each return a result or a reason, never neither and never both; on Windows the one `CodeNotSupported` recognition may answer with is a missing OCR language pack, and it has to say so), `scroll_modifier_stub_contract_test.go` and `scroll_stub_contract_nocgo_test.go` in `accessibility/native/linux` (the first of those also in `accessibility/native/windows`), and `overlay_stub_contract_other_test.go` in each of `overlay/render/{grid,hints,modeindicator}`. The nocgo one is worth reading before adding a background path anywhere: it pins that `smooth_scroll` cannot turn a loud `CodeNotSupported` into silence, because the backend is detected from the environment and says nothing about whether this build can inject. Write a new one when a caller could read the stub's `nil` as success. Keep `ports/capabilities.go` / `capability_presets.go` honest: a stub reports `stub`, not `supported` (`neru doctor` reports this matrix).
8
+
- **Stubs are loud** — return `derrors.CodeNotSupported`, never a silent no-op, whenever the signature has an error to carry it. A `bool` answer has none, and `true` is not a silent no-op: `SystemPort.CheckScreenCapturePermission` and `platform.CheckAccessibilityPermissions` report "this platform has no such gate" where there is none, which `ports/system.go` specifies — and where there *is* one they report it, so that bool is a live consent state on macOS and on Linux's `wayland-kde`, whose portal ScreenCast grant is the only way to read a KWin screen — making them loud would re-prompt forever for a consent that is already granted. Contract tests pin the loudness per subsystem, not for every stub in the tree; each lives beside the stub it pins as `*stub_contract*_test.go`. The ones that exist are `platform/linux/system_stub_contract_test.go`, `overlay/linux/stub_contract_test.go`, `eventtap/linux/global_hotkey_stub_contract_nocgo_test.go`, `vision/adapter_stub_contract_other_test.go` and its Linux and Windows siblings `vision/adapter_stub_contract_linux_test.go` and `vision/adapter_stub_contract_windows_test.go` (the port is implemented there, so those files pin the *shape* of every answer rather than a refusal — capture and recognition each return a result or a reason, never neither and never both; on Windows the one `CodeNotSupported` recognition may answer with is a missing OCR language pack, and it has to say so), `scroll_modifier_stub_contract_test.go` and `scroll_stub_contract_nocgo_test.go` in `accessibility/native/linux`, and `overlay_stub_contract_other_test.go` in each of `overlay/render/{grid,hints,modeindicator}`. The nocgo one is worth reading before adding a background path anywhere: it pins that `smooth_scroll` cannot turn a loud `CodeNotSupported` into silence, because the backend is detected from the environment and says nothing about whether this build can inject. Write a new one when a caller could read the stub's `nil` as success. Keep `ports/capabilities.go` / `capability_presets.go` honest: a stub reports `stub`, not `supported` (`neru doctor` reports this matrix).
9
9
-**Coordinates** — shared code is global top-left origin, Y down, unscaled pixels. Cocoa's bottom-left flip happens inside the darwin adapter, open-coded at each site that needs it rather than in one file; the whole of what the rule buys is that no flipped value reaches shared Go. `docs/ARCHITECTURE.md` ("Coordinate System") owns the detail, including which packages are *not* where a flip lives.
10
10
-**`linux/wlr_protocol/` is generated** (`just generate-all-protocols`); never hand-edit.
0 commit comments