660 lines
30 KiB
C++
660 lines
30 KiB
C++
#pragma once
|
|
/// @file event.hpp
|
|
/// For complete documentation, see src/event.cpp
|
|
#include <SDL3/SDL_events.h>
|
|
#include <SDL3/SDL_init.h>
|
|
#include <hdk/grid/EPS.hpp>
|
|
#include <hdk/sdl/video/Window.hpp>
|
|
#include <cstdio>
|
|
#include <map>
|
|
#include <string>
|
|
|
|
namespace hdk::sdl {
|
|
class Event {
|
|
public:
|
|
static void AddWatch(SDL_EventFilter filter, void* userdata) { SDL_AddEventWatch(filter, userdata); }
|
|
static bool EventEnabled(Uint32 type) { return SDL_EventEnabled(type); }
|
|
static void FilterEvents(SDL_EventFilter filter, void* userdata) { SDL_FilterEvents(filter, userdata); }
|
|
static void FlushEvent(Uint32 type) { SDL_FlushEvent(type); }
|
|
static void FlushEvents(Uint32 min_type, Uint32 max_type) { SDL_FlushEvents(min_type, max_type); }
|
|
static int GetDescription(const SDL_Event* event, char* buf, int buflen) {
|
|
return SDL_GetEventDescription(event, buf, buflen);
|
|
}
|
|
static std::string GetDescription(const SDL_Event* event) {
|
|
char buf[256];
|
|
GetDescription(event, buf, sizeof(buf));
|
|
return std::string(buf);
|
|
}
|
|
static bool GetFilter(SDL_EventFilter* filter, void** userdata) { return SDL_GetEventFilter(filter, userdata); }
|
|
static Window GetWindowFromEvent(const SDL_Event* event) {
|
|
return Window::get_or_view(SDL_GetWindowFromEvent(event));
|
|
}
|
|
static bool Has(Uint32 type) { return SDL_HasEvent(type); }
|
|
static bool Has(Uint32 min_type, Uint32 max_type) { return SDL_HasEvents(min_type, max_type); }
|
|
static int Peep(SDL_Event* events, int numevents, SDL_EventAction action, Uint32 min_type, Uint32 max_type) {
|
|
return SDL_PeepEvents(events, numevents, action, min_type, max_type);
|
|
}
|
|
static bool Poll(SDL_Event* event) { return SDL_PollEvent(event); }
|
|
static void Pump() { SDL_PumpEvents(); }
|
|
static bool Push(SDL_Event* event) { return SDL_PushEvent(event); }
|
|
template <int BUFLEN = 512> static std::string GetDescription(const SDL_Event* event) {
|
|
char buf[BUFLEN];
|
|
int actual_length = SDL_GetEventDescription(event, buf, sizeof(buf));
|
|
if (actual_length > BUFLEN) {
|
|
return std::string("BUFFER TOO SMALL");
|
|
}
|
|
return std::string(buf);
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
namespace hdk::sdl::evt {
|
|
|
|
class EventConduit : public hdk::grid::eps::Conduit<SDL_Event*> {
|
|
public:
|
|
using hdk::grid::eps::Conduit<SDL_Event*>::Conduit;
|
|
};
|
|
|
|
template <typename ValueType, typename EventType = EventConduit,
|
|
typename MapType = std::map<ValueType, EventType*>>
|
|
class EventValueRouter : public EventConduit {
|
|
public:
|
|
// The type of the map of values to dispatch (for child classes to use)
|
|
typedef MapType value_dispatch_map_t;
|
|
// The map of values to dispatch to
|
|
value_dispatch_map_t value_dispatch_map;
|
|
// Constructor takes a map of values to dispatch to
|
|
EventValueRouter(value_dispatch_map_t dispatch_map)
|
|
: value_dispatch_map(dispatch_map) { }
|
|
// The extractor function is a pure virtual function that child classes must implement to extract the value from
|
|
// the event
|
|
virtual ValueType extractor(SDL_Event* event) const = 0;
|
|
// The Trigger function overrides the base Event Trigger function to extract the value from the event and dispatch
|
|
// to the appropriate callback based on that value, as well as triggering any callbacks in the base Event dispatch
|
|
// list.
|
|
virtual void Trigger(SDL_Event* event) const override {
|
|
if (!event)
|
|
return;
|
|
ValueType value = this->extractor(event);
|
|
auto it = value_dispatch_map.find(value);
|
|
if (it != value_dispatch_map.end() && it->second) {
|
|
(*it->second)(event);
|
|
} else {
|
|
return;
|
|
}
|
|
EventConduit::Trigger(event);
|
|
}
|
|
// Allow direct access to the dispatch map for subscribing to specific values
|
|
EventType& operator[](ValueType value) { return *value_dispatch_map[value]; }
|
|
};
|
|
|
|
class EventTypeRouter
|
|
: public EventValueRouter<SDL_EventType, EventConduit, std::map<SDL_EventType, EventConduit*>> {
|
|
public:
|
|
EventTypeRouter(value_dispatch_map_t dispatch_map)
|
|
: EventValueRouter(std::move(dispatch_map)) { }
|
|
virtual SDL_EventType extractor(SDL_Event* event) const override { return (SDL_EventType)event->type; }
|
|
};
|
|
|
|
class DisplayEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit Orientation, Added, Removed, Moved, DesktopModeChanged, CurrentModeChanged, ContentScaleChanged;
|
|
DisplayEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_DISPLAY_ORIENTATION, &Orientation }, { SDL_EVENT_DISPLAY_ADDED, &Added },
|
|
{ SDL_EVENT_DISPLAY_REMOVED, &Removed }, { SDL_EVENT_DISPLAY_MOVED, &Moved },
|
|
{ SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED, &DesktopModeChanged },
|
|
{ SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED, &CurrentModeChanged },
|
|
{ SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED, &ContentScaleChanged } }) { }
|
|
};
|
|
|
|
class KeyEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit Down, Up;
|
|
KeyEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_KEY_DOWN, &Down }, { SDL_EVENT_KEY_UP, &Up } }) { };
|
|
};
|
|
|
|
class KeysEvents : public EventValueRouter<SDL_Keycode, KeyEvents> {
|
|
public:
|
|
KeysEvents()
|
|
: EventValueRouter({}) { }
|
|
virtual SDL_Keycode extractor(SDL_Event* event) const override { return event->key.key; }
|
|
};
|
|
|
|
class JoystickAxisEvents : public EventValueRouter<Uint8> {
|
|
public:
|
|
JoystickAxisEvents()
|
|
: EventValueRouter({}) { }
|
|
virtual Uint8 extractor(SDL_Event* event) const override { return event->jaxis.axis; }
|
|
};
|
|
|
|
class JoystickBallEvents : public EventValueRouter<Uint8> {
|
|
public:
|
|
JoystickBallEvents()
|
|
: EventValueRouter({}) { }
|
|
virtual Uint8 extractor(SDL_Event* event) const override { return event->jball.ball; }
|
|
};
|
|
|
|
class JoystickHatEvents : public EventValueRouter<Uint8> {
|
|
public:
|
|
JoystickHatEvents()
|
|
: EventValueRouter({}) { }
|
|
virtual Uint8 extractor(SDL_Event* event) const override { return event->jhat.hat; }
|
|
};
|
|
|
|
class JoystickButtonEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit Down, Up;
|
|
JoystickButtonEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_JOYSTICK_BUTTON_DOWN, &Down }, { SDL_EVENT_JOYSTICK_BUTTON_UP, &Up } }) { }
|
|
};
|
|
|
|
class JoystickButtonsEvents : public EventValueRouter<Uint8, JoystickButtonEvents> {
|
|
public:
|
|
JoystickButtonsEvents()
|
|
: EventValueRouter({}) { }
|
|
virtual Uint8 extractor(SDL_Event* event) const override { return event->jbutton.button; }
|
|
};
|
|
|
|
class JoystickEvents : public EventTypeRouter {
|
|
public:
|
|
JoystickAxisEvents AxisMotion;
|
|
JoystickBallEvents BallMotion;
|
|
JoystickHatEvents HatMotion;
|
|
JoystickButtonsEvents Button;
|
|
EventConduit Added, Removed, BatteryUpdated, UpdateComplete;
|
|
JoystickEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_JOYSTICK_AXIS_MOTION, &AxisMotion },
|
|
{ SDL_EVENT_JOYSTICK_BALL_MOTION, &BallMotion }, { SDL_EVENT_JOYSTICK_HAT_MOTION, &HatMotion },
|
|
{ SDL_EVENT_JOYSTICK_BUTTON_DOWN, &Button }, { SDL_EVENT_JOYSTICK_BUTTON_UP, &Button },
|
|
{ SDL_EVENT_JOYSTICK_ADDED, &Added }, { SDL_EVENT_JOYSTICK_REMOVED, &Removed },
|
|
{ SDL_EVENT_JOYSTICK_BATTERY_UPDATED, &BatteryUpdated },
|
|
{ SDL_EVENT_JOYSTICK_UPDATE_COMPLETE, &UpdateComplete } }) { }
|
|
};
|
|
|
|
class JoysticksEvents : public EventValueRouter<SDL_JoystickID, JoystickEvents> {
|
|
public:
|
|
JoysticksEvents()
|
|
: EventValueRouter({}) { }
|
|
virtual SDL_JoystickID extractor(SDL_Event* event) const override {
|
|
switch (event->type) {
|
|
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
|
|
return event->jaxis.which;
|
|
case SDL_EVENT_JOYSTICK_BALL_MOTION:
|
|
return event->jball.which;
|
|
case SDL_EVENT_JOYSTICK_HAT_MOTION:
|
|
return event->jhat.which;
|
|
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
|
|
case SDL_EVENT_JOYSTICK_BUTTON_UP:
|
|
return event->jbutton.which;
|
|
case SDL_EVENT_JOYSTICK_ADDED:
|
|
case SDL_EVENT_JOYSTICK_REMOVED:
|
|
case SDL_EVENT_JOYSTICK_BATTERY_UPDATED:
|
|
case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE:
|
|
return event->jdevice.which;
|
|
default:
|
|
return -1; // Invalid ID for unsupported event types
|
|
}
|
|
}
|
|
};
|
|
|
|
class GamepadAxisEvents : public EventValueRouter<SDL_GamepadAxis> {
|
|
public:
|
|
GamepadAxisEvents()
|
|
: EventValueRouter({}) { }
|
|
virtual SDL_GamepadAxis extractor(SDL_Event* event) const override { return (SDL_GamepadAxis)event->gaxis.axis; }
|
|
};
|
|
|
|
class GamepadButtonEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit Down, Up;
|
|
GamepadButtonEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_GAMEPAD_BUTTON_DOWN, &Down }, { SDL_EVENT_GAMEPAD_BUTTON_UP, &Up } }) { }
|
|
};
|
|
|
|
class GamepadButtonsEvents : public EventValueRouter<SDL_GamepadButton, GamepadButtonEvents> {
|
|
public:
|
|
GamepadButtonsEvents()
|
|
: EventValueRouter({}) { }
|
|
virtual SDL_GamepadButton extractor(SDL_Event* event) const override {
|
|
return (SDL_GamepadButton)event->gbutton.button;
|
|
}
|
|
};
|
|
|
|
class GamepadTouchpadEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit Down, Motion, Up;
|
|
GamepadTouchpadEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN, &Down },
|
|
{ SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION, &Motion }, { SDL_EVENT_GAMEPAD_TOUCHPAD_UP, &Up } }) { }
|
|
};
|
|
|
|
class GamepadEvents : public EventTypeRouter {
|
|
public:
|
|
GamepadAxisEvents AxisMotion;
|
|
GamepadButtonsEvents Button;
|
|
EventConduit Added, Removed, Remapped;
|
|
GamepadTouchpadEvents Touchpad;
|
|
EventConduit SensorUpdate, UpdateComplete, SteamHandleUpdate;
|
|
|
|
GamepadEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_GAMEPAD_AXIS_MOTION, &AxisMotion }, { SDL_EVENT_GAMEPAD_BUTTON_DOWN, &Button },
|
|
{ SDL_EVENT_GAMEPAD_BUTTON_UP, &Button }, { SDL_EVENT_GAMEPAD_ADDED, &Added },
|
|
{ SDL_EVENT_GAMEPAD_REMOVED, &Removed }, { SDL_EVENT_GAMEPAD_REMAPPED, &Remapped },
|
|
{ SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN, &Touchpad }, { SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION, &Touchpad },
|
|
{ SDL_EVENT_GAMEPAD_TOUCHPAD_UP, &Touchpad }, { SDL_EVENT_GAMEPAD_SENSOR_UPDATE, &SensorUpdate },
|
|
{ SDL_EVENT_GAMEPAD_UPDATE_COMPLETE, &UpdateComplete } }) {
|
|
}
|
|
};
|
|
|
|
class GamepadsEvents : public EventValueRouter<SDL_JoystickID, GamepadEvents> {
|
|
public:
|
|
GamepadsEvents()
|
|
: EventValueRouter({}) { }
|
|
virtual SDL_JoystickID extractor(SDL_Event* event) const override {
|
|
switch (event->type) {
|
|
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
|
return event->gaxis.which;
|
|
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
|
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
|
return event->gbutton.which;
|
|
case SDL_EVENT_GAMEPAD_ADDED:
|
|
case SDL_EVENT_GAMEPAD_REMOVED:
|
|
case SDL_EVENT_GAMEPAD_REMAPPED:
|
|
return event->gdevice.which;
|
|
case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
|
|
case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
|
|
case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
|
|
return event->gtouchpad.which;
|
|
case SDL_EVENT_GAMEPAD_SENSOR_UPDATE:
|
|
case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE:
|
|
case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED:
|
|
return event->gsensor.which;
|
|
default:
|
|
return -1; // Invalid ID for unsupported event types
|
|
}
|
|
}
|
|
};
|
|
|
|
class FingerEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit Down, Up, Motion, Canceled;
|
|
FingerEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_FINGER_DOWN, &Down }, { SDL_EVENT_FINGER_UP, &Up },
|
|
{ SDL_EVENT_FINGER_MOTION, &Motion }, { SDL_EVENT_FINGER_CANCELED, &Canceled } }) { }
|
|
};
|
|
|
|
class DropEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit File, Text, Begin, Complete;
|
|
DropEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_DROP_FILE, &File }, { SDL_EVENT_DROP_TEXT, &Text },
|
|
{ SDL_EVENT_DROP_BEGIN, &Begin }, { SDL_EVENT_DROP_COMPLETE, &Complete } }) { }
|
|
};
|
|
|
|
class AudioDeviceEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit Added, Removed, FormatChanged;
|
|
AudioDeviceEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_AUDIO_DEVICE_ADDED, &Added }, { SDL_EVENT_AUDIO_DEVICE_REMOVED, &Removed },
|
|
{ SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED, &FormatChanged } }) {
|
|
}
|
|
};
|
|
|
|
class PenEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit ProximityIn, ProximityOut, Down, Up, Motion;
|
|
PenEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_PEN_PROXIMITY_IN, &ProximityIn }, { SDL_EVENT_PEN_PROXIMITY_OUT, &ProximityOut },
|
|
{ SDL_EVENT_PEN_DOWN, &Down }, { SDL_EVENT_PEN_UP, &Up }, { SDL_EVENT_PEN_MOTION, &Motion } }) { }
|
|
};
|
|
|
|
class CameraDeviceEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit Added, Removed, Approved, Denied;
|
|
CameraDeviceEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_CAMERA_DEVICE_ADDED, &Added }, { SDL_EVENT_CAMERA_DEVICE_REMOVED, &Removed },
|
|
{ SDL_EVENT_CAMERA_DEVICE_APPROVED, &Approved }, { SDL_EVENT_CAMERA_DEVICE_DENIED, &Denied } }) {
|
|
}
|
|
};
|
|
|
|
class RenderEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit TargetsReset, DeviceReset, DeviceLost;
|
|
RenderEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_RENDER_TARGETS_RESET, &TargetsReset },
|
|
{ SDL_EVENT_RENDER_DEVICE_RESET, &DeviceReset }, { SDL_EVENT_RENDER_DEVICE_LOST, &DeviceLost } }) { }
|
|
};
|
|
|
|
class KeyboardEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit Added, Removed;
|
|
KeyboardEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_KEYBOARD_ADDED, &Added }, { SDL_EVENT_KEYBOARD_REMOVED, &Removed } }) { }
|
|
};
|
|
|
|
class MouseButtonEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit Down, Up;
|
|
MouseButtonEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_MOUSE_BUTTON_DOWN, &Down }, { SDL_EVENT_MOUSE_BUTTON_UP, &Up } }) { }
|
|
};
|
|
|
|
class MouseButtonsEvents : public EventValueRouter<Uint8, MouseButtonEvents> {
|
|
public:
|
|
MouseButtonsEvents()
|
|
: EventValueRouter({}) { }
|
|
virtual Uint8 extractor(SDL_Event* event) const override { return event->button.button; }
|
|
};
|
|
|
|
class MouseEvents : public EventTypeRouter {
|
|
public:
|
|
MouseButtonsEvents Button;
|
|
EventConduit Motion, Wheel, Added, Removed;
|
|
MouseEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_MOUSE_MOTION, &Motion }, { SDL_EVENT_MOUSE_BUTTON_DOWN, &Button },
|
|
{ SDL_EVENT_MOUSE_BUTTON_UP, &Button }, { SDL_EVENT_MOUSE_WHEEL, &Wheel },
|
|
{ SDL_EVENT_MOUSE_ADDED, &Added }, { SDL_EVENT_MOUSE_REMOVED, &Removed } }) { }
|
|
};
|
|
|
|
class MiceEvents : public EventValueRouter<SDL_MouseID, MouseEvents> {
|
|
public:
|
|
MiceEvents()
|
|
: EventValueRouter({}) { }
|
|
virtual SDL_MouseID extractor(SDL_Event* event) const override {
|
|
switch (event->type) {
|
|
case SDL_EVENT_MOUSE_MOTION:
|
|
return event->motion.which;
|
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
|
return event->button.which;
|
|
case SDL_EVENT_MOUSE_WHEEL:
|
|
return event->wheel.which;
|
|
case SDL_EVENT_MOUSE_ADDED:
|
|
case SDL_EVENT_MOUSE_REMOVED:
|
|
return event->mdevice.which;
|
|
default:
|
|
return -1; // Invalid ID for unsupported event types
|
|
}
|
|
}
|
|
};
|
|
|
|
class TextEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit Input, Editing, EditingCandidates;
|
|
TextEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_TEXT_INPUT, &Input }, { SDL_EVENT_TEXT_EDITING, &Editing },
|
|
{ SDL_EVENT_TEXT_EDITING_CANDIDATES, &EditingCandidates } }) { }
|
|
};
|
|
|
|
class WindowEvents : public EventTypeRouter {
|
|
public:
|
|
EventConduit Shown, Hidden, Exposed, Moved, Resized, PixelSizeChanged, MetalViewResized, Minimized, Maximized, Restored,
|
|
MouseEnter, MouseLeave, FocusLost, CloseRequested, HitTest, ICCProfChange, DisplayChanged, DisplayScaleChanged,
|
|
SafeAreaChanged, Occluded, EnterFullscreen, LeaveFullscreen, LeaveDesktop, TakeFocus, HitTestResult, Destroyed,
|
|
HdrStateChanged;
|
|
|
|
// @todo possibly refactor to a specialized subclass,
|
|
// these are not "WINDOW" events; but events that identify "WindowID",
|
|
// and so we dispatch them to handlers for that window so that each window can have its own
|
|
// unified set of handlers.
|
|
FingerEvents Finger;
|
|
PenEvents Pen;
|
|
MiceEvents Mouse;
|
|
KeysEvents Key;
|
|
TextEvents Text;
|
|
DropEvents Drop;
|
|
RenderEvents Render;
|
|
WindowEvents()
|
|
: EventTypeRouter({ { SDL_EVENT_WINDOW_SHOWN, &Shown }, { SDL_EVENT_WINDOW_HIDDEN, &Hidden },
|
|
{ SDL_EVENT_WINDOW_EXPOSED, &Exposed }, { SDL_EVENT_WINDOW_MOVED, &Moved },
|
|
{ SDL_EVENT_WINDOW_RESIZED, &Resized }, { SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED, &PixelSizeChanged },
|
|
{ SDL_EVENT_WINDOW_METAL_VIEW_RESIZED, &MetalViewResized }, { SDL_EVENT_WINDOW_MINIMIZED, &Minimized },
|
|
{ SDL_EVENT_WINDOW_MAXIMIZED, &Maximized }, { SDL_EVENT_WINDOW_RESTORED, &Restored },
|
|
{ SDL_EVENT_WINDOW_MOUSE_ENTER, &MouseEnter }, { SDL_EVENT_WINDOW_MOUSE_LEAVE, &MouseLeave },
|
|
{ SDL_EVENT_WINDOW_FOCUS_LOST, &FocusLost }, { SDL_EVENT_WINDOW_CLOSE_REQUESTED, &CloseRequested },
|
|
{ SDL_EVENT_WINDOW_HIT_TEST, &HitTest }, { SDL_EVENT_WINDOW_ICCPROF_CHANGED, &ICCProfChange },
|
|
{ SDL_EVENT_WINDOW_DISPLAY_CHANGED, &DisplayChanged },
|
|
{ SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED, &DisplayScaleChanged },
|
|
{ SDL_EVENT_WINDOW_SAFE_AREA_CHANGED, &SafeAreaChanged }, { SDL_EVENT_WINDOW_OCCLUDED, &Occluded },
|
|
{ SDL_EVENT_WINDOW_ENTER_FULLSCREEN, &EnterFullscreen },
|
|
{ SDL_EVENT_WINDOW_LEAVE_FULLSCREEN, &LeaveFullscreen }, { SDL_EVENT_WINDOW_DESTROYED, &Destroyed },
|
|
{ SDL_EVENT_WINDOW_HDR_STATE_CHANGED, &HdrStateChanged }, { SDL_EVENT_FINGER_DOWN, &Finger },
|
|
{ SDL_EVENT_FINGER_UP, &Finger }, { SDL_EVENT_FINGER_MOTION, &Finger },
|
|
{ SDL_EVENT_FINGER_CANCELED, &Finger }, { SDL_EVENT_PEN_MOTION, &Pen },
|
|
{ SDL_EVENT_PEN_BUTTON_DOWN, &Pen }, { SDL_EVENT_PEN_BUTTON_UP, &Pen }, { SDL_EVENT_PEN_AXIS, &Pen },
|
|
{ SDL_EVENT_MOUSE_WHEEL, &Mouse }, { SDL_EVENT_MOUSE_MOTION, &Mouse },
|
|
{ SDL_EVENT_MOUSE_BUTTON_DOWN, &Mouse }, { SDL_EVENT_MOUSE_BUTTON_UP, &Mouse },
|
|
{ SDL_EVENT_KEY_DOWN, &Key }, { SDL_EVENT_KEY_UP, &Key }, { SDL_EVENT_PEN_PROXIMITY_IN, &Pen },
|
|
{ SDL_EVENT_PEN_PROXIMITY_OUT, &Pen }, { SDL_EVENT_PEN_DOWN, &Pen }, { SDL_EVENT_PEN_UP, &Pen },
|
|
{ SDL_EVENT_TEXT_INPUT, &Text }, { SDL_EVENT_TEXT_EDITING, &Text },
|
|
{ SDL_EVENT_TEXT_EDITING_CANDIDATES, &Text }, { SDL_EVENT_RENDER_TARGETS_RESET, &Render },
|
|
{ SDL_EVENT_RENDER_DEVICE_RESET, &Render }, { SDL_EVENT_RENDER_DEVICE_LOST, &Render },
|
|
{ SDL_EVENT_DROP_BEGIN, &Drop }, { SDL_EVENT_DROP_FILE, &Drop }, { SDL_EVENT_DROP_TEXT, &Drop },
|
|
{ SDL_EVENT_DROP_COMPLETE, &Drop }, { SDL_EVENT_DROP_POSITION, &Drop } }) { }
|
|
};
|
|
|
|
class WindowsEvents : public EventValueRouter<SDL_WindowID, WindowEvents> {
|
|
public:
|
|
std::map<SDL_WindowID, WindowEvents> windows;
|
|
WindowsEvents()
|
|
: EventValueRouter({}) { }
|
|
WindowEvents& operator[](SDL_WindowID window_id) {
|
|
WindowEvents& window = windows[window_id];
|
|
value_dispatch_map[window_id] = &window;
|
|
return window;
|
|
}
|
|
virtual SDL_WindowID extractor(SDL_Event* event) const override {
|
|
switch (event->type) {
|
|
case SDL_EVENT_WINDOW_SHOWN:
|
|
case SDL_EVENT_WINDOW_HIDDEN:
|
|
case SDL_EVENT_WINDOW_EXPOSED:
|
|
case SDL_EVENT_WINDOW_MOVED:
|
|
case SDL_EVENT_WINDOW_RESIZED:
|
|
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
|
case SDL_EVENT_WINDOW_METAL_VIEW_RESIZED:
|
|
case SDL_EVENT_WINDOW_MINIMIZED:
|
|
case SDL_EVENT_WINDOW_MAXIMIZED:
|
|
case SDL_EVENT_WINDOW_RESTORED:
|
|
case SDL_EVENT_WINDOW_MOUSE_ENTER:
|
|
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
|
|
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
|
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
|
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
|
case SDL_EVENT_WINDOW_HIT_TEST:
|
|
case SDL_EVENT_WINDOW_ICCPROF_CHANGED:
|
|
case SDL_EVENT_WINDOW_DISPLAY_CHANGED:
|
|
case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
|
|
case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED:
|
|
case SDL_EVENT_WINDOW_OCCLUDED:
|
|
case SDL_EVENT_WINDOW_ENTER_FULLSCREEN:
|
|
case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN:
|
|
case SDL_EVENT_WINDOW_DESTROYED:
|
|
return event->window.windowID;
|
|
|
|
case SDL_EVENT_FINGER_DOWN:
|
|
case SDL_EVENT_FINGER_UP:
|
|
case SDL_EVENT_FINGER_MOTION:
|
|
case SDL_EVENT_FINGER_CANCELED:
|
|
return event->tfinger.windowID;
|
|
|
|
case SDL_EVENT_PEN_BUTTON_DOWN:
|
|
case SDL_EVENT_PEN_BUTTON_UP:
|
|
return event->pbutton.windowID;
|
|
|
|
case SDL_EVENT_PEN_AXIS:
|
|
return event->paxis.windowID;
|
|
|
|
case SDL_EVENT_MOUSE_WHEEL:
|
|
return event->wheel.windowID;
|
|
case SDL_EVENT_MOUSE_MOTION:
|
|
return event->motion.windowID;
|
|
|
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
|
return event->button.windowID;
|
|
|
|
case SDL_EVENT_KEY_DOWN:
|
|
case SDL_EVENT_KEY_UP:
|
|
return event->key.windowID;
|
|
|
|
case SDL_EVENT_PEN_PROXIMITY_IN:
|
|
case SDL_EVENT_PEN_PROXIMITY_OUT:
|
|
return event->pproximity.windowID;
|
|
|
|
case SDL_EVENT_PEN_DOWN:
|
|
case SDL_EVENT_PEN_UP:
|
|
return event->ptouch.windowID;
|
|
|
|
case SDL_EVENT_TEXT_INPUT:
|
|
return event->text.windowID;
|
|
|
|
case SDL_EVENT_TEXT_EDITING:
|
|
return event->edit.windowID;
|
|
|
|
case SDL_EVENT_TEXT_EDITING_CANDIDATES:
|
|
return event->edit_candidates.windowID;
|
|
|
|
case SDL_EVENT_RENDER_TARGETS_RESET:
|
|
case SDL_EVENT_RENDER_DEVICE_RESET:
|
|
case SDL_EVENT_RENDER_DEVICE_LOST:
|
|
return event->render.windowID;
|
|
|
|
case SDL_EVENT_DROP_BEGIN:
|
|
case SDL_EVENT_DROP_FILE:
|
|
case SDL_EVENT_DROP_TEXT:
|
|
case SDL_EVENT_DROP_COMPLETE:
|
|
case SDL_EVENT_DROP_POSITION:
|
|
return event->drop.windowID;
|
|
|
|
default:
|
|
if (event->type >= SDL_EVENT_USER && event->type <= SDL_EVENT_LAST) {
|
|
// User events may have a windowID, but it's not guaranteed, so we check for it here
|
|
return event->user.windowID;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
class AllTypes : public EventTypeRouter {
|
|
public:
|
|
EventConduit Quit, Terminating, LowMemory, WillEnterBackground, DidEnterBackground, WillEnterForeground, LocaleChanged,
|
|
SystemThemeChanged;
|
|
DisplayEvents Display;
|
|
WindowsEvents Window;
|
|
TextEvents Text;
|
|
EventConduit KeymapChanged;
|
|
KeysEvents Key;
|
|
KeyboardEvents Keyboard;
|
|
MiceEvents Mouse;
|
|
JoysticksEvents Joystick;
|
|
GamepadsEvents Gamepad;
|
|
FingerEvents Finger;
|
|
EventConduit ClipboardUpdate;
|
|
DropEvents Drop;
|
|
AudioDeviceEvents AudioDevice;
|
|
EventConduit SensorUpdate;
|
|
PenEvents Pen;
|
|
CameraDeviceEvents CameraDevice;
|
|
/* Render Events */
|
|
RenderEvents Render;
|
|
AllTypes()
|
|
// https://wiki.libsdl.org/SDL3/SDL_EventType
|
|
: EventTypeRouter({ { SDL_EVENT_QUIT, &Quit }, { SDL_EVENT_TERMINATING, &Terminating },
|
|
{ SDL_EVENT_LOW_MEMORY, &LowMemory }, { SDL_EVENT_WILL_ENTER_BACKGROUND, &WillEnterBackground },
|
|
{ SDL_EVENT_DID_ENTER_BACKGROUND, &DidEnterBackground },
|
|
{ SDL_EVENT_WILL_ENTER_FOREGROUND, &WillEnterForeground }, { SDL_EVENT_LOCALE_CHANGED, &LocaleChanged },
|
|
{ SDL_EVENT_SYSTEM_THEME_CHANGED, &SystemThemeChanged }, { SDL_EVENT_DISPLAY_ORIENTATION, &Display },
|
|
{ SDL_EVENT_DISPLAY_ADDED, &Display }, { SDL_EVENT_DISPLAY_REMOVED, &Display },
|
|
{ SDL_EVENT_DISPLAY_MOVED, &Display }, { SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED, &Display },
|
|
{ SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED, &Display }, { SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED, &Display },
|
|
{ SDL_EVENT_WINDOW_SHOWN, &Window }, { SDL_EVENT_WINDOW_HIDDEN, &Window },
|
|
{ SDL_EVENT_WINDOW_EXPOSED, &Window }, { SDL_EVENT_WINDOW_MOVED, &Window },
|
|
{ SDL_EVENT_WINDOW_RESIZED, &Window }, { SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED, &Window },
|
|
{ SDL_EVENT_WINDOW_METAL_VIEW_RESIZED, &Window }, { SDL_EVENT_WINDOW_MINIMIZED, &Window },
|
|
{ SDL_EVENT_WINDOW_MAXIMIZED, &Window }, { SDL_EVENT_WINDOW_RESTORED, &Window },
|
|
{ SDL_EVENT_WINDOW_MOUSE_ENTER, &Window }, { SDL_EVENT_WINDOW_MOUSE_LEAVE, &Window },
|
|
{ SDL_EVENT_WINDOW_FOCUS_LOST, &Window }, { SDL_EVENT_WINDOW_CLOSE_REQUESTED, &Window },
|
|
{ SDL_EVENT_WINDOW_HIT_TEST, &Window }, { SDL_EVENT_WINDOW_ICCPROF_CHANGED, &Window },
|
|
{ SDL_EVENT_WINDOW_DISPLAY_CHANGED, &Window }, { SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED, &Window },
|
|
{ SDL_EVENT_WINDOW_SAFE_AREA_CHANGED, &Window }, { SDL_EVENT_WINDOW_OCCLUDED, &Window },
|
|
{ SDL_EVENT_WINDOW_ENTER_FULLSCREEN, &Window }, { SDL_EVENT_WINDOW_LEAVE_FULLSCREEN, &Window },
|
|
{ SDL_EVENT_WINDOW_DESTROYED, &Window }, { SDL_EVENT_WINDOW_HDR_STATE_CHANGED, &Window },
|
|
{ SDL_EVENT_KEY_DOWN, &Key }, { SDL_EVENT_KEY_UP, &Key }, { SDL_EVENT_TEXT_EDITING, &Text },
|
|
{ SDL_EVENT_TEXT_INPUT, &Text }, { SDL_EVENT_TEXT_EDITING_CANDIDATES, &Text },
|
|
{ SDL_EVENT_KEYMAP_CHANGED, &KeymapChanged }, { SDL_EVENT_KEYBOARD_ADDED, &Keyboard },
|
|
{ SDL_EVENT_KEYBOARD_REMOVED, &Keyboard }, { SDL_EVENT_MOUSE_MOTION, &Mouse },
|
|
{ SDL_EVENT_MOUSE_BUTTON_DOWN, &Mouse }, { SDL_EVENT_MOUSE_BUTTON_UP, &Mouse },
|
|
{ SDL_EVENT_MOUSE_WHEEL, &Mouse }, { SDL_EVENT_MOUSE_ADDED, &Mouse }, { SDL_EVENT_MOUSE_REMOVED, &Mouse },
|
|
{ SDL_EVENT_JOYSTICK_AXIS_MOTION, &Joystick }, { SDL_EVENT_JOYSTICK_BALL_MOTION, &Joystick },
|
|
{ SDL_EVENT_JOYSTICK_HAT_MOTION, &Joystick }, { SDL_EVENT_JOYSTICK_BUTTON_DOWN, &Joystick },
|
|
{ SDL_EVENT_JOYSTICK_BUTTON_UP, &Joystick }, { SDL_EVENT_JOYSTICK_ADDED, &Joystick },
|
|
{ SDL_EVENT_JOYSTICK_REMOVED, &Joystick }, { SDL_EVENT_JOYSTICK_BATTERY_UPDATED, &Joystick },
|
|
{ SDL_EVENT_JOYSTICK_UPDATE_COMPLETE, &Joystick }, { SDL_EVENT_GAMEPAD_AXIS_MOTION, &Gamepad },
|
|
{ SDL_EVENT_GAMEPAD_BUTTON_DOWN, &Gamepad }, { SDL_EVENT_GAMEPAD_BUTTON_UP, &Gamepad },
|
|
{ SDL_EVENT_GAMEPAD_ADDED, &Gamepad }, { SDL_EVENT_GAMEPAD_REMOVED, &Gamepad },
|
|
{ SDL_EVENT_GAMEPAD_REMAPPED, &Gamepad }, { SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN, &Gamepad },
|
|
{ SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION, &Gamepad }, { SDL_EVENT_GAMEPAD_TOUCHPAD_UP, &Gamepad },
|
|
{ SDL_EVENT_GAMEPAD_SENSOR_UPDATE, &Gamepad }, { SDL_EVENT_GAMEPAD_UPDATE_COMPLETE, &Gamepad },
|
|
{ SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED, &Gamepad }, { SDL_EVENT_FINGER_DOWN, &Finger },
|
|
{ SDL_EVENT_FINGER_UP, &Finger }, { SDL_EVENT_FINGER_MOTION, &Finger },
|
|
{ SDL_EVENT_FINGER_CANCELED, &Finger }, { SDL_EVENT_CLIPBOARD_UPDATE, &ClipboardUpdate },
|
|
{ SDL_EVENT_DROP_FILE, &Drop }, { SDL_EVENT_DROP_TEXT, &Drop }, { SDL_EVENT_DROP_BEGIN, &Drop },
|
|
{ SDL_EVENT_DROP_COMPLETE, &Drop }, { SDL_EVENT_DROP_POSITION, &Drop },
|
|
{ SDL_EVENT_AUDIO_DEVICE_ADDED, &AudioDevice }, { SDL_EVENT_AUDIO_DEVICE_REMOVED, &AudioDevice },
|
|
{ SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED, &AudioDevice }, { SDL_EVENT_SENSOR_UPDATE, &SensorUpdate },
|
|
{ SDL_EVENT_PEN_PROXIMITY_IN, &Pen }, { SDL_EVENT_PEN_PROXIMITY_OUT, &Pen }, { SDL_EVENT_PEN_DOWN, &Pen },
|
|
{ SDL_EVENT_PEN_UP, &Pen }, { SDL_EVENT_PEN_BUTTON_DOWN, &Pen }, { SDL_EVENT_PEN_BUTTON_UP, &Pen },
|
|
{ SDL_EVENT_PEN_MOTION, &Pen }, { SDL_EVENT_PEN_AXIS, &Pen },
|
|
{ SDL_EVENT_CAMERA_DEVICE_ADDED, &CameraDevice }, { SDL_EVENT_CAMERA_DEVICE_REMOVED, &CameraDevice },
|
|
{ SDL_EVENT_CAMERA_DEVICE_APPROVED, &CameraDevice }, { SDL_EVENT_CAMERA_DEVICE_DENIED, &CameraDevice },
|
|
{ SDL_EVENT_RENDER_TARGETS_RESET, &Render }, { SDL_EVENT_RENDER_DEVICE_RESET, &Render },
|
|
{ SDL_EVENT_RENDER_DEVICE_LOST, &Render } }) { };
|
|
|
|
// In addition to dispatching things to their normal handler we are also going to send all events that have a
|
|
// WindowID to the CompleteWindowsEvents handler, so that users can listen for all events related to a specific
|
|
// window in one place if they want to.
|
|
virtual void Trigger(SDL_Event* event) const override {
|
|
switch (event->type) {
|
|
// SDL_EVENT_WINDOW_* is already forwarded to Window event handlers
|
|
// But these following events contain a WindowID, and so we want to forward them too there.
|
|
// THat way people can subscribe to things like All mouse events for Window 'x'.
|
|
case SDL_EVENT_FINGER_DOWN:
|
|
case SDL_EVENT_FINGER_UP:
|
|
case SDL_EVENT_FINGER_MOTION:
|
|
case SDL_EVENT_FINGER_CANCELED:
|
|
case SDL_EVENT_PEN_MOTION:
|
|
case SDL_EVENT_PEN_BUTTON_DOWN:
|
|
case SDL_EVENT_PEN_BUTTON_UP:
|
|
case SDL_EVENT_PEN_AXIS:
|
|
case SDL_EVENT_MOUSE_WHEEL:
|
|
case SDL_EVENT_MOUSE_MOTION:
|
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
|
case SDL_EVENT_KEY_DOWN:
|
|
case SDL_EVENT_KEY_UP:
|
|
case SDL_EVENT_PEN_PROXIMITY_IN:
|
|
case SDL_EVENT_PEN_PROXIMITY_OUT:
|
|
case SDL_EVENT_PEN_DOWN:
|
|
case SDL_EVENT_PEN_UP:
|
|
case SDL_EVENT_TEXT_INPUT:
|
|
case SDL_EVENT_TEXT_EDITING:
|
|
case SDL_EVENT_TEXT_EDITING_CANDIDATES:
|
|
case SDL_EVENT_RENDER_TARGETS_RESET:
|
|
case SDL_EVENT_RENDER_DEVICE_RESET:
|
|
case SDL_EVENT_RENDER_DEVICE_LOST:
|
|
case SDL_EVENT_DROP_BEGIN:
|
|
case SDL_EVENT_DROP_FILE:
|
|
case SDL_EVENT_DROP_TEXT:
|
|
case SDL_EVENT_DROP_COMPLETE:
|
|
case SDL_EVENT_DROP_POSITION:
|
|
Window(event);
|
|
// default:
|
|
// do nothing additional for the others
|
|
}
|
|
EventTypeRouter::Trigger(event);
|
|
}
|
|
};
|
|
} // namespace hdk::sdl::evt
|