1#!/usr/bin/env python3
2"""Apply keyboard controls during a native paragraph-fixture inspection."""
3import argparse
4import base64
5import json
6from pathlib import Path
7import xml.etree.ElementTree as ET
8
9from native_runner import navigation_script, windows
10from native_xml import ns
11
12
13def apply(output):
14 target = json.loads((output / 'machine.json').read_text())['name']
15 pages = {page.get('name'): page for path in (output / 'read').glob('page-*.xml')
16 for page in [ET.parse(path).getroot()]}
17 cases = json.loads((Path(__file__).resolve().parent.parent /
18 'corpus/paragraph-edit/reconciliation/cases.json').read_text(encoding='utf-8-sig'))
19 scripts = output / 'keyboard'
20 scripts.mkdir()
21 for case in cases:
22 page = pages[case['name']]
23 paragraphs = page.findall('one:Outline/one:OEChildren/one:OE', ns)
24 join = case['operation'] == 'join'
25 change = case['change']
26 at = 1 if join and change in ('child', 'list', 'tag', 'format', 'right-boundary') else 0
27 keys = {
28 'prefix': '{Left}X',
29 'boundary': '{Right}X' if join else '{Left}{Right 2}X',
30 'right-boundary': '{Left}X',
31 'child': '{Right}{Enter}{Tab}Native child',
32 'list': '{Left}^.',
33 'tag': '{Left}^1',
34 'format': '^i',
35 'sibling': 'Native sibling',
36 'adoption': '{Left}X',
37 }[change]
38 if change == 'sibling':
39 at = len(paragraphs) - 1
40 steps = [(paragraphs[at].get('objectID'), keys)]
41 if join and change == 'prefix':
42 steps.append((paragraphs[1].get('objectID'), '{Right}Y'))
43 script = ''.join(navigation_script(page.get('ID'), oid) + f'Send "{keys}"\nSleep 300\n'
44 for oid, keys in steps)
45 stem = scripts / case['name'].lower().replace(' ', '-')
46 stem.with_suffix('.ahk').write_text(script)
47 result = windows.do_exec(script, target=target, shot_delay_ms=500)
48 stem.with_suffix('.json').write_text(json.dumps({k: v for k, v in result.items() if k != 'png_b64'}, indent=2))
49 if result.get('png_b64'):
50 stem.with_suffix('.png').write_bytes(base64.b64decode(result['png_b64']))
51 if result.get('error') or result.get('exit') != 0 or not result.get('png_b64'):
52 raise RuntimeError(windows.text_result(result))
53 print(case['name'], flush=True)
54 (output / 'finish').touch()
55
56
57if __name__ == '__main__':
58 parser = argparse.ArgumentParser(description=__doc__)
59 parser.add_argument('output', type=Path)
60 apply(parser.parse_args().output)