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