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 ~FileDropEvent() = default;
242
243 [[nodiscard]] zstring_view getFileName() const { return fileName.get(); }
244
245private:
246 StringStorage fileName;
247};
248
249
250class QuitEvent final : public EventBase {};
251
252
258{
259public:
260 enum class Button {LEFT, RIGHT, UP, DOWN, A, B,
261 NUM};
262 [[nodiscard]] Button getButton() const { return button; }
263
264protected:
265 explicit OsdControlEvent(Button button_)
266 : button(button_) {}
267
268private:
269 Button button;
270};
271
273{
274public:
276 : OsdControlEvent(button_) {}
277};
278
280{
281public:
282 explicit OsdControlPressEvent(Button 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 ~CliCommandEvent() = default;
345
346 [[nodiscard]] zstring_view getCommand() const { return command.get(); }
347 [[nodiscard]] const CliConnection* getId() const { return id; }
348
349private:
350 StringStorage command;
351 const CliConnection* id;
352};
353
354class ImGuiActiveEvent final : public EventBase
355{
356public:
357 explicit ImGuiActiveEvent(bool active_)
358 : active(active_) {}
359 [[nodiscard]] bool getActive() const { return active; }
360
361private:
362 bool active;
363};
364
365
366// Events that don't need additional data
367class SimpleEvent : public EventBase {};
368
370class BootEvent final : public SimpleEvent {};
371
376class FrameDrawnEvent final : public SimpleEvent {};
377
378class BreakEvent final : public SimpleEvent {};
379class SwitchRendererEvent final : public SimpleEvent {};
380
382class TakeReverseSnapshotEvent final : public SimpleEvent {};
383
385class AfterTimedEvent final : public SimpleEvent {};
386
388class MachineLoadedEvent final : public SimpleEvent {};
389
392class MachineActivatedEvent final : public SimpleEvent {};
393class MachineDeactivatedEvent final : public SimpleEvent {};
394
395class MidiInReaderEvent final : public SimpleEvent {};
396class MidiInWindowsEvent final : public SimpleEvent {};
397class MidiInCoreMidiEvent final : public SimpleEvent {};
399class MidiInALSAEvent final : public SimpleEvent {};
400class Rs232TesterEvent final : public SimpleEvent {};
401class Rs232NetEvent final : public SimpleEvent {};
402class ImGuiDelayedActionEvent final : public SimpleEvent {};
403
404
405// --- Put all (non-abstract) Event classes into a std::variant ---
406
407using Event = std::variant<
421 TextEvent,
423 QuitEvent,
427 BootEvent,
445>;
446
447template<typename T>
448inline constexpr uint8_t event_index = get_index<T, Event>::value;
449
450
451// --- Define an enum for all concrete event types. ---
452// Use the numeric value from the corresponding index in the Event.
453enum class EventType : uint8_t
454{
455 KEY_UP = event_index<KeyUpEvent>,
456 KEY_DOWN = event_index<KeyDownEvent>,
457 MOUSE_MOTION = event_index<MouseMotionEvent>,
458 MOUSE_BUTTON_UP = event_index<MouseButtonUpEvent>,
459 MOUSE_BUTTON_DOWN = event_index<MouseButtonDownEvent>,
460 MOUSE_WHEEL = event_index<MouseWheelEvent>,
461 JOY_AXIS_MOTION = event_index<JoystickAxisMotionEvent>,
462 JOY_HAT = event_index<JoystickHatEvent>,
463 JOY_BUTTON_UP = event_index<JoystickButtonUpEvent>,
464 JOY_BUTTON_DOWN = event_index<JoystickButtonDownEvent>,
465 OSD_CONTROL_RELEASE = event_index<OsdControlReleaseEvent>,
466 OSD_CONTROL_PRESS = event_index<OsdControlPressEvent>,
467 WINDOW = event_index<WindowEvent>,
468 TEXT = event_index<TextEvent>,
469 FILE_DROP = event_index<FileDropEvent>,
470 QUIT = event_index<QuitEvent>,
471 GROUP = event_index<GroupEvent>,
472 BOOT = event_index<BootEvent>,
473 FINISH_FRAME = event_index<FinishFrameEvent>,
474 FRAME_DRAWN = event_index<FrameDrawnEvent>,
475 BREAK = event_index<BreakEvent>,
476 SWITCH_RENDERER = event_index<SwitchRendererEvent>,
477 TAKE_REVERSE_SNAPSHOT = event_index<TakeReverseSnapshotEvent>,
478 CLICOMMAND = event_index<CliCommandEvent>,
479 AFTER_TIMED = event_index<AfterTimedEvent>,
480 MACHINE_LOADED = event_index<MachineLoadedEvent>,
481 MACHINE_ACTIVATED = event_index<MachineActivatedEvent>,
482 MACHINE_DEACTIVATED = event_index<MachineDeactivatedEvent>,
483 MIDI_IN_READER = event_index<MidiInReaderEvent>,
484 MIDI_IN_WINDOWS = event_index<MidiInWindowsEvent>,
485 MIDI_IN_COREMIDI = event_index<MidiInCoreMidiEvent>,
486 MIDI_IN_COREMIDI_VIRTUAL = event_index<MidiInCoreMidiVirtualEvent>,
487 MIDI_IN_ALSA = event_index<MidiInALSAEvent>,
488 RS232_TESTER = event_index<Rs232TesterEvent>,
489 RS232_NET = event_index<Rs232NetEvent>,
490 IMGUI_DELAYED_ACTION = event_index<ImGuiDelayedActionEvent>,
491 IMGUI_ACTIVE = event_index<ImGuiActiveEvent>,
492
493 NUM_EVENT_TYPES // must be last
494};
495
496
497// --- Event class, free functions ---
498
499[[nodiscard]] EventType getType(const Event& event);
500
502[[nodiscard]] std::string toString(const Event& event);
503
505[[nodiscard]] TclObject toTclList(const Event& event);
506
507[[nodiscard]] bool operator==(const Event& x, const Event& y);
508
512[[nodiscard]] bool matches(const Event& self, const Event& other);
513
514
515// --- Event class implementation, free functions ---
516
517inline EventType getType(const Event& event)
518{
519 return EventType(event.index());
520}
521
522// Similar to std::get() and std::get_if()
523template<typename T>
524struct GetIfEventHelper { // standard std::get_if() behavior
525 const T* operator()(const Event& event) {
526 return std::get_if<T>(&event);
527 }
528};
529template<>
530struct GetIfEventHelper<SdlEvent> { // extension for base-classes
531 [[nodiscard]] const SdlEvent* operator()(const Event& event) const {
532 const auto& var = event;
533 switch (EventType(var.index())) {
534 using enum EventType;
535 case KEY_UP: return &std::get<KeyUpEvent>(var);
536 case KEY_DOWN: return &std::get<KeyDownEvent>(var);
537 case MOUSE_BUTTON_UP: return &std::get<MouseButtonUpEvent>(var);
538 case MOUSE_BUTTON_DOWN: return &std::get<MouseButtonDownEvent>(var);
539 case MOUSE_WHEEL: return &std::get<MouseWheelEvent>(var);
540 case MOUSE_MOTION: return &std::get<MouseMotionEvent>(var);
541 case JOY_BUTTON_UP: return &std::get<JoystickButtonUpEvent>(var);
542 case JOY_BUTTON_DOWN: return &std::get<JoystickButtonDownEvent>(var);
543 case JOY_AXIS_MOTION: return &std::get<JoystickAxisMotionEvent>(var);
544 case JOY_HAT: return &std::get<JoystickHatEvent>(var);
545 case WINDOW: return &std::get<WindowEvent>(var);
546 case TEXT: return &std::get<TextEvent>(var);
547 default: return nullptr;
548 }
549 }
550};
551template<>
553 [[nodiscard]] const KeyEvent* operator()(const Event& event) const {
554 const auto& var = event;
555 switch (EventType(var.index())) {
556 using enum EventType;
557 case KEY_UP: return &std::get<KeyUpEvent>(var);
558 case KEY_DOWN: return &std::get<KeyDownEvent>(var);
559 default: return nullptr;
560 }
561 }
562};
563template<>
565 [[nodiscard]] const JoystickEvent* operator()(const Event& event) const {
566 const auto& var = event;
567 switch (EventType(var.index())) {
568 using enum EventType;
569 case JOY_BUTTON_UP: return &std::get<JoystickButtonUpEvent>(var);
570 case JOY_BUTTON_DOWN: return &std::get<JoystickButtonDownEvent>(var);
571 case JOY_AXIS_MOTION: return &std::get<JoystickAxisMotionEvent>(var);
572 case JOY_HAT: return &std::get<JoystickHatEvent>(var);
573 default: return nullptr;
574 }
575 }
576};
577template<typename T>
578const T* get_event_if(const Event& event)
579{
580 GetIfEventHelper<T> helper;
581 return helper(event);
582}
583template<typename T>
584const T& get_event(const Event& event)
585{
586 const T* t = get_event_if<T>(event);
587 assert(t);
588 return *t;
589}
590
591} // namespace openmsx
592
593#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:385
Sent when the MSX resets or powers up.
Definition Event.hh:370
Command received on CliComm connection.
Definition Event.hh:336
CliCommandEvent & operator=(CliCommandEvent &&)=default
const CliConnection * getId() const
Definition Event.hh:347
CliCommandEvent(CliCommandEvent &&)=default
zstring_view getCommand() const
Definition Event.hh:346
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:243
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:376
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:359
ImGuiActiveEvent(bool active_)
Definition Event.hh:357
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:392
Send when a (new) machine configuration is loaded.
Definition Event.hh:388
auto getButton() const
Definition Event.hh:114
OSD events are triggered by other events.
Definition Event.hh:258
Button getButton() const
Definition Event.hh:262
OsdControlEvent(Button button_)
Definition Event.hh:265
OsdControlPressEvent(Button button_)
Definition Event.hh:282
OsdControlReleaseEvent(Button 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:382
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:448
EventType
Definition Event.hh:454
const T * get_event_if(const Event &event)
Definition Event.hh:578
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:211
TclObject toTclList(const Event &event)
Similar to toString(), but retains the structure of the event.
Definition Event.cc:102
EventType getType(const Event &event)
Definition Event.hh:517
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:445
const T & get_event(const Event &event)
Definition Event.hh:584
STL namespace.
const JoystickEvent * operator()(const Event &event) const
Definition Event.hh:565
const KeyEvent * operator()(const Event &event) const
Definition Event.hh:553
const SdlEvent * operator()(const Event &event) const
Definition Event.hh:531
const T * operator()(const Event &event)
Definition Event.hh:525