OXYGENHUB
◆ main openmsx / src / events / AnalogInput.cc
3.7 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "AnalogInput.hh"
2
3
#include "StringOp.hh"
4
#include "narrow.hh"
5
#include "one_of.hh"
6
#include "stl.hh"
7
8
#include <cctype>
9
#include <tuple>
10
11
namespace openmsx {
12
13
std::string toString(const AnalogInput& input)
14
{
15
	return std::visit(overloaded{
16
		[](const AnalogMouseAxis& m) {
17
			return strCat("mouse ", (m.getAxis() ? 'Y' : 'X'), "-axis");
18
		},
19
		[](const AnalogJoystickAxis& j) {
20
			return strCat(j.getJoystick().str(), " axis", j.getAxis());
21
		},
22
	}, input);
23
}
24
25
std::optional<AnalogInput> parseAnalogInput(std::string_view text)
26
{
27
	auto tokenizer = StringOp::split_view<StringOp::EmptyParts::REMOVE>(text, ' ');
28
	auto it = tokenizer.begin();
29
	auto et = tokenizer.end();
30
31
	if (it == et) return std::nullopt;
32
	auto type = *it++;
33
	if (it == et) return std::nullopt;
34
	if (type == "mouse") {
35
		auto axis = *it++;
36
		if (it != et) return std::nullopt;
37
		if (axis.size() != 6 || !axis.ends_with("-axis")) return std::nullopt;
38
		auto n = tolower(axis[0]) - 'x';
39
		if (n != one_of(0, 1)) return std::nullopt;
40
		return AnalogMouseAxis(n);
41
	} else if (type.starts_with("joy")) {
42
		type.remove_prefix(3);
43
		auto j = StringOp::stringToBase<10, unsigned>(type);
44
		if (!j || *j == 0) return std::nullopt;
45
		auto joyId = JoystickId(*j - 1);
46
47
		auto axis = *it++;
48
		if (it != et) return std::nullopt;
49
		if (!axis.starts_with("axis")) return std::nullopt;
50
		axis.remove_prefix(4);
51
		auto a = StringOp::stringToBase<10, unsigned>(axis);
52
		if (!a || *a > 255) return std::nullopt;
53
		return AnalogJoystickAxis(joyId, narrow<uint8_t>(*a));
54
	}
55
	return std::nullopt;
56
57
}
58
59
static constexpr int mouseThreshold = 5;
60
std::optional<AnalogInput> captureAnalogInput(const Event& event, function_ref<int(JoystickId)> getJoyDeadThreshold)
61
{
62
	return std::visit(overloaded{
63
		[](const MouseMotionEvent& e) -> std::optional<AnalogInput> {
64
			int x = std::abs(e.getX());
65
			int y = std::abs(e.getY());
66
			if (x > y && x >= mouseThreshold) return AnalogMouseAxis(0);
67
			if (y > x && y >= mouseThreshold) return AnalogMouseAxis(1);
68
			return std::nullopt;
69
		},
70
		[&](const JoystickAxisMotionEvent& e) -> std::optional<AnalogInput> {
71
			auto joyId = e.getJoystick();
72
			int threshold = getJoyDeadThreshold(joyId);
73
			auto value = std::abs(e.getValue());
74
			if (value <= threshold) return std::nullopt;
75
			return AnalogJoystickAxis(joyId, e.getAxis());
76
		},
77
		[](const EventBase&) -> std::optional<AnalogInput> {
78
			return std::nullopt;
79
		}
80
	}, event);
81
}
82
83
bool operator==(const AnalogInput& x, const AnalogInput& y)
84
{
85
	return std::visit(overloaded{
86
		[](const AnalogMouseAxis& m1, const AnalogMouseAxis& m2) {
87
			return m1.getAxis() == m2.getAxis();
88
		},
89
		[](const AnalogJoystickAxis& j1, const AnalogJoystickAxis& j2) {
90
			return std::tuple(j1.getJoystick(), j1.getAxis()) ==
91
			       std::tuple(j2.getJoystick(), j2.getAxis());
92
		},
93
		[](const auto&, const auto&) { // mixed types
94
			return false;
95
		}
96
	}, x, y);
97
}
98
99
100
std::optional<float> match(const AnalogInput& binding, const Event& event,
101
                          function_ref<float(JoystickId, const JoystickAxisMotionEvent&)> getJoyValue)
102
{
103
	return std::visit(overloaded{
104
		[](const AnalogMouseAxis& bind, const MouseMotionEvent& mouse) -> std::optional<float> {
105
			auto a = bind.getAxis();
106
			if (a != one_of(0, 1)) return std::nullopt;
107
			auto d = a ? mouse.getY() : mouse.getX();
108
			return (std::abs(d) < mouseThreshold) ? 0.0f : float(d);
109
		},
110
		[&](const AnalogJoystickAxis& bind, const JoystickAxisMotionEvent& e) -> std::optional<float> {
111
			if (bind.getJoystick() != e.getJoystick()) return std::nullopt;
112
			if (bind.getAxis() != e.getAxis()) return std::nullopt;
113
			return getJoyValue(bind.getJoystick(), e);
114
		},
115
		[](const auto& /*bind*/, const auto& /*event*/) -> std::optional<float> {
116
			return std::nullopt;
117
		}
118
	}, binding, event);
119
}
120
121
} // namespace openmsx