fixed bug - careet in notepad and menu start OS

This commit is contained in:
2026-08-08 23:00:37 +05:00
parent ba0748920b
commit 5ecc46f7a3
4 changed files with 113 additions and 33 deletions
+48 -28
View File
@@ -15,29 +15,6 @@ namespace CursorLang.Interop;
/// </remarks>
internal static class CaretNative
{
[StructLayout(LayoutKind.Sequential)]
private struct GuiThreadInfo
{
public int cbSize;
public uint flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCaret;
public PopupWindowNative.Rect rcCaret;
}
[DllImport("user32.dll")]
private static extern bool GetGUIThreadInfo(uint idThread, ref GuiThreadInfo lpgui);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId);
[DllImport("user32.dll")]
private static extern bool ClientToScreen(IntPtr hWnd, ref PopupWindowNative.Point lpPoint);
@@ -45,6 +22,12 @@ internal static class CaretNative
private static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint dwObjectId,
ref Guid riid, out IAccessible ppvObject);
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, out PopupWindowNative.Rect lpRect);
[DllImport("user32.dll")]
private static extern uint GetDpiForWindow(IntPtr hWnd);
private const uint OBJID_CARET = 0xFFFFFFF8;
private const int CHILDID_SELF = 0;
@@ -54,18 +37,55 @@ internal static class CaretNative
/// </summary>
internal static PopupWindowNative.Rect? TryGetCaretRect()
{
var info = new GuiThreadInfo { cbSize = Marshal.SizeOf<GuiThreadInfo>() };
uint threadId = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
if (!GetGUIThreadInfo(threadId, ref info))
if (!ForegroundInputNative.TryGetInfo(out ForegroundInputNative.GuiThreadInfo info))
{
return null;
}
return TryGetSystemCaret(info)
PopupWindowNative.Rect? caret = TryGetSystemCaret(info)
?? TryGetAccessibleCaret(info.hwndFocus)
?? TryGetAutomationCaret();
return caret is null ? null : Validate(caret.Value, info.hwndFocus);
}
/// <summary>
/// Отсеивает заведомо неверные координаты.
/// </summary>
/// <remarks>
/// Часть приложений отдаёт положение каретки в своей системе координат либо
/// без учёта масштаба экрана, и подсказка уезжает далеко от поля ввода.
/// Каретка обязана находиться внутри окна ввода — это и проверяем, а перед
/// отказом пробуем истолковать координаты как немасштабированные.
/// </remarks>
private static PopupWindowNative.Rect? Validate(PopupWindowNative.Rect caret, IntPtr hwndFocus)
{
if (hwndFocus == IntPtr.Zero || !GetWindowRect(hwndFocus, out PopupWindowNative.Rect window))
{
return caret;
}
if (IsInside(caret, window))
{
return caret;
}
double scale = GetDpiForWindow(hwndFocus) / 96.0;
var scaled = new PopupWindowNative.Rect
{
Left = (int)(caret.Left * scale),
Top = (int)(caret.Top * scale),
Right = (int)(caret.Right * scale),
Bottom = (int)(caret.Bottom * scale),
};
return IsInside(scaled, window) ? scaled : null;
}
private static bool IsInside(PopupWindowNative.Rect inner, PopupWindowNative.Rect outer) =>
inner.Left >= outer.Left && inner.Right <= outer.Right &&
inner.Top >= outer.Top && inner.Bottom <= outer.Bottom;
/// <summary>Сколько ждём ответа от чужого приложения по UI Automation.</summary>
private static readonly TimeSpan AutomationTimeout = TimeSpan.FromMilliseconds(150);
@@ -127,7 +147,7 @@ internal static class CaretNative
}
// Системная каретка: координаты приходят относительно окна, которому она принадлежит
private static PopupWindowNative.Rect? TryGetSystemCaret(GuiThreadInfo info)
private static PopupWindowNative.Rect? TryGetSystemCaret(ForegroundInputNative.GuiThreadInfo info)
{
if (info.hwndCaret == IntPtr.Zero || IsEmpty(info.rcCaret))
{