// Virtual-pointer injector mode for the F10 demo:
//
// f10_pointer_capture inject <hold_ms> <steps> <dx> <dy> <interval_ms>
//
// Plugs a `zwlr_virtual_pointer_v1` device in (which is what makes a headless
// wlroots seat gain the pointer capability — the F12 lesson), streams `steps`
// relative motions of (dx, dy) every `interval_ms`, keeps the device alive
// for another `hold_ms`, then destroys it (capability drop). One invocation
// is one plug/unplug cycle — but unlike `wlrctl pointer move`, whose device
// lives only long enough for a single motion (the motion is consumed
// establishing pointer focus, so the client under test never sees a motion
// stream at all), the held device delivers real `wl_pointer.motion` /
// `zwp_relative_pointer_v1.relative_motion` streams while focused.
// ./run.sh composes the F10 phase choreography out of these invocations.
module (module) injectinject;
import c; // ImportC shim — wsi_vpm_* / wsi_vptr_* are hand-marshalled (see ./c.c)
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.stdioD header file for C99 <stdio.h>
pubs.opengroup.org/onlinepubs/009695399/basedefs/stdio.h.html, stdio.h
Source
core/stdc/stdio.d
stdio : (alias) inject.fprintf = int core.stdc.stdio.fprintf(shared(core.stdc.stdio._IO_FILE)* stream, scope const(char*) format, scope const ...) nothrow @nogcfprintf, (alias) inject.printf = int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogcprintf, (alias shared global) inject.stderr = shared(core.stdc.stdio._IO_FILE*) core.stdc.stdio.stderrstderr;
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.stringD header file for C99.
pubs.opengroup.org/onlinepubs/009695399/basedefs/string.h.html, string.h
Source
core/stdc/string.d
string : (alias) inject.strcmp = int core.stdc.string.strcmp(scope const(char*) s1, scope const(char*) s2) pure nothrow @nogcstrcmp;
__gshared wl_proxy* _error_ inject.gi_mgrgi_mgr;
__gshared wl_seat* _error_ inject.gi_seatgi_seat;
extern (C) void inject.injGlobalinjGlobal(void* data, wl_registry* (parameter) wl_registry* regreg, uint name,
const(char)* iface, uint ver) nothrow @nogc
{
if (strcmp(iface, "zwlr_virtual_pointer_manager_v1") == 0)
gi_mgr = cast(wl_proxy*) wsi_registry_bind(reg, name,
&wsi_virtual_pointer_manager_interface, 1);
else if (strcmp(iface, wl_seat_interface.name) == 0 && gi_seat is null)
gi_seat = cast(wl_seat*) wsi_registry_bind(reg, name, &wl_seat_interface, 1);
}
extern (C) void inject.injGlobalRemoveinjGlobalRemove(void* data, wl_registry* (parameter) wl_registry* regreg, uint name) nothrow @nogc {}
__gshared wl_registry_listener _error_ inject.gi_registryListenergi_registryListener = {&injGlobal, &injGlobalRemove};
int int inject.injectMain(int holdMs, int steps, int dx, int dy, int intervalMs)injectMain(int (parameter) int holdMsholdMs, int (parameter) int stepssteps, int (parameter) int dxdx, int (parameter) int dydy, int (parameter) int intervalMsintervalMs)
{
wl_display* (local variable) _error_ dpydpy = wl_display_connect(null);
if (dpy is null)
{
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogcprintf("SKIP: inject: no Wayland compositor\n");
return 0;
}
wl_registry* (local variable) _error_ regreg = wsi_display_get_registry(dpy);
wsi_registry_add_listener(reg, &gi_registryListener, null);
wl_display_roundtrip(dpy);
if (gi_mgr is null)
{
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogcprintf("SKIP: inject: no zwlr_virtual_pointer_manager_v1\n");
wl_display_disconnect(dpy);
return 0;
}
wl_proxy* (local variable) _error_ ptrptr = wsi_vpm_create_virtual_pointer(gi_mgr, gi_seat);
wl_display_roundtrip(dpy); // device plugged → seat gains the pointer capability
foreach ((local variable) int ii; 0 .. (parameter) int stepssteps)
{
wsi_vptr_motion(ptr, 0, dx * 256, dy * 256);
wsi_vptr_frame(ptr);
wl_display_flush(dpy);
usleep(intervalMs * 1000);
}
usleep(holdMs * 1000);
wsi_vptr_destroy(ptr); // device unplugged → capability drop on the seat
wsi_vpm_destroy(gi_mgr);
wl_display_roundtrip(dpy);
wl_display_disconnect(dpy);
int core.stdc.stdio.fprintf(shared(core.stdc.stdio._IO_FILE)* stream, scope const(char*) format, scope const ...) nothrow @nogcfprintf((shared global) shared(core.stdc.stdio._IO_FILE*) core.stdc.stdio.stderrstderr, "inject: done steps=%d delta=%d,%d interval_ms=%d hold_ms=%d\n",
(parameter) int stepssteps, (parameter) int dxdx, (parameter) int dydy, (parameter) int intervalMsintervalMs, (parameter) int holdMsholdMs);
return 0;
}