2014-06-01 17:55:23 +00:00
|
|
|
/*
|
2018-09-02 00:57:29 +00:00
|
|
|
* This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
|
2014-06-01 17:55:23 +00:00
|
|
|
* It is copyright by its individual contributors, as recorded in the
|
|
|
|
* project's Git history. See COPYING.txt at the top level for license
|
|
|
|
* terms and a link to the Git history.
|
|
|
|
*/
|
2006-07-27 09:46:44 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* SDL Event related stuff
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2015-11-01 21:15:40 +00:00
|
|
|
#include <SDL.h>
|
2006-03-20 16:43:15 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2009-05-21 12:16:39 +00:00
|
|
|
#include "event.h"
|
2008-11-17 23:38:43 +00:00
|
|
|
#include "key.h"
|
2012-03-18 10:04:16 +00:00
|
|
|
#include "mouse.h"
|
2009-05-21 12:16:39 +00:00
|
|
|
#include "window.h"
|
2010-07-16 11:07:42 +00:00
|
|
|
#include "timer.h"
|
2010-12-28 18:11:06 +00:00
|
|
|
#include "config.h"
|
2015-07-18 21:01:56 +00:00
|
|
|
#include "inferno.h"
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2013-01-03 15:37:49 +00:00
|
|
|
#include "joy.h"
|
2012-06-10 22:26:20 +00:00
|
|
|
#include "args.h"
|
2020-05-27 03:07:17 +00:00
|
|
|
#include "partial_range.h"
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2015-12-13 18:00:49 +00:00
|
|
|
namespace dcx {
|
2015-12-05 22:57:24 +00:00
|
|
|
|
2020-05-27 03:07:17 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
struct event_poll_state
|
|
|
|
{
|
|
|
|
uint8_t clean_uniframe = 1;
|
|
|
|
const window *const front_window = window_get_front();
|
|
|
|
window_event_result highest_result = window_event_result::ignored;
|
|
|
|
void process_event_batch(partial_range_t<const SDL_Event *>);
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-07-28 23:22:58 +00:00
|
|
|
#if SDL_MAJOR_VERSION == 2
|
|
|
|
extern SDL_Window *g_pRebirthSDLMainWindow;
|
2019-08-18 20:37:29 +00:00
|
|
|
|
|
|
|
static void windowevent_handler(const SDL_WindowEvent &windowevent)
|
|
|
|
{
|
|
|
|
switch (windowevent.event)
|
|
|
|
{
|
|
|
|
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
|
|
|
{
|
|
|
|
const d_window_size_event e{windowevent.data1, windowevent.data2};
|
|
|
|
event_send(e);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-28 23:22:58 +00:00
|
|
|
#endif
|
|
|
|
|
2020-05-27 03:07:17 +00:00
|
|
|
static void event_notify_begin_loop()
|
|
|
|
{
|
|
|
|
const d_event_begin_loop event;
|
|
|
|
event_send(event);
|
|
|
|
}
|
|
|
|
|
2016-10-28 06:43:20 +00:00
|
|
|
window_event_result event_poll()
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
2020-05-27 03:07:17 +00:00
|
|
|
event_poll_state state;
|
2020-05-27 03:07:17 +00:00
|
|
|
event_notify_begin_loop();
|
|
|
|
|
2020-05-27 03:07:17 +00:00
|
|
|
for (;;)
|
|
|
|
{
|
2010-07-25 00:49:33 +00:00
|
|
|
// If the front window changes, exit this loop, otherwise unintended behavior can occur
|
|
|
|
// like pressing 'Return' really fast at 'Difficulty Level' causing multiple games to be started
|
2020-05-27 03:07:17 +00:00
|
|
|
if (state.front_window != window_get_front())
|
|
|
|
break;
|
|
|
|
std::array<SDL_Event, 128> events;
|
|
|
|
|
|
|
|
SDL_PumpEvents();
|
|
|
|
#if SDL_MAJOR_VERSION == 1
|
|
|
|
const auto peep = SDL_PeepEvents(events.data(), events.size(), SDL_GETEVENT, SDL_ALLEVENTS);
|
|
|
|
#elif SDL_MAJOR_VERSION == 2
|
|
|
|
const auto peep = SDL_PeepEvents(events.data(), events.size(), SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
|
|
|
|
#endif
|
|
|
|
if (peep <= 0)
|
|
|
|
break;
|
|
|
|
state.process_event_batch(unchecked_partial_range(events.data(), static_cast<unsigned>(peep)));
|
|
|
|
if (state.highest_result == window_event_result::deleted)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Send the idle event if there were no other events (or they were ignored)
|
|
|
|
if (state.highest_result == window_event_result::ignored)
|
|
|
|
{
|
|
|
|
const d_event ievent{EVENT_IDLE};
|
|
|
|
state.highest_result = std::max(event_send(ievent), state.highest_result);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if DXX_USE_EDITOR
|
|
|
|
event_reset_idle_seconds();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
mouse_cursor_autohide();
|
|
|
|
return state.highest_result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void event_poll_state::process_event_batch(partial_range_t<const SDL_Event *> events)
|
|
|
|
{
|
|
|
|
for (auto &&event : events)
|
2010-07-25 00:49:33 +00:00
|
|
|
{
|
2020-05-22 02:40:26 +00:00
|
|
|
window_event_result result;
|
2006-07-27 09:46:44 +00:00
|
|
|
switch(event.type) {
|
2019-08-18 20:37:29 +00:00
|
|
|
#if SDL_MAJOR_VERSION == 2
|
|
|
|
case SDL_WINDOWEVENT:
|
|
|
|
windowevent_handler(event.window);
|
2020-05-22 02:40:26 +00:00
|
|
|
continue;
|
2019-08-18 20:37:29 +00:00
|
|
|
#endif
|
2006-11-22 05:35:10 +00:00
|
|
|
case SDL_KEYDOWN:
|
|
|
|
case SDL_KEYUP:
|
2008-11-17 23:38:43 +00:00
|
|
|
if (clean_uniframe)
|
2018-07-28 23:22:58 +00:00
|
|
|
{
|
|
|
|
clean_uniframe=0;
|
2014-07-14 03:18:40 +00:00
|
|
|
unicode_frame_buffer = {};
|
2018-07-28 23:22:58 +00:00
|
|
|
}
|
2020-05-22 02:40:26 +00:00
|
|
|
result = key_handler(&event.key);
|
2006-11-22 05:35:10 +00:00
|
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
|
|
case SDL_MOUSEBUTTONUP:
|
2016-10-28 06:43:20 +00:00
|
|
|
if (CGameArg.CtlNoMouse)
|
2020-05-22 02:40:26 +00:00
|
|
|
continue;
|
|
|
|
result = mouse_button_handler(&event.button);
|
2006-11-22 05:35:10 +00:00
|
|
|
break;
|
|
|
|
case SDL_MOUSEMOTION:
|
2016-10-28 06:43:20 +00:00
|
|
|
if (CGameArg.CtlNoMouse)
|
2020-05-22 02:40:26 +00:00
|
|
|
continue;
|
|
|
|
result = mouse_motion_handler(&event.motion);
|
2006-11-22 05:35:10 +00:00
|
|
|
break;
|
|
|
|
case SDL_JOYBUTTONDOWN:
|
|
|
|
case SDL_JOYBUTTONUP:
|
2016-10-28 06:43:20 +00:00
|
|
|
if (CGameArg.CtlNoJoystick)
|
2020-05-22 02:40:26 +00:00
|
|
|
continue;
|
|
|
|
result = joy_button_handler(&event.jbutton);
|
2006-11-22 05:35:10 +00:00
|
|
|
break;
|
|
|
|
case SDL_JOYAXISMOTION:
|
2016-10-28 06:43:20 +00:00
|
|
|
if (CGameArg.CtlNoJoystick)
|
2020-05-22 02:40:26 +00:00
|
|
|
continue;
|
2019-09-01 14:14:02 +00:00
|
|
|
highest_result = std::max(joy_axisbutton_handler(&event.jaxis), highest_result);
|
2020-05-22 02:40:26 +00:00
|
|
|
result = joy_axis_handler(&event.jaxis);
|
2006-11-22 05:35:10 +00:00
|
|
|
break;
|
|
|
|
case SDL_JOYHATMOTION:
|
2016-10-28 06:43:20 +00:00
|
|
|
if (CGameArg.CtlNoJoystick)
|
2020-05-22 02:40:26 +00:00
|
|
|
continue;
|
|
|
|
result = joy_hat_handler(&event.jhat);
|
2006-11-22 05:35:10 +00:00
|
|
|
break;
|
|
|
|
case SDL_JOYBALLMOTION:
|
2020-05-22 02:40:26 +00:00
|
|
|
continue;
|
2006-11-22 05:35:10 +00:00
|
|
|
case SDL_QUIT: {
|
2011-07-13 21:26:42 +00:00
|
|
|
d_event qevent = { EVENT_QUIT };
|
2020-05-22 02:40:26 +00:00
|
|
|
result = call_default_handler(qevent);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
continue;
|
2006-11-22 05:35:10 +00:00
|
|
|
}
|
2020-05-22 02:40:26 +00:00
|
|
|
highest_result = std::max(result, highest_result);
|
2006-11-22 05:35:10 +00:00
|
|
|
}
|
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2010-07-30 17:59:21 +00:00
|
|
|
void event_flush()
|
|
|
|
{
|
2020-05-22 02:40:26 +00:00
|
|
|
std::array<SDL_Event, 128> events;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
SDL_PumpEvents();
|
|
|
|
#if SDL_MAJOR_VERSION == 1
|
|
|
|
const auto peep = SDL_PeepEvents(events.data(), events.size(), SDL_GETEVENT, SDL_ALLEVENTS);
|
|
|
|
#elif SDL_MAJOR_VERSION == 2
|
|
|
|
const auto peep = SDL_PeepEvents(events.data(), events.size(), SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
|
|
|
|
#endif
|
|
|
|
if (peep != events.size())
|
|
|
|
break;
|
|
|
|
}
|
2010-07-30 17:59:21 +00:00
|
|
|
}
|
|
|
|
|
2006-03-20 16:43:15 +00:00
|
|
|
int event_init()
|
|
|
|
{
|
2006-07-27 09:46:44 +00:00
|
|
|
// We should now be active and responding to events.
|
|
|
|
return 0;
|
2006-11-22 05:35:10 +00:00
|
|
|
}
|
2009-05-21 12:16:39 +00:00
|
|
|
|
2016-10-27 08:36:24 +00:00
|
|
|
window_event_result call_default_handler(const d_event &event)
|
2010-04-02 05:01:08 +00:00
|
|
|
{
|
2015-05-14 02:23:13 +00:00
|
|
|
return standard_handler(event);
|
2010-04-02 05:01:08 +00:00
|
|
|
}
|
|
|
|
|
2016-10-28 06:43:20 +00:00
|
|
|
window_event_result event_send(const d_event &event)
|
2011-01-13 04:36:19 +00:00
|
|
|
{
|
|
|
|
window *wind;
|
2014-08-06 02:10:49 +00:00
|
|
|
window_event_result handled = window_event_result::ignored;
|
2011-01-13 04:36:19 +00:00
|
|
|
|
2015-01-17 18:31:41 +00:00
|
|
|
for (wind = window_get_front(); wind && handled == window_event_result::ignored; wind = window_get_prev(*wind))
|
2011-10-09 10:31:44 +00:00
|
|
|
if (window_is_visible(wind))
|
|
|
|
{
|
2015-01-17 18:31:40 +00:00
|
|
|
handled = window_send_event(*wind, event);
|
2011-10-09 10:31:44 +00:00
|
|
|
|
2016-10-28 00:27:02 +00:00
|
|
|
if (handled == window_event_result::deleted) // break away if necessary: window_send_event() could have closed wind by now
|
2011-11-27 20:35:58 +00:00
|
|
|
break;
|
2015-01-17 18:31:40 +00:00
|
|
|
if (window_is_modal(*wind))
|
2011-10-09 10:31:44 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-08-06 02:10:49 +00:00
|
|
|
if (handled == window_event_result::ignored)
|
2016-10-28 06:43:20 +00:00
|
|
|
return call_default_handler(event);
|
|
|
|
|
|
|
|
return handled;
|
2011-01-13 04:36:19 +00:00
|
|
|
}
|
|
|
|
|
2009-05-21 12:16:39 +00:00
|
|
|
// Process the first event in queue, sending to the appropriate handler
|
|
|
|
// This is the new object-oriented system
|
2010-01-30 03:24:19 +00:00
|
|
|
// Uses the old system for now, but this may change
|
2016-10-28 06:43:20 +00:00
|
|
|
window_event_result event_process(void)
|
2009-05-21 12:16:39 +00:00
|
|
|
{
|
2010-08-06 06:49:45 +00:00
|
|
|
window *wind = window_get_front();
|
2016-10-28 06:43:20 +00:00
|
|
|
window_event_result highest_result;
|
2009-05-21 12:16:39 +00:00
|
|
|
|
2011-02-02 00:36:43 +00:00
|
|
|
timer_update();
|
|
|
|
|
2016-10-28 06:43:20 +00:00
|
|
|
highest_result = event_poll(); // send input events first
|
2010-01-30 03:24:19 +00:00
|
|
|
|
2015-02-11 07:35:44 +00:00
|
|
|
cmd_queue_process();
|
|
|
|
|
2011-01-13 04:36:19 +00:00
|
|
|
// Doing this prevents problems when a draw event can create a newmenu,
|
2010-08-06 06:49:45 +00:00
|
|
|
// such as some network menus when they report a problem
|
2016-10-28 06:43:20 +00:00
|
|
|
// Also checking for window_event_result::deleted in case a window was created
|
|
|
|
// with the same pointer value as the deleted one
|
|
|
|
if ((highest_result == window_event_result::deleted) || (window_get_front() != wind))
|
|
|
|
return highest_result;
|
2018-05-12 18:24:19 +00:00
|
|
|
|
|
|
|
const d_event event{EVENT_WINDOW_DRAW}; // then draw all visible windows
|
2016-11-13 03:47:59 +00:00
|
|
|
for (wind = window_get_first(); wind != nullptr;)
|
2011-02-12 22:58:39 +00:00
|
|
|
{
|
2009-05-21 12:16:39 +00:00
|
|
|
if (window_is_visible(wind))
|
2011-05-26 07:41:26 +00:00
|
|
|
{
|
2016-11-07 01:32:06 +00:00
|
|
|
auto prev = window_get_prev(*wind);
|
2016-10-31 06:58:34 +00:00
|
|
|
auto result = window_send_event(*wind, event);
|
2016-11-13 03:47:59 +00:00
|
|
|
highest_result = std::max(result, highest_result);
|
2016-10-31 06:58:34 +00:00
|
|
|
if (result == window_event_result::deleted)
|
2016-11-13 03:47:59 +00:00
|
|
|
{
|
|
|
|
if (!prev)
|
|
|
|
{
|
|
|
|
wind = window_get_first();
|
|
|
|
continue;
|
|
|
|
}
|
2016-11-07 01:32:06 +00:00
|
|
|
wind = prev; // take the previous window and get the next one from that (if prev isn't nullptr)
|
2016-11-13 03:47:59 +00:00
|
|
|
}
|
2011-05-26 07:41:26 +00:00
|
|
|
}
|
2016-11-13 03:47:59 +00:00
|
|
|
wind = window_get_next(*wind);
|
2011-02-12 22:58:39 +00:00
|
|
|
}
|
2009-12-26 01:08:57 +00:00
|
|
|
|
|
|
|
gr_flip();
|
2016-10-28 06:43:20 +00:00
|
|
|
|
|
|
|
return highest_result;
|
2009-05-21 12:16:39 +00:00
|
|
|
}
|
2010-12-28 18:11:06 +00:00
|
|
|
|
2015-05-09 17:39:03 +00:00
|
|
|
template <bool activate_focus>
|
|
|
|
static void event_change_focus()
|
2010-12-28 18:11:06 +00:00
|
|
|
{
|
2018-07-28 23:22:58 +00:00
|
|
|
const auto enable_grab = activate_focus && CGameCfg.Grabinput && likely(!CGameArg.DbgForbidConsoleGrab);
|
|
|
|
#if SDL_MAJOR_VERSION == 1
|
|
|
|
SDL_WM_GrabInput(enable_grab ? SDL_GRAB_ON : SDL_GRAB_OFF);
|
|
|
|
#elif SDL_MAJOR_VERSION == 2
|
|
|
|
SDL_SetWindowGrab(g_pRebirthSDLMainWindow, enable_grab ? SDL_TRUE : SDL_FALSE);
|
2018-07-29 21:17:09 +00:00
|
|
|
SDL_SetRelativeMouseMode(enable_grab ? SDL_TRUE : SDL_FALSE);
|
2018-07-28 23:22:58 +00:00
|
|
|
#endif
|
2015-05-28 03:08:38 +00:00
|
|
|
if (activate_focus)
|
|
|
|
mouse_disable_cursor();
|
|
|
|
else
|
|
|
|
mouse_enable_cursor();
|
2010-12-28 18:11:06 +00:00
|
|
|
}
|
|
|
|
|
2015-05-09 17:39:03 +00:00
|
|
|
void event_enable_focus()
|
|
|
|
{
|
|
|
|
event_change_focus<true>();
|
|
|
|
}
|
|
|
|
|
|
|
|
void event_disable_focus()
|
|
|
|
{
|
|
|
|
event_change_focus<false>();
|
|
|
|
}
|
|
|
|
|
2018-02-10 22:23:36 +00:00
|
|
|
#if DXX_USE_EDITOR
|
2012-03-18 10:04:16 +00:00
|
|
|
static fix64 last_event = 0;
|
|
|
|
|
|
|
|
void event_reset_idle_seconds()
|
|
|
|
{
|
|
|
|
last_event = timer_query();
|
|
|
|
}
|
|
|
|
|
|
|
|
fix event_get_idle_seconds()
|
|
|
|
{
|
|
|
|
return (timer_query() - last_event)/F1_0;
|
|
|
|
}
|
2018-02-10 22:23:36 +00:00
|
|
|
#endif
|
2012-03-18 10:04:16 +00:00
|
|
|
|
2015-12-05 22:57:24 +00:00
|
|
|
}
|