87 lines
4.0 KiB
C++
87 lines
4.0 KiB
C++
#include "vdi_input_priority.h"
|
|
#undef NDEBUG
|
|
#include <cassert>
|
|
#include <cstdio>
|
|
|
|
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");
|
|
}
|