Files
recordingtest/docs/history/2026-04-08_gap-i1-deferred.md
minsung a771352bcb recorder: focus poller PoC for Gap I-1 (deferred, #14)
Adds a background focus poller that periodically calls
Automation.FocusedElement() and stamps the path onto key_down RawEvents,
so DragCollapser can fill type-step targets without relying on the stale
post-hoc Resolve() pass. Plumbing:

  Program.cs   — focus poller Task + diagnostic counters
  LowLevelHook — volatile CurrentFocusedPath, stamped on key_down
  RawEvent     — FocusedElementPath already existed (focus_change)
  DragCollapser— typeFocusPath captured at first printable key_down,
                 takes precedence over lastFocusPath/lastMousePath

Result on box-v7.yaml live recording: null_target_steps unchanged (13).
Root cause: EG-BIM Modeler's CommandBox and similar input controls lack
AutomationPeer, so UIA-based focus tracking — from any external process —
cannot see them. The WPF-internal Keyboard.FocusedElement is in-process
only and unreachable from the recorder.

Deferred. The plumbing stays in place because the same stamping path can
be reused by a future generic WPF DLL-injection probe. Player's existing
null-target fallback (Type→OS focus, Click→raw_coord) remains the official
strategy and successfully replays box-v7 end-to-end.

See docs/history/2026-04-08_gap-i1-deferred.md for analysis and future
options (generic WPF injection / AutomationPeer AI attachment).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:49:08 +09:00

2.5 KiB

2026-04-08 — Gap I-1 (recorder focus poller) deferred

소요 시간: ~45분 Context 사용량: ~25k tokens (Opus 4.6, 동일 세션 누적)

시도

issue #14의 recorder Gap I-1: type 스텝 target이 항상 null로 남는 문제를 root에서 풀기 위해 시도.

접근:

  1. 백그라운드 Task가 100ms 주기로 automation.FocusedElement() 폴링
  2. 결과 path를 LowLevelHook.CurrentFocusedPath volatile 필드에 저장
  3. KeyboardProc가 key_down RawEvent 생성 시 이 필드를 FocusedElementPath에 stamp
  4. DragCollapser가 type burst 시작 시 typeFocusPath 로컬에 캡처, FlushType fallback에서 우선 사용
  5. 진단 카운터 추가 (success/null_focus/wrong_pid/errors/last_path)

결과

box-v7.yaml 녹화 → null_target_steps=13 (이전 12와 사실상 동일). type 스텝의 target: 여전히 비어있음.

원인

UIA FocusedElement()AutomationPeer가 부착된 컨트롤만 보고할 수 있다. EG-BIM Modeler의 CommandBox 등 핵심 입력 컨트롤은 AutomationPeer가 없어서 UIA 트리에 의미 있게 노출되지 않음. 외부 프로세스에서 어떤 UIA API를 호출해도 동일한 한계.

WPF의 진짜 포커스(Keyboard.FocusedElement)는 in-process API라 외부 recorder에서는 직접 호출 불가.

결정

Gap I-1 deferred. 현재는 Player fallback이 공식 전략:

  • Type with null target → OS 레벨 키보드 입력 (SUT의 WPF가 자기 포커스 컨트롤로 라우팅)
  • Click with null target + raw_coord → 화면 절대좌표 클릭

이 fallback으로 box-v6/v7 모두 E2E 재생 성공 확인됨. 결정성/진단성은 떨어지지만 실행 자체엔 충분.

향후 옵션 (선결 PoC 필요)

  1. Generic WPF DLL injection — CreateRemoteThread + LoadLibrary로 임의 WPF 프로세스에 probe DLL 주입, Dispatcher 위에서 Keyboard.FocusedElement 읽어 named pipe로 노출. 권한 이슈 있음.
  2. AutomationPeer AI 부착 PoC (메모리 project_recordingtest_automationpeer_ai.md) — SUT fork에 AI로 AutomationPeer 자동 부착하는 별도 PR 트랙. SUT 협조 필요.

둘 다 본 이슈 범위를 벗어나므로 별도 트랙. PLAN.md에서 제거됨.

남긴 코드

진단 가능한 형태로 commit (revert하지 않음). 향후 generic injection PoC가 들어올 때 같은 stamping 메커니즘(LowLevelHook.CurrentFocusedPathRawEvent.FocusedElementPathDragCollapser.typeFocusPath) 그대로 재사용 가능.