From 375d627a7abd0c07b95d70395ce89b2f4c42d106 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Wed, 28 Oct 2026 13:10:58 -0400 Subject: tools/guest-diag: guest frame capture + input driving for the two-VM GZDoom video (Xvfb XGetImage capture, SDL present shim, window resize, XTEST input, QGA range fetch) --- tools/guest-diag/xtest_move.c | 107 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 tools/guest-diag/xtest_move.c (limited to 'tools/guest-diag/xtest_move.c') diff --git a/tools/guest-diag/xtest_move.c b/tools/guest-diag/xtest_move.c new file mode 100644 index 0000000..a156bf8 --- /dev/null +++ b/tools/guest-diag/xtest_move.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: BSD-3-Clause +// xtest_move.c - drive the game with XTEST: hold forward + fire and tap +// left/right periodically so the captured footage has constant motion. +// Usage: xtest_move +#include +#include +#include +#include +#include +#include + +extern int XTestFakeKeyEvent(Display *, unsigned int, int, unsigned long); + +int main(int argc, char **argv) +{ + Display *d = XOpenDisplay(argc > 1 ? argv[1] : ":1"); + int secs = argc > 2 ? atoi(argv[2]) : 12; + KeyCode kFwd, kFire, kLeft, kRight; + int t; + + if (!d) { + fprintf(stderr, "xtest_move: no display\n"); + return 1; + } + /* No WM on Xvfb: give the game window input focus ourselves. */ + { + Window r, parent, *kids = NULL; + unsigned int nk = 0; + + if (XQueryTree(d, DefaultRootWindow(d), &r, &parent, &kids, &nk)) { + unsigned int i; + + for (i = 0; i < nk; i++) { + char *nm = NULL; + + if (XFetchName(d, kids[i], &nm) && nm) { + int hit = strstr(nm, "Freedoom") || strstr(nm, "Doom") || + strstr(nm, "gzdoom") || strstr(nm, "Outer"); + + XFree(nm); + if (hit) { + XSetInputFocus(d, kids[i], RevertToParent, CurrentTime); + fprintf(stderr, "xtest_move: focused 0x%lx\n", + (unsigned long)kids[i]); + break; + } + } + } + if (kids) + XFree(kids); + } + } + kFwd = XKeysymToKeycode(d, XK_Up); + kFire = XKeysymToKeycode(d, XK_space); + kLeft = XKeysymToKeycode(d, XK_Left); + kRight = XKeysymToKeycode(d, XK_Right); + fprintf(stderr, "xtest_move: fwd=%d fire=%d left=%d right=%d\n", + kFwd, kFire, kLeft, kRight); + XTestFakeKeyEvent(d, kFwd, 1, 0); + XTestFakeKeyEvent(d, kFire, 1, 0); + XFlush(d); + /* Continuous motion: rotate steadily (hold a turn key ~0.8 s, then + * the other) while forward+fire stay held - every frame changes. */ + for (t = 0; t < secs * 10; t++) { + KeyCode turn = (t & 8) ? kLeft : kRight; + Window wr, wpar, *wk = NULL; + unsigned int wnk = 0; + + /* Re-assert focus every tick: Xvfb has no WM, and any new X client + * (the capture tool) can leave the game unfocused - GZDoom pauses + * the game the moment SDL reports focus loss. */ + if (XQueryTree(d, DefaultRootWindow(d), &wr, &wpar, &wk, &wnk)) { + unsigned int i; + + for (i = 0; i < wnk; i++) { + char *nm = NULL; + + if (XFetchName(d, wk[i], &nm) && nm) { + int hit = strstr(nm, "Freedoom") || strstr(nm, "Outer") || + strstr(nm, "Doom"); + + XFree(nm); + if (hit) { + XSetInputFocus(d, wk[i], RevertToParent, + CurrentTime); + break; + } + } + } + if (wk) + XFree(wk); + } + XTestFakeKeyEvent(d, kLeft, 0, 0); + XTestFakeKeyEvent(d, kRight, 0, 0); + XTestFakeKeyEvent(d, turn, 1, 0); + XFlush(d); + usleep(100000); + } + XTestFakeKeyEvent(d, kLeft, 0, 0); + XTestFakeKeyEvent(d, kRight, 0, 0); + XTestFakeKeyEvent(d, kFwd, 0, 0); + XTestFakeKeyEvent(d, kFire, 0, 0); + XFlush(d); + XCloseDisplay(d); + fprintf(stderr, "xtest_move: done\n"); + return 0; +} -- cgit v1.2.3