When the user revokes Accessibility in System Settings while Lan
Mouse is in a captured session (cursor on a remote client), the
session-level event tap receives `TapDisabledByUserInput`. The
previous flow was:
1. Callback sends `ProducerEvent::EventTapDisabled` to notify_tx.
2. Callback falls through the `current_pos.is_some()` branch and
returns `CallbackResult::Drop` — *this very event*, plus any
racing callback still in flight, get `set_type(Null)`'d and
consumed.
3. Outer task calls `handle_producer_event(..).unwrap_or_else(|e|
log::error!(..))` — the `EventTapDisabled` error is just logged,
the loop keeps running, `current_pos` stays `Some`, cursor
stays hidden.
Net effect for the user: mouse motion keeps working (pass-through
when the tap is fully dead), but clicks and keypresses in the brief
disable window silently disappear, and the cursor is still hidden
where the captured session left it. Input looks broken until the
app is force-quit.
Fix:
- In the callback, when `TapDisabled*` fires, clear `current_pos`
and `CGDisplay::show_cursor` synchronously, then return
`CallbackResult::Keep` so this event (and any subsequent racing
one) can't hit the drop branch.
- Mirror the cleanup in `handle_producer_event`'s
`EventTapDisabled` arm so even if the outer task only logs the
error, state is still released.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
On macOS the three TCC grants (Accessibility, Input Monitoring, Post
Event) live in separate Privacy panes. Before this change the
"Reenable" row sent the user to Accessibility regardless of which
grant was actually missing, and the daemon's own permission checks
re-fired the Accessibility prompt on every retry.
- lan-mouse-gtk/src/macos_privacy.rs: new module that exposes silent
preflight checks (AXIsProcessTrusted, CGPreflightListenEventAccess,
CGPreflightPostEventAccess), per-pane URL-scheme navigation, and
a Once-guarded fire_initial_prompts() called from build_ui. The
initial-prompt path only fires the Accessibility prompt if AX is
missing and then returns; secondary registrations run only after
AX is granted, which prevents a double Accessibility alert on
Sequoia where Post Event is nested under Accessibility.
- Input Monitoring registration attempts CGEventTapCreate at
kCGSessionEventTap (not kCGHIDEventTap) so a failure surfaces as
an Input Monitoring signal rather than triggering an Accessibility
prompt as a side effect.
- lan-mouse-gtk/src/window/imp.rs: handle_capture / handle_emulation
switch on the missing-pane enum and navigate to the specific pane
via x-apple.systempreferences:... URLs before re-requesting.
- lan-mouse-gtk/resources/window.ui: pill class on the Reenable
buttons so the hover padding matches the rest of libadwaita.
- input-capture/src/macos.rs, input-emulation/src/macos.rs: make
request_*_permission() a silent preflight (AXIsProcessTrusted /
CGPreflightListenEventAccess / CGPreflightPostEventAccess), so the
daemon no longer fires TCC prompts on retry — all prompting is
owned by the GUI.
- input-capture/src/error.rs, input-emulation/src/error.rs: new
error variants so the GUI can distinguish missing-AX from
missing-IM / missing-PostEvent for pane routing.
Verified on macOS 15.5: first launch fires a single AX prompt;
second launch (AX granted) registers under Input Monitoring via the
session-tap attempt and requests Post Event. Sequoia auto-grants the
listen-only path via AX so the IM list may stay empty, which is the
intended OS behavior and no longer blocks capture.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(macos): forward back/forward mouse buttons in capture and emulation
OtherMouseDown/Up events on macOS carry a button number field that
distinguishes middle (2), back (3), and forward (4) buttons. The
capture backend was unconditionally mapping all OtherMouse events to
BTN_MIDDLE, silently dropping back/forward. The emulation backend had
no match arms for BTN_BACK/BTN_FORWARD, causing them to be dropped
with a warning.
Fix capture by reading MOUSE_EVENT_BUTTON_NUMBER and mapping 3->BTN_BACK,
4->BTN_FORWARD. Fix emulation by adding match arms for BTN_BACK/BTN_FORWARD
and setting MOUSE_EVENT_BUTTON_NUMBER on the emitted CGEvent so macOS
apps receive the correct button identity.
* fix(macos): track button state and double-clicks by evdev code instead of CGMouseButton
Back, forward, and middle buttons all map to CGMouseButton::Center on
macOS, which caused them to share a single pressed-state boolean and
alias in double-click detection. Replace the ButtonState struct with a
HashSet<u32> keyed by evdev button code so each button is tracked
independently.
---------
Co-authored-by: Ferdinand Schober <ferdinandschober20@gmail.com>
* reference count capture
Multiple captures can now be created at the same position.
Captures at the same position are reference counted.
* update testcase
will be required by #200 / #164
* Input capture and emulation can now be disabled and will prompt the user to enable again.
* Improved error handling to deliver more useful error messages