|
10 | 10 | using SnapX.Core.Utils.Extensions; |
11 | 11 | using Windows.Win32; |
12 | 12 | using Windows.Win32.Foundation; |
| 13 | +using Windows.Win32.Graphics.Gdi; |
13 | 14 | using Windows.Win32.System.Memory; |
| 15 | +using Windows.Win32.UI.HiDpi; |
14 | 16 | using Windows.Win32.UI.Shell; |
15 | 17 | using Windows.Win32.UI.WindowsAndMessaging; |
16 | 18 |
|
@@ -241,6 +243,77 @@ public static Rectangle GetWindowRect(IntPtr hwnd) |
241 | 243 | return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); |
242 | 244 | } |
243 | 245 |
|
| 246 | + public override Screen? GetScreen(Point pos) |
| 247 | + { |
| 248 | + var pt = new System.Drawing.Point(pos.X, pos.Y); |
| 249 | + |
| 250 | + // 2. Get the HMONITOR handle. |
| 251 | + // MONITOR_DEFAULTTONEAREST ensures that even if the point is off-screen, |
| 252 | + // it returns the closest monitor rather than null. |
| 253 | + var hMonitor = PInvoke.MonitorFromPoint(pt, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST); |
| 254 | + |
| 255 | + if (hMonitor == IntPtr.Zero) |
| 256 | + { |
| 257 | + return null; |
| 258 | + } |
| 259 | + |
| 260 | + unsafe |
| 261 | + { |
| 262 | + var info = new MONITORINFOEXW(); |
| 263 | + info.monitorInfo.cbSize = (uint)Marshal.SizeOf<MONITORINFOEXW>(); |
| 264 | + |
| 265 | + if (!PInvoke.GetMonitorInfo(hMonitor, (MONITORINFO*)&info)) return null; |
| 266 | + var deviceName = info.szDevice.ToString(); |
| 267 | + var devMode = new DEVMODEW { dmSize = (ushort)sizeof(DEVMODEW) }; |
| 268 | + uint refreshRate = 0; |
| 269 | + var orientation = ScreenOrientation.Landscape; |
| 270 | + if (PInvoke.EnumDisplaySettings(deviceName, ENUM_DISPLAY_SETTINGS_MODE.ENUM_CURRENT_SETTINGS, ref devMode)) |
| 271 | + { |
| 272 | + refreshRate = devMode.dmDisplayFrequency; |
| 273 | + orientation = devMode.Anonymous1.Anonymous2.dmDisplayOrientation switch |
| 274 | + { |
| 275 | + DEVMODE_DISPLAY_ORIENTATION.DMDO_90 => ScreenOrientation.Portrait, |
| 276 | + DEVMODE_DISPLAY_ORIENTATION.DMDO_270 => ScreenOrientation.Portrait, |
| 277 | + _ => ScreenOrientation.Landscape |
| 278 | + }; |
| 279 | + } |
| 280 | + PInvoke.GetDpiForMonitor(hMonitor, MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, out var dpiX, out var _); |
| 281 | + var scaleFactor = dpiX / 96.0; |
| 282 | + var hdc = PInvoke.CreateDCW(null, deviceName, null, null); |
| 283 | + double diagonalInches = 0; |
| 284 | + if (!hdc.IsNull) |
| 285 | + { |
| 286 | + var widthMm = PInvoke.GetDeviceCaps(hdc, GET_DEVICE_CAPS_INDEX.HORZSIZE); |
| 287 | + var heightMm = PInvoke.GetDeviceCaps(hdc, GET_DEVICE_CAPS_INDEX.VERTSIZE); |
| 288 | + |
| 289 | + var widthInches = widthMm / 25.4; |
| 290 | + var heightInches = heightMm / 25.4; |
| 291 | + diagonalInches = Math.Sqrt(Math.Pow(widthInches, 2) + Math.Pow(heightInches, 2)); |
| 292 | + |
| 293 | + PInvoke.DeleteDC(hdc); |
| 294 | + } |
| 295 | + return new Screen |
| 296 | + { |
| 297 | + Id = deviceName, |
| 298 | + // Index = index, unknown |
| 299 | + Name = deviceName, |
| 300 | + Bounds = new Rectangle( |
| 301 | + info.monitorInfo.rcMonitor.left, |
| 302 | + info.monitorInfo.rcMonitor.top, |
| 303 | + info.monitorInfo.rcMonitor.right - info.monitorInfo.rcMonitor.left, |
| 304 | + info.monitorInfo.rcMonitor.bottom - info.monitorInfo.rcMonitor.top |
| 305 | + ), |
| 306 | + RefreshRate = refreshRate, |
| 307 | + Orientation = orientation, |
| 308 | + DPI = dpiX, |
| 309 | + ScaleFactor = scaleFactor, |
| 310 | + DiagonalSizeInches = Math.Round(diagonalInches, 1), |
| 311 | + IsPrimary = (info.monitorInfo.dwFlags & PInvoke.MONITORINFOF_PRIMARY) != 0, |
| 312 | + SessionType = SessionType.Windows |
| 313 | + }; |
| 314 | + } |
| 315 | + } |
| 316 | + |
244 | 317 | // Beginning of IntegrationHelper class being integrated into WindowsAPI class |
245 | 318 |
|
246 | 319 | private static readonly string ApplicationPath = $"\"{AppDomain.CurrentDomain.BaseDirectory}\""; |
|
0 commit comments