Files
hdk-sdl/include/hdk/sdl/event.hpp
T
2026-05-13 19:48:22 +00:00

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