fixed comment into code

This commit is contained in:
2026-08-09 20:02:23 +05:00
parent 778fc1034b
commit 7e4e569d53
34 changed files with 332 additions and 306 deletions
+26 -26
View File
@@ -6,12 +6,12 @@ using Accessibility;
namespace CursorLang.Interop;
/// <summary>
/// Определяет положение каретки в активном поле ввода — в том числе в чужом приложении.
/// Locates the caret in the active input field — including one in another application.
/// </summary>
/// <remarks>
/// Единого способа нет: классические Win32-приложения заводят системную каретку,
/// а Chrome, Electron и прочие рисуют её сами и сообщают положение только через
/// средства доступности. Поэтому сначала спрашиваем систему, затем — приложение.
/// There is no single way to do it: classic Win32 applications create a system caret,
/// while Chrome, Electron and others draw it themselves and report its position only
/// through accessibility interfaces. So we ask the system first, then the application.
/// </remarks>
internal static class CaretNative
{
@@ -32,8 +32,8 @@ internal static class CaretNative
private const int CHILDID_SELF = 0;
/// <summary>
/// Прямоугольник каретки в пикселях экрана или <c>null</c>, если активное
/// приложение не сообщает её положение.
/// The caret rectangle in screen pixels, or <c>null</c> when the active
/// application does not report its position.
/// </summary>
internal static PopupWindowNative.Rect? TryGetCaretRect()
{
@@ -50,13 +50,13 @@ internal static class CaretNative
}
/// <summary>
/// Отсеивает заведомо неверные координаты.
/// Filters out obviously wrong coordinates.
/// </summary>
/// <remarks>
/// Часть приложений отдаёт положение каретки в своей системе координат либо
/// без учёта масштаба экрана, и подсказка уезжает далеко от поля ввода.
/// Каретка обязана находиться внутри окна ввода — это и проверяем, а перед
/// отказом пробуем истолковать координаты как немасштабированные.
/// Some applications report the caret position in their own coordinate system or
/// without accounting for display scaling, and the popup ends up far from the input
/// field. The caret must be inside the input window — that is what we check, and
/// before giving up we try to read the coordinates as unscaled ones.
/// </remarks>
private static PopupWindowNative.Rect? Validate(PopupWindowNative.Rect caret, IntPtr hwndFocus)
{
@@ -86,16 +86,16 @@ internal static class CaretNative
inner.Left >= outer.Left && inner.Right <= outer.Right &&
inner.Top >= outer.Top && inner.Bottom <= outer.Bottom;
/// <summary>Сколько ждём ответа от чужого приложения по UI Automation.</summary>
/// <summary>How long we wait for another application to answer over UI Automation.</summary>
private static readonly TimeSpan AutomationTimeout = TimeSpan.FromMilliseconds(150);
// Браузеры и другие приложения на своих движках рисуют каретку сами и
// сообщают её положение только через UI Automation. Запрос идёт в чужой
// процесс, поэтому он самый медленный и стоит последним
// Browsers and other applications with their own rendering engines draw the caret
// themselves and report its position only through UI Automation. The request goes
// into another process, so it is the slowest one and comes last
private static PopupWindowNative.Rect? TryGetAutomationCaret()
{
// Зависшее приложение не должно подвешивать подсказку вместе с собой:
// ждём ответ ограниченное время, иначе показываем у курсора
// A hung application must not hang the popup along with it: we wait for the
// answer for a limited time, otherwise we show the popup at the cursor
Task<PopupWindowNative.Rect?> query = Task.Run(QueryAutomationCaret);
return query.Wait(AutomationTimeout) ? query.Result : null;
}
@@ -117,8 +117,8 @@ internal static class CaretNative
return null;
}
// У каретки выделение пустое и прямоугольника не имеет,
// поэтому расширяем его до ближайшего символа
// The caret has an empty selection and therefore no rectangle,
// so we expand it to the nearest character
TextPatternRange range = selection[0].Clone();
range.ExpandToEnclosingUnit(TextUnit.Character);
@@ -141,12 +141,12 @@ internal static class CaretNative
or InvalidOperationException
or COMException)
{
// Приложение закрылось или не отвечает — подсказку это ронять не должно
// The application closed or stopped responding — that must not take the popup down
return null;
}
}
// Системная каретка: координаты приходят относительно окна, которому она принадлежит
// The system caret: its coordinates come relative to the window that owns it
private static PopupWindowNative.Rect? TryGetSystemCaret(ForegroundInputNative.GuiThreadInfo info)
{
if (info.hwndCaret == IntPtr.Zero || IsEmpty(info.rcCaret))
@@ -170,7 +170,7 @@ internal static class CaretNative
};
}
// Каретка через средства доступности: сюда попадают браузеры и Electron
// The caret through accessibility interfaces: this is where browsers and Electron land
private static PopupWindowNative.Rect? TryGetAccessibleCaret(IntPtr hwndFocus)
{
if (hwndFocus == IntPtr.Zero)
@@ -199,7 +199,7 @@ internal static class CaretNative
}
catch (COMException)
{
// Приложение объявило поддержку, но положение не отдало
// The application declared support but did not report the position
return null;
}
finally
@@ -208,7 +208,7 @@ internal static class CaretNative
}
}
// Когда каретки нет, её прямоугольник приходит нулевой высоты.
// Судим только по высоте: нулевые координаты — это обычное начало пустого поля
private static bool IsEmpty(PopupWindowNative.Rect rect) => rect.Bottom - rect.Top <= 0;
// When there is no caret, its rectangle comes back with zero height.
// We judge by height alone: zero coordinates are a normal start of an empty field
internal static bool IsEmpty(PopupWindowNative.Rect rect) => rect.Bottom - rect.Top <= 0;
}