Modifies WaitEvent and WaitEventTimeout to actually wait instead of polling

When possible use native os functions to make a blocking call waiting for
an incoming event. Previous behavior was to continuously poll the event
queue with a small delay between each poll.

The blocking call uses a new optional video driver event,
WaitEventTimeout, if available. It is called only if an window
already shown is available. If present the window is designated
using the variable wakeup_window to receive a wakeup event if
needed.

The WaitEventTimeout function accept a timeout parameter. If
positive the call will wait for an event or return if the timeout
expired without any event. If the timeout is zero it will
implement a polling behavior. If the timeout is negative the
function will block indefinetely waiting for an event.

To let the main thread sees events sent form a different thread
a "wake-up" signal is sent to the main thread if the main thread
is in a blocking state. The wake-up event is sent to the designated
wakeup_window if present.

The wake-up event is sent only if the PushEvent call is coming
from a different thread. Before sending the wake-up event
the ID of the thread making the blocking call is saved using the
variable blocking_thread_id and it is compared to the current
thread's id to decide if the wake-up event should be sent.

Two new optional video device methods are introduced:

WaitEventTimeout
SendWakeupEvent

in addition the mutex

wakeup_lock

which is defined and initialized but only for the drivers supporting the
methods above.

If the methods are not present the system behaves as previously
performing a periodic polling of the events queue.

The blocking call is disabled if a joystick or sensor is detected
and falls back to previous behavior.
This commit is contained in:
Francesco Abbate
2021-03-12 21:58:20 +01:00
committed by Sam Lantinga
parent 40e5ce7fe5
commit 0dd7024d55
16 changed files with 716 additions and 132 deletions

View File

@@ -759,6 +759,80 @@ SDL_PollEvent(SDL_Event * event)
return SDL_WaitEventTimeout(event, 0);
}
static int
SDL_WaitEventTimeout_Device(_THIS, SDL_Window *wakeup_window, SDL_Event * event, int timeout)
{
/* Release any keys held down from last frame */
SDL_ReleaseAutoReleaseKeys();
for (;;) {
if (!_this->wakeup_lock || SDL_LockMutex(_this->wakeup_lock) == 0) {
int status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
/* If status == 0 we are going to block so wakeup will be needed. */
if (status == 0) {
_this->wakeup_window = wakeup_window;
_this->blocking_thread_id = SDL_ThreadID();
} else {
_this->wakeup_window = NULL;
_this->blocking_thread_id = 0;
}
if (_this->wakeup_lock) {
SDL_UnlockMutex(_this->wakeup_lock);
}
if (status < 0) {
/* Got an error: return */
break;
}
if (status > 0) {
/* There is an event, we can return. */
SDL_SendPendingSignalEvents(); /* in case we had a signal handler fire, etc. */
return 1;
}
/* No events found in the queue, call WaitEventTimeout to wait for an event. */
status = _this->WaitEventTimeout(_this, timeout);
/* Set wakeup_window to NULL without holding the lock. */
_this->wakeup_window = NULL;
if (status <= 0) {
/* There is either an error or the timeout is elapsed: return */
return 0;
}
/* An event was found and pumped into the SDL events queue. Continue the loop
to let SDL_PeepEvents pick it up .*/
}
}
return 0;
}
static int
SDL_events_need_polling() {
SDL_bool need_polling = SDL_FALSE;
#if !SDL_JOYSTICK_DISABLED
need_polling = \
(!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY)) \
&& (SDL_NumJoysticks() > 0);
#endif
#if !SDL_SENSOR_DISABLED
need_polling = need_polling || (!SDL_disabled_events[SDL_SENSORUPDATE >> 8] && \
(SDL_NumSensors() > 0));
#endif
return need_polling;
}
static SDL_Window *
SDL_find_active_window(SDL_VideoDevice * _this)
{
SDL_Window *window;
for (window = _this->windows; window; window = window->next) {
if (!window->is_destroying) {
return window;
}
}
return NULL;
}
int
SDL_WaitEvent(SDL_Event * event)
{
@@ -768,11 +842,24 @@ SDL_WaitEvent(SDL_Event * event)
int
SDL_WaitEventTimeout(SDL_Event * event, int timeout)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
SDL_bool need_polling = SDL_events_need_polling();
SDL_Window *wakeup_window = NULL;
Uint32 expiration = 0;
if (timeout > 0)
expiration = SDL_GetTicks() + timeout;
if (!need_polling && _this) {
/* Look if a shown window is available to send the wakeup event. */
wakeup_window = SDL_find_active_window(_this);
need_polling = (wakeup_window == NULL);
}
if (!need_polling && _this && _this->WaitEventTimeout && _this->SendWakeupEvent) {
return SDL_WaitEventTimeout_Device(_this, wakeup_window, event, timeout);
}
for (;;) {
SDL_PumpEvents();
switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
@@ -796,6 +883,24 @@ SDL_WaitEventTimeout(SDL_Event * event, int timeout)
}
}
static int
SDL_SendWakeupEvent()
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (!_this || !_this->SendWakeupEvent) {
return 0;
}
if (!_this->wakeup_lock || SDL_LockMutex(_this->wakeup_lock) == 0) {
if (_this->wakeup_window && _this->blocking_thread_id != 0 && _this->blocking_thread_id != SDL_ThreadID()) {
_this->SendWakeupEvent(_this, _this->wakeup_window);
}
if (_this->wakeup_lock) {
SDL_UnlockMutex(_this->wakeup_lock);
}
}
return 0;
}
int
SDL_PushEvent(SDL_Event * event)
{
@@ -845,6 +950,7 @@ SDL_PushEvent(SDL_Event * event)
return -1;
}
SDL_SendWakeupEvent();
SDL_GestureProcessEvent(event);
return 1;

