InputManager: Add device/motor enumeration, connect callbacks

This commit is contained in:
Connor McLaughlin 2022-01-27 23:45:19 +10:00 committed by refractionpcsx2
parent 7555091d56
commit 14b54e554e
7 changed files with 133 additions and 15 deletions

View File

@ -535,8 +535,7 @@ std::vector<const HotkeyInfo*> InputManager::GetHotkeyList()
for (const HotkeyInfo* hotkey = hotkey_list; hotkey->name != nullptr; hotkey++)
ret.push_back(hotkey);
}
std::sort(ret.begin(), ret.end(), [](const HotkeyInfo* left, const HotkeyInfo* right)
{
std::sort(ret.begin(), ret.end(), [](const HotkeyInfo* left, const HotkeyInfo* right) {
// category -> display name
if (const int res = StringUtil::Strcasecmp(left->category, right->category); res != 0)
return (res < 0);
@ -577,9 +576,9 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const ch
if (!bindings.empty())
{
// we use axes for all pad bindings to simplify things, and because they are pressure sensitive
AddBindings(bindings, InputAxisEventHandler{ [pad_index, bind_index, bind_names](float value) {
AddBindings(bindings, InputAxisEventHandler{[pad_index, bind_index, bind_names](float value) {
PAD::SetControllerState(pad_index, bind_index, value);
} });
}});
}
}
}
@ -593,7 +592,7 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const ch
bool has_any_bindings = false;
switch (vibcaps)
{
case PAD::VibrationCapabilities::LargeSmallMotors:
case PAD::VibrationCapabilities::LargeSmallMotors:
{
const std::string large_binding(si.GetStringValue(section.c_str(), "LargeMotor"));
const std::string small_binding(si.GetStringValue(section.c_str(), "SmallMotor"));
@ -602,15 +601,15 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const ch
}
break;
case PAD::VibrationCapabilities::SingleMotor:
case PAD::VibrationCapabilities::SingleMotor:
{
const std::string binding(si.GetStringValue(section.c_str(), "Motor"));
has_any_bindings |= ParseBindingAndGetSource(binding, &vib.motors[0].binding, &vib.motors[0].source);
}
break;
default:
break;
default:
break;
}
if (has_any_bindings)
@ -660,7 +659,8 @@ bool InputManager::InvokeEvents(InputBindingKey key, float value)
binding->current_mask = new_mask;
// invert if we're negative, since the handler expects 0..1
const float value_to_pass = (negative ? ((value < 0.0f) ? -value : 0.0f) : (value > 0.0f) ? value : 0.0f);
const float value_to_pass = (negative ? ((value < 0.0f) ? -value : 0.0f) : (value > 0.0f) ? value :
0.0f);
// axes are fired regardless of a state change, unless they're zero
// for buttons, we can use the state of the last chord key, because it'll be 1 on press,
@ -825,10 +825,7 @@ bool InputManager::DoEventHook(InputBindingKey key, float value)
return false;
const InputInterceptHook::CallbackResult action = m_event_intercept_callback(key, value);
if (action == InputInterceptHook::CallbackResult::StopMonitoring)
m_event_intercept_callback = {};
return true;
return (action == InputInterceptHook::CallbackResult::StopProcessingEvent);
}
// ------------------------------------------------------------------------
@ -884,6 +881,48 @@ void InputManager::PollSources()
UpdateContinuedVibration();
}
std::vector<std::pair<std::string, std::string>> InputManager::EnumerateDevices()
{
std::vector<std::pair<std::string, std::string>> ret;
ret.emplace_back("Keyboard", "Keyboard");
ret.emplace_back("Mouse", "Mouse");
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{
if (s_input_sources[i])
{
std::vector<std::pair<std::string, std::string>> devs(s_input_sources[i]->EnumerateDevices());
if (ret.empty())
ret = std::move(devs);
else
std::move(devs.begin(), devs.end(), std::back_inserter(ret));
}
}
return ret;
}
std::vector<InputBindingKey> InputManager::EnumerateMotors()
{
std::vector<InputBindingKey> ret;
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{
if (s_input_sources[i])
{
std::vector<InputBindingKey> devs(s_input_sources[i]->EnumerateMotors());
if (ret.empty())
ret = std::move(devs);
else
std::move(devs.begin(), devs.end(), std::back_inserter(ret));
}
}
return ret;
}
template <typename T>
static void UpdateInputSourceState(SettingsInterface& si, InputSourceType type, bool default_state)
{

View File

@ -17,6 +17,7 @@
#include <functional>
#include <optional>
#include <string_view>
#include <variant>
#include <utility>
@ -100,8 +101,8 @@ struct InputInterceptHook
{
enum class CallbackResult
{
StopMonitoring,
ContinueMonitoring
StopProcessingEvent,
ContinueProcessingEvent
};
using Callback = std::function<CallbackResult(InputBindingKey key, float value)>;
@ -171,6 +172,12 @@ namespace InputManager
/// Returns a list of all hotkeys.
std::vector<const HotkeyInfo*> GetHotkeyList();
/// Enumerates available devices. Returns a pair of the prefix (e.g. SDL-0) and the device name.
std::vector<std::pair<std::string, std::string>> EnumerateDevices();
/// Enumerates available vibration motors at the time of call.
std::vector<InputBindingKey> EnumerateMotors();
/// Re-parses the config and registers all hotkey and pad bindings.
void ReloadBindings(SettingsInterface& si);
@ -209,3 +216,12 @@ namespace InputManager
/// The pad vibration state will internally remain, so that when emulation is unpaused, the effect resumes.
void PauseVibration();
} // namespace InputManager
namespace Host
{
/// Called when a new input device is connected.
void OnInputDeviceConnected(const std::string_view& identifier, const std::string_view& device_name);
/// Called when an input device is disconnected.
void OnInputDeviceDisconnected(const std::string_view& identifier);
}

View File

@ -17,6 +17,7 @@
#include <optional>
#include <string_view>
#include <utility>
#include <vector>
#include "common/Pcsx2Defs.h"
@ -40,6 +41,9 @@ public:
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.
virtual std::vector<std::pair<std::string, std::string>> EnumerateDevices() = 0;
/// Enumerates available vibration motors at the time of call.
virtual std::vector<InputBindingKey> EnumerateMotors() = 0;

View File

@ -93,6 +93,11 @@ void SDLInputSource::UpdateSettings(SettingsInterface& si)
}
}
void SDLInputSource::Shutdown()
{
ShutdownSubsystem();
}
void SDLInputSource::LoadSettings(SettingsInterface& si)
{
m_controller_enhanced_mode = si.GetBoolValue("InputSources", "SDLControllerEnhancedMode", false);
@ -145,6 +150,24 @@ void SDLInputSource::PollEvents()
}
}
std::vector<std::pair<std::string, std::string>> SDLInputSource::EnumerateDevices()
{
std::vector<std::pair<std::string, std::string>> ret;
for (const ControllerData& cd : m_controllers)
{
std::string id(StringUtil::StdStringFromFormat("SDL-%d", cd.player_id));
const char* name = SDL_GameControllerName(cd.game_controller);
if (name)
ret.emplace_back(std::move(id), name);
else
ret.emplace_back(std::move(id), "Unknown Device");
}
return ret;
}
std::optional<InputBindingKey> SDLInputSource::ParseKeyString(
const std::string_view& device, const std::string_view& binding)
{
@ -391,6 +414,9 @@ bool SDLInputSource::OpenGameController(int index)
Console.Warning("(SDLInputSource) Rumble is not supported on '%s'", SDL_GameControllerName(gcontroller));
m_controllers.push_back(std::move(cd));
const char* name = SDL_GameControllerName(cd.game_controller);
Host::OnInputDeviceConnected(StringUtil::StdStringFromFormat("SDL-%d", player_id), name ? name : "Unknown Device");
return true;
}
@ -404,7 +430,11 @@ bool SDLInputSource::CloseGameController(int joystick_index)
SDL_HapticClose(static_cast<SDL_Haptic*>(it->haptic));
SDL_GameControllerClose(static_cast<SDL_GameController*>(it->game_controller));
const int player_id = it->player_id;
m_controllers.erase(it);
Host::OnInputDeviceDisconnected(StringUtil::StdStringFromFormat("SDL-%d", player_id));
return true;
}

