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());
19 for (
int i = 0; i < SDL_NumJoysticks(); i++)
addJoystick(i);
21 SDL_JoystickEventState(SDL_ENABLE);
22 SDL_GameControllerEventState(SDL_ENABLE);
26 for (
auto* stick : joysticks_) {
31 activeSticks_.clear();
33 if (SDL_WasInit(SDL_INIT_HAPTIC) != 0) SDL_QuitSubSystem(SDL_INIT_HAPTIC);
34 SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
38 if (joyindex < 0 ||
static_cast<size_t>(joyindex) >= activeSticks_.size())
return nullptr;
39 return activeSticks_[
static_cast<size_t>(joyindex)];
43 for (
int i = 0; i < static_cast<int>(activeSticks_.size()); i++) {
44 if (activeSticks_[
static_cast<size_t>(i)] == pad)
return i;
50 return static_cast<int>(activeSticks_.size());
54 for (
auto* stick : activeSticks_) {
55 if (stick->getInstanceID() == instanceid)
return stick;
61 if (deviceindex < 0 || deviceindex >= SDL_NumJoysticks())
return nullptr;
63 std::string guidstr = getDeviceGUID(deviceindex);
67 for (
auto* stick : joysticks_) {
68 if (!stick->isConnected() && stick->getGUID() == guidstr) {
76 pad =
new Pad(
static_cast<int>(joysticks_.size()));
77 joysticks_.push_back(pad);
82 if (!pad->
open(deviceindex))
return nullptr;
84 for (
auto*
active : activeSticks_) {
88 joysticks_.remove(pad);
97 activeSticks_.push_back(pad);
103 auto it = std::find(activeSticks_.begin(), activeSticks_.end(), pad);
104 if (it != activeSticks_.end()) {
106 activeSticks_.erase(it);
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;
115 for (
auto* stick : activeSticks_) {
116 if (guid.compare(stick->getGUID()) != 0)
continue;
118 SDL_GameController* controller = SDL_GameControllerOpen(d_index);
119 if (!controller)
continue;
121 SDL_Joystick* sdlstick = SDL_GameControllerGetJoystick(controller);
122 bool open_gamepad = (sdlstick ==
static_cast<SDL_Joystick*
>(stick->getHandle()));
123 SDL_GameControllerClose(controller);
125 if (open_gamepad) stick->openGamepad(d_index);
130std::string Joystick::getDeviceGUID(
int deviceindex)
const {
131 if (deviceindex < 0 || deviceindex >= SDL_NumJoysticks())
return "";
133 char guidstr[33] = {
'\0'};
134 SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(deviceindex);
135 SDL_JoystickGetGUIDString(guid, guidstr,
sizeof(guidstr));
140 std::stringstream ss(mappings);
142 bool success =
false;
144 while (std::getline(ss, mapping)) {
145 if (mapping.empty())
continue;
146 if (mapping[0] ==
'#')
continue;
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) {
157 pstartpos -= strlen(
"platform:");
158 mapping.erase(pstartpos, pendpos - pstartpos + 1);
161 if (SDL_GameControllerAddMapping(mapping.c_str()) != -1) {
163 std::string guid = mapping.substr(0, mapping.find_first_of(
','));
164 recentGamepadGUIDs_[guid] =
true;
169 if (!success && !mappings.empty())
throw eve::Exception(
"Invalid gamepad mappings.");
173 SDL_JoystickGUID sdlguid = SDL_JoystickGetGUIDFromString(guid.c_str());
174 char* sdlmapping = SDL_GameControllerMappingForGUID(sdlguid);
175 if (!sdlmapping)
return "";
177 std::string mapping(sdlmapping);
178 SDL_free(sdlmapping);
180 if (mapping.find_last_of(
',') != mapping.length() - 1) mapping +=
",";
181 mapping +=
"platform:" + std::string(SDL_GetPlatform());
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;
192 std::string mapping = sdlmapping;
193 SDL_free(sdlmapping);
195 if (mapping.find_last_of(
',') != mapping.length() - 1) mapping +=
",";
196 mapping +=
"platform:" + std::string(SDL_GetPlatform()) +
",\n";
One connected (or previously connected) joystick / gamepad device. Gamepad axis/button names follow S...
int getJoystickCount() const override
std::string saveGamepadMappings() override
void removeJoystick(eve::joystick::Pad *pad) override
std::string getGamepadMappingString(const std::string &guid) const override
Pad * addJoystick(int deviceindex) override
Open a device by SDL device index; returns null on failure.
void loadGamepadMappings(const std::string &mappings) override
Load SDL GameController mapping database (newline-separated).
int getIndex(const eve::joystick::Pad *pad) override
Pad * getJoystick(int joyindex) override
Pad * getJoystickFromID(int instanceid) override
SDL 手柄/摇杆后端实现(含 GameController 与振动)。
bool isGamepad() const override
bool open(int deviceindex) override
std::string getGUID() const override
void * getHandle() const override