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