Skip to content

Commit b071201

Browse files
authored
Fix multimonitors (#202)
Co-authored-by: Jacob Barber <[email protected]> closes #83
1 parent f52f19d commit b071201

File tree

1 file changed

+80
-13
lines changed

1 file changed

+80
-13
lines changed

input-emulation/src/macos.rs

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use super::{error::EmulationError, Emulation, EmulationHandle};
22
use async_trait::async_trait;
3-
use core_graphics::display::{CGDisplayBounds, CGMainDisplayID, CGPoint};
3+
use core_graphics::base::CGFloat;
4+
use core_graphics::display::{
5+
CGDirectDisplayID, CGDisplayBounds, CGGetDisplaysWithRect, CGPoint, CGRect, CGSize,
6+
};
47
use core_graphics::event::{
58
CGEvent, CGEventTapLocation, CGEventType, CGKeyCode, CGMouseButton, EventField, ScrollEventUnit,
69
};
@@ -105,6 +108,77 @@ fn key_event(event_source: CGEventSource, key: u16, state: u8) {
105108
event.post(CGEventTapLocation::HID);
106109
}
107110

111+
fn get_display_at_point(x: CGFloat, y: CGFloat) -> Option<CGDirectDisplayID> {
112+
let mut displays: [CGDirectDisplayID; 16] = [0; 16];
113+
let mut display_count: u32 = 0;
114+
let rect = CGRect::new(&CGPoint::new(x, y), &CGSize::new(0.0, 0.0));
115+
116+
let error = unsafe {
117+
CGGetDisplaysWithRect(
118+
rect,
119+
1,
120+
displays.as_mut_ptr(),
121+
&mut display_count as *mut u32,
122+
)
123+
};
124+
125+
if error != 0 {
126+
log::warn!("error getting displays at point ({}, {}): {}", x, y, error);
127+
return Option::None;
128+
}
129+
130+
if display_count == 0 {
131+
log::debug!("no displays found at point ({}, {})", x, y);
132+
return Option::None;
133+
}
134+
135+
return displays.first().copied();
136+
}
137+
138+
fn get_display_bounds(display: CGDirectDisplayID) -> (CGFloat, CGFloat, CGFloat, CGFloat) {
139+
unsafe {
140+
let bounds = CGDisplayBounds(display);
141+
let min_x = bounds.origin.x;
142+
let max_x = bounds.origin.x + bounds.size.width;
143+
let min_y = bounds.origin.y;
144+
let max_y = bounds.origin.y + bounds.size.height;
145+
(min_x as f64, min_y as f64, max_x as f64, max_y as f64)
146+
}
147+
}
148+
149+
fn clamp_to_screen_space(
150+
current_x: CGFloat,
151+
current_y: CGFloat,
152+
dx: CGFloat,
153+
dy: CGFloat,
154+
) -> (CGFloat, CGFloat) {
155+
// Check which display the mouse is currently on
156+
// Determine what the location of the mouse would be after applying the move
157+
// Get the display at the new location
158+
// If the point is not on a display
159+
// Clamp the mouse to the current display
160+
// Else If the point is on a display
161+
// Clamp the mouse to the new display
162+
let current_display = match get_display_at_point(current_x, current_y) {
163+
Some(display) => display,
164+
None => {
165+
log::warn!("could not get current display!");
166+
return (current_x, current_y);
167+
}
168+
};
169+
170+
let new_x = current_x + dx;
171+
let new_y = current_y + dy;
172+
173+
let final_display = get_display_at_point(new_x, new_y).unwrap_or(current_display);
174+
let (min_x, min_y, max_x, max_y) = get_display_bounds(final_display);
175+
176+
(
177+
new_x.clamp(min_x, max_x - 1.),
178+
new_y.clamp(min_y, max_y - 1.),
179+
)
180+
}
181+
108182
#[async_trait]
109183
impl Emulation for MacOSEmulation {
110184
async fn consume(
@@ -115,16 +189,6 @@ impl Emulation for MacOSEmulation {
115189
match event {
116190
Event::Pointer(pointer_event) => match pointer_event {
117191
PointerEvent::Motion { time: _, dx, dy } => {
118-
// FIXME secondary displays?
119-
let (min_x, min_y, max_x, max_y) = unsafe {
120-
let display = CGMainDisplayID();
121-
let bounds = CGDisplayBounds(display);
122-
let min_x = bounds.origin.x;
123-
let max_x = bounds.origin.x + bounds.size.width;
124-
let min_y = bounds.origin.y;
125-
let max_y = bounds.origin.y + bounds.size.height;
126-
(min_x as f64, min_y as f64, max_x as f64, max_y as f64)
127-
};
128192
let mut mouse_location = match self.get_mouse_location() {
129193
Some(l) => l,
130194
None => {
@@ -133,8 +197,11 @@ impl Emulation for MacOSEmulation {
133197
}
134198
};
135199

136-
mouse_location.x = (mouse_location.x + dx).clamp(min_x, max_x - 1.);
137-
mouse_location.y = (mouse_location.y + dy).clamp(min_y, max_y - 1.);
200+
let (new_mouse_x, new_mouse_y) =
201+
clamp_to_screen_space(mouse_location.x, mouse_location.y, dx, dy);
202+
203+
mouse_location.x = new_mouse_x;
204+
mouse_location.y = new_mouse_y;
138205

139206
let mut event_type = CGEventType::MouseMoved;
140207
if self.button_state.left {

0 commit comments

Comments
 (0)