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:
262
263 [[nodiscard]] unsigned getButton() const { return button; }
264
265protected:
266 explicit OsdControlEvent(unsigned button_)
267 : button(button_) {}
268
269private:
270 unsigned button;
271};
272
274{
275public:
276 explicit OsdControlReleaseEvent(unsigned button_)
277 : OsdControlEvent(button_) {}
278};
279
281{
282public:
283 explicit OsdControlPressEvent(unsigned button_)
284 : OsdControlEvent(button_) {}
285};
286
287
288class GroupEvent final : public EventBase
289{
290public:
291 GroupEvent(std::initializer_list<EventType> typesToMatch_, TclObject tclListComponents_)
292 : typesToMatch(typesToMatch_)
293 , tclListComponents(std::move(tclListComponents_)) {}
294
295 [[nodiscard]] const auto& getTypesToMatch() const { return typesToMatch; }
296 [[nodiscard]] const auto& getTclListComponents() const { return tclListComponents; }
297
298private:
299 static_vector<EventType, 3> typesToMatch;
300 TclObject tclListComponents;
301};
302
314class FinishFrameEvent final : public EventBase
315{
316public:
317 FinishFrameEvent(int thisSource_, int selectedSource_,
318 bool skipped_)
319 : thisSource(thisSource_), selectedSource(selectedSource_)
320 , skipped(skipped_)
321 {
322 }
323
324 [[nodiscard]] int getSource() const { return thisSource; }
325 [[nodiscard]] int getSelectedSource() const { return selectedSource; }
326 [[nodiscard]] bool isSkipped() const { return skipped; }
327 [[nodiscard]] bool needRender() const { return !skipped && (thisSource == selectedSource); }
328
329private:
330 int thisSource;
331 int selectedSource;
332 bool skipped;
333};
334
336class CliCommandEvent final : public EventBase
337{
338public:
339 CliCommandEvent(std::string_view command_, const CliConnection* id_)
340 : command(allocate_c_string(command_)), id(id_) {}
341 CliCommandEvent(const CliCommandEvent&) { assert(false); }
342 CliCommandEvent& operator=(const CliCommandEvent&) { assert(false); return *this; }
345 ~CliCommandEvent() = default;
346
347 [[nodiscard]] zstring_view getCommand() const { return command.get(); }
348 [[nodiscard]] const CliConnection* getId() const { return id; }
349
350private:
351 StringStorage command;
352 const CliConnection* id;
353};
354
355class ImGuiActiveEvent final : public EventBase
356{
357public:
358 explicit ImGuiActiveEvent(bool active_)
359 : active(active_) {}
360 [[nodiscard]] bool getActive() const { return active; }
361
362private:
363 bool active;
364};
365
366
367// Events that don't need additional data
368class SimpleEvent : public EventBase {};
369
371class BootEvent final : public SimpleEvent {};
372
377class FrameDrawnEvent final : public SimpleEvent {};
378
379class BreakEvent final : public SimpleEvent {};
380class SwitchRendererEvent final : public SimpleEvent {};
381
383class TakeReverseSnapshotEvent final : public SimpleEvent {};
384
386class AfterTimedEvent final : public SimpleEvent {};
387
389class MachineLoadedEvent final : public SimpleEvent {};
390
393class MachineActivatedEvent final : public SimpleEvent {};
394class MachineDeactivatedEvent final : public SimpleEvent {};
395
396class MidiInReaderEvent final : public SimpleEvent {};
397class MidiInWindowsEvent final : public SimpleEvent {};
398class MidiInCoreMidiEvent final : public SimpleEvent {};
400class MidiInALSAEvent final : public SimpleEvent {};
401class Rs232TesterEvent final : public SimpleEvent {};
402class Rs232NetEvent final : public SimpleEvent {};
403class ImGuiDelayedActionEvent final : public SimpleEvent {};
404
405
406// --- Put all (non-abstract) Event classes into a std::variant ---
407
408using Event = std::variant<
422 TextEvent,
424 QuitEvent,
428 BootEvent,
446>;
447
448template<typename T>
449inline constexpr uint8_t event_index = get_index<T, Event>::value;
450
451
452// --- Define an enum for all concrete event types. ---
453// Use the numeric value from the corresponding index in the Event.
454enum class EventType : uint8_t
455{
456 KEY_UP = event_index<KeyUpEvent>,
457 KEY_DOWN = event_index<KeyDownEvent>,
458 MOUSE_MOTION = event_index<MouseMotionEvent>,
459 MOUSE_BUTTON_UP = event_index<MouseButtonUpEvent>,
460 MOUSE_BUTTON_DOWN = event_index<MouseButtonDownEvent>,
461 MOUSE_WHEEL = event_index<MouseWheelEvent>,
462 JOY_AXIS_MOTION = event_index<JoystickAxisMotionEvent>,
463 JOY_HAT = event_index<JoystickHatEvent>,
464 JOY_BUTTON_UP = event_index<JoystickButtonUpEvent>,
465 JOY_BUTTON_DOWN = event_index<JoystickButtonDownEvent>,
466 OSD_CONTROL_RELEASE = event_index<OsdControlReleaseEvent>,
467 OSD_CONTROL_PRESS = event_index<OsdControlPressEvent>,
468 WINDOW = event_index<WindowEvent>,
469 TEXT = event_index<TextEvent>,
470 FILE_DROP = event_index<FileDropEvent>,
471 QUIT = event_index<QuitEvent>,
472 GROUP = event_index<GroupEvent>,
473 BOOT = event_index<BootEvent>,
474 FINISH_FRAME = event_index<FinishFrameEvent>,
475 FRAME_DRAWN = event_index<FrameDrawnEvent>,
476 BREAK = event_index<BreakEvent>,
477 SWITCH_RENDERER = event_index<SwitchRendererEvent>,
478 TAKE_REVERSE_SNAPSHOT = event_index<TakeReverseSnapshotEvent>,
479 CLICOMMAND = event_index<CliCommandEvent>,
480 AFTER_TIMED = event_index<AfterTimedEvent>,
481 MACHINE_LOADED = event_index<MachineLoadedEvent>,
482 MACHINE_ACTIVATED = event_index<MachineActivatedEvent>,
483 MACHINE_DEACTIVATED = event_index<MachineDeactivatedEvent>,
484 MIDI_IN_READER = event_index<MidiInReaderEvent>,
485 MIDI_IN_WINDOWS = event_index<MidiInWindowsEvent>,
486 MIDI_IN_COREMIDI = event_index<MidiInCoreMidiEvent>,
487 MIDI_IN_COREMIDI_VIRTUAL = event_index<MidiInCoreMidiVirtualEvent>,
488 MIDI_IN_ALSA = event_index<MidiInALSAEvent>,
489 RS232_TESTER = event_index<Rs232TesterEvent>,
490 RS232_NET = event_index<Rs232NetEvent>,
491 IMGUI_DELAYED_ACTION = event_index<ImGuiDelayedActionEvent>,
492 IMGUI_ACTIVE = event_index<ImGuiActiveEvent>,
493
494 NUM_EVENT_TYPES // must be last
495};
496
497
498// --- Event class, free functions ---
499
500[[nodiscard]] EventType getType(const Event& event);
501
503[[nodiscard]] std::string toString(const Event& event);
504
506[[nodiscard]] TclObject toTclList(const Event& event);
507
508[[nodiscard]] bool operator==(const Event& x, const Event& y);
509
513[[nodiscard]] bool matches(const Event& self, const Event& other);
514
515
516// --- Event class implementation, free functions ---
517
518inline EventType getType(const Event& event)
519{
520 return EventType(event.index());
521}
522
523// Similar to std::get() and std::get_if()
524template<typename T>
525struct GetIfEventHelper { // standard std::get_if() behavior
526 const T* operator()(const Event& event) {
527 return std::get_if<T>(&event);
528 }
529};
530template<>
531struct GetIfEventHelper<SdlEvent> { // extension for base-classes
532 [[nodiscard]] const SdlEvent* operator()(const Event& event) const {
533 const auto& var = event;
534 switch (EventType(var.index())) {
535 using enum EventType;
536 case KEY_UP: return &std::get<KeyUpEvent>(var);
537 case KEY_DOWN: return &std::get<KeyDownEvent>(var);
538 case MOUSE_BUTTON_UP: return &std::get<MouseButtonUpEvent>(var);
539 case MOUSE_BUTTON_DOWN: return &std::get<MouseButtonDownEvent>(var);
540 case MOUSE_WHEEL: return &std::get<MouseWheelEvent>(var);
541 case MOUSE_MOTION: return &std::get<MouseMotionEvent>(var);
542 case JOY_BUTTON_UP: return &std::get<JoystickButtonUpEvent>(var);
543 case JOY_BUTTON_DOWN: return &std::get<JoystickButtonDownEvent>(var);
544 case JOY_AXIS_MOTION: return &std::get<JoystickAxisMotionEvent>(var);
545 case JOY_HAT: return &std::get<JoystickHatEvent>(var);
546 case WINDOW: return &std::get<WindowEvent>(var);
547 case TEXT: return &std::get<TextEvent>(var);
548 default: return nullptr;
549 }
550 }
551};
552template<>
554 [[nodiscard]] const KeyEvent* operator()(const Event& event) const {
555 const auto& var = event;
556 switch (EventType(var.index())) {
557 using enum EventType;
558 case KEY_UP: return &std::get<KeyUpEvent>(var);
559 case KEY_DOWN: return &std::get<KeyDownEvent>(var);
560 default: return nullptr;
561 }
562 }
563};
564template<>
566 [[nodiscard]] const JoystickEvent* operator()(const Event& event) const {
567 const auto& var = event;
568 switch (EventType(var.index())) {
569 using enum EventType;
570 case JOY_BUTTON_UP: return &std::get<JoystickButtonUpEvent>(var);
571 case JOY_BUTTON_DOWN: return &std::get<JoystickButtonDownEvent>(var);
572 case JOY_AXIS_MOTION: return &std::get<JoystickAxisMotionEvent>(var);
573 case JOY_HAT: return &std::get<JoystickHatEvent>(var);
574 default: return nullptr;
575 }
576 }
577};
578template<typename T>
579const T* get_event_if(const Event& event)
580{
581 GetIfEventHelper<T> helper;
582 return helper(event);
583}
584template<typename T>
585const T& get_event(const Event& event)
586{
587 const T* t = get_event_if<T>(event);
588 assert(t);
589 return *t;
590}
591
592} // namespace openmsx
593
594#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:386
Sent when the MSX resets or powers up.
Definition Event.hh:371
Command received on CliComm connection.
Definition Event.hh:337
CliCommandEvent & operator=(CliCommandEvent &&)=default
const CliConnection * getId() const
Definition Event.hh:348
CliCommandEvent(CliCommandEvent &&)=default
zstring_view getCommand() const
Definition Event.hh:347
CliCommandEvent(const CliCommandEvent &)
Definition Event.hh:341
CliCommandEvent(std::string_view command_, const CliConnection *id_)
Definition Event.hh:339
CliCommandEvent & operator=(const CliCommandEvent &)
Definition Event.hh:342
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:315
FinishFrameEvent(int thisSource_, int selectedSource_, bool skipped_)
Definition Event.hh:317
int getSource() const
Definition Event.hh:324
bool isSkipped() const
Definition Event.hh:326
int getSelectedSource() const
Definition Event.hh:325
bool needRender() const
Definition Event.hh:327
Sent when a FINISH_FRAME caused a redraw of the screen.
Definition Event.hh:377
GroupEvent(std::initializer_list< EventType > typesToMatch_, TclObject tclListComponents_)
Definition Event.hh:291
const auto & getTypesToMatch() const
Definition Event.hh:295
const auto & getTclListComponents() const
Definition Event.hh:296
bool getActive() const
Definition Event.hh:360
ImGuiActiveEvent(bool active_)
Definition Event.hh:358
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:393
Send when a (new) machine configuration is loaded.
Definition Event.hh:389
auto getButton() const
Definition Event.hh:114
OSD events are triggered by other events.
Definition Event.hh:258
OsdControlEvent(unsigned button_)
Definition Event.hh:266
unsigned getButton() const
Definition Event.hh:263
OsdControlPressEvent(unsigned button_)
Definition Event.hh:283
OsdControlReleaseEvent(unsigned button_)
Definition Event.hh:276
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:383
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:449
EventType
Definition Event.hh:455
const T * get_event_if(const Event &event)
Definition Event.hh:579
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:518
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:446
const T & get_event(const Event &event)
Definition Event.hh:585
STL namespace.
const JoystickEvent * operator()(const Event &event) const
Definition Event.hh:566
const KeyEvent * operator()(const Event &event) const
Definition Event.hh:554
const SdlEvent * operator()(const Event &event) const
Definition Event.hh:532
const T * operator()(const Event &event)
Definition Event.hh:526