mirror of
https://github.com/izzy2lost/Super3.git
synced 2026-07-05 15:18:38 -07:00
Add more controller support
This commit is contained in:
@@ -58,6 +58,9 @@ AddressOut = "127.0.0.1"
|
||||
; absolute positioning when enabled, ideal for using Lightguns.
|
||||
ABSMiceOnly = false
|
||||
|
||||
; Optional SDL GameController mapping database (used by `-input-system=sdlgamepad` and by the Android port).
|
||||
; SDLGameControllerDB = "Config/gamecontrollerdb.txt"
|
||||
|
||||
; Common
|
||||
InputUIExit = "JOY1_BUTTON10+JOY1_BUTTON9"
|
||||
InputUIPause = "JOY1_BUTTON9+JOY1_BUTTON4"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
param(
|
||||
[string]$SourceUrl = "https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Write-DbFile([string]$Path, [string]$Content) {
|
||||
$dir = Split-Path -Parent $Path
|
||||
if ($dir -and !(Test-Path $dir)) { New-Item -ItemType Directory -Force -Path $dir | Out-Null }
|
||||
|
||||
# SDL's parser is happiest with UTF-8 without BOM.
|
||||
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
|
||||
[System.IO.File]::WriteAllText($Path, $Content, $utf8NoBom)
|
||||
$bytes = $utf8NoBom.GetByteCount($Content)
|
||||
Write-Host ("Wrote {0} ({1} bytes)" -f $Path, $bytes)
|
||||
}
|
||||
|
||||
Write-Host ("Downloading SDL_GameControllerDB from {0}..." -f $SourceUrl)
|
||||
$headers = @{ "User-Agent" = "Super3-update-gamecontrollerdb" }
|
||||
$irm = Get-Command Invoke-RestMethod -ErrorAction Stop
|
||||
if ($irm.Parameters.ContainsKey("UseBasicParsing")) {
|
||||
$db = Invoke-RestMethod -UseBasicParsing -Uri $SourceUrl -Headers $headers
|
||||
} else {
|
||||
$db = Invoke-RestMethod -Uri $SourceUrl -Headers $headers
|
||||
}
|
||||
$db = [string]$db
|
||||
if (-not $db -or $db.Length -lt 1000) {
|
||||
throw "Downloaded database looks too small; aborting."
|
||||
}
|
||||
|
||||
$stamp = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
|
||||
$header = @(
|
||||
"# Super3 snapshot of SDL_GameControllerDB"
|
||||
("# Source: {0}" -f $SourceUrl)
|
||||
("# Updated: {0}" -f $stamp)
|
||||
""
|
||||
) -join "`n"
|
||||
|
||||
$content = $header + $db.TrimEnd() + "`n"
|
||||
|
||||
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||
Write-DbFile (Join-Path $repoRoot "Config/gamecontrollerdb.txt") $content
|
||||
Write-DbFile (Join-Path $repoRoot "android/app/src/main/assets/Config/gamecontrollerdb.txt") $content
|
||||
|
||||
Write-Host "Done."
|
||||
@@ -36,12 +36,30 @@
|
||||
#include "Inputs/Manymouse.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
static int available_mice = 1;
|
||||
static ManyMouseEvent mm_event;
|
||||
|
||||
static void TryLoadGameControllerMappings(const Util::Config::Node& config)
|
||||
{
|
||||
std::string mappingsPath = config["SDLGameControllerDB"].ValueAsDefault<std::string>("");
|
||||
if (mappingsPath.empty())
|
||||
mappingsPath = "Config/gamecontrollerdb.txt";
|
||||
|
||||
SDL_RWops* rw = SDL_RWFromFile(mappingsPath.c_str(), "rb");
|
||||
if (rw == nullptr)
|
||||
return;
|
||||
|
||||
const int added = SDL_GameControllerAddMappingsFromRW(rw, 1);
|
||||
if (added > 0)
|
||||
InfoLog("Loaded %d SDL game controller mappings from %s\n", added, mappingsPath.c_str());
|
||||
else if (added < 0)
|
||||
ErrorLog("Failed to load SDL game controller mappings from %s (%s)\n", mappingsPath.c_str(), SDL_GetError());
|
||||
}
|
||||
|
||||
SDLKeyMapStruct CSDLInputSystem::s_keyMap[] =
|
||||
{
|
||||
// General keys
|
||||
@@ -209,8 +227,22 @@ void CSDLInputSystem::OpenJoysticks()
|
||||
|
||||
if (m_useGameController)
|
||||
{
|
||||
gamepad = SDL_GameControllerOpen(joyNum);
|
||||
joystick = SDL_GameControllerGetJoystick(gamepad);
|
||||
if (!SDL_IsGameController(joyNum))
|
||||
{
|
||||
DebugLog("SDL joystick %d ('%s') is not recognized as a game controller (add mapping to Config/gamecontrollerdb.txt or use -input-system=sdl).\n",
|
||||
joyNum + 1,
|
||||
SDL_JoystickNameForIndex(joyNum) ? SDL_JoystickNameForIndex(joyNum) : "Unknown");
|
||||
continue;
|
||||
}
|
||||
|
||||
gamepad = SDL_GameControllerOpen(joyNum);
|
||||
if (gamepad == nullptr)
|
||||
{
|
||||
ErrorLog("Unable to open SDL game controller device %d (%s) - skipping controller.\n", joyNum + 1, SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
joystick = SDL_GameControllerGetJoystick(gamepad);
|
||||
} else
|
||||
{
|
||||
joystick = SDL_JoystickOpen(joyNum);
|
||||
@@ -218,6 +250,8 @@ void CSDLInputSystem::OpenJoysticks()
|
||||
|
||||
if (joystick == nullptr)
|
||||
{
|
||||
if (m_useGameController && gamepad != nullptr)
|
||||
SDL_GameControllerClose(gamepad);
|
||||
ErrorLog("Unable to open joystick device %d with SDL - skipping joystick.\n", joyNum + 1);
|
||||
continue;
|
||||
}
|
||||
@@ -233,7 +267,7 @@ void CSDLInputSystem::OpenJoysticks()
|
||||
joyDetails.name[MAX_NAME_LENGTH] = '\0';
|
||||
joyDetails.numAxes = 6;
|
||||
joyDetails.numPOVs = 4;
|
||||
joyDetails.numButtons = 16;
|
||||
joyDetails.numButtons = 17;
|
||||
} else
|
||||
{
|
||||
const char *pName = SDL_JoystickName(joystick);
|
||||
@@ -405,7 +439,8 @@ void CSDLInputSystem::OpenJoysticks()
|
||||
void CSDLInputSystem::CloseJoysticks()
|
||||
{
|
||||
// Close all previously opened joysticks
|
||||
for (int i = 0; i < GetNumJoysticks(); i++)
|
||||
const int numJoys = GetNumJoysticks();
|
||||
for (int i = 0; i < numJoys; i++)
|
||||
{
|
||||
JoyDetails joyDetails = m_joyDetails[i];
|
||||
if (joyDetails.hasFFeedback)
|
||||
@@ -426,14 +461,14 @@ void CSDLInputSystem::CloseJoysticks()
|
||||
{
|
||||
SDL_GameController *gamepad = m_gamepads[i];
|
||||
SDL_GameControllerClose(gamepad);
|
||||
m_gamepads.clear();
|
||||
} else {
|
||||
SDL_Joystick *joystick = m_joysticks[i];
|
||||
SDL_JoystickClose(joystick);
|
||||
m_joysticks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
m_gamepads.clear();
|
||||
m_joysticks.clear();
|
||||
m_joyDetails.clear();
|
||||
m_SDLHapticDatas.clear();
|
||||
|
||||
@@ -459,6 +494,7 @@ bool CSDLInputSystem::InitializeSystem()
|
||||
ErrorLog("Unable to initialize SDL joystick subsystem (%s).\n", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
TryLoadGameControllerMappings(m_config);
|
||||
SDL_GameControllerEventState(SDL_ENABLE);
|
||||
} else {
|
||||
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) != 0)
|
||||
|
||||
@@ -36,6 +36,9 @@ New3DAccurate = 0
|
||||
; Input system (Android uses SDL input backend)
|
||||
InputSystem = sdl
|
||||
|
||||
; Optional SDL GameController mapping database.
|
||||
; SDLGameControllerDB = "Config/gamecontrollerdb.txt"
|
||||
|
||||
; Touch defaults:
|
||||
; - bottom-left: Coin1
|
||||
; - bottom-right: Start1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -143,6 +143,15 @@ void AndroidInputSystem::ApplyConfig(const Util::Config::Node& config)
|
||||
return config[key].ValueAsDefault<std::string>(fallback);
|
||||
};
|
||||
|
||||
{
|
||||
const std::string newPath = config["SDLGameControllerDB"].ValueAsDefault<std::string>("");
|
||||
if (newPath != m_gameControllerMappingsPath)
|
||||
{
|
||||
m_gameControllerMappingsPath = newPath;
|
||||
m_gameControllerMappingsLoaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
m_gunAutoTrigger = config["InputAutoTrigger"].ValueAsDefault<unsigned>(0) != 0;
|
||||
|
||||
auto keySc = [&](const std::string& mapping, SDL_Scancode fallback) -> SDL_Scancode {
|
||||
@@ -217,6 +226,28 @@ void AndroidInputSystem::ApplyConfig(const Util::Config::Node& config)
|
||||
m_touchSkiSelect2.a = keySc(get("InputSkiSelect2", "KEY_W"), SDL_SCANCODE_W);
|
||||
}
|
||||
|
||||
void AndroidInputSystem::EnsureGameControllerMappingsLoaded()
|
||||
{
|
||||
if (m_gameControllerMappingsLoaded)
|
||||
return;
|
||||
|
||||
std::string mappingsPath = m_gameControllerMappingsPath;
|
||||
if (mappingsPath.empty())
|
||||
mappingsPath = "Config/gamecontrollerdb.txt";
|
||||
|
||||
SDL_RWops* rw = SDL_RWFromFile(mappingsPath.c_str(), "rb");
|
||||
if (rw != nullptr)
|
||||
{
|
||||
const int added = SDL_GameControllerAddMappingsFromRW(rw, 1);
|
||||
if (added > 0)
|
||||
SDL_Log("Loaded %d SDL game controller mappings from %s", added, mappingsPath.c_str());
|
||||
else if (added < 0)
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load SDL game controller mappings from %s (%s)", mappingsPath.c_str(), SDL_GetError());
|
||||
}
|
||||
|
||||
m_gameControllerMappingsLoaded = true;
|
||||
}
|
||||
|
||||
bool AndroidInputSystem::InitializeSystem()
|
||||
{
|
||||
std::fill(m_keys.begin(), m_keys.end(), 0);
|
||||
@@ -238,6 +269,7 @@ bool AndroidInputSystem::InitializeSystem()
|
||||
m_virtualJoyY = 0;
|
||||
m_lastVirtualGear = -1;
|
||||
|
||||
EnsureGameControllerMappingsLoaded();
|
||||
SDL_GameControllerEventState(SDL_ENABLE);
|
||||
RefreshControllers();
|
||||
return true;
|
||||
@@ -891,15 +923,41 @@ void AndroidInputSystem::RefreshControllers()
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
if (!SDL_IsGameController(i))
|
||||
{
|
||||
const char* name = SDL_JoystickNameForIndex(i);
|
||||
SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(i);
|
||||
char guidStr[64] = {};
|
||||
SDL_JoystickGetGUIDString(guid, guidStr, sizeof(guidStr));
|
||||
SDL_Log("Unmapped joystick %d: %s (guid=%s). Add a mapping to %s to enable it.",
|
||||
i + 1,
|
||||
name ? name : "Unknown",
|
||||
guidStr,
|
||||
m_gameControllerMappingsPath.empty() ? "Config/gamecontrollerdb.txt" : m_gameControllerMappingsPath.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
SDL_GameController* controller = SDL_GameControllerOpen(i);
|
||||
if (!controller)
|
||||
{
|
||||
const char* name = SDL_JoystickNameForIndex(i);
|
||||
SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(i);
|
||||
char guidStr[64] = {};
|
||||
SDL_JoystickGetGUIDString(guid, guidStr, sizeof(guidStr));
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open game controller %d: %s (guid=%s) (%s)",
|
||||
i + 1,
|
||||
name ? name : "Unknown",
|
||||
guidStr,
|
||||
SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
SDL_Joystick* js = SDL_GameControllerGetJoystick(controller);
|
||||
if (!js)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get joystick handle for controller %d: %s (%s)",
|
||||
i + 1,
|
||||
SDL_GameControllerName(controller) ? SDL_GameControllerName(controller) : "GameController",
|
||||
SDL_GetError());
|
||||
SDL_GameControllerClose(controller);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,8 @@ private:
|
||||
bool ButtonPressedFor(const ControllerState& c, int butNum) const;
|
||||
bool PovPressedFor(const ControllerState& c, int povDir) const;
|
||||
|
||||
void EnsureGameControllerMappingsLoaded();
|
||||
|
||||
void SetMouseButton(int butNum, bool down);
|
||||
void PulseMouseButton(int butNum, uint32_t durationMs);
|
||||
void SetMousePosFromNormalized(float x, float y);
|
||||
@@ -205,4 +207,7 @@ private:
|
||||
std::unordered_map<SDL_FingerID, HeldDirKeys> m_fingerHeldDir;
|
||||
std::unordered_map<SDL_FingerID, DualScancode> m_fingerHeldKey;
|
||||
std::unordered_map<SDL_Scancode, uint32_t> m_pulseUntilMs;
|
||||
|
||||
std::string m_gameControllerMappingsPath;
|
||||
bool m_gameControllerMappingsLoaded = false;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user