openMSX
Event.hh
Go to the documentation of this file.
1#ifndef EVENT_HH
2#define EVENT_HH
3
4#include "JoystickId.hh"
5#include "SDLKey.hh"
6#include "StringStorage.hh"
7#include "TclObject.hh"
8
9#include "static_vector.hh"
10#include "stl.hh"
11
12#include <cassert>
13#include <cstdint>
14#include <string>
15#include <utility>
16#include <variant>
17
18#include <SDL.h>
19
20namespace openmsx {
21
22class CliConnection;
23enum class EventType : uint8_t;
24
25// --- The actual event classes (the Event class refers to one of these) ---
26
27class EventBase {};
28
29class SdlEvent : public EventBase
30{
31public:
32 explicit SdlEvent(const SDL_Event& e) : evt(e) {}
33 [[nodiscard]] const SDL_Event& getSdlEvent() const { return evt; }
34 [[nodiscard]] const SDL_CommonEvent& getCommonSdlEvent() const { return evt.common; }
35
36protected:
37 SDL_Event evt;
38};
39
40
41class KeyEvent : public SdlEvent
42{
43public:
45
46 [[nodiscard]] bool getRepeat() const { return evt.key.repeat; }
47 [[nodiscard]] SDL_Keycode getKeyCode() const { return evt.key.keysym.sym; }
48 [[nodiscard]] SDL_Scancode getScanCode() const { return evt.key.keysym.scancode; }
49 [[nodiscard]] uint16_t getModifiers() const { return evt.key.keysym.mod; }
50 [[nodiscard]] uint32_t getUnicode() const {
51 // HACK: repurposed 'unused' field as 'unicode' field
52 return evt.key.keysym.unused;
53 }
54 [[nodiscard]] SDLKey getKey() const { return SDLKey{evt.key.keysym, evt.type == SDL_KEYDOWN}; }
55};
56
57class KeyUpEvent final : public KeyEvent
58{
59public:
60 using KeyEvent::KeyEvent;
61
62 [[nodiscard]] static KeyUpEvent create(SDL_Keycode code, SDL_Keymod mod = KMOD_NONE) {
63 SDL_Event evt;
64 evt.key = SDL_KeyboardEvent{};
65 auto& e = evt.key;
66
67 e.type = SDL_KEYUP;
68 e.timestamp = SDL_GetTicks();
69 e.state = SDL_RELEASED;
70 e.keysym.sym = code;
71 e.keysym.mod = mod;
72 return KeyUpEvent(evt);
73 }
74};
75
76class KeyDownEvent final : public KeyEvent
77{
78public:
79 using KeyEvent::KeyEvent;
80
81 [[nodiscard]] static KeyDownEvent create(SDL_Keycode code, SDL_Keymod mod = KMOD_NONE) {
82 SDL_Event evt;
83 evt.key = SDL_KeyboardEvent{};
84 auto& e = evt.key;
85
86 e.type = SDL_KEYDOWN;
87 e.timestamp = SDL_GetTicks();
88 e.state = SDL_PRESSED;
89 e.keysym.sym = code;
90 e.keysym.mod = mod;
91 return KeyDownEvent(evt);
92 }
93 [[nodiscard]] static KeyDownEvent create(uint32_t timestamp, unsigned unicode) {
94 SDL_Event evt;
95 evt.key = SDL_KeyboardEvent{};
96 auto& e = evt.key;
97
98 e.type = SDL_KEYDOWN;
99 e.timestamp = timestamp;
100 e.state = SDL_PRESSED;
101 e.keysym.sym = SDLK_UNKNOWN;
102 e.keysym.mod = KMOD_NONE;
103 e.keysym.unused = unicode;
104 return KeyDownEvent(evt);
105 }
106};
107
108
110{
111public:
112 using SdlEvent::SdlEvent;
113
114 [[nodiscard]] auto getButton() const { return evt.button.button; }
115};
116
118{
119public:
120 using MouseButtonEvent::MouseButtonEvent;
121};
122
124{
125public:
126 using MouseButtonEvent::MouseButtonEvent;
127};
128
129class MouseWheelEvent final : public SdlEvent
130{
131public:
132 using SdlEvent::SdlEvent;
133
134 [[nodiscard]] int getX() const { return normalize(evt.wheel.x); }
135 [[nodiscard]] int getY() const { return normalize(evt.wheel.y); }
136
137private:
138 [[nodiscard]] int normalize(int x) const {
139 return evt.wheel.direction == SDL_MOUSEWHEEL_FLIPPED ? -x : x;
140 }
141};
142
143class MouseMotionEvent final : public SdlEvent
144{
145public:
146 using SdlEvent::SdlEvent;
147
148 [[nodiscard]] int getX() const { return evt.motion.xrel; }
149 [[nodiscard]] int getY() const { return evt.motion.yrel; }
150 [[nodiscard]] int getAbsX() const { return evt.motion.x; }
151 [[nodiscard]] int getAbsY() const { return evt.motion.y; }
152};
153
154
156{
157public:
158 using SdlEvent::SdlEvent;
159
160 [[nodiscard]] JoystickId getJoystick() const {
161 // SDL joystick instance ID has already been translated to an openMSX JoystickID
162 return JoystickId(evt.jbutton.which);
163 }
164};
165
167{
168public:
169 using JoystickEvent::JoystickEvent;
170
171 [[nodiscard]] unsigned getButton() const { return evt.jbutton.button; }
172};
173
175{
176public:
177 using JoystickButtonEvent::JoystickButtonEvent;
178};
179
181{
182public:
183 using JoystickButtonEvent::JoystickButtonEvent;
184};
185
187{
188public:
189 static constexpr uint8_t X_AXIS = 0;
190 static constexpr uint8_t Y_AXIS = 1;
191
192 using JoystickEvent::JoystickEvent;
193
194 [[nodiscard]] uint8_t getAxis() const { return evt.jaxis.axis; }
195 [[nodiscard]] int16_t getValue() const { return evt.jaxis.value; }
196};
197
198class JoystickHatEvent final : public JoystickEvent
199{
200public:
201 using JoystickEvent::JoystickEvent;
202
203 [[nodiscard]] uint8_t getHat() const { return evt.jhat.hat; }
204 [[nodiscard]] uint8_t getValue() const { return evt.jhat.value; }
205};
206
207
208class WindowEvent : public SdlEvent
209{
210public:
211 using SdlEvent::SdlEvent;
212
213 [[nodiscard]] const SDL_WindowEvent& getSdlWindowEvent() const { return evt.window; }
214 [[nodiscard]] bool isMainWindow() const { return isMainWindow(evt.window.windowID); }
215
216public:
217 static void setMainWindowId(uint32_t id) { mainWindowId = id; }
218 static uint32_t getMainWindowId() { return mainWindowId; }
219 [[nodiscard]] static bool isMainWindow(unsigned id) { return id == mainWindowId; }
220private:
221 static inline uint32_t mainWindowId = unsigned(-1);
222};
223
224
225class TextEvent : public SdlEvent
226{
227public:
228 using SdlEvent::SdlEvent;
229};
230
231
232class FileDropEvent final : public EventBase
233{
234public:
235 explicit FileDropEvent(std::string_view fileName_)
236 : fileName(allocate_c_string(fileName_)) {}
237 FileDropEvent(const FileDropEvent&) { assert(false); }
238 FileDropEvent& operator=(const FileDropEvent&) { assert(false); return *this; }
241
242 [[nodiscard]] zstring_view getFileName() const { return fileName.get(); }
243
244private:
245 StringStorage fileName;
246};
247
248
249class QuitEvent final : public EventBase {};
250
251
257{
258public:
261
262 [[nodiscard]] unsigned getButton() const { return button; }
263
264protected:
265 explicit OsdControlEvent(unsigned button_)
266 : button(button_) {}
267
268private:
269 unsigned button;
270};
271
273{
274public:
275 explicit OsdControlReleaseEvent(unsigned button_)
276 : OsdControlEvent(button_) {}
277};
278
280{
281public:
282 explicit OsdControlPressEvent(unsigned button_)
283 : OsdControlEvent(button_) {}
284};
285
286
287class GroupEvent final : public EventBase
288{
289public:
290 GroupEvent(std::initializer_list<EventType> typesToMatch_, TclObject tclListComponents_)
291 : typesToMatch(typesToMatch_)
292 , tclListComponents(std::move(tclListComponents_)) {}
293
294 [[nodiscard]] const auto& getTypesToMatch() const { return typesToMatch; }
295 [[nodiscard]] const auto& getTclListComponents() const { return tclListComponents; }
296
297private:
298 static_vector<EventType, 3> typesToMatch;
299 TclObject tclListComponents;
300};
301
313class FinishFrameEvent final : public EventBase
314{
315public:
316 FinishFrameEvent(int thisSource_, int selectedSource_,
317 bool skipped_)
318 : thisSource(thisSource_), selectedSource(selectedSource_)
319 , skipped(skipped_)
320 {
321 }
322
323 [[nodiscard]] int getSource() const { return thisSource; }
324 [[nodiscard]] int getSelectedSource() const { return selectedSource; }
325 [[nodiscard]] bool isSkipped() const { return skipped; }
326 [[nodiscard]] bool needRender() const { return !skipped && (thisSource == selectedSource); }
327
328private:
329 int thisSource;
330 int selectedSource;
331 bool skipped;
332};
333
335class CliCommandEvent final : public EventBase
336{
337public:
338 CliCommandEvent(std::string_view command_, const CliConnection* id_)
339 : command(allocate_c_string(command_)), id(id_) {}
340 CliCommandEvent(const CliCommandEvent&) { assert(false); }
341 CliCommandEvent& operator=(const CliCommandEvent&) { assert(false); return *this; }
344
345 [[nodiscard]] zstring_view getCommand() const { return command.get(); }
346 [[nodiscard]] const CliConnection* getId() const { return id; }
347
348private:
349 StringStorage command;
350 const CliConnection* id;
351};
352
353class ImGuiActiveEvent final : public EventBase
354{
355public:
356 explicit ImGuiActiveEvent(bool active_)
357 : active(active_) {}
358 [[nodiscard]] bool getActive() const { return active; }
359
360private:
361 bool active;
362};
363
364
365// Events that don't need additional data
366class SimpleEvent : public EventBase {};
367
369class BootEvent final : public SimpleEvent {};
370
375class FrameDrawnEvent final : public SimpleEvent {};
376
377class BreakEvent final : public SimpleEvent {};
378class SwitchRendererEvent final : public SimpleEvent {};
379
381class TakeReverseSnapshotEvent final : public SimpleEvent {};
382
384class AfterTimedEvent final : public SimpleEvent {};
385
387class MachineLoadedEvent final : public SimpleEvent {};
388
391class MachineActivatedEvent final : public SimpleEvent {};
392class MachineDeactivatedEvent final : public SimpleEvent {};
393
394class MidiInReaderEvent final : public SimpleEvent {};
395class MidiInWindowsEvent final : public SimpleEvent {};
396class MidiInCoreMidiEvent final : public SimpleEvent {};
398class MidiInALSAEvent final : public SimpleEvent {};
399class Rs232TesterEvent final : public SimpleEvent {};
400class Rs232NetEvent final : public SimpleEvent {};
401class ImGuiDelayedActionEvent final : public SimpleEvent {};
402
403
404// --- Put all (non-abstract) Event classes into a std::variant ---
405
406using Event = std::variant<
420 TextEvent,
422 QuitEvent,
426 BootEvent,
444>;
445
446template<typename T>
447inline constexpr uint8_t event_index = get_index<T, Event>::value;
448
449
450// --- Define an enum for all concrete event types. ---
451// Use the numeric value from the corresponding index in the Event.
452enum class EventType : uint8_t
453{
454 KEY_UP = event_index<KeyUpEvent>,
455 KEY_DOWN = event_index<KeyDownEvent>,
456 MOUSE_MOTION = event_index<MouseMotionEvent>,
457 MOUSE_BUTTON_UP = event_index<MouseButtonUpEvent>,
458 MOUSE_BUTTON_DOWN = event_index<MouseButtonDownEvent>,
459 MOUSE_WHEEL = event_index<MouseWheelEvent>,
460 JOY_AXIS_MOTION = event_index<JoystickAxisMotionEvent>,
461 JOY_HAT = event_index<JoystickHatEvent>,
462 JOY_BUTTON_UP = event_index<JoystickButtonUpEvent>,
463 JOY_BUTTON_DOWN = event_index<JoystickButtonDownEvent>,
464 OSD_CONTROL_RELEASE = event_index<OsdControlReleaseEvent>,
465 OSD_CONTROL_PRESS = event_index<OsdControlPressEvent>,
466 WINDOW = event_index<WindowEvent>,
467 TEXT = event_index<TextEvent>,
468 FILE_DROP = event_index<FileDropEvent>,
469 QUIT = event_index<QuitEvent>,
470 GROUP = event_index<GroupEvent>,
471 BOOT = event_index<BootEvent>,
472 FINISH_FRAME = event_index<FinishFrameEvent>,
473 FRAME_DRAWN = event_index<FrameDrawnEvent>,
474 BREAK = event_index<BreakEvent>,
475 SWITCH_RENDERER = event_index<SwitchRendererEvent>,
476 TAKE_REVERSE_SNAPSHOT = event_index<TakeReverseSnapshotEvent>,
477 CLICOMMAND = event_index<CliCommandEvent>,
478 AFTER_TIMED = event_index<AfterTimedEvent>,
479 MACHINE_LOADED = event_index<MachineLoadedEvent>,
480 MACHINE_ACTIVATED = event_index<MachineActivatedEvent>,
481 MACHINE_DEACTIVATED = event_index<MachineDeactivatedEvent>,
482 MIDI_IN_READER = event_index<MidiInReaderEvent>,
483 MIDI_IN_WINDOWS = event_index<MidiInWindowsEvent>,
484 MIDI_IN_COREMIDI = event_index<MidiInCoreMidiEvent>,
485 MIDI_IN_COREMIDI_VIRTUAL = event_index<MidiInCoreMidiVirtualEvent>,
486 MIDI_IN_ALSA = event_index<MidiInALSAEvent>,
487 RS232_TESTER = event_index<Rs232TesterEvent>,
488 RS232_NET = event_index<Rs232NetEvent>,
489 IMGUI_DELAYED_ACTION = event_index<ImGuiDelayedActionEvent>,
490 IMGUI_ACTIVE = event_index<ImGuiActiveEvent>,
491
492 NUM_EVENT_TYPES // must be last
493};
494
495
496// --- Event class, free functions ---
497
498[[nodiscard]] EventType getType(const Event& event);
499
501[[nodiscard]] std::string toString(const Event& event);
502
504[[nodiscard]] TclObject toTclList(const Event& event);
505
506[[nodiscard]] bool operator==(const Event& x, const Event& y);
507
511[[nodiscard]] bool matches(const Event& self, const Event& other);
512
513
514// --- Event class implementation, free functions ---
515
516inline EventType getType(const Event& event)
517{
518 return EventType(event.index());
519}
520
521// Similar to std::get() and std::get_if()
522template<typename T>
523struct GetIfEventHelper { // standard std::get_if() behavior
524 const T* operator()(const Event& event) {
525 return std::get_if<T>(&event);
526 }
527};
528template<>
529struct GetIfEventHelper<SdlEvent> { // extension for base-classes
530 [[nodiscard]] const SdlEvent* operator()(const Event& event) const {
531 const auto& var = event;
532 switch (EventType(var.index())) {
533 case EventType::KEY_UP: return &std::get<KeyUpEvent>(var);
534 case EventType::KEY_DOWN: return &std::get<KeyDownEvent>(var);
535 case EventType::MOUSE_BUTTON_UP: return &std::get<MouseButtonUpEvent>(var);
536 case EventType::MOUSE_BUTTON_DOWN: return &std::get<MouseButtonDownEvent>(var);
537 case EventType::MOUSE_WHEEL: return &std::get<MouseWheelEvent>(var);
538 case EventType::MOUSE_MOTION: return &std::get<MouseMotionEvent>(var);
539 case EventType::JOY_BUTTON_UP: return &std::get<JoystickButtonUpEvent>(var);
540 case EventType::JOY_BUTTON_DOWN: return &std::get<JoystickButtonDownEvent>(var);
541 case EventType::JOY_AXIS_MOTION: return &std::get<JoystickAxisMotionEvent>(var);
542 case EventType::JOY_HAT: return &std::get<JoystickHatEvent>(var);
543 case EventType::WINDOW: return &std::get<WindowEvent>(var);
544 case EventType::TEXT: return &std::get<TextEvent>(var);
545 default: return nullptr;
546 }
547 }
548};
549template<>
551 [[nodiscard]] const KeyEvent* operator()(const Event& event) const {
552 const auto& var = event;
553 switch (EventType(var.index())) {
554 case EventType::KEY_UP: return &std::get<KeyUpEvent>(var);
555 case EventType::KEY_DOWN: return &std::get<KeyDownEvent>(var);
556 default: return nullptr;
557 }
558 }
559};
560template<>
562 [[nodiscard]] const JoystickEvent* operator()(const Event& event) const {
563 const auto& var = event;
564 switch (EventType(var.index())) {
565 case EventType::JOY_BUTTON_UP: return &std::get<JoystickButtonUpEvent>(var);
566 case EventType::JOY_BUTTON_DOWN: return &std::get<JoystickButtonDownEvent>(var);
567 case EventType::JOY_AXIS_MOTION: return &std::get<JoystickAxisMotionEvent>(var);
568 case EventType::JOY_HAT: return &std::get<JoystickHatEvent>(var);
569 default: return nullptr;
570 }
571 }
572};
573template<typename T>
574const T* get_event_if(const Event& event)
575{
576 GetIfEventHelper<T> helper;
577 return helper(event);
578}
579template<typename T>
580const T& get_event(const Event& event)
581{
582 const T* t = get_event_if<T>(event);
583 assert(t);
584 return *t;
585}
586
587} // namespace openmsx
588
589#endif
uintptr_t id
std::unique_ptr< char, FreeStringStorage > StringStorage
StringStorage allocate_c_string(std::string_view s)
Allocate memory for and copy a c-string (zero-terminated string).
TclObject t
Send when an after-EmuTime command should be executed.
Definition Event.hh:384
Sent when the MSX resets or powers up.
Definition Event.hh:369
Command received on CliComm connection.
Definition Event.hh:336
CliCommandEvent & operator=(CliCommandEvent &&)=default
const CliConnection * getId() const
Definition Event.hh:346
CliCommandEvent(CliCommandEvent &&)=default
zstring_view getCommand() const
Definition Event.hh:345
CliCommandEvent(const CliCommandEvent &)
Definition Event.hh:340
CliCommandEvent(std::string_view command_, const CliConnection *id_)
Definition Event.hh:338
CliCommandEvent & operator=(const CliCommandEvent &)
Definition Event.hh:341
FileDropEvent(std::string_view fileName_)
Definition Event.hh:235
FileDropEvent & operator=(const FileDropEvent &)
Definition Event.hh:238
zstring_view getFileName() const
Definition Event.hh:242
FileDropEvent(const FileDropEvent &)
Definition Event.hh:237
FileDropEvent & operator=(FileDropEvent &&)=default
FileDropEvent(FileDropEvent &&)=default
This event is send when a device (v99x8, v9990, video9000, laserdisc) reaches the end of a frame.
Definition Event.hh:314
FinishFrameEvent(int thisSource_, int selectedSource_, bool skipped_)
Definition Event.hh:316
int getSource() const
Definition Event.hh:323
bool isSkipped() const
Definition Event.hh:325
int getSelectedSource() const
Definition Event.hh:324
bool needRender() const
Definition Event.hh:326
Sent when a FINISH_FRAME caused a redraw of the screen.
Definition Event.hh:375
GroupEvent(std::initializer_list< EventType > typesToMatch_, TclObject tclListComponents_)
Definition Event.hh:290
const auto & getTypesToMatch() const
Definition Event.hh:294
const auto & getTclListComponents() const
Definition Event.hh:295
bool getActive() const
Definition Event.hh:358
ImGuiActiveEvent(bool active_)
Definition Event.hh:356
static constexpr uint8_t X_AXIS
Definition Event.hh:189
static constexpr uint8_t Y_AXIS
Definition Event.hh:190
unsigned getButton() const
Definition Event.hh:171
JoystickId getJoystick() const
Definition Event.hh:160
uint8_t getValue() const
Definition Event.hh:204
uint8_t getHat() const
Definition Event.hh:203
static KeyDownEvent create(SDL_Keycode code, SDL_Keymod mod=KMOD_NONE)
Definition Event.hh:81
static KeyDownEvent create(uint32_t timestamp, unsigned unicode)
Definition Event.hh:93
bool getRepeat() const
Definition Event.hh:46
SDL_Keycode getKeyCode() const
Definition Event.hh:47
uint32_t getUnicode() const
Definition Event.hh:50
SDL_Scancode getScanCode() const
Definition Event.hh:48
uint16_t getModifiers() const
Definition Event.hh:49
SDLKey getKey() const
Definition Event.hh:54
static KeyUpEvent create(SDL_Keycode code, SDL_Keymod mod=KMOD_NONE)
Definition Event.hh:62
Send when a machine is (de)activated.
Definition Event.hh:391
Send when a (new) machine configuration is loaded.
Definition Event.hh:387
auto getButton() const
Definition Event.hh:114
OSD events are triggered by other events.
Definition Event.hh:257
OsdControlEvent(unsigned button_)
Definition Event.hh:265
unsigned getButton() const
Definition Event.hh:262
OsdControlPressEvent(unsigned button_)
Definition Event.hh:282
OsdControlReleaseEvent(unsigned button_)
Definition Event.hh:275
const SDL_CommonEvent & getCommonSdlEvent() const
Definition Event.hh:34
SdlEvent(const SDL_Event &e)
Definition Event.hh:32
SDL_Event evt
Definition Event.hh:37
const SDL_Event & getSdlEvent() const
Definition Event.hh:33
Used to schedule 'taking reverse snapshots' between Z80 instructions.
Definition Event.hh:381
static uint32_t getMainWindowId()
Definition Event.hh:218
bool isMainWindow() const
Definition Event.hh:214
const SDL_WindowEvent & getSdlWindowEvent() const
Definition Event.hh:213
static void setMainWindowId(uint32_t id)
Definition Event.hh:217
static bool isMainWindow(unsigned id)
Definition Event.hh:219
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
This file implemented 3 utility functions:
Definition Autofire.cc:11
constexpr uint8_t event_index
Definition Event.hh:447
EventType
Definition Event.hh:453
const T * get_event_if(const Event &event)
Definition Event.hh:574
bool operator==(const BooleanInput &x, const BooleanInput &y)
bool matches(const Event &self, const Event &other)
Does this event 'match' the given event.
Definition Event.cc:210
TclObject toTclList(const Event &event)
Similar to toString(), but retains the structure of the event.
Definition Event.cc:101
EventType getType(const Event &event)
Definition Event.hh:516
std::string toString(const BooleanInput &input)
std::variant< KeyUpEvent, KeyDownEvent, MouseMotionEvent, MouseButtonUpEvent, MouseButtonDownEvent, MouseWheelEvent, JoystickAxisMotionEvent, JoystickHatEvent, JoystickButtonUpEvent, JoystickButtonDownEvent, OsdControlReleaseEvent, OsdControlPressEvent, WindowEvent, TextEvent, FileDropEvent, QuitEvent, FinishFrameEvent, CliCommandEvent, GroupEvent, BootEvent, FrameDrawnEvent, BreakEvent, SwitchRendererEvent, TakeReverseSnapshotEvent, AfterTimedEvent, MachineLoadedEvent, MachineActivatedEvent, MachineDeactivatedEvent, MidiInReaderEvent, MidiInWindowsEvent, MidiInCoreMidiEvent, MidiInCoreMidiVirtualEvent, MidiInALSAEvent, Rs232TesterEvent, Rs232NetEvent, ImGuiDelayedActionEvent, ImGuiActiveEvent > Event
Definition Event.hh:444
const T & get_event(const Event &event)
Definition Event.hh:580
STL namespace.
const JoystickEvent * operator()(const Event &event) const
Definition Event.hh:562
const KeyEvent * operator()(const Event &event) const
Definition Event.hh:551
const SdlEvent * operator()(const Event &event) const
Definition Event.hh:530
const T * operator()(const Event &event)
Definition Event.hh:524