Repository navigation
fix: restore runInBackground on the main thread after input simulation - #1812
Merged
hatayama merged 1 commit intoJul 17, 2026
Conversation
Contributor
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (3)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
simulate-mouse-input and simulate-keyboard always failed with "set_runInBackground can only be called from the main thread" (UNITY_RPC_ERROR) even though the simulation itself succeeded, and the thrown exception additionally left PlayMode in Error Pause. The executor awaits in both use cases were given .ConfigureAwait(false) by the ConfigureAwait guard (#1778). Their completions come from a TCS created with RunContinuationsAsynchronously, so the method always resumed on a thread-pool thread, and the `using` scope's Dispose then set Application.runInBackground (a main-thread-only API) off the main thread, discarding the successful response. Follow the existing PlayModeTestExecuter pattern: replace `using` with an explicit scope + try-finally that switches back to the main thread via InputSystemUpdateHelper.SwitchToMainThreadIfNeeded before Dispose. Also assert the main-thread precondition inside InputSimulationRunInBackgroundScope.Dispose so future regressions fail fast (requires the ToolContracts asmdef reference).
hatayama
force-pushed
the
fix/input-simulation-run-in-background-dispose
branch
from
July 17, 2026 11:50
f64e531 to
47c3c9d
Compare
Contributor
|
Caution Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted. Error details |
hatayama
merged commit Jul 17, 2026
200677c
into
feature/windows-v3-verification-integration
8 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
uloop simulate-mouse-inputanduloop simulate-keyboardfailed on every invocation withUNITY_RPC_ERROR / set_runInBackground can only be called from the main thread(reproduced 5/5 on Windows during the v3 verification pass; the mechanism is platform-independent). The simulation itself succeeded (VibeLogs recorded*_completewithSuccess:true), but the successful response was discarded, and the escaped exception left PlayMode in Error Pause, blocking subsequent attempts.Root cause
.ConfigureAwait(false)to the executor awaits inSimulateMouseInputUseCase/SimulateKeyboardUseCase.TaskCompletionSourcecreated withTaskCreationOptions.RunContinuationsAsynchronously(InputSystemConfiguredUpdateApplier), so withConfigureAwait(false)the continuation always resumes on a thread-pool thread instead of Unity's main thread.using InputSimulationRunInBackgroundScopeDispose then ran on that pool thread and setApplication.runInBackground— a main-thread-only API — which threw, replacing the successful response with an internal error.Fix
Follow the existing precedent in
PlayModeTestExecuter(why-not-using+ finally with a main-thread switch):SimulateMouseInputUseCase/SimulateKeyboardUseCase: replaceusingwith an explicit scope +try/finally; thefinallyawaitsInputSystemUpdateHelper.SwitchToMainThreadIfNeeded(CancellationToken.None)beforeDispose(). (SwitchToMainThreadIfNeededis a custom awaitable, so it is outside the ConfigureAwait guard's scope — no re-collision.)InputSimulationRunInBackgroundScope.Dispose: addedDebug.Assert(MainThreadSwitcher.IsMainThread, ...)so any future off-main-thread disposal fails fast. This required referencing the ToolContracts asmdef from the InputSimulation asmdef (same dependency the sibling Common/InputSystem asmdef already has).Verification (Windows, Unity 2022.3.62f3, native uloop 3.1.0-beta.13)
SimulateMouseInputTests.LongPress_Should_RestoreRunInBackground_WhenOriginallyDisabledandSimulateKeyboardTests.Press_Should_RestoreRunInBackground_WhenOriginallyDisabledboth failed before the fix with exactlyset_runInBackground can only be called from the main thread.uloop compile: 0 errors, 0 warnings.uloop simulate-keyboard --action Press --key Spacex3 anduloop simulate-mouse-input --action Clickx3 → allSuccess:true/ exit 0 (previously 0/5); Unity console shows no errors or warnings afterwards; PlayMode stopped cleanly (no Error Pause).SimulateMouseInputTests+SimulateKeyboardTestssuites → 49/49 passed.