openMSX
Event.cc
Go to the documentation of this file.
1 #include "Event.hh"
2 #include "stl.hh"
3 #include "strCat.hh"
4 #include <tuple>
5 #include <SDL.h>
6 
7 using namespace std::literals;
8 
9 namespace openmsx {
10 
11 bool operator==(const Event& x, const Event& y)
12 {
13  return visit(overloaded{
14  [](const KeyUpEvent& a, const KeyUpEvent& b) {
15  // note: don't compare scancode, unicode
16  return a.getKeyCode() == b.getKeyCode();
17  },
18  [](const KeyDownEvent& a, const KeyDownEvent& b) {
19  // note: don't compare scancode, unicode
20  return a.getKeyCode() == b.getKeyCode();
21  },
22  [](const MouseMotionEvent& a, const MouseMotionEvent& b) {
23  return std::tuple(a.getX(), a.getY(), a.getAbsX(), a.getAbsY()) ==
24  std::tuple(b.getX(), b.getY(), b.getAbsX(), b.getAbsY());
25  },
26  [](const MouseButtonUpEvent& a, const MouseButtonUpEvent& b) {
27  return a.getButton() == b.getButton();
28  },
29  [](const MouseButtonDownEvent& a, const MouseButtonDownEvent& b) {
30  return a.getButton() == b.getButton();
31  },
32  [](const MouseWheelEvent& a, const MouseWheelEvent& b) {
33  return std::tuple(a.getX(), a.getY()) ==
34  std::tuple(b.getX(), b.getY());
35  },
36  [](const JoystickAxisMotionEvent& a, const JoystickAxisMotionEvent& b) {
37  return std::tuple(a.getJoystick(), a.getAxis(), a.getValue()) ==
38  std::tuple(b.getJoystick(), b.getAxis(), b.getValue());
39  },
40  [](const JoystickHatEvent& a, const JoystickHatEvent& b) {
41  return std::tuple(a.getJoystick(), a.getHat(), a.getValue()) ==
42  std::tuple(b.getJoystick(), b.getHat(), b.getValue());
43  },
44  [](const JoystickButtonUpEvent& a, const JoystickButtonUpEvent& b) {
45  return std::tuple(a.getJoystick(), a.getButton()) ==
46  std::tuple(b.getJoystick(), b.getButton());
47  },
48  [](const JoystickButtonDownEvent& a, const JoystickButtonDownEvent& b) {
49  return std::tuple(a.getJoystick(), a.getButton()) ==
50  std::tuple(b.getJoystick(), b.getButton());
51  },
52  [](const OsdControlReleaseEvent& a, const OsdControlReleaseEvent& b) {
53  return a.getButton() == b.getButton();
54  },
55  [](const OsdControlPressEvent& a, const OsdControlPressEvent& b) {
56  return a.getButton() == b.getButton();
57  },
58  [](const FocusEvent& a, const FocusEvent& b) {
59  return a.getGain() == b.getGain();
60  },
61  [](const ResizeEvent& a, const ResizeEvent& b) {
62  return std::tuple(a.getX(), a.getY()) ==
63  std::tuple(b.getX(), b.getY());
64  },
65  [](const FileDropEvent& a, const FileDropEvent& b) {
66  return a.getFileName() == b.getFileName();
67  },
68  [](const FinishFrameEvent& a, const FinishFrameEvent& b) {
69  return std::tuple(a.getSource(), a.getSelectedSource(), a.isSkipped()) ==
70  std::tuple(b.getSource(), b.getSelectedSource(), b.isSkipped());
71  },
72  [](const CliCommandEvent& a, const CliCommandEvent& b) {
73  return a.getCommand() == b.getCommand();
74  },
75  [](const GroupEvent& a, const GroupEvent& b) {
76  return a.getTclListComponents() ==
77  b.getTclListComponents();
78  },
79  [&](const EventBase& /*a*/, const EventBase& /*b*/) {
80  return getType(x) == getType(y);
81  }
82  }, x, y);
83 }
84 
85 TclObject toTclList(const Event& event)
86 {
87  static constexpr std::array osdControlNames = {
88  "LEFT"sv, "RIGHT"sv, "UP"sv, "DOWN"sv, "A"sv, "B"sv
89  };
90 
91  return visit(overloaded{
92  [](const KeyEvent& e) {
93  // Note: 'scanCode' is not included (also not in operator==()).
94  //
95  // At the moment 'scanCode' is only used in the MSX Keyboard code when
96  // the POSITIONAL mapping mode is active. It is not used for key
97  // bindings (the 'bind' or the 'after' commands) or for the openMSX
98  // console. KeyEvents also don't end up in 'reverse replay' files
99  // (instead those files contain more low level MSX keyboard matrix
100  // changes).
101  //
102  // Within these constraints it's fine to ignore 'scanCode' in this
103  // method.
104  auto result = makeTclList("keyb", Keys::getName(e.getKeyCode()));
105  if (e.getUnicode() != 0) {
106  result.addListElement(tmpStrCat("unicode", e.getUnicode()));
107  }
108  return result;
109  },
110  [](const MouseMotionEvent& e) {
111  return makeTclList("mouse", "motion", e.getX(), e.getY(), e.getAbsX(), e.getAbsY());
112  },
113  [](const MouseButtonUpEvent& e) {
114  return makeTclList("mouse", tmpStrCat("button", e.getButton()), "up");
115  },
116  [](const MouseButtonDownEvent& e) {
117  return makeTclList("mouse", tmpStrCat("button", e.getButton()), "down");
118  },
119  [](const MouseWheelEvent& e) {
120  return makeTclList("mouse", "wheel", e.getX(), e.getY());
121  },
122  [](const JoystickAxisMotionEvent& e) {
123  return makeTclList(tmpStrCat("joy", e.getJoystick() + 1), tmpStrCat("axis", e.getAxis()), e.getValue());
124  },
125  [](const JoystickHatEvent& e) {
126  const char* str = [&] {
127  switch (e.getValue()) {
128  case SDL_HAT_UP: return "up";
129  case SDL_HAT_RIGHT: return "right";
130  case SDL_HAT_DOWN: return "down";
131  case SDL_HAT_LEFT: return "left";
132  case SDL_HAT_RIGHTUP: return "rightup";
133  case SDL_HAT_RIGHTDOWN: return "rightdown";
134  case SDL_HAT_LEFTUP: return "leftup";
135  case SDL_HAT_LEFTDOWN: return "leftdown";
136  default: return "center";
137  }
138  }();
139  return makeTclList(tmpStrCat("joy", e.getJoystick() + 1), tmpStrCat("hat", e.getHat()), str);
140  },
141  [](const JoystickButtonUpEvent& e) {
142  return makeTclList(tmpStrCat("joy", e.getJoystick() + 1), tmpStrCat("button", e.getButton()), "up");
143  },
144  [](const JoystickButtonDownEvent& e) {
145  return makeTclList(tmpStrCat("joy", e.getJoystick() + 1), tmpStrCat("button", e.getButton()), "down");
146  },
147  [](const OsdControlReleaseEvent& e) {
148  return makeTclList("OSDcontrol", osdControlNames[e.getButton()], "RELEASE");
149  },
150  [](const OsdControlPressEvent& e) {
151  return makeTclList("OSDcontrol", osdControlNames[e.getButton()], "PRESS");
152  },
153  [](const FocusEvent& e) {
154  return makeTclList("focus", e.getGain());
155  },
156  [](const ResizeEvent& e) {
157  return makeTclList("resize", int(e.getX()), int(e.getY()));
158  },
159  [](const FileDropEvent& e) {
160  return makeTclList("filedrop", e.getFileName());
161  },
162  [](const QuitEvent& /*e*/) {
163  return makeTclList("quit");
164  },
165  [](const FinishFrameEvent& e) {
166  return makeTclList("finishframe", int(e.getSource()), int(e.getSelectedSource()), e.isSkipped());
167  },
168  [](const CliCommandEvent& e) {
169  return makeTclList("CliCmd", e.getCommand());
170  },
171  [](const GroupEvent& e) {
172  return e.getTclListComponents();
173  },
174  [&](const SimpleEvent& /*e*/) {
175  return makeTclList("simple", int(getType(event)));
176  }
177  }, event);
178 }
179 
180 std::string toString(const Event& event)
181 {
182  return std::string(toTclList(event).getString());
183 }
184 
185 bool isRepeatStopper(const Event& self, const Event& other)
186 {
187  assert(self && other);
188  return visit(overloaded{
189  // Normally all events should stop the repeat process in 'bind -repeat',
190  // but in case of OsdControlEvent there are two exceptions:
191  // - we should not stop because of the original host event that
192  // actually generated this 'artificial' OsdControlEvent.
193  // - if the original host event is a joystick motion event, we
194  // should not stop repeat for 'small' relative new joystick events.
195  [&](const OsdControlEvent& e) {
196  // If this OsdControlEvent was generated by the other event, then
197  // repeat should not be stopped.
198  if (!e.getOrigEvent()) return true;
199  if (e.getOrigEvent() == other) return false;
200 
201  // If this OsdControlEvent event was generated by a joystick motion
202  // event and the new event is also a joystick motion event then don't
203  // stop repeat. We don't need to check the actual values of the events
204  // (it also isn't trivial), because when the values differ by enough,
205  // a new OsdControlEvent will be generated and that one will stop
206  // repeat.
207  return (getType(e.getOrigEvent()) != EventType::JOY_AXIS_MOTION) ||
208  (getType(other) != EventType::JOY_AXIS_MOTION);
209  },
210  [](const EventBase& /*e*/) {
211  return true;
212  }
213  }, self);
214 }
215 
216 bool matches(const Event& self, const Event& other)
217 {
218  assert(self && other);
219  return visit(overloaded{
220  [&](const GroupEvent& e) {
221  return contains(e.getTypesToMatch(), getType(other));
222  },
223  [&](const EventBase&) {
224  return self == other;
225  }
226  }, self);
227 }
228 
229 } // namespace openmsx
Command received on CliComm connection.
Definition: Event.hh:407
This event is send when a device (v99x8, v9990, video9000, laserdisc) reaches the end of a frame.
Definition: Event.hh:385
Keys::KeyCode getKeyCode() const
Definition: Event.hh:94
OSD events are triggered by other events.
Definition: Event.hh:321
std::string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:741
This file implemented 3 utility functions:
Definition: Autofire.cc:9
bool operator==(const Event &x, const Event &y)
Definition: Event.cc:11
bool isRepeatStopper(const Event &self, const Event &other)
Should 'bind -repeat' be stopped by 'other' event.
Definition: Event.cc:185
bool matches(const Event &self, const Event &other)
Does this event 'match' the given event.
Definition: Event.cc:216
auto visit(Visitor &&visitor, const Event &event)
Definition: Event.hh:653
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:118
TclObject toTclList(const Event &event)
Similar to toString(), but retains the structure of the event.
Definition: Event.cc:85
EventType getType(const Event &event)
Definition: Event.hh:645
TclObject makeTclList(Args &&... args)
Definition: TclObject.hh:290
std::string toString(const Event &event)
Get a string representation of this event.
Definition: Event.cc:180
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition: stl.hh:32
TemporaryString tmpStrCat(Ts &&... ts)
Definition: strCat.hh:659