From b30bc1ccd23e909f281c742629281e822854e802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Tue, 2 Jan 2018 12:47:39 +0100 Subject: Add many events and event functions --- c_src/sdl_events.c | 504 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 360 insertions(+), 144 deletions(-) (limited to 'c_src/sdl_events.c') 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 +// Copyright (c) 2014-2017, Loïc Hoguin // // 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); +} -- cgit v1.2.3