{"record":{"id":"8b13467406497a96","repo":"babalae/better-genshin-impact","slug":"snapshot-description-attempts-sna","errorCode":null,"errorMessage":"动作 {snapshot.Description} 执行 {attempts} 次后，等待 {snapshot.TargetDescription} 超时（{snapshot.Timeout}ms）","messagePattern":"动作 (.+?) 执行 (.+?) 次后，等待 (.+?) 超时（(.+?)ms）","errorType":"exception","errorClass":"TimeoutException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Core/BgiVision/BvFlow.cs","lineNumber":349,"sourceCode":"            return Task.CompletedTask;\n        });\n    }\n\n    private async Task ExecuteActionStep(BvFlowActionSnapshot snapshot, BvFlowExecutionContext context)\n    {\n        var startedAt = _services.GetTimestamp();\n        var attempts = 0;\n\n        while (true)\n        {\n            _services.ThrowIfCancellationRequested();\n            attempts++;\n            await snapshot.Action(context);\n\n            var remainingMilliseconds = snapshot.Timeout - _services.GetElapsedMilliseconds(startedAt);\n            if (remainingMilliseconds <= 0)\n            {\n                throw new TimeoutException(\n                    $\"动作 {snapshot.Description} 执行 {attempts} 次后，等待 {snapshot.TargetDescription} 超时（{snapshot.Timeout}ms）\");\n            }\n\n            await _services.Delay(GetDelayMilliseconds(snapshot.RetryInterval, remainingMilliseconds));\n\n            if (_services.GetElapsedMilliseconds(startedAt) >= snapshot.Timeout)\n            {\n                throw new TimeoutException(\n                    $\"动作 {snapshot.Description} 执行 {attempts} 次后，等待 {snapshot.TargetDescription} 超时（{snapshot.Timeout}ms）\");\n            }\n\n            var result = FindTargets(snapshot.Targets, snapshot.Condition);\n            _services.ThrowIfCancellationRequested();\n            if (_services.GetElapsedMilliseconds(startedAt) >= snapshot.Timeout)\n            {\n                throw new TimeoutException(\n                    $\"动作 {snapshot.Description} 执行 {attempts} 次后，等待 {snapshot.TargetDescription} 超时（{snapshot.Timeout}ms）\");\n            }","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Core/BgiVision/BvFlow.cs#L331-L367","documentation":"Thrown when ChildSessionNativeMethods.TryFocusRdpInputWindow(Handle) returns false, meaning the Win32 SetForegroundWindow or equivalent call failed to give keyboard focus to the RDP input child window. Without focus, SendKeys would deliver keystrokes to the wrong target, so the code refuses to send.","triggerScenarios":"Called inside SendShortcut after ConnectedState is 1. TryFocusRdpInputWindow fails when the RDP window handle is not in the foreground-capable state — e.g. the BetterGI window is minimized, another application grabbed focus, or the RDP child window handle cache is stale after a reconnection.","commonSituations":"User clicked away to another app between triggering the shortcut and delivery, the main window is minimized/background (Windows restricts SetForegroundWindow for background processes), or the cached RDP input window handle pointed to a destroyed window after reconnect.","solutions":["Ensure the BetterGI main window is foreground before invoking shortcuts (bring it to front first).","Call ChildSessionNativeMethods.ClearRdpInputWindowCache(Handle) to invalidate stale handles then retry.","Retry the focus attempt a few times with short delays; if still failing, notify the user to click the child session area.","Allow the OperatingSystem focus-stealing workaround (AttachThreadInput) if available in TryFocusRdpInputWindow."],"exampleFix":"// before\nif (!ChildSessionNativeMethods.TryFocusRdpInputWindow(Handle))\n    throw new InvalidOperationException(\"无法将键盘焦点切换到桌面分身。\");\nRunComStep($\"向 Child Session 发送 {displayName}\", () => SendKeyStrokes(strokes));\n\n// after — retry focus, then degrade gracefully\nChildSessionNativeMethods.ClearRdpInputWindowCache(Handle);\nvar focused = false;\nfor (var i = 0; i < 3; i++)\n{\n    if (ChildSessionNativeMethods.TryFocusRdpInputWindow(Handle)) { focused = true; break; }\n    await Task.Delay(100, ct);\n}\nif (!focused)\n    throw new InvalidOperationException(\"无法将键盘焦点切换到桌面分身，请点击桌面分身窗口后重试。\");","handlingStrategy":"retry","validationCode":"// Bring main window to foreground before focusing RDP\nChildSessionNativeMethods.ClearRdpInputWindowCache(Handle);\nvar focused = ChildSessionNativeMethods.TryFocusRdpInputWindow(Handle);","typeGuard":"bool CanFocusRdpWindow() =>\n    ConnectedState == 1 && ChildSessionNativeMethods.TryFocusRdpInputWindow(Handle);","tryCatchPattern":"for (var i = 0; i < 3; i++)\n{\n    if (ChildSessionNativeMethods.TryFocusRdpInputWindow(Handle)) break;\n    await Task.Delay(100, ct);\n}\nif (!focused) throw new InvalidOperationException(\"无法将键盘焦点切换到桌面分身。\");","preventionTips":["Bring the BetterGI main window to foreground before sending shortcuts.","Clear the cached RDP input window handle after reconnections.","Retry focus with short delays; Windows restricts background SetForegroundWindow."],"tags":["rdp","child-session","win32","focus","keyboard"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}