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; 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) bool InputConfig::isMappedTo(const std::string& name, Input input)
{ {
Input comp; Input comp;

View file

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

View file

@ -142,7 +142,7 @@ void InputManager::removeJoystickByJoystickID(SDL_JoystickID joyId)
mJoysticks.erase(joyIt); mJoysticks.erase(joyIt);
} }
else { 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()) if (!initialized())
return; return;
for (auto iter = mJoysticks.cbegin(); iter != mJoysticks.cend(); iter++) for (auto it = mJoysticks.cbegin(); it != mJoysticks.cend(); it++)
SDL_JoystickClose(iter->second); SDL_JoystickClose(it->second);
mJoysticks.clear(); mJoysticks.clear();
for (auto iter = mInputConfigs.cbegin(); iter != mInputConfigs.cend(); iter++) for (auto it = mInputConfigs.cbegin(); it != mInputConfigs.cend(); it++)
delete iter->second; delete it->second;
mInputConfigs.clear(); mInputConfigs.clear();
for (auto iter = mPrevAxisValues.cbegin(); iter != mPrevAxisValues.cend(); iter++) for (auto it = mPrevAxisValues.cbegin(); it != mPrevAxisValues.cend(); it++)
delete[] iter->second; delete[] it->second;
mPrevAxisValues.clear(); mPrevAxisValues.clear();
if (mKeyboardInputConfig != nullptr) { if (mKeyboardInputConfig != nullptr) {
@ -191,11 +191,11 @@ int InputManager::getButtonCountByDevice(SDL_JoystickID id)
if (id == DEVICE_KEYBOARD) if (id == DEVICE_KEYBOARD)
return 120; // It's a lot, okay. return 120; // It's a lot, okay.
else if (id == DEVICE_CEC) else if (id == DEVICE_CEC)
#ifdef HAVE_CECLIB #ifdef HAVE_CECLIB
return CEC::CEC_USER_CONTROL_CODE_MAX; return CEC::CEC_USER_CONTROL_CODE_MAX;
#else // HAVE_LIBCEF #else // HAVE_LIBCEF
return 0; return 0;
#endif // HAVE_CECLIB #endif // HAVE_CECLIB
else else
return SDL_JoystickNumButtons(mJoysticks[id]); return SDL_JoystickNumButtons(mJoysticks[id]);
} }
@ -213,26 +213,40 @@ InputConfig* InputManager::getInputConfigByDevice(int device)
bool InputManager::parseEvent(const SDL_Event& ev, Window* window) bool InputManager::parseEvent(const SDL_Event& ev, Window* window)
{ {
bool causedEvent = false; bool causedEvent = false;
int32_t axisValue;
switch (ev.type) { switch (ev.type) {
case SDL_JOYAXISMOTION: case SDL_JOYAXISMOTION:
// If it switched boundaries. axisValue = ev.jaxis.value;
if ((abs(ev.jaxis.value) > DEADZONE) != // 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)) { (abs(mPrevAxisValues[ev.jaxis.which][ev.jaxis.axis]) > DEADZONE)) {
int normValue; int normValue;
if (abs(ev.jaxis.value) <= DEADZONE) if (abs(axisValue) <= DEADZONE) {
normValue = 0; normValue = 0;
else }
if (ev.jaxis.value > 0) else {
if (axisValue > 0)
normValue = 1; normValue = 1;
else else
normValue = -1; normValue = -1;
}
window->input(getInputConfigByDevice(ev.jaxis.which), Input(ev.jaxis.which, window->input(getInputConfigByDevice(ev.jaxis.which), Input(ev.jaxis.which,
TYPE_AXIS, ev.jaxis.axis, normValue, false)); TYPE_AXIS, ev.jaxis.axis, normValue, false));
causedEvent = true; causedEvent = true;
} }
mPrevAxisValues[ev.jaxis.which][ev.jaxis.axis] = ev.jaxis.value; mPrevAxisValues[ev.jaxis.which][ev.jaxis.axis] = axisValue;
return causedEvent; return causedEvent;
case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONDOWN:

View file

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