// Copyright (c) 2014-2015, 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
// 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 EVENT_TYPE_ENUM(E) \
E(window, SDL_WINDOWEVENT) \
E(key_down, SDL_KEYDOWN) \
E(key_up, SDL_KEYUP) \
E(mouse_motion, SDL_MOUSEMOTION) \
E(mouse_down, SDL_MOUSEBUTTONDOWN) \
E(mouse_up, SDL_MOUSEBUTTONUP) \
E(mouse_wheel, SDL_MOUSEWHEEL) \
E(quit, SDL_QUIT)
static NIF_ENUM_TO_ATOM_FUNCTION(event_type_to_atom, 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)
// poll_event
NIF_CALL_HANDLER(thread_poll_event)
{
SDL_Event event;
ERL_NIF_TERM map;
if (SDL_PollEvent(&event) == 0)
return atom_false;
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);
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);
}
// @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
return map;
}
NIF_FUNCTION(poll_event)
{
return nif_thread_call(env, thread_poll_event, 0);
}