openMSX
Event.cc
Go to the documentation of this file.
1#include "Event.hh"
2#include "stl.hh"
3#include "strCat.hh"
4
5#include <tuple>
6#include <SDL.h>
7
8using namespace std::literals;
9
10namespace openmsx {
11
12[[nodiscard]] static constexpr uint16_t normalizeKeyMod(uint16_t m)
13{
14 // when either left or right modifier is pressed, add the other one as well
15 if (m & KMOD_SHIFT) m |= KMOD_SHIFT;
16 if (m & KMOD_CTRL) m |= KMOD_CTRL;
17 if (m & KMOD_ALT) m |= KMOD_ALT;
18 if (m & KMOD_GUI) m |= KMOD_GUI;
19 // ignore stuff like: KMOD_NUM, KMOD_CAPS, KMOD_SCROLL
20 m &= (KMOD_SHIFT | KMOD_CTRL | KMOD_ALT | KMOD_GUI | KMOD_MODE);
21 return m;
22}
23
24bool operator==(const Event& x, const Event& y)
25{
26 return std::visit(overloaded{
27 [](const KeyUpEvent& a, const KeyUpEvent& b) {
28 // note: don't compare scancode, unicode
29 return std::tuple(a.getKeyCode(), normalizeKeyMod(a.getModifiers())) ==
30 std::tuple(b.getKeyCode(), normalizeKeyMod(b.getModifiers()));
31 },
32 [](const KeyDownEvent& a, const KeyDownEvent& b) {
33 // note: don't compare scancode, unicode
34 return std::tuple(a.getKeyCode(), normalizeKeyMod(a.getModifiers())) ==
35 std::tuple(b.getKeyCode(), normalizeKeyMod(b.getModifiers()));
36 },
37 [](const MouseMotionEvent& a, const MouseMotionEvent& b) {
38 return std::tuple(a.getX(), a.getY(), a.getAbsX(), a.getAbsY()) ==
39 std::tuple(b.getX(), b.getY(), b.getAbsX(), b.getAbsY());
40 },
41 [](const MouseButtonUpEvent& a, const MouseButtonUpEvent& b) {
42 return a.getButton() == b.getButton();
43 },
44 [](const MouseButtonDownEvent& a, const MouseButtonDownEvent& b) {
45 return a.getButton() == b.getButton();
46 },
47 [](const MouseWheelEvent& a, const MouseWheelEvent& b) {
48 return std::tuple(a.getX(), a.getY()) ==
49 std::tuple(b.getX(), b.getY());
50 },
52 return std::tuple(a.getJoystick(), a.getAxis(), a.getValue()) ==
53 std::tuple(b.getJoystick(), b.getAxis(), b.getValue());
54 },
55 [](const JoystickHatEvent& a, const JoystickHatEvent& b) {
56 return std::tuple(a.getJoystick(), a.getHat(), a.getValue()) ==
57 std::tuple(b.getJoystick(), b.getHat(), b.getValue());
58 },
59 [](const JoystickButtonUpEvent& a, const JoystickButtonUpEvent& b) {
60 return std::tuple(a.getJoystick(), a.getButton()) ==
61 std::tuple(b.getJoystick(), b.getButton());
62 },
64 return std::tuple(a.getJoystick(), a.getButton()) ==
65 std::tuple(b.getJoystick(), b.getButton());
66 },
67 [](const OsdControlReleaseEvent& a, const OsdControlReleaseEvent& b) {
68 return a.getButton() == b.getButton();
69 },
70 [](const OsdControlPressEvent& a, const OsdControlPressEvent& b) {
71 return a.getButton() == b.getButton();
72 },
73 [](const WindowEvent& a_, const WindowEvent& b_) {
74 const auto& a = a_.getSdlWindowEvent();
75 const auto& b = b_.getSdlWindowEvent();
76 // don't compare timestamp
77 if (a.event != b.event) return false;
78 if (a.windowID != b.windowID) return false;
79 // TODO for specific events, compare data1 and data2
80 return true;
81 },
82 [](const FileDropEvent& a, const FileDropEvent& b) {
83 return a.getFileName() == b.getFileName();
84 },
85 [](const FinishFrameEvent& a, const FinishFrameEvent& b) {
86 return std::tuple(a.getSource(), a.getSelectedSource(), a.isSkipped()) ==
87 std::tuple(b.getSource(), b.getSelectedSource(), b.isSkipped());
88 },
89 [](const CliCommandEvent& a, const CliCommandEvent& b) {
90 return a.getCommand() == b.getCommand();
91 },
92 [](const GroupEvent& a, const GroupEvent& b) {
93 return a.getTclListComponents() ==
94 b.getTclListComponents();
95 },
96 [&](const EventBase& /*a*/, const EventBase& /*b*/) {
97 return getType(x) == getType(y);
98 }
99 }, x, y);
100}
101
103{
105 "LEFT"sv, "RIGHT"sv, "UP"sv, "DOWN"sv, "A"sv, "B"sv
106 };
107
108 return std::visit(overloaded{
109 [](const KeyEvent& e) {
110 // Note: 'scanCode' is not included (also not in operator==()).
111 //
112 // At the moment 'scanCode' is only used in the MSX Keyboard code when
113 // the POSITIONAL mapping mode is active. It is not used for key
114 // bindings (the 'bind' or the 'after' commands) or for the openMSX
115 // console. KeyEvents also don't end up in 'reverse replay' files
116 // (instead those files contain more low level MSX keyboard matrix
117 // changes).
118 //
119 // Within these constraints it's fine to ignore 'scanCode' in this
120 // method.
121 auto result = makeTclList("keyb", e.getKey().toString());
122 if (e.getUnicode() != 0) {
123 result.addListElement(tmpStrCat("unicode", e.getUnicode()));
124 }
125 return result;
126 },
127 [](const MouseMotionEvent& e) {
128 return makeTclList("mouse", "motion", e.getX(), e.getY(), e.getAbsX(), e.getAbsY());
129 },
130 [](const MouseButtonUpEvent& e) {
131 return makeTclList("mouse", tmpStrCat("button", e.getButton()), "up");
132 },
133 [](const MouseButtonDownEvent& e) {
134 return makeTclList("mouse", tmpStrCat("button", e.getButton()), "down");
135 },
136 [](const MouseWheelEvent& e) {
137 return makeTclList("mouse", "wheel", e.getX(), e.getY());
138 },
139 [](const JoystickAxisMotionEvent& e) {
140 return makeTclList(e.getJoystick().str(), tmpStrCat("axis", e.getAxis()), e.getValue());
141 },
142 [](const JoystickHatEvent& e) {
143 const char* str = [&] {
144 switch (e.getValue()) {
145 case SDL_HAT_UP: return "up";
146 case SDL_HAT_RIGHT: return "right";
147 case SDL_HAT_DOWN: return "down";
148 case SDL_HAT_LEFT: return "left";
149 case SDL_HAT_RIGHTUP: return "rightup";
150 case SDL_HAT_RIGHTDOWN: return "rightdown";
151 case SDL_HAT_LEFTUP: return "leftup";
152 case SDL_HAT_LEFTDOWN: return "leftdown";
153 default: return "center";
154 }
155 }();
156 return makeTclList(e.getJoystick().str(), tmpStrCat("hat", e.getHat()), str);
157 },
158 [](const JoystickButtonUpEvent& e) {
159 return makeTclList(e.getJoystick().str(), tmpStrCat("button", e.getButton()), "up");
160 },
161 [](const JoystickButtonDownEvent& e) {
162 return makeTclList(e.getJoystick().str(), tmpStrCat("button", e.getButton()), "down");
163 },
164 [](const OsdControlReleaseEvent& e) {
165 return makeTclList("OSDcontrol", osdControlNames[e.getButton()], "RELEASE");
166 },
167 [](const OsdControlPressEvent& e) {
168 return makeTclList("OSDcontrol", osdControlNames[e.getButton()], "PRESS");
169 },
170 [](const WindowEvent& e_) {
171 const auto& e = e_.getSdlWindowEvent();
172 if (e.event == SDL_WINDOWEVENT_FOCUS_GAINED) {
173 return makeTclList("focus", true);
174 } else if (e.event == SDL_WINDOWEVENT_FOCUS_LOST) {
175 return makeTclList("focus", false);
176 }
177 return makeTclList(); // other events don't need a textual representation (yet)
178 },
179 [](const TextEvent&) {
180 return makeTclList(); // doesn't need a textual representation (yet)
181 },
182 [](const FileDropEvent& e) {
183 return makeTclList("filedrop", e.getFileName());
184 },
185 [](const QuitEvent& /*e*/) {
186 return makeTclList("quit");
187 },
188 [](const FinishFrameEvent& e) {
189 return makeTclList("finishframe", int(e.getSource()), int(e.getSelectedSource()), e.isSkipped());
190 },
191 [](const CliCommandEvent& e) {
192 return makeTclList("CliCmd", e.getCommand());
193 },
194 [](const GroupEvent& e) {
195 return e.getTclListComponents();
196 },
197 [&](const SimpleEvent& /*e*/) {
198 return makeTclList("simple", int(getType(event)));
199 },
200 [](const ImGuiActiveEvent& e) {
201 return makeTclList("imgui", e.getActive());
202 }
203 }, event);
204}
205
206std::string toString(const Event& event)
207{
208 return std::string(toTclList(event).getString());
209}
210
211bool matches(const Event& self, const Event& other)
212{
213 return std::visit(overloaded{
214 [&](const GroupEvent& e) {
215 return contains(e.getTypesToMatch(), getType(other));
216 },
217 [&](const EventBase&) {
218 return self == other;
219 }
220 }, self);
221}
222
223} // namespace openmsx
Command received on CliComm connection.
Definition Event.hh:336
This event is send when a device (v99x8, v9990, video9000, laserdisc) reaches the end of a frame.
Definition Event.hh:314
SDL_Keycode getKeyCode() const
Definition Event.hh:47
uint16_t getModifiers() const
Definition Event.hh:49
const SDL_WindowEvent & getSdlWindowEvent() const
Definition Event.hh:213
This file implemented 3 utility functions:
Definition Autofire.cc:11
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
TclObject makeTclList(Args &&... args)
Definition TclObject.hh:293
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition stl.hh:35
TemporaryString tmpStrCat(Ts &&... ts)
Definition strCat.hh:742