mirror of https://github.com/PCSX2/pcsx2.git
InputManager: Add generic input mappings
This commit is contained in:
parent
9504671919
commit
51d47a1455
|
@ -935,6 +935,61 @@ std::vector<InputBindingKey> InputManager::EnumerateMotors()
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void GetKeyboardGenericBindingMapping(std::vector<std::pair<GenericInputBinding, std::string>>* mapping)
|
||||
{
|
||||
mapping->emplace_back(GenericInputBinding::DPadUp, "Keyboard/Up");
|
||||
mapping->emplace_back(GenericInputBinding::DPadRight, "Keyboard/Right");
|
||||
mapping->emplace_back(GenericInputBinding::DPadDown, "Keyboard/Down");
|
||||
mapping->emplace_back(GenericInputBinding::DPadLeft, "Keyboard/Left");
|
||||
mapping->emplace_back(GenericInputBinding::LeftStickUp, "Keyboard/W");
|
||||
mapping->emplace_back(GenericInputBinding::LeftStickRight, "Keyboard/D");
|
||||
mapping->emplace_back(GenericInputBinding::LeftStickDown, "Keyboard/S");
|
||||
mapping->emplace_back(GenericInputBinding::LeftStickLeft, "Keyboard/A");
|
||||
mapping->emplace_back(GenericInputBinding::RightStickUp, "Keyboard/T");
|
||||
mapping->emplace_back(GenericInputBinding::RightStickRight, "Keyboard/H");
|
||||
mapping->emplace_back(GenericInputBinding::RightStickDown, "Keyboard/G");
|
||||
mapping->emplace_back(GenericInputBinding::RightStickLeft, "Keyboard/F");
|
||||
mapping->emplace_back(GenericInputBinding::Start, "Keyboard/Return");
|
||||
mapping->emplace_back(GenericInputBinding::Select, "Keyboard/Backspace");
|
||||
mapping->emplace_back(GenericInputBinding::Triangle, "Keyboard/I");
|
||||
mapping->emplace_back(GenericInputBinding::Circle, "Keyboard/L");
|
||||
mapping->emplace_back(GenericInputBinding::Cross, "Keyboard/K");
|
||||
mapping->emplace_back(GenericInputBinding::Square, "Keyboard/J");
|
||||
mapping->emplace_back(GenericInputBinding::L1, "Keyboard/Q");
|
||||
mapping->emplace_back(GenericInputBinding::L2, "Keyboard/1");
|
||||
mapping->emplace_back(GenericInputBinding::L3, "Keyboard/2");
|
||||
mapping->emplace_back(GenericInputBinding::R1, "Keyboard/E");
|
||||
mapping->emplace_back(GenericInputBinding::R2, "Keyboard/2");
|
||||
mapping->emplace_back(GenericInputBinding::R3, "Keyboard/4");
|
||||
}
|
||||
|
||||
static bool GetInternalGenericBindingMapping(const std::string_view& device, GenericInputBindingMapping* mapping)
|
||||
{
|
||||
if (device == "Keyboard")
|
||||
{
|
||||
GetKeyboardGenericBindingMapping(mapping);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
GenericInputBindingMapping InputManager::GetGenericBindingMapping(const std::string_view& device)
|
||||
{
|
||||
GenericInputBindingMapping mapping;
|
||||
|
||||
if (!GetInternalGenericBindingMapping(device, &mapping))
|
||||
{
|
||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||
{
|
||||
if (s_input_sources[i] && s_input_sources[i]->GetGenericBindingMapping(device, &mapping))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void UpdateInputSourceState(SettingsInterface& si, InputSourceType type, bool default_state)
|
||||
{
|
||||
|
|
|
@ -125,6 +125,50 @@ DECLARE_HOTKEY_LIST(g_vm_manager_hotkeys);
|
|||
DECLARE_HOTKEY_LIST(g_gs_hotkeys);
|
||||
DECLARE_HOTKEY_LIST(g_host_hotkeys);
|
||||
|
||||
/// Generic input bindings. These roughly match a DualShock 4 or XBox One controller.
|
||||
/// They are used for automatic binding to PS2 controller types.
|
||||
enum class GenericInputBinding : u8
|
||||
{
|
||||
Unknown,
|
||||
|
||||
DPadUp,
|
||||
DPadRight,
|
||||
DPadLeft,
|
||||
DPadDown,
|
||||
|
||||
LeftStickUp,
|
||||
LeftStickRight,
|
||||
LeftStickDown,
|
||||
LeftStickLeft,
|
||||
L3,
|
||||
|
||||
RightStickUp,
|
||||
RightStickRight,
|
||||
RightStickDown,
|
||||
RightStickLeft,
|
||||
R3,
|
||||
|
||||
Triangle, // Y on XBox pads.
|
||||
Circle, // B on XBox pads.
|
||||
Cross, // A on XBox pads.
|
||||
Square, // X on XBox pads.
|
||||
|
||||
Select, // Share on DS4, View on XBox pads.
|
||||
Start, // Options on DS4, Menu on XBox pads.
|
||||
System, // PS button on DS4, Guide button on XBox pads.
|
||||
|
||||
L1, // LB on Xbox pads.
|
||||
L2, // Left trigger on XBox pads.
|
||||
R1, // RB on XBox pads.
|
||||
R2, // Right trigger on Xbox pads.
|
||||
|
||||
SmallMotor, // High frequency vibration.
|
||||
LargeMotor, // Low frequency vibration.
|
||||
|
||||
Count,
|
||||
};
|
||||
using GenericInputBindingMapping = std::vector<std::pair<GenericInputBinding, std::string>>;
|
||||
|
||||
/// External input source class.
|
||||
class InputSource;
|
||||
|
||||
|
@ -178,6 +222,9 @@ namespace InputManager
|
|||
/// Enumerates available vibration motors at the time of call.
|
||||
std::vector<InputBindingKey> EnumerateMotors();
|
||||
|
||||
/// Retrieves bindings that match the generic bindings for the specified device.
|
||||
GenericInputBindingMapping GetGenericBindingMapping(const std::string_view& device);
|
||||
|
||||
/// Re-parses the config and registers all hotkey and pad bindings.
|
||||
void ReloadBindings(SettingsInterface& si);
|
||||
|
||||
|
|
|
@ -47,6 +47,10 @@ public:
|
|||
/// Enumerates available vibration motors at the time of call.
|
||||
virtual std::vector<InputBindingKey> EnumerateMotors() = 0;
|
||||
|
||||
/// Retrieves bindings that match the generic bindings for the specified device.
|
||||
/// Returns false if it's not one of our devices.
|
||||
virtual bool GetGenericBindingMapping(const std::string_view& device, GenericInputBindingMapping* mapping) = 0;
|
||||
|
||||
/// Informs the source of a new vibration motor state. Changes may not take effect until the next PollEvents() call.
|
||||
virtual void UpdateMotorState(InputBindingKey key, float intensity) = 0;
|
||||
|
||||
|
|
|
@ -31,6 +31,14 @@ static const char* s_sdl_axis_names[] = {
|
|||
"LeftTrigger", // SDL_CONTROLLER_AXIS_TRIGGERLEFT
|
||||
"RightTrigger", // SDL_CONTROLLER_AXIS_TRIGGERRIGHT
|
||||
};
|
||||
static const GenericInputBinding s_sdl_generic_binding_axis_mapping[][2] = {
|
||||
{GenericInputBinding::LeftStickLeft, GenericInputBinding::LeftStickRight}, // SDL_CONTROLLER_AXIS_LEFTX
|
||||
{GenericInputBinding::LeftStickUp, GenericInputBinding::LeftStickDown}, // SDL_CONTROLLER_AXIS_LEFTY
|
||||
{GenericInputBinding::RightStickLeft, GenericInputBinding::RightStickRight}, // SDL_CONTROLLER_AXIS_RIGHTX
|
||||
{GenericInputBinding::RightStickUp, GenericInputBinding::RightStickDown}, // SDL_CONTROLLER_AXIS_RIGHTY
|
||||
{GenericInputBinding::Unknown, GenericInputBinding::L2}, // SDL_CONTROLLER_AXIS_TRIGGERLEFT
|
||||
{GenericInputBinding::Unknown, GenericInputBinding::R2}, // SDL_CONTROLLER_AXIS_TRIGGERRIGHT
|
||||
};
|
||||
|
||||
static const char* s_sdl_button_names[] = {
|
||||
"A", // SDL_CONTROLLER_BUTTON_A
|
||||
|
@ -55,6 +63,29 @@ static const char* s_sdl_button_names[] = {
|
|||
"Paddle4", // SDL_CONTROLLER_BUTTON_PADDLE4
|
||||
"Touchpad", // SDL_CONTROLLER_BUTTON_TOUCHPAD
|
||||
};
|
||||
static const GenericInputBinding s_sdl_generic_binding_button_mapping[] = {
|
||||
GenericInputBinding::Cross, // SDL_CONTROLLER_BUTTON_A
|
||||
GenericInputBinding::Circle, // SDL_CONTROLLER_BUTTON_B
|
||||
GenericInputBinding::Square, // SDL_CONTROLLER_BUTTON_X
|
||||
GenericInputBinding::Triangle, // SDL_CONTROLLER_BUTTON_Y
|
||||
GenericInputBinding::Select, // SDL_CONTROLLER_BUTTON_BACK
|
||||
GenericInputBinding::System, // SDL_CONTROLLER_BUTTON_GUIDE
|
||||
GenericInputBinding::Start, // SDL_CONTROLLER_BUTTON_START
|
||||
GenericInputBinding::L3, // SDL_CONTROLLER_BUTTON_LEFTSTICK
|
||||
GenericInputBinding::R3, // SDL_CONTROLLER_BUTTON_RIGHTSTICK
|
||||
GenericInputBinding::L1, // SDL_CONTROLLER_BUTTON_LEFTSHOULDER
|
||||
GenericInputBinding::R1, // SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
|
||||
GenericInputBinding::DPadUp, // SDL_CONTROLLER_BUTTON_DPAD_UP
|
||||
GenericInputBinding::DPadDown, // SDL_CONTROLLER_BUTTON_DPAD_DOWN
|
||||
GenericInputBinding::DPadLeft, // SDL_CONTROLLER_BUTTON_DPAD_LEFT
|
||||
GenericInputBinding::DPadRight, // SDL_CONTROLLER_BUTTON_DPAD_RIGHT
|
||||
GenericInputBinding::Unknown, // SDL_CONTROLLER_BUTTON_MISC1
|
||||
GenericInputBinding::Unknown, // SDL_CONTROLLER_BUTTON_PADDLE1
|
||||
GenericInputBinding::Unknown, // SDL_CONTROLLER_BUTTON_PADDLE2
|
||||
GenericInputBinding::Unknown, // SDL_CONTROLLER_BUTTON_PADDLE3
|
||||
GenericInputBinding::Unknown, // SDL_CONTROLLER_BUTTON_PADDLE4
|
||||
GenericInputBinding::Unknown, // SDL_CONTROLLER_BUTTON_TOUCHPAD
|
||||
};
|
||||
|
||||
SDLInputSource::SDLInputSource() = default;
|
||||
|
||||
|
@ -478,6 +509,60 @@ std::vector<InputBindingKey> SDLInputSource::EnumerateMotors()
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool SDLInputSource::GetGenericBindingMapping(const std::string_view& device, GenericInputBindingMapping* mapping)
|
||||
{
|
||||
if (!StringUtil::StartsWith(device, "SDL-"))
|
||||
return false;
|
||||
|
||||
const std::optional<s32> player_id = StringUtil::FromChars<s32>(device.substr(4));
|
||||
if (!player_id.has_value() || player_id.value() < 0)
|
||||
return false;
|
||||
|
||||
ControllerDataVector::iterator it = GetControllerDataForPlayerId(player_id.value());
|
||||
if (it == m_controllers.end())
|
||||
return false;
|
||||
|
||||
if (it->game_controller)
|
||||
{
|
||||
// assume all buttons are present.
|
||||
const s32 pid = player_id.value();
|
||||
for (u32 i = 0; i < std::size(s_sdl_generic_binding_axis_mapping); i++)
|
||||
{
|
||||
const GenericInputBinding negative = s_sdl_generic_binding_axis_mapping[i][0];
|
||||
const GenericInputBinding positive = s_sdl_generic_binding_axis_mapping[i][1];
|
||||
if (negative != GenericInputBinding::Unknown)
|
||||
mapping->emplace_back(negative, StringUtil::StdStringFromFormat("SDL-%d/-%s", pid, s_sdl_axis_names[i]));
|
||||
|
||||
if (positive != GenericInputBinding::Unknown)
|
||||
mapping->emplace_back(positive, StringUtil::StdStringFromFormat("SDL-%d/+%s", pid, s_sdl_axis_names[i]));
|
||||
}
|
||||
for (u32 i = 0; i < std::size(s_sdl_generic_binding_button_mapping); i++)
|
||||
{
|
||||
const GenericInputBinding binding = s_sdl_generic_binding_button_mapping[i];
|
||||
if (binding != GenericInputBinding::Unknown)
|
||||
mapping->emplace_back(binding, StringUtil::StdStringFromFormat("SDL-%d/%s", pid, s_sdl_button_names[i]));
|
||||
}
|
||||
|
||||
if (it->use_game_controller_rumble || it->haptic_left_right_effect)
|
||||
{
|
||||
mapping->emplace_back(GenericInputBinding::SmallMotor, StringUtil::StdStringFromFormat("SDL-%d/SmallMotor", pid));
|
||||
mapping->emplace_back(GenericInputBinding::LargeMotor, StringUtil::StdStringFromFormat("SDL-%d/LargeMotor", pid));
|
||||
}
|
||||
else
|
||||
{
|
||||
mapping->emplace_back(GenericInputBinding::SmallMotor, StringUtil::StdStringFromFormat("SDL-%d/Haptic", pid));
|
||||
mapping->emplace_back(GenericInputBinding::LargeMotor, StringUtil::StdStringFromFormat("SDL-%d/Haptic", pid));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// joysticks, which we haven't implemented yet anyway.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void SDLInputSource::UpdateMotorState(InputBindingKey key, float intensity)
|
||||
{
|
||||
if (key.source_subtype != InputSubclass::ControllerMotor && key.source_subtype != InputSubclass::ControllerHaptic)
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
void PollEvents() override;
|
||||
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
|
||||
std::vector<InputBindingKey> EnumerateMotors() override;
|
||||
bool GetGenericBindingMapping(const std::string_view& device, GenericInputBindingMapping* mapping) override;
|
||||
void UpdateMotorState(InputBindingKey key, float intensity) override;
|
||||
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity, float small_intensity) override;
|
||||
|
||||
|
|
|
@ -29,6 +29,14 @@ const char* XInputSource::s_axis_names[XInputSource::NUM_AXES] = {
|
|||
"LeftTrigger", // AXIS_TRIGGERLEFT
|
||||
"RightTrigger", // AXIS_TRIGGERRIGHT
|
||||
};
|
||||
static const GenericInputBinding s_sdl_generic_binding_axis_mapping[][2] = {
|
||||
{GenericInputBinding::LeftStickLeft, GenericInputBinding::LeftStickRight}, // AXIS_LEFTX
|
||||
{GenericInputBinding::LeftStickUp, GenericInputBinding::LeftStickDown}, // AXIS_LEFTY
|
||||
{GenericInputBinding::RightStickLeft, GenericInputBinding::RightStickRight}, // AXIS_RIGHTX
|
||||
{GenericInputBinding::RightStickUp, GenericInputBinding::RightStickDown}, // AXIS_RIGHTY
|
||||
{GenericInputBinding::Unknown, GenericInputBinding::L2}, // AXIS_TRIGGERLEFT
|
||||
{GenericInputBinding::Unknown, GenericInputBinding::R2}, // AXIS_TRIGGERRIGHT
|
||||
};
|
||||
|
||||
const char* XInputSource::s_button_names[XInputSource::NUM_BUTTONS] = {
|
||||
"DPadUp", // XINPUT_GAMEPAD_DPAD_UP
|
||||
|
@ -64,6 +72,23 @@ const u16 XInputSource::s_button_masks[XInputSource::NUM_BUTTONS] = {
|
|||
XINPUT_GAMEPAD_Y,
|
||||
0x400, // XINPUT_GAMEPAD_GUIDE
|
||||
};
|
||||
static const GenericInputBinding s_sdl_generic_binding_button_mapping[] = {
|
||||
GenericInputBinding::DPadUp, // XINPUT_GAMEPAD_DPAD_UP
|
||||
GenericInputBinding::DPadDown, // XINPUT_GAMEPAD_DPAD_DOWN
|
||||
GenericInputBinding::DPadLeft, // XINPUT_GAMEPAD_DPAD_LEFT
|
||||
GenericInputBinding::DPadRight, // XINPUT_GAMEPAD_DPAD_RIGHT
|
||||
GenericInputBinding::Start, // XINPUT_GAMEPAD_START
|
||||
GenericInputBinding::Select, // XINPUT_GAMEPAD_BACK
|
||||
GenericInputBinding::L3, // XINPUT_GAMEPAD_LEFT_THUMB
|
||||
GenericInputBinding::R3, // XINPUT_GAMEPAD_RIGHT_THUMB
|
||||
GenericInputBinding::L1, // XINPUT_GAMEPAD_LEFT_SHOULDER
|
||||
GenericInputBinding::R1, // XINPUT_GAMEPAD_RIGHT_SHOULDER
|
||||
GenericInputBinding::Cross, // XINPUT_GAMEPAD_A
|
||||
GenericInputBinding::Circle, // XINPUT_GAMEPAD_B
|
||||
GenericInputBinding::Square, // XINPUT_GAMEPAD_X
|
||||
GenericInputBinding::Triangle, // XINPUT_GAMEPAD_Y
|
||||
GenericInputBinding::System, // XINPUT_GAMEPAD_GUIDE
|
||||
};
|
||||
|
||||
XInputSource::XInputSource() = default;
|
||||
|
||||
|
@ -286,6 +311,45 @@ std::vector<InputBindingKey> XInputSource::EnumerateMotors()
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool XInputSource::GetGenericBindingMapping(const std::string_view& device, GenericInputBindingMapping* mapping)
|
||||
{
|
||||
if (!StringUtil::StartsWith(device, "XInput-"))
|
||||
return false;
|
||||
|
||||
const std::optional<s32> player_id = StringUtil::FromChars<s32>(device.substr(7));
|
||||
if (!player_id.has_value() || player_id.value() < 0)
|
||||
return false;
|
||||
|
||||
if (player_id.value() < 0 || player_id.value() >= static_cast<s32>(XUSER_MAX_COUNT))
|
||||
return false;
|
||||
|
||||
// assume all buttons are present.
|
||||
const s32 pid = player_id.value();
|
||||
for (u32 i = 0; i < std::size(s_sdl_generic_binding_axis_mapping); i++)
|
||||
{
|
||||
const GenericInputBinding negative = s_sdl_generic_binding_axis_mapping[i][0];
|
||||
const GenericInputBinding positive = s_sdl_generic_binding_axis_mapping[i][1];
|
||||
if (negative != GenericInputBinding::Unknown)
|
||||
mapping->emplace_back(negative, StringUtil::StdStringFromFormat("XInput-%d/-%s", pid, s_axis_names[i]));
|
||||
|
||||
if (positive != GenericInputBinding::Unknown)
|
||||
mapping->emplace_back(positive, StringUtil::StdStringFromFormat("XInput-%d/+%s", pid, s_axis_names[i]));
|
||||
}
|
||||
for (u32 i = 0; i < std::size(s_sdl_generic_binding_button_mapping); i++)
|
||||
{
|
||||
const GenericInputBinding binding = s_sdl_generic_binding_button_mapping[i];
|
||||
if (binding != GenericInputBinding::Unknown)
|
||||
mapping->emplace_back(binding, StringUtil::StdStringFromFormat("XInput-%d/%s", pid, s_button_names[i]));
|
||||
}
|
||||
|
||||
if (m_controllers[pid].has_small_motor)
|
||||
mapping->emplace_back(GenericInputBinding::SmallMotor, StringUtil::StdStringFromFormat("XInput-%d/SmallMotor", pid));
|
||||
if (m_controllers[pid].has_large_motor)
|
||||
mapping->emplace_back(GenericInputBinding::LargeMotor, StringUtil::StdStringFromFormat("XInput-%d/LargeMotor", pid));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void XInputSource::HandleControllerConnection(u32 index)
|
||||
{
|
||||
Console.WriteLn("XInput controller %u connected.", index);
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
void PollEvents() override;
|
||||
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
|
||||
std::vector<InputBindingKey> EnumerateMotors() override;
|
||||
bool GetGenericBindingMapping(const std::string_view& device, GenericInputBindingMapping* mapping) override;
|
||||
void UpdateMotorState(InputBindingKey key, float intensity) override;
|
||||
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity, float small_intensity) override;
|
||||
|
||||
|
|
Loading…
Reference in New Issue