[SDL] Log controller GUIDs and their mapping

This commit is contained in:
Adrian 2024-03-17 23:58:31 +00:00 committed by Radosław Gliński
parent 61ea486481
commit 6e13258ad4
4 changed files with 94 additions and 25 deletions

3
.gitmodules vendored
View File

@ -94,3 +94,6 @@
[submodule "third_party/tabulate"]
path = third_party/tabulate
url = https://github.com/p-ranav/tabulate.git
[submodule "third_party/rapidcsv"]
path = third_party/rapidcsv
url = https://github.com/d99kris/rapidcsv

View File

@ -111,36 +111,87 @@ X_STATUS SDLInputDriver::Setup() {
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) < 0) {
return;
}
sdl_gamecontroller_initialized_ = true;
if (!cvars::mappings_file.empty()) {
if (!std::filesystem::exists(cvars::mappings_file)) {
XELOGW("SDL GameControllerDB: file '{}' does not exist.",
xe::path_to_utf8(cvars::mappings_file));
} else {
auto mappings_file = filesystem::OpenFile(cvars::mappings_file, "rb");
if (!mappings_file) {
XELOGE("SDL GameControllerDB: failed to open file '{}'.",
xe::path_to_utf8(cvars::mappings_file));
} else {
auto mappings_result = SDL_GameControllerAddMappingsFromRW(
SDL_RWFromFP(mappings_file, SDL_TRUE), 1);
if (mappings_result < 0) {
XELOGE("SDL GameControllerDB: error loading file '{}': {}.",
xe::path_to_utf8(cvars::mappings_file), mappings_result);
} else {
XELOGI("SDL GameControllerDB: loaded {} mappings.",
mappings_result);
}
}
}
}
LoadGameControllerDB();
});
return (sdl_events_initialized_ && sdl_gamecontroller_initialized_)
? X_STATUS_SUCCESS
: X_STATUS_UNSUCCESSFUL;
}
void SDLInputDriver::LoadGameControllerDB() {
if (cvars::mappings_file.empty()) {
return;
}
if (!std::filesystem::exists(cvars::mappings_file)) {
XELOGW("SDL GameControllerDB: file '{}' does not exist.",
xe::path_to_utf8(cvars::mappings_file));
return;
}
XELOGI("SDL GameControllerDB: Loading {}",
xe::path_to_utf8(cvars::mappings_file));
uint32_t updated_mappings = 0;
uint32_t added_mappings = 0;
rapidcsv::Document mappings(
xe::path_to_utf8(cvars::mappings_file), rapidcsv::LabelParams(-1, -1),
rapidcsv::SeparatorParams(), rapidcsv::ConverterParams(),
rapidcsv::LineReaderParams(true /* pSkipCommentLines */,
'#' /* pCommentPrefix */,
true /* pSkipEmptyLines */));
for (size_t i = 0; i < mappings.GetRowCount(); i++) {
std::vector<std::string> row = mappings.GetRow<std::string>(i);
if (row.size() < 2) {
continue;
}
std::string guid = row[0];
std::string controller_name = row[1];
auto format = [](std::string& ss, std::string& s) {
return ss.empty() ? s : ss + "," + s;
};
std::string mapping_str =
std::accumulate(row.begin(), row.end(), std::string{}, format);
int updated = SDL_GameControllerAddMapping(mapping_str.c_str());
switch (updated) {
case 0: {
XELOGI("SDL GameControllerDB: Updated {}, {}", controller_name, guid);
updated_mappings++;
} break;
case 1: {
added_mappings++;
} break;
default:
XELOGW("SDL GameControllerDB: error loading mapping '{}'", mapping_str);
break;
}
}
for (uint32_t i = 0; i < HID_SDL_USER_COUNT; i++) {
auto controller = GetControllerState(i);
if (controller) {
XELOGI("SDL Controller {}: {}", i,
SDL_GameControllerMapping(controller->sdl));
}
}
XELOGI("SDL GameControllerDB: Updated {} mappings.", updated_mappings);
XELOGI("SDL GameControllerDB: Added {} mappings.", added_mappings);
}
X_RESULT SDLInputDriver::GetCapabilities(uint32_t user_index, uint32_t flags,
X_INPUT_CAPABILITIES* out_caps) {
assert(sdl_events_initialized_ && sdl_gamecontroller_initialized_);
@ -419,12 +470,20 @@ void SDLInputDriver::OnControllerDeviceAdded(const SDL_Event& event) {
assert_always();
return;
}
char guid_str[33];
SDL_JoystickGetGUIDString(
SDL_JoystickGetGUID(SDL_GameControllerGetJoystick(controller)), guid_str,
33);
XELOGI(
"SDL OnControllerDeviceAdded: \"{}\", "
"JoystickType({}), "
"GameControllerType({}), "
"VendorID(0x{:04X}), "
"ProductID(0x{:04X})",
"ProductID(0x{:04X}), "
"GUID({})",
SDL_GameControllerName(controller),
SDL_JoystickGetType(SDL_GameControllerGetJoystick(controller)),
#if SDL_VERSION_ATLEAST(2, 0, 12)
@ -434,10 +493,11 @@ void SDLInputDriver::OnControllerDeviceAdded(const SDL_Event& event) {
#endif
#if SDL_VERSION_ATLEAST(2, 0, 6)
SDL_GameControllerGetVendor(controller),
SDL_GameControllerGetProduct(controller));
SDL_GameControllerGetProduct(controller),
#else
"?", "?");
"?", "?",
#endif
guid_str);
int user_id = -1;
#if SDL_VERSION_ATLEAST(2, 0, 9)
// Check if the controller has a player index LED.
@ -468,6 +528,8 @@ void SDLInputDriver::OnControllerDeviceAdded(const SDL_Event& event) {
UpdateXCapabilities(state);
XELOGI("SDL OnControllerDeviceAdded: Added at index {}.", user_id);
XELOGI("SDL Controller {}: {}", user_id,
SDL_GameControllerMapping(controller));
} else {
// No more controllers needed, close it.
SDL_GameControllerClose(controller);

View File

@ -16,6 +16,7 @@
#include <optional>
#include "SDL.h"
#include "third_party/rapidcsv/src/rapidcsv.h"
#include "xenia/hid/input_driver.h"
#define HID_SDL_USER_COUNT 4
@ -35,6 +36,8 @@ class SDLInputDriver final : public InputDriver {
X_STATUS Setup() override;
void LoadGameControllerDB();
X_RESULT GetCapabilities(uint32_t user_index, uint32_t flags,
X_INPUT_CAPABILITIES* out_caps) override;
X_RESULT GetState(uint32_t user_index, X_INPUT_STATE* out_state) override;

1
third_party/rapidcsv vendored Submodule

@ -0,0 +1 @@
Subproject commit 7e87d8cac42a03c323d06c8414d2afddd21788f2