mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-05-08 23:28:04 +03:00
style: apply cargo fmt
No behavior changes. Brings three files back in line with the project's `style_edition = "2024"` rustfmt config so subsequent edits don't carry unrelated formatting in their diffs.
This commit is contained in:
committed by
Ferdinand Schober
parent
e863cdb801
commit
e5862e10e3
@@ -435,113 +435,114 @@ fn create_event_tap<'a>(
|
|||||||
CGEventType::FlagsChanged,
|
CGEventType::FlagsChanged,
|
||||||
];
|
];
|
||||||
|
|
||||||
let event_tap_callback =
|
let event_tap_callback = move |_proxy: CGEventTapProxy,
|
||||||
move |_proxy: CGEventTapProxy, event_type: CGEventType, cg_ev: &CGEvent| {
|
event_type: CGEventType,
|
||||||
log::trace!("Got event from tap: {event_type:?}");
|
cg_ev: &CGEvent| {
|
||||||
let mut state = client_state.blocking_lock();
|
log::trace!("Got event from tap: {event_type:?}");
|
||||||
let mut capture_position = None;
|
let mut state = client_state.blocking_lock();
|
||||||
let mut res_events = vec![];
|
let mut capture_position = None;
|
||||||
|
let mut res_events = vec![];
|
||||||
|
|
||||||
if matches!(event_type, CGEventType::TapDisabledByTimeout) {
|
if matches!(event_type, CGEventType::TapDisabledByTimeout) {
|
||||||
// The kernel disables the tap when our callback runs
|
// The kernel disables the tap when our callback runs
|
||||||
// longer than ~1s on a single event — typical causes
|
// longer than ~1s on a single event — typical causes
|
||||||
// are heavy load, scheduler contention, or this
|
// are heavy load, scheduler contention, or this
|
||||||
// process being briefly suspended (e.g. App Nap on a
|
// process being briefly suspended (e.g. App Nap on a
|
||||||
// long idle). It is NOT a fatal condition: Apple's
|
// long idle). It is NOT a fatal condition: Apple's
|
||||||
// documented recovery is to call CGEventTapEnable
|
// documented recovery is to call CGEventTapEnable
|
||||||
// and resume processing. Re-enable in place and KEEP
|
// and resume processing. Re-enable in place and KEEP
|
||||||
// existing capture state so the user doesn't see the
|
// existing capture state so the user doesn't see the
|
||||||
// cursor pop back to the local screen mid-session.
|
// cursor pop back to the local screen mid-session.
|
||||||
if let Some(&port) = tap_mach_port_cb.get() {
|
if let Some(&port) = tap_mach_port_cb.get() {
|
||||||
log::warn!("CGEventTap disabled by timeout — re-enabling");
|
log::warn!("CGEventTap disabled by timeout — re-enabling");
|
||||||
unsafe {
|
unsafe {
|
||||||
CGEventTapEnable(port as *mut c_void, true);
|
CGEventTapEnable(port as *mut c_void, true);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log::error!(
|
|
||||||
"CGEventTap disabled by timeout, but mach port not yet stored — cannot re-enable"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return CallbackResult::Keep;
|
|
||||||
}
|
|
||||||
|
|
||||||
if matches!(event_type, CGEventType::TapDisabledByUserInput) {
|
|
||||||
// Deliberate kill — secure-input mode (e.g. password
|
|
||||||
// field), TCC Accessibility revoked mid-session, or
|
|
||||||
// the user disabling event-monitoring. We can't
|
|
||||||
// recover from this; drop captured state synchronously
|
|
||||||
// and return Keep on this event. Otherwise the
|
|
||||||
// `current_pos.is_some()` branch below would drop this
|
|
||||||
// event (and any racing callback still in flight) back
|
|
||||||
// into `CallbackResult::Drop`, silently eating the
|
|
||||||
// user's clicks and keypresses while the tap winds
|
|
||||||
// down. Clear state + show the cursor here, then
|
|
||||||
// notify the producer loop so the service can tear
|
|
||||||
// down cleanly.
|
|
||||||
log::error!("CGEventTap disabled by user input, releasing capture state");
|
|
||||||
if state.current_pos.is_some() {
|
|
||||||
let _ = CGDisplay::show_cursor(&CGDisplay::main());
|
|
||||||
state.current_pos = None;
|
|
||||||
}
|
|
||||||
notify_tx
|
|
||||||
.blocking_send(ProducerEvent::EventTapDisabled)
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
log::error!("Failed to send notification: {e}");
|
|
||||||
});
|
|
||||||
return CallbackResult::Keep;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Are we in a client?
|
|
||||||
if let Some(current_pos) = state.current_pos {
|
|
||||||
capture_position = Some(current_pos);
|
|
||||||
get_events(
|
|
||||||
&event_type,
|
|
||||||
cg_ev,
|
|
||||||
&mut res_events,
|
|
||||||
&mut state.modifier_state,
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
log::error!("Failed to get events: {e}");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Keep (hidden) cursor at the edge of the screen
|
|
||||||
if matches!(
|
|
||||||
event_type,
|
|
||||||
CGEventType::MouseMoved
|
|
||||||
| CGEventType::LeftMouseDragged
|
|
||||||
| CGEventType::RightMouseDragged
|
|
||||||
| CGEventType::OtherMouseDragged
|
|
||||||
) {
|
|
||||||
state.reset_cursor().unwrap_or_else(|e| log::warn!("{e}"));
|
|
||||||
}
|
|
||||||
} else if matches!(event_type, CGEventType::MouseMoved) {
|
|
||||||
// Did we cross a barrier?
|
|
||||||
if let Some(new_pos) = state.crossed(cg_ev) {
|
|
||||||
capture_position = Some(new_pos);
|
|
||||||
state
|
|
||||||
.start_capture(cg_ev, new_pos)
|
|
||||||
.unwrap_or_else(|e| log::warn!("{e}"));
|
|
||||||
res_events.push(CaptureEvent::Begin);
|
|
||||||
notify_tx
|
|
||||||
.blocking_send(ProducerEvent::Grab(new_pos))
|
|
||||||
.expect("Failed to send notification");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(pos) = capture_position {
|
|
||||||
res_events.iter().for_each(|e| {
|
|
||||||
// error must be ignored, since the event channel
|
|
||||||
// may already be closed when the InputCapture instance is dropped.
|
|
||||||
let _ = event_tx.blocking_send((pos, *e));
|
|
||||||
});
|
|
||||||
// Returning Drop should stop the event from being processed
|
|
||||||
// but core fundation still returns the event
|
|
||||||
cg_ev.set_type(CGEventType::Null);
|
|
||||||
CallbackResult::Drop
|
|
||||||
} else {
|
} else {
|
||||||
CallbackResult::Keep
|
log::error!(
|
||||||
|
"CGEventTap disabled by timeout, but mach port not yet stored — cannot re-enable"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
return CallbackResult::Keep;
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(event_type, CGEventType::TapDisabledByUserInput) {
|
||||||
|
// Deliberate kill — secure-input mode (e.g. password
|
||||||
|
// field), TCC Accessibility revoked mid-session, or
|
||||||
|
// the user disabling event-monitoring. We can't
|
||||||
|
// recover from this; drop captured state synchronously
|
||||||
|
// and return Keep on this event. Otherwise the
|
||||||
|
// `current_pos.is_some()` branch below would drop this
|
||||||
|
// event (and any racing callback still in flight) back
|
||||||
|
// into `CallbackResult::Drop`, silently eating the
|
||||||
|
// user's clicks and keypresses while the tap winds
|
||||||
|
// down. Clear state + show the cursor here, then
|
||||||
|
// notify the producer loop so the service can tear
|
||||||
|
// down cleanly.
|
||||||
|
log::error!("CGEventTap disabled by user input, releasing capture state");
|
||||||
|
if state.current_pos.is_some() {
|
||||||
|
let _ = CGDisplay::show_cursor(&CGDisplay::main());
|
||||||
|
state.current_pos = None;
|
||||||
|
}
|
||||||
|
notify_tx
|
||||||
|
.blocking_send(ProducerEvent::EventTapDisabled)
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
log::error!("Failed to send notification: {e}");
|
||||||
|
});
|
||||||
|
return CallbackResult::Keep;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are we in a client?
|
||||||
|
if let Some(current_pos) = state.current_pos {
|
||||||
|
capture_position = Some(current_pos);
|
||||||
|
get_events(
|
||||||
|
&event_type,
|
||||||
|
cg_ev,
|
||||||
|
&mut res_events,
|
||||||
|
&mut state.modifier_state,
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
log::error!("Failed to get events: {e}");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Keep (hidden) cursor at the edge of the screen
|
||||||
|
if matches!(
|
||||||
|
event_type,
|
||||||
|
CGEventType::MouseMoved
|
||||||
|
| CGEventType::LeftMouseDragged
|
||||||
|
| CGEventType::RightMouseDragged
|
||||||
|
| CGEventType::OtherMouseDragged
|
||||||
|
) {
|
||||||
|
state.reset_cursor().unwrap_or_else(|e| log::warn!("{e}"));
|
||||||
|
}
|
||||||
|
} else if matches!(event_type, CGEventType::MouseMoved) {
|
||||||
|
// Did we cross a barrier?
|
||||||
|
if let Some(new_pos) = state.crossed(cg_ev) {
|
||||||
|
capture_position = Some(new_pos);
|
||||||
|
state
|
||||||
|
.start_capture(cg_ev, new_pos)
|
||||||
|
.unwrap_or_else(|e| log::warn!("{e}"));
|
||||||
|
res_events.push(CaptureEvent::Begin);
|
||||||
|
notify_tx
|
||||||
|
.blocking_send(ProducerEvent::Grab(new_pos))
|
||||||
|
.expect("Failed to send notification");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(pos) = capture_position {
|
||||||
|
res_events.iter().for_each(|e| {
|
||||||
|
// error must be ignored, since the event channel
|
||||||
|
// may already be closed when the InputCapture instance is dropped.
|
||||||
|
let _ = event_tx.blocking_send((pos, *e));
|
||||||
|
});
|
||||||
|
// Returning Drop should stop the event from being processed
|
||||||
|
// but core fundation still returns the event
|
||||||
|
cg_ev.set_type(CGEventType::Null);
|
||||||
|
CallbackResult::Drop
|
||||||
|
} else {
|
||||||
|
CallbackResult::Keep
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let tap = CGEventTap::new(
|
let tap = CGEventTap::new(
|
||||||
CGEventTapLocation::Session,
|
CGEventTapLocation::Session,
|
||||||
@@ -599,8 +600,7 @@ fn event_tap_thread(
|
|||||||
// callback runs on this thread's CFRunLoop. Box-leak the sender
|
// callback runs on this thread's CFRunLoop. Box-leak the sender
|
||||||
// so the C side has a stable user_info pointer; reclaim it after
|
// so the C side has a stable user_info pointer; reclaim it after
|
||||||
// the run loop exits.
|
// the run loop exits.
|
||||||
let display_user_info =
|
let display_user_info = Box::into_raw(Box::new(display_notify_tx)) as *mut c_void;
|
||||||
Box::into_raw(Box::new(display_notify_tx)) as *mut c_void;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
CGDisplayRegisterReconfigurationCallback(
|
CGDisplayRegisterReconfigurationCallback(
|
||||||
display_reconfiguration_callback,
|
display_reconfiguration_callback,
|
||||||
@@ -613,10 +613,7 @@ fn event_tap_thread(
|
|||||||
log::debug!("event tap thread exiting!...");
|
log::debug!("event tap thread exiting!...");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
CGDisplayRemoveReconfigurationCallback(
|
CGDisplayRemoveReconfigurationCallback(display_reconfiguration_callback, display_user_info);
|
||||||
display_reconfiguration_callback,
|
|
||||||
display_user_info,
|
|
||||||
);
|
|
||||||
// Reclaim the leaked sender Box so we don't leak a tokio
|
// Reclaim the leaked sender Box so we don't leak a tokio
|
||||||
// channel sender on every capture create/destroy cycle.
|
// channel sender on every capture create/destroy cycle.
|
||||||
drop(Box::from_raw(
|
drop(Box::from_raw(
|
||||||
@@ -633,11 +630,7 @@ fn event_tap_thread(
|
|||||||
/// then again afterwards with the actual change flags (Add, Remove,
|
/// then again afterwards with the actual change flags (Add, Remove,
|
||||||
/// Mode, DesktopShapeChanged, etc.). Skip the begin phase; on the
|
/// Mode, DesktopShapeChanged, etc.). Skip the begin phase; on the
|
||||||
/// real notification, kick the producer task to refresh bounds.
|
/// real notification, kick the producer task to refresh bounds.
|
||||||
extern "C" fn display_reconfiguration_callback(
|
extern "C" fn display_reconfiguration_callback(_display: u32, flags: u32, user_info: *mut c_void) {
|
||||||
_display: u32,
|
|
||||||
flags: u32,
|
|
||||||
user_info: *mut c_void,
|
|
||||||
) {
|
|
||||||
const K_CG_DISPLAY_BEGIN_CONFIGURATION_FLAG: u32 = 1 << 0;
|
const K_CG_DISPLAY_BEGIN_CONFIGURATION_FLAG: u32 = 1 << 0;
|
||||||
if flags & K_CG_DISPLAY_BEGIN_CONFIGURATION_FLAG != 0 {
|
if flags & K_CG_DISPLAY_BEGIN_CONFIGURATION_FLAG != 0 {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -219,9 +219,7 @@ fn build_ui(app: &Application) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
macos_privacy::AccessibilityChange::Revoked => {
|
macos_privacy::AccessibilityChange::Revoked => {
|
||||||
log::warn!(
|
log::warn!("Accessibility revoked — quitting to avoid wedging system input");
|
||||||
"Accessibility revoked — quitting to avoid wedging system input"
|
|
||||||
);
|
|
||||||
if let Some(app) = app_weak.upgrade() {
|
if let Some(app) = app_weak.upgrade() {
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
@@ -291,4 +289,3 @@ fn build_ui(app: &Application) {
|
|||||||
window.present();
|
window.present();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ pub fn accessibility_granted() -> bool {
|
|||||||
raw != 0
|
raw != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub enum AccessibilityChange {
|
pub enum AccessibilityChange {
|
||||||
/// AX was missing at startup and the user has now granted it.
|
/// AX was missing at startup and the user has now granted it.
|
||||||
/// Capture/emulation still need a relaunch to take effect, since
|
/// Capture/emulation still need a relaunch to take effect, since
|
||||||
|
|||||||
Reference in New Issue
Block a user