core/hid: Fully implement native mouse

This commit is contained in:
german77 2021-11-14 14:09:29 -06:00 committed by Narr the Reg
parent bca299e8e0
commit 654d76e79e
21 changed files with 323 additions and 1039 deletions

View file

@ -24,7 +24,10 @@ void EmulatedConsole::SetTouchParams() {
std::size_t index = 0;
// Hardcode mouse, touchscreen and cemuhook parameters
touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"};
if (!Settings::values.mouse_enabled) {
// We can't use mouse as touch if native mouse is enabled
touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"};
}
touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"};
touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"};
touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:0,axis_y:1,button:0"};
@ -36,6 +39,9 @@ void EmulatedConsole::SetTouchParams() {
// Map the rest of the fingers from touch from button configuration
for (const auto& config_entry : touch_buttons) {
if (index >= touch_params.size()) {
continue;
}
Common::ParamPackage params{config_entry};
Common::ParamPackage touch_button_params;
const int x = params.Get("x", 0);
@ -49,9 +55,6 @@ void EmulatedConsole::SetTouchParams() {
touch_button_params.Set("touch_id", static_cast<int>(index));
touch_params[index] = touch_button_params;
index++;
if (index >= touch_params.size()) {
return;
}
}
}

View file

@ -15,21 +15,34 @@ EmulatedDevices::EmulatedDevices() = default;
EmulatedDevices::~EmulatedDevices() = default;
void EmulatedDevices::ReloadFromSettings() {
const auto& mouse = Settings::values.mouse_buttons;
for (std::size_t index = 0; index < mouse.size(); ++index) {
mouse_button_params[index] = Common::ParamPackage(mouse[index]);
}
ReloadInput();
}
void EmulatedDevices::ReloadInput() {
std::transform(mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_BEGIN,
mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_END,
mouse_button_devices.begin(),
Common::Input::CreateDevice<Common::Input::InputDevice>);
// If you load any device here add the equivalent to the UnloadInput() function
std::size_t key_index = 0;
for (auto& mouse_device : mouse_button_devices) {
Common::ParamPackage mouse_params;
mouse_params.Set("engine", "mouse");
mouse_params.Set("button", static_cast<int>(key_index));
mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params);
key_index++;
}
mouse_stick_device = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>(
"engine:mouse,axis_x:0,axis_y:1");
// First two axis are reserved for mouse position
key_index = 2;
for (auto& mouse_device : mouse_analog_devices) {
Common::ParamPackage mouse_params;
mouse_params.Set("engine", "mouse");
mouse_params.Set("axis", static_cast<int>(key_index));
mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params);
key_index++;
}
key_index = 0;
for (auto& keyboard_device : keyboard_devices) {
// Keyboard keys are only mapped on port 1, pad 0
Common::ParamPackage keyboard_params;
@ -64,6 +77,23 @@ void EmulatedDevices::ReloadInput() {
mouse_button_devices[index]->SetCallback(button_callback);
}
for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) {
if (!mouse_analog_devices[index]) {
continue;
}
Common::Input::InputCallback button_callback{
[this, index](Common::Input::CallbackStatus callback) {
SetMouseAnalog(callback, index);
}};
mouse_analog_devices[index]->SetCallback(button_callback);
}
if (mouse_stick_device) {
Common::Input::InputCallback button_callback{
[this](Common::Input::CallbackStatus callback) { SetMouseStick(callback); }};
mouse_stick_device->SetCallback(button_callback);
}
for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {
if (!keyboard_devices[index]) {
continue;
@ -91,6 +121,10 @@ void EmulatedDevices::UnloadInput() {
for (auto& button : mouse_button_devices) {
button.reset();
}
for (auto& analog : mouse_analog_devices) {
analog.reset();
}
mouse_stick_device.reset();
for (auto& button : keyboard_devices) {
button.reset();
}
@ -116,12 +150,6 @@ void EmulatedDevices::SaveCurrentConfig() {
if (!is_configuring) {
return;
}
auto& mouse = Settings::values.mouse_buttons;
for (std::size_t index = 0; index < mouse.size(); ++index) {
mouse[index] = mouse_button_params[index].Serialize();
}
}
void EmulatedDevices::RestoreConfig() {
@ -131,21 +159,6 @@ void EmulatedDevices::RestoreConfig() {
ReloadFromSettings();
}
Common::ParamPackage EmulatedDevices::GetMouseButtonParam(std::size_t index) const {
if (index >= mouse_button_params.size()) {
return {};
}
return mouse_button_params[index];
}
void EmulatedDevices::SetMouseButtonParam(std::size_t index, Common::ParamPackage param) {
if (index >= mouse_button_params.size()) {
return;
}
mouse_button_params[index] = param;
ReloadInput();
}
void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) {
if (index >= device_status.keyboard_values.size()) {
return;
@ -334,6 +347,51 @@ void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std
TriggerOnChange(DeviceTriggerType::Mouse);
}
void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index) {
if (index >= device_status.mouse_analog_values.size()) {
return;
}
std::lock_guard lock{mutex};
const auto analog_value = TransformToAnalog(callback);
device_status.mouse_analog_values[index] = analog_value;
if (is_configuring) {
device_status.mouse_position_state = {};
TriggerOnChange(DeviceTriggerType::Mouse);
return;
}
switch (index) {
case Settings::NativeMouseWheel::X:
device_status.mouse_wheel_state.x = static_cast<s32>(analog_value.value);
break;
case Settings::NativeMouseWheel::Y:
device_status.mouse_wheel_state.y = static_cast<s32>(analog_value.value);
break;
}
TriggerOnChange(DeviceTriggerType::Mouse);
}
void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) {
std::lock_guard lock{mutex};
const auto stick_value = TransformToStick(callback);
device_status.mouse_stick_value = stick_value;
if (is_configuring) {
device_status.mouse_position_state = {};
TriggerOnChange(DeviceTriggerType::Mouse);
return;
}
device_status.mouse_position_state.x = stick_value.x.value;
device_status.mouse_position_state.y = stick_value.y.value;
TriggerOnChange(DeviceTriggerType::Mouse);
}
KeyboardValues EmulatedDevices::GetKeyboardValues() const {
return device_status.keyboard_values;
}
@ -362,6 +420,10 @@ MousePosition EmulatedDevices::GetMousePosition() const {
return device_status.mouse_position_state;
}
AnalogStickState EmulatedDevices::GetMouseDeltaWheel() const {
return device_status.mouse_wheel_state;
}
void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
for (const auto& poller_pair : callback_list) {
const InterfaceUpdateCallback& poller = poller_pair.second;

View file

@ -17,13 +17,15 @@
#include "core/hid/hid_types.h"
namespace Core::HID {
using KeyboardDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeKeyboard::NumKeyboardKeys>;
using KeyboardModifierDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeKeyboard::NumKeyboardMods>;
using MouseButtonDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeMouseButton::NumMouseButtons>;
using MouseAnalogDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeMouseWheel::NumMouseWheels>;
using MouseStickDevice = std::unique_ptr<Common::Input::InputDevice>;
using MouseButtonParams =
std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons>;
@ -34,12 +36,13 @@ using KeyboardModifierValues =
std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardMods>;
using MouseButtonValues =
std::array<Common::Input::ButtonStatus, Settings::NativeMouseButton::NumMouseButtons>;
using MouseAnalogValues =
std::array<Common::Input::AnalogStatus, Settings::NativeMouseWheel::NumMouseWheels>;
using MouseStickValue = Common::Input::StickStatus;
struct MousePosition {
s32 x;
s32 y;
s32 delta_wheel_x;
s32 delta_wheel_y;
f32 x;
f32 y;
};
struct DeviceStatus {
@ -47,12 +50,15 @@ struct DeviceStatus {
KeyboardValues keyboard_values{};
KeyboardModifierValues keyboard_moddifier_values{};
MouseButtonValues mouse_button_values{};
MouseAnalogValues mouse_analog_values{};
MouseStickValue mouse_stick_value{};
// Data for HID serices
KeyboardKey keyboard_state{};
KeyboardModifier keyboard_moddifier_state{};
MouseButton mouse_button_state{};
MousePosition mouse_position_state{};
AnalogStickState mouse_wheel_state{};
};
enum class DeviceTriggerType {
@ -102,15 +108,6 @@ public:
/// Reverts any mapped changes made that weren't saved
void RestoreConfig();
/// Returns the current mapped mouse button device
Common::ParamPackage GetMouseButtonParam(std::size_t index) const;
/**
* Updates the current mapped mouse button device
* @param ParamPackage with controller data to be mapped
*/
void SetMouseButtonParam(std::size_t index, Common::ParamPackage param);
/// Returns the latest status of button input from the keyboard with parameters
KeyboardValues GetKeyboardValues() const;
@ -132,9 +129,12 @@ public:
/// Returns the latest mouse coordinates
MousePosition GetMousePosition() const;
/// Returns the latest mouse wheel change
AnalogStickState GetMouseDeltaWheel() const;
/**
* Adds a callback to the list of events
* @param ConsoleUpdateCallback that will be triggered
* @param InterfaceUpdateCallback that will be triggered
* @return an unique key corresponding to the callback index in the list
*/
int SetCallback(InterfaceUpdateCallback update_callback);
@ -150,26 +150,40 @@ private:
void UpdateKey(std::size_t key_index, bool status);
/**
* Updates the touch status of the console
* Updates the touch status of the keyboard device
* @param callback: A CallbackStatus containing the key status
* @param index: key ID to be updated
*/
void SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index);
/**
* Updates the touch status of the console
* Updates the keyboard status of the keyboard device
* @param callback: A CallbackStatus containing the modifier key status
* @param index: modifier key ID to be updated
*/
void SetKeyboardModifier(Common::Input::CallbackStatus callback, std::size_t index);
/**
* Updates the touch status of the console
* Updates the mouse button status of the mouse device
* @param callback: A CallbackStatus containing the button status
* @param index: Button ID of the to be updated
* @param index: Button ID to be updated
*/
void SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index);
/**
* Updates the mouse wheel status of the mouse device
* @param callback: A CallbackStatus containing the wheel status
* @param index: wheel ID to be updated
*/
void SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index);
/**
* Updates the mouse position status of the mouse device
* @param callback: A CallbackStatus containing the position status
* @param index: stick ID to be updated
*/
void SetMouseStick(Common::Input::CallbackStatus callback);
/**
* Triggers a callback that something has changed on the device status
* @param Input type of the event to trigger
@ -178,11 +192,11 @@ private:
bool is_configuring{false};
MouseButtonParams mouse_button_params;
KeyboardDevices keyboard_devices;
KeyboardModifierDevices keyboard_modifier_devices;
MouseButtonDevices mouse_button_devices;
MouseAnalogDevices mouse_analog_devices;
MouseStickDevice mouse_stick_device;
mutable std::mutex mutex;
std::unordered_map<int, InterfaceUpdateCallback> callback_list;

View file

@ -242,6 +242,27 @@ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackSta
return status;
}
Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback) {
Common::Input::AnalogStatus status{};
switch (callback.type) {
case Common::Input::InputType::Analog:
status.properties = callback.analog_status.properties;
status.raw_value = callback.analog_status.raw_value;
break;
default:
LOG_ERROR(Input, "Conversion from type {} to analog not implemented", callback.type);
break;
}
SanitizeAnalog(status, false);
// Adjust if value is inverted
status.value = status.properties.inverted ? -status.value : status.value;
return status;
}
void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) {
const auto& properties = analog.properties;
float& raw_value = analog.raw_value;

View file

@ -68,6 +68,15 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus&
*/
Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback);
/**
* Converts raw input data into a valid analog status. Applies offset, deadzone, range and
* invert properties to the output.
*
* @param Supported callbacks: Analog.
* @return A valid AnalogStatus object.
*/
Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback);
/**
* Converts raw analog data into a valid analog value
* @param An analog object containing raw data and properties, bool that determines if the value

View file

@ -38,13 +38,14 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
if (Settings::values.mouse_enabled) {
const auto& mouse_button_state = emulated_devices->GetMouseButtons();
const auto& mouse_position_state = emulated_devices->GetMousePosition();
const auto& mouse_wheel_state = emulated_devices->GetMouseDeltaWheel();
next_state.attribute.is_connected.Assign(1);
next_state.x = mouse_position_state.x;
next_state.y = mouse_position_state.y;
next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width);
next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height);
next_state.delta_x = next_state.x - last_entry.x;
next_state.delta_y = next_state.y - last_entry.y;
next_state.delta_wheel_x = mouse_position_state.delta_wheel_x;
next_state.delta_wheel_y = mouse_position_state.delta_wheel_y;
next_state.delta_wheel_x = mouse_wheel_state.x;
next_state.delta_wheel_y = mouse_wheel_state.y;
next_state.button = mouse_button_state;
}