Files
cursor-lang/CursorLang.Core/Interop/PopupWindowNative.cs
T
alex 55ac8e6556 lightweight variant (#1)
Reviewed-on: #1
Co-authored-by: Aleksandr Neychev <alexnejchev73@gmail.com>
2026-08-12 13:37:30 +00:00

113 lines
3.5 KiB
C#

using System.Runtime.InteropServices;
namespace CursorLang.Core.Interop;
/// <summary>
/// Win32 API for the popup window: styles, positioning near the cursor
/// and the scale of the monitor the cursor is on.
/// </summary>
internal static class PopupWindowNative
{
[StructLayout(LayoutKind.Sequential)]
internal struct Point
{
public int X;
public int Y;
}
[DllImport("user32.dll")]
private static extern bool GetCursorPos(out Point lpPoint);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
private static extern IntPtr MonitorFromPoint(Point pt, uint dwFlags);
[DllImport("shcore.dll")]
private static extern int GetDpiForMonitor(IntPtr hMonitor, int dpiType, out uint dpiX, out uint dpiY);
[DllImport("user32.dll")]
private static extern IntPtr MonitorFromWindow(IntPtr hWnd, uint dwFlags);
[DllImport("user32.dll")]
private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MonitorInfo lpmi);
[StructLayout(LayoutKind.Sequential)]
internal struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential)]
private struct MonitorInfo
{
public int cbSize;
public Rect rcMonitor;
public Rect rcWork;
public uint dwFlags;
}
private const uint SWP_NOSIZE = 0x0001;
private const uint SWP_NOZORDER = 0x0004;
private const uint SWP_NOACTIVATE = 0x0010;
private const uint MONITOR_DEFAULTTONEAREST = 2;
private const int MDT_EFFECTIVE_DPI = 0;
internal static Point GetCursorPosition()
{
GetCursorPos(out Point cursor);
return cursor;
}
/// <summary>
/// Moves the window to a screen point without changing its size or z-order.
/// The coordinates are physical pixels: monitors have different scaling, while
/// Window.Left/Top are converted using the DPI of the monitor the window is on
/// right now, which misses the target on a neighbouring monitor.
/// </summary>
internal static void MoveTo(IntPtr hWnd, int x, int y)
{
SetWindowPos(hWnd, IntPtr.Zero, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
/// <summary>The scale of the monitor the point is on (1.0 at 96 DPI).</summary>
internal static double GetScaleAt(Point point) =>
GetScaleOf(MonitorFromPoint(point, MONITOR_DEFAULTTONEAREST));
/// <summary>
/// The work area of the monitor holding the active window — without the taskbar —
/// and its scale. That is the monitor the user is working on right now.
/// </summary>
internal static (Rect WorkArea, double Scale) GetActiveMonitorWorkArea()
{
IntPtr monitor = MonitorFromWindow(GetForegroundWindow(), MONITOR_DEFAULTTONEAREST);
var info = new MonitorInfo { cbSize = Marshal.SizeOf<MonitorInfo>() };
if (!GetMonitorInfo(monitor, ref info))
{
return (new Rect(), 1.0);
}
return (info.rcWork, GetScaleOf(monitor));
}
private static double GetScaleOf(IntPtr monitor)
{
if (GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, out uint dpiX, out _) < 0)
{
return 1.0;
}
return dpiX / 96.0;
}
}