fix(apple/cursor): disable the client-side cursor (gamescope traps input)

The client-side cursor positions the host pointer with ABSOLUTE events, but
gamescope's input socket (EIS) grants only a relative pointer — the host drops the
absolute events (libei.rs: no PointerAbsolute → not emitted), so the pointer never
moves and clicks/scroll land on the stuck position. Auto-mode enabled exactly this on
gamescope, making all input appear dead until toggled off.

Force `cursorVisible = false`, neuter the ⌘⇧C toggle, and hide the now-inert Settings
picker. The resolution logic + handlers are kept (commented) for when per-compositor
gating (KWin/GNOME/Sway have an absolute pointer) or a synthetic-cursor-over-relative
path lands. Relative capture (the working path) is now always used.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-14 17:14:57 +00:00
parent 5b5749c6d2
commit 0c8bee8d1f
2 changed files with 16 additions and 31 deletions
@@ -18,7 +18,6 @@ struct SettingsView: View {
@AppStorage(DefaultsKey.gamepadType) private var gamepadType = 0
@AppStorage(DefaultsKey.bitrateKbps) private var bitrateKbps = 0
@AppStorage(DefaultsKey.presenter) private var presenter = "stage1"
@AppStorage(DefaultsKey.cursorMode) private var cursorMode = "auto"
@AppStorage(DefaultsKey.libraryEnabled) private var libraryEnabled = false
@AppStorage(DefaultsKey.fullscreenWhileStreaming) private var fullscreenWhileStreaming = true
@AppStorage(DefaultsKey.micEnabled) private var micEnabled = true
@@ -385,22 +384,9 @@ struct SettingsView: View {
.font(.caption)
.foregroundStyle(.secondary)
}
Section {
Picker("Cursor in stream", selection: $cursorMode) {
Text("Auto (gamescope)").tag("auto")
Text("Always").tag("always")
Text("Never").tag("never")
}
} header: {
Text("Cursor")
} footer: {
Text("Show the local system cursor over the stream instead of capturing it. "
+ "gamescope's capture carries no cursor, so the client draws its own — "
+ "Auto turns this on only for gamescope sessions. ⌘⇧C toggles it live "
+ "during a session.")
.font(.caption)
.foregroundStyle(.secondary)
}
// The client-side cursor picker is hidden while the feature is disabled (gamescope's
// input is relative-only, so absolute cursor positioning traps input see StreamView).
// Restore this Section when per-compositor gating / a synthetic cursor lands.
#endif
Section {
Picker("Presenter", selection: $presenter) {