PDA

View Full Version : poll event?



luwak
11-06-2012, 09:15 AM
Hi,
I would like to know if there is a method to get events from a function call instead of from a callback?
Callbacks are usually fine, and make things easy, but in some situations callbacks make things more complicated.
Other multimedia libs like SDL and SFML provide a pollEvent function, it seems ClanLib do not.
In case I'm wrong, could you tell me where is the equivalent for poll-event?
In case I'm right, could you add a poll-event in a future release?

Thanks

sphair
11-06-2012, 12:27 PM
http://clanlib.org/wiki/MainDocs:User_Input

Polling a device is fairly simple and straight forward (just call the appropriate functions), but the actual state of an input device does not always update immediately - in some cases they are updated based on input messages received from the underlying windowing system, which means that they will not update until you have made a call to CL_KeepAlive::process(). The following code correctly polls for hitting escape to quit the loop:


CL_DisplayWindow window(640, 480, "Hello Input");
CL_InputContext ic = window.get_ic();
CL_InputDevice keyboard = ic.get_keyboard();
while (true)
{
bool escape_down = keyboard.get_keycode(CL_KEY_ESCAPE);
if (escape_down)
break;

CL_KeepAlive::process();

window.get_gc().clear(CL_Color::white);
window.flip();
CL_System::sleep(10);
}

luwak
11-06-2012, 04:25 PM
No, your code does not get an event, it gets the current state.

I want to get the events when there are some, and nothing if there are no new events.

rombust
11-08-2012, 05:11 PM
Do you mean like?



CL_Slot slot_quit = window.sig_window_close().connect(this, &Basic2D::on_window_close);

// Connect a keyboard handler to on_key_up()
CL_Slot slot_input_up = (window.get_ic().get_keyboard()).sig_key_up().conn ect(this, &Basic2D::on_input_up);

while(!quit)
{
CL_KeepAlive::process(0);
}

// A key was pressed
void Basic2D::on_input_up(const CL_InputEvent &key, const CL_InputState &state)
{
if(key.id == CL_KEY_ESCAPE)
{
quit = true;
}
}

// The window was closed
void Basic2D::on_window_close()
{
quit = true;
}


There are more events - See the Display/Thread example

Also see CL_Event and inherit CL_EventProvider for advanced event handling
eg accept_event = CL_Event(new CL_EventProvider_Win32Socket(&socket, CL_EventProvider_Win32Socket::socket_event_read));

It would take a long time to explain all methods ... but every option is there :)

Judas
11-09-2012, 05:02 AM
I believe he is thinking of a system like GetMessage where you get an event structure back, instead of KeepAlive.process dispatching the messages for you.

There are some problems in adding such a system. First problem is that ClanLib does not internally have any such message structure (our targets dispatch directly). This could be solved by creating one, although I personally have a hard time seeing the advantage in doing manual message dispatching.

The second problem is iOS and the NSRunLoop. I do not know if SDL supports iOS and if it does how it gets around certain limitations with iOS. The problem here is that iOS requires the application to call a function running the runloop, and this function then never returns. Internally this function dispatches all messages, kinda like having a KeepAlive.process function that never returns and now your app is entirely driven by handling callbacks.

Judas
11-09-2012, 05:13 AM
Oh by the way. Maybe we should rename KeepAlive to RunLoop in 3.0? It seems a better name for it.

luwak
11-10-2012, 11:45 AM
Do you mean like?

No, read again my question: I said without callbacks.

The callback mechanism is indeed the problem.
Well it is not a show-stopper, but it makes things far more complicated.


I believe he is thinking of a system like GetMessage where you get an event structure back, instead of KeepAlive.process dispatching the messages for you.

As I said I was looking for something equivalent to the pollEvent functions that are in SDL, SFML and other libs.
I don't know about internals, but it would be more easy to use for me than a callback.

Anyway I was just asking in case it was somewhere but I would just not find it in the doc. OK now I know that there is just no equivalent.

