Wait for QEMU input releases (#546)

This commit is contained in:
Noah
2026-09-11 11:15:02 -06:00
parent 55660b7c01
commit 2efe36f582
2 changed files with 45 additions and 35 deletions
+34 -29
View File
@@ -217,26 +217,36 @@ def do_tap(s, f, ax, ay, hold=TAP_HOLD_S):
send_events(s, f, [btn_ev(False)])
def do_observed_tap(ctx, ax, ay):
"""Press until the guest reports consuming it, then release."""
before = parse_stats(ctx.ctl.send("stats")).get("presses")
def wait_input_count(ctx, field, before):
"""Wait until one guest input counter advances."""
if before is None:
time.sleep(0.05)
return True
deadline = time.monotonic() + TAP_OBSERVE_TIMEOUT_S
while time.monotonic() < deadline:
now = parse_stats(ctx.ctl.send("stats")).get(field)
if now is not None and now != before:
return True
time.sleep(0.02)
return False
def do_observed_tap(ctx, ax, ay):
"""Wait until the guest consumes both halves of a tap."""
before = parse_stats(ctx.ctl.send("stats"))
if before.get("presses") is None:
do_tap(ctx.s, ctx.f, ax, ay)
return True
send_events(ctx.s, ctx.f, [abs_ev("x", ax), abs_ev("y", ay), btn_ev(True)])
observed = False
deadline = time.monotonic() + TAP_OBSERVE_TIMEOUT_S
pressed = False
try:
while time.monotonic() < deadline:
now = parse_stats(ctx.ctl.send("stats")).get("presses")
if now is not None and now != before:
observed = True
break
time.sleep(0.02)
pressed = wait_input_count(ctx, "presses", before.get("presses"))
finally:
send_events(ctx.s, ctx.f, [btn_ev(False)])
return observed
if not pressed:
return False
return wait_input_count(ctx, "releases", before.get("releases"))
def _move_swipe(s, f, ax1, ay1, ax2, ay2, ms, steps):
@@ -278,27 +288,18 @@ def do_observed_swipe(ctx, x1, y1, x2, y2, ms=400, steps=None):
if steps is None:
steps = max(6, int(ms / 25))
before = parse_stats(ctx.ctl.send("stats")).get("presses")
before = parse_stats(ctx.ctl.send("stats"))
send_events(ctx.s, ctx.f, [abs_ev("x", ax1), abs_ev("y", ay1), btn_ev(True)])
observed = before is None
pressed = False
try:
if observed:
time.sleep(0.05)
else:
deadline = time.monotonic() + TAP_OBSERVE_TIMEOUT_S
while time.monotonic() < deadline:
now = parse_stats(ctx.ctl.send("stats")).get("presses")
if now is not None and now != before:
observed = True
break
time.sleep(0.02)
if not observed:
pressed = wait_input_count(ctx, "presses", before.get("presses"))
if not pressed:
return False
_move_swipe(ctx.s, ctx.f, ax1, ay1, ax2, ay2, ms, steps)
return True
finally:
send_events(ctx.s, ctx.f, [btn_ev(False)])
return wait_input_count(ctx, "releases", before.get("releases"))
class Ctl:
@@ -593,6 +594,7 @@ STATS_FIELD_RE = {
"render": re.compile(r'^render:\s*(-?\d+(?:\.\d+)?)\s*ms/frame\s*$'),
"idle": re.compile(r'^idle:\s*(\d+)\s*$'),
"presses": re.compile(r'^presses:\s*(\d+)\s*$'),
"releases": re.compile(r'^releases:\s*(\d+)\s*$'),
"termbusy": re.compile(r'^termbusy:\s*(\d+)\s*$'),
"termintr": re.compile(r'^termintr:\s*(\d+)\s*$'),
"termfg": re.compile(r'^termfg:\s*(-?\d+)\s*$'),
@@ -755,20 +757,23 @@ def verb_shot(ctx, lineno, cmd, args, line):
def verb_tap(ctx, lineno, cmd, args, line):
x, y = int(args[0]), int(args[1])
observed = do_observed_tap(ctx, to_axis(x, ctx.size), to_axis(y, ctx.size))
return ("ok", "") if observed else ("fail", "press was not consumed within 2 seconds")
return (("ok", "") if observed else
("fail", "input press or release was not consumed within 2 seconds"))
def verb_swipe(ctx, lineno, cmd, args, line):
ms = int(args[4]) if len(args) > 4 else 400
observed = do_observed_swipe(
ctx, int(args[0]), int(args[1]), int(args[2]), int(args[3]), ms)
return ("ok", "") if observed else ("fail", "press was not consumed within 2 seconds")
return (("ok", "") if observed else
("fail", "input press or release was not consumed within 2 seconds"))
def verb_fling(ctx, lineno, cmd, args, line):
observed = do_observed_swipe(
ctx, int(args[0]), int(args[1]), int(args[2]), int(args[3]), ms=120)
return ("ok", "") if observed else ("fail", "press was not consumed within 2 seconds")
return (("ok", "") if observed else
("fail", "input press or release was not consumed within 2 seconds"))
def verb_sleep(ctx, lineno, cmd, args, line):