Something went wrong. Try again.
Native control, inspection, UI automation and evidence capture for a running Witcher 3 process.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869"""Strict selectors over the instrumented live Scaleform display tree.
Dispatch is synthetic Flash mouse event delivery, like Playwright dispatchEvent.It is not a physical mouse click and does not claim pixel occlusion testing.The native virtual controller remains available for normal game input paths."""import mathimport contextvarsimport timefrom . import nativefrom .diagnostics import PostconditionError
OWNER_CALL=contextvars.ContextVar('ui_owner_call',default=None)
def call(command,args='',timeout=5): adapter=OWNER_CALL.get() return adapter(command,args) if adapter else native.call(command,args,timeout=timeout)
def data(reply): if not reply.get('ok'):raise RuntimeError(str(reply.get('data'))) value=reply['data'] if isinstance(value,dict) and 'error' in value:raise RuntimeError(value['error']) return value
def tree(root=''): header=data(call('ui_scan',root,timeout=15)) rows=[] for start in range(0,header['count'],32): rows.extend(data(call('ui_rows',f"{header['revision']}|{start}|32",timeout=15))) if len(rows)!=header['count']:raise RuntimeError('UI snapshot was incomplete') return dict(ok=True,session=native.state()['session'],**header,nodes=rows)
def matches(snapshot,field,value): if snapshot['truncated']:raise RuntimeError('UI tree exceeded limit; refusing selection from partial results') return [n for n in snapshot['nodes'] if n.get(field)==value]
def find(field,value,root='',timeout=10): if not math.isfinite(timeout) or not 0<timeout<=60:raise ValueError('UI timeout must be in (0,60]') end=time.monotonic()+timeout while True: try:snapshot=tree(root) except RuntimeError as e: if str(e)!='ui_root_unavailable' or time.monotonic()>=end:raise time.sleep(.15);continue found=matches(snapshot,field,value) if len(found)>1:raise RuntimeError(f'Strict UI selector matched {len(found)} nodes') if found:return dict(ok=True,session=snapshot['session'],revision=snapshot['revision'],node=found[0]) if time.monotonic()>=end:raise TimeoutError('UI selector did not match before deadline') time.sleep(.15)
def dispatch(field,value,root='',timeout=10,expect_label=None): found=find(field,value,root,timeout) reference=f"{found['revision']}|{found['node']['id']}" before=data(call('ui_node',reference))['node'] time.sleep(.15) fresh=data(call('ui_node',reference))['node'] if any(abs(a-b)>.5 for a,b in zip(before['bounds'],fresh['bounds'])): raise RuntimeError('UI target is still moving; no input dispatched') reply=data(call('ui_dispatch',reference)) result=dict(ok=True,reference=found,delivery=reply,transport='synthetic_flash_mouse_events',effect_verified=False) if expect_label is not None: try: result['observed']=find('label',expect_label,root,timeout) except (OSError, ValueError, RuntimeError) as error: result.update(ok=False, expected_label=expect_label) raise PostconditionError(str(error), result) from error result['effect_verified']=True return result