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/esdl2.h | 61 ++++++- c_src/sdl_events.c | 504 +++++++++++++++++++++++++++++++++++++--------------- c_src/sdl_keycode.c | 30 ++++ c_src/sdl_mouse.c | 18 +- c_src/sdl_window.c | 20 +++ ebin/esdl2.app | 2 +- src/esdl2.erl | 24 +++ src/sdl_events.erl | 98 ++++++++-- src/sdl_keycode.erl | 19 ++ src/sdl_mouse.erl | 15 +- src/sdl_window.erl | 5 + 11 files changed, 623 insertions(+), 173 deletions(-) create mode 100644 c_src/sdl_keycode.c create mode 100644 src/sdl_keycode.erl diff --git a/c_src/esdl2.h b/c_src/esdl2.h index 5a1ec99..bd80acf 100644 --- a/c_src/esdl2.h +++ b/c_src/esdl2.h @@ -23,8 +23,16 @@ A(accelerated) \ A(add) \ A(allow_high_dpi) \ + A(app_did_enter_background) \ + A(app_did_enter_foreground) \ + A(app_low_memory) \ + A(app_terminating) \ + A(app_will_enter_background) \ + A(app_will_enter_foreground) \ A(arrow) \ A(audio) \ + A(audio_device_added) \ + A(audio_device_removed) \ A(blend) \ A(borderless) \ A(button) \ @@ -34,10 +42,24 @@ A(charged) \ A(charging) \ A(clicks) \ + A(clipboard_update) \ A(close) \ + A(controller_axis_motion) \ + A(controller_button_down) \ + A(controller_button_up) \ + A(controller_device_added) \ + A(controller_device_remapped) \ + A(controller_device_removed) \ A(crosshair) \ - A(data) \ + A(data1) \ + A(data2) \ A(direction) \ + A(dollar_gesture) \ + A(dollar_record) \ + A(drop_begin) \ + A(drop_complete) \ + A(drop_file) \ + A(drop_text) \ A(dst_alpha) \ A(dst_color) \ A(enter) \ @@ -47,6 +69,10 @@ A(everything) \ A(exposed) \ A(false) \ + A(finger_down) \ + A(finger_motion) \ + A(finger_up) \ + A(first) \ A(flipped) \ A(focus_gained) \ A(focus_lost) \ @@ -54,18 +80,29 @@ A(fullscreen) \ A(fullscreen_desktop) \ A(game_controller) \ + A(get) \ A(h) \ A(hand) \ A(haptic) \ A(hidden) \ + A(hit_test) \ A(horizontal) \ A(ibeam) \ A(input_focus) \ A(input_grabbed) \ A(invalid) \ + A(joy_axis_motion) \ + A(joy_ball_motion) \ + A(joy_button_down) \ + A(joy_button_up) \ + A(joy_device_added) \ + A(joy_device_removed) \ + A(joy_hat_motion) \ A(joystick) \ A(key_down) \ A(key_up) \ + A(keymap_changed) \ + A(last) \ A(leave) \ A(left) \ A(left_alt) \ @@ -91,6 +128,7 @@ A(mouse_up) \ A(mouse_wheel) \ A(moved) \ + A(multi_gesture) \ A(no) \ A(no_battery) \ A(none) \ @@ -99,8 +137,13 @@ A(on_battery) \ A(one) \ A(opengl) \ + A(peek) \ A(present_vsync) \ + A(pressed) \ A(quit) \ + A(released) \ + A(render_targets_reset) \ + A(render_device_reset) \ A(repeat) \ A(resizable) \ A(resized) \ @@ -125,7 +168,11 @@ A(state) \ A(substract) \ A(sym) \ + A(syswm) \ + A(take_focus) \ A(target_texture) \ + A(text_editing) \ + A(text_input) \ A(touch) \ A(true) \ A(timer) \ @@ -206,7 +253,13 @@ F(set_cursor, 1) \ F(show_cursor, 1) \ /* sdl_events */ \ + F(flush_event, 1) \ + F(flush_events, 2) \ + F(has_event, 1) \ + F(has_events, 2) \ + F(peep_events, 4) \ F(poll_event, 0) \ + F(pump_events, 0) \ /* sdl_filesystem */ \ F(get_base_path, 0) \ F(get_pref_path, 2) \ @@ -316,7 +369,13 @@ NIF_FUNCTIONS(NIF_FUNCTION_H_DECL) NIF_ATOM_TO_ENUM_FUNCTION_DECL(atom_to_bool, SDL_bool) NIF_ATOM_TO_ENUM_FUNCTION_DECL(atom_to_blend_mode, SDL_BlendMode) NIF_ENUM_TO_ATOM_FUNCTION_DECL(blend_mode_to_atom, SDL_BlendMode) +NIF_ENUM_TO_ATOM_FUNCTION_DECL(button_to_atom, Uint8) NIF_ENUM_TO_ATOM_FUNCTION_DECL(mousewheel_direction_to_atom, Uint32) +NIF_ENUM_TO_ATOM_FUNCTION_DECL(window_event_to_atom, Uint8) + +NIF_FLAGS_TO_LIST_FUNCTION_DECL(keymod_flags_to_list, Uint16) + +ERL_NIF_TERM mouse_state_to_list(ErlNifEnv*, Uint32); // -- 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); +} diff --git a/c_src/sdl_keycode.c b/c_src/sdl_keycode.c new file mode 100644 index 0000000..539accd --- /dev/null +++ b/c_src/sdl_keycode.c @@ -0,0 +1,30 @@ +// 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 +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include "esdl2.h" + +#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) + +NIF_FLAGS_TO_LIST_FUNCTION(keymod_flags_to_list, Uint16, KEYMOD_FLAGS) diff --git a/c_src/sdl_mouse.c b/c_src/sdl_mouse.c index eb2af39..018b44c 100644 --- a/c_src/sdl_mouse.c +++ b/c_src/sdl_mouse.c @@ -20,7 +20,16 @@ NIF_ENUM_TO_ATOM_FUNCTION(mousewheel_direction_to_atom, Uint32, MOUSEWHEEL_DIRECTION_ENUM) -static ERL_NIF_TERM get_mouse_state_common(ErlNifEnv* env, int x, int y, Uint32 state) +#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) + +NIF_ENUM_TO_ATOM_FUNCTION(button_to_atom, Uint8, BUTTON_ENUM) + +ERL_NIF_TERM mouse_state_to_list(ErlNifEnv* env, Uint32 state) { ERL_NIF_TERM list; @@ -37,10 +46,15 @@ static ERL_NIF_TERM get_mouse_state_common(ErlNifEnv* env, int x, int y, Uint32 if (state & SDL_BUTTON_X2MASK) list = enif_make_list_cell(env, atom_x2, list); + return list; +} + +static ERL_NIF_TERM get_mouse_state_common(ErlNifEnv* env, int x, int y, Uint32 state) +{ return enif_make_tuple3(env, enif_make_int(env, x), enif_make_int(env, y), - list + mouse_state_to_list(env, state) ); } diff --git a/c_src/sdl_window.c b/c_src/sdl_window.c index 4ac3604..36ddcc2 100644 --- a/c_src/sdl_window.c +++ b/c_src/sdl_window.c @@ -49,6 +49,26 @@ static NIF_FLAGS_TO_LIST_FUNCTION(window_flags_to_list, Uint32, WINDOW_FLAGS) static NIF_ATOM_TO_ENUM_FUNCTION(atom_to_window_pos, int, WINDOW_POS_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) \ + E(take_focus, SDL_WINDOWEVENT_TAKE_FOCUS) \ + E(hit_test, SDL_WINDOWEVENT_HIT_TEST) + +NIF_ENUM_TO_ATOM_FUNCTION(window_event_to_atom, Uint8, WINDOW_EVENT_ENUM) + #define WINDOW_FULLSCREEN_ENUM(E) \ E(fullscreen, SDL_WINDOW_FULLSCREEN) \ E(fullscreen_desktop, SDL_WINDOW_FULLSCREEN_DESKTOP) \ diff --git a/ebin/esdl2.app b/ebin/esdl2.app index ccb9664..3b48762 100644 --- a/ebin/esdl2.app +++ b/ebin/esdl2.app @@ -1,7 +1,7 @@ {application, 'esdl2', [ {description, "SDL2 Erlang NIF."}, {vsn, "0.1.0"}, - {modules, ['esdl2','esdl2_app','esdl2_callbacks','esdl2_sup','sdl','sdl_blend_mode','sdl_clipboard','sdl_cpu_info','sdl_cursor','sdl_events','sdl_filesystem','sdl_gl','sdl_hints','sdl_keyboard','sdl_mouse','sdl_power','sdl_renderer','sdl_surface','sdl_texture','sdl_version','sdl_window']}, + {modules, ['esdl2','esdl2_app','esdl2_callbacks','esdl2_sup','sdl','sdl_blend_mode','sdl_clipboard','sdl_cpu_info','sdl_cursor','sdl_events','sdl_filesystem','sdl_gl','sdl_hints','sdl_keyboard','sdl_keycode','sdl_mouse','sdl_power','sdl_renderer','sdl_surface','sdl_texture','sdl_version','sdl_window']}, {registered, [esdl2_sup]}, {applications, [kernel,stdlib]}, {mod, {esdl2_app, []}}, diff --git a/src/esdl2.erl b/src/esdl2.erl index 1020849..5fa9a16 100644 --- a/src/esdl2.erl +++ b/src/esdl2.erl @@ -60,7 +60,13 @@ -export([show_cursor/1]). %% sdl_events +-export([flush_event/1]). +-export([flush_events/2]). +-export([has_event/1]). +-export([has_events/2]). +-export([peep_events/4]). -export([poll_event/0]). +-export([pump_events/0]). %% sdl_filesystem -export([get_base_path/0]). @@ -293,9 +299,27 @@ show_cursor(_) -> %% sdl_events +flush_event(_) -> + erlang:nif_error({not_loaded, ?MODULE}). + +flush_events(_, _) -> + erlang:nif_error({not_loaded, ?MODULE}). + +has_event(_) -> + erlang:nif_error({not_loaded, ?MODULE}). + +has_events(_, _) -> + erlang:nif_error({not_loaded, ?MODULE}). + +peep_events(_, _, _, _) -> + erlang:nif_error({not_loaded, ?MODULE}). + poll_event() -> erlang:nif_error({not_loaded, ?MODULE}). +pump_events() -> + erlang:nif_error({not_loaded, ?MODULE}). + %% sdl_filesystem get_base_path() -> diff --git a/src/sdl_events.erl b/src/sdl_events.erl index 366edeb..034ca3d 100644 --- a/src/sdl_events.erl +++ b/src/sdl_events.erl @@ -14,40 +14,100 @@ -module(sdl_events). +-export([flush/1]). +-export([flush/2]). +-export([get/3]). +-export([has/1]). +-export([has/2]). +-export([peek/3]). -export([poll/0]). +-export([pump/0]). + +-type event_type() :: first + | quit + | app_terminating | app_low_memory | app_will_enter_background + | app_did_enter_background | app_will_enter_foreground | app_did_enter_foreground + | window | syswm + | key_down | key_up | text_editing | text_input | keymap_changed + | mouse_motion | mouse_down | mouse_up | mouse_wheel + | joy_axis_motion | joy_ball_motion | joy_hat_motion + | joy_button_down | joy_button_up | joy_device_added | joy_device_removed + | controller_axis_motion | controller_button_down | controller_button_up + | controller_device_added | controller_device_removed | controller_device_remapped + | finger_down | finger_up | finger_motion + | dollar_gesture | dollar_record | multi_gesture + | clipboard_update + | drop_file | drop_text | drop_begin | drop_complete + | audio_device_added | audio_device_removed + | render_targets_reset | render_device_reset + | last. --type window_event_type() :: shown | hidden | exposed | moved | resized - | size_changed | minimized | maximized | restored | enter | leave - | focus_gained | focus_lost | close. -type window_event() :: #{type=>window, timestamp=>non_neg_integer(), - window_id=>non_neg_integer(), event=>window_event_type(), - data=>{integer(), integer()}}. + window_id=>non_neg_integer(), event=>sdl_window:window_event_type(), + data1=>integer(), data2=>integer()}. --type keymod() :: left_shift | right_shift | left_ctrl | right_ctrl - | left_alt | right_alt | left_gui | right_gui | num | caps | mode. --type key_event() :: #{type=>key_down | key_up, timestamp=>non_neg_integer(), - window_id=>non_neg_integer(), repeat=>boolean(), scancode=>non_neg_integer(), - sym=>non_neg_integer(), mod=>[keymod()]}. - --type mouse_button() :: left | middle | right | x1 | x2 | non_neg_integer(). --type mouse_button_event() :: #{type=>mouse_down | mouse_up, timestamp=>non_neg_integer(), - window_id=>non_neg_integer(), which=>touch | non_neg_integer(), - button=>mouse_button(), clicks=>non_neg_integer(), x=>integer(), y=>integer()}. +-type keyboard_event() :: #{type=>key_down | key_up, timestamp=>non_neg_integer(), + window_id=>non_neg_integer(), state=>released | pressed, repeat=>boolean(), + scancode=>non_neg_integer(), sym=>non_neg_integer(), mod=>[sdl_keycode:keymod()]}. -type mouse_motion_event() :: #{type=>mouse_motion, timestamp=>non_neg_integer(), window_id=>non_neg_integer(), which=>touch | non_neg_integer(), x=>integer(), y=>integer(), xrel=>integer(), yrel=>integer()}. +-type mouse_button_event() :: #{type=>mouse_down | mouse_up, timestamp=>non_neg_integer(), + window_id=>non_neg_integer(), which=>touch | non_neg_integer(), + button=>sdl_mouse:button(), state=>released | pressed, + clicks=>non_neg_integer(), x=>integer(), y=>integer()}. + -type mouse_wheel_event() :: #{type=>mouse_wheel, timestamp=>non_neg_integer(), window_id=>non_neg_integer(), which=>touch | non_neg_integer(), - x=>integer(), y=>integer()}. + x=>integer(), y=>integer(), direction=>sdl_mouse:wheel_direction()}. + +-type generic_event() :: #{ + type=> quit | app_terminating | app_low_memory | app_will_enter_background + | app_did_enter_background | app_will_enter_foreground | app_did_enter_foreground + | keymap_changed | clipboard_update | render_targets_reset | render_device_reset, + timestamp=>non_neg_integer()}. + +-type event() :: window_event() | keyboard_event() + | mouse_motion_event() | mouse_button_event() | mouse_wheel_event() + | generic_event(). --type quit_event() :: #{type=>quit, timestamp=>non_neg_integer()}. +-spec flush(event_type()) -> ok. +flush(Type) -> + esdl2:flush_event(Type). --type event() :: window_event() | key_event() | mouse_button_event() - | mouse_motion_event() | mouse_wheel_event() | quit_event(). +-spec flush(event_type(), event_type()) -> ok. +flush(MinType, MaxType) -> + esdl2:flush_events(MinType, MaxType). + +-spec get(non_neg_integer(), event_type(), event_type()) + -> {ok, [event()]} | sdl:error(). +get(NumEvents, MinType, MaxType) -> + esdl2:peep_events(get, NumEvents, MinType, MaxType), + receive {'_nif_thread_ret_', Ret} -> Ret end. + +-spec has(event_type()) -> boolean(). +has(Type) -> + esdl2:has_event(Type), + receive {'_nif_thread_ret_', Ret} -> Ret end. + +-spec has(event_type(), event_type()) -> boolean(). +has(MinType, MaxType) -> + esdl2:has_events(MinType, MaxType), + receive {'_nif_thread_ret_', Ret} -> Ret end. + +-spec peek(non_neg_integer(), event_type(), event_type()) + -> {ok, [event()]} | sdl:error(). +peek(NumEvents, MinType, MaxType) -> + esdl2:peep_events(peek, NumEvents, MinType, MaxType), + receive {'_nif_thread_ret_', Ret} -> Ret end. -spec poll() -> event() | false. poll() -> esdl2:poll_event(), receive {'_nif_thread_ret_', Ret} -> Ret end. + +-spec pump() -> ok. +pump() -> + esdl2:pump_events(). diff --git a/src/sdl_keycode.erl b/src/sdl_keycode.erl new file mode 100644 index 0000000..6ab1cf4 --- /dev/null +++ b/src/sdl_keycode.erl @@ -0,0 +1,19 @@ +%% 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 +%% copyright notice and this permission notice appear in all copies. +%% +%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +-module(sdl_keycode). + +-type keymod() :: left_shift | right_shift | left_ctrl | right_ctrl + | left_alt | right_alt | left_gui | right_gui | num | caps | mode. +-export_type([keymod/0]). diff --git a/src/sdl_mouse.erl b/src/sdl_mouse.erl index d6c3815..6d34b8d 100644 --- a/src/sdl_mouse.erl +++ b/src/sdl_mouse.erl @@ -24,6 +24,12 @@ -export([warp/2]). -export([warp/3]). +-type wheel_direction() :: normal | flipped. +-export_type([wheel_direction/0]). + +-type button() :: left | middle | right | x1 | x2. +-export_type([button/0]). + -spec capture(boolean()) -> ok | sdl:error(). capture(Bool) -> esdl2:capture_mouse(Bool), @@ -34,8 +40,7 @@ get_focused_window() -> esdl2:get_mouse_focus(), receive {'_nif_thread_ret_', Ret} -> Ret end. --spec get_global_state() - -> {integer(), integer(), [left | middle | right | x1 | x2]}. +-spec get_global_state() -> {integer(), integer(), [button()]}. get_global_state() -> esdl2:get_global_mouse_state(), receive {'_nif_thread_ret_', Ret} -> Ret end. @@ -45,14 +50,12 @@ get_relative_mode() -> esdl2:get_relative_mouse_mode(), receive {'_nif_thread_ret_', Ret} -> Ret end. --spec get_relative_state() - -> {integer(), integer(), [left | middle | right | x1 | x2]}. +-spec get_relative_state() -> {integer(), integer(), [button()]}. get_relative_state() -> esdl2:get_relative_mouse_state(), receive {'_nif_thread_ret_', Ret} -> Ret end. --spec get_state() - -> {integer(), integer(), [left | middle | right | x1 | x2]}. +-spec get_state() -> {integer(), integer(), [button()]}. get_state() -> esdl2:get_mouse_state(), receive {'_nif_thread_ret_', Ret} -> Ret end. diff --git a/src/sdl_window.erl b/src/sdl_window.erl index 5d31392..ea757bf 100644 --- a/src/sdl_window.erl +++ b/src/sdl_window.erl @@ -51,6 +51,11 @@ | hidden | borderless | resizable | minimized | maximized | input_grabbed | input_focus | mouse_focus | foreign | allow_high_dpi. +-type window_event_type() :: shown | hidden | exposed | moved | resized + | size_changed | minimized | maximized | restored | enter | leave + | focus_gained | focus_lost | close | take_focus | hit_test. +-export_type([window_event_type/0]). + -spec create(string(), window_pos(), window_pos(), integer(), integer(), [window_flag()]) -> {ok, window()} | sdl:error(). create(Title, X, Y, W, H, Flags) -> -- cgit v1.2.3