View File

@@ -290,6 +290,8 @@ struct SDL_VideoDevice
/*
* Event manager functions
*/
int (*WaitEventTimeout) (_THIS, int timeout);
void (*SendWakeupEvent) (_THIS, SDL_Window *window);
void (*PumpEvents) (_THIS);
/* Suspend the screensaver */
@@ -324,6 +326,9 @@ struct SDL_VideoDevice
/* Data common to all drivers */
SDL_bool is_dummy;
SDL_bool suspend_screensaver;
SDL_Window *wakeup_window;
SDL_threadID blocking_thread_id;
SDL_mutex *wakeup_lock; /* Initialized only if WaitEventTimeout/SendWakeupEvent are supported */
int num_displays;
SDL_VideoDisplay *displays;
SDL_Window *windows;

View File

@@ -25,6 +25,8 @@
extern void Cocoa_RegisterApp(void);
extern void Cocoa_PumpEvents(_THIS);
extern int Cocoa_WaitEventTimeout(_THIS, int timeout);
extern void Cocoa_SendWakeupEvent(_THIS, SDL_Window *window);
extern void Cocoa_SuspendScreenSaver(_THIS);
#endif /* SDL_cocoaevents_h_ */

View File

@@ -512,9 +512,8 @@ Cocoa_RegisterApp(void)
}
}}
void
Cocoa_PumpEvents(_THIS)
{ @autoreleasepool
int
Cocoa_PumpEventsUntilDate(_THIS, NSDate *expiration, bool accumulate)
{
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
/* Update activity every 30 seconds to prevent screensaver */
@@ -530,9 +529,9 @@ Cocoa_PumpEvents(_THIS)
#endif
for ( ; ; ) {
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES ];
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:expiration inMode:NSDefaultRunLoopMode dequeue:YES ];
if ( event == nil ) {
break;
return 0;
}
if (!s_bShouldHandleEventsInSDLApplication) {
@@ -541,7 +540,52 @@ Cocoa_PumpEvents(_THIS)
// Pass events down to SDLApplication to be handled in sendEvent:
[NSApp sendEvent:event];
if ( !accumulate) {
break;
}
}
return 1;
}
int
Cocoa_WaitEventTimeout(_THIS, int timeout)
{ @autoreleasepool
{
if (timeout > 0) {
NSDate *limitDate = [NSDate dateWithTimeIntervalSinceNow: (double) timeout / 1000.0];
return Cocoa_PumpEventsUntilDate(_this, limitDate, false);
} else if (timeout == 0) {
return Cocoa_PumpEventsUntilDate(_this, [NSDate distantPast], false);
} else {
while (Cocoa_PumpEventsUntilDate(_this, [NSDate distantFuture], false) == 0) {
}
}
return 1;
}}
void
Cocoa_PumpEvents(_THIS)
{ @autoreleasepool
{
Cocoa_PumpEventsUntilDate(_this, [NSDate distantPast], true);
}}
void Cocoa_SendWakeupEvent(_THIS, SDL_Window *window)
{ @autoreleasepool
{
NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
NSEvent* event = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
location: NSMakePoint(0,0)
modifierFlags: 0
timestamp: 0.0
windowNumber: nswindow.windowNumber
context: nil
subtype: 0
data1: 0
data2: 0];
[NSApp postEvent: event atStart: YES];
}}
void

