aboutsummaryrefslogtreecommitdiffstats
path: root/c_src/sdl_events.c
diff options
context:
space:
mode:
Diffstat (limited to 'c_src/sdl_events.c')
-rw-r--r--c_src/sdl_events.c504
1 files changed, 360 insertions, 144 deletions
diff --git a/c_src/sdl_events.c b/c_src/sdl_events.c
index 9b212ce..bf91356 100644
--- a/c_src/sdl_events.c
+++ b/c_src/sdl_events.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2015, Loïc Hoguin <[email protected]>
+// Copyright (c) 2014-2017, Loïc Hoguin <[email protected]>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
@@ -15,175 +15,391 @@
#include "esdl2.h"
#define EVENT_TYPE_ENUM(E) \
+ E(first, SDL_FIRSTEVENT) \
+ E(quit, SDL_QUIT) \
+ E(app_terminating, SDL_APP_TERMINATING) \
+ E(app_low_memory, SDL_APP_LOWMEMORY) \
+ E(app_will_enter_background, SDL_APP_WILLENTERBACKGROUND) \
+ E(app_did_enter_background, SDL_APP_DIDENTERBACKGROUND) \
+ E(app_will_enter_foreground, SDL_APP_WILLENTERFOREGROUND) \
+ E(app_did_enter_foreground, SDL_APP_DIDENTERFOREGROUND) \
E(window, SDL_WINDOWEVENT) \
+ E(syswm, SDL_SYSWMEVENT) \
E(key_down, SDL_KEYDOWN) \
E(key_up, SDL_KEYUP) \
+ E(text_editing, SDL_TEXTEDITING) \
+ E(text_input, SDL_TEXTINPUT) \
+ E(keymap_changed, SDL_KEYMAPCHANGED) \
E(mouse_motion, SDL_MOUSEMOTION) \
E(mouse_down, SDL_MOUSEBUTTONDOWN) \
E(mouse_up, SDL_MOUSEBUTTONUP) \
E(mouse_wheel, SDL_MOUSEWHEEL) \
- E(quit, SDL_QUIT)
+ E(joy_axis_motion, SDL_JOYAXISMOTION) \
+ E(joy_ball_motion, SDL_JOYBALLMOTION) \
+ E(joy_hat_motion, SDL_JOYHATMOTION) \
+ E(joy_button_down, SDL_JOYBUTTONDOWN) \
+ E(joy_button_up, SDL_JOYBUTTONUP) \
+ E(joy_device_added, SDL_JOYDEVICEADDED) \
+ E(joy_device_removed, SDL_JOYDEVICEREMOVED) \
+ E(controller_axis_motion, SDL_CONTROLLERAXISMOTION) \
+ E(controller_button_down, SDL_CONTROLLERBUTTONDOWN) \
+ E(controller_button_up, SDL_CONTROLLERBUTTONUP) \
+ E(controller_device_added, SDL_CONTROLLERDEVICEADDED) \
+ E(controller_device_removed, SDL_CONTROLLERDEVICEREMOVED) \
+ E(controller_device_remapped, SDL_CONTROLLERDEVICEREMAPPED) \
+ E(finger_down, SDL_FINGERDOWN) \
+ E(finger_up, SDL_FINGERUP) \
+ E(finger_motion, SDL_FINGERMOTION) \
+ E(dollar_gesture, SDL_DOLLARGESTURE) \
+ E(dollar_record, SDL_DOLLARRECORD) \
+ E(multi_gesture, SDL_MULTIGESTURE) \
+ E(clipboard_update, SDL_CLIPBOARDUPDATE) \
+ E(drop_file, SDL_DROPFILE) \
+ E(drop_text, SDL_DROPTEXT) \
+ E(drop_begin, SDL_DROPBEGIN) \
+ E(drop_complete, SDL_DROPCOMPLETE) \
+ E(audio_device_added, SDL_AUDIODEVICEADDED) \
+ E(audio_device_removed, SDL_AUDIODEVICEREMOVED) \
+ E(render_targets_reset, SDL_RENDER_TARGETS_RESET) \
+ E(render_device_reset, SDL_RENDER_DEVICE_RESET) \
+ E(last, SDL_LASTEVENT)
static NIF_ENUM_TO_ATOM_FUNCTION(event_type_to_atom, Uint32, EVENT_TYPE_ENUM)
+static NIF_ATOM_TO_ENUM_FUNCTION(atom_to_event_type, Uint32, EVENT_TYPE_ENUM)
-#define WINDOW_EVENT_ENUM(E) \
- E(shown, SDL_WINDOWEVENT_SHOWN) \
- E(hidden, SDL_WINDOWEVENT_HIDDEN) \
- E(exposed, SDL_WINDOWEVENT_EXPOSED) \
- E(moved, SDL_WINDOWEVENT_MOVED) \
- E(resized, SDL_WINDOWEVENT_RESIZED) \
- E(size_changed, SDL_WINDOWEVENT_SIZE_CHANGED) \
- E(minimized, SDL_WINDOWEVENT_MINIMIZED) \
- E(maximized, SDL_WINDOWEVENT_MAXIMIZED) \
- E(restored, SDL_WINDOWEVENT_RESTORED) \
- E(enter, SDL_WINDOWEVENT_ENTER) \
- E(leave, SDL_WINDOWEVENT_LEAVE) \
- E(focus_gained, SDL_WINDOWEVENT_FOCUS_GAINED) \
- E(focus_lost, SDL_WINDOWEVENT_FOCUS_LOST) \
- E(close, SDL_WINDOWEVENT_CLOSE)
-
-static NIF_ENUM_TO_ATOM_FUNCTION(window_event_to_atom, Uint8, WINDOW_EVENT_ENUM)
-
-#define KEYMOD_FLAGS(F) \
- F(left_shift, KMOD_LSHIFT) \
- F(right_shift, KMOD_RSHIFT) \
- F(left_ctrl, KMOD_LCTRL) \
- F(right_ctrl, KMOD_RCTRL) \
- F(left_alt, KMOD_LALT) \
- F(right_alt, KMOD_RALT) \
- F(left_gui, KMOD_LGUI) \
- F(right_gui, KMOD_RGUI) \
- F(num, KMOD_NUM) \
- F(caps, KMOD_CAPS) \
- F(mode, KMOD_MODE)
-
-static NIF_FLAGS_TO_LIST_FUNCTION(keymod_flags_to_list, Uint16, KEYMOD_FLAGS)
-
-#define BUTTON_ENUM(E) \
- E(left, SDL_BUTTON_LEFT) \
- E(middle, SDL_BUTTON_MIDDLE) \
- E(right, SDL_BUTTON_RIGHT) \
- E(x1, SDL_BUTTON_X1) \
- E(x2, SDL_BUTTON_X2)
-
-static NIF_ENUM_TO_ATOM_FUNCTION(button_to_atom, Uint8, BUTTON_ENUM)
+#define EVENT_ACTION_ENUM(E) \
+ E(add, SDL_ADDEVENT) \
+ E(peek, SDL_PEEKEVENT) \
+ E(get, SDL_GETEVENT)
-// poll_event
+static NIF_ATOM_TO_ENUM_FUNCTION(atom_to_event_action, SDL_eventaction, EVENT_ACTION_ENUM)
-NIF_CALL_HANDLER(thread_poll_event)
+// Event conversion functions.
+
+static ERL_NIF_TERM window_event_to_map(ErlNifEnv* env, SDL_Event* event, ERL_NIF_TERM map)
{
- SDL_Event event;
- ERL_NIF_TERM map;
+ enif_make_map_put(env, map, atom_window_id,
+ enif_make_uint(env, event->window.windowID), &map);
+ enif_make_map_put(env, map, atom_event,
+ window_event_to_atom(event->window.event), &map);
+ enif_make_map_put(env, map, atom_data1,
+ enif_make_int(env, event->window.data1), &map);
+ enif_make_map_put(env, map, atom_data2,
+ enif_make_int(env, event->window.data2), &map);
- if (SDL_PollEvent(&event) == 0)
- return atom_false;
+ return map;
+}
+
+static ERL_NIF_TERM keyboard_event_to_map(ErlNifEnv* env, SDL_Event* event, ERL_NIF_TERM map)
+{
+ enif_make_map_put(env, map, atom_window_id,
+ enif_make_uint(env, event->key.windowID), &map);
+ enif_make_map_put(env, map, atom_state,
+ event->key.state == SDL_RELEASED ? atom_released : atom_pressed, &map);
+ enif_make_map_put(env, map, atom_repeat,
+ event->key.repeat == 0 ? atom_false : atom_true, &map);
+ enif_make_map_put(env, map, atom_scancode,
+ enif_make_uint(env, event->key.keysym.scancode), &map);
+ enif_make_map_put(env, map, atom_sym,
+ enif_make_uint(env, event->key.keysym.sym), &map);
+ enif_make_map_put(env, map, atom_mod,
+ keymod_flags_to_list(env, event->key.keysym.mod), &map);
+
+ return map;
+}
+
+static ERL_NIF_TERM mouse_motion_event_to_map(ErlNifEnv* env, SDL_Event* event, ERL_NIF_TERM map)
+{
+ enif_make_map_put(env, map, atom_window_id,
+ enif_make_uint(env, event->motion.windowID), &map);
+ enif_make_map_put(env, map, atom_which,
+ (event->motion.which == SDL_TOUCH_MOUSEID)
+ ? atom_touch
+ : enif_make_uint(env, event->motion.which),
+ &map);
+ enif_make_map_put(env, map, atom_state,
+ mouse_state_to_list(env, event->motion.state), &map);
+ enif_make_map_put(env, map, atom_x,
+ enif_make_int(env, event->motion.x), &map);
+ enif_make_map_put(env, map, atom_y,
+ enif_make_int(env, event->motion.y), &map);
+ enif_make_map_put(env, map, atom_xrel,
+ enif_make_int(env, event->motion.xrel), &map);
+ enif_make_map_put(env, map, atom_yrel,
+ enif_make_int(env, event->motion.yrel), &map);
+
+ return map;
+}
+
+static ERL_NIF_TERM mouse_button_event_to_map(ErlNifEnv* env, SDL_Event* event, ERL_NIF_TERM map)
+{
+ enif_make_map_put(env, map, atom_window_id,
+ enif_make_uint(env, event->button.windowID), &map);
+ enif_make_map_put(env, map, atom_which,
+ (event->button.which == SDL_TOUCH_MOUSEID)
+ ? atom_touch
+ : enif_make_uint(env, event->button.which),
+ &map);
+ enif_make_map_put(env, map, atom_button,
+ button_to_atom(event->button.button), &map);
+ enif_make_map_put(env, map, atom_state,
+ event->button.state == SDL_RELEASED ? atom_released : atom_pressed, &map);
+ enif_make_map_put(env, map, atom_clicks,
+ enif_make_uint(env, event->button.clicks), &map);
+ enif_make_map_put(env, map, atom_x,
+ enif_make_int(env, event->button.x), &map);
+ enif_make_map_put(env, map, atom_y,
+ enif_make_int(env, event->button.y), &map);
+
+ return map;
+}
+
+static ERL_NIF_TERM mouse_wheel_event_to_map(ErlNifEnv* env, SDL_Event* event, ERL_NIF_TERM map)
+{
+ enif_make_map_put(env, map, atom_window_id,
+ enif_make_uint(env, event->wheel.windowID), &map);
+ enif_make_map_put(env, map, atom_which,
+ (event->wheel.which == SDL_TOUCH_MOUSEID)
+ ? atom_touch
+ : enif_make_uint(env, event->wheel.which),
+ &map);
+ enif_make_map_put(env, map, atom_x,
+ enif_make_int(env, event->wheel.x), &map);
+ enif_make_map_put(env, map, atom_y,
+ enif_make_int(env, event->wheel.y), &map);
+ enif_make_map_put(env, map, atom_direction,
+ mousewheel_direction_to_atom(event->wheel.direction), &map);
+
+ return map;
+}
+
+static ERL_NIF_TERM event_to_map(ErlNifEnv* env, SDL_Event* event)
+{
+ ERL_NIF_TERM map;
map = enif_make_new_map(env);
// All events have a type and a timestamp.
+
enif_make_map_put(env, map, atom_type,
- event_type_to_atom(event.type), &map);
+ event_type_to_atom(event->type), &map);
enif_make_map_put(env, map, atom_timestamp,
- enif_make_uint(env, event.common.timestamp), &map);
-
- // Some events have additional information.
- if (event.type == SDL_WINDOWEVENT) {
- enif_make_map_put(env, map, atom_window_id,
- enif_make_uint(env, event.window.windowID), &map);
- enif_make_map_put(env, map, atom_event,
- window_event_to_atom(event.window.event), &map);
- enif_make_map_put(env, map, atom_data,
- enif_make_tuple2(env,
- enif_make_int(env, event.window.data1),
- enif_make_int(env, event.window.data2)),
- &map);
- } else if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) {
- enif_make_map_put(env, map, atom_window_id,
- enif_make_uint(env, event.key.windowID), &map);
- // We don't pass the state as this information is redundant with the type.
- enif_make_map_put(env, map, atom_repeat,
- event.key.repeat == 0 ? atom_false : atom_true, &map);
- enif_make_map_put(env, map, atom_scancode,
- enif_make_uint(env, event.key.keysym.scancode), &map);
- enif_make_map_put(env, map, atom_sym,
- enif_make_uint(env, event.key.keysym.sym), &map);
- enif_make_map_put(env, map, atom_mod,
- keymod_flags_to_list(env, event.key.keysym.mod), &map);
- } else if (event.type == SDL_MOUSEMOTION) {
- enif_make_map_put(env, map, atom_window_id,
- enif_make_uint(env, event.motion.windowID), &map);
- enif_make_map_put(env, map, atom_which,
- (event.motion.which == SDL_TOUCH_MOUSEID)
- ? atom_touch
- : enif_make_uint(env, event.motion.which),
- &map);
- // @todo We may want the state value here as it's a bitmask.
- // Question is how do we represent it to the Erlang code?
- enif_make_map_put(env, map, atom_x,
- enif_make_int(env, event.motion.x), &map);
- enif_make_map_put(env, map, atom_y,
- enif_make_int(env, event.motion.y), &map);
- enif_make_map_put(env, map, atom_xrel,
- enif_make_int(env, event.motion.xrel), &map);
- enif_make_map_put(env, map, atom_yrel,
- enif_make_int(env, event.motion.yrel), &map);
- } else if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) {
- enif_make_map_put(env, map, atom_window_id,
- enif_make_uint(env, event.button.windowID), &map);
- enif_make_map_put(env, map, atom_which,
- (event.button.which == SDL_TOUCH_MOUSEID)
- ? atom_touch
- : enif_make_uint(env, event.button.which),
- &map);
- enif_make_map_put(env, map, atom_button,
- (event.button.button <= SDL_BUTTON_X2)
- ? button_to_atom(event.button.button)
- : enif_make_uint(env, event.button.button),
- &map);
- // We don't pass the state as this information is redundant with the type.
- enif_make_map_put(env, map, atom_clicks,
- enif_make_uint(env, event.button.clicks), &map);
- enif_make_map_put(env, map, atom_x,
- enif_make_int(env, event.button.x), &map);
- enif_make_map_put(env, map, atom_y,
- enif_make_int(env, event.button.y), &map);
- } else if (event.type == SDL_MOUSEWHEEL) {
- enif_make_map_put(env, map, atom_window_id,
- enif_make_uint(env, event.wheel.windowID), &map);
- enif_make_map_put(env, map, atom_which,
- (event.wheel.which == SDL_TOUCH_MOUSEID)
- ? atom_touch
- : enif_make_uint(env, event.wheel.which),
- &map);
- enif_make_map_put(env, map, atom_x,
- enif_make_int(env, event.wheel.x), &map);
- enif_make_map_put(env, map, atom_y,
- enif_make_int(env, event.wheel.y), &map);
- enif_make_map_put(env, map, atom_direction,
- mousewheel_direction_to_atom(event.wheel.direction), &map);
- }
+ enif_make_uint(env, event->common.timestamp), &map);
+
+ // The following event types have no additional fields:
+ //
+ // - SDL_QUIT
+ // - SDL_APP_TERMINATING
+ // - SDL_APP_LOWMEMORY
+ // - SDL_APP_WILLENTERBACKGROUND
+ // - SDL_APP_DIDENTERBACKGROUND
+ // - SDL_APP_WILLENTERFOREGROUND
+ // - SDL_APP_DIDENTERFOREGROUND
+ // - SDL_KEYMAPCHANGED
+ // - SDL_CLIPBOARDUPDATE
+ // - SDL_RENDER_TARGETS_RESET
+ // - SDL_RENDER_DEVICE_RESET
+
+ switch (event->type) {
+ case SDL_WINDOWEVENT:
+ return window_event_to_map(env, event, map);
+
+ // @todo SDL_SYSWMEVENT
+
+ case SDL_KEYDOWN:
+ case SDL_KEYUP:
+ return keyboard_event_to_map(env, event, map);
+
+ // @todo SDL_TEXTEDITING
+ // @todo SDL_TEXTINPUT
+
+ case SDL_MOUSEMOTION:
+ return mouse_motion_event_to_map(env, event, map);
+
+ case SDL_MOUSEBUTTONDOWN:
+ case SDL_MOUSEBUTTONUP:
+ return mouse_button_event_to_map(env, event, map);
+
+ case SDL_MOUSEWHEEL:
+ return mouse_wheel_event_to_map(env, event, map);
+
+ // @todo SDL_JOYAXISMOTION
+ // @todo SDL_JOYBALLMOTION
+ // @todo SDL_JOYHATMOTION
+ // @todo SDL_JOYBUTTONDOWN
+ // @todo SDL_JOYBUTTONUP
+ // @todo SDL_JOYDEVICEADDED
+ // @todo SDL_JOYDEVICEREMOVED
+
+ // @todo SDL_CONTROLLERAXISMOTION
+ // @todo SDL_CONTROLLERBUTTONDOWN
+ // @todo SDL_CONTROLLERBUTTONUP
+ // @todo SDL_CONTROLLERDEVICEADDED
+ // @todo SDL_CONTROLLERDEVICEREMOVED
+ // @todo SDL_CONTROLLERDEVICEREMAPPED
+
+ // @todo SDL_FINGERDOWN
+ // @todo SDL_FINGERUP
+ // @todo SDL_FINGERMOTION
+
+ // @todo SDL_DOLLARGESTURE
+ // @todo SDL_DOLLARRECORD
+ // @todo SDL_MULTIGESTURE
- // @todo SDL_TextEditingEvent
- // @todo SDL_TextInputEvent
- // @todo SDL_JoyAxisEvent
- // @todo SDL_JoyBallEvent
- // @todo SDL_JoyHatEvent
- // @todo SDL_JoyButtonEvent
- // @todo SDL_JoyDeviceEvent
- // @todo SDL_ControllerAxisEvent
- // @todo SDL_ControllerButtonEvent
- // @todo SDL_ControllerDeviceEvent
- // @todo SDL_UserEvent
- // @todo SDL_SysWMEvent
- // @todo SDL_TouchFingerEvent
- // @todo SDL_MultiGestureEvent
- // @todo SDL_DollarGestureEvent
- // @todo SDL_DropEvent
+ // @todo SDL_DROPFILE
+ // @todo SDL_DROPTEXT
+ // @todo SDL_DROPBEGIN
+ // @todo SDL_DROPCOMPLETE
+
+ // @todo SDL_AUDIODEVICEADDED
+ // @todo SDL_AUDIODEVICEREMOVED
+ }
return map;
}
+// flush_event
+
+NIF_CAST_HANDLER(thread_flush_event)
+{
+ SDL_FlushEvent((long)args[0]);
+}
+
+NIF_FUNCTION(flush_event)
+{
+ Uint32 type;
+
+ BADARG_IF(!atom_to_event_type(env, argv[0], &type));
+
+ return nif_thread_cast(env, thread_flush_event, 1, type);
+}
+
+// flush_events
+
+NIF_CAST_HANDLER(thread_flush_events)
+{
+ SDL_FlushEvents((long)args[0], (long)args[1]);
+}
+
+NIF_FUNCTION(flush_events)
+{
+ Uint32 minType, maxType;
+
+ BADARG_IF(!atom_to_event_type(env, argv[0], &minType));
+ BADARG_IF(!atom_to_event_type(env, argv[1], &maxType));
+
+ return nif_thread_cast(env, thread_flush_events, 2, minType, maxType);
+}
+
+// has_event
+
+NIF_CALL_HANDLER(thread_has_event)
+{
+ if (SDL_HasEvent((long)args[0]))
+ return atom_true;
+
+ return atom_false;
+}
+
+NIF_FUNCTION(has_event)
+{
+ Uint32 type;
+
+ BADARG_IF(!atom_to_event_type(env, argv[0], &type));
+
+ return nif_thread_call(env, thread_has_event, 1, type);
+}
+
+// has_events
+
+NIF_CALL_HANDLER(thread_has_events)
+{
+ if (SDL_HasEvents((long)args[0], (long)args[1]))
+ return atom_true;
+
+ return atom_false;
+}
+
+NIF_FUNCTION(has_events)
+{
+ Uint32 minType, maxType;
+
+ BADARG_IF(!atom_to_event_type(env, argv[0], &minType));
+ BADARG_IF(!atom_to_event_type(env, argv[1], &maxType));
+
+ return nif_thread_call(env, thread_has_events, 2, minType, maxType);
+}
+
+// peep_events
+//
+// @todo It is not currently possible to add events at the back of the queue.
+
+NIF_CALL_HANDLER(thread_peep_events)
+{
+ SDL_Event* events;
+ int i, numEvents;
+ ERL_NIF_TERM list;
+
+ events = malloc(sizeof(SDL_Event) * (long)args[1]);
+
+ numEvents = SDL_PeepEvents(events, (long)args[1],
+ (long)args[0], (long)args[2], (long)args[3]);
+
+ if (numEvents < 0)
+ return sdl_error_tuple(env);
+
+ list = enif_make_list(env, 0);
+
+ for (i = 0; i < numEvents; i++)
+ list = enif_make_list_cell(env, event_to_map(env, &events[i]), list);
+
+ free(events);
+
+ return enif_make_tuple2(env, atom_ok, list);
+}
+
+NIF_FUNCTION(peep_events)
+{
+ SDL_eventaction action;
+ int numEvents;
+ Uint32 minType, maxType;
+
+ BADARG_IF(enif_is_identical(atom_add, argv[0]));
+
+ BADARG_IF(!atom_to_event_action(env, argv[0], &action));
+ BADARG_IF(!enif_get_int(env, argv[1], &numEvents));
+ BADARG_IF(!atom_to_event_type(env, argv[2], &minType));
+ BADARG_IF(!atom_to_event_type(env, argv[3], &maxType));
+
+ return nif_thread_call(env, thread_peep_events, 4,
+ action, numEvents, minType, maxType);
+}
+
+// poll_event
+
+NIF_CALL_HANDLER(thread_poll_event)
+{
+ SDL_Event event;
+
+ if (SDL_PollEvent(&event) == 0)
+ return atom_false;
+
+ return event_to_map(env, &event);
+}
+
NIF_FUNCTION(poll_event)
{
return nif_thread_call(env, thread_poll_event, 0);
}
+
+// pump_events
+
+NIF_CAST_HANDLER(thread_pump_events)
+{
+ SDL_PumpEvents();
+}
+
+NIF_FUNCTION(pump_events)
+{
+ return nif_thread_cast(env, thread_pump_events, 0);
+}