openMSX
InputEventFactory.cc
Go to the documentation of this file.
2#include "Event.hh"
3#include "CommandException.hh"
4#include "Keys.hh"
5#include "StringOp.hh"
6#include "TclObject.hh"
7#include "one_of.hh"
8#include <SDL.h>
9
11
12[[nodiscard]] static Event parseKeyEvent(std::string_view str, uint32_t unicode)
13{
14 auto keyCode = Keys::getCode(str);
15 if (keyCode == Keys::K_NONE) {
16 throw CommandException("Invalid keycode: ", str);
17 }
18 if (keyCode & Keys::KD_RELEASE) {
19 return Event::create<KeyUpEvent>(keyCode);
20 } else {
21 return Event::create<KeyDownEvent>(keyCode, unicode);
22 }
23}
24
25[[nodiscard]] static Event parseKeyEvent(const TclObject& str, Interpreter& interp)
26{
27 auto len = str.getListLength(interp);
28 if (len == 1) {
29 return Event::create<GroupEvent>(
30 std::initializer_list<EventType>{EventType::KEY_UP, EventType::KEY_DOWN},
31 makeTclList("keyb"));
32 } else if (len == 2) {
33 auto comp1 = str.getListIndex(interp, 1).getString();
34 return parseKeyEvent(comp1, 0);
35 } else if (len == 3) {
36 auto comp1 = str.getListIndex(interp, 1).getString();
37 auto comp2 = str.getListIndex(interp, 2).getString();
38 if (comp2.starts_with("unicode")) {
39 if (auto u = StringOp::stringToBase<10, unsigned>(comp2.substr(7))) {
40 return parseKeyEvent(comp1, *u);
41 }
42 }
43 }
44 throw CommandException("Invalid keyboard event: ", str.getString());
45}
46
47[[nodiscard]] static bool upDown(std::string_view str)
48{
49 if (str == "up") {
50 return true;
51 } else if (str == "down") {
52 return false;
53 }
54 throw CommandException(
55 "Invalid direction (expected 'up' or 'down'): ", str);
56}
57
58[[nodiscard]] static Event parseMouseEvent(const TclObject& str, Interpreter& interp)
59{
60 auto len = str.getListLength(interp);
61 if (len >= 2) {
62 auto comp1 = str.getListIndex(interp, 1).getString();
63 if (comp1 == "motion") {
64 if (len == 2) {
65 return Event::create<GroupEvent>(
66 std::initializer_list<EventType>{EventType::MOUSE_MOTION},
67 makeTclList("mouse", comp1));
68 } else if (len == one_of(4u, 6u)) {
69 int absX = 0, absY = 0;
70 if (len == 6) {
71 absX = str.getListIndex(interp, 4).getInt(interp);
72 absY = str.getListIndex(interp, 5).getInt(interp);
73 } else {
74 // for bw-compat also allow events without absX,absY
75 }
76 return Event::create<MouseMotionEvent>(
77 str.getListIndex(interp, 2).getInt(interp),
78 str.getListIndex(interp, 3).getInt(interp),
79 absX, absY);
80 }
81 } else if (comp1.starts_with("button")) {
82 if (len == 2) {
83 return Event::create<GroupEvent>(
84 std::initializer_list<EventType>{EventType::MOUSE_BUTTON_UP, EventType::MOUSE_BUTTON_DOWN},
85 makeTclList("mouse", "button"));
86 } else if (len == 3) {
87 if (auto button = StringOp::stringToBase<10, unsigned>(comp1.substr(6))) {
88 if (upDown(str.getListIndex(interp, 2).getString())) {
89 return Event::create<MouseButtonUpEvent> (*button);
90 } else {
91 return Event::create<MouseButtonDownEvent>(*button);
92 }
93 }
94 }
95 } else if (comp1 == "wheel") {
96 if (len == 2) {
97 return Event::create<GroupEvent>(
98 std::initializer_list<EventType>{EventType::MOUSE_WHEEL},
99 makeTclList("mouse", comp1));
100 } else if (len == 4) {
101 return Event::create<MouseWheelEvent>(
102 str.getListIndex(interp, 2).getInt(interp),
103 str.getListIndex(interp, 3).getInt(interp));
104 }
105 }
106 }
107 throw CommandException("Invalid mouse event: ", str.getString());
108}
109
110[[nodiscard]] static Event parseOsdControlEvent(const TclObject& str, Interpreter& interp)
111{
112 if (str.getListLength(interp) == 3) {
113 auto buttonName = str.getListIndex(interp, 1).getString();
114 unsigned button = [&] {
115 if (buttonName == "LEFT") {
117 } else if (buttonName == "RIGHT") {
119 } else if (buttonName == "UP") {
121 } else if (buttonName == "DOWN") {
123 } else if (buttonName == "A") {
125 } else if (buttonName == "B") {
127 } else {
128 throw CommandException(
129 "Invalid OSDcontrol event, invalid button name: ",
130 buttonName);
131 }
132 }();
133 auto buttonAction = str.getListIndex(interp, 2).getString();
134 if (buttonAction == "RELEASE") {
135 return Event::create<OsdControlReleaseEvent>(button, Event{});
136 } else if (buttonAction == "PRESS") {
137 return Event::create<OsdControlPressEvent> (button, Event{});
138 }
139 }
140 throw CommandException("Invalid OSDcontrol event: ", str.getString());
141}
142
143[[nodiscard]] static Event parseJoystickEvent(const TclObject& str, Interpreter& interp)
144{
145 auto len = str.getListLength(interp);
146 if (len >= 2) {
147 auto comp0 = str.getListIndex(interp, 0).getString(); // joyN
148 auto comp1 = str.getListIndex(interp, 1).getString();
149
150 if (len == 2) {
151 if (comp1.starts_with("button")) {
152 return Event::create<GroupEvent>(
153 std::initializer_list<EventType>{EventType::JOY_BUTTON_UP, EventType::JOY_BUTTON_DOWN},
154 makeTclList("joy", "button"));
155 } else if (comp1.starts_with("axis")) {
156 return Event::create<GroupEvent>(
157 std::initializer_list<EventType>{EventType::JOY_AXIS_MOTION},
158 makeTclList("joy", "axis"));
159 } else if (comp1.starts_with("hat")) {
160 return Event::create<GroupEvent>(
161 std::initializer_list<EventType>{EventType::JOY_HAT},
162 makeTclList("joy", "hat"));
163 }
164 } else if (len == 3) {
165 auto comp2 = str.getListIndex(interp, 2);
166 if (auto j = StringOp::stringToBase<10, unsigned>(comp0.substr(3))) {
167 unsigned joystick = *j - 1;
168 if (comp1.starts_with("button")) {
169 if (auto button = StringOp::stringToBase<10, unsigned>(comp1.substr(6))) {
170 if (upDown(comp2.getString())) {
171 return Event::create<JoystickButtonUpEvent> (joystick, *button);
172 } else {
173 return Event::create<JoystickButtonDownEvent>(joystick, *button);
174 }
175 }
176 } else if (comp1.starts_with("axis")) {
177 if (auto axis = StringOp::stringToBase<10, unsigned>(comp1.substr(4))) {
178 int value = str.getListIndex(interp, 2).getInt(interp);
179 return Event::create<JoystickAxisMotionEvent>(joystick, *axis, value);
180 }
181 } else if (comp1.starts_with("hat")) {
182 if (auto hat = StringOp::stringToBase<10, unsigned>(comp1.substr(3))) {
183 auto valueStr = str.getListIndex(interp, 2).getString();
184 int value = [&] {
185 if (valueStr == "up") return SDL_HAT_UP;
186 else if (valueStr == "right") return SDL_HAT_RIGHT;
187 else if (valueStr == "down") return SDL_HAT_DOWN;
188 else if (valueStr == "left") return SDL_HAT_LEFT;
189 else if (valueStr == "rightup") return SDL_HAT_RIGHTUP;
190 else if (valueStr == "rightdown") return SDL_HAT_RIGHTDOWN;
191 else if (valueStr == "leftup") return SDL_HAT_LEFTUP;
192 else if (valueStr == "leftdown") return SDL_HAT_LEFTDOWN;
193 else if (valueStr == "center") return SDL_HAT_CENTERED;
194 else {
195 throw CommandException("Invalid hat value: ", valueStr);
196 }
197 }();
198 return Event::create<JoystickHatEvent>(joystick, *hat, value);
199 }
200 }
201 }
202 }
203 }
204 throw CommandException("Invalid joystick event: ", str.getString());
205}
206
207[[nodiscard]] static Event parseFocusEvent(const TclObject& str, Interpreter& interp)
208{
209 if (str.getListLength(interp) != 2) {
210 throw CommandException("Invalid focus event: ", str.getString());
211 }
212 return Event::create<FocusEvent>(str.getListIndex(interp, 1).getBoolean(interp));
213}
214
215[[nodiscard]] static Event parseFileDropEvent(const TclObject& str, Interpreter& interp)
216{
217 if (str.getListLength(interp) != 1) {
218 throw CommandException("Invalid filedrop event: ", str.getString());
219 }
220 return Event::create<GroupEvent>(
221 std::initializer_list<EventType>{EventType::FILE_DROP},
222 makeTclList("filename"));
223}
224
225[[nodiscard]] static Event parseResizeEvent(const TclObject& str, Interpreter& interp)
226{
227 if (str.getListLength(interp) != 3) {
228 throw CommandException("Invalid resize event: ", str.getString());
229 }
230 return Event::create<ResizeEvent>(
231 str.getListIndex(interp, 1).getInt(interp),
232 str.getListIndex(interp, 2).getInt(interp));
233}
234
235[[nodiscard]] static Event parseQuitEvent(const TclObject& str, Interpreter& interp)
236{
237 if (str.getListLength(interp) != 1) {
238 throw CommandException("Invalid quit event: ", str.getString());
239 }
240 return Event::create<QuitEvent>();
241}
242
244{
245 if (str.getListLength(interp) == 0) {
246 throw CommandException("Invalid event: ", str.getString());
247 }
248 auto type = str.getListIndex(interp, 0).getString();
249 if (type == "keyb") {
250 return parseKeyEvent(str, interp);
251 } else if (type == "mouse") {
252 return parseMouseEvent(str, interp);
253 } else if (type.starts_with("joy")) {
254 return parseJoystickEvent(str, interp);
255 } else if (type == "focus") {
256 return parseFocusEvent(str, interp);
257 } else if (type == "filedrop") {
258 return parseFileDropEvent(str, interp);
259 } else if (type == "resize") {
260 return parseResizeEvent(str, interp);
261 } else if (type == "quit") {
262 return parseQuitEvent(str, interp);
263 } else if (type == "command") {
264 return Event::create<KeyUpEvent>(Keys::K_UNKNOWN); // dummy event, for bw compat
265 //return parseCommandEvent(str);
266 } else if (type == "OSDcontrol") {
267 return parseOsdControlEvent(str, interp);
268 } else {
269 // fall back
270 return parseKeyEvent(type, 0);
271 }
272}
273Event createInputEvent(std::string_view str, Interpreter& interp)
274{
275 return createInputEvent(TclObject(str), interp);
276}
277
278} // namespace openmsx::InputEventFactory
Definition: one_of.hh:7
unsigned getListLength(Interpreter &interp) const
Definition: TclObject.cc:134
TclObject getListIndex(Interpreter &interp, unsigned index) const
Definition: TclObject.cc:152
zstring_view getString() const
Definition: TclObject.cc:120
Event createInputEvent(const TclObject &str, Interpreter &interp)
@ KD_RELEASE
Definition: Keys.hh:212
@ K_UNKNOWN
Definition: Keys.hh:30
KeyCode getCode(string_view name)
Translate key name to key code.
Definition: Keys.cc:330
TclObject makeTclList(Args &&... args)
Definition: TclObject.hh:283