"""Reverse-thrust verification: hold W to build throttle, then hold LALT and confirm the mapper flips to reverse (speedDemand goes negative). Injects keys with keybd_event into a btl4 launched with BT_KEY_NOFOCUS=1, so it does not need window focus. Kills ONLY the PID it spawned. """ import ctypes import os import re import subprocess import sys import time VK_W = 0x57 VK_LMENU = 0xA4 # left Alt KEYEVENTF_KEYUP = 0x0002 user32 = ctypes.windll.user32 def hold(vk, seconds): user32.keybd_event(vk, 0, 0, 0) time.sleep(seconds) def release(vk): user32.keybd_event(vk, 0, KEYEVENTF_KEYUP, 0) CONTENT = r"C:\git\bt411\content" EXE = r"C:\git\bt411\build\Release\btl4.exe" LOG = r"C:\git\bt411\scratchpad_rev.log" if os.path.exists(LOG): os.remove(LOG) env = dict(os.environ) env.update({ "BT_START_INSIDE": "1", "BT_KEY_NOFOCUS": "1", "BT_MPPR_TRACE": "1", # [mppr-c] thr= rev= -> dmd= "BT_PAD_LOG": "1", # [padwrite] reverse button "BT_LOG": LOG, }) proc = subprocess.Popen([EXE, "-egg", "LAST.EGG"], cwd=CONTENT, env=env) print("spawned pid", proc.pid) try: # wait for the mission to be running (the trace only prints in-mission) deadline = time.time() + 180 while time.time() < deadline: if os.path.exists(LOG): txt = open(LOG, errors="replace").read() if "[mppr-c]" in txt: break time.sleep(2) else: print("FAIL: never reached the mapper trace") sys.exit(1) # 1) throttle up with W for 3s, no Alt -> expect rev=0, dmd > 0 hold(VK_W, 6.0) release(VK_W) time.sleep(1.5) mark = len(open(LOG, errors="replace").read()) # 2) now hold LALT for 4s -> expect rev=1 and dmd < 0 hold(VK_LMENU, 5.0) release(VK_LMENU) time.sleep(1.5) txt = open(LOG, errors="replace").read() before = txt[:mark] during = txt[mark:] def rows(chunk): return re.findall(r"\[mppr-c\] thr=([-\d.]+) rev=(\d+).*?dmd=([-\d.]+)", chunk) b = rows(before) d = rows(during) print("\n--- forward phase (last 3 samples):", b[-3:]) print("--- alt-held phase (samples): ", d[:6]) print("--- [padwrite] lines:", re.findall(r"\[padwrite\] reverse button.*", txt)[:4]) fwd_ok = any(int(r[1]) == 0 and float(r[2]) > 0.5 for r in b) rev_ok = any(int(r[1]) == 1 and float(r[2]) < -0.5 for r in d) print("\nforward (rev=0, dmd>0): %s" % ("PASS" if fwd_ok else "FAIL")) print("reverse (rev=1, dmd<0): %s" % ("PASS" if rev_ok else "FAIL")) finally: proc.terminate() print("killed", proc.pid)