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 EventBase& /*a*/, const EventBase& /*b*/) {
76  return getType(x) == getType(y);
77  }
78  }, x, y);
79 }
80 
81 TclObject toTclList(const Event& event)
82 {
83  static constexpr std::array osdControlNames = {
84  "LEFT"sv, "RIGHT"sv, "UP"sv, "DOWN"sv, "A"sv, "B"sv
85  };
86 
87  return visit(overloaded{
88  [](const KeyEvent& e) {
89  // Note: 'scanCode' is not included (also not in operator==()).
90  //
91  // At the moment 'scanCode' is only used in the MSX Keyboard code when
92  // the POSITIONAL mapping mode is active. It is not used for key
93  // bindings (the 'bind' or the 'after' commands) or for the openMSX
94  // console. KeyEvents also don't end up in 'reverse replay' files
95  // (instead those files contain more low level MSX keyboard matrix
96  // changes).
97  //
98  // Within these constraints it's fine to ignore 'scanCode' in this
99  // method.
100  auto result = makeTclList("keyb", Keys::getName(e.getKeyCode()));
101  if (e.getUnicode() != 0) {
102  result.addListElement(tmpStrCat("unicode", e.getUnicode()));
103  }
104  return result;
105  },
106  [](const MouseMotionEvent& e) {
107  return makeTclList("mouse", "motion", e.getX(), e.getY(), e.getAbsX(), e.getAbsY());
108  },
109  [](const MouseButtonUpEvent& e) {
110  return makeTclList("mouse", tmpStrCat("button", e.getButton()), "up");
111  },
112  [](const MouseButtonDownEvent& e) {
113  return makeTclList("mouse", tmpStrCat("button", e.getButton()), "down");
114  },
115  [](const MouseWheelEvent& e) {
116  return makeTclList("mouse", "wheel", e.getX(), e.getY());
117  },
118  [](const JoystickAxisMotionEvent& e) {
119  return makeTclList(tmpStrCat("joy", e.getJoystick() + 1), tmpStrCat("axis", e.getAxis()), e.getValue());
120  },
121  [](const JoystickHatEvent& e) {
122  const char* str = [&] {
123  switch (e.getValue()) {
124  case SDL_HAT_UP: return "up";
125  case SDL_HAT_RIGHT: return "right";
126  case SDL_HAT_DOWN: return "down";
127  case SDL_HAT_LEFT: return "left";
128  case SDL_HAT_RIGHTUP: return "rightup";
129  case SDL_HAT_RIGHTDOWN: return "rightdown";
130  case SDL_HAT_LEFTUP: return "leftup";
131  case SDL_HAT_LEFTDOWN: return "leftdown";
132  default: return "center";
133  }
134  }();
135  return makeTclList(tmpStrCat("joy", e.getJoystick() + 1), tmpStrCat("hat", e.getHat()), str);
136  },
137  [](const JoystickButtonUpEvent& e) {
138  return makeTclList(tmpStrCat("joy", e.getJoystick() + 1), tmpStrCat("button", e.getButton()), "up");
139  },
140  [](const JoystickButtonDownEvent& e) {
141  return makeTclList(tmpStrCat("joy", e.getJoystick() + 1), tmpStrCat("button", e.getButton()), "down");
142  },
143  [](const OsdControlReleaseEvent& e) {
144  return makeTclList("OSDcontrol", osdControlNames[e.getButton()], "RELEASE");
145  },
146  [](const OsdControlPressEvent& e) {
147  return makeTclList("OSDcontrol", osdControlNames[e.getButton()], "PRESS");
148  },
149  [](const FocusEvent& e) {
150  return makeTclList("focus", e.getGain());
151  },
152  [](const ResizeEvent& e) {
153  return makeTclList("resize", int(e.getX()), int(e.getY()));
154  },
155  [](const FileDropEvent& e) {
156  return makeTclList("filedrop", e.getFileName());
157  },
158  [](const QuitEvent& /*e*/) {
159  return makeTclList("quit");
160  },
161  [](const FinishFrameEvent& e) {
162  return makeTclList("finishframe", int(e.getSource()), int(e.getSelectedSource()), e.isSkipped());
163  },
164  [](const CliCommandEvent& e) {
165  return makeTclList("CliCmd", e.getCommand());
166  },
167  [](const GroupEvent& e) {
168  return e.getTclListComponents();
169  },
170  [&](const SimpleEvent& /*e*/) {
171  return makeTclList("simple", int(getType(event)));
172  }
173  }, event);
174 }
175 
176 std::string toString(const Event& event)
177 {
178  return std::string(toTclList(event).getString());
179 }
180 
181 bool isRepeatStopper(const Event& self, const Event& other)
182 {
183  assert(self && other);
184  return visit(overloaded{
185  // Normally all events should stop the repeat process in 'bind -repeat',
186  // but in case of OsdControlEvent there are two exceptions:
187  // - we should not stop because of the original host event that
188  // actually generated this 'artificial' OsdControlEvent.
189  // - if the original host event is a joystick motion event, we
190  // should not stop repeat for 'small' relative new joystick events.
191  [&](const OsdControlEvent& e) {
192  // If this OsdControlEvent was generated by the other event, then
193  // repeat should not be stopped.
194  if (!e.getOrigEvent()) return true;
195  if (e.getOrigEvent() == other) return false;
196 
197  // If this OsdControlEvent event was generated by a joystick motion
198  // event and the new event is also a joystick motion event then don't
199  // stop repeat. We don't need to check the actual values of the events
200  // (it also isn't trivial), because when the values differ by enough,
201  // a new OsdControlEvent will be generated and that one will stop
202  // repeat.
203  return (getType(e.getOrigEvent()) != EventType::JOY_AXIS_MOTION) ||
204  (getType(other) != EventType::JOY_AXIS_MOTION);
205  },
206  [](const EventBase& /*e*/) {
207  return true;
208  }
209  }, self);
210 }
211 
212 bool matches(const Event& self, const Event& other)
213 {
214  assert(self && other);
215  return visit(overloaded{
216  [&](const GroupEvent& e) {
217  return contains(e.getTypesToMatch(), getType(other));
218  },
219  [&](const EventBase&) {
220  return self == other;
221  }
222  }, self);
223 }
224 
225 } // 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:181
bool matches(const Event &self, const Event &other)
Does this event 'match' the given event.
Definition: Event.cc:212
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:81
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:176
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition: stl.hh:31
TemporaryString tmpStrCat(Ts &&... ts)
Definition: strCat.hh:659