Improved the trigger button handling and made it work (somehow) on Windows.

There are still some issues on Windows, especially with Dual Shock controllers, but a larger rewrite is required anyway of the input handling so it's not worthwhile trying to fix it at this time.
This commit is contained in:
Leon Styhre 2020-07-24 18:24:04 +02:00
parent a90fb33cc7
commit dc4870f543
4 changed files with 70 additions and 38 deletions

View file

@ -96,6 +96,15 @@ bool InputConfig::getInputByName(const std::string& name, Input* result)
return false;
}
int InputConfig::getInputIDByName(const std::string& name)
{
auto it = mNameMap.find(toLower(name));
if (it != mNameMap.cend()) {
return it->second.id;
}
return -1;
}
bool InputConfig::isMappedTo(const std::string& name, Input input)
{
Input comp;

View file

@ -142,6 +142,7 @@ public:
// Returns true if there is an Input mapped to this name, false otherwise.
// Writes Input mapped to this name to result if true.
bool getInputByName(const std::string& name, Input* result);
int getInputIDByName(const std::string& name);
void loadFromXML(pugi::xml_node& root);
void writeToXML(pugi::xml_node& parent);

View file

@ -142,7 +142,7 @@ void InputManager::removeJoystickByJoystickID(SDL_JoystickID joyId)
mJoysticks.erase(joyIt);
}
else {
LOG(LogError) << "Could not find joystick to close (instance ID: " << joyId << ")";
LOG(LogError) << "Error - Could not find joystick to close (instance ID: " << joyId << ")";
}
}
@ -151,16 +151,16 @@ void InputManager::deinit()
if (!initialized())
return;
for (auto iter = mJoysticks.cbegin(); iter != mJoysticks.cend(); iter++)
SDL_JoystickClose(iter->second);
for (auto it = mJoysticks.cbegin(); it != mJoysticks.cend(); it++)
SDL_JoystickClose(it->second);
mJoysticks.clear();
for (auto iter = mInputConfigs.cbegin(); iter != mInputConfigs.cend(); iter++)
delete iter->second;
for (auto it = mInputConfigs.cbegin(); it != mInputConfigs.cend(); it++)
delete it->second;
mInputConfigs.clear();
for (auto iter = mPrevAxisValues.cbegin(); iter != mPrevAxisValues.cend(); iter++)
delete[] iter->second;
for (auto it = mPrevAxisValues.cbegin(); it != mPrevAxisValues.cend(); it++)
delete[] it->second;
mPrevAxisValues.clear();
if (mKeyboardInputConfig != nullptr) {
@ -191,11 +191,11 @@ int InputManager::getButtonCountByDevice(SDL_JoystickID id)
if (id == DEVICE_KEYBOARD)
return 120; // It's a lot, okay.
else if (id == DEVICE_CEC)
#ifdef HAVE_CECLIB
#ifdef HAVE_CECLIB
return CEC::CEC_USER_CONTROL_CODE_MAX;
#else // HAVE_LIBCEF
#else // HAVE_LIBCEF
return 0;
#endif // HAVE_CECLIB
#endif // HAVE_CECLIB
else
return SDL_JoystickNumButtons(mJoysticks[id]);
}
@ -213,26 +213,40 @@ InputConfig* InputManager::getInputConfigByDevice(int device)
bool InputManager::parseEvent(const SDL_Event& ev, Window* window)
{
bool causedEvent = false;
int32_t axisValue;
switch (ev.type) {
case SDL_JOYAXISMOTION:
// If it switched boundaries.
if ((abs(ev.jaxis.value) > DEADZONE) !=
axisValue = ev.jaxis.value;
// For the analog trigger buttons, convert the negative<->positive axis values to only
// positive values in order to avoid registering double inputs. This is only a
// temporary solution until ES has been updated to use the SDL GameController API.
if (ev.jaxis.axis == mInputConfigs[ev.jaxis.which]->getInputIDByName("lefttrigger") ||
ev.jaxis.axis == mInputConfigs[ev.jaxis.which]->getInputIDByName("righttrigger")) {
axisValue += 32768;
axisValue /= 2;
}
// Check if the input value switched boundaries.
if ((abs(axisValue) > DEADZONE) !=
(abs(mPrevAxisValues[ev.jaxis.which][ev.jaxis.axis]) > DEADZONE)) {
int normValue;
if (abs(ev.jaxis.value) <= DEADZONE)
if (abs(axisValue) <= DEADZONE) {
normValue = 0;
else
if (ev.jaxis.value > 0)
}
else {
if (axisValue > 0)
normValue = 1;
else
normValue = -1;
}
window->input(getInputConfigByDevice(ev.jaxis.which), Input(ev.jaxis.which,
TYPE_AXIS, ev.jaxis.axis, normValue, false));
causedEvent = true;
}
mPrevAxisValues[ev.jaxis.which][ev.jaxis.axis] = ev.jaxis.value;
mPrevAxisValues[ev.jaxis.which][ev.jaxis.axis] = axisValue;
return causedEvent;
case SDL_JOYBUTTONDOWN:

View file

@ -380,26 +380,35 @@ bool GuiInputConfig::filterTrigger(Input input, InputConfig* config, int inputId
#if defined(__linux__)
// On Linux, some gamepads return both an analog axis and a digital button for the trigger;
// we want the analog axis only, so this function removes the button press event.
if ((
// Match PlayStation joystick with 6 axes only.
strstr(config->getDeviceName().c_str(), "PLAYSTATION") != nullptr ||
strstr(config->getDeviceName().c_str(), "PS3 Ga") != nullptr ||
strstr(config->getDeviceName().c_str(), "PS(R) Ga") != nullptr ||
// BigBen kid's PS3 gamepad 146b:0902, matched on SDL GUID because its name "Bigben
// Interactive Bigben Game Pad" may be too generic.
strcmp(config->getDeviceGUIDString().c_str(), "030000006b1400000209000011010000") == 0)
&& InputManager::getInstance()->getAxisCountByDevice(config->getDeviceId()) == 6) {
// Digital triggers are unwanted.
if (input.type == TYPE_BUTTON && (input.id == 6 || input.id == 7)) {
mHoldingInput = false;
return true;
// This is relevant mostly for Sony Dual Shock controllers.
if (InputManager::getInstance()->getAxisCountByDevice(config->getDeviceId()) == 6) {
if (config->getDeviceName().find("PLAYSTATION") != std::string::npos ||
config->getDeviceName().find("PS3 Ga") != std::string::npos ||
config->getDeviceName().find("PS(R) Ga") != std::string::npos ||
config->getDeviceName().find("PS4 Controller") != std::string::npos ||
config->getDeviceName().find("Sony Interactive") != std::string::npos ||
// BigBen kid's PS3 gamepad 146b:0902, matched on SDL GUID because its name
// "Bigben Interactive Bigben Game Pad" may be too generic.
config->getDeviceGUIDString().find("030000006b1400000209000011010000")
!= std::string::npos ) {
// Remove digital trigger events.
if (input.type == TYPE_BUTTON && (input.id == 6 || input.id == 7)) {
mHoldingInput = false;
return true;
}
}
}
#endif
// Ignore negative pole for axes 2/5 only when triggers are being configured.
if (input.type == TYPE_AXIS && (input.id == 2 || input.id == 5)) {
if (strstr(GUI_INPUT_CONFIG_LIST[inputId].name, "Trigger") != nullptr) {
// Ignore negative poles when triggers are being configured.
// This is not a good solution as it's hardcoded to input 2 and 5 (Xbox controllers) and
// input 4 and 5 (Playstation Dual Shock controllers) instead of using a general detection
// for which type of axis input is used. This is also hardcoded to only work when configuring
// the trigger buttons, so it will not be possible to map trigger buttons to the shoulder
// button functions in ES for instance. It's probably necessary to update ES to use the SDL
// GameController API to fix this properly.
if (input.type == TYPE_AXIS && (input.id == 2 || input.id == 4 || input.id == 5)) {
if (std::string(GUI_INPUT_CONFIG_LIST[inputId].name).find("Trigger") != std::string::npos) {
if (input.value == 1)
mSkipAxis = true;
else if (input.value == -1)
@ -410,11 +419,10 @@ bool GuiInputConfig::filterTrigger(Input input, InputConfig* config, int inputId
return true;
}
}
#else
(void)input;
(void)config;
(void)inputId;
#endif
// (void)input;
// (void)config;
// (void)inputId;
return false;
}