View File

@@ -38,6 +38,9 @@ static void Cocoa_VideoQuit(_THIS);
static void
Cocoa_DeleteDevice(SDL_VideoDevice * device)
{
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
SDL_free(device->driverdata);
SDL_free(device);
}
@@ -63,6 +66,7 @@ Cocoa_CreateDevice(int devindex)
return NULL;
}
device->driverdata = data;
device->wakeup_lock = SDL_CreateMutex();
/* Set the function pointers */
device->VideoInit = Cocoa_VideoInit;
@@ -73,6 +77,8 @@ Cocoa_CreateDevice(int devindex)
device->GetDisplayModes = Cocoa_GetDisplayModes;
device->SetDisplayMode = Cocoa_SetDisplayMode;
device->PumpEvents = Cocoa_PumpEvents;
device->WaitEventTimeout = Cocoa_WaitEventTimeout;
device->SendWakeupEvent = Cocoa_SendWakeupEvent;
device->SuspendScreenSaver = Cocoa_SuspendScreenSaver;
device->CreateSDLWindow = Cocoa_CreateWindow;

View File

@@ -1276,6 +1276,45 @@ void SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata)
g_WindowsMessageHookData = userdata;
}
int
WIN_WaitEventTimeout(_THIS, int timeout)
{
MSG msg;
if (g_WindowsEnableMessageLoop) {
BOOL message_result;
UINT_PTR timer_id = 0;
if (timeout > 0) {
timer_id = SetTimer(NULL, 0, timeout, NULL);
message_result = GetMessage(&msg, 0, 0, 0);
KillTimer(NULL, timer_id);
} else if (timeout == 0) {
message_result = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
} else {
message_result = GetMessage(&msg, 0, 0, 0);
}
if (message_result) {
if (msg.message == WM_TIMER && msg.hwnd == NULL && msg.wParam == timer_id) {
return 0;
}
if (g_WindowsMessageHook) {
g_WindowsMessageHook(g_WindowsMessageHookData, msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
/* Always translate the message in case it's a non-SDL window (e.g. with Qt integration) */
TranslateMessage(&msg);
DispatchMessage(&msg);
return 1;
}
}
return 0;
}
void
WIN_SendWakeupEvent(_THIS, SDL_Window *window)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
PostMessage(data->hwnd, data->videodata->_SDL_WAKEUP, 0, 0);
}
void
WIN_PumpEvents(_THIS)
{

View File

@@ -31,6 +31,8 @@ extern LRESULT CALLBACK WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lP
extern LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam);
extern void WIN_PumpEvents(_THIS);
extern void WIN_SendWakeupEvent(_THIS, SDL_Window *window);
extern int WIN_WaitEventTimeout(_THIS, int timeout);
#endif /* SDL_windowsevents_h_ */

View File

@@ -87,7 +87,9 @@ WIN_DeleteDevice(SDL_VideoDevice * device)
if (data->shcoreDLL) {
SDL_UnloadObject(data->shcoreDLL);
}
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
SDL_free(device->driverdata);
SDL_free(device);
}
@@ -113,6 +115,7 @@ WIN_CreateDevice(int devindex)
return NULL;
}
device->driverdata = data;
device->wakeup_lock = SDL_CreateMutex();
data->userDLL = SDL_LoadObject("USER32.DLL");
if (data->userDLL) {
@@ -139,6 +142,8 @@ WIN_CreateDevice(int devindex)
device->GetDisplayModes = WIN_GetDisplayModes;
device->SetDisplayMode = WIN_SetDisplayMode;
device->PumpEvents = WIN_PumpEvents;
device->WaitEventTimeout = WIN_WaitEventTimeout;
device->SendWakeupEvent = WIN_SendWakeupEvent;
device->SuspendScreenSaver = WIN_SuspendScreenSaver;
device->CreateSDLWindow = WIN_CreateWindow;
@@ -226,6 +231,8 @@ VideoBootStrap WINDOWS_bootstrap = {
int
WIN_VideoInit(_THIS)
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
if (WIN_InitModes(_this) < 0) {
return -1;
}
@@ -236,6 +243,8 @@ WIN_VideoInit(_THIS)
SDL_AddHintCallback(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, UpdateWindowsEnableMessageLoop, NULL);
SDL_AddHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL);
data->_SDL_WAKEUP = RegisterWindowMessageA("_SDL_WAKEUP");
return 0;
}

