TASK 20 step 2: hotkey config UI + modifier chord persistence + conflict detection
This commit is contained in:
@@ -31,7 +31,7 @@ public sealed class GlobalHotkeyTests : IDisposable
|
||||
public readonly List<HotkeyId> Registered = new();
|
||||
public readonly List<HotkeyId> Unregistered = new();
|
||||
|
||||
public bool Register(IntPtr hwnd, HotkeyId id, uint virtualKey)
|
||||
public bool Register(IntPtr hwnd, HotkeyId id, uint modifiers, uint virtualKey)
|
||||
{
|
||||
Registered.Add(id);
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Xunit;
|
||||
using ytLive.Services;
|
||||
|
||||
namespace ytLive.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// TASK 20 step 2 integration: custom hotkey bindings survive a DB round-trip.
|
||||
/// Save a mix of modifier chords and unbound actions to a temp LayoutStore,
|
||||
/// load them back, and verify that (a) custom chords match, (b) unbound actions
|
||||
/// are absent, and (c) actions the user didn't touch retain their defaults.
|
||||
/// </summary>
|
||||
public sealed class HotkeyConfigTests : IDisposable
|
||||
{
|
||||
private readonly string _tempDb;
|
||||
|
||||
public HotkeyConfigTests()
|
||||
{
|
||||
_tempDb = System.IO.Path.Combine(
|
||||
System.IO.Path.GetTempPath(),
|
||||
$"ytLlive-hotkeycfg-{Guid.NewGuid():N}.db");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HotkeyBindings_Persist_RoundTrip()
|
||||
{
|
||||
// Arrange: create a fresh DB
|
||||
using (new LayoutStore(_tempDb)) { }
|
||||
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
|
||||
|
||||
var bindings = new Dictionary<HotkeyId, HotkeyChord?>
|
||||
{
|
||||
[HotkeyId.SceneStarting] = new HotkeyChord(HotkeyChord.MOD_CONTROL, 0x79), // Ctrl+F10
|
||||
[HotkeyId.ToggleMicMute] = null, // explicitly unbound
|
||||
[HotkeyId.StartStopStream] = new HotkeyChord(HotkeyChord.MOD_ALT | HotkeyChord.MOD_SHIFT, 0x7B), // Alt+Shift+F12
|
||||
};
|
||||
|
||||
// Act: save then load
|
||||
using (var store = new LayoutStore(_tempDb))
|
||||
{
|
||||
store.SaveHotkeyBindings(bindings);
|
||||
}
|
||||
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
|
||||
|
||||
Dictionary<HotkeyId, HotkeyChord> loaded;
|
||||
using (var store = new LayoutStore(_tempDb))
|
||||
{
|
||||
loaded = store.LoadHotkeyBindings();
|
||||
}
|
||||
|
||||
// Assert: custom modifier chord round-trips correctly
|
||||
Assert.True(loaded.TryGetValue(HotkeyId.SceneStarting, out var sceneStarting));
|
||||
Assert.Equal(HotkeyChord.MOD_CONTROL, sceneStarting!.Modifiers);
|
||||
Assert.Equal(0x79u, sceneStarting.VirtualKey);
|
||||
|
||||
// Assert: explicitly unbound action is absent
|
||||
Assert.False(loaded.ContainsKey(HotkeyId.ToggleMicMute));
|
||||
|
||||
// Assert: multi-modifier chord round-trips correctly
|
||||
Assert.True(loaded.TryGetValue(HotkeyId.StartStopStream, out var startStop));
|
||||
Assert.Equal(HotkeyChord.MOD_ALT | HotkeyChord.MOD_SHIFT, startStop!.Modifiers);
|
||||
Assert.Equal(0x7Bu, startStop.VirtualKey);
|
||||
|
||||
// Assert: untouched actions are absent (caller fills defaults)
|
||||
Assert.False(loaded.ContainsKey(HotkeyId.SceneBrb));
|
||||
Assert.False(loaded.ContainsKey(HotkeyId.TraxPlayPause));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HotkeyChord_DisplayString_FormatsModifiers()
|
||||
{
|
||||
var ctrlF10 = new HotkeyChord(HotkeyChord.MOD_CONTROL, 0x79);
|
||||
Assert.Equal("Ctrl+F10", ctrlF10.ToDisplayString());
|
||||
|
||||
var altShiftF12 = new HotkeyChord(HotkeyChord.MOD_ALT | HotkeyChord.MOD_SHIFT, 0x7B);
|
||||
Assert.Equal("Alt+Shift+F12", altShiftF12.ToDisplayString());
|
||||
|
||||
var bareF5 = new HotkeyChord(0, 0x74);
|
||||
Assert.Equal("F5", bareF5.ToDisplayString());
|
||||
|
||||
var none = HotkeyChord.DisplayString(null);
|
||||
Assert.Equal("None", none);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HotkeyChord_StorageRoundTrip()
|
||||
{
|
||||
var original = new HotkeyChord(HotkeyChord.MOD_CONTROL | HotkeyChord.MOD_WIN, 0x7B);
|
||||
var stored = original.ToString();
|
||||
var parsed = HotkeyChord.ParseStorage(stored);
|
||||
Assert.Equal(original, parsed);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
|
||||
try { System.IO.File.Delete(_tempDb); } catch { }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user