11use super :: { error:: EmulationError , Emulation , EmulationHandle } ;
22use 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+ } ;
47use 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]
109183impl 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