View File

@@ -190,6 +190,7 @@ typedef struct SDL_VideoData
TSFSink *ime_ippasink;
BYTE pre_hook_key_state[256];
UINT _SDL_WAKEUP;
} SDL_VideoData;
extern SDL_bool g_WindowsEnableMessageLoop;

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,8 @@
#define SDL_x11events_h_
extern void X11_PumpEvents(_THIS);
extern int X11_WaitEventTimeout(_THIS, int timeout);
extern void X11_SendWakeupEvent(_THIS, SDL_Window *window);
extern void X11_SuspendScreenSaver(_THIS);
#endif /* SDL_x11events_h_ */

View File

@@ -105,7 +105,13 @@ X11_DeleteDevice(SDL_VideoDevice * device)
X11_XSetErrorHandler(orig_x11_errhandler);
X11_XCloseDisplay(data->display);
}
if (data->request_display) {
X11_XCloseDisplay(data->request_display);
}
SDL_free(data->windowlist);
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
SDL_free(device->driverdata);
SDL_free(device);
@@ -178,10 +184,22 @@ X11_CreateDevice(int devindex)
return NULL;
}
device->driverdata = data;
device->wakeup_lock = SDL_CreateMutex();
data->global_mouse_changed = SDL_TRUE;
data->display = x11_display;
data->request_display = X11_XOpenDisplay(display);
if (data->request_display == NULL) {
X11_XCloseDisplay(data->display);
SDL_free(device->driverdata);
SDL_free(device);
SDL_X11_UnloadSymbols();
return NULL;
}
device->wakeup_lock = SDL_CreateMutex();
#ifdef X11_DEBUG
X11_XSynchronize(data->display, True);
#endif
@@ -201,6 +219,8 @@ X11_CreateDevice(int devindex)
device->SetDisplayMode = X11_SetDisplayMode;
device->SuspendScreenSaver = X11_SuspendScreenSaver;
device->PumpEvents = X11_PumpEvents;
device->WaitEventTimeout = X11_WaitEventTimeout;
device->SendWakeupEvent = X11_SendWakeupEvent;
device->CreateSDLWindow = X11_CreateWindow;
device->CreateSDLWindowFrom = X11_CreateWindowFrom;
@@ -403,6 +423,7 @@ X11_VideoInit(_THIS)
GET_ATOM(_NET_WM_USER_TIME);
GET_ATOM(_NET_ACTIVE_WINDOW);
GET_ATOM(_NET_FRAME_EXTENTS);
GET_ATOM(_SDL_WAKEUP);
GET_ATOM(UTF8_STRING);
GET_ATOM(PRIMARY);
GET_ATOM(XdndEnter);

View File

