// 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; }