@@ -6,12 +6,10 @@ use windows::Win32::Graphics::Gdi::{
66 GetDeviceCaps , GetDIBits , GetPixel , LOGPIXELSX , ReleaseDC , SelectObject , BITMAPINFO ,
77 BITMAPINFOHEADER , BI_RGB , CLR_INVALID , DIB_RGB_COLORS , HDC , SRCCOPY ,
88} ;
9- use windows:: Win32 :: UI :: WindowsAndMessaging :: { GetCursorPos , GetSystemMetrics , SM_CXVIRTUALSCREEN , SM_CYVIRTUALSCREEN } ;
9+ use windows:: Win32 :: UI :: WindowsAndMessaging :: GetCursorPos ;
1010
1111pub struct WindowsSampler {
1212 hdc : HDC ,
13- screen_width : i32 ,
14- screen_height : i32 ,
1513 dpi_scale : f64 ,
1614}
1715
@@ -24,23 +22,14 @@ impl WindowsSampler {
2422 return Err ( "Failed to get device context" . to_string ( ) ) ;
2523 }
2624
27- // Get virtual screen dimensions (supports multi-monitor)
28- let screen_width = GetSystemMetrics ( SM_CXVIRTUALSCREEN ) ;
29- let screen_height = GetSystemMetrics ( SM_CYVIRTUALSCREEN ) ;
30-
3125 // Get DPI scaling factor
3226 // GetDeviceCaps returns DPI (e.g., 96 for 100%, 192 for 200%)
3327 // Standard DPI is 96, so scale = actual_dpi / 96
3428 let dpi = GetDeviceCaps ( hdc, LOGPIXELSX ) ;
3529 let dpi_scale = dpi as f64 / 96.0 ;
3630
37- eprintln ! ( "Windows sampler initialized ({}x{}, DPI scale: {})" ,
38- screen_width, screen_height, dpi_scale) ;
39-
4031 Ok ( WindowsSampler {
4132 hdc,
42- screen_width,
43- screen_height,
4433 dpi_scale,
4534 } )
4635 }
@@ -58,11 +47,14 @@ impl Drop for WindowsSampler {
5847impl PixelSampler for WindowsSampler {
5948 fn sample_pixel ( & mut self , x : i32 , y : i32 ) -> Result < Color , String > {
6049 unsafe {
61- // Convert from physical pixels to logical pixels
62- let logical_x = ( x as f64 / self . dpi_scale ) as i32 ;
63- let logical_y = ( y as f64 / self . dpi_scale ) as i32 ;
50+ // Electron is DPI-aware, so:
51+ // - GetCursorPos returns VIRTUAL pixels (e.g., 0-2559 at 200% on 5120 wide screen)
52+ // - GetPixel expects PHYSICAL pixels (e.g., 0-5119)
53+ // We must convert: physical = virtual * dpi_scale
54+ let physical_x = ( x as f64 * self . dpi_scale ) as i32 ;
55+ let physical_y = ( y as f64 * self . dpi_scale ) as i32 ;
6456
65- let color_ref = GetPixel ( self . hdc , logical_x , logical_y ) ;
57+ let color_ref = GetPixel ( self . hdc , physical_x , physical_y ) ;
6658
6759 // Check for error (CLR_INVALID is returned on error)
6860 // COLORREF is a newtype wrapper around u32
@@ -102,15 +94,15 @@ impl PixelSampler for WindowsSampler {
10294 unsafe {
10395 let half_size = ( grid_size / 2 ) as i32 ;
10496
105- // Convert cursor coordinates from physical pixels to logical pixels
106- // GetCursorPos returns physical pixels, but DC uses logical pixels
107- // At 200% DPI : physical 2000 -> logical 1000
108- let logical_x = ( center_x as f64 / self . dpi_scale ) as i32 ;
109- let logical_y = ( center_y as f64 / self . dpi_scale ) as i32 ;
97+ // Electron is DPI-aware, so GetCursorPos returns virtual coordinates
98+ // but GetDC/BitBlt use physical coordinates
99+ // Convert : physical = virtual * dpi_scale
100+ let physical_center_x = ( center_x as f64 * self . dpi_scale ) as i32 ;
101+ let physical_center_y = ( center_y as f64 * self . dpi_scale ) as i32 ;
110102
111- // Calculate capture region in logical pixels
112- let x_start = logical_x - half_size;
113- let y_start = logical_y - half_size;
103+ // Calculate capture region in physical pixel coordinates
104+ let x_start = physical_center_x - half_size;
105+ let y_start = physical_center_y - half_size;
114106 let width = grid_size as i32 ;
115107 let height = grid_size as i32 ;
116108
@@ -148,7 +140,6 @@ impl PixelSampler for WindowsSampler {
148140 let _ = DeleteObject ( bitmap) ;
149141 let _ = DeleteDC ( mem_dc) ;
150142
151- eprintln ! ( "BitBlt failed, falling back to pixel-by-pixel sampling" ) ;
152143 return self . sample_grid_fallback ( center_x, center_y, grid_size) ;
153144 }
154145
@@ -191,7 +182,6 @@ impl PixelSampler for WindowsSampler {
191182 let _ = DeleteDC ( mem_dc) ;
192183
193184 if scan_lines == 0 {
194- eprintln ! ( "GetDIBits failed, falling back to pixel-by-pixel sampling" ) ;
195185 return self . sample_grid_fallback ( center_x, center_y, grid_size) ;
196186 }
197187
@@ -232,20 +222,19 @@ impl WindowsSampler {
232222 let half_size = ( grid_size / 2 ) as i32 ;
233223 let mut grid = Vec :: with_capacity ( grid_size) ;
234224
235- // Convert center from physical to logical pixels
236- // This ensures we sample distinct logical pixels, not duplicates at high DPI
237- let logical_center_x = ( center_x as f64 / self . dpi_scale ) as i32 ;
238- let logical_center_y = ( center_y as f64 / self . dpi_scale ) as i32 ;
225+ // Convert virtual cursor coordinates to physical for DC sampling
226+ let physical_center_x = ( center_x as f64 * self . dpi_scale ) as i32 ;
227+ let physical_center_y = ( center_y as f64 * self . dpi_scale ) as i32 ;
239228
240229 for row in 0 ..grid_size {
241230 let mut row_pixels = Vec :: with_capacity ( grid_size) ;
242231 for col in 0 ..grid_size {
243- // Work in logical pixel space to match main path behavior
244- let logical_x = logical_center_x + ( col as i32 - half_size) ;
245- let logical_y = logical_center_y + ( row as i32 - half_size) ;
232+ // Calculate physical pixel coordinates
233+ let physical_x = physical_center_x + ( col as i32 - half_size) ;
234+ let physical_y = physical_center_y + ( row as i32 - half_size) ;
246235
247- // Sample directly in logical space using GetPixel
248- let color_ref = GetPixel ( self . hdc , logical_x , logical_y ) ;
236+ // Sample using physical coordinates
237+ let color_ref = GetPixel ( self . hdc , physical_x , physical_y ) ;
249238
250239 let color = if color_ref. 0 == CLR_INVALID {
251240 Color :: new ( 128 , 128 , 128 ) // Gray fallback for out-of-bounds
0 commit comments