@@ -3,14 +3,15 @@ use std::{ffi::c_void, mem::size_of, ptr, sync::OnceLock};
33use windows_capture:: { monitor:: Monitor , window:: Window } ;
44
55use windows:: Win32 :: {
6- Foundation :: POINT ,
6+ Foundation :: { HWND , POINT } ,
77 Graphics :: Gdi :: {
88 BI_RGB , BITMAP , BITMAPINFO , BITMAPINFOHEADER , CreateCompatibleDC , CreateDIBSection ,
99 DIB_RGB_COLORS , DeleteDC , DeleteObject , GetMonitorInfoW , GetObjectW , HGDIOBJ , HMONITOR ,
1010 MONITORINFO , SelectObject ,
1111 } ,
1212 UI :: {
1313 Input :: KeyboardAndMouse :: { GetAsyncKeyState , VK_LBUTTON , VK_MBUTTON , VK_RBUTTON } ,
14+ Shell :: GetScaleFactorForMonitor ,
1415 WindowsAndMessaging :: {
1516 CURSOR_SHOWING , CURSORINFO , DI_NORMAL , DrawIconEx , GetCursorInfo , GetIconInfo ,
1617 GetPhysicalCursorPos , HICON , ICONINFO , IDC_APPSTARTING , IDC_ARROW , IDC_CROSS , IDC_HAND ,
@@ -44,6 +45,12 @@ pub struct WindowsCursorSample {
4445 pub shape : Option < WindowsCursorShape > ,
4546}
4647
48+ #[ derive( Debug , Clone , Copy , PartialEq ) ]
49+ pub struct WindowsCursorSourceContext {
50+ pub region : CaptureRegion ,
51+ pub display_scale_factor : Option < f64 > ,
52+ }
53+
4754pub fn sample_cursor (
4855 region : CaptureRegion ,
4956 include_shape : bool ,
@@ -78,7 +85,7 @@ pub fn sample_cursor(
7885 } )
7986}
8087
81- pub fn source_region ( source_id : & SourceId ) -> Result < CaptureRegion , CaptureError > {
88+ pub fn source_context ( source_id : & SourceId ) -> Result < WindowsCursorSourceContext , CaptureError > {
8289 let _physical_coordinates = super :: dpi:: PhysicalCoordinates :: enter ( ) ?;
8390 if let Some ( device_name) = source_id. as_str ( ) . strip_prefix ( "wgc:monitor:" ) {
8491 let monitor = Monitor :: enumerate ( )
@@ -94,7 +101,11 @@ pub fn source_region(source_id: &SourceId) -> Result<CaptureRegion, CaptureError
94101 if !unsafe { GetMonitorInfoW ( HMONITOR ( monitor. as_raw_hmonitor ( ) ) , & mut info) } . as_bool ( ) {
95102 return Err ( CaptureError :: Backend ( "GetMonitorInfoW failed" . into ( ) ) ) ;
96103 }
97- return region_from_rect ( info. rcMonitor ) ;
104+ let monitor = HMONITOR ( monitor. as_raw_hmonitor ( ) ) ;
105+ return Ok ( WindowsCursorSourceContext {
106+ region : region_from_rect ( info. rcMonitor ) ?,
107+ display_scale_factor : display_scale_factor ( monitor) ,
108+ } ) ;
98109 }
99110 if source_id. as_str ( ) . starts_with ( "wgc:window:" ) {
100111 let window = Window :: enumerate ( )
@@ -104,13 +115,34 @@ pub fn source_region(source_id: &SourceId) -> Result<CaptureRegion, CaptureError
104115 source_id. as_str ( ) == format ! ( "wgc:window:{:x}" , window. as_raw_hwnd( ) as usize )
105116 } )
106117 . ok_or_else ( || CaptureError :: SourceNotFound ( source_id. to_string ( ) ) ) ?;
107- return region_from_rect ( window. rect ( ) . map_err ( backend_error) ?) ;
118+ let monitor = unsafe {
119+ windows:: Win32 :: Graphics :: Gdi :: MonitorFromWindow (
120+ HWND ( window. as_raw_hwnd ( ) ) ,
121+ windows:: Win32 :: Graphics :: Gdi :: MONITOR_DEFAULTTONEAREST ,
122+ )
123+ } ;
124+ return Ok ( WindowsCursorSourceContext {
125+ region : region_from_rect ( window. rect ( ) . map_err ( backend_error) ?) ?,
126+ display_scale_factor : ( !monitor. is_invalid ( ) )
127+ . then ( || display_scale_factor ( monitor) )
128+ . flatten ( ) ,
129+ } ) ;
108130 }
109131 Err ( CaptureError :: InvalidConfiguration ( format ! (
110132 "{source_id} is not a Windows visual source"
111133 ) ) )
112134}
113135
136+ pub fn source_region ( source_id : & SourceId ) -> Result < CaptureRegion , CaptureError > {
137+ Ok ( source_context ( source_id) ?. region )
138+ }
139+
140+ fn display_scale_factor ( monitor : HMONITOR ) -> Option < f64 > {
141+ // SAFETY: the handle comes from monitor enumeration or MonitorFromWindow.
142+ let percentage = unsafe { GetScaleFactorForMonitor ( monitor) } . ok ( ) ?. 0 ;
143+ ( percentage > 0 ) . then ( || f64:: from ( percentage) / 100.0 )
144+ }
145+
114146fn region_from_rect ( rect : windows:: Win32 :: Foundation :: RECT ) -> Result < CaptureRegion , CaptureError > {
115147 Ok ( CaptureRegion {
116148 x : rect. left ,
0 commit comments