fix(client): restore retail interaction parity
All checks were successful
CI / linux-portable (push) Successful in 3m27s
CI / windows-gate (push) Successful in 6m42s
CI / release (push) Successful in 2m12s

Harden keyboard and camera routing, inventory and vendor interactions, chat/emotes, relog portal flow, and paperdoll rendering. Add retail research, connected gate coverage, and release-gate validation.
This commit is contained in:
Erik 2026-08-26 20:45:11 +02:00
parent 0c699240e0
commit f6fe0f2a4f
151 changed files with 10162 additions and 1211 deletions

View file

@ -12,8 +12,8 @@ namespace AcDream.UI.Abstractions.Tests.Input;
/// non-modifier chord is reported via the supplied callback and the
/// dispatcher does NOT fire normal action events for that chord. Esc
/// cancels capture (callback receives a sentinel <c>default</c> chord).
/// Modifier-only key transitions don't complete capture — the user can
/// dial in Shift / Ctrl / Alt before pressing the trigger key.
/// A modifier key is captured on release when used alone, or remains a
/// modifier prefix when another key is pressed while it is held.
/// </summary>
public class InputDispatcherCaptureTests
{
@ -93,6 +93,23 @@ public class InputDispatcherCaptureTests
Assert.Equal(new KeyChord(Key.A, ModifierMask.Shift | ModifierMask.Ctrl), captured!.Value);
}
[Fact]
public void BeginCapture_modifier_released_alone_becomes_bare_primary_key()
{
var (dispatcher, kb, _, _, fired) = Build();
KeyChord? captured = null;
dispatcher.BeginCapture(chord => captured = chord);
kb.EmitKeyDown(Key.ShiftLeft, ModifierMask.Shift);
Assert.Null(captured);
kb.EmitKeyUp(Key.ShiftLeft, ModifierMask.Shift);
Assert.Equal(
new KeyChord(Key.ShiftLeft, ModifierMask.None),
captured);
Assert.Empty(fired);
}
[Fact]
public void BeginCapture_completes_with_modifier_state()
{
@ -106,6 +123,26 @@ public class InputDispatcherCaptureTests
Assert.Equal(new KeyChord(Key.A, ModifierMask.Ctrl), captured!.Value);
}
[Fact]
public void BeginCapture_consumes_mouse_button_as_retail_qualified_control()
{
var (dispatcher, _, mouse, bindings, fired) = Build();
var left = new KeyChord(
InputDispatcher.MouseButtonToKey(MouseButton.Left),
ModifierMask.Ctrl,
Device: 1);
bindings.Add(new Binding(left, InputAction.ToggleInventoryPanel));
mouse.WantCaptureMouse = true;
KeyChord? captured = null;
dispatcher.BeginCapture(chord => captured = chord);
mouse.EmitMouseDown(MouseButton.Left, ModifierMask.Ctrl);
Assert.Equal(left, captured);
Assert.False(dispatcher.IsCapturing);
Assert.Empty(fired);
}
[Fact]
public void CancelCapture_invokes_callback_with_default_chord_and_clears_state()
{