@@ -75,6 +75,7 @@
typedef struct SDL_VideoData
{
Display *display;
Display *request_display;
char *classname;
pid_t pid;
XIM im;
@@ -111,6 +112,7 @@ typedef struct SDL_VideoData
Atom _NET_WM_USER_TIME;
Atom _NET_ACTIVE_WINDOW;
Atom _NET_FRAME_EXTENTS;
Atom _SDL_WAKEUP;
Atom UTF8_STRING;
Atom PRIMARY;
Atom XdndEnter;

View File

@@ -20,6 +20,7 @@ add_definitions(-DHAVE_OPENGL)
endif()
add_executable(checkkeys checkkeys.c)
add_executable(checkkeysthreads checkkeysthreads.c)
add_executable(loopwave loopwave.c)
add_executable(loopwavequeue loopwavequeue.c)
add_executable(testresample testresample.c)

View File

@@ -9,6 +9,7 @@ LIBS = @LIBS@
TARGETS = \
checkkeys$(EXE) \
checkkeysthreads$(EXE) \
controllermap$(EXE) \
loopwave$(EXE) \
loopwavequeue$(EXE) \
@@ -83,6 +84,9 @@ Makefile: $(srcdir)/Makefile.in
checkkeys$(EXE): $(srcdir)/checkkeys.c
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
checkkeysthreads$(EXE): $(srcdir)/checkkeysthreads.c
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
loopwave$(EXE): $(srcdir)/loopwave.c
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)

275
test/checkkeysthreads.c Normal file
View File

