#pragma once /// @file event.hpp /// For complete documentation, see src/event.cpp #include #include #include #include #include #include #include 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 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 { public: using hdk::grid::eps::Conduit::Conduit; }; template > 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) = 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) 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> { public: EventTypeRouter(value_dispatch_map_t dispatch_map) : EventValueRouter(std::move(dispatch_map)) { } virtual SDL_EventType extractor(SDL_Event* event) override { return (SDL_EventType)event->type; } }; class DisplayEvents : public EventTypeRouter { public: EventConduit Orientation, Added, Removed, Moved, DesktopModeChanged, CurrentModeChanged, ContentScaleChanged; // clang-format off 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 } }) { } // clang-format on }; class KeyEvents : public EventTypeRouter { public: EventConduit Down, Up; // clang-format off KeyEvents() : EventTypeRouter({ { SDL_EVENT_KEY_DOWN, &Down }, { SDL_EVENT_KEY_UP, &Up } }) { }; // clang-format on }; class KeysEvents : public EventValueRouter { public: KeysEvents() : EventValueRouter({}) { } virtual SDL_Keycode extractor(SDL_Event* event) override { return event->key.key; } }; class JoystickAxisEvents : public EventValueRouter { public: JoystickAxisEvents() : EventValueRouter({}) { } virtual Uint8 extractor(SDL_Event* event) override { return event->jaxis.axis; } }; class JoystickBallEvents : public EventValueRouter { public: JoystickBallEvents() : EventValueRouter({}) { } virtual Uint8 extractor(SDL_Event* event) override { return event->jball.ball; } }; class JoystickHatEvents : public EventValueRouter { public: JoystickHatEvents() : EventValueRouter({}) { } virtual Uint8 extractor(SDL_Event* event) override { return event->jhat.hat; } }; class JoystickButtonEvents : public EventTypeRouter { public: EventConduit Down, Up; // clang-format off JoystickButtonEvents() : EventTypeRouter({ { SDL_EVENT_JOYSTICK_BUTTON_DOWN, &Down }, { SDL_EVENT_JOYSTICK_BUTTON_UP, &Up } }) { } // clang-format on }; class JoystickButtonsEvents : public EventValueRouter { public: JoystickButtonsEvents() : EventValueRouter({}) { } virtual Uint8 extractor(SDL_Event* event) override { return event->jbutton.button; } }; class JoystickEvents : public EventTypeRouter { public: JoystickAxisEvents AxisMotion; JoystickBallEvents BallMotion; JoystickHatEvents HatMotion; JoystickButtonsEvents Button; EventConduit Added, Removed, BatteryUpdated, UpdateComplete; // clang-format off 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 } }) { } // clang-format on }; class JoysticksEvents : public EventValueRouter { public: JoysticksEvents() : EventValueRouter({}) { } virtual SDL_JoystickID extractor(SDL_Event* event) 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 { public: GamepadAxisEvents() : EventValueRouter({}) { } virtual SDL_GamepadAxis extractor(SDL_Event* event) override { return (SDL_GamepadAxis)event->gaxis.axis; } }; class GamepadButtonEvents : public EventTypeRouter { public: EventConduit Down, Up; // clang-format off GamepadButtonEvents() : EventTypeRouter({ { SDL_EVENT_GAMEPAD_BUTTON_DOWN, &Down }, { SDL_EVENT_GAMEPAD_BUTTON_UP, &Up } }) { } // clang-format on }; class GamepadButtonsEvents : public EventValueRouter { public: GamepadButtonsEvents() : EventValueRouter({}) { } virtual SDL_GamepadButton extractor(SDL_Event* event) override { return (SDL_GamepadButton)event->gbutton.button; } }; class GamepadTouchpadEvents : public EventTypeRouter { public: EventConduit Down, Motion, Up; // clang-format off GamepadTouchpadEvents() : EventTypeRouter({ { SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN, &Down }, { SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION, &Motion }, { SDL_EVENT_GAMEPAD_TOUCHPAD_UP, &Up } }) { } // clang-format on }; class GamepadEvents : public EventTypeRouter { public: GamepadAxisEvents AxisMotion; GamepadButtonsEvents Button; EventConduit Added, Removed, Remapped; GamepadTouchpadEvents Touchpad; EventConduit SensorUpdate, UpdateComplete, SteamHandleUpdate; // clang-format off 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 } }) { } // clang-format on }; class GamepadsEvents : public EventValueRouter { public: GamepadsEvents() : EventValueRouter({}) { } virtual SDL_JoystickID extractor(SDL_Event* event) 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; // clang-format off FingerEvents() : EventTypeRouter({ { SDL_EVENT_FINGER_DOWN, &Down }, { SDL_EVENT_FINGER_UP, &Up }, { SDL_EVENT_FINGER_MOTION, &Motion } , { SDL_EVENT_FINGER_CANCELED, &Canceled } }) { } // clang-format on }; class DropEvents : public EventTypeRouter { public: EventConduit File, Text, Begin, Complete; // clang-format off DropEvents() : EventTypeRouter({ { SDL_EVENT_DROP_FILE, &File }, { SDL_EVENT_DROP_TEXT, &Text }, { SDL_EVENT_DROP_BEGIN, &Begin }, { SDL_EVENT_DROP_COMPLETE, &Complete } }) { } // clang-format on }; class AudioDeviceEvents : public EventTypeRouter { public: EventConduit Added, Removed, FormatChanged; // clang-format off AudioDeviceEvents() : EventTypeRouter({ { SDL_EVENT_AUDIO_DEVICE_ADDED, &Added }, { SDL_EVENT_AUDIO_DEVICE_REMOVED, &Removed }, { SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED, &FormatChanged } }) { } // clang-format on }; class PenEvents : public EventTypeRouter { public: EventConduit ProximityIn, ProximityOut, Down, Up, Motion; // clang-format off 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 } }) { } // clang-format on }; class CameraDeviceEvents : public EventTypeRouter { public: EventConduit Added, Removed, Approved, Denied; // clang-format off 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} }) { } // clang-format on }; class RenderEvents : public EventTypeRouter { public: EventConduit TargetsReset, DeviceReset, DeviceLost; // clang-format off RenderEvents() : EventTypeRouter({ { SDL_EVENT_RENDER_TARGETS_RESET, &TargetsReset }, { SDL_EVENT_RENDER_DEVICE_RESET, &DeviceReset }, { SDL_EVENT_RENDER_DEVICE_LOST, &DeviceLost } }) { } // clang-format on }; class KeyboardEvents : public EventTypeRouter { public: EventConduit Added, Removed; // clang-format off KeyboardEvents() : EventTypeRouter({ { SDL_EVENT_KEYBOARD_ADDED, &Added }, { SDL_EVENT_KEYBOARD_REMOVED, &Removed } }) { } // clang-format on }; class MouseButtonEvents : public EventTypeRouter { public: EventConduit Down, Up; // clang-format off MouseButtonEvents() : EventTypeRouter({ { SDL_EVENT_MOUSE_BUTTON_DOWN, &Down }, { SDL_EVENT_MOUSE_BUTTON_UP, &Up } }) { } // clang-format on }; class MouseButtonsEvents : public EventValueRouter { public: MouseButtonsEvents() : EventValueRouter({}) { } virtual Uint8 extractor(SDL_Event* event) override { return event->button.button; } }; class MouseEvents : public EventTypeRouter { public: MouseButtonsEvents Button; EventConduit Motion, Wheel, Added, Removed; // clang-format off 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 } }) { } // clang-format on }; class MiceEvents : public EventValueRouter { public: MiceEvents() : EventValueRouter({}) { } virtual SDL_MouseID extractor(SDL_Event* event) 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; // clang-format off TextEvents() : EventTypeRouter({ { SDL_EVENT_TEXT_INPUT, &Input }, { SDL_EVENT_TEXT_EDITING, &Editing }, { SDL_EVENT_TEXT_EDITING_CANDIDATES, &EditingCandidates } }) { } // clang-format on }; 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; // clang-format off 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 } }) { } // clang-format on }; class WindowsEvents : public EventValueRouter { public: std::map 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) 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; // clang-format off 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} }) { }; // clang-format on // 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) 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