Thanks for your answers.

luwak
11-10-2012, 11:51 AM
OK, so as a replacement I wrote this piece of code.
As I'm a beginner in C++ could you have a look at it, and tell me how I could improve it?

The file "CL_InputEventQueue.cpp":



/* This dirty code is in the public domain */

#include <ClanLib/Display/Window/input_event.h>
#include <ClanLib/Display/Window/input_device.h>

#include <queue>
#include <tuple>

static std::queue<
std::tuple<CL_InputEvent, int, CL_InputDevice::Type>> cl_event_queue;

#define callbacks_for_device(dev) \
static void cb_##dev##_on_key_down( \
const CL_InputEvent &key, const CL_InputState &state, int dev_num) \
{ cl_event_queue.push(std::make_tuple(key, dev_num, CL_InputDevice::dev)); } \
static void cb_##dev##_on_key_up( \
const CL_InputEvent &key, const CL_InputState &state, int dev_num) \
{ cl_event_queue.push(std::make_tuple(key, dev_num, CL_InputDevice::dev)); } \
static void cb_##dev##_on_pointer_move( \
const CL_InputEvent &key, const CL_InputState &state, int dev_num) \
{ cl_event_queue.push(std::make_tuple(key, dev_num, CL_InputDevice::dev)); } \
static void cb_##dev##_on_axis_move( \
const CL_InputEvent &key, const CL_InputState &state, int dev_num) \
{ cl_event_queue.push(std::make_tuple(key, dev_num, CL_InputDevice::dev)); }

callbacks_for_device(keyboard)
callbacks_for_device(pointer)
callbacks_for_device(joystick)
callbacks_for_device(tablet)
callbacks_for_device(unknown)

/* TODO:
static void cb_on_window_close() {}
CL_Slot slot_quit = window.sig_window_close().connect(cb_on_window_clo se);
*/

#include <map>
static std::map<int, CL_Slot *> sig_conn_slots;

#define SWITCH_CB(cb) \
void (* cb_##cb)(const CL_InputEvent &key, \
const CL_InputState &state, int dev_number); \
switch (dev_t) \
{ \
case CL_InputDevice::keyboard: cb_##cb = cb_keyboard_##cb; break; \
case CL_InputDevice::pointer: cb_##cb = cb_pointer_##cb; break; \
case CL_InputDevice::joystick: cb_##cb = cb_joystick_##cb; break; \
case CL_InputDevice::tablet: cb_##cb = cb_tablet_##cb; break; \
case CL_InputDevice::unknown: cb_##cb = cb_unknown_##cb; break; \
}

void
CL_InputDevice_sig_key_down_connect(
CL_InputDevice *inDev, int dev_number)
{
CL_InputDevice::Type dev_t = inDev->get_type();
int id = static_cast<int>(dev_t);
CL_Slot *slot_input_down = new CL_Slot();
SWITCH_CB(on_key_down)
*slot_input_down = inDev->sig_key_down().connect(
cb_on_key_down, dev_number);
sig_conn_slots[id] = slot_input_down;
}

void
CL_InputDevice_sig_key_down_disconnect(
CL_InputDevice *inDev)
{
CL_InputDevice::Type dev_t = inDev->get_type();
int id = static_cast<int>(dev_t);
CL_Slot *slot_input_down = sig_conn_slots[id];
sig_conn_slots.erase(id);
delete slot_input_down;
}

void
CL_InputDevice_sig_key_up_connect(
CL_InputDevice *inDev, int dev_number)
{
CL_InputDevice::Type dev_t = inDev->get_type();
int id = static_cast<int>(dev_t);
CL_Slot *slot_input_up = new CL_Slot();
SWITCH_CB(on_key_up)
*slot_input_up = inDev->sig_key_up().connect(
cb_on_key_up, dev_number);
sig_conn_slots[id] = slot_input_up;
}

