openMSX
JoystickManager.cc
Go to the documentation of this file.
1#include "JoystickManager.hh"
2
3#include "IntegerSetting.hh"
4
5#include "narrow.hh"
6#include "ranges.hh"
7#include "strCat.hh"
8
9namespace openmsx {
10
11JoystickManager::JoystickManager(CommandController& commandController_)
12 : commandController(commandController_)
13{
14 // Note: we don't explicitly enumerate all joysticks which are already
15 // present at startup. Instead we rely on SDL_JOYDEVICEADDED events:
16 // these also get send for the initial joysticks.
17
18 // joysticks generate events
19 SDL_JoystickEventState(SDL_ENABLE); // is this needed?
20}
21
23{
24 for (auto& info : infos) {
25 if (info.joystick) SDL_JoystickClose(info.joystick);
26 }
27}
28
29size_t JoystickManager::getFreeSlot()
30{
31 if (auto it = ranges::find(infos, nullptr, &Info::joystick); it != infos.end()) {
32 return std::distance(infos.begin(), it);
33 }
34 auto idx = infos.size();
35 infos.emplace_back();
36 infos[idx].deadZoneSetting = std::make_unique<IntegerSetting>(
37 commandController,
38 tmpStrCat("joystick", idx + 1, "_deadzone"),
39 "size (as a percentage) of the dead center zone",
40 25, 0, 100);
41 return idx;
42}
43
44void JoystickManager::add(int deviceIndex)
45{
46 auto idx = getFreeSlot();
47 auto& info = infos[idx];
48 info.joystick = SDL_JoystickOpen(deviceIndex);
49 info.instanceId = info.joystick ? SDL_JoystickInstanceID(info.joystick) : -1;
50}
51
52void JoystickManager::remove(int instanceId)
53{
54 auto it = ranges::find(infos, instanceId, &Info::instanceId);
55 if (it == infos.end()) return; // this shouldn't happen
56
57 SDL_JoystickClose(it->joystick);
58 it->joystick = nullptr;
59 it->instanceId = -1;
60}
61
62std::vector<JoystickId> JoystickManager::getConnectedJoysticks() const
63{
64 // TODO c++20 view::filter | view::transform
65 std::vector<JoystickId> result;
66 for (auto i : xrange(infos.size())) {
67 if (!infos[i].joystick) continue;
68 result.push_back(JoystickId(unsigned(i)));
69 }
70 return result;
71}
72
74{
75 unsigned id = joyId.raw();
76 return (id < infos.size()) ? infos[id].deadZoneSetting.get() : nullptr;
77}
78
80{
81 unsigned id = joyId.raw();
82 auto* joystick = (id < infos.size()) ? infos[id].joystick : nullptr;
83 return joystick ? SDL_JoystickName(joystick) : "[Not plugged in]";
84}
85
86std::optional<unsigned> JoystickManager::getNumButtons(JoystickId joyId) const
87{
88 unsigned id = joyId.raw();
89 auto* joystick = (id < infos.size()) ? infos[id].joystick : nullptr;
90 if (!joystick) return {};
91 return SDL_JoystickNumButtons(joystick);
92}
93
94std::optional<JoystickId> JoystickManager::translateSdlInstanceId(SDL_Event& evt) const
95{
96 int instanceId = evt.jbutton.which; // any SDL joystick event
97 auto it = ranges::find(infos, instanceId, &Info::instanceId);
98 if (it == infos.end()) return {}; // should not happen
99 evt.jbutton.which = narrow<int>(std::distance(infos.begin(), it));
100 return JoystickId(evt.jbutton.which);
101}
102
103} // namespace openmsx
uintptr_t id
A Setting with an integer value.
unsigned raw() const
Definition JoystickId.hh:14
void add(int deviceIndex)
IntegerSetting * getJoyDeadZoneSetting(JoystickId joyId) const
std::optional< unsigned > getNumButtons(JoystickId joyId) const
void remove(int instanceId)
std::vector< JoystickId > getConnectedJoysticks() const
std::optional< JoystickId > translateSdlInstanceId(SDL_Event &evt) const
std::string getDisplayName(JoystickId joyId) const
This file implemented 3 utility functions:
Definition Autofire.cc:11
auto find(InputRange &&range, const T &value)
Definition ranges.hh:160
TemporaryString tmpStrCat(Ts &&... ts)
Definition strCat.hh:742
constexpr auto xrange(T e)
Definition xrange.hh:132