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