94 lines
3.3 KiB
C#
94 lines
3.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using Xunit;
|
|
using ytLive.Services;
|
|
|
|
namespace ytLive.Tests;
|
|
|
|
/// <summary>
|
|
/// TASK 20 integration: global hotkeys reach their commands. A real MainWindow
|
|
/// attaches the GlobalHotkeyManager (fake registrar — no OS-wide registration in
|
|
/// tests); posting a genuine WM_HOTKEY through the window's own HwndSource hook
|
|
/// must stage the mapped scene and flip the mic mute. Closing must revoke every
|
|
/// registration made.
|
|
/// </summary>
|
|
[Collection("RealApp")]
|
|
public sealed class GlobalHotkeyTests : IDisposable
|
|
{
|
|
[Fact]
|
|
public void WmHotkey_StagesScene_And_TogglesMic_And_RevokesOnClose()
|
|
{
|
|
_app.Run(Run);
|
|
}
|
|
|
|
private readonly RealAppHost _app;
|
|
|
|
public GlobalHotkeyTests(RealAppHost app) => _app = app;
|
|
|
|
private sealed class FakeRegistrar : IHotkeyRegistrar
|
|
{
|
|
public readonly List<HotkeyId> Registered = new();
|
|
public readonly List<HotkeyId> Unregistered = new();
|
|
|
|
public bool Register(IntPtr hwnd, HotkeyId id, uint modifiers, uint virtualKey)
|
|
{
|
|
Registered.Add(id);
|
|
return true;
|
|
}
|
|
|
|
public void Unregister(IntPtr hwnd, HotkeyId id) => Unregistered.Add(id);
|
|
}
|
|
|
|
private void Run()
|
|
{
|
|
var tempDb = System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"ytLlive-hotkeys-{Guid.NewGuid():N}.db");
|
|
ViewModels.MainViewModel.LayoutPathOverride = tempDb;
|
|
GlobalHotkeyManager.RegistrarOverride = () => _registrar;
|
|
var window = default(MainWindow);
|
|
try
|
|
{
|
|
using (var schema = new ytLive.Services.LayoutStore(tempDb)) { }
|
|
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
|
|
|
|
window = new MainWindow();
|
|
var vm = (ViewModels.MainViewModel)window.DataContext;
|
|
|
|
new System.Windows.Interop.WindowInteropHelper(window).EnsureHandle();
|
|
var hwnd = new System.Windows.Interop.WindowInteropHelper(window).Handle;
|
|
|
|
Assert.Equal(Enum.GetValues(typeof(HotkeyId)).Length, _registrar.Registered.Count);
|
|
|
|
SendMessage(hwnd, GlobalHotkeyManager.WM_HOTKEY, (IntPtr)HotkeyId.SceneBrb, IntPtr.Zero);
|
|
Assert.NotNull(vm.StagedScene);
|
|
Assert.Equal("BRB", vm.StagedScene!.Name);
|
|
|
|
SendMessage(hwnd, GlobalHotkeyManager.WM_HOTKEY, (IntPtr)HotkeyId.SceneLive, IntPtr.Zero);
|
|
Assert.Equal("Live", vm.StagedScene!.Name);
|
|
|
|
var wasMuted = vm.MicMuted;
|
|
SendMessage(hwnd, GlobalHotkeyManager.WM_HOTKEY, (IntPtr)HotkeyId.ToggleMicMute, IntPtr.Zero);
|
|
Assert.NotEqual(wasMuted, vm.MicMuted);
|
|
|
|
window.Close();
|
|
window = null;
|
|
Assert.Equal(_registrar.Registered.Count, _registrar.Unregistered.Count);
|
|
}
|
|
finally
|
|
{
|
|
window?.Close();
|
|
GlobalHotkeyManager.RegistrarOverride = null;
|
|
ViewModels.MainViewModel.LayoutPathOverride = null;
|
|
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
|
|
try { System.IO.File.Delete(tempDb); } catch { /* best-effort cleanup */ }
|
|
}
|
|
}
|
|
|
|
private readonly FakeRegistrar _registrar = new();
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
|
|
|
|
public void Dispose() => GC.SuppressFinalize(this);
|
|
}
|