Add default mapping from sdl controller

Also adjust default non-sdl mapping, maybe now 4 actions in 1 stick
works better...
This commit is contained in:
Benau 2020-04-21 09:46:00 +08:00
parent 2405a3a00c
commit 6db8906adb
3 changed files with 154 additions and 10 deletions

View File

@ -19,6 +19,9 @@
#include "input/gamepad_config.hpp"
#ifdef ANDROID
#include "graphics/irr_driver.hpp"
#endif
#include "io/xml_node.hpp"
#include "utils/log.hpp"
#include "utils/string_utils.hpp"
@ -125,21 +128,21 @@ void GamepadConfig::setDefaultBinds ()
{
setBinding(PA_STEER_LEFT, Input::IT_STICKMOTION, 0, Input::AD_NEGATIVE);
setBinding(PA_STEER_RIGHT, Input::IT_STICKMOTION, 0, Input::AD_POSITIVE);
setBinding(PA_ACCEL, Input::IT_STICKBUTTON, 0, Input::AD_NEGATIVE);
setBinding(PA_BRAKE, Input::IT_STICKBUTTON, 3, Input::AD_POSITIVE);
setBinding(PA_FIRE, Input::IT_STICKBUTTON, 1);
setBinding(PA_NITRO, Input::IT_STICKBUTTON, 4);
setBinding(PA_DRIFT, Input::IT_STICKBUTTON, 5);
setBinding(PA_RESCUE, Input::IT_STICKBUTTON, 8);
setBinding(PA_LOOK_BACK, Input::IT_STICKBUTTON, 6);
setBinding(PA_PAUSE_RACE, Input::IT_STICKBUTTON, 9);
setBinding(PA_ACCEL, Input::IT_STICKMOTION, 1, Input::AD_NEGATIVE);
setBinding(PA_BRAKE, Input::IT_STICKMOTION, 1, Input::AD_POSITIVE);
setBinding(PA_FIRE, Input::IT_STICKBUTTON, 0);
setBinding(PA_NITRO, Input::IT_STICKBUTTON, 1);
setBinding(PA_DRIFT, Input::IT_STICKBUTTON, 2);
setBinding(PA_RESCUE, Input::IT_STICKBUTTON, 3);
setBinding(PA_LOOK_BACK, Input::IT_STICKBUTTON, 4);
setBinding(PA_PAUSE_RACE, Input::IT_STICKBUTTON, 5);
setBinding(PA_MENU_UP, Input::IT_STICKMOTION, 1, Input::AD_NEGATIVE);
setBinding(PA_MENU_DOWN, Input::IT_STICKMOTION, 1, Input::AD_POSITIVE);
setBinding(PA_MENU_LEFT, Input::IT_STICKMOTION, 0, Input::AD_NEGATIVE);
setBinding(PA_MENU_RIGHT, Input::IT_STICKMOTION, 0, Input::AD_POSITIVE);
setBinding(PA_MENU_SELECT, Input::IT_STICKBUTTON, 0);
setBinding(PA_MENU_CANCEL, Input::IT_STICKBUTTON, 3);
setBinding(PA_MENU_SELECT, Input::IT_STICKBUTTON, 6);
setBinding(PA_MENU_CANCEL, Input::IT_STICKBUTTON, 7);
} // setDefaultBinds
//------------------------------------------------------------------------------
@ -433,7 +436,144 @@ void GamepadConfig::initSDLController(const std::string& mapping, int buttons,
#endif
} // initSDLController
// ----------------------------------------------------------------------------
void GamepadConfig::setBindingFromTuple(const PlayerAction action,
std::tuple<int, Input::AxisDirection>& t)
{
#ifndef SERVER_ONLY
int id = std::get<0>(t);
Input::AxisDirection ad = std::get<1>(t);
Input::InputType type = ad ==
Input::AD_NEUTRAL ? Input::IT_STICKBUTTON : Input::IT_STICKMOTION;
setBinding(action, type, id, ad);
#endif
} // setBindingFromTuple
// ----------------------------------------------------------------------------
void GamepadConfig::initSDLMapping()
{
#ifndef SERVER_ONLY
if (m_sdl_mapping.empty())
return;
std::map<int, std::tuple<int, Input::AxisDirection> > actions_map;
for (auto& p : m_sdl_mapping)
actions_map[p.second] = p.first;
bool has_direction = false;
// Some old gamepad map axes to DPad, handle it too
bool use_axes_direction = false;
if (actions_map.find(SDL_CONTROLLER_AXIS_LEFTX_RIGHT) != actions_map.end() &&
actions_map.find(SDL_CONTROLLER_AXIS_LEFTX_LEFT) != actions_map.end() &&
actions_map.find(SDL_CONTROLLER_AXIS_LEFTY_DOWN) != actions_map.end() &&
actions_map.find(SDL_CONTROLLER_AXIS_LEFTY_UP) != actions_map.end())
{
has_direction = true;
use_axes_direction = true;
}
if (actions_map.find(SDL_CONTROLLER_BUTTON_DPAD_UP) != actions_map.end() &&
actions_map.find(SDL_CONTROLLER_BUTTON_DPAD_DOWN) != actions_map.end() &&
actions_map.find(SDL_CONTROLLER_BUTTON_DPAD_LEFT) != actions_map.end() &&
actions_map.find(SDL_CONTROLLER_BUTTON_DPAD_RIGHT) != actions_map.end())
{
has_direction = true;
}
if (!has_direction)
return;
#ifdef ANDROID
// For android tv we default to dpad if it has direction pad, because it
// cannot rebind control using touchscreen, and dpad direction seems more
// reliable
if (!irr_driver->getDevice()->supportsTouchDevice() && has_direction)
use_axes_direction = false;
#endif
if (use_axes_direction)
{
setBindingFromTuple(PA_STEER_LEFT, actions_map.at(SDL_CONTROLLER_AXIS_LEFTX_LEFT));
setBindingFromTuple(PA_STEER_RIGHT, actions_map.at(SDL_CONTROLLER_AXIS_LEFTX_RIGHT));
setBindingFromTuple(PA_ACCEL, actions_map.at(SDL_CONTROLLER_AXIS_LEFTY_UP));
setBindingFromTuple(PA_BRAKE, actions_map.at(SDL_CONTROLLER_AXIS_LEFTY_DOWN));
setBindingFromTuple(PA_MENU_UP, actions_map.at(SDL_CONTROLLER_AXIS_LEFTY_UP));
setBindingFromTuple(PA_MENU_DOWN, actions_map.at(SDL_CONTROLLER_AXIS_LEFTY_DOWN));
setBindingFromTuple(PA_MENU_LEFT, actions_map.at(SDL_CONTROLLER_AXIS_LEFTX_LEFT));
setBindingFromTuple(PA_MENU_RIGHT, actions_map.at(SDL_CONTROLLER_AXIS_LEFTX_RIGHT));
}
else
{
setBindingFromTuple(PA_STEER_LEFT, actions_map.at(SDL_CONTROLLER_BUTTON_DPAD_LEFT));
setBindingFromTuple(PA_STEER_RIGHT, actions_map.at(SDL_CONTROLLER_BUTTON_DPAD_RIGHT));
setBindingFromTuple(PA_ACCEL, actions_map.at(SDL_CONTROLLER_BUTTON_DPAD_UP));
setBindingFromTuple(PA_BRAKE, actions_map.at(SDL_CONTROLLER_BUTTON_DPAD_DOWN));
setBindingFromTuple(PA_MENU_UP, actions_map.at(SDL_CONTROLLER_BUTTON_DPAD_UP));
setBindingFromTuple(PA_MENU_DOWN, actions_map.at(SDL_CONTROLLER_BUTTON_DPAD_DOWN));
setBindingFromTuple(PA_MENU_LEFT, actions_map.at(SDL_CONTROLLER_BUTTON_DPAD_LEFT));
setBindingFromTuple(PA_MENU_RIGHT, actions_map.at(SDL_CONTROLLER_BUTTON_DPAD_RIGHT));
}
// Goto fallback if not all required bindings are found
if (actions_map.find(SDL_CONTROLLER_BUTTON_A) == actions_map.end())
goto fallback;
if (actions_map.find(SDL_CONTROLLER_BUTTON_B) == actions_map.end())
goto fallback;
if (actions_map.find(SDL_CONTROLLER_BUTTON_X) == actions_map.end())
goto fallback;
if (actions_map.find(SDL_CONTROLLER_BUTTON_Y) == actions_map.end())
goto fallback;
if (actions_map.find(SDL_CONTROLLER_BUTTON_BACK) == actions_map.end())
goto fallback;
if (actions_map.find(SDL_CONTROLLER_BUTTON_START) == actions_map.end())
goto fallback;
setBindingFromTuple(PA_FIRE, actions_map.at(SDL_CONTROLLER_BUTTON_B));
setBindingFromTuple(PA_NITRO, actions_map.at(SDL_CONTROLLER_BUTTON_A));
setBindingFromTuple(PA_DRIFT, actions_map.at(SDL_CONTROLLER_BUTTON_X));
setBindingFromTuple(PA_LOOK_BACK, actions_map.at(SDL_CONTROLLER_BUTTON_Y));
setBindingFromTuple(PA_RESCUE, actions_map.at(SDL_CONTROLLER_BUTTON_START));
setBindingFromTuple(PA_PAUSE_RACE, actions_map.at(SDL_CONTROLLER_BUTTON_BACK));
setBindingFromTuple(PA_MENU_SELECT, actions_map.at(SDL_CONTROLLER_BUTTON_B));
setBindingFromTuple(PA_MENU_CANCEL, actions_map.at(SDL_CONTROLLER_BUTTON_BACK));
return;
fallback:
// Bind at least select and cancel so the player can at least toggle menu
// without any binding in the beginning
// This usually happens for android auto-detect controller mapping
setBinding(PA_FIRE, Input::IT_NONE, 0, Input::AD_NEUTRAL);
setBinding(PA_NITRO, Input::IT_NONE, 0, Input::AD_NEUTRAL);
setBinding(PA_DRIFT, Input::IT_NONE, 0, Input::AD_NEUTRAL);
setBinding(PA_LOOK_BACK, Input::IT_NONE, 0, Input::AD_NEUTRAL);
setBinding(PA_RESCUE, Input::IT_NONE, 0, Input::AD_NEUTRAL);
setBinding(PA_PAUSE_RACE, Input::IT_NONE, 0, Input::AD_NEUTRAL);
setBinding(PA_MENU_SELECT, Input::IT_NONE, 0, Input::AD_NEUTRAL);
setBinding(PA_MENU_CANCEL, Input::IT_NONE, 0, Input::AD_NEUTRAL);
actions_map.clear();
for (auto& p : m_sdl_mapping)
{
if (p.second >= SDL_CONTROLLER_BUTTON_MAX)
continue;
actions_map[p.second] = p.first;
}
auto it = actions_map.begin();
if (it != actions_map.end())
{
// Prefer start and back button if exist
auto start_bind = actions_map.find(SDL_CONTROLLER_BUTTON_START);
if (start_bind != actions_map.end())
it = start_bind;
setBindingFromTuple(PA_MENU_SELECT, it->second);
actions_map.erase(it);
it = actions_map.begin();
if (it != actions_map.end())
{
auto back_bind = actions_map.find(SDL_CONTROLLER_BUTTON_BACK);
if (back_bind != actions_map.end())
it = back_bind;
setBindingFromTuple(PA_MENU_CANCEL, it->second);
setBindingFromTuple(PA_PAUSE_RACE, it->second);
}
return;
}
// Last fallback, bind without mapping
setBinding(PA_MENU_SELECT, Input::IT_STICKBUTTON, 0);
setBinding(PA_MENU_CANCEL, Input::IT_STICKBUTTON, 1);
setBinding(PA_PAUSE_RACE, Input::IT_STICKBUTTON, 1);
#endif
} // initSDLMapping

View File

@ -65,6 +65,8 @@ private:
bool getMappingTuple(const std::string& rhs,
std::tuple<int, Input::AxisDirection>& t);
void setBindingFromTuple(const PlayerAction action,
std::tuple<int, Input::AxisDirection>& t);
public:
GamepadConfig ();

View File

@ -156,6 +156,8 @@ SDLController::SDLController(int device_id)
}
}
cfg->initSDLController(mapping_string, m_buttons, m_axes, m_hats);
if (created)
cfg->initSDLMapping();
cfg->setPlugged();
for (int i = 0; i < dm->getGamePadAmount(); i++)
{