void
CL_InputDevice_sig_key_up_disconnect(
CL_InputDevice *inDev)
{
CL_InputDevice::Type dev_t = inDev->get_type();
int id = static_cast<int>(dev_t);
CL_Slot *slot_input_up = sig_conn_slots[id];
sig_conn_slots.erase(id);
delete slot_input_up;
}

void
CL_InputDevice_sig_pointer_move_connect(
CL_InputDevice *inDev, int dev_number)
{
CL_InputDevice::Type dev_t = inDev->get_type();
int id = static_cast<int>(dev_t);
CL_Slot *slot_pointer_move = new CL_Slot();
SWITCH_CB(on_pointer_move)
*slot_pointer_move = inDev->sig_pointer_move().connect(
cb_on_pointer_move, dev_number);
sig_conn_slots[id] = slot_pointer_move;
}

void
CL_InputDevice_sig_pointer_move_disconnect(
CL_InputDevice *inDev)
{
CL_InputDevice::Type dev_t = inDev->get_type();
int id = static_cast<int>(dev_t);
CL_Slot *slot_pointer_move = sig_conn_slots[id];
sig_conn_slots.erase(id);
delete slot_pointer_move;
}

void
CL_InputDevice_sig_axis_move_connect(
CL_InputDevice *inDev, int dev_number)
{
CL_InputDevice::Type dev_t = inDev->get_type();
int id = static_cast<int>(dev_t);
CL_Slot *slot_axis_move = new CL_Slot();
SWITCH_CB(on_axis_move)
*slot_axis_move = inDev->sig_axis_move().connect(
cb_on_axis_move, dev_number);
sig_conn_slots[id] = slot_axis_move;
}

void
CL_InputDevice_sig_axis_move_disconnect(
CL_InputDevice *inDev)
{
CL_InputDevice::Type dev_t = inDev->get_type();
int id = static_cast<int>(dev_t);
CL_Slot *slot_axis_move = sig_conn_slots[id];
sig_conn_slots.erase(id);
delete slot_axis_move;
}

bool
CL_InputEventQueue_isEmpty()
{
return cl_event_queue.empty();
}

typedef struct {
CL_InputEvent * input_event;
int device_number;
CL_InputDevice::Type device_type;
} CL_polledEvent;

bool
CL_InputEventQueue_pollEvent(CL_polledEvent *pEv)
{
if (CL_InputEventQueue_isEmpty())
return false;

pEv->input_event = new CL_InputEvent();

std::tie(
*pEv->input_event,
pEv->device_number,
pEv->device_type) = cl_event_queue.front();

cl_event_queue.pop();

return true;
}


The file "CL_InputEventQueue.hpp":



#ifndef _CL_INPUTEVENT_QUEUE_INC
#define _CL_INPUTEVENT_QUEUE_INC

#include <ClanLib/Display/Window/input_device.h>
#include <ClanLib/Display/Window/input_event.h>

void CL_InputDevice_sig_key_down_connect(
CL_InputDevice *inDev, int dev_number);

void CL_InputDevice_sig_key_down_disconnect(
CL_InputDevice *inDev);

void CL_InputDevice_sig_key_up_connect(
CL_InputDevice *inDev, int dev_number);

void CL_InputDevice_sig_key_up_disconnect(
CL_InputDevice *inDev);

void CL_InputDevice_sig_pointer_move_connect(
CL_InputDevice *inDev, int dev_number);

void CL_InputDevice_sig_pointer_move_disconnect(
CL_InputDevice *inDev);

void CL_InputDevice_sig_axis_move_connect(
CL_InputDevice *inDev, int dev_number);

void CL_InputDevice_sig_axis_move_disconnect(
CL_InputDevice *inDev);

bool CL_InputEventQueue_isEmpty();

typedef struct {
CL_InputEvent * input_event;
int device_number;
CL_InputDevice::Type device_type;
} CL_polledEvent;

bool CL_InputEventQueue_pollEvent(CL_polledEvent *pEv);

#endif // _CL_INPUTEVENT_QUEUE_INC