InputManager: Move GenericInputBinding to core

This commit is contained in:
Connor McLaughlin 2022-11-27 20:12:59 +10:00 committed by refractionpcsx2
parent 6f407b2080
commit d7c7aa2215
11 changed files with 193 additions and 213 deletions

View File

@ -48,7 +48,7 @@ struct SettingInfo
const char* max_value;
const char* step_value;
const char* format;
const char** options;
const char* const* options;
float multiplier;
const char* StringDefaultValue() const;
@ -65,6 +65,7 @@ struct SettingInfo
enum class GenericInputBinding : u8;
// TODO(Stenzek): Move to InputCommon.h or something?
struct InputBindingInfo
{
enum class Type : u8
@ -84,6 +85,49 @@ struct InputBindingInfo
GenericInputBinding generic_mapping;
};
/// Generic input bindings. These roughly match a DualShock 4 or XBox One controller.
/// They are used for automatic binding to PS2 controller types, and for big picture mode navigation.
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,
};
enum GamefixId
{
GamefixId_FIRST = 0,

View File

@ -84,8 +84,8 @@ bool DInputSource::Initialize(SettingsInterface& si, std::unique_lock<std::mutex
return false;
}
HRESULT hr = create(
GetModuleHandleA(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8W, reinterpret_cast<LPVOID*>(m_dinput.put()), nullptr);
HRESULT hr =
create(GetModuleHandleA(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8W, reinterpret_cast<LPVOID*>(m_dinput.put()), nullptr);
m_joystick_data_format = get_joystick_data_format();
if (FAILED(hr) || !m_joystick_data_format)
{
@ -309,7 +309,7 @@ std::vector<InputBindingKey> DInputSource::EnumerateMotors()
return {};
}
bool DInputSource::GetGenericBindingMapping(const std::string_view& device, GenericInputBindingMapping* mapping)
bool DInputSource::GetGenericBindingMapping(const std::string_view& device, InputManager::GenericInputBindingMapping* mapping)
{
return {};
}
@ -391,7 +391,8 @@ std::string DInputSource::ConvertKeyToString(InputBindingKey key)
{
if (key.source_subtype == InputSubclass::ControllerAxis)
{
ret = fmt::format("DInput-{}/{}Axis{}", u32(key.source_index), key.modifier == InputModifier::Negate ? '-' : '+', u32(key.data));
ret =
fmt::format("DInput-{}/{}Axis{}", u32(key.source_index), key.modifier == InputModifier::Negate ? '-' : '+', u32(key.data));
}
else if (key.source_subtype == InputSubclass::ControllerButton && key.data >= MAX_NUM_BUTTONS)
{

View File

@ -52,7 +52,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;
bool GetGenericBindingMapping(const std::string_view& device, InputManager::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;

View File

@ -1150,7 +1150,7 @@ static void GetKeyboardGenericBindingMapping(std::vector<std::pair<GenericInputB
mapping->emplace_back(GenericInputBinding::R3, "Keyboard/4");
}
static bool GetInternalGenericBindingMapping(const std::string_view& device, GenericInputBindingMapping* mapping)
static bool GetInternalGenericBindingMapping(const std::string_view& device, InputManager::GenericInputBindingMapping* mapping)
{
if (device == "Keyboard")
{
@ -1161,7 +1161,7 @@ static bool GetInternalGenericBindingMapping(const std::string_view& device, Gen
return false;
}
GenericInputBindingMapping InputManager::GetGenericBindingMapping(const std::string_view& device)
InputManager::GenericInputBindingMapping InputManager::GetGenericBindingMapping(const std::string_view& device)
{
GenericInputBindingMapping mapping;

View File

@ -26,6 +26,8 @@
#include "common/SettingsInterface.h"
#include "common/WindowInfo.h"
#include "pcsx2/Config.h"
/// Class, or source of an input event.
enum class InputSourceType : u32
{
@ -143,50 +145,6 @@ DECLARE_HOTKEY_LIST(g_common_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, and for big picture mode navigation.
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>>;
/// Host mouse relative axes are X, Y, wheel horizontal, wheel vertical.
enum class InputPointerAxis : u8
{
@ -255,6 +213,7 @@ namespace InputManager
std::vector<InputBindingKey> EnumerateMotors();
/// Retrieves bindings that match the generic bindings for the specified device.
using GenericInputBindingMapping = std::vector<std::pair<GenericInputBinding, std::string>>;
GenericInputBindingMapping GetGenericBindingMapping(const std::string_view& device);
/// Returns whether a given input source is enabled.

View File

@ -38,8 +38,7 @@ public:
virtual void PollEvents() = 0;
virtual std::optional<InputBindingKey> ParseKeyString(
const std::string_view& device, const std::string_view& binding) = 0;
virtual std::optional<InputBindingKey> ParseKeyString(const std::string_view& device, const std::string_view& binding) = 0;
virtual std::string ConvertKeyToString(InputBindingKey key) = 0;
/// Enumerates available devices. Returns a pair of the prefix (e.g. SDL-0) and the device name.
@ -50,7 +49,7 @@ public:
/// 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;
virtual bool GetGenericBindingMapping(const std::string_view& device, InputManager::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;

View File

@ -89,7 +89,10 @@ static const GenericInputBinding s_sdl_generic_binding_button_mapping[] = {
SDLInputSource::SDLInputSource() = default;
SDLInputSource::~SDLInputSource() { pxAssert(m_controllers.empty()); }
SDLInputSource::~SDLInputSource()
{
pxAssert(m_controllers.empty());
}
bool SDLInputSource::Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock)
{
@ -207,8 +210,7 @@ std::vector<std::pair<std::string, std::string>> SDLInputSource::EnumerateDevice
return ret;
}
std::optional<InputBindingKey> SDLInputSource::ParseKeyString(
const std::string_view& device, const std::string_view& binding)
std::optional<InputBindingKey> SDLInputSource::ParseKeyString(const std::string_view& device, const std::string_view& binding)
{
if (!StringUtil::StartsWith(device, "SDL-") || binding.empty())
return std::nullopt;
@ -388,14 +390,12 @@ bool SDLInputSource::ProcessSDLEvent(const SDL_Event* event)
SDLInputSource::ControllerDataVector::iterator SDLInputSource::GetControllerDataForJoystickId(int id)
{
return std::find_if(
m_controllers.begin(), m_controllers.end(), [id](const ControllerData& cd) { return cd.joystick_id == id; });
return std::find_if(m_controllers.begin(), m_controllers.end(), [id](const ControllerData& cd) { return cd.joystick_id == id; });
}
SDLInputSource::ControllerDataVector::iterator SDLInputSource::GetControllerDataForPlayerId(int id)
{
return std::find_if(
m_controllers.begin(), m_controllers.end(), [id](const ControllerData& cd) { return cd.player_id == id; });
return std::find_if(m_controllers.begin(), m_controllers.end(), [id](const ControllerData& cd) { return cd.player_id == id; });
}
int SDLInputSource::GetFreePlayerId() const
@ -439,8 +439,8 @@ bool SDLInputSource::OpenGameController(int index)
player_id = free_player_id;
}
Console.WriteLn("(SDLInputSource) Opened controller %d (instance id %d, player id %d): %s", index, joystick_id,
player_id, SDL_GameControllerName(gcontroller));
Console.WriteLn("(SDLInputSource) Opened controller %d (instance id %d, player id %d): %s", index, joystick_id, player_id,
SDL_GameControllerName(gcontroller));
ControllerData cd = {};
cd.player_id = player_id;
@ -452,7 +452,7 @@ bool SDLInputSource::OpenGameController(int index)
const int num_buttons = SDL_JoystickNumButtons(joystick);
cd.joy_axis_used_in_gc.resize(num_axes, false);
cd.joy_button_used_in_gc.resize(num_buttons, false);
auto mark_bind = [&](SDL_GameControllerButtonBind bind){
auto mark_bind = [&](SDL_GameControllerButtonBind bind) {
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS && bind.value.axis < num_axes)
cd.joy_axis_used_in_gc[bind.value.axis] = true;
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON && bind.value.button < num_buttons)
@ -466,8 +466,7 @@ bool SDLInputSource::OpenGameController(int index)
cd.use_game_controller_rumble = (SDL_GameControllerRumble(gcontroller, 0, 0, 0) == 0);
if (cd.use_game_controller_rumble)
{
Console.WriteLn(
"(SDLInputSource) Rumble is supported on '%s' via gamecontroller", SDL_GameControllerName(gcontroller));
Console.WriteLn("(SDLInputSource) Rumble is supported on '%s' via gamecontroller", SDL_GameControllerName(gcontroller));
}
else
{
@ -500,8 +499,7 @@ bool SDLInputSource::OpenGameController(int index)
}
if (cd.haptic)
Console.WriteLn(
"(SDLInputSource) Rumble is supported on '%s' via haptic", SDL_GameControllerName(gcontroller));
Console.WriteLn("(SDLInputSource) Rumble is supported on '%s' via haptic", SDL_GameControllerName(gcontroller));
}
if (!cd.haptic && !cd.use_game_controller_rumble)
@ -616,7 +614,7 @@ std::vector<InputBindingKey> SDLInputSource::EnumerateMotors()
return ret;
}
bool SDLInputSource::GetGenericBindingMapping(const std::string_view& device, GenericInputBindingMapping* mapping)
bool SDLInputSource::GetGenericBindingMapping(const std::string_view& device, InputManager::GenericInputBindingMapping* mapping)
{
if (!StringUtil::StartsWith(device, "SDL-"))
return false;

View File

@ -37,7 +37,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;
bool GetGenericBindingMapping(const std::string_view& device, InputManager::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;

View File

@ -56,20 +56,9 @@ const char* XInputSource::s_button_names[XInputSource::NUM_BUTTONS] = {
"Guide", // XINPUT_GAMEPAD_GUIDE
};
const u16 XInputSource::s_button_masks[XInputSource::NUM_BUTTONS] = {
XINPUT_GAMEPAD_DPAD_UP,
XINPUT_GAMEPAD_DPAD_DOWN,
XINPUT_GAMEPAD_DPAD_LEFT,
XINPUT_GAMEPAD_DPAD_RIGHT,
XINPUT_GAMEPAD_START,
XINPUT_GAMEPAD_BACK,
XINPUT_GAMEPAD_LEFT_THUMB,
XINPUT_GAMEPAD_RIGHT_THUMB,
XINPUT_GAMEPAD_LEFT_SHOULDER,
XINPUT_GAMEPAD_RIGHT_SHOULDER,
XINPUT_GAMEPAD_A,
XINPUT_GAMEPAD_B,
XINPUT_GAMEPAD_X,
XINPUT_GAMEPAD_Y,
XINPUT_GAMEPAD_DPAD_UP, XINPUT_GAMEPAD_DPAD_DOWN, XINPUT_GAMEPAD_DPAD_LEFT, XINPUT_GAMEPAD_DPAD_RIGHT, XINPUT_GAMEPAD_START,
XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_LEFT_THUMB, XINPUT_GAMEPAD_RIGHT_THUMB, XINPUT_GAMEPAD_LEFT_SHOULDER, XINPUT_GAMEPAD_RIGHT_SHOULDER,
XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, XINPUT_GAMEPAD_X, XINPUT_GAMEPAD_Y,
0x400, // XINPUT_GAMEPAD_GUIDE
};
static const GenericInputBinding s_xinput_generic_binding_button_mapping[] = {
@ -114,18 +103,15 @@ bool XInputSource::Initialize(SettingsInterface& si, std::unique_lock<std::mutex
}
// Try the hidden version of XInputGetState(), which lets us query the guide button.
m_xinput_get_state =
reinterpret_cast<decltype(m_xinput_get_state)>(GetProcAddress(m_xinput_module, reinterpret_cast<LPCSTR>(100)));
m_xinput_get_state = reinterpret_cast<decltype(m_xinput_get_state)>(GetProcAddress(m_xinput_module, reinterpret_cast<LPCSTR>(100)));
if (!m_xinput_get_state)
reinterpret_cast<decltype(m_xinput_get_state)>(GetProcAddress(m_xinput_module, "XInputGetState"));
m_xinput_set_state =
reinterpret_cast<decltype(m_xinput_set_state)>(GetProcAddress(m_xinput_module, "XInputSetState"));
m_xinput_set_state = reinterpret_cast<decltype(m_xinput_set_state)>(GetProcAddress(m_xinput_module, "XInputSetState"));
m_xinput_get_capabilities =
reinterpret_cast<decltype(m_xinput_get_capabilities)>(GetProcAddress(m_xinput_module, "XInputGetCapabilities"));
// SCP extension, only exists when the bridge xinput1_3.dll is in use
m_xinput_get_extended =
reinterpret_cast<decltype(m_xinput_get_extended)>(GetProcAddress(m_xinput_module, "XInputGetExtended"));
m_xinput_get_extended = reinterpret_cast<decltype(m_xinput_get_extended)>(GetProcAddress(m_xinput_module, "XInputGetExtended"));
if (!m_xinput_get_state || !m_xinput_set_state || !m_xinput_get_capabilities)
{
Console.Error("Failed to get XInput function pointers.");
@ -242,15 +228,13 @@ std::vector<std::pair<std::string, std::string>> XInputSource::EnumerateDevices(
if (!m_controllers[i].connected)
continue;
ret.emplace_back(StringUtil::StdStringFromFormat("XInput-%u", i),
StringUtil::StdStringFromFormat("XInput Controller %u", i));
ret.emplace_back(StringUtil::StdStringFromFormat("XInput-%u", i), StringUtil::StdStringFromFormat("XInput Controller %u", i));
}
return ret;
}
std::optional<InputBindingKey> XInputSource::ParseKeyString(
const std::string_view& device, const std::string_view& binding)
std::optional<InputBindingKey> XInputSource::ParseKeyString(const std::string_view& device, const std::string_view& binding)
{
if (!StringUtil::StartsWith(device, "XInput-") || binding.empty())
return std::nullopt;
@ -324,8 +308,7 @@ std::string XInputSource::ConvertKeyToString(InputBindingKey key)
if (key.source_subtype == InputSubclass::ControllerAxis && key.data < std::size(s_axis_names))
{
const char modifier = key.modifier == InputModifier::Negate ? '-' : '+';
ret = StringUtil::StdStringFromFormat(
"XInput-%u/%c%s", key.source_index, modifier, s_axis_names[key.data]);
ret = StringUtil::StdStringFromFormat("XInput-%u/%c%s", key.source_index, modifier, s_axis_names[key.data]);
}
else if (key.source_subtype == InputSubclass::ControllerButton && key.data < std::size(s_button_names))
{
@ -360,7 +343,7 @@ std::vector<InputBindingKey> XInputSource::EnumerateMotors()
return ret;
}
bool XInputSource::GetGenericBindingMapping(const std::string_view& device, GenericInputBindingMapping* mapping)
bool XInputSource::GetGenericBindingMapping(const std::string_view& device, InputManager::GenericInputBindingMapping* mapping)
{
if (!StringUtil::StartsWith(device, "XInput-"))
return false;
@ -414,8 +397,8 @@ void XInputSource::HandleControllerConnection(u32 index)
cd.last_state = {};
cd.last_state_scp = {};
Host::OnInputDeviceConnected(StringUtil::StdStringFromFormat("XInput-%u", index),
StringUtil::StdStringFromFormat("XInput Controller %u", index));
Host::OnInputDeviceConnected(
StringUtil::StdStringFromFormat("XInput-%u", index), StringUtil::StdStringFromFormat("XInput Controller %u", index));
}
void XInputSource::HandleControllerDisconnection(u32 index)
@ -438,8 +421,7 @@ void XInputSource::CheckForStateChanges(u32 index, const XINPUT_STATE& new_state
#define CHECK_AXIS(field, axis, min_value, max_value) \
if (ogp.field != ngp.field) \
{ \
InputManager::InvokeEvents( \
MakeGenericControllerAxisKey(InputSourceType::XInput, index, axis), \
InputManager::InvokeEvents(MakeGenericControllerAxisKey(InputSourceType::XInput, index, axis), \
static_cast<float>(ngp.field) / ((ngp.field < 0) ? min_value : max_value)); \
}
@ -463,11 +445,10 @@ void XInputSource::CheckForStateChanges(u32 index, const XINPUT_STATE& new_state
if ((old_button_bits & button_mask) != (new_button_bits & button_mask))
{
const GenericInputBinding generic_key = (button < std::size(s_xinput_generic_binding_button_mapping)) ?
s_xinput_generic_binding_button_mapping[button] : GenericInputBinding::Unknown;
s_xinput_generic_binding_button_mapping[button] :
GenericInputBinding::Unknown;
const float value = ((new_button_bits & button_mask) != 0) ? 1.0f : 0.0f;
InputManager::InvokeEvents(
MakeGenericControllerButtonKey(InputSourceType::XInput, index, button),
value, generic_key);
InputManager::InvokeEvents(MakeGenericControllerButtonKey(InputSourceType::XInput, index, button), value, generic_key);
}
}
}
@ -487,16 +468,14 @@ void XInputSource::CheckForStateChangesSCP(u32 index, const SCP_EXTN& new_state)
#define CHECK_AXIS(field, mult) \
if (ogp.field != ngp.field) \
{ \
InputManager::InvokeEvents( \
MakeGenericControllerAxisKey(InputSourceType::XInput, index, axis), ngp.field * mult); \
InputManager::InvokeEvents(MakeGenericControllerAxisKey(InputSourceType::XInput, index, axis), ngp.field* mult); \
} \
axis++;
#define CHECK_BUTTON(field) \
if (ogp.field != ngp.field) \
{ \
InputManager::InvokeEvents( \
MakeGenericControllerButtonKey(InputSourceType::XInput, index, button), ngp.field); \
InputManager::InvokeEvents(MakeGenericControllerButtonKey(InputSourceType::XInput, index, button), ngp.field); \
} \
button++;

View File

@ -71,7 +71,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;
bool GetGenericBindingMapping(const std::string_view& device, InputManager::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;

View File

@ -607,7 +607,7 @@ PAD::VibrationCapabilities PAD::GetControllerVibrationCapabilities(const std::st
}
static u32 TryMapGenericMapping(SettingsInterface& si, const std::string& section,
const GenericInputBindingMapping& mapping, GenericInputBinding generic_name,
const InputManager::GenericInputBindingMapping& mapping, GenericInputBinding generic_name,
const char* bind_name)
{
// find the mapping it corresponds to