openMSX
BooleanInput.cc
Go to the documentation of this file.
1#include "BooleanInput.hh"
2
3#include "Event.hh"
4#include "SDLKey.hh"
5
6#include "narrow.hh"
7#include "one_of.hh"
8#include "stl.hh"
9#include "strCat.hh"
10#include "StringOp.hh"
11#include "unreachable.hh"
12
13#include <tuple>
14
15namespace openmsx {
16
17std::string toString(const BooleanInput& input)
18{
19 return std::visit(overloaded{
20 [](const BooleanKeyboard& k) {
21 return strCat("keyb ", SDLKey::toString(k.getKeyCode()));
22 },
23 [](const BooleanMouseButton& m) {
24 return strCat("mouse button", m.getButton());
25 },
26 [](const BooleanJoystickButton& j) {
27 return strCat(j.getJoystick().str(), " button", j.getButton());
28 },
29 [](const BooleanJoystickHat& h) {
30 const char* str = [&] {
31 switch (h.getValue()) {
32 case BooleanJoystickHat::UP: return " up";
33 case BooleanJoystickHat::RIGHT: return " right";
34 case BooleanJoystickHat::DOWN: return " down";
35 case BooleanJoystickHat::LEFT: return " left";
36 default: UNREACHABLE;
37 }
38 }();
39 return strCat(h.getJoystick().str(), " hat", h.getHat(), str);
40 },
41 [&](const BooleanJoystickAxis& a) {
42 return strCat(a.getJoystick().str(), ' ',
43 (a.getDirection() == BooleanJoystickAxis::POS ? '+' : '-'),
44 "axis", a.getAxis());
45 }
46 }, input);
47}
48
49[[nodiscard]] static std::optional<unsigned> parseValueWithPrefix(std::string_view str, std::string_view prefix)
50{
51 if (!str.starts_with(prefix)) return std::nullopt;
52 str.remove_prefix(prefix.size());
53 return StringOp::stringToBase<10, unsigned>(str);
54}
55
56std::optional<BooleanInput> parseBooleanInput(std::string_view text)
57{
58 auto tokenizer = StringOp::split_view<StringOp::REMOVE_EMPTY_PARTS>(text, ' ');
59 auto it = tokenizer.begin();
60 auto et = tokenizer.end();
61
62 if (it == et) return std::nullopt;
63 auto type = *it++;
64 if (it == et) return std::nullopt;
65 if (type == "keyb") {
66 std::string key{*it++};
67 while (it != et) strAppend(key, ' ', *it++); // allow for key-name containing space chars
68 auto keycode = SDLKey::keycodeFromString(key);
69 if (keycode == SDLK_UNKNOWN) return std::nullopt;
70 return BooleanKeyboard(keycode);
71
72 } else if (type == "mouse") {
73 auto button = *it++;
74 if (it != et) return std::nullopt;
75 auto n = parseValueWithPrefix(button, "button");
76 if (!n) return std::nullopt;
77 if (*n > 255) return std::nullopt;
78 return BooleanMouseButton(narrow<uint8_t>(*n));
79
80 } else if (auto joystick = parseValueWithPrefix(type, "joy")) {
81 if (*joystick == 0) return std::nullopt;
82 auto joyId = JoystickId(*joystick - 1);
83
84 auto subType = *it++;
85 if (auto button = parseValueWithPrefix(subType, "button")) {
86 if (*button > 255) return std::nullopt;
87 if (it != et) return std::nullopt;
88 return BooleanJoystickButton(joyId, narrow<uint8_t>(*button));
89
90 } else if (auto hat = parseValueWithPrefix(subType, "hat")) {
91 if (*hat > 255) return std::nullopt;
92 if (it == et) return std::nullopt;
93 auto valueStr = *it++;
94 if (it != et) return std::nullopt;
95
97 if (valueStr == "up" ) value = BooleanJoystickHat::UP;
98 else if (valueStr == "right") value = BooleanJoystickHat::RIGHT;
99 else if (valueStr == "down" ) value = BooleanJoystickHat::DOWN;
100 else if (valueStr == "left" ) value = BooleanJoystickHat::LEFT;
101 else return std::nullopt;
102
103 return BooleanJoystickHat(joyId, narrow<uint8_t>(*hat), value);
104
105 } else if (auto pAxis = parseValueWithPrefix(subType, "+axis")) {
106 if (*pAxis > 255) return std::nullopt;
107 if (it != et) return std::nullopt;
108 return BooleanJoystickAxis(joyId, narrow<uint8_t>(*pAxis), BooleanJoystickAxis::POS);
109 } else if (auto nAxis = parseValueWithPrefix(subType, "-axis")) {
110 if (*nAxis > 255) return std::nullopt;
111 if (it != et) return std::nullopt;
112 return BooleanJoystickAxis(joyId, narrow<uint8_t>(*nAxis), BooleanJoystickAxis::NEG);
113 }
114 }
115 return std::nullopt;
116}
117
118std::optional<BooleanInput> captureBooleanInput(const Event& event, function_ref<int(JoystickId)> getJoyDeadZone)
119{
120 return std::visit(overloaded{
121 [](const KeyDownEvent& e) -> std::optional<BooleanInput> {
122 return BooleanKeyboard(e.getKeyCode());
123 },
124 [](const MouseButtonDownEvent& e) -> std::optional<BooleanInput> {
125 return BooleanMouseButton(e.getButton());
126 },
127 [](const JoystickButtonDownEvent& e) -> std::optional<BooleanInput> {
128 return BooleanJoystickButton(e.getJoystick(), narrow<uint8_t>(e.getButton()));
129 },
130 [](const JoystickHatEvent& e) -> std::optional<BooleanInput> {
131 auto value = e.getValue();
132 if (value != one_of(SDL_HAT_UP, SDL_HAT_RIGHT, SDL_HAT_DOWN, SDL_HAT_LEFT)) {
133 return std::nullopt;
134 }
135 return BooleanJoystickHat(e.getJoystick(), e.getHat(),
137 },
138 [&](const JoystickAxisMotionEvent& e) -> std::optional<BooleanInput> {
139 auto joyId = e.getJoystick();
140 int deadZone = getJoyDeadZone(joyId); // percentage 0..100
141 int threshold = (deadZone * 32768) / 100;
142
143 auto value = e.getValue();
144 if ((-threshold <= value) && (value <= threshold)) {
145 return std::nullopt;
146 }
147 return BooleanJoystickAxis(joyId, e.getAxis(),
148 (value > 0 ? BooleanJoystickAxis::POS
150 },
151 [](const EventBase&) -> std::optional<BooleanInput> {
152 return std::nullopt;
153 }
154 }, event);
155}
156
157bool operator==(const BooleanInput& x, const BooleanInput& y)
158{
159 return std::visit(overloaded{
160 [](const BooleanKeyboard& k1, const BooleanKeyboard& k2) {
161 return k1.getKeyCode() == k2.getKeyCode();
162 },
163 [](const BooleanMouseButton& m1, const BooleanMouseButton& m2) {
164 return m1.getButton() == m2.getButton();
165 },
166 [](const BooleanJoystickButton& j1, const BooleanJoystickButton& j2) {
167 return std::tuple(j1.getJoystick(), j1.getButton()) ==
168 std::tuple(j2.getJoystick(), j2.getButton());
169 },
170 [](const BooleanJoystickHat& j1, const BooleanJoystickHat& j2) {
171 return std::tuple(j1.getJoystick(), j1.getHat(), j1.getValue()) ==
172 std::tuple(j2.getJoystick(), j2.getHat(), j2.getValue());
173 },
174 [](const BooleanJoystickAxis& j1, const BooleanJoystickAxis& j2) {
175 return std::tuple(j1.getJoystick(), j1.getAxis(), j1.getDirection()) ==
176 std::tuple(j2.getJoystick(), j2.getAxis(), j2.getDirection());
177 },
178 [](const auto&, const auto&) { // mixed types
179 return false;
180 }
181 }, x, y);
182}
183
184std::optional<bool> match(const BooleanInput& binding, const Event& event,
185 function_ref<int(JoystickId)> getJoyDeadZone)
186{
187 return std::visit(overloaded{
188 [](const BooleanKeyboard& bind, const KeyDownEvent& down) -> std::optional<bool> {
189 if (bind.getKeyCode() == down.getKeyCode()) return true;
190 return std::nullopt;
191 },
192 [](const BooleanKeyboard& bind, const KeyUpEvent& up) -> std::optional<bool> {
193 if (bind.getKeyCode() == up.getKeyCode()) return false; // no longer pressed
194 return std::nullopt;
195 },
196
197 [](const BooleanMouseButton& bind, const MouseButtonDownEvent& down) -> std::optional<bool> {
198 if (bind.getButton() == down.getButton()) return true;
199 return std::nullopt;
200 },
201 [](const BooleanMouseButton& bind, const MouseButtonUpEvent& up) -> std::optional<bool> {
202 if (bind.getButton() == up.getButton()) return false; // no longer pressed
203 return std::nullopt;
204 },
205
206 [](const BooleanJoystickButton& bind, const JoystickButtonDownEvent& down) -> std::optional<bool> {
207 if (bind.getJoystick() != down.getJoystick()) return std::nullopt;
208 if (bind.getButton() == down.getButton()) return true;
209 return std::nullopt;
210 },
211 [](const BooleanJoystickButton& bind, const JoystickButtonUpEvent& up) -> std::optional<bool> {
212 if (bind.getJoystick() != up.getJoystick()) return std::nullopt;
213 if (bind.getButton() == up.getButton()) return false; // no longer pressed
214 return std::nullopt;
215 },
216
217 [](const BooleanJoystickHat& bind, const JoystickHatEvent& e) -> std::optional<bool> {
218 if (bind.getJoystick() != e.getJoystick()) return std::nullopt;
219 if (bind.getHat() != e.getHat()) return std::nullopt;
220 return bind.getValue() & e.getValue();
221 },
222
223 [&](const BooleanJoystickAxis& bind, const JoystickAxisMotionEvent& e) -> std::optional<bool> {
224 if (bind.getJoystick() != e.getJoystick()) return std::nullopt;
225 if (bind.getAxis() != e.getAxis()) return std::nullopt;
226 int deadZone = getJoyDeadZone(bind.getJoystick()); // percentage 0..100
227 int threshold = (deadZone * 32768) / 100;
228 if (bind.getDirection() == BooleanJoystickAxis::POS) {
229 return e.getValue() > threshold;
230 } else {
231 return e.getValue() < -threshold;
232 }
233 },
234
235 [](const auto& /*bind*/, const auto& /*event*/) -> std::optional<bool> {
236 return std::nullopt;
237 }
238 }, binding, event);
239}
240
241} // namespace openmsx
This file implemented 3 utility functions:
Definition Autofire.cc:11
std::optional< BooleanInput > captureBooleanInput(const Event &event, function_ref< int(JoystickId)> getJoyDeadZone)
bool operator==(const BooleanInput &x, const BooleanInput &y)
std::optional< bool > match(const BooleanInput &binding, const Event &event, function_ref< int(JoystickId)> getJoyDeadZone)
std::optional< BooleanInput > parseBooleanInput(std::string_view text)
std::variant< BooleanKeyboard, BooleanMouseButton, BooleanJoystickButton, BooleanJoystickHat, BooleanJoystickAxis > BooleanInput
std::string toString(const BooleanInput &input)
std::variant< KeyUpEvent, KeyDownEvent, MouseMotionEvent, MouseButtonUpEvent, MouseButtonDownEvent, MouseWheelEvent, JoystickAxisMotionEvent, JoystickHatEvent, JoystickButtonUpEvent, JoystickButtonDownEvent, OsdControlReleaseEvent, OsdControlPressEvent, WindowEvent, TextEvent, FileDropEvent, QuitEvent, FinishFrameEvent, CliCommandEvent, GroupEvent, BootEvent, FrameDrawnEvent, BreakEvent, SwitchRendererEvent, TakeReverseSnapshotEvent, AfterTimedEvent, MachineLoadedEvent, MachineActivatedEvent, MachineDeactivatedEvent, MidiInReaderEvent, MidiInWindowsEvent, MidiInCoreMidiEvent, MidiInCoreMidiVirtualEvent, MidiInALSAEvent, Rs232TesterEvent, Rs232NetEvent, ImGuiDelayedActionEvent, ImGuiActiveEvent > Event
Definition Event.hh:444
std::string strCat()
Definition strCat.hh:703
void strAppend(std::string &result, Ts &&...ts)
Definition strCat.hh:752
static SDL_Keycode keycodeFromString(zstring_view name)
Definition SDLKey.cc:109
std::string toString() const
Definition SDLKey.cc:230
#define UNREACHABLE