载入中...
搜索中...
未找到
Joystick.cpp
浏览该文件的文档.
2
3#include "common/Exception.h"
6
7#include <SDL2/SDL.h>
8
9#include <algorithm>
10#include <cstring>
11#include <sstream>
12
13namespace eve::joystick::sdl {
14
16 StartupStage stage("joystick: SDL subsystem init + device enumeration");
17 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0)
18 throw eve::Exception("Could not initialize SDL joystick subsystem (%s)", SDL_GetError());
19
20 for (int i = 0; i < SDL_NumJoysticks(); i++) addJoystick(i);
21
22 SDL_JoystickEventState(SDL_ENABLE);
23 SDL_GameControllerEventState(SDL_ENABLE);
25}
26
29 for (auto* stick : joysticks_) {
30 stick->close();
31 delete stick;
32 }
33 joysticks_.clear();
34 activeSticks_.clear();
35
36 if (SDL_WasInit(SDL_INIT_HAPTIC) != 0) SDL_QuitSubSystem(SDL_INIT_HAPTIC);
37 SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
38}
39
40Pad* Joystick::getJoystick(int joyindex) {
41 if (joyindex < 0 || static_cast<size_t>(joyindex) >= activeSticks_.size()) return nullptr;
42 return activeSticks_[static_cast<size_t>(joyindex)];
43}
44
46 for (int i = 0; i < static_cast<int>(activeSticks_.size()); i++) {
47 if (activeSticks_[static_cast<size_t>(i)] == pad) return i;
48 }
49 return -1;
50}
51
53 return static_cast<int>(activeSticks_.size());
54}
55
57 for (auto* stick : activeSticks_) {
58 if (stick->getInstanceID() == instanceid) return stick;
59 }
60 return nullptr;
61}
62
63Pad* Joystick::addJoystick(int deviceindex) {
64 if (deviceindex < 0 || deviceindex >= SDL_NumJoysticks()) return nullptr;
65
66 std::string guidstr = getDeviceGUID(deviceindex);
67 Pad* pad = nullptr;
68 bool reused = false;
69
70 for (auto* stick : joysticks_) {
71 if (!stick->isConnected() && stick->getGUID() == guidstr) {
72 pad = stick;
73 reused = true;
74 break;
75 }
76 }
77
78 if (!pad) {
79 pad = new Pad(static_cast<int>(joysticks_.size()));
80 joysticks_.push_back(pad);
81 }
82
84
85 if (!pad->open(deviceindex)) return nullptr;
86
87 for (auto* active : activeSticks_) {
88 if (pad->getHandle() == active->getHandle()) {
89 pad->close();
90 if (!reused) {
91 joysticks_.remove(pad);
92 delete pad;
93 }
94 return active;
95 }
96 }
97
98 if (pad->isGamepad()) recentGamepadGUIDs_[pad->getGUID()] = true;
99
100 activeSticks_.push_back(pad);
101 return pad;
102}
103
105 if (!pad) return;
106 auto it = std::find(activeSticks_.begin(), activeSticks_.end(), pad);
107 if (it != activeSticks_.end()) {
108 (*it)->close();
109 activeSticks_.erase(it);
110 }
111}
112
113void Joystick::checkGamepads(const std::string& guid) const {
114 for (int d_index = 0; d_index < SDL_NumJoysticks(); d_index++) {
115 if (!SDL_IsGameController(d_index)) continue;
116 if (guid.compare(getDeviceGUID(d_index)) != 0) continue;
117
118 for (auto* stick : activeSticks_) {
119 if (guid.compare(stick->getGUID()) != 0) continue;
120
121 SDL_GameController* controller = SDL_GameControllerOpen(d_index);
122 if (!controller) continue;
123
124 SDL_Joystick* sdlstick = SDL_GameControllerGetJoystick(controller);
125 bool open_gamepad = (sdlstick == static_cast<SDL_Joystick*>(stick->getHandle()));
126 SDL_GameControllerClose(controller);
127
128 if (open_gamepad) stick->openGamepad(d_index);
129 }
130 }
131}
132
133std::string Joystick::getDeviceGUID(int deviceindex) const {
134 if (deviceindex < 0 || deviceindex >= SDL_NumJoysticks()) return "";
135
136 char guidstr[33] = {'\0'};
137 SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(deviceindex);
138 SDL_JoystickGetGUIDString(guid, guidstr, sizeof(guidstr));
139 return guidstr;
140}
141
142void Joystick::loadGamepadMappings(const std::string& mappings) {
143 std::stringstream ss(mappings);
144 std::string mapping;
145 bool success = false;
146
147 while (std::getline(ss, mapping)) {
148 if (mapping.empty()) continue;
149 if (mapping[0] == '#') continue;
150
151 size_t pstartpos = mapping.find("platform:");
152 if (pstartpos != std::string::npos) {
153 pstartpos += strlen("platform:");
154 size_t pendpos = mapping.find_first_of(',', pstartpos);
155 std::string platform = mapping.substr(pstartpos, pendpos - pstartpos);
156 if (platform.compare(SDL_GetPlatform()) != 0) {
157 success = true;
158 continue;
159 }
160 pstartpos -= strlen("platform:");
161 mapping.erase(pstartpos, pendpos - pstartpos + 1);
162 }
163
164 if (SDL_GameControllerAddMapping(mapping.c_str()) != -1) {
165 success = true;
166 std::string guid = mapping.substr(0, mapping.find_first_of(','));
167 recentGamepadGUIDs_[guid] = true;
168 checkGamepads(guid);
169 }
170 }
171
172 if (!success && !mappings.empty()) throw eve::Exception("Invalid gamepad mappings.");
173}
174
175std::string Joystick::getGamepadMappingString(const std::string& guid) const {
176 SDL_JoystickGUID sdlguid = SDL_JoystickGetGUIDFromString(guid.c_str());
177 char* sdlmapping = SDL_GameControllerMappingForGUID(sdlguid);
178 if (!sdlmapping) return "";
179
180 std::string mapping(sdlmapping);
181 SDL_free(sdlmapping);
182
183 if (mapping.find_last_of(',') != mapping.length() - 1) mapping += ",";
184 mapping += "platform:" + std::string(SDL_GetPlatform());
185 return mapping;
186}
187
189 std::string mappings;
190 for (const auto& g : recentGamepadGUIDs_) {
191 SDL_JoystickGUID sdlguid = SDL_JoystickGetGUIDFromString(g.first.c_str());
192 char* sdlmapping = SDL_GameControllerMappingForGUID(sdlguid);
193 if (!sdlmapping) continue;
194
195 std::string mapping = sdlmapping;
196 SDL_free(sdlmapping);
197
198 if (mapping.find_last_of(',') != mapping.length() - 1) mapping += ",";
199 mapping += "platform:" + std::string(SDL_GetPlatform()) + ",\n";
200 mappings += mapping;
201 }
202 return mappings;
203}
204
205} // namespace eve::joystick::sdl
bool & active
tensor::Graph g
Definition GpuGraph.cpp:7
int reused
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
StartupStage public API.
One connected (or previously connected) joystick / gamepad device. Gamepad axis/button names follow S...
Definition Pad.h:13
int getJoystickCount() const override
Number of currently tracked pads.
Definition Joystick.cpp:52
Joystick()
Initializes SDL joystick subsystems used by this backend.
Definition Joystick.cpp:15
std::string saveGamepadMappings() override
Serializes the in-memory GameController mapping database.
Definition Joystick.cpp:188
void removeJoystick(eve::joystick::Pad *pad) override
Removes and destroys a previously opened pad.
Definition Joystick.cpp:104
std::string getGamepadMappingString(const std::string &guid) const override
Mapping string for a device GUID, or empty if none.
Definition Joystick.cpp:175
Pad * addJoystick(int deviceindex) override
Open a device by SDL device index; returns null on failure.
Definition Joystick.cpp:63
void loadGamepadMappings(const std::string &mappings) override
Load SDL GameController mapping database (newline-separated).
Definition Joystick.cpp:142
int getIndex(const eve::joystick::Pad *pad) override
Dense index of pad, or -1 if not tracked.
Definition Joystick.cpp:45
~Joystick() override
Closes all tracked pads.
Definition Joystick.cpp:27
Pad * getJoystick(int joyindex) override
Pad at a dense joyindex in [0, getJoystickCount()).
Definition Joystick.cpp:40
Pad * getJoystickFromID(int instanceid) override
Looks up a pad by SDL instance id; null if unknown.
Definition Joystick.cpp:56
SDL joystick/gamepad backend (GameController + optional haptic rumble).
Definition Pad.h:13
void bindJoystickEventSinkOwner(eve::joystick::Joystick *owner) noexcept
Bind the live Joystick module into the SDL event sink. @ownership Borrowed; the Joystick module owns ...
uint32_t pad[2]