diff --git a/Assets/Tests/Editor/MouseUiSimulationResponseFactoryTests.cs b/Assets/Tests/Editor/MouseUiSimulationResponseFactoryTests.cs
new file mode 100644
index 0000000000..f7f9ab351b
--- /dev/null
+++ b/Assets/Tests/Editor/MouseUiSimulationResponseFactoryTests.cs
@@ -0,0 +1,222 @@
+#nullable enable
+using NUnit.Framework;
+using UnityEngine;
+
+using io.github.hatayama.UnityCliLoop.FirstPartyTools;
+using io.github.hatayama.UnityCliLoop.Runtime;
+using io.github.hatayama.UnityCliLoop.ToolContracts;
+
+namespace io.github.hatayama.UnityCliLoop.Tests.Editor
+{
+ ///
+ /// Characterizes wire-visible mouse UI response construction before factory extraction.
+ ///
+ [TestFixture]
+ public sealed class MouseUiSimulationResponseFactoryTests
+ {
+ ///
+ /// Verifies generic validation failures preserve the command action and supplied message.
+ ///
+ [Test]
+ public void CreateFailure_WithCommandAndMessage_MapsFailureResponse()
+ {
+ MouseUiSimulationCommand command = CreateCommand(new SimulateMouseUiSchema
+ {
+ Action = UnityCliLoopMouseUiAction.LongPress
+ });
+
+ SimulateMouseUiResponse response =
+ MouseUiSimulationResponseFactory.CreateFailure(command, "Validation failed.");
+
+ Assert.That(response.Success, Is.False);
+ Assert.That(response.Message, Is.EqualTo("Validation failed."));
+ Assert.That(response.Action, Is.EqualTo(MouseAction.LongPress.ToString()));
+ }
+
+ ///
+ /// Verifies frame timeout responses preserve the hit and complete drag coordinates.
+ ///
+ [Test]
+ public void CreateFrameTimeoutResult_WithEndPosition_MapsAllCoordinates()
+ {
+ Vector2 position = new(10.25f, 20.75f);
+ Vector2 endPosition = new(30.5f, 40.25f);
+
+ SimulateMouseUiResponse response = MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(
+ MouseAction.Drag,
+ position,
+ endPosition,
+ "DragTarget");
+
+ Assert.That(response.Success, Is.False);
+ Assert.That(
+ response.Message,
+ Is.EqualTo(
+ $"Timed out after {UnityCliLoopConstants.EDITOR_FRAME_WAIT_TIMEOUT_MS}ms while waiting for an editor frame."));
+ Assert.That(response.Action, Is.EqualTo(MouseAction.Drag.ToString()));
+ Assert.That(response.HitGameObjectName, Is.EqualTo("DragTarget"));
+ Assert.That(response.PositionX, Is.EqualTo(position.x));
+ Assert.That(response.PositionY, Is.EqualTo(position.y));
+ Assert.That(response.EndPositionX, Is.EqualTo(endPosition.x));
+ Assert.That(response.EndPositionY, Is.EqualTo(endPosition.y));
+ }
+
+ ///
+ /// Verifies frame timeout responses keep optional hit and end coordinates absent.
+ ///
+ [Test]
+ public void CreateFrameTimeoutResult_WithoutEndPosition_LeavesOptionalFieldsNull()
+ {
+ Vector2 position = new(10.25f, 20.75f);
+
+ SimulateMouseUiResponse response = MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(
+ MouseAction.Click,
+ position,
+ null,
+ null);
+
+ Assert.That(response.Action, Is.EqualTo(MouseAction.Click.ToString()));
+ Assert.That(response.HitGameObjectName, Is.Null);
+ Assert.That(response.EndPositionX, Is.Null);
+ Assert.That(response.EndPositionY, Is.Null);
+ }
+
+ ///
+ /// Verifies click results retain normal, bypass, and no-hit message contracts.
+ ///
+ [TestCase(false, true, "ClickTarget", "", "Clicked 'ClickTarget' at (10.3, 20.8)")]
+ [TestCase(true, true, "ClickTarget", "Canvas/ClickTarget", "Bypass-clicked 'ClickTarget' at (10.3, 20.8) via 'Canvas/ClickTarget'")]
+ [TestCase(false, false, null, "", "Clicked at (10.3, 20.8) - no UI element hit")]
+ public void CreateClickResult_WithHitMode_MapsMessageAndFields(
+ bool bypassRaycast,
+ bool hitTarget,
+ string? targetName,
+ string targetPath,
+ string expectedMessage)
+ {
+ MouseUiSimulationCommand command = CreateCommand(new SimulateMouseUiSchema
+ {
+ Action = UnityCliLoopMouseUiAction.Click,
+ BypassRaycast = bypassRaycast,
+ TargetPath = targetPath
+ });
+ Vector2 position = new(10.25f, 20.75f);
+
+ SimulateMouseUiResponse response =
+ MouseUiSimulationResponseFactory.CreateClickResult(command, position, targetName, hitTarget);
+
+ Assert.That(response.Success, Is.True);
+ Assert.That(response.Message, Is.EqualTo(expectedMessage));
+ Assert.That(response.Action, Is.EqualTo(MouseAction.Click.ToString()));
+ Assert.That(response.HitGameObjectName, Is.EqualTo(targetName));
+ Assert.That(response.PositionX, Is.EqualTo(position.x));
+ Assert.That(response.PositionY, Is.EqualTo(position.y));
+ }
+
+ ///
+ /// Verifies long-press results retain normal, bypass, and no-hit message contracts.
+ ///
+ [TestCase(false, true, "PressTarget", "", "Long-pressed 'PressTarget' at (10.3, 20.8) for 1.3s")]
+ [TestCase(true, true, "PressTarget", "Canvas/PressTarget", "Bypass-long-pressed 'PressTarget' at (10.3, 20.8) via 'Canvas/PressTarget' for 1.3s")]
+ [TestCase(false, false, null, "", "Long-pressed at (10.3, 20.8) for 1.3s - no UI element hit")]
+ public void CreateLongPressResult_WithHitMode_MapsMessageAndFields(
+ bool bypassRaycast,
+ bool hitTarget,
+ string? targetName,
+ string targetPath,
+ string expectedMessage)
+ {
+ MouseUiSimulationCommand command = CreateCommand(new SimulateMouseUiSchema
+ {
+ Action = UnityCliLoopMouseUiAction.LongPress,
+ BypassRaycast = bypassRaycast,
+ TargetPath = targetPath,
+ Duration = 1.25f
+ });
+ Vector2 position = new(10.25f, 20.75f);
+
+ SimulateMouseUiResponse response =
+ MouseUiSimulationResponseFactory.CreateLongPressResult(command, position, targetName, hitTarget);
+
+ Assert.That(response.Success, Is.True);
+ Assert.That(response.Message, Is.EqualTo(expectedMessage));
+ Assert.That(response.Action, Is.EqualTo(MouseAction.LongPress.ToString()));
+ Assert.That(response.HitGameObjectName, Is.EqualTo(targetName));
+ Assert.That(response.PositionX, Is.EqualTo(position.x));
+ Assert.That(response.PositionY, Is.EqualTo(position.y));
+ }
+
+ ///
+ /// Verifies one-shot drag results retain normal and bypass message contracts.
+ ///
+ [TestCase(false, "", "Dragged 'DragTarget' from (10.3, 20.8) to (30.5, 40.3) at 125 px/s")]
+ [TestCase(true, "Canvas/DragTarget", "Bypass-dragged 'DragTarget' from (10.3, 20.8) to (30.5, 40.3) via 'Canvas/DragTarget' at 125 px/s")]
+ public void CreateDragResult_WithBypassMode_MapsMessageAndFields(
+ bool bypassRaycast,
+ string targetPath,
+ string expectedMessage)
+ {
+ MouseUiSimulationCommand command = CreateCommand(new SimulateMouseUiSchema
+ {
+ Action = UnityCliLoopMouseUiAction.Drag,
+ BypassRaycast = bypassRaycast,
+ TargetPath = targetPath,
+ DragSpeed = 125f
+ });
+ Vector2 startPosition = new(10.25f, 20.75f);
+ Vector2 endPosition = new(30.5f, 40.25f);
+
+ SimulateMouseUiResponse response = MouseUiSimulationResponseFactory.CreateDragResult(
+ command,
+ startPosition,
+ endPosition,
+ "DragTarget");
+
+ Assert.That(response.Success, Is.True);
+ Assert.That(response.Message, Is.EqualTo(expectedMessage));
+ Assert.That(response.Action, Is.EqualTo(MouseAction.Drag.ToString()));
+ Assert.That(response.HitGameObjectName, Is.EqualTo("DragTarget"));
+ Assert.That(response.PositionX, Is.EqualTo(startPosition.x));
+ Assert.That(response.PositionY, Is.EqualTo(startPosition.y));
+ Assert.That(response.EndPositionX, Is.EqualTo(endPosition.x));
+ Assert.That(response.EndPositionY, Is.EqualTo(endPosition.y));
+ }
+
+ ///
+ /// Verifies drag-end results preserve the final position and speed message.
+ ///
+ [Test]
+ public void CreateDragEndResult_WithFinalPosition_MapsMessageAndFields()
+ {
+ MouseUiSimulationCommand command = CreateCommand(new SimulateMouseUiSchema
+ {
+ Action = UnityCliLoopMouseUiAction.DragEnd,
+ DragSpeed = 125f
+ });
+ Vector2 endPosition = new(30.5f, 40.25f);
+
+ SimulateMouseUiResponse response = MouseUiSimulationResponseFactory.CreateDragEndResult(
+ command,
+ endPosition,
+ "DragTarget");
+
+ Assert.That(response.Success, Is.True);
+ Assert.That(
+ response.Message,
+ Is.EqualTo("Drag ended on 'DragTarget' at (30.5, 40.3) at 125 px/s"));
+ Assert.That(response.Action, Is.EqualTo(MouseAction.DragEnd.ToString()));
+ Assert.That(response.HitGameObjectName, Is.EqualTo("DragTarget"));
+ Assert.That(response.PositionX, Is.EqualTo(endPosition.x));
+ Assert.That(response.PositionY, Is.EqualTo(endPosition.y));
+ }
+
+ private static MouseUiSimulationCommand CreateCommand(SimulateMouseUiSchema schema)
+ {
+ (MouseUiSimulationCommand? command, string? errorMessage) =
+ MouseUiSimulationCommand.TryFromSchema(schema);
+ Assert.That(errorMessage, Is.Null);
+ Assert.That(command, Is.Not.Null);
+ return command!;
+ }
+ }
+}
diff --git a/Assets/Tests/Editor/MouseUiSimulationResponseFactoryTests.cs.meta b/Assets/Tests/Editor/MouseUiSimulationResponseFactoryTests.cs.meta
new file mode 100644
index 0000000000..34e14adcc8
--- /dev/null
+++ b/Assets/Tests/Editor/MouseUiSimulationResponseFactoryTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e8a4d821c67342d4ab063457c70d4072
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/MouseUiSimulationResponseFactory.cs b/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/MouseUiSimulationResponseFactory.cs
new file mode 100644
index 0000000000..739f75311b
--- /dev/null
+++ b/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/MouseUiSimulationResponseFactory.cs
@@ -0,0 +1,124 @@
+#nullable enable
+using UnityEngine;
+
+using io.github.hatayama.UnityCliLoop.Runtime;
+using io.github.hatayama.UnityCliLoop.ToolContracts;
+
+namespace io.github.hatayama.UnityCliLoop.FirstPartyTools
+{
+ ///
+ /// Creates wire-visible responses for mouse UI simulation outcomes.
+ ///
+ internal static class MouseUiSimulationResponseFactory
+ {
+ internal static SimulateMouseUiResponse CreateFailure(
+ MouseUiSimulationCommand parameters,
+ string message)
+ {
+ return new SimulateMouseUiResponse
+ {
+ Success = false,
+ Message = message,
+ Action = parameters.Action.ToString()
+ };
+ }
+
+ internal static SimulateMouseUiResponse CreateFrameTimeoutResult(
+ MouseAction action,
+ Vector2 position,
+ Vector2? endPosition,
+ string? hitGameObjectName)
+ {
+ return new SimulateMouseUiResponse
+ {
+ Success = false,
+ Message = $"Timed out after {UnityCliLoopConstants.EDITOR_FRAME_WAIT_TIMEOUT_MS}ms while waiting for an editor frame.",
+ Action = action.ToString(),
+ HitGameObjectName = hitGameObjectName,
+ PositionX = position.x,
+ PositionY = position.y,
+ EndPositionX = endPosition.HasValue ? endPosition.Value.x : null,
+ EndPositionY = endPosition.HasValue ? endPosition.Value.y : null
+ };
+ }
+
+ internal static SimulateMouseUiResponse CreateClickResult(
+ MouseUiSimulationCommand parameters,
+ Vector2 inputPos,
+ string? targetName,
+ bool hitTarget)
+ {
+ return new SimulateMouseUiResponse
+ {
+ Success = true,
+ Message = hitTarget
+ ? parameters.BypassRaycast
+ ? $"Bypass-clicked '{targetName}' at ({inputPos.x:F1}, {inputPos.y:F1}) via '{parameters.TargetPath}'"
+ : $"Clicked '{targetName}' at ({inputPos.x:F1}, {inputPos.y:F1})"
+ : $"Clicked at ({inputPos.x:F1}, {inputPos.y:F1}) - no UI element hit",
+ Action = MouseAction.Click.ToString(),
+ HitGameObjectName = targetName,
+ PositionX = inputPos.x,
+ PositionY = inputPos.y
+ };
+ }
+
+ internal static SimulateMouseUiResponse CreateLongPressResult(
+ MouseUiSimulationCommand parameters,
+ Vector2 inputPos,
+ string? targetName,
+ bool hitTarget)
+ {
+ return new SimulateMouseUiResponse
+ {
+ Success = true,
+ Message = hitTarget
+ ? parameters.BypassRaycast
+ ? $"Bypass-long-pressed '{targetName}' at ({inputPos.x:F1}, {inputPos.y:F1}) via '{parameters.TargetPath}' for {parameters.Duration:F1}s"
+ : $"Long-pressed '{targetName}' at ({inputPos.x:F1}, {inputPos.y:F1}) for {parameters.Duration:F1}s"
+ : $"Long-pressed at ({inputPos.x:F1}, {inputPos.y:F1}) for {parameters.Duration:F1}s - no UI element hit",
+ Action = MouseAction.LongPress.ToString(),
+ HitGameObjectName = targetName,
+ PositionX = inputPos.x,
+ PositionY = inputPos.y
+ };
+ }
+
+ internal static SimulateMouseUiResponse CreateDragResult(
+ MouseUiSimulationCommand parameters,
+ Vector2 inputStart,
+ Vector2 inputEnd,
+ string targetName)
+ {
+ return new SimulateMouseUiResponse
+ {
+ Success = true,
+ Message = parameters.BypassRaycast
+ ? $"Bypass-dragged '{targetName}' from ({inputStart.x:F1}, {inputStart.y:F1}) to ({inputEnd.x:F1}, {inputEnd.y:F1}) via '{parameters.TargetPath}' at {parameters.DragSpeed:F0} px/s"
+ : $"Dragged '{targetName}' from ({inputStart.x:F1}, {inputStart.y:F1}) to ({inputEnd.x:F1}, {inputEnd.y:F1}) at {parameters.DragSpeed:F0} px/s",
+ Action = MouseAction.Drag.ToString(),
+ HitGameObjectName = targetName,
+ PositionX = inputStart.x,
+ PositionY = inputStart.y,
+ EndPositionX = inputEnd.x,
+ EndPositionY = inputEnd.y
+ };
+ }
+
+ internal static SimulateMouseUiResponse CreateDragEndResult(
+ MouseUiSimulationCommand parameters,
+ Vector2 inputEnd,
+ string targetName)
+ {
+ return new SimulateMouseUiResponse
+ {
+ Success = true,
+ Message = $"Drag ended on '{targetName}' at ({inputEnd.x:F1}, {inputEnd.y:F1}) at {parameters.DragSpeed:F0} px/s",
+ Action = MouseAction.DragEnd.ToString(),
+ HitGameObjectName = targetName,
+ PositionX = inputEnd.x,
+ PositionY = inputEnd.y
+ };
+ }
+ }
+}
diff --git a/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/MouseUiSimulationResponseFactory.cs.meta b/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/MouseUiSimulationResponseFactory.cs.meta
new file mode 100644
index 0000000000..1014954af7
--- /dev/null
+++ b/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/MouseUiSimulationResponseFactory.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b56a2e6129684475a65e9cfdfa18ccfd
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/MouseUiSimulationValidator.cs b/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/MouseUiSimulationValidator.cs
index 0c1d16be2d..0a0b3db02d 100644
--- a/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/MouseUiSimulationValidator.cs
+++ b/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/MouseUiSimulationValidator.cs
@@ -20,12 +20,12 @@ internal static class MouseUiSimulationValidator
PlayModeToolPreflightService.RequireActiveAndNotPaused(pausedActionDescription);
if (!playModeResult.IsValid)
{
- return CreateFailure(parameters, playModeResult.ErrorMessage);
+ return MouseUiSimulationResponseFactory.CreateFailure(parameters, playModeResult.ErrorMessage);
}
if (eventSystem == null)
{
- return CreateFailure(
+ return MouseUiSimulationResponseFactory.CreateFailure(
parameters,
"No EventSystem found in the scene. Ensure an EventSystem GameObject exists.");
}
@@ -40,48 +40,36 @@ internal static class MouseUiSimulationValidator
return null;
}
- return CreateFailure(
+ return MouseUiSimulationResponseFactory.CreateFailure(
parameters,
$"Cannot {parameters.Action.ToString()} while a split drag is active. Call DragEnd first.");
}
- internal static SimulateMouseUiResponse CreateFailure(
- MouseUiSimulationCommand parameters,
- string message)
- {
- return new SimulateMouseUiResponse
- {
- Success = false,
- Message = message,
- Action = parameters.Action.ToString()
- };
- }
-
private static SimulateMouseUiResponse? ValidateSimulationRequestOptions(
MouseUiSimulationCommand parameters)
{
if (parameters.Action != MouseAction.Click && parameters.Action != MouseAction.LongPress && parameters.DragSpeed < 0f)
{
- return CreateFailure(parameters, $"DragSpeed must be non-negative, got: {parameters.DragSpeed}");
+ return MouseUiSimulationResponseFactory.CreateFailure(parameters, $"DragSpeed must be non-negative, got: {parameters.DragSpeed}");
}
if (IsDragAction(parameters.Action) && parameters.Button != MouseButton.Left)
{
- return CreateFailure(
+ return MouseUiSimulationResponseFactory.CreateFailure(
parameters,
$"Drag actions only support Left button (uGUI ignores non-left drags), got: {parameters.Button}");
}
if (parameters.BypassRaycast && !SupportsBypassRaycast(parameters.Action))
{
- return CreateFailure(parameters, "BypassRaycast is not supported for this action.");
+ return MouseUiSimulationResponseFactory.CreateFailure(parameters, "BypassRaycast is not supported for this action.");
}
if (parameters.BypassRaycast &&
RequiresBypassTargetPath(parameters.Action) &&
string.IsNullOrWhiteSpace(parameters.TargetPath))
{
- return CreateFailure(
+ return MouseUiSimulationResponseFactory.CreateFailure(
parameters,
"TargetPath is required when BypassRaycast is true for Click, LongPress, Drag, or DragStart.");
}
@@ -90,7 +78,7 @@ internal static SimulateMouseUiResponse CreateFailure(
parameters.Action != MouseAction.Drag &&
parameters.Action != MouseAction.DragEnd)
{
- return CreateFailure(parameters, "DropTargetPath supports Drag and DragEnd only.");
+ return MouseUiSimulationResponseFactory.CreateFailure(parameters, "DropTargetPath supports Drag and DragEnd only.");
}
return null;
diff --git a/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/SimulateMouseUiUseCase.cs b/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/SimulateMouseUiUseCase.cs
index d1d1ac1721..0e2afe7b94 100644
--- a/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/SimulateMouseUiUseCase.cs
+++ b/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/SimulateMouseUiUseCase.cs
@@ -140,7 +140,7 @@ private async Task ExecuteMouseAction(
default:
// Unreachable when TryFromSchema succeeds; kept as a defensive Success=false response
// instead of a throw so any future MouseAction addition surfaces as a validation failure.
- return MouseUiSimulationValidator.CreateFailure(
+ return MouseUiSimulationResponseFactory.CreateFailure(
parameters,
$"Unknown mouse action: {parameters.Action}");
}
@@ -214,7 +214,7 @@ private async Task ExecuteClick(
if (!expandCompleted)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.Click, inputPos, null, targetName);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.Click, inputPos, null, targetName);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
@@ -225,11 +225,11 @@ private async Task ExecuteClick(
if (!dissipateCompleted)
{
QueueOverlayClear();
- return CreateClickResult(parameters, inputPos, targetName, hitTarget);
+ return MouseUiSimulationResponseFactory.CreateClickResult(parameters, inputPos, targetName, hitTarget);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
- return CreateClickResult(parameters, inputPos, targetName, hitTarget);
+ return MouseUiSimulationResponseFactory.CreateClickResult(parameters, inputPos, targetName, hitTarget);
}
private async Task ExecuteLongPress(
@@ -278,7 +278,7 @@ private async Task ExecuteLongPress(
if (!expandCompleted)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.LongPress, inputPos, null, targetName);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.LongPress, inputPos, null, targetName);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
@@ -296,7 +296,7 @@ private async Task ExecuteLongPress(
if (!frameReady)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.LongPress, inputPos, null, targetName);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.LongPress, inputPos, null, targetName);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
elapsed = Time.realtimeSinceStartup - startTime;
@@ -317,11 +317,11 @@ private async Task ExecuteLongPress(
if (!dissipateCompleted)
{
QueueOverlayClear();
- return CreateLongPressResult(parameters, inputPos, targetName, hitTarget);
+ return MouseUiSimulationResponseFactory.CreateLongPressResult(parameters, inputPos, targetName, hitTarget);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
- return CreateLongPressResult(parameters, inputPos, targetName, hitTarget);
+ return MouseUiSimulationResponseFactory.CreateLongPressResult(parameters, inputPos, targetName, hitTarget);
}
private static PointerEventData CreatePointerPressData(
@@ -545,7 +545,7 @@ private async Task ExecuteDragOneShot(
if (!expandCompleted)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.Drag, inputStart, inputEnd, null);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.Drag, inputStart, inputEnd, null);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
@@ -553,7 +553,7 @@ private async Task ExecuteDragOneShot(
if (!dissipateCompleted)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.Drag, inputStart, inputEnd, null);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.Drag, inputStart, inputEnd, null);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
@@ -586,7 +586,7 @@ private async Task ExecuteDragOneShot(
if (!expandCompleted)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.Drag, inputStart, inputEnd, targetName);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.Drag, inputStart, inputEnd, targetName);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
@@ -595,7 +595,7 @@ private async Task ExecuteDragOneShot(
if (!dragCompleted)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.Drag, inputStart, inputEnd, targetName);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.Drag, inputStart, inputEnd, targetName);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
@@ -603,7 +603,7 @@ private async Task ExecuteDragOneShot(
if (!frameReady)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.Drag, inputStart, inputEnd, targetName);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.Drag, inputStart, inputEnd, targetName);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
}
@@ -619,11 +619,11 @@ private async Task ExecuteDragOneShot(
if (!completedDissipate)
{
QueueOverlayClear();
- return CreateDragResult(parameters, inputStart, inputEnd, targetName);
+ return MouseUiSimulationResponseFactory.CreateDragResult(parameters, inputStart, inputEnd, targetName);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
- return CreateDragResult(parameters, inputStart, inputEnd, targetName);
+ return MouseUiSimulationResponseFactory.CreateDragResult(parameters, inputStart, inputEnd, targetName);
}
// Lifecycle must match StandaloneInputModule: raycast → pointerUp → drop → endDrag
@@ -774,7 +774,7 @@ private async Task ExecuteDragStart(
if (!expandCompleted)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.DragStart, inputPos, null, null);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.DragStart, inputPos, null, null);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
@@ -782,7 +782,7 @@ private async Task ExecuteDragStart(
if (!dissipateCompleted)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.DragStart, inputPos, null, null);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.DragStart, inputPos, null, null);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
@@ -816,7 +816,7 @@ private async Task ExecuteDragStart(
if (!animationCompleted)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.DragStart, inputPos, null, targetName);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.DragStart, inputPos, null, targetName);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
animationCompleted = true;
@@ -888,7 +888,7 @@ private async Task ExecuteDragMove(
if (!dragCompleted)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.DragMove, inputEnd, null, targetName);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.DragMove, inputEnd, null, targetName);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
@@ -960,7 +960,7 @@ private async Task ExecuteDragEnd(
if (!dragCompleted)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.DragEnd, inputEnd, null, targetName);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.DragEnd, inputEnd, null, targetName);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
@@ -968,7 +968,7 @@ private async Task ExecuteDragEnd(
if (!frameReady)
{
QueueOverlayClear();
- return CreateFrameTimeoutResult(MouseAction.DragEnd, inputEnd, null, targetName);
+ return MouseUiSimulationResponseFactory.CreateFrameTimeoutResult(MouseAction.DragEnd, inputEnd, null, targetName);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
}
@@ -988,11 +988,11 @@ private async Task ExecuteDragEnd(
if (!dissipateCompleted)
{
QueueOverlayClear();
- return CreateDragEndResult(parameters, inputEnd, targetName);
+ return MouseUiSimulationResponseFactory.CreateDragEndResult(parameters, inputEnd, targetName);
}
await MainThreadSwitcher.SwitchToMainThread(ct);
- return CreateDragEndResult(parameters, inputEnd, targetName);
+ return MouseUiSimulationResponseFactory.CreateDragEndResult(parameters, inputEnd, targetName);
}
// User input during a CLI drag can cause Unity's StandaloneInputModule to
@@ -1128,104 +1128,6 @@ private void ExecuteCleanupOnMainThread(Action cleanup)
context.Post(_ => cleanup(), null);
}
- private static SimulateMouseUiResponse CreateFrameTimeoutResult(
- MouseAction action,
- Vector2 position,
- Vector2? endPosition,
- string? hitGameObjectName)
- {
- return new SimulateMouseUiResponse
- {
- Success = false,
- Message = $"Timed out after {UnityCliLoopConstants.EDITOR_FRAME_WAIT_TIMEOUT_MS}ms while waiting for an editor frame.",
- Action = action.ToString(),
- HitGameObjectName = hitGameObjectName,
- PositionX = position.x,
- PositionY = position.y,
- EndPositionX = endPosition.HasValue ? endPosition.Value.x : null,
- EndPositionY = endPosition.HasValue ? endPosition.Value.y : null
- };
- }
-
- private static SimulateMouseUiResponse CreateClickResult(
- MouseUiSimulationCommand parameters,
- Vector2 inputPos,
- string? targetName,
- bool hitTarget)
- {
- return new SimulateMouseUiResponse
- {
- Success = true,
- Message = hitTarget
- ? parameters.BypassRaycast
- ? $"Bypass-clicked '{targetName}' at ({inputPos.x:F1}, {inputPos.y:F1}) via '{parameters.TargetPath}'"
- : $"Clicked '{targetName}' at ({inputPos.x:F1}, {inputPos.y:F1})"
- : $"Clicked at ({inputPos.x:F1}, {inputPos.y:F1}) - no UI element hit",
- Action = MouseAction.Click.ToString(),
- HitGameObjectName = targetName,
- PositionX = inputPos.x,
- PositionY = inputPos.y
- };
- }
-
- private static SimulateMouseUiResponse CreateLongPressResult(
- MouseUiSimulationCommand parameters,
- Vector2 inputPos,
- string? targetName,
- bool hitTarget)
- {
- return new SimulateMouseUiResponse
- {
- Success = true,
- Message = hitTarget
- ? parameters.BypassRaycast
- ? $"Bypass-long-pressed '{targetName}' at ({inputPos.x:F1}, {inputPos.y:F1}) via '{parameters.TargetPath}' for {parameters.Duration:F1}s"
- : $"Long-pressed '{targetName}' at ({inputPos.x:F1}, {inputPos.y:F1}) for {parameters.Duration:F1}s"
- : $"Long-pressed at ({inputPos.x:F1}, {inputPos.y:F1}) for {parameters.Duration:F1}s - no UI element hit",
- Action = MouseAction.LongPress.ToString(),
- HitGameObjectName = targetName,
- PositionX = inputPos.x,
- PositionY = inputPos.y
- };
- }
-
- private static SimulateMouseUiResponse CreateDragResult(
- MouseUiSimulationCommand parameters,
- Vector2 inputStart,
- Vector2 inputEnd,
- string targetName)
- {
- return new SimulateMouseUiResponse
- {
- Success = true,
- Message = parameters.BypassRaycast
- ? $"Bypass-dragged '{targetName}' from ({inputStart.x:F1}, {inputStart.y:F1}) to ({inputEnd.x:F1}, {inputEnd.y:F1}) via '{parameters.TargetPath}' at {parameters.DragSpeed:F0} px/s"
- : $"Dragged '{targetName}' from ({inputStart.x:F1}, {inputStart.y:F1}) to ({inputEnd.x:F1}, {inputEnd.y:F1}) at {parameters.DragSpeed:F0} px/s",
- Action = MouseAction.Drag.ToString(),
- HitGameObjectName = targetName,
- PositionX = inputStart.x,
- PositionY = inputStart.y,
- EndPositionX = inputEnd.x,
- EndPositionY = inputEnd.y
- };
- }
-
- private static SimulateMouseUiResponse CreateDragEndResult(
- MouseUiSimulationCommand parameters,
- Vector2 inputEnd,
- string targetName)
- {
- return new SimulateMouseUiResponse
- {
- Success = true,
- Message = $"Drag ended on '{targetName}' at ({inputEnd.x:F1}, {inputEnd.y:F1}) at {parameters.DragSpeed:F0} px/s",
- Action = MouseAction.DragEnd.ToString(),
- HitGameObjectName = targetName,
- PositionX = inputEnd.x,
- PositionY = inputEnd.y
- };
- }
-
private static RaycastResult? RaycastUI(Vector2 screenPosition, EventSystem eventSystem)
{
return UiRaycastHelper.RaycastUI(screenPosition, eventSystem);