From 0243f33b3a8e3b82d018c5a3471e8542a34fcb10 Mon Sep 17 00:00:00 2001 From: hatayama Date: Thu, 9 Jul 2026 11:46:36 +0900 Subject: [PATCH] Extract keyboard input action execution Move press, key-down, and key-up workflows into a stateless executor so the keyboard use case retains only validation, setup, logging, and dispatch. Preserve input update ordering, timeout escalation, and cleanup behavior. --- .../Editor/StaticFacadeStateGuardTests.cs | 3 +- .../KeyboardInputActionExecutor.cs | 311 ++++++++++++++++++ .../KeyboardInputActionExecutor.cs.meta | 11 + .../SimulateKeyboardUseCase.cs | 295 +---------------- 4 files changed, 331 insertions(+), 289 deletions(-) create mode 100644 Packages/src/Editor/FirstPartyTools/SimulateKeyboard/KeyboardInputActionExecutor.cs create mode 100644 Packages/src/Editor/FirstPartyTools/SimulateKeyboard/KeyboardInputActionExecutor.cs.meta diff --git a/Assets/Tests/Editor/StaticFacadeStateGuardTests.cs b/Assets/Tests/Editor/StaticFacadeStateGuardTests.cs index 95d3409156..6c4ce584a3 100644 --- a/Assets/Tests/Editor/StaticFacadeStateGuardTests.cs +++ b/Assets/Tests/Editor/StaticFacadeStateGuardTests.cs @@ -66,7 +66,8 @@ public sealed class StaticFacadeStateGuardTests "Packages/src/Editor/FirstPartyTools/SimulateMouseInput/MouseInputPressActionExecutor.cs", "Packages/src/Editor/FirstPartyTools/SimulateMouseInput/MouseInputMotionActionExecutor.cs", "Packages/src/Editor/FirstPartyTools/SimulateKeyboard/SimulateKeyboardUseCase.cs", - "Packages/src/Editor/FirstPartyTools/SimulateKeyboard/KeyboardInputMainThreadCleanup.cs" + "Packages/src/Editor/FirstPartyTools/SimulateKeyboard/KeyboardInputMainThreadCleanup.cs", + "Packages/src/Editor/FirstPartyTools/SimulateKeyboard/KeyboardInputActionExecutor.cs" }; private static readonly Dictionary OverloadGuardMethodsByPath = new Dictionary diff --git a/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/KeyboardInputActionExecutor.cs b/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/KeyboardInputActionExecutor.cs new file mode 100644 index 0000000000..14be89f6b7 --- /dev/null +++ b/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/KeyboardInputActionExecutor.cs @@ -0,0 +1,311 @@ +#if ULOOP_HAS_INPUT_SYSTEM +#nullable enable +using System; +using System.Threading; +using System.Threading.Tasks; +using UnityEngine.InputSystem; + +using io.github.hatayama.UnityCliLoop.Runtime; +using io.github.hatayama.UnityCliLoop.ToolContracts; + +namespace io.github.hatayama.UnityCliLoop.FirstPartyTools +{ + /// + /// Executes press, key-down, and key-up keyboard input actions. + /// + internal static class KeyboardInputActionExecutor + { + internal static async Task ExecutePress( + Keyboard keyboard, Key key, float duration, CancellationToken ct) + { + if (duration < 0f || float.IsNaN(duration) || float.IsInfinity(duration)) + { + return new SimulateKeyboardResponse + { + Success = false, + Message = $"Duration must be non-negative, got: {duration}", + Action = UnityCliLoopKeyboardAction.Press.ToString(), + KeyName = key.ToString() + }; + } + + string keyName = key.ToString(); + if (KeyboardKeyState.IsKeyHeld(key)) + { + return new SimulateKeyboardResponse + { + Success = false, + Message = $"Key '{keyName}' is already held down. Call KeyUp first.", + Action = UnityCliLoopKeyboardAction.Press.ToString(), + KeyName = keyName + }; + } + + SimulateKeyboardOverlayState.ShowPress(keyName); + KeyboardKeyState.RegisterTransientKey(key); + bool pressWasApplied = false; + bool pressEdgeObserved = false; + InputSimulationWaitOutcome waitOutcome = InputSimulationWaitOutcome.Completed; + + // The edge must be probed inside gameplay input updates: editor-tick polling can + // miss the single frame where wasPressedThisFrame is true, and an editor-update + // consumed press is exactly the failure gameplay code cannot see. + await InputSystemUpdateHelper.SwitchToMainThreadIfNeeded(ct); + Action pressEdgeMonitor = () => pressEdgeObserved |= IsGameplayPressEdgeVisible(keyboard, key); + InputSystem.onAfterUpdate += pressEdgeMonitor; + + try + { + waitOutcome = await InputSystemUpdateHelper.ApplyOnNextConfiguredUpdate( + () => KeyboardKeyState.SetKeyState(keyboard, key, true), + ct).ConfigureAwait(false); + if (waitOutcome == InputSimulationWaitOutcome.Completed) + { + pressWasApplied = true; + waitOutcome = await InputSystemUpdateHelper.WaitForPressLifetime(duration, ct) + .ConfigureAwait(false); + } + } + finally + { + await InputSystemUpdateHelper.SwitchToMainThreadIfNeeded(CancellationToken.None); + InputSystem.onAfterUpdate -= pressEdgeMonitor; + if (waitOutcome == InputSimulationWaitOutcome.TimedOut) + { + KeyboardInputMainThreadCleanup.ScheduleTimedOutPressCleanup( + keyboard, + key, + pressWasApplied); + } + else if (pressWasApplied) + { + InputSimulationWaitOutcome releaseOutcome = + await KeyboardInputMainThreadCleanup.ReleaseKeyStateIfPossible( + keyboard, + key, + CancellationToken.None).ConfigureAwait(false); + if (releaseOutcome == InputSimulationWaitOutcome.TimedOut) + { + waitOutcome = InputSimulationWaitOutcome.TimedOut; + KeyboardInputMainThreadCleanup.ScheduleTimedOutPressCleanup(keyboard, key, false); + } + else if (waitOutcome == InputSimulationWaitOutcome.Paused) + { + KeyboardKeyState.UnregisterTransientKey(key); + SimulateKeyboardOverlayState.ClearPress(); + } + else + { + KeyboardKeyState.UnregisterTransientKey(key); + await KeyboardInputMainThreadCleanup.FinalizePressOverlay(ct).ConfigureAwait(false); + } + } + else + { + KeyboardKeyState.UnregisterTransientKey(key); + SimulateKeyboardOverlayState.ClearPress(); + } + } + + if (waitOutcome == InputSimulationWaitOutcome.Paused) + { + return KeyboardInputSimulationResponseFactory.InterruptedKeyResult( + UnityCliLoopKeyboardAction.Press, + keyName, + pressEdgeObserved); + } + + if (waitOutcome == InputSimulationWaitOutcome.TimedOut) + { + return KeyboardInputSimulationResponseFactory.TimedOutKeyResult( + UnityCliLoopKeyboardAction.Press, + keyName); + } + + string durationText = duration > 0f ? $" for {InputSimulationDurationFormatter.FormatSeconds(duration)}s" : ""; + string edgeText = pressEdgeObserved + ? "" + : " (press edge was not observed via wasPressedThisFrame; gameplay polling may have missed it, so retry or verify with a focused log)"; + return new SimulateKeyboardResponse + { + Success = true, + Message = $"Pressed '{keyName}'{durationText}{edgeText}", + Action = UnityCliLoopKeyboardAction.Press.ToString(), + KeyName = keyName, + PressEdgeObserved = pressEdgeObserved + }; + } + + internal static async Task ExecuteKeyDown( + Keyboard keyboard, + Key key, + CancellationToken ct) + { + string keyName = key.ToString(); + + if (KeyboardKeyState.IsKeyHeld(key)) + { + return new SimulateKeyboardResponse + { + Success = false, + Message = $"Key '{keyName}' is already held down. Call KeyUp first.", + Action = UnityCliLoopKeyboardAction.KeyDown.ToString(), + KeyName = keyName + }; + } + + bool keyDownApplied = false; + bool committed = false; + bool pressEdgeObserved = false; + InputSimulationWaitOutcome waitOutcome = InputSimulationWaitOutcome.Completed; + + await InputSystemUpdateHelper.SwitchToMainThreadIfNeeded(ct); + Action keyDownEdgeMonitor = () => pressEdgeObserved |= IsGameplayPressEdgeVisible(keyboard, key); + InputSystem.onAfterUpdate += keyDownEdgeMonitor; + + try + { + waitOutcome = await InputSystemUpdateHelper.ApplyOnNextConfiguredUpdate( + () => KeyboardKeyState.SetKeyState(keyboard, key, true), + ct).ConfigureAwait(false); + if (waitOutcome == InputSimulationWaitOutcome.Completed) + { + keyDownApplied = true; + await InputSystemUpdateHelper.SwitchToMainThreadIfNeeded(CancellationToken.None); + KeyboardKeyState.SetKeyDown(key); + SimulateKeyboardOverlayState.AddHeldKey(keyName); + waitOutcome = await InputSystemUpdateHelper.WaitForObservationFrames(ct) + .ConfigureAwait(false); + committed = waitOutcome == InputSimulationWaitOutcome.Completed; + } + } + finally + { + await InputSystemUpdateHelper.SwitchToMainThreadIfNeeded(CancellationToken.None); + InputSystem.onAfterUpdate -= keyDownEdgeMonitor; + if (waitOutcome == InputSimulationWaitOutcome.TimedOut) + { + KeyboardInputMainThreadCleanup.ScheduleTimedOutHeldKeyCleanup( + keyboard, + key, + keyName, + keyDownApplied); + } + else if (keyDownApplied && !committed) + { + InputSimulationWaitOutcome rollbackOutcome = + await KeyboardInputMainThreadCleanup.RollbackHeldKey( + keyboard, + key, + keyName, + CancellationToken.None).ConfigureAwait(false); + if (rollbackOutcome == InputSimulationWaitOutcome.TimedOut) + { + waitOutcome = InputSimulationWaitOutcome.TimedOut; + } + } + } + + if (waitOutcome == InputSimulationWaitOutcome.Paused) + { + return KeyboardInputSimulationResponseFactory.InterruptedKeyResult( + UnityCliLoopKeyboardAction.KeyDown, + keyName, + pressEdgeObserved); + } + + if (waitOutcome == InputSimulationWaitOutcome.TimedOut) + { + return KeyboardInputSimulationResponseFactory.TimedOutKeyResult( + UnityCliLoopKeyboardAction.KeyDown, + keyName); + } + + string keyDownEdgeText = pressEdgeObserved + ? "" + : " (press edge was not observed via wasPressedThisFrame; gameplay polling may have missed it)"; + return new SimulateKeyboardResponse + { + Success = true, + Message = $"Key '{keyName}' held down{keyDownEdgeText}", + Action = UnityCliLoopKeyboardAction.KeyDown.ToString(), + KeyName = keyName, + PressEdgeObserved = pressEdgeObserved + }; + } + + internal static async Task ExecuteKeyUp( + Keyboard keyboard, + Key key, + CancellationToken ct) + { + string keyName = key.ToString(); + + if (!KeyboardKeyState.IsKeyHeld(key)) + { + return new SimulateKeyboardResponse + { + Success = false, + Message = $"Key '{keyName}' is not currently held. Call KeyDown first.", + Action = UnityCliLoopKeyboardAction.KeyUp.ToString(), + KeyName = keyName + }; + } + + InputSimulationWaitOutcome releaseOutcome = + await KeyboardInputMainThreadCleanup.ReleaseKeyStateIfPossible( + keyboard, + key, + CancellationToken.None).ConfigureAwait(false); + + if (releaseOutcome == InputSimulationWaitOutcome.TimedOut) + { + KeyboardInputMainThreadCleanup.ScheduleTimedOutHeldKeyCleanup(keyboard, key, keyName, false); + return KeyboardInputSimulationResponseFactory.TimedOutKeyResult( + UnityCliLoopKeyboardAction.KeyUp, + keyName); + } + + await InputSystemUpdateHelper.SwitchToMainThreadIfNeeded(CancellationToken.None); + KeyboardKeyState.SetKeyUp(key); + SimulateKeyboardOverlayState.RemoveHeldKey(keyName); + + InputSimulationWaitOutcome waitOutcome = await InputSystemUpdateHelper.WaitForObservationFrames(ct) + .ConfigureAwait(false); + if (waitOutcome == InputSimulationWaitOutcome.Paused) + { + return KeyboardInputSimulationResponseFactory.InterruptedKeyResult( + UnityCliLoopKeyboardAction.KeyUp, + keyName, + null); + } + + if (waitOutcome == InputSimulationWaitOutcome.TimedOut) + { + return KeyboardInputSimulationResponseFactory.TimedOutKeyResult( + UnityCliLoopKeyboardAction.KeyUp, + keyName); + } + + return new SimulateKeyboardResponse + { + Success = true, + Message = $"Key '{keyName}' released", + Action = UnityCliLoopKeyboardAction.KeyUp.ToString(), + KeyName = keyName + }; + } + + // Runs inside InputSystem.onAfterUpdate. Editor updates are excluded because a press + // consumed there never surfaces as wasPressedThisFrame to gameplay Update polling. + private static bool IsGameplayPressEdgeVisible(Keyboard keyboard, Key key) + { + if (UnityEngine.InputSystem.LowLevel.InputState.currentUpdateType == UnityEngine.InputSystem.LowLevel.InputUpdateType.Editor) + { + return false; + } + return keyboard[key].wasPressedThisFrame; + } + } +} +#endif diff --git a/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/KeyboardInputActionExecutor.cs.meta b/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/KeyboardInputActionExecutor.cs.meta new file mode 100644 index 0000000000..32c4e5bbb0 --- /dev/null +++ b/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/KeyboardInputActionExecutor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ce22ac762e0a4213a85e5f98518dd8e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/SimulateKeyboardUseCase.cs b/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/SimulateKeyboardUseCase.cs index 9965251560..7f94d18841 100644 --- a/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/SimulateKeyboardUseCase.cs +++ b/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/SimulateKeyboardUseCase.cs @@ -107,15 +107,19 @@ public async Task ExecuteAsync( switch (parameters.Action) { case UnityCliLoopKeyboardAction.Press: - response = await ExecutePress(keyboard, key, parameters.Duration, ct); + response = await KeyboardInputActionExecutor.ExecutePress( + keyboard, + key, + parameters.Duration, + ct); break; case UnityCliLoopKeyboardAction.KeyDown: - response = await ExecuteKeyDown(keyboard, key, ct); + response = await KeyboardInputActionExecutor.ExecuteKeyDown(keyboard, key, ct); break; case UnityCliLoopKeyboardAction.KeyUp: - response = await ExecuteKeyUp(keyboard, key, ct); + response = await KeyboardInputActionExecutor.ExecuteKeyUp(keyboard, key, ct); break; default: @@ -146,281 +150,6 @@ private static void EnsureOverlayExists() OverlayCanvasFactory.EnsureExists(); } - private async Task ExecutePress( - Keyboard keyboard, Key key, float duration, CancellationToken ct) - { - if (duration < 0f || float.IsNaN(duration) || float.IsInfinity(duration)) - { - return new SimulateKeyboardResponse - { - Success = false, - Message = $"Duration must be non-negative, got: {duration}", - Action = UnityCliLoopKeyboardAction.Press.ToString(), - KeyName = key.ToString() - }; - } - - string keyName = key.ToString(); - if (KeyboardKeyState.IsKeyHeld(key)) - { - return new SimulateKeyboardResponse - { - Success = false, - Message = $"Key '{keyName}' is already held down. Call KeyUp first.", - Action = UnityCliLoopKeyboardAction.Press.ToString(), - KeyName = keyName - }; - } - - SimulateKeyboardOverlayState.ShowPress(keyName); - KeyboardKeyState.RegisterTransientKey(key); - bool pressWasApplied = false; - bool pressEdgeObserved = false; - InputSimulationWaitOutcome waitOutcome = InputSimulationWaitOutcome.Completed; - - // The edge must be probed inside gameplay input updates: editor-tick polling can - // miss the single frame where wasPressedThisFrame is true, and an editor-update - // consumed press is exactly the failure gameplay code cannot see. - await InputSystemUpdateHelper.SwitchToMainThreadIfNeeded(ct); - Action pressEdgeMonitor = () => pressEdgeObserved |= IsGameplayPressEdgeVisible(keyboard, key); - InputSystem.onAfterUpdate += pressEdgeMonitor; - - try - { - waitOutcome = await InputSystemUpdateHelper.ApplyOnNextConfiguredUpdate( - () => KeyboardKeyState.SetKeyState(keyboard, key, true), - ct).ConfigureAwait(false); - if (waitOutcome == InputSimulationWaitOutcome.Completed) - { - pressWasApplied = true; - waitOutcome = await InputSystemUpdateHelper.WaitForPressLifetime(duration, ct) - .ConfigureAwait(false); - } - } - finally - { - await InputSystemUpdateHelper.SwitchToMainThreadIfNeeded(CancellationToken.None); - InputSystem.onAfterUpdate -= pressEdgeMonitor; - if (waitOutcome == InputSimulationWaitOutcome.TimedOut) - { - KeyboardInputMainThreadCleanup.ScheduleTimedOutPressCleanup( - keyboard, - key, - pressWasApplied); - } - else if (pressWasApplied) - { - InputSimulationWaitOutcome releaseOutcome = - await KeyboardInputMainThreadCleanup.ReleaseKeyStateIfPossible( - keyboard, - key, - CancellationToken.None).ConfigureAwait(false); - if (releaseOutcome == InputSimulationWaitOutcome.TimedOut) - { - waitOutcome = InputSimulationWaitOutcome.TimedOut; - KeyboardInputMainThreadCleanup.ScheduleTimedOutPressCleanup(keyboard, key, false); - } - else if (waitOutcome == InputSimulationWaitOutcome.Paused) - { - KeyboardKeyState.UnregisterTransientKey(key); - SimulateKeyboardOverlayState.ClearPress(); - } - else - { - KeyboardKeyState.UnregisterTransientKey(key); - await KeyboardInputMainThreadCleanup.FinalizePressOverlay(ct).ConfigureAwait(false); - } - } - else - { - KeyboardKeyState.UnregisterTransientKey(key); - SimulateKeyboardOverlayState.ClearPress(); - } - } - - if (waitOutcome == InputSimulationWaitOutcome.Paused) - { - return KeyboardInputSimulationResponseFactory.InterruptedKeyResult( - UnityCliLoopKeyboardAction.Press, - keyName, - pressEdgeObserved); - } - - if (waitOutcome == InputSimulationWaitOutcome.TimedOut) - { - return KeyboardInputSimulationResponseFactory.TimedOutKeyResult( - UnityCliLoopKeyboardAction.Press, - keyName); - } - - string durationText = duration > 0f ? $" for {InputSimulationDurationFormatter.FormatSeconds(duration)}s" : ""; - string edgeText = pressEdgeObserved - ? "" - : " (press edge was not observed via wasPressedThisFrame; gameplay polling may have missed it, so retry or verify with a focused log)"; - return new SimulateKeyboardResponse - { - Success = true, - Message = $"Pressed '{keyName}'{durationText}{edgeText}", - Action = UnityCliLoopKeyboardAction.Press.ToString(), - KeyName = keyName, - PressEdgeObserved = pressEdgeObserved - }; - } - - private async Task ExecuteKeyDown(Keyboard keyboard, Key key, CancellationToken ct) - { - string keyName = key.ToString(); - - if (KeyboardKeyState.IsKeyHeld(key)) - { - return new SimulateKeyboardResponse - { - Success = false, - Message = $"Key '{keyName}' is already held down. Call KeyUp first.", - Action = UnityCliLoopKeyboardAction.KeyDown.ToString(), - KeyName = keyName - }; - } - - bool keyDownApplied = false; - bool committed = false; - bool pressEdgeObserved = false; - InputSimulationWaitOutcome waitOutcome = InputSimulationWaitOutcome.Completed; - - await InputSystemUpdateHelper.SwitchToMainThreadIfNeeded(ct); - Action keyDownEdgeMonitor = () => pressEdgeObserved |= IsGameplayPressEdgeVisible(keyboard, key); - InputSystem.onAfterUpdate += keyDownEdgeMonitor; - - try - { - waitOutcome = await InputSystemUpdateHelper.ApplyOnNextConfiguredUpdate( - () => KeyboardKeyState.SetKeyState(keyboard, key, true), - ct).ConfigureAwait(false); - if (waitOutcome == InputSimulationWaitOutcome.Completed) - { - keyDownApplied = true; - await InputSystemUpdateHelper.SwitchToMainThreadIfNeeded(CancellationToken.None); - KeyboardKeyState.SetKeyDown(key); - SimulateKeyboardOverlayState.AddHeldKey(keyName); - waitOutcome = await InputSystemUpdateHelper.WaitForObservationFrames(ct) - .ConfigureAwait(false); - committed = waitOutcome == InputSimulationWaitOutcome.Completed; - } - } - finally - { - await InputSystemUpdateHelper.SwitchToMainThreadIfNeeded(CancellationToken.None); - InputSystem.onAfterUpdate -= keyDownEdgeMonitor; - if (waitOutcome == InputSimulationWaitOutcome.TimedOut) - { - KeyboardInputMainThreadCleanup.ScheduleTimedOutHeldKeyCleanup( - keyboard, - key, - keyName, - keyDownApplied); - } - else if (keyDownApplied && !committed) - { - InputSimulationWaitOutcome rollbackOutcome = - await KeyboardInputMainThreadCleanup.RollbackHeldKey( - keyboard, - key, - keyName, - CancellationToken.None).ConfigureAwait(false); - if (rollbackOutcome == InputSimulationWaitOutcome.TimedOut) - { - waitOutcome = InputSimulationWaitOutcome.TimedOut; - } - } - } - - if (waitOutcome == InputSimulationWaitOutcome.Paused) - { - return KeyboardInputSimulationResponseFactory.InterruptedKeyResult( - UnityCliLoopKeyboardAction.KeyDown, - keyName, - pressEdgeObserved); - } - - if (waitOutcome == InputSimulationWaitOutcome.TimedOut) - { - return KeyboardInputSimulationResponseFactory.TimedOutKeyResult( - UnityCliLoopKeyboardAction.KeyDown, - keyName); - } - - string keyDownEdgeText = pressEdgeObserved - ? "" - : " (press edge was not observed via wasPressedThisFrame; gameplay polling may have missed it)"; - return new SimulateKeyboardResponse - { - Success = true, - Message = $"Key '{keyName}' held down{keyDownEdgeText}", - Action = UnityCliLoopKeyboardAction.KeyDown.ToString(), - KeyName = keyName, - PressEdgeObserved = pressEdgeObserved - }; - } - - private async Task ExecuteKeyUp(Keyboard keyboard, Key key, CancellationToken ct) - { - string keyName = key.ToString(); - - if (!KeyboardKeyState.IsKeyHeld(key)) - { - return new SimulateKeyboardResponse - { - Success = false, - Message = $"Key '{keyName}' is not currently held. Call KeyDown first.", - Action = UnityCliLoopKeyboardAction.KeyUp.ToString(), - KeyName = keyName - }; - } - - InputSimulationWaitOutcome releaseOutcome = - await KeyboardInputMainThreadCleanup.ReleaseKeyStateIfPossible( - keyboard, - key, - CancellationToken.None).ConfigureAwait(false); - - if (releaseOutcome == InputSimulationWaitOutcome.TimedOut) - { - KeyboardInputMainThreadCleanup.ScheduleTimedOutHeldKeyCleanup(keyboard, key, keyName, false); - return KeyboardInputSimulationResponseFactory.TimedOutKeyResult( - UnityCliLoopKeyboardAction.KeyUp, - keyName); - } - - await InputSystemUpdateHelper.SwitchToMainThreadIfNeeded(CancellationToken.None); - KeyboardKeyState.SetKeyUp(key); - SimulateKeyboardOverlayState.RemoveHeldKey(keyName); - - InputSimulationWaitOutcome waitOutcome = await InputSystemUpdateHelper.WaitForObservationFrames(ct) - .ConfigureAwait(false); - if (waitOutcome == InputSimulationWaitOutcome.Paused) - { - return KeyboardInputSimulationResponseFactory.InterruptedKeyResult( - UnityCliLoopKeyboardAction.KeyUp, - keyName, - null); - } - - if (waitOutcome == InputSimulationWaitOutcome.TimedOut) - { - return KeyboardInputSimulationResponseFactory.TimedOutKeyResult( - UnityCliLoopKeyboardAction.KeyUp, - keyName); - } - - return new SimulateKeyboardResponse - { - Success = true, - Message = $"Key '{keyName}' released", - Action = UnityCliLoopKeyboardAction.KeyUp.ToString(), - KeyName = keyName - }; - } - private static string NormalizeKeyName(string keyName) { if (string.Equals(keyName, "Return", StringComparison.OrdinalIgnoreCase)) @@ -430,16 +159,6 @@ private static string NormalizeKeyName(string keyName) return keyName; } - // Runs inside InputSystem.onAfterUpdate. Editor updates are excluded because a press - // consumed there never surfaces as wasPressedThisFrame to gameplay Update polling. - private static bool IsGameplayPressEdgeVisible(Keyboard keyboard, Key key) - { - if (UnityEngine.InputSystem.LowLevel.InputState.currentUpdateType == UnityEngine.InputSystem.LowLevel.InputUpdateType.Editor) - { - return false; - } - return keyboard[key].wasPressedThisFrame; - } #endif } }