tools(ui-probe): mouselook <dx> <dy> verb — raw mouse-look delta injection for scripted camera pitch
Issue #464 needs a repeatable tilted self-gate frame at the cathedral stair-arch pose, but the automation's `drag at`/`mousemove` verbs only move the retained-UI cursor — they never reach mouse-look, so every scripted route replays the DEFAULT camera and can't reproduce the owner's upward-tilted frame (docs/ISSUES.md #464, the 2026-09-03 22:07 transcript note: "the automation's `drag at` verb does not drive mouse-look"). Add `mouselook <dx> <dy>`: it calls the SAME GameplayInputFrameController.QueueRawMouseDelta the real mouse's Silk MouseMove callback drives (CameraPointerInputController. ProcessMouseMove), through an injected delegate threaded RetailUiAutomationScriptRunner <- RetailUiProbeBindings <- InteractionRetainedUiDependencies.GameplayInputFrame. That last seam is resolved fresh on every call rather than captured once at mount, since GameplayInputFrameController is created per live session (SessionPlayerComposition), strictly after the retained UI composes and across reconnects — the same never-capture-a-deferred-Func discipline the secure-trade command-bus regression taught (claude-memory/feedback_resolve_deferred_funcs_per_call.md). The delta only takes effect while mouse-look is active (bracket with `input down`/`up CameraInstantMouseLook`) and one call consumes exactly one raw sample on the controller's next tick, so a route must `sleep` between calls — documented on DoMouseLook and the class doc comment. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
37d1357baa
commit
ddae5704da
5 changed files with 165 additions and 7 deletions
|
|
@ -626,6 +626,98 @@ public sealed class RetailUiAutomationProbeTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScriptRunner_mouselook_injectsRawDeltaThroughDelegate()
|
||||
{
|
||||
var (root, _, _, _, objects) = RootWithTwoItemLists();
|
||||
var probe = new RetailUiAutomationProbe(root, objects);
|
||||
var logs = new List<string>();
|
||||
var deltas = new List<(float Dx, float Dy)>();
|
||||
string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".ui-probe.txt");
|
||||
File.WriteAllLines(path, ["mouselook 3 -4.5"]);
|
||||
|
||||
try
|
||||
{
|
||||
using var runner = new RetailUiAutomationScriptRunner(
|
||||
probe,
|
||||
path,
|
||||
dumpOnStart: false,
|
||||
log: logs.Add,
|
||||
queueMouseLookDelta: (dx, dy) => deltas.Add((dx, dy)));
|
||||
|
||||
runner.Tick(0d);
|
||||
|
||||
Assert.True(runner.Completed);
|
||||
Assert.Contains(logs, line => line.Contains("UI probe script complete"));
|
||||
Assert.Equal([(3f, -4.5f)], deltas);
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScriptRunner_mouselook_wrongArity_stopsWithUsageAndNeverInvokesDelegate()
|
||||
{
|
||||
var (root, _, _, _, objects) = RootWithTwoItemLists();
|
||||
var probe = new RetailUiAutomationProbe(root, objects);
|
||||
var logs = new List<string>();
|
||||
var deltas = new List<(float Dx, float Dy)>();
|
||||
string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".ui-probe.txt");
|
||||
File.WriteAllLines(path, ["mouselook 1"]);
|
||||
|
||||
try
|
||||
{
|
||||
using var runner = new RetailUiAutomationScriptRunner(
|
||||
probe,
|
||||
path,
|
||||
dumpOnStart: false,
|
||||
log: logs.Add,
|
||||
queueMouseLookDelta: (dx, dy) => deltas.Add((dx, dy)));
|
||||
|
||||
runner.Tick(0d);
|
||||
|
||||
Assert.True(runner.Completed);
|
||||
Assert.Contains(logs, line =>
|
||||
line.Contains("usage: mouselook <dx> <dy>", StringComparison.Ordinal));
|
||||
Assert.Empty(deltas);
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScriptRunner_mouselook_noDelegate_stopsAsUnavailable()
|
||||
{
|
||||
var (root, _, _, _, objects) = RootWithTwoItemLists();
|
||||
var probe = new RetailUiAutomationProbe(root, objects);
|
||||
var logs = new List<string>();
|
||||
string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".ui-probe.txt");
|
||||
File.WriteAllLines(path, ["mouselook 3 -4.5"]);
|
||||
|
||||
try
|
||||
{
|
||||
using var runner = new RetailUiAutomationScriptRunner(
|
||||
probe,
|
||||
path,
|
||||
dumpOnStart: false,
|
||||
log: logs.Add);
|
||||
|
||||
runner.Tick(0d);
|
||||
|
||||
Assert.True(runner.Completed);
|
||||
Assert.Contains(logs, line =>
|
||||
line.Contains("mouselook injection is unavailable", StringComparison.Ordinal));
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScriptRunner_dispose_releasesInjectedHeldActions()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue