yuzu/src/core/hid/emulated_console.cpp

301 lines
8.9 KiB
C++
Raw Normal View History

// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
2021-09-21 00:43:16 +00:00
#include "common/settings.h"
2021-09-21 00:43:16 +00:00
#include "core/hid/emulated_console.h"
#include "core/hid/input_converter.h"
namespace Core::HID {
2021-10-23 04:04:06 +00:00
EmulatedConsole::EmulatedConsole() = default;
2021-09-21 00:43:16 +00:00
EmulatedConsole::~EmulatedConsole() = default;
void EmulatedConsole::ReloadFromSettings() {
2021-11-04 04:35:45 +00:00
// Using first motion device from player 1. No need to assign any unique config at the moment
2021-09-21 00:43:16 +00:00
const auto& player = Settings::values.players.GetValue()[0];
motion_params = Common::ParamPackage(player.motions[0]);
ReloadInput();
}
2021-10-21 04:18:04 +00:00
void EmulatedConsole::SetTouchParams() {
2021-09-21 00:43:16 +00:00
std::size_t index = 0;
2021-10-21 04:18:04 +00:00
// We can't use mouse as touch if native mouse is enabled
2021-11-14 20:09:29 +00:00
if (!Settings::values.mouse_enabled) {
touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"};
}
touch_params[index++] =
Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"};
touch_params[index++] =
Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"};
for (int i = 0; i < static_cast<int>(MaxActiveTouchInputs); i++) {
Common::ParamPackage touchscreen_param{};
touchscreen_param.Set("engine", "touch");
touchscreen_param.Set("axis_x", i * 2);
touchscreen_param.Set("axis_y", (i * 2) + 1);
touchscreen_param.Set("button", i);
touch_params[index++] = touchscreen_param;
}
2021-10-21 04:18:04 +00:00
2021-09-21 00:43:16 +00:00
const auto button_index =
static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
const auto& touch_buttons = Settings::values.touch_from_button_maps[button_index].buttons;
2021-10-21 04:18:04 +00:00
2021-11-04 04:35:45 +00:00
// Map the rest of the fingers from touch from button configuration
2021-09-21 00:43:16 +00:00
for (const auto& config_entry : touch_buttons) {
if (index >= MaxTouchDevices) {
2021-11-14 20:09:29 +00:00
continue;
}
2021-09-21 00:43:16 +00:00
Common::ParamPackage params{config_entry};
Common::ParamPackage touch_button_params;
const int x = params.Get("x", 0);
const int y = params.Get("y", 0);
params.Erase("x");
params.Erase("y");
touch_button_params.Set("engine", "touch_from_button");
touch_button_params.Set("button", params.Serialize());
touch_button_params.Set("x", x);
touch_button_params.Set("y", y);
2021-10-21 04:18:04 +00:00
touch_params[index] = touch_button_params;
index++;
}
}
2021-09-21 00:43:16 +00:00
2021-10-21 04:18:04 +00:00
void EmulatedConsole::ReloadInput() {
2021-11-04 04:35:45 +00:00
// If you load any device here add the equivalent to the UnloadInput() function
2021-10-21 04:18:04 +00:00
SetTouchParams();
2021-11-04 04:35:45 +00:00
motion_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(motion_params);
2021-10-21 04:18:04 +00:00
if (motion_devices) {
motion_devices->SetCallback({
.on_change =
[this](const Common::Input::CallbackStatus& callback) { SetMotion(callback); },
});
2021-10-21 04:18:04 +00:00
}
2021-11-04 04:35:45 +00:00
// Unique index for identifying touch device source
2021-10-21 04:18:04 +00:00
std::size_t index = 0;
for (auto& touch_device : touch_devices) {
touch_device = Common::Input::CreateDevice<Common::Input::InputDevice>(touch_params[index]);
2021-10-21 04:18:04 +00:00
if (!touch_device) {
continue;
}
touch_device->SetCallback({
.on_change =
[this, index](const Common::Input::CallbackStatus& callback) {
SetTouch(callback, index);
},
});
2021-09-21 00:43:16 +00:00
index++;
}
}
void EmulatedConsole::UnloadInput() {
motion_devices.reset();
for (auto& touch : touch_devices) {
touch.reset();
}
}
void EmulatedConsole::EnableConfiguration() {
is_configuring = true;
SaveCurrentConfig();
}
void EmulatedConsole::DisableConfiguration() {
is_configuring = false;
}
bool EmulatedConsole::IsConfiguring() const {
return is_configuring;
}
void EmulatedConsole::SaveCurrentConfig() {
if (!is_configuring) {
return;
}
}
void EmulatedConsole::RestoreConfig() {
if (!is_configuring) {
return;
}
ReloadFromSettings();
}
Common::ParamPackage EmulatedConsole::GetMotionParam() const {
return motion_params;
}
void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
motion_params = param;
ReloadInput();
}
void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
std::unique_lock lock{mutex};
2021-09-21 00:43:16 +00:00
auto& raw_status = console.motion_values.raw_status;
auto& emulated = console.motion_values.emulated;
raw_status = TransformToMotion(callback);
emulated.SetAcceleration(Common::Vec3f{
raw_status.accel.x.value,
raw_status.accel.y.value,
raw_status.accel.z.value,
});
emulated.SetGyroscope(Common::Vec3f{
raw_status.gyro.x.value,
raw_status.gyro.y.value,
raw_status.gyro.z.value,
});
emulated.UpdateRotation(raw_status.delta_timestamp);
emulated.UpdateOrientation(raw_status.delta_timestamp);
if (is_configuring) {
lock.unlock();
2021-09-21 00:43:16 +00:00
TriggerOnChange(ConsoleTriggerType::Motion);
return;
}
auto& motion = console.motion_state;
motion.accel = emulated.GetAcceleration();
motion.gyro = emulated.GetGyroscope();
motion.rotation = emulated.GetRotations();
2021-09-21 00:43:16 +00:00
motion.orientation = emulated.GetOrientation();
motion.quaternion = emulated.GetQuaternion();
motion.gyro_bias = emulated.GetGyroBias();
motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
// Find what is this value
motion.verticalization_error = 0.0f;
2021-09-21 00:43:16 +00:00
lock.unlock();
2021-09-21 00:43:16 +00:00
TriggerOnChange(ConsoleTriggerType::Motion);
}
void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) {
if (index >= MaxTouchDevices) {
2021-09-21 00:43:16 +00:00
return;
}
std::unique_lock lock{mutex};
2021-09-21 00:43:16 +00:00
const auto touch_input = TransformToTouch(callback);
auto touch_index = GetIndexFromFingerId(index);
bool is_new_input = false;
if (!touch_index.has_value() && touch_input.pressed.value) {
touch_index = GetNextFreeIndex();
is_new_input = true;
}
// No free entries or invalid state. Ignore input
if (!touch_index.has_value()) {
return;
}
auto& touch_value = console.touch_values[touch_index.value()];
if (is_new_input) {
touch_value.pressed.value = true;
touch_value.id = static_cast<u32>(index);
}
touch_value.x = touch_input.x;
touch_value.y = touch_input.y;
if (!touch_input.pressed.value) {
touch_value.pressed.value = false;
}
2021-09-21 00:43:16 +00:00
if (is_configuring) {
lock.unlock();
2021-09-21 00:43:16 +00:00
TriggerOnChange(ConsoleTriggerType::Touch);
return;
}
// Touch outside allowed range. Ignore input
if (touch_index.value() >= MaxActiveTouchInputs) {
return;
}
console.touch_state[touch_index.value()] = {
.position = {touch_value.x.value, touch_value.y.value},
.id = static_cast<u32>(touch_index.value()),
.pressed = touch_input.pressed.value,
2021-09-21 00:43:16 +00:00
};
lock.unlock();
2021-09-21 00:43:16 +00:00
TriggerOnChange(ConsoleTriggerType::Touch);
}
ConsoleMotionValues EmulatedConsole::GetMotionValues() const {
std::scoped_lock lock{mutex};
2021-09-21 00:43:16 +00:00
return console.motion_values;
}
TouchValues EmulatedConsole::GetTouchValues() const {
std::scoped_lock lock{mutex};
2021-09-21 00:43:16 +00:00
return console.touch_values;
}
ConsoleMotion EmulatedConsole::GetMotion() const {
std::scoped_lock lock{mutex};
2021-09-21 00:43:16 +00:00
return console.motion_state;
}
TouchFingerState EmulatedConsole::GetTouch() const {
std::scoped_lock lock{mutex};
2021-09-21 00:43:16 +00:00
return console.touch_state;
}
std::optional<std::size_t> EmulatedConsole::GetIndexFromFingerId(std::size_t finger_id) const {
for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
const auto& finger = console.touch_values[index];
if (!finger.pressed.value) {
continue;
}
if (finger.id == static_cast<int>(finger_id)) {
return index;
}
}
return std::nullopt;
}
std::optional<std::size_t> EmulatedConsole::GetNextFreeIndex() const {
for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
if (!console.touch_values[index].pressed.value) {
return index;
}
}
return std::nullopt;
}
2021-09-21 00:43:16 +00:00
void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
std::scoped_lock lock{callback_mutex};
2021-10-23 04:04:06 +00:00
for (const auto& poller_pair : callback_list) {
2021-09-21 00:43:16 +00:00
const ConsoleUpdateCallback& poller = poller_pair.second;
if (poller.on_change) {
poller.on_change(type);
}
}
}
int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) {
std::scoped_lock lock{callback_mutex};
2021-09-21 00:43:16 +00:00
callback_list.insert_or_assign(last_callback_key, update_callback);
return last_callback_key++;
}
void EmulatedConsole::DeleteCallback(int key) {
std::scoped_lock lock{callback_mutex};
2021-11-01 20:17:53 +00:00
const auto& iterator = callback_list.find(key);
if (iterator == callback_list.end()) {
2021-09-21 00:43:16 +00:00
LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
return;
}
2021-11-01 20:17:53 +00:00
callback_list.erase(iterator);
2021-09-21 00:43:16 +00:00
}
} // namespace Core::HID