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