mirror of
https://github.com/patchzyy/wiicompiled
synced 2026-10-20 21:49:51 -04:00
Support Linux Wii controller mappings
This commit is contained in:
@@ -195,7 +195,7 @@ std::array<PADButtonMapping, PAD_BUTTON_COUNT> g_defaultButtonsJoyPair{{
|
||||
}};
|
||||
|
||||
// Wii U Pro Controllers through SDL's HIDAPI Wii driver. No SDL_GamepadType
|
||||
// singles them out, so they are picked by the name the driver gives them (see
|
||||
// singles them out, so they are picked by name or USB id (see
|
||||
// __PADSetDefaultMapping). Wii Remotes, with or without a Nunchuk or Classic
|
||||
// Controller, are read by the game through KPAD instead and never get a
|
||||
// GameCube mapping (the runtime hides those ports from PADRead).
|
||||
@@ -451,11 +451,14 @@ static void reset_alt_button_mapping(aurora::input::GameController* controller)
|
||||
|
||||
// SDL's hidapi Wii driver names the pad "Nintendo Wii U Pro Controller"; the
|
||||
// other names it produces are Wii Remotes, which the game reads through KPAD
|
||||
// and which therefore never take a GameCube mapping.
|
||||
// and which therefore never take a GameCube mapping. The Linux kernel driver's
|
||||
// "Nintendo Wii Remote Pro Controller" is only recognised by its USB id.
|
||||
static bool wii_default_mapping(const aurora::input::GameController* controller,
|
||||
std::array<PADButtonMapping, PAD_BUTTON_COUNT>& out) {
|
||||
const char* name = SDL_GetGamepadName(controller->m_controller);
|
||||
if (name == nullptr || SDL_strstr(name, "Wii U Pro Controller") == nullptr) {
|
||||
const bool wiiUProId = SDL_GetGamepadVendor(controller->m_controller) == 0x057e &&
|
||||
SDL_GetGamepadProduct(controller->m_controller) == 0x0330;
|
||||
if (!wiiUProId && (name == nullptr || SDL_strstr(name, "Wii U Pro Controller") == nullptr)) {
|
||||
return false;
|
||||
}
|
||||
out = g_defaultButtonsWiiUPro;
|
||||
|
||||
@@ -790,6 +790,12 @@ void DrawControllerSettings() {
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (WiiRemoteInput::IsRemoteChannel(selectedGamePort)) {
|
||||
ImGui::TextDisabled("The game reads this controller as a Wii Remote, so the button mapping does not apply.");
|
||||
DrawRumbleSettings();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t mappingCount = 0;
|
||||
PADButtonMapping* mappings = PADGetButtonMappings(static_cast<uint32_t>(g_controllerPort), &mappingCount);
|
||||
if (mappings == nullptr || mappingCount != PAD_BUTTON_COUNT) {
|
||||
|
||||
@@ -63,6 +63,8 @@ constexpr uint32_t kClUp = 0x0001, kClLeft = 0x0002, kClZR = 0x0004, kClX = 0x00
|
||||
kClB = 0x0040, kClZL = 0x0080, kClR = 0x0200, kClPlus = 0x0400, kClHome = 0x0800,
|
||||
kClMinus = 0x1000, kClL = 0x2000, kClDown = 0x4000, kClRight = 0x8000;
|
||||
|
||||
constexpr Uint16 kNintendoVendor = 0x057e;
|
||||
|
||||
// How long a vanished remote keeps its channel alive with neutral input. SDL's
|
||||
// in-place reconnect after an extension change takes well under a second; a
|
||||
// remote that is really gone shows up as disconnected after this.
|
||||
@@ -86,6 +88,7 @@ bool g_scanning = false;
|
||||
uint64_t g_driverOffSinceMs = 0;
|
||||
// When the current scan started (last Wii controller seen).
|
||||
uint64_t g_lostAtMs = 0;
|
||||
bool g_hidrawWarned = false;
|
||||
|
||||
// Instance ids whose accelerometers have been switched on. SDL keeps sensors
|
||||
// off until asked and forgets that when the gamepad is closed, so a re-paired
|
||||
@@ -346,6 +349,40 @@ bool AnyWiiControllerConnected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// True for an evdev node served by the kernel hid-wiimote driver.
|
||||
bool IsKernelWiiNode(SDL_JoystickID id) {
|
||||
const char* path = SDL_GetGamepadPathForID(id);
|
||||
return SDL_GetGamepadVendorForID(id) == kNintendoVendor && path != nullptr &&
|
||||
std::strncmp(path, "/dev/input/", 11) == 0;
|
||||
}
|
||||
|
||||
// Logs once when the kernel driver serves a Wii controller SDL's driver could have had.
|
||||
void WarnIfKernelDriverServing() {
|
||||
if (g_hidrawWarned || !g_wiiDriverEnabled) {
|
||||
return;
|
||||
}
|
||||
const uint64_t now = SDL_GetTicks();
|
||||
static uint64_t s_nextCheckMs = 0;
|
||||
if (now < s_nextCheckMs) {
|
||||
return;
|
||||
}
|
||||
s_nextCheckMs = now + 2000;
|
||||
int count = 0;
|
||||
SDL_JoystickID* ids = SDL_GetGamepads(&count);
|
||||
if (ids == nullptr) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < count && !g_hidrawWarned; ++i) {
|
||||
const Uint16 product = SDL_GetGamepadProductForID(ids[i]);
|
||||
if ((product == 0x0306 || product == 0x0330) && IsKernelWiiNode(ids[i])) {
|
||||
g_hidrawWarned = true;
|
||||
RT_LOG(RT_TAG_CONFIG) << "A Wii controller is served by the kernel hid-wiimote driver. For full Wii "
|
||||
<< "Remote support see the Linux udev rule in the README." << std::endl;
|
||||
}
|
||||
}
|
||||
SDL_free(ids);
|
||||
}
|
||||
|
||||
// Route SDL's input diagnostics (HIDAPI open failures, the Wii driver's
|
||||
// extension/status messages) into console.log, minus the periodic chatter.
|
||||
// A sub-warning message is written once: SDL repeats the same line on every
|
||||
@@ -464,6 +501,7 @@ void Poll() {
|
||||
for (uint32_t port = 0; port < PAD_MAX_CONTROLLERS; ++port) {
|
||||
(void)EffectiveKind(port);
|
||||
}
|
||||
WarnIfKernelDriverServing();
|
||||
if (!g_wiiDriverEnabled) {
|
||||
return;
|
||||
}
|
||||
@@ -518,11 +556,13 @@ uint32_t ScanCount() {
|
||||
return g_scanCount;
|
||||
}
|
||||
|
||||
// Maps the gamepad name SDL's Wii driver reports to a Kind.
|
||||
// Maps the gamepad name SDL reports to a Kind: "Nintendo Wii Remote",
|
||||
// "... with Nunchuk", "... with Classic Controller" and "Nintendo Wii U Pro
|
||||
// Controller" from SDL's Wii driver; the Linux kernel's "Nintendo Wii Remote
|
||||
// Classic Controller" is read like the Classic Controller.
|
||||
Kind KindForName(const char* name) {
|
||||
// Names come from SDL's hidapi Wii driver: "Nintendo Wii Remote",
|
||||
// "Nintendo Wii Remote with Nunchuk", "Nintendo Wii Remote with Classic
|
||||
// Controller" and "Nintendo Wii U Pro Controller".
|
||||
// The kernel's Pro Controller is a plain gamepad with a built-in SDL mapping.
|
||||
if (NameContains(name, "Wii Remote Pro Controller")) return Kind::NotWii;
|
||||
if (NameContains(name, "Wii U Pro Controller")) return Kind::WiiUPro;
|
||||
if (!NameContains(name, "Wii Remote")) return Kind::NotWii;
|
||||
if (NameContains(name, "Nunchuk")) return Kind::RemoteWithNunchuk;
|
||||
@@ -674,8 +714,12 @@ bool ReadKpadSample(uint32_t chan, KpadSample& sample) {
|
||||
// Home, the L/R clicks as shoulders, the D-pad as buttons 11-14 (never
|
||||
// through SDL's gamepad mapping, which expects a hat), ZL/ZR as the
|
||||
// trigger axes.
|
||||
const auto cl = [&](int index, uint32_t bit) {
|
||||
if (SDL_GetJoystickButton(joystick, index)) sample.clHold |= bit;
|
||||
// The kernel's evdev node has a regular SDL mapping, so it is read as a gamepad.
|
||||
const bool mapped = IsKernelWiiNode(SDL_GetGamepadID(gamepad));
|
||||
const auto cl = [&](SDL_GamepadButton button, uint32_t bit) {
|
||||
if (mapped ? SDL_GetGamepadButton(gamepad, button) : SDL_GetJoystickButton(joystick, button)) {
|
||||
sample.clHold |= bit;
|
||||
}
|
||||
};
|
||||
cl(SDL_GAMEPAD_BUTTON_EAST, kClA);
|
||||
cl(SDL_GAMEPAD_BUTTON_SOUTH, kClB);
|
||||
|
||||
Reference in New Issue
Block a user