babalae/better-genshin-impact · error · TimeoutException
动作 {snapshot.Description} 执行 {attempts} 次后,等待 {snapshot.Targ
Error message
动作 {snapshot.Description} 执行 {attempts} 次后,等待 {snapshot.TargetDescription} 超时({snapshot.Timeout}ms) What it means
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.
Source
Thrown at BetterGenshinImpact/Core/BgiVision/BvFlow.cs:349
return Task.CompletedTask;
});
}
private async Task ExecuteActionStep(BvFlowActionSnapshot snapshot, BvFlowExecutionContext context)
{
var startedAt = _services.GetTimestamp();
var attempts = 0;
while (true)
{
_services.ThrowIfCancellationRequested();
attempts++;
await snapshot.Action(context);
var remainingMilliseconds = snapshot.Timeout - _services.GetElapsedMilliseconds(startedAt);
if (remainingMilliseconds <= 0)
{
throw new TimeoutException(
$"动作 {snapshot.Description} 执行 {attempts} 次后,等待 {snapshot.TargetDescription} 超时({snapshot.Timeout}ms)");
}
await _services.Delay(GetDelayMilliseconds(snapshot.RetryInterval, remainingMilliseconds));
if (_services.GetElapsedMilliseconds(startedAt) >= snapshot.Timeout)
{
throw new TimeoutException(
$"动作 {snapshot.Description} 执行 {attempts} 次后,等待 {snapshot.TargetDescription} 超时({snapshot.Timeout}ms)");
}
var result = FindTargets(snapshot.Targets, snapshot.Condition);
_services.ThrowIfCancellationRequested();
if (_services.GetElapsedMilliseconds(startedAt) >= snapshot.Timeout)
{
throw new TimeoutException(
$"动作 {snapshot.Description} 执行 {attempts} 次后,等待 {snapshot.TargetDescription} 超时({snapshot.Timeout}ms)");
}View on GitHub (pinned to a7cb36712d)
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.
Example fix
// before
if (!ChildSessionNativeMethods.TryFocusRdpInputWindow(Handle))
throw new InvalidOperationException("无法将键盘焦点切换到桌面分身。");
RunComStep($"向 Child Session 发送 {displayName}", () => SendKeyStrokes(strokes));
// after — retry focus, then degrade gracefully
ChildSessionNativeMethods.ClearRdpInputWindowCache(Handle);
var focused = false;
for (var i = 0; i < 3; i++)
{
if (ChildSessionNativeMethods.TryFocusRdpInputWindow(Handle)) { focused = true; break; }
await Task.Delay(100, ct);
}
if (!focused)
throw new InvalidOperationException("无法将键盘焦点切换到桌面分身,请点击桌面分身窗口后重试。"); Defensive patterns
Strategy: retry
Validate before calling
// Bring main window to foreground before focusing RDP ChildSessionNativeMethods.ClearRdpInputWindowCache(Handle); var focused = ChildSessionNativeMethods.TryFocusRdpInputWindow(Handle);
Type guard
bool CanFocusRdpWindow() =>
ConnectedState == 1 && ChildSessionNativeMethods.TryFocusRdpInputWindow(Handle); Try / catch
for (var i = 0; i < 3; i++)
{
if (ChildSessionNativeMethods.TryFocusRdpInputWindow(Handle)) break;
await Task.Delay(100, ct);
}
if (!focused) throw new InvalidOperationException("无法将键盘焦点切换到桌面分身。"); Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- {paramName} 必须大于 0
- 同一个 BvFlow 不能并发执行
- BvFlow 第 {i + 1} 步执行失败:{step.Description}
- BvFlow 已经开始执行,不能再添加步骤
- 当前没有可用的桌面分身,请先启动桌面分身。
AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13).
Data as JSON: /api/errors/8b13467406497a96.
Report an issue: GitHub.