dxx-rebirth/common/arch/sdl/event.cpp

309 lines
7.4 KiB
C++
Raw Normal View History

2014-06-01 17:55:23 +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.
*/
/*
*
* SDL Event related stuff
*
*
*/
#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"
#include "key.h"
#include "mouse.h"
2009-05-21 12:16:39 +00:00
#include "window.h"
#include "timer.h"
#include "cmd.h"
#include "config.h"
#include "inferno.h"
2006-03-20 16:43:15 +00:00
#include "joy.h"
#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 {
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 *>);
};
}
Enable building with SDL2 This commit enables Rebirth to build with SDL2, but the result is not perfect. - SDL2 removed some sticky key support. Rebirth may behave differently now in this area. - SDL2 removed some key-repeat related support. Rebirth may behave differently now in this area. - SDL2 gained the ability to make a window fullscreen by sizing it to the desktop instead of by changing the desktop resolution. Rebirth uses this, and it mostly works. - Resizing while in the automap does not notify the automap code, so the view is wrong until the player switches out of automap mode and back in. - SDL2 changed how to enumerate available resolutions. Since fitting the window to the desktop is generally more useful than fitting the desktop to the window, I chose to drop support for enumerating resolutions instead of porting to the new API. Users can now enter an arbitrary window dimension and Rebirth will make an attempt to use it. - It might be useful to cap the window dimension at the desktop dimension, but that is not done yet. - Entering fullscreen mode through the Controls->Graphics submenu failed to notify the relevant subsystems, causing the rendered content not to rescale. For now, compile out the option to toggle full screen through that menu. Toggling through Alt+Enter works properly. Despite these quirks, this is a substantial improvement over the prior commit, where SDL2 cannot be used at all. The remaining issues can be resolved in future work. References: <https://github.com/dxx-rebirth/dxx-rebirth/issues/82>
2018-07-28 23:22:58 +00:00
#if SDL_MAJOR_VERSION == 2
extern SDL_Window *g_pRebirthSDLMainWindow;
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;
}
}
}
Enable building with SDL2 This commit enables Rebirth to build with SDL2, but the result is not perfect. - SDL2 removed some sticky key support. Rebirth may behave differently now in this area. - SDL2 removed some key-repeat related support. Rebirth may behave differently now in this area. - SDL2 gained the ability to make a window fullscreen by sizing it to the desktop instead of by changing the desktop resolution. Rebirth uses this, and it mostly works. - Resizing while in the automap does not notify the automap code, so the view is wrong until the player switches out of automap mode and back in. - SDL2 changed how to enumerate available resolutions. Since fitting the window to the desktop is generally more useful than fitting the desktop to the window, I chose to drop support for enumerating resolutions instead of porting to the new API. Users can now enter an arbitrary window dimension and Rebirth will make an attempt to use it. - It might be useful to cap the window dimension at the desktop dimension, but that is not done yet. - Entering fullscreen mode through the Controls->Graphics submenu failed to notify the relevant subsystems, causing the rendered content not to rescale. For now, compile out the option to toggle full screen through that menu. Toggling through Alt+Enter works properly. Despite these quirks, this is a substantial improvement over the prior commit, where SDL2 cannot be used at all. The remaining issues can be resolved in future work. References: <https://github.com/dxx-rebirth/dxx-rebirth/issues/82>
2018-07-28 23:22:58 +00:00
#endif
static void event_notify_begin_loop()
{
const d_event_begin_loop event;
event_send(event);
}
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;
event_notify_begin_loop();
2020-05-27 03:07:17 +00:00
for (;;)
{
// 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)
{
window_event_result result;
switch(event.type) {
#if SDL_MAJOR_VERSION == 2
case SDL_WINDOWEVENT:
windowevent_handler(event.window);
continue;
#endif
case SDL_KEYDOWN:
case SDL_KEYUP:
if (clean_uniframe)
Enable building with SDL2 This commit enables Rebirth to build with SDL2, but the result is not perfect. - SDL2 removed some sticky key support. Rebirth may behave differently now in this area. - SDL2 removed some key-repeat related support. Rebirth may behave differently now in this area. - SDL2 gained the ability to make a window fullscreen by sizing it to the desktop instead of by changing the desktop resolution. Rebirth uses this, and it mostly works. - Resizing while in the automap does not notify the automap code, so the view is wrong until the player switches out of automap mode and back in. - SDL2 changed how to enumerate available resolutions. Since fitting the window to the desktop is generally more useful than fitting the desktop to the window, I chose to drop support for enumerating resolutions instead of porting to the new API. Users can now enter an arbitrary window dimension and Rebirth will make an attempt to use it. - It might be useful to cap the window dimension at the desktop dimension, but that is not done yet. - Entering fullscreen mode through the Controls->Graphics submenu failed to notify the relevant subsystems, causing the rendered content not to rescale. For now, compile out the option to toggle full screen through that menu. Toggling through Alt+Enter works properly. Despite these quirks, this is a substantial improvement over the prior commit, where SDL2 cannot be used at all. The remaining issues can be resolved in future work. References: <https://github.com/dxx-rebirth/dxx-rebirth/issues/82>
2018-07-28 23:22:58 +00:00
{
clean_uniframe=0;
2014-07-14 03:18:40 +00:00
unicode_frame_buffer = {};
Enable building with SDL2 This commit enables Rebirth to build with SDL2, but the result is not perfect. - SDL2 removed some sticky key support. Rebirth may behave differently now in this area. - SDL2 removed some key-repeat related support. Rebirth may behave differently now in this area. - SDL2 gained the ability to make a window fullscreen by sizing it to the desktop instead of by changing the desktop resolution. Rebirth uses this, and it mostly works. - Resizing while in the automap does not notify the automap code, so the view is wrong until the player switches out of automap mode and back in. - SDL2 changed how to enumerate available resolutions. Since fitting the window to the desktop is generally more useful than fitting the desktop to the window, I chose to drop support for enumerating resolutions instead of porting to the new API. Users can now enter an arbitrary window dimension and Rebirth will make an attempt to use it. - It might be useful to cap the window dimension at the desktop dimension, but that is not done yet. - Entering fullscreen mode through the Controls->Graphics submenu failed to notify the relevant subsystems, causing the rendered content not to rescale. For now, compile out the option to toggle full screen through that menu. Toggling through Alt+Enter works properly. Despite these quirks, this is a substantial improvement over the prior commit, where SDL2 cannot be used at all. The remaining issues can be resolved in future work. References: <https://github.com/dxx-rebirth/dxx-rebirth/issues/82>
2018-07-28 23:22:58 +00:00
}
result = key_handler(&event.key);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
if (CGameArg.CtlNoMouse)
continue;
result = mouse_button_handler(&event.button);
break;
case SDL_MOUSEMOTION:
if (CGameArg.CtlNoMouse)
continue;
result = mouse_motion_handler(&event.motion);
break;
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
if (CGameArg.CtlNoJoystick)
continue;
result = joy_button_handler(&event.jbutton);
break;
case SDL_JOYAXISMOTION:
if (CGameArg.CtlNoJoystick)
continue;
#if DXX_MAX_BUTTONS_PER_JOYSTICK || DXX_MAX_HATS_PER_JOYSTICK
highest_result = std::max(joy_axisbutton_handler(&event.jaxis), highest_result);
#endif
result = joy_axis_handler(&event.jaxis);
break;
case SDL_JOYHATMOTION:
if (CGameArg.CtlNoJoystick)
continue;
result = joy_hat_handler(&event.jhat);
break;
case SDL_JOYBALLMOTION:
continue;
case SDL_QUIT: {
d_event qevent = { EVENT_QUIT };
result = call_default_handler(qevent);
break;
}
default:
continue;
}
highest_result = std::max(result, highest_result);
}
}
2006-03-20 16:43:15 +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;
}
}
2006-03-20 16:43:15 +00:00
int event_init()
{
// We should now be active and responding to events.
return 0;
}
2009-05-21 12:16:39 +00:00
window_event_result call_default_handler(const d_event &event)
{
return standard_handler(event);
}
window_event_result event_send(const d_event &event)
{
window *wind;
2014-08-06 02:10:49 +00:00
window_event_result handled = window_event_result::ignored;
2015-01-17 18:31:41 +00:00
for (wind = window_get_front(); wind && handled == window_event_result::ignored; wind = window_get_prev(*wind))
if (window_is_visible(*wind))
{
2015-01-17 18:31:40 +00:00
handled = window_send_event(*wind, event);
if (handled == window_event_result::deleted) // break away if necessary: window_send_event() could have closed wind by now
break;
2015-01-17 18:31:40 +00:00
if (window_is_modal(*wind))
break;
}
2014-08-06 02:10:49 +00:00
if (handled == window_event_result::ignored)
return call_default_handler(event);
return handled;
}
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
// Uses the old system for now, but this may change
window_event_result event_process(void)
2009-05-21 12:16:39 +00:00
{
window *wind = window_get_front();
window_event_result highest_result;
2009-05-21 12:16:39 +00:00
timer_update();
highest_result = event_poll(); // send input events first
2015-02-11 07:35:44 +00:00
cmd_queue_process();
// Doing this prevents problems when a draw event can create a newmenu,
// such as some network menus when they report a problem
// 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
for (wind = window_get_first(); wind != nullptr;)
{
if (window_is_visible(*wind))
{
auto prev = window_get_prev(*wind);
auto result = window_send_event(*wind, event);
highest_result = std::max(result, highest_result);
if (result == window_event_result::deleted)
{
if (!prev)
{
wind = window_get_first();
continue;
}
wind = prev; // take the previous window and get the next one from that (if prev isn't nullptr)
}
}
wind = window_get_next(*wind);
}
gr_flip();
return highest_result;
2009-05-21 12:16:39 +00:00
}
2015-05-09 17:39:03 +00:00
template <bool activate_focus>
static void event_change_focus()
{
Enable building with SDL2 This commit enables Rebirth to build with SDL2, but the result is not perfect. - SDL2 removed some sticky key support. Rebirth may behave differently now in this area. - SDL2 removed some key-repeat related support. Rebirth may behave differently now in this area. - SDL2 gained the ability to make a window fullscreen by sizing it to the desktop instead of by changing the desktop resolution. Rebirth uses this, and it mostly works. - Resizing while in the automap does not notify the automap code, so the view is wrong until the player switches out of automap mode and back in. - SDL2 changed how to enumerate available resolutions. Since fitting the window to the desktop is generally more useful than fitting the desktop to the window, I chose to drop support for enumerating resolutions instead of porting to the new API. Users can now enter an arbitrary window dimension and Rebirth will make an attempt to use it. - It might be useful to cap the window dimension at the desktop dimension, but that is not done yet. - Entering fullscreen mode through the Controls->Graphics submenu failed to notify the relevant subsystems, causing the rendered content not to rescale. For now, compile out the option to toggle full screen through that menu. Toggling through Alt+Enter works properly. Despite these quirks, this is a substantial improvement over the prior commit, where SDL2 cannot be used at all. The remaining issues can be resolved in future work. References: <https://github.com/dxx-rebirth/dxx-rebirth/issues/82>
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);
SDL_SetRelativeMouseMode(enable_grab ? SDL_TRUE : SDL_FALSE);
Enable building with SDL2 This commit enables Rebirth to build with SDL2, but the result is not perfect. - SDL2 removed some sticky key support. Rebirth may behave differently now in this area. - SDL2 removed some key-repeat related support. Rebirth may behave differently now in this area. - SDL2 gained the ability to make a window fullscreen by sizing it to the desktop instead of by changing the desktop resolution. Rebirth uses this, and it mostly works. - Resizing while in the automap does not notify the automap code, so the view is wrong until the player switches out of automap mode and back in. - SDL2 changed how to enumerate available resolutions. Since fitting the window to the desktop is generally more useful than fitting the desktop to the window, I chose to drop support for enumerating resolutions instead of porting to the new API. Users can now enter an arbitrary window dimension and Rebirth will make an attempt to use it. - It might be useful to cap the window dimension at the desktop dimension, but that is not done yet. - Entering fullscreen mode through the Controls->Graphics submenu failed to notify the relevant subsystems, causing the rendered content not to rescale. For now, compile out the option to toggle full screen through that menu. Toggling through Alt+Enter works properly. Despite these quirks, this is a substantial improvement over the prior commit, where SDL2 cannot be used at all. The remaining issues can be resolved in future work. References: <https://github.com/dxx-rebirth/dxx-rebirth/issues/82>
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();
}
2015-05-09 17:39:03 +00:00
void event_enable_focus()
{
event_change_focus<true>();
}
void event_disable_focus()
{
event_change_focus<false>();
}
#if DXX_USE_EDITOR
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;
}
#endif
}