In my SDL 1.2 program I have a function KeyPressed which needs to check if a key has been pressed. If the mouse pointer has not been moved in front of the window the program halts as intended when a key is pressed. On the other hand, if the mouse pointer is moved in front of the window the event queue seems to fill up and after that the program does not respond to key presses. Is there a way to empty the event queue when there are no keyboard events in it?
#include <SDL/SDL.h>
#include <stdio.h>
static void Init(int *error)
{
SDL_Surface *display;
*error = SDL_Init(SDL_INIT_VIDEO);
if (! *error) {
display = SDL_SetVideoMode(640, 480, 8, 0);
if (display != NULL) {
*error = 0;
} else {
fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError());
*error = 1;
}
} else {
fprintf(stderr, "SDL_Init: %s\n", SDL_GetError());
*error = 1;
}
}
static int KeyPressed(void)
{
SDL_Event event;
int count, result;
result = 0;
SDL_PumpEvents();
count = SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_EVENTMASK(SDL_KEYDOWN));
switch (count) {
case -1:
fprintf(stderr, "SDL_PeepEvents: %s\n", SDL_GetError());
break;
case 0:
break;
case 1:
result = 1;
break;
}
return result;
}
int main(void)
{
int error;
Init(&error);
if (! error) {
do {
/*nothing*/
} while (! KeyPressed());
}
return error;
}
You should be checking event's in a while loop using polling which will pop the events from the queue as they are handled. Use either multiple if/then statements or a swicth block for handling the event. I recommend this method as you can easily miss important events such as SDL_QUIT when using SDL_PeepEvent
Basic example:
SDL_Event e;
while (SDL_PollEvent(&e))
{
if (e.type == SDL_QUIT)
{
// do something here
}
}
The following solution, inspired by Zammalad's comment seems to work. When no key down event is found we remove one event (typically a mouse event) from the queue to make room for new events. To make the code more robust I have also replaced the scalar event with the array events.
#define LEN(a) ((int) (sizeof (a) / sizeof (a)[0]))
static int KeyPressed(void)
{
SDL_Event events[1];
int count, result;
result = 0;
SDL_PumpEvents();
/*search the event queue for key down events*/
count = SDL_PeepEvents(events, LEN(events), SDL_PEEKEVENT, SDL_EVENTMASK(SDL_KEYDOWN));
switch (count) {
case -1:
fprintf(stderr, "SDL_PeepEvents: %s\n", SDL_GetError());
break;
case 0:
/*make room for new events by removing (non-key down) event from the queue*/
count = SDL_PeepEvents(events, LEN(events), SDL_GETEVENT, -1);
if ((count > 0) && (events[0].type == SDL_QUIT)) {
exit(EXIT_SUCCESS);
}
break;
case 1:
result = 1;
break;
}
return result;
}
Related
I was try to capture old and future windows events logs by subscribing "Security" channel. But i get only old Events and all future events are missing.
Currently working on Windows events Logs.
I want old events from specific event Record id and all future events.
for this I subscribe specific channel e.g. "Security" and try to capture events that i want.
But in case of Security channel for subscription i use "EvtSubscribeStartAtOldestRecord" flag so that all old events and future events will be subscribed but I got only old events only and future events are missing.
EvtSubscribe (
NULL,
arrWaitHandle[1],
pwszChannel,
wsQuery,
NULL,
NULL,
NULL,
EvtSubscribeStartAtOldestRecord
);
for subscribe the channel i Use above API and EvtSubscribeStartAtOldestRecord flag because i want old events as well as future events but in case of "Security" channel I got only old events and future events are not captured.
I observe that in case of other channels e.g "Application" or "System" I got both old as well as future events.
But for "Security" channel I got only old Events.
I am able to capture both old events and future events with the domain admin account, with the following code, that's the sample on Subscribing to Events and I've changed few of them:
#include <windows.h>
#include <conio.h>
#include <stdio.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib")
#define ARRAY_SIZE 10
DWORD EnumerateResults(EVT_HANDLE hResults);
DWORD PrintEvent(EVT_HANDLE hEvent);
BOOL IsKeyEvent(HANDLE hStdIn);
void __cdecl wmain()
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hSubscription = NULL;
HANDLE aWaitHandles[2];
DWORD dwWait = 0;
// Get a handle for console input, so you can break out of the loop.
aWaitHandles[0] = GetStdHandle(STD_INPUT_HANDLE);
if (INVALID_HANDLE_VALUE == aWaitHandles[0])
{
wprintf(L"GetStdHandle failed with %lu.\n", GetLastError());
goto cleanup;
}
// Get a handle to a manual reset event object that the subscription will signal
// when events become available that match your query criteria.
aWaitHandles[1] = CreateEvent(NULL, TRUE, TRUE, NULL);
if (NULL == aWaitHandles[1])
{
wprintf(L"CreateEvent failed with %lu.\n", GetLastError());
goto cleanup;
}
// Subscribe to events.
hSubscription = EvtSubscribe(NULL, aWaitHandles[1], L"Security", NULL, NULL, NULL, NULL, EvtSubscribeStartAtOldestRecord);
if (NULL == hSubscription)
{
status = GetLastError();
if (ERROR_EVT_CHANNEL_NOT_FOUND == status)
wprintf(L"Channel was not found.\n");
else if (ERROR_EVT_INVALID_QUERY == status)
wprintf(L"The query was not found.\n");
else
wprintf(L"EvtSubscribe failed with %lu.\n", status);
goto cleanup;
}
wprintf(L"Press any key to quit.\n");
// Loop until the user presses a key or there is an error.
while (true)
{
dwWait = WaitForMultipleObjects(sizeof(aWaitHandles) / sizeof(HANDLE), aWaitHandles, FALSE, INFINITE);
if (0 == dwWait - WAIT_OBJECT_0) // Console input
{
if (IsKeyEvent(aWaitHandles[0]))
break;
}
else if (1 == dwWait - WAIT_OBJECT_0) // Query results
{
if (ERROR_NO_MORE_ITEMS != (status = EnumerateResults(hSubscription)))
{
break;
}
ResetEvent(aWaitHandles[1]);
}
else
{
if (WAIT_FAILED == dwWait)
{
wprintf(L"WaitForSingleObject failed with %lu\n", GetLastError());
}
break;
}
}
cleanup:
if (hSubscription)
EvtClose(hSubscription);
if (aWaitHandles[0])
CloseHandle(aWaitHandles[0]);
if (aWaitHandles[1])
CloseHandle(aWaitHandles[1]);
}
// Enumerate the events in the result set.
DWORD EnumerateResults(EVT_HANDLE hResults)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hEvents[ARRAY_SIZE];
DWORD dwReturned = 0;
while (true)
{
// Get a block of events from the result set.
if (!EvtNext(hResults, ARRAY_SIZE, hEvents, INFINITE, 0, &dwReturned))
{
if (ERROR_NO_MORE_ITEMS != (status = GetLastError()))
{
wprintf(L"EvtNext failed with %lu\n", status);
}
goto cleanup;
}
// For each event, call the PrintEvent function which renders the
// event for display.
for (DWORD i = 0; i < dwReturned; i++)
{
if (ERROR_SUCCESS == (status = PrintEvent(hEvents[i])))
{
EvtClose(hEvents[i]);
hEvents[i] = NULL;
}
else
{
goto cleanup;
}
}
}
cleanup:
// Closes any events in case an error occurred above.
for (DWORD i = 0; i < dwReturned; i++)
{
if (NULL != hEvents[i])
EvtClose(hEvents[i]);
}
return status;
}
// Render the event as an XML string and print it.
DWORD PrintEvent(EVT_HANDLE hEvent)
{
DWORD status = ERROR_SUCCESS;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD dwPropertyCount = 0;
LPWSTR pRenderedContent = NULL;
// The EvtRenderEventXml flag tells EvtRender to render the event as an XML string.
if (!EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount))
{
if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError()))
{
dwBufferSize = dwBufferUsed;
pRenderedContent = (LPWSTR)malloc(dwBufferSize);
if (pRenderedContent)
{
EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount);
}
else
{
wprintf(L"malloc failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtRender failed with %d\n", GetLastError());
goto cleanup;
}
}
wprintf(L"\n\n%s", pRenderedContent);
cleanup:
if (pRenderedContent)
free(pRenderedContent);
return status;
}
// Determines whether the console input was a key event.
BOOL IsKeyEvent(HANDLE hStdIn)
{
INPUT_RECORD Record[128];
DWORD dwRecordsRead = 0;
BOOL fKeyPress = FALSE;
if (ReadConsoleInput(hStdIn, Record, 128, &dwRecordsRead))
{
for (DWORD i = 0; i < dwRecordsRead; i++)
{
if (KEY_EVENT == Record[i].EventType)
{
fKeyPress = TRUE;
break;
}
}
}
return fKeyPress;
}
Common users do not have access to read Security logs. The Security log is designed for use by the system. However, users can read and clear the Security log if they have been granted the SE_SECURITY_NAME privilege (the "manage auditing and security log" user right).
UPDATE:
When I set the breakpoint into the event call back, the future events are also captured, but then nothing will be update to the console output. After pressing any key to quit, some inputs flashed across in the console. So I flush the console output buffer, Then solve the problem.
In function DWORD PrintEvent(EVT_HANDLE hEvent):
{
...
wprintf(L"\n\n%s", pRenderedContent);
fflush(stdout);
...
}
I am trying to read mouse events from the /dev/input/mice file. I am able to parse the 3 byte mouse input for getting the three button states and the increments in X and Y coordinates. However, the mouse input when I scroll up is identical to that when I scroll down. How do I distinguish a scroll up event from a scroll down event? Are there any ioctls that can do any required configuration so that I get different inputs from the mouse on these two events?
The following is a simple program to see the input from a mouse when a mouse event occurs. Scroll up and scroll down events cause the same output to be printed by this program (namely, 8 0 0).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
int main(void) {
int mouse_fd = open("/dev/input/mice", O_RDONLY | O_NONBLOCK);
signed char input[4];
ssize_t rd_cnt;
if(mouse_fd < 0)
{
perror("Could not open /dev/input/mice");
exit(EXIT_FAILURE);
}
while(true)
{
errno = 0;
rd_cnt = read(mouse_fd, input, 4);
if(rd_cnt <= 0 && errno != EAGAIN)
{
perror("Mouse read error:");
exit(EXIT_FAILURE);
}
else
{
for(int i = 0; i < rd_cnt; i++)
{
printf("%d", input[i]);
if(i == rd_cnt - 1)
{
printf("\n");
}
else
{
printf("\t");
}
}
}
}
return 0;
}
An alternative would be to use SDL2.
I've managed to mash together an example of reading mouse inputs with SDL, so take what you like from it.
#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
char* itoa(int i, char b[]){
char const digit[] = "0123456789";
char* p = b;
if(i<0){
*p++ = '-';
i *= -1;
}
int shifter = i;
do{ //Move to where representation ends
++p;
shifter = shifter/10;
}while(shifter);
*p = '\0';
do{ //Move back, inserting digits as u go
*--p = digit[i%10];
i = i/10;
}while(i);
return b;
}
int main()
{
//initialize the window
bool quit = false;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("Mouse Events", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
// the event that will occur when a mouse event happens
SDL_Event event;
while(!quit)
{
while (SDL_PollEvent(&event)) //returns one is there is a pending event (if an event happens)
{
switch(event.type)
{
case SDL_QUIT: //if the window is exited
quit = true;
break;
case SDL_MOUSEBUTTONDOWN:
switch (event.button.button)
{
case SDL_BUTTON_LEFT:
SDL_ShowSimpleMessageBox(0, "Click", "Left button was pressed!", window);
break;
case SDL_BUTTON_RIGHT:
SDL_ShowSimpleMessageBox(0, "Click", "Right button was pressed!", window);
break;
}
break;
case SDL_MOUSEWHEEL:
if(event.wheel.y == -1) //negative means the scroll wheel has gone away from the user
{
SDL_ShowSimpleMessageBox(0, "Wheel Event", "You rolled away from yourself!", window);
} else if (event.wheel.y == 1) //vice-versa
{
SDL_ShowSimpleMessageBox(0, "Wheel Event", "You rolled towards yourself!", window);
}
}
}
//do some SDL cleanup
SDL_Rect dstrect = { 288, 208, 64, 64 };
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
}
}
The event.wheel type can be found here: https://wiki.libsdl.org/SDL_MouseWheelEvent
Hope this is of some use to you!
If you don't want to use SDL2, it may be worth have a look in the source of the library to see what it's doing.
When I call the function PeekEvents below the program prints zeros on the standard output and never finishes even though I type on the keyboard when the SDL window has focus. Why doesn't the function catch my keystrokes?
void PeekEvents(void)
{
SDL_Event events[1];
int count;
do {
count = SDL_PeepEvents(events, LEN(events), SDL_PEEKEVENT, SDL_EVENTMASK(SDL_KEYDOWN));
printf("%d\n", count);
} while (count == 0);
}
Here is the complete program:
#include <SDL/SDL.h>
#include <stdio.h>
#define LEN(a) ((int) (sizeof (a) / sizeof (a)[0]))
static void PeekEvents(void)
{
SDL_Event events[1];
int count;
do {
count = SDL_PeepEvents(events, LEN(events), SDL_PEEKEVENT, SDL_EVENTMASK(SDL_KEYDOWN));
printf("%d\n", count);
} while (count == 0);
}
static void Init(int *error)
{
SDL_Surface *display;
*error = SDL_Init(SDL_INIT_VIDEO);
if (! *error) {
display = SDL_SetVideoMode(640, 480, 8, 0);
if (display != NULL) {
*error = 0;
} else {
fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError());
*error = 1;
}
} else {
fprintf(stderr, "SDL_Init: %s\n", SDL_GetError());
*error = 1;
}
}
int main(void)
{
int error;
Init(&error);
if (! error) {
PeekEvents();
}
return error;
}
Documentation states somewhere that SDL_INIT_EVENTS is implicit when using SDL_INIT_VIDEO.
You need to add a call to SDL_PumpEvents in your loop, otherwise no messages will ever get in the queue.
SDL_PumpEvents gathers all the pending input information from devices and places it on the event queue. Without calls to SDL_PumpEvents no events would ever be placed on the queue. Often the need for calls to SDL_PumpEvents is hidden from the user since SDL_PollEvent and SDL_WaitEvent implicitly call SDL_PumpEvents. However, if you are not polling or waiting for events (e.g. you are filtering them), then you must call SDL_PumpEvents to force an event queue update.
I'm trying to find out how to fix these memory leaks I'm getting while running this program with Valgrind. The leaks occur with the two allocations in nShell_client_main. But I'm not
sure how to properly free them.
I've tried freeing them at nShell_Connect, but it's causing libUV to abort the program. I've tried freeing them at the end of nShell_client_main, but then I get read/write errors when closing the loop. Does anyone know how I'm supposed to close these handles? I've read this, which got me started. But, it seams out-dated because uv_ip4_addr has a different prototype in the latest version.
(nShell_main is the "entry" point)
#include "nPort.h"
#include "nShell-main.h"
void nShell_Close(
uv_handle_t * term_handle
){
}
void nShell_Connect(uv_connect_t * term_handle, int status){
uv_close((uv_handle_t *) term_handle, 0);
}
nError * nShell_client_main(nShell * n_shell, uv_loop_t * n_shell_loop){
int uv_error = 0;
nError * n_error = 0;
uv_tcp_t * n_shell_socket = 0;
uv_connect_t * n_shell_connect = 0;
struct sockaddr_in dest_addr;
n_shell_socket = malloc(sizeof(uv_tcp_t));
if (!n_shell_socket){
// handle error
}
uv_error = uv_tcp_init(n_shell_loop, n_shell_socket);
if (uv_error){
// handle error
}
uv_error = uv_ip4_addr("127.0.0.1", NPORT, &dest_addr);
if (uv_error){
// handle error
}
n_shell_connect = malloc(sizeof(uv_connect_t));
if (!n_shell_connect){
// handle error
}
uv_error = uv_tcp_connect(n_shell_connect, n_shell_socket, (struct sockaddr *) &dest_addr, nShell_Connect);
if (uv_error){
// handle error
}
uv_error = uv_run(n_shell_loop, UV_RUN_DEFAULT);
if (uv_error){
// handle error
}
return 0;
}
nError * nShell_loop_main(nShell * n_shell){
int uv_error = 0;
nError * n_error = 0;
uv_loop_t * n_shell_loop = 0;
n_shell_loop = malloc(sizeof(uv_loop_t));
if (!n_shell_loop){
// handle error
}
uv_error = uv_loop_init(n_shell_loop);
if (uv_error){
// handle error
}
n_error = nShell_client_main(n_shell, n_shell_loop);
if (n_error){
// handle error
}
uv_loop_close(n_shell_loop);
free(n_shell_loop);
return 0;
}
The assertion is happening at the end of the switch statement in this excerpt of code (taken from Joyent's libUV page on Github):
void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
handle->flags |= UV_CLOSING;
handle->close_cb = close_cb;
switch (handle->type) {
case UV_NAMED_PIPE:
uv__pipe_close((uv_pipe_t*)handle);
break;
case UV_TTY:
uv__stream_close((uv_stream_t*)handle);
break;
case UV_TCP:
uv__tcp_close((uv_tcp_t*)handle);
break;
case UV_UDP:
uv__udp_close((uv_udp_t*)handle);
break;
case UV_PREPARE:
uv__prepare_close((uv_prepare_t*)handle);
break;
case UV_CHECK:
uv__check_close((uv_check_t*)handle);
break;
case UV_IDLE:
uv__idle_close((uv_idle_t*)handle);
break;
case UV_ASYNC:
uv__async_close((uv_async_t*)handle);
break;
case UV_TIMER:
uv__timer_close((uv_timer_t*)handle);
break;
case UV_PROCESS:
uv__process_close((uv_process_t*)handle);
break;
case UV_FS_EVENT:
uv__fs_event_close((uv_fs_event_t*)handle);
break;
case UV_POLL:
uv__poll_close((uv_poll_t*)handle);
break;
case UV_FS_POLL:
uv__fs_poll_close((uv_fs_poll_t*)handle);
break;
case UV_SIGNAL:
uv__signal_close((uv_signal_t*) handle);
/* Signal handles may not be closed immediately. The signal code will */
/* itself close uv__make_close_pending whenever appropriate. */
return;
default:
assert(0); // assertion is happening here
}
uv__make_close_pending(handle);
}
I could call uv__tcp_close manually, but it's not in the public headers (and probably not the right solution anyway).
libuv is not done with a handle until it's close callback is called. That is the exact moment when you can free the handle.
I see you call uv_loop_close, but you don't check for the return value. If there are still pending handles, it will return UV_EBUSY, so you should check for that.
If you want to close a loop and close all handles, you need to do the following:
Use uv_stop to stop the loop
Use uv_walk and call uv_close on all handles which are not closing
Run the loop again with uv_run so all close callbacks are called and you can free the memory in the callbacks
Call uv_loop_close, it should return 0 now
I finally figured out how to stop a loop and clean up all handles.
I created a bunch of handles and SIGINT signal handle:
uv_signal_t *sigint = new uv_signal_t;
uv_signal_init(uv_default_loop(), sigint);
uv_signal_start(sigint, on_sigint_received, SIGINT);
When SIGINT is received (Ctrl+C in console is pressed) the on_sigint_received callback is called.
The on_sigint_received looks like:
void on_sigint_received(uv_signal_t *handle, int signum)
{
int result = uv_loop_close(handle->loop);
if (result == UV_EBUSY)
{
uv_walk(handle->loop, on_uv_walk, NULL);
}
}
It triggers a call back function on_uv_walk:
void on_uv_walk(uv_handle_t* handle, void* arg)
{
uv_close(handle, on_uv_close);
}
It tries to close each opened libuv handle.
Note: that I do not call uv_stop before uv_walk, as mentioned saghul.
After on_sigint_received function is called libuv loop continuous the execution and on the next iteration calls on_uv_close for each opened handle. If you call the uv_stop function, then the on_uv_close callback will not be called.
void on_uv_close(uv_handle_t* handle)
{
if (handle != NULL)
{
delete handle;
}
}
After that libuv do not have opened handles and finishes the loop (exits from uv_run):
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
int result = uv_loop_close(uv_default_loop());
if (result)
{
cerr << "failed to close libuv loop: " << uv_err_name(result) << endl;
}
else
{
cout << "libuv loop is closed successfully!\n";
}
I like the solution given by Konstantin Gindemit
I did run into a couple of problems however. His on_uv_close() function ends with a core dump. Also the uv_signal_t variable was causing valgrind to report a "definitely lost" memory leak.
I am using his code with fixes for these 2 situations.
void on_uv_walk(uv_handle_t* handle, void* arg) {
uv_close(handle, NULL);
}
void on_sigint_received(uv_signal_t *handle, int signum) {
int result = uv_loop_close(handle->loop);
if(result == UV_EBUSY) {
uv_walk(handle->loop, on_uv_walk, NULL);
}
}
int main(int argc, char *argv[]) {
uv_signal_t *sigint = new uv_signal_t;
uv_signal_init(uv_default_loop(), sigint);
uv_signal_start(sigint, on_sigint_received, SIGINT);
uv_loop_t* main_loop = uv_default_loop();
...
uv_run(main_loop, UV_RUN_DEFAULT));
uv_loop_close(uv_default_loop());
delete sigint;
return 0;
}
How can I track the keyboard or mouse events in Linux, in C?
Like for example if the user presses ESC Shift etc. I should be able to track it. Same way for the mouse. If the user moves the mouse or clicks left or right.
The implementation idea is to create a small screen saver with timer and I am struggling how to track the keyboard or mouse events to reset the timer.
One possibility is to use the Input Subsystem.
Take a look at this article: Using the Input Subsystem (http://www.linuxjournal.com/article/6429)
Another one is to create a working thread that try to read the file /dev/input/event* like e.g. here for keyboard:
// (const char *)ptr - pass your device like "/dev/input/event2" here
fd = open((const char *)ptr, O_RDONLY);
if (fd < 0)
{
fprintf(stderr, "failed to open input device %s: %s\n", (const char *)ptr, strerror(errno));
return NULL;
}
struct timeval escapeDown = { 0, 0};
int code;
while (1)
{
if (read(fd, &ev, sizeof(struct input_event)) < 0)
{
fprintf(stderr, "failed to read input event from input device %s: %s\n", (const char *)ptr, strerror(errno));
if (errno == EINTR)
continue;
break;
}
code = -1;
if (ev.type == EV_KEY)
{
switch (ev.code)
{
case eEsc:
if (ev.value == 1)
{
escapeDown = ev.time;
printf("DOWN: ESC\n");
}
else if (ev.value == 0 && escapeDown.tv_sec)
{
printf("UP: ESC\n");
if (isLongPressed(&escapeDown, &ev.time))
code = eEscLong;
else
code = eEsc;
escapeDown.tv_sec = 0;
escapeDown.tv_usec = 0;
}
break;
case eOk:
case eUp:
case eRight:
case eLeft:
case eDown:
if (ev.value == 0)
{
printf("UP: %s\n", keyName(ev.code));
code = ev.code;
}
else if (ev.value == 1)
{
printf("DOWN: %s\n", keyName(ev.code));
}
escapeDown.tv_sec = 0;
escapeDown.tv_usec = 0;
break;
default:
break;
}
}
if (code > 0)
{
struct sMsg* pMsg = malloc(sizeof(struct sMsg));
if (pMsg)
{
pMsg->nMsgType = eMsgKeyLogger;
pMsg->nIntValue= code;
postMsg(pMsg);
}
printf("generated keyboard event: %u %s\n",
code,
keyName(code));
}
else
usleep(100);
}
close(fd);
Considering the size and nature of your project, you might want to have a look at GLUT. It is actually a convenience library for OpenGL, but also provides easy-to-use cross-platform input handling and timer functionality. Just in case that you want to move to other platforms in the future. Other than that, it blends in well with the graphical nature of your application.
Edit: The project I linked is actually a successor to the original GLUT with an overall enhanced API. For the original API reference, look here.
In your case, you could use something like:
void keyboardFunc(unsigned char key, int x, int y)
{
switch (key)
{
case 'a':
break;
/* etc */
}
}
void displayFunc()
{
/* Statements issuing the drawing of your screensaver */
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
/* Other initialization code */
glutKeyboardFunc(keyboardFunc);
glutDisplayFunc(displayFunc);
glutMainLoop();
}