"""Real-app keyboard evidence. Pair first; open Settings > General.
Requires Chrome on X11, agent-browser connected over CDP, ffmpeg, setxkbmap,
xdotool, Python, libX11 and libXtst. No synthetic DOM keyboard events.
Run with DISPLAY/XAUTHORITY set, AB pointing to agent-browser, SESSION and CDP.
Arguments: side output-root. Each run creates a new timestamped directory.
"""
import datetime, json, os, pathlib, subprocess, sys, time
side, root = sys.argv[1:]
out = pathlib.Path(root) / (side + '-' + datetime.datetime.now().strftime('%Y%m%d-%H%M%S'))
out.mkdir(parents=True)
ab = [os.environ['AB'], '--session', os.environ['SESSION'], '--cdp', os.environ['CDP']]
def run(*args, **kw):
    return subprocess.run(args, check=True, text=True, capture_output=True, **kw).stdout
def browser(*args, **kw): return run(*ab, *args, **kw)
def evaluate(js): return json.loads(browser('eval', '--stdin', input=js))
def key(*codes): run('python3', str(pathlib.Path(__file__).with_name('physical-key.py')), *map(str,codes))
def note(label):
    evaluate('document.getElementById("evidence-note").textContent = '+json.dumps('Linux · Chrome · 1280 × 800 · Light\nNative X11 keyboard · '+label)+'; true')
evaluate('''(() => {
 const panel = document.createElement('div'); panel.id='evidence-note';
 Object.assign(panel.style,{position:'fixed',bottom:'20px',right:'20px',zIndex:'99999',padding:'16px',background:'#111827',color:'white',borderRadius:'8px',font:'16px sans-serif',maxWidth:'650px',pointerEvents:'none',whiteSpace:'pre-line'});
 document.body.append(panel);
 window.observedKeys=[];
 window.addEventListener('keydown', e => { if(!['Control','Shift','Escape'].includes(e.key)) window.observedKeys.push({key:e.key,code:e.code,ctrl:e.ctrlKey,shift:e.shiftKey,trusted:e.isTrusted}); },true);
 return {width:innerWidth,height:innerHeight};
})()''')
note('Starting')
record = subprocess.Popen(['ffmpeg','-y','-f','x11grab','-video_size','1280x800','-framerate','20','-i',os.environ['DISPLAY']+'+0,0','-c:v','libx264','-preset','ultrafast','-crf','20','-pix_fmt','yuv420p',str(out/'recording.mp4')],stdout=(out/'ffmpeg.log').open('w'),stderr=subprocess.STDOUT)
results=[]
try:
 for label, query, layout, codes in [
   ('Russian physical Slash — empty query','','ru',[61]),
   ('Russian Ctrl + physical F — empty query','','ru',[37,41]),
   ('Russian physical Slash — select query','theme','ru',[61]),
   ('Russian Ctrl + physical F — select query','theme','ru',[37,41]),
   ('German Shift + 7 — select query','theme','de',[50,16]),
 ]:
    run('setxkbmap',layout)
    browser('find','label','Search settings','fill',query)
    run('xdotool','mousemove','650','130','click','1')
    evaluate('window.observedKeys=[]; true')
    note(label+'\nClicked outside search. Pressing shortcut next…')
    time.sleep(1.5)
    key(*codes)
    time.sleep(.3)
    result=evaluate('''(() => {const i=document.querySelector('input[aria-label="Search settings"]');return {focused:document.activeElement===i,query:i.value,selection:[i.selectionStart,i.selectionEnd],events:window.observedKeys};})()''')
    result['case']=label;results.append(result)
    event=result['events'][-1] if result['events'] else {}
    note(label+'\nkey='+str(event.get('key'))+' · code='+str(event.get('code'))+' · trusted='+str(event.get('trusted'))+'\nSearch focused: '+str(result['focused'])+' · Selection: '+str(result['selection']))
    time.sleep(2.5)
    if 37 in codes and not result["focused"]: key(9)
 note('Finished · '+str(sum(r['focused'] for r in results))+'/5 shortcuts focused Settings search')
 time.sleep(1.5)
finally:
 record.terminate();record.wait()
 (out/'results.json').write_text(json.dumps(results,ensure_ascii=False,indent=2))
print(out)
print(json.dumps(results,ensure_ascii=False,indent=2))