@@ -0,0 +1,275 @@
/*
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely.
*/
/* Simple program: Loop, watching keystrokes
Note that you need to call SDL_PollEvent() or SDL_WaitEvent() to
pump the event loop and catch keystrokes.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
#include "SDL.h"
int done;
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
static void
quit(int rc)
{
SDL_Quit();
exit(rc);
}
static void
print_string(char **text, size_t *maxlen, const char *fmt, ...)
{
int len;
va_list ap;
va_start(ap, fmt);
len = SDL_vsnprintf(*text, *maxlen, fmt, ap);
if (len > 0) {
*text += len;
if ( ((size_t) len) < *maxlen ) {
*maxlen -= (size_t) len;
} else {
*maxlen = 0;
}
}
va_end(ap);
}
static void
print_modifiers(char **text, size_t *maxlen)
{
int mod;
print_string(text, maxlen, " modifiers:");
mod = SDL_GetModState();
if (!mod) {
print_string(text, maxlen, " (none)");
return;
}
if (mod & KMOD_LSHIFT)
print_string(text, maxlen, " LSHIFT");
if (mod & KMOD_RSHIFT)
print_string(text, maxlen, " RSHIFT");
if (mod & KMOD_LCTRL)
print_string(text, maxlen, " LCTRL");
if (mod & KMOD_RCTRL)
print_string(text, maxlen, " RCTRL");
if (mod & KMOD_LALT)
print_string(text, maxlen, " LALT");
if (mod & KMOD_RALT)
print_string(text, maxlen, " RALT");
if (mod & KMOD_LGUI)
print_string(text, maxlen, " LGUI");
if (mod & KMOD_RGUI)
print_string(text, maxlen, " RGUI");
if (mod & KMOD_NUM)
print_string(text, maxlen, " NUM");
if (mod & KMOD_CAPS)
print_string(text, maxlen, " CAPS");
if (mod & KMOD_MODE)
print_string(text, maxlen, " MODE");
}
static void
PrintModifierState()
{
char message[512];
char *spot;
size_t left;
spot = message;
left = sizeof(message);
print_modifiers(&spot, &left);
SDL_Log("Initial state:%s\n", message);
}
static void
PrintKey(SDL_Keysym * sym, SDL_bool pressed, SDL_bool repeat)
{
char message[512];
char *spot;
size_t left;
spot = message;
left = sizeof(message);
/* Print the keycode, name and state */
if (sym->sym) {
print_string(&spot, &left,
"Key %s: scancode %d = %s, keycode 0x%08X = %s ",
pressed ? "pressed " : "released",
sym->scancode,
SDL_GetScancodeName(sym->scancode),
sym->sym, SDL_GetKeyName(sym->sym));
} else {
print_string(&spot, &left,
"Unknown Key (scancode %d = %s) %s ",
sym->scancode,
SDL_GetScancodeName(sym->scancode),
pressed ? "pressed " : "released");
}
print_modifiers(&spot, &left);
if (repeat) {
print_string(&spot, &left, " (repeat)");
}
SDL_Log("%s\n", message);
fflush(stderr);
}
static void
PrintText(char *eventtype, char *text)
{
char *spot, expanded[1024];
expanded[0] = '\0';
for ( spot = text; *spot; ++spot )
{
size_t length = SDL_strlen(expanded);
SDL_snprintf(expanded + length, sizeof(expanded) - length, "\\x%.2x", (unsigned char)*spot);
}
SDL_Log("%s Text (%s): \"%s%s\"\n", eventtype, expanded, *text == '"' ? "\\" : "", text);
}
void
loop()
{
SDL_Event event;
/* Check for events */
/*SDL_WaitEvent(&event); emscripten does not like waiting*/
fprintf(stderr, "starting loop\n"); fflush(stderr);
// while (SDL_PollEvent(&event)) {
while (!done && SDL_WaitEvent(&event)) {
fprintf(stderr, "got event type: %d\n", event.type); fflush(stderr);
switch (event.type) {
case SDL_KEYDOWN:
case SDL_KEYUP:
PrintKey(&event.key.keysym, (event.key.state == SDL_PRESSED) ? SDL_TRUE : SDL_FALSE, (event.key.repeat) ? SDL_TRUE : SDL_FALSE);
break;
case SDL_TEXTEDITING:
PrintText("EDIT", event.text.text);
break;
case SDL_TEXTINPUT:
PrintText("INPUT", event.text.text);
break;
case SDL_MOUSEBUTTONDOWN:
/* Left button quits the app, other buttons toggles text input */
fprintf(stderr, "mouse button down button: %d (LEFT=%d)\n", event.button.button, SDL_BUTTON_LEFT); fflush(stderr);
if (event.button.button == SDL_BUTTON_LEFT) {
done = 1;
} else {
if (SDL_IsTextInputActive()) {
SDL_Log("Stopping text input\n");
SDL_StopTextInput();
} else {
SDL_Log("Starting text input\n");
SDL_StartTextInput();
}
}
break;
case SDL_QUIT:
done = 1;
break;
default:
break;
}
fprintf(stderr, "waiting new event\n"); fflush(stderr);
}
fprintf(stderr, "exiting event loop\n"); fflush(stderr);
#ifdef __EMSCRIPTEN__
if (done) {
emscripten_cancel_main_loop();
}
#endif
}
/* Very simple thread - counts 0 to 9 delaying 50ms between increments */
static int ping_thread(void *ptr)
{
int cnt;
SDL_Event sdlevent;
memset(&sdlevent, 0 , sizeof(SDL_Event));
for (cnt = 0; cnt < 10; ++cnt) {
fprintf(stderr, "sending event (%d/%d) from thread.\n", cnt + 1, 10); fflush(stderr);
sdlevent.type = SDL_KEYDOWN;
sdlevent.key.keysym.sym = SDLK_1;
SDL_PushEvent(&sdlevent);
SDL_Delay(1000 + rand() % 1000);
}
return cnt;
}
int
main(int argc, char *argv[])
{
SDL_Window *window;
/* Enable standard application logging */
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
/* Initialize SDL */
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
return (1);
}
/* Set 640x480 video mode */
window = SDL_CreateWindow("CheckKeys Test",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
640, 480, 0);
if (!window) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create 640x480 window: %s\n",
SDL_GetError());
quit(2);
}
#if __IPHONEOS__
/* Creating the context creates the view, which we need to show keyboard */
SDL_GL_CreateContext(window);
#endif
SDL_StartTextInput();
/* Print initial modifier state */
SDL_PumpEvents();
PrintModifierState();
/* Watch keystrokes */
done = 0;
SDL_Thread *thread;
thread = SDL_CreateThread(ping_thread, "PingThread", (void *)NULL);
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(loop, 0, 1);
#else
while (!done) {
loop();
}
#endif
SDL_WaitThread(thread, NULL);
SDL_Quit();
return (0);
}
/* vi: set ts=4 sw=4 expandtab: */