using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Loader;
using System.Security.Cryptography;
using Mono.Cecil;
using Mono.Cecil.Cil;
using XFESystem.Core;
using XFESystem.Desktop;
using XFESystem.Kernel;
using Xunit;
namespace XFESystem.Desktop.Platform.Tests;
///
/// Executes the pinned driver's real boot-report differ and HID usage map.
/// Only its final Report sink is redirected to the real desktop capture queue;
/// this verifies the software boundary, not an xHCI/Corsair hardware transfer.
///
public sealed class UsbHidShortcutTests
{
private sealed class Canvas : IDesktopCanvas
{
public int Width => 1280;
public int Height => 800;
public void Fill(uint rgb, int x, int y, int width, int height) { }
public void Line(uint rgb, int x1, int y1, int x2, int y2) { }
public void Text(string text, uint rgb, int x, int y) { }
public void Present() { }
}
private sealed class Web : IBrowserService, IInteractiveBrowserFactory, IInteractiveBrowserSession
{
public readonly List Keys = [];
public BrowserPage CurrentPage { get; private set; } = new("about:Start", "Test", "");
public long Revision => 0;
public double DocumentHeight => 0;
public IInteractiveBrowserSession CreatePageSession() => this;
public BrowserPage Navigate(string address) => CurrentPage = new(address, "Test", "");
public BrowserPage NavigateEditor(string source, string path) => CurrentPage = new(path, "Test", source);
public string? ReadEditorText() => CurrentPage.Text;
public string ExecuteJavaScript(string source) => "";
public string PreviewMarkdown(string markdown) => markdown;
public void Paint(IDesktopCanvas canvas, DesktopBounds viewport, double scrollY) { }
public bool Pointer(BrowserPointerInput input) => false;
public bool Key(BrowserKeyboardInput input) { Keys.Add(input); return true; }
public bool AdvanceTime(long monotonicMilliseconds) => false;
}
private sealed class DriverBoundary : IDisposable
{
private delegate void ReportHandler(ReadOnlySpan report);
private readonly AssemblyLoadContext context = new("PinnedUsbBootReports-" + Guid.NewGuid().ToString("N"), true);
private readonly string packages, source, originalHash, patched;
private readonly ReportHandler onReport;
public DriverBoundary()
{
packages = Environment.GetEnvironmentVariable("NUGET_PACKAGES") ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages");
source = PackageAssembly("Cosmos.Kernel.Drivers");
originalHash = Hash(source);
string directory = Path.Combine(AppContext.BaseDirectory, "PatchFixtures", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(directory);
patched = Path.Combine(directory, "Cosmos.Kernel.Drivers.dll");
using (var driver = AssemblyDefinition.ReadAssembly(source, new ReaderParameters { InMemory = true }))
{
var type = driver.MainModule.Types.Single(t => t.FullName == "Cosmos.Kernel.Drivers.Usb.Input.UsbKeyboard.UsbKeyboardState");
var output = type.Methods.Single(m => m.Name == "Report");
Assert.Equal(new[] { MetadataType.Byte, MetadataType.Boolean }, output.Parameters.Select(p => p.ParameterType.MetadataType));
output.Body = new Mono.Cecil.Cil.MethodBody(output);
var il = output.Body.GetILProcessor();
il.Append(il.Create(OpCodes.Ldarg_1)); il.Append(il.Create(OpCodes.Ldarg_2));
il.Append(il.Create(OpCodes.Call, driver.MainModule.ImportReference(typeof(NativeKeyboardCapture).GetMethod(nameof(NativeKeyboardCapture.Observe))!)));
il.Append(il.Create(OpCodes.Ret));
driver.Write(patched);
}
context.Resolving += (_, name) => name.Name == typeof(NativeKeyboardCapture).Assembly.GetName().Name
? typeof(NativeKeyboardCapture).Assembly
: name.Name?.StartsWith("Cosmos.", StringComparison.Ordinal) == true ? context.LoadFromAssemblyPath(PackageAssembly(name.Name)) : null;
var assembly = context.LoadFromAssemblyPath(patched);
var stateType = assembly.GetType("Cosmos.Kernel.Drivers.Usb.Input.UsbKeyboard.UsbKeyboardState", true)!;
var state = RuntimeHelpers.GetUninitializedObject(stateType);
stateType.GetField("_previousReport", BindingFlags.Instance | BindingFlags.NonPublic)!.SetValue(state, new byte[8]);
onReport = stateType.GetMethod("OnReport", BindingFlags.Instance | BindingFlags.NonPublic)!.CreateDelegate(state);
while (NativeKeyboardCapture.TryRead(out _, out _, out _)) { }
}
public void Send(NativeDesktopInput router, DesktopSession session, byte modifiers, params byte[] usages)
{
byte[] report = new byte[8]; report[0] = modifiers;
usages.AsSpan().CopyTo(report.AsSpan(2)); onReport(report);
while (NativeKeyboardCapture.TryRead(out var scan, out var released, out var lost))
if (router.Translate(scan, released, lost, session, out var character) is { } key) session.Key(key, character);
}
private string PackageAssembly(string name)
{
string root = Path.Combine(packages, name.ToLowerInvariant(), "3.0.94");
string runtime = Path.Combine(root, "runtimes", "linux-x64", "lib", "net10.0", name + ".dll");
return File.Exists(runtime) ? runtime : Path.Combine(root, "lib", "net10.0", name + ".dll");
}
private static string Hash(string path) => Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(path)));
public void Dispose() { Assert.Equal(originalHash, Hash(source)); context.Unload(); }
}
[Theory]
[InlineData((byte)0x08)]
[InlineData((byte)0x80)]
public void RealUsbGuiReportOpensStartOnRelease(byte modifier)
{
using var usb = new DriverBoundary(); var input = new NativeDesktopInput(); var desktop = new DesktopSession(new Canvas(), new MemoryWorkspace());
usb.Send(input, desktop, modifier); Assert.False(desktop.IsStartMenuOpen);
usb.Send(input, desktop, 0); Assert.True(desktop.IsStartMenuOpen);
usb.Send(input, desktop, 0); Assert.True(desktop.IsStartMenuOpen);
}
[Theory]
[InlineData((byte)0x04)]
[InlineData((byte)0x40)]
public void RealUsbAltTabWinsOverFocusedWebEditorAndCommitsOnAltRelease(byte modifier)
{
using var usb = new DriverBoundary(); var web = new Web(); var desktop = new DesktopSession(new Canvas(), new MemoryWorkspace(), web);
var files = desktop.Open(DesktopApplication.Files);
var editor = desktop.Open(DesktopApplication.Editor, SystemPaths.Combine(SystemPaths.Documents, "Hello.cs"));
desktop.Open(DesktopApplication.Browser);
var input = new NativeDesktopInput();
usb.Send(input, desktop, modifier, 0x2B); Assert.Same(editor, desktop.ActiveWindow); Assert.True(desktop.IsWindowSwitching);
usb.Send(input, desktop, modifier); usb.Send(input, desktop, modifier, 0x2B); Assert.Same(files, desktop.ActiveWindow);
usb.Send(input, desktop, 0); Assert.False(desktop.IsWindowSwitching);
Assert.DoesNotContain(web.Keys, key => key.Code == "Tab" || key.Key == "Tab");
Assert.DoesNotContain(web.Keys, key => key.Text.Contains('\t'));
}
[Theory]
[InlineData((byte)0x08)]
[InlineData((byte)0x80)]
public void RealUsbWinEReleaseInSameReportDoesNotLeakUnmatchedEditorKeyup(byte modifier)
{
using var usb = new DriverBoundary(); var web = new Web(); var desktop = new DesktopSession(new Canvas(), new MemoryWorkspace(), web);
desktop.Open(DesktopApplication.Editor, SystemPaths.Combine(SystemPaths.Documents, "Hello.cs"));
var input = new NativeDesktopInput();
usb.Send(input, desktop, modifier, 0x08); Assert.Equal(DesktopApplication.Files, desktop.ActiveWindow!.Application);
// Re-focus a web editor before the combined modifier/key break arrives.
desktop.Open(DesktopApplication.Editor, SystemPaths.Combine(SystemPaths.Documents, "Hello.cs"));
usb.Send(input, desktop, 0);
Assert.False(desktop.IsStartMenuOpen);
Assert.DoesNotContain(web.Keys, key => key.Code == "KeyE");
}
[Fact]
public void RealUsbShiftAltTabReversesAndKeepsSwitchUntilBothAltsRelease()
{
using var usb = new DriverBoundary(); var desktop = new DesktopSession(new Canvas(), new MemoryWorkspace());
var files = desktop.Open(DesktopApplication.Files);
desktop.Open(DesktopApplication.Editor); desktop.Open(DesktopApplication.Terminal);
var input = new NativeDesktopInput();
usb.Send(input, desktop, 0x46, 0x2B); // LShift + LAlt + RAlt + Tab
Assert.Same(files, desktop.ActiveWindow); Assert.True(desktop.IsWindowSwitching);
usb.Send(input, desktop, 0x40); Assert.True(desktop.IsWindowSwitching);
usb.Send(input, desktop, 0); Assert.False(desktop.IsWindowSwitching);
}
[Fact]
public void RealUsbWinDMinimizesAllWindowsWithoutOpeningStart()
{
using var usb = new DriverBoundary(); var desktop = new DesktopSession(new Canvas(), new MemoryWorkspace());
var files = desktop.Open(DesktopApplication.Files); var editor = desktop.Open(DesktopApplication.Editor);
var input = new NativeDesktopInput();
usb.Send(input, desktop, 0x08, 0x07);
Assert.True(files.IsMinimized); Assert.True(editor.IsMinimized);
usb.Send(input, desktop, 0); Assert.False(desktop.IsStartMenuOpen);
}
[Fact]
public void UnsupportedWindowsChordDoesNotLeakItsBreakIntoWebEditor()
{
using var usb = new DriverBoundary(); var web = new Web(); var desktop = new DesktopSession(new Canvas(), new MemoryWorkspace(), web);
desktop.Open(DesktopApplication.Editor, SystemPaths.Combine(SystemPaths.Documents, "Hello.cs"));
var input = new NativeDesktopInput();
usb.Send(input, desktop, 0x08, 0x14); // Win+Q has no command yet.
usb.Send(input, desktop, 0);
Assert.False(desktop.IsStartMenuOpen);
Assert.DoesNotContain(web.Keys, key => key.Code == "KeyQ");
}
[Fact]
public void ControlEscapeIsSystemOwnedEvenWhenWebEditorHasFocus()
{
using var usb = new DriverBoundary(); var web = new Web(); var desktop = new DesktopSession(new Canvas(), new MemoryWorkspace(), web);
desktop.Open(DesktopApplication.Editor, SystemPaths.Combine(SystemPaths.Documents, "Hello.cs"));
var input = new NativeDesktopInput();
usb.Send(input, desktop, 0x01, 0x29); Assert.True(desktop.IsStartMenuOpen);
usb.Send(input, desktop, 0);
Assert.DoesNotContain(web.Keys, key => key.Key == "Escape");
}
[Fact]
public void ShortcutDiagnosticsExposeOnlySystemCodesAndDispatch()
{
var trace = new List(); var input = new NativeDesktopInput { Trace = trace.Add }; var desktop = new DesktopSession(new Canvas(), new MemoryWorkspace());
input.Translate(0x5B, false, false, desktop, out _);
Assert.Equal(DesktopKey.OpenFiles, input.Translate(0x12, false, false, desktop, out _));
Assert.Contains(trace, line => line.Contains("XFE_NATIVE_SHORTCUT|Desktop|Scan|18|Released|0|Key|OpenFiles", StringComparison.Ordinal));
Assert.DoesNotContain(trace, line => line.Contains("KeyE", StringComparison.Ordinal));
}
}