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