View File

@ -34,6 +34,7 @@ public:
void Shutdown() override;
void PollEvents() override;
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
std::vector<InputBindingKey> EnumerateMotors() 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

@ -116,6 +116,12 @@ void XInputSource::UpdateSettings(SettingsInterface& si)
void XInputSource::Shutdown()
{
for (u32 i = 0; i < NUM_CONTROLLERS; i++)
{
if (m_controllers[i].connected)
HandleControllerDisconnection(i);
}
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
if (m_xinput_module)
{
@ -154,6 +160,22 @@ void XInputSource::PollEvents()
}
}
std::vector<std::pair<std::string, std::string>> XInputSource::EnumerateDevices()
{
std::vector<std::pair<std::string, std::string>> ret;
for (u32 i = 0; i < NUM_CONTROLLERS; i++)
{
if (!m_controllers[i].connected)
continue;
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)
{
@ -276,12 +298,17 @@ void XInputSource::HandleControllerConnection(u32 index)
cd.connected = true;
cd.has_large_motor = caps.Vibration.wLeftMotorSpeed != 0;
cd.has_small_motor = caps.Vibration.wRightMotorSpeed != 0;
Host::OnInputDeviceConnected(StringUtil::StdStringFromFormat("XInput-%u", index),
StringUtil::StdStringFromFormat("XInput Controller %u", index));
}
void XInputSource::HandleControllerDisconnection(u32 index)
{
Console.WriteLn("XInput controller %u disconnected.", index);
m_controllers[index] = {};
Host::OnInputDeviceDisconnected(StringUtil::StdStringFromFormat("XInput-%u", index));
}
void XInputSource::CheckForStateChanges(u32 index, const XINPUT_STATE& new_state)

View File

@ -34,6 +34,7 @@ public:
void Shutdown() override;
void PollEvents() override;
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
std::vector<InputBindingKey> EnumerateMotors() override;
void UpdateMotorState(InputBindingKey key, float intensity) override;
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity, float small_intensity) override;