lightweight variant (#1)

Reviewed-on: #1
Co-authored-by: Aleksandr Neychev <alexnejchev73@gmail.com>
This commit was merged in pull request #1.
This commit is contained in:
2026-08-12 13:37:30 +00:00
committed by alex
parent a0d3098fe4
commit 55ac8e6556
147 changed files with 4055 additions and 2349 deletions
@@ -0,0 +1,159 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using CursorLang.Core.Interop;
using CursorLang.Settings.Interop;
using CursorLang.Settings.Tests.Infrastructure;
namespace CursorLang.Settings.Tests.Interop;
/// <summary>
/// Checks that need a real foreground window with an input field: the caret
/// and the layout switch live exactly there.
/// </summary>
/// <remarks>
/// Windows does not always allow a window to come forward — when the screen is
/// locked, say, or when the run happens in a session without a desktop. In
/// those cases the check reports itself as skipped rather than failed: there
/// would be nothing to verify.
/// </remarks>
public sealed class ForegroundWindowTests
{
[Fact]
public void The_caret_in_an_input_field_is_found()
{
Sta.Run(() =>
{
using var input = new InputWindow();
input.RequireForeground();
PopupWindowNative.Rect? caret = CaretNative.TryGetCaretRect();
if (caret is null)
{
Assert.Skip("The input field did not report the caret position");
}
// The caret has to sit inside the input window and to have a height
PopupWindowNative.Rect bounds = WindowPlacementNative.TryGetBounds(input.Handle)!.Value;
Assert.True(caret.Value.Bottom > caret.Value.Top);
Assert.InRange(caret.Value.Left, bounds.Left, bounds.Right);
Assert.InRange(caret.Value.Top, bounds.Top, bounds.Bottom);
});
}
[Fact]
public void The_tooltip_at_the_caret_lands_next_to_it()
{
Sta.Run(() =>
{
using var input = new InputWindow();
input.RequireForeground();
PopupWindowNative.Rect? caret = CaretNative.TryGetCaretRect();
if (caret is null)
{
Assert.Skip("The input field did not report the caret position");
}
PopupWindowNative.Rect field =
WindowPlacementNative.TryGetBounds(input.Handle)!.Value;
Assert.True(CaretNative.IsInside(caret.Value, field),
"the caret reported by the input field is outside that field");
});
}
// The request to switch the layout goes to the window holding the input
// focus, so it only concerns the test window itself
[Fact]
public void The_request_to_change_the_layout_reaches_its_own_window()
{
Sta.Run(() =>
{
using var input = new InputWindow();
input.RequireForeground();
int before = KeyboardLayoutNative.GetActiveLocaleId();
KeyboardLayoutNative.RequestNextLayout();
Sta.Pause(TimeSpan.FromMilliseconds(150));
int after = KeyboardLayoutNative.GetActiveLocaleId();
Assert.InRange(after, 1, 0xFFFF);
if (after == before)
{
// The system may hold a single layout — there is nothing to switch to
return;
}
// Bring the layout back around the circle to where it was
for (int i = 0; i < 8 && KeyboardLayoutNative.GetActiveLocaleId() != before; i++)
{
KeyboardLayoutNative.RequestNextLayout();
Sta.Pause(TimeSpan.FromMilliseconds(150));
}
});
}
/// <summary>A window with an input field brought to the foreground.</summary>
private sealed class InputWindow : IDisposable
{
private readonly Window _window;
internal InputWindow()
{
var box = new TextBox { Text = "check", FontSize = 20 };
_window = new Window
{
Width = 400,
Height = 200,
ShowInTaskbar = false,
WindowStartupLocation = WindowStartupLocation.Manual,
Left = 100,
Top = 100,
Topmost = true,
Content = box,
};
_window.Show();
Handle = new WindowInteropHelper(_window).Handle;
// Windows grants the right to bring a window forward neither to
// everyone nor at once, so it takes a few attempts
for (int attempt = 0; attempt < 10; attempt++)
{
_window.Activate();
box.Focus();
box.CaretIndex = box.Text.Length;
Sta.Pause(TimeSpan.FromMilliseconds(50));
if (KeyboardLayoutNative.GetForegroundWindow() == Handle)
{
break;
}
}
// The caret does not appear at the same instant as the focus
Sta.Pause(TimeSpan.FromMilliseconds(100));
}
internal IntPtr Handle { get; }
/// <summary>Skips the check if the window never became the foreground one.</summary>
internal void RequireForeground()
{
if (KeyboardLayoutNative.GetForegroundWindow() != Handle)
{
Assert.Skip("The window could not be brought to the foreground");
}
}
public void Dispose() => _window.Close();
}
}
@@ -0,0 +1,212 @@
using System.Windows;
using System.Windows.Interop;
using CursorLang.Core.Interop;
using CursorLang.Settings.Interop;
using CursorLang.Settings.Tests.Infrastructure;
namespace CursorLang.Settings.Tests.Interop;
/// <summary>
/// The Win32 wrappers: what is checked is that the calls are put together
/// right — structures of the expected size, flags in place, and the answers
/// of the system read correctly.
/// </summary>
public sealed class NativeWrappersTests
{
[Fact]
public void The_cursor_position_is_read()
{
PopupWindowNative.Point cursor = PopupWindowNative.GetCursorPosition();
// The virtual screen may run into negative coordinates, but not beyond
// reason: a misread structure would give garbage
Assert.InRange(cursor.X, -32_000, 32_000);
Assert.InRange(cursor.Y, -32_000, 32_000);
}
[Fact]
public void The_scale_of_the_monitor_under_the_cursor_is_positive()
{
double scale = PopupWindowNative.GetScaleAt(PopupWindowNative.GetCursorPosition());
Assert.InRange(scale, 0.5, 8.0);
}
[Fact]
public void The_work_area_of_the_active_monitor_is_not_empty()
{
(PopupWindowNative.Rect work, double scale) = PopupWindowNative.GetActiveMonitorWorkArea();
Assert.True(work.Right > work.Left);
Assert.True(work.Bottom > work.Top);
Assert.InRange(scale, 0.5, 8.0);
}
[Fact]
public void The_window_bounds_are_read_from_the_system()
{
Sta.Run(() =>
{
using var window = new HandleWindow();
PopupWindowNative.Rect? bounds = WindowPlacementNative.TryGetBounds(window.Handle);
Assert.NotNull(bounds);
Assert.True(bounds.Value.Right > bounds.Value.Left);
Assert.True(bounds.Value.Bottom > bounds.Value.Top);
});
}
[Fact]
public void A_window_that_does_not_exist_has_no_bounds()
{
Assert.Null(WindowPlacementNative.TryGetBounds(IntPtr.Zero));
}
[Fact]
public void A_window_is_moved_to_the_given_point()
{
Sta.Run(() =>
{
using var window = new HandleWindow();
PopupWindowNative.MoveTo(window.Handle, 120, 90);
PopupWindowNative.Rect bounds = WindowPlacementNative.TryGetBounds(window.Handle)!.Value;
Assert.Equal(120, bounds.Left);
Assert.Equal(90, bounds.Top);
});
}
[Fact]
public void Moving_does_not_change_the_window_size()
{
Sta.Run(() =>
{
using var window = new HandleWindow();
PopupWindowNative.Rect before = WindowPlacementNative.TryGetBounds(window.Handle)!.Value;
PopupWindowNative.MoveTo(window.Handle, 200, 150);
PopupWindowNative.Rect after = WindowPlacementNative.TryGetBounds(window.Handle)!.Value;
Assert.Equal(before.Right - before.Left, after.Right - after.Left);
Assert.Equal(before.Bottom - before.Top, after.Bottom - after.Top);
});
}
[Fact]
public void The_work_area_is_found_by_the_rectangle_of_the_window()
{
Sta.Run(() =>
{
using var window = new HandleWindow();
PopupWindowNative.Rect bounds = WindowPlacementNative.TryGetBounds(window.Handle)!.Value;
PopupWindowNative.Rect? work = WindowPlacementNative.TryGetWorkAreaNear(bounds);
Assert.NotNull(work);
Assert.True(work.Value.Right > work.Value.Left);
Assert.True(work.Value.Bottom > work.Value.Top);
});
}
// The nearest monitor is picked, so an area is found even for a point far off screen
[Fact]
public void For_a_rectangle_off_every_screen_the_nearest_monitor_is_taken()
{
var far = new PopupWindowNative.Rect { Left = 30_000, Top = 30_000, Right = 30_100, Bottom = 30_100 };
PopupWindowNative.Rect? work = WindowPlacementNative.TryGetWorkAreaNear(far);
Assert.NotNull(work);
Assert.True(work.Value.Right > work.Value.Left);
}
[Fact]
public void The_layout_of_the_foreground_window_is_read()
{
int localeId = KeyboardLayoutNative.GetActiveLocaleId();
// The low word of the HKL is the locale identifier, and it is never zero
Assert.NotEqual(0, localeId);
Assert.InRange(localeId, 1, 0xFFFF);
}
[Fact]
public void The_layout_is_read_for_any_window()
{
int localeId = KeyboardLayoutNative.GetLocaleIdOf(KeyboardLayoutNative.GetForegroundWindow());
Assert.InRange(localeId, 0, 0xFFFF);
}
[Fact]
public void The_input_state_of_the_foreground_is_read()
{
bool received = ForegroundInputNative.TryGetInfo(out ForegroundInputNative.GuiThreadInfo info);
if (received)
{
// The structure size is filled in by the wrapper itself, and it has
// to match what Windows expects
Assert.Equal(System.Runtime.InteropServices.Marshal.SizeOf<ForegroundInputNative.GuiThreadInfo>(),
info.cbSize);
}
}
[Fact]
public void The_right_to_show_a_window_is_given_away_without_errors()
{
ForegroundPermissionNative.GrantToAnyProcess();
}
[Fact]
public void The_window_title_bar_is_repainted()
{
Sta.Run(() =>
{
using var window = new HandleWindow();
WindowThemeNative.SetDarkTitleBar(window.Handle, isDark: true);
WindowThemeNative.SetDarkTitleBar(window.Handle, isDark: false);
});
}
// The window may be gone by the time of the repaint
[Fact]
public void Repainting_a_window_that_does_not_exist_passes_silently()
{
WindowThemeNative.SetDarkTitleBar(IntPtr.Zero, isDark: true);
}
[Fact]
public void The_package_flag_is_computed_once_and_does_not_change()
{
bool first = PackageIdentityNative.IsPackaged;
Assert.Equal(first, PackageIdentityNative.IsPackaged);
}
/// <summary>A window with a created handle that never appears on screen.</summary>
private sealed class HandleWindow : IDisposable
{
private readonly Window _window;
internal HandleWindow()
{
_window = new Window
{
Width = 300,
Height = 200,
ShowInTaskbar = false,
WindowStartupLocation = WindowStartupLocation.Manual,
};
Handle = new WindowInteropHelper(_window).EnsureHandle();
}
internal IntPtr Handle { get; }
public void Dispose() => _window.Close();
}
}