#include "vdi_input_priority.h" #undef NDEBUG #include #include constexpr Sint32 frameCode = 123; static SDL_Event frame() { SDL_Event e{}; e.type = SDL_USEREVENT; e.user.code = frameCode; return e; } static SDL_Event input(Uint32 type, Uint32 window = 1) { SDL_Event e{}; e.type = type; e.key.windowID = window; return e; } static void push(SDL_Event e) { assert(SDL_PushEvent(&e) == 1); } static SDL_Event pop() { SDL_Event e{}; assert(SDL_PeepEvents(&e,1,SDL_GETEVENT,SDL_FIRSTEVENT,SDL_LASTEVENT)==1); return e; } int main() { assert(SDL_Init(SDL_INIT_EVENTS)==0); SDL_Event out{}; VdiInputPriority disabled(false, frameCode); push(input(SDL_MOUSEMOTION)); assert(!disabled.deferFrame(frame()) && !disabled.takeDeferred(out,1)); assert(pop().type == SDL_MOUSEMOTION); // Only a contiguous input prefix can pass a frame. No focus/quit/decoder // barrier may be skipped, even if input is waiting further down the queue. for (Uint32 barrier : {Uint32(SDL_WINDOWEVENT),Uint32(SDL_QUIT), Uint32(SDL_USEREVENT),Uint32(SDL_RENDER_DEVICE_RESET), Uint32(SDL_CONTROLLERDEVICEADDED)}) { VdiInputPriority scheduler(true, frameCode); push(input(SDL_MOUSEBUTTONDOWN)); push(input(SDL_MOUSEBUTTONUP)); push(input(barrier)); push(input(SDL_KEYDOWN)); assert(scheduler.deferFrame(frame())); assert(scheduler.takeDeferred(out,1) && out.type==SDL_MOUSEBUTTONDOWN); assert(scheduler.takeDeferred(out,1) && out.type==SDL_MOUSEBUTTONUP); assert(scheduler.takeDeferred(out,1) && out.type==SDL_USEREVENT && out.user.code==frameCode); assert(!scheduler.takeDeferred(out,1)); assert(pop().type==barrier && pop().type==SDL_KEYDOWN); assert(scheduler.prioritized()==2); } // Preserve all input order, including keyboard releases and drag edges. { VdiInputPriority scheduler(true,frameCode); for (Uint32 t : {Uint32(SDL_KEYDOWN),Uint32(SDL_MOUSEMOTION),Uint32(SDL_MOUSEBUTTONDOWN), Uint32(SDL_MOUSEMOTION),Uint32(SDL_MOUSEBUTTONUP),Uint32(SDL_KEYUP)}) push(input(t)); assert(scheduler.deferFrame(frame())); for (Uint32 t : {Uint32(SDL_KEYDOWN),Uint32(SDL_MOUSEMOTION),Uint32(SDL_MOUSEBUTTONDOWN), Uint32(SDL_MOUSEMOTION),Uint32(SDL_MOUSEBUTTONUP),Uint32(SDL_KEYUP)}) assert(scheduler.takeDeferred(out,1) && out.type==t); assert(scheduler.takeDeferred(out,1) && out.type==SDL_USEREVENT); } for (bool synthetic : {false,true}) { VdiInputPriority scheduler(true,frameCode); auto e=input(SDL_MOUSEMOTION,synthetic?1:2); if(synthetic) e.motion.which=SDL_TOUCH_MOUSEID; push(e); assert(scheduler.deferFrame(frame())); assert(scheduler.takeDeferred(out,1) && out.type==SDL_USEREVENT); assert(pop().type==SDL_MOUSEMOTION); } // A high-rate input device cannot starve video. { VdiInputPriority scheduler(true,frameCode); for(int i=0;i<1000;++i) push(input(SDL_MOUSEWHEEL)); assert(scheduler.deferFrame(frame())); unsigned n=0; while(scheduler.takeDeferred(out,1) && out.type!=SDL_USEREVENT) ++n; assert(n<=32 && n>0 && out.type==SDL_USEREVENT); SDL_FlushEvents(SDL_FIRSTEVENT,SDL_LASTEVENT); } { VdiInputPriority scheduler(true,frameCode); push(input(SDL_MOUSEBUTTONUP)); assert(scheduler.deferFrame(frame())); SDL_Delay(4); assert(scheduler.takeDeferred(out,1) && out.type==SDL_USEREVENT); assert(pop().type==SDL_MOUSEBUTTONUP); } // Instrumentation never consumes events or changes cursor visibility. VdiInputTiming timing(true); auto e=input(SDL_MOUSEMOTION); e.common.timestamp=SDL_GetTicks(); timing.observe(e,1); auto start=timing.startRender(); timing.endRender(start); timing.report(0); SDL_Quit(); std::puts("PASS: input FIFO, focus/quit/reset/window barriers, disabled mode, device/window isolation, count/time bounds"); }