core: hid: Implement true multitouch support
This commit is contained in:
parent
08091ff3e3
commit
38c48cf8d8
|
@ -19,27 +19,26 @@ void EmulatedConsole::ReloadFromSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedConsole::SetTouchParams() {
|
void EmulatedConsole::SetTouchParams() {
|
||||||
// TODO(german77): Support any number of fingers
|
|
||||||
std::size_t index = 0;
|
std::size_t index = 0;
|
||||||
|
|
||||||
// Hardcode mouse, touchscreen and cemuhook parameters
|
// We can't use mouse as touch if native mouse is enabled
|
||||||
if (!Settings::values.mouse_enabled) {
|
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:mouse,axis_x:10,axis_y:11,button:0"};
|
||||||
}
|
}
|
||||||
|
|
||||||
touch_params[index++] =
|
touch_params[index++] =
|
||||||
Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0,touch_id:0"};
|
Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"};
|
||||||
touch_params[index++] =
|
touch_params[index++] =
|
||||||
Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1,touch_id:1"};
|
Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"};
|
||||||
touch_params[index++] =
|
|
||||||
Common::ParamPackage{"engine:touch,axis_x:4,axis_y:5,button:2,touch_id:2"};
|
for (int i = 0; i < static_cast<int>(MaxActiveTouchInputs); i++) {
|
||||||
touch_params[index++] =
|
Common::ParamPackage touchscreen_param{};
|
||||||
Common::ParamPackage{"engine:touch,axis_x:6,axis_y:7,button:3,touch_id:3"};
|
touchscreen_param.Set("engine", "touch");
|
||||||
touch_params[index++] =
|
touchscreen_param.Set("axis_x", i * 2);
|
||||||
Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536,touch_id:0"};
|
touchscreen_param.Set("axis_y", (i * 2) + 1);
|
||||||
touch_params[index++] =
|
touchscreen_param.Set("button", i);
|
||||||
Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072,touch_id:1"};
|
touch_params[index++] = touchscreen_param;
|
||||||
|
}
|
||||||
|
|
||||||
const auto button_index =
|
const auto button_index =
|
||||||
static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
|
static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
|
||||||
|
@ -47,7 +46,7 @@ void EmulatedConsole::SetTouchParams() {
|
||||||
|
|
||||||
// Map the rest of the fingers from touch from button configuration
|
// Map the rest of the fingers from touch from button configuration
|
||||||
for (const auto& config_entry : touch_buttons) {
|
for (const auto& config_entry : touch_buttons) {
|
||||||
if (index >= touch_params.size()) {
|
if (index >= MaxTouchDevices) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Common::ParamPackage params{config_entry};
|
Common::ParamPackage params{config_entry};
|
||||||
|
@ -60,7 +59,6 @@ void EmulatedConsole::SetTouchParams() {
|
||||||
touch_button_params.Set("button", params.Serialize());
|
touch_button_params.Set("button", params.Serialize());
|
||||||
touch_button_params.Set("x", x);
|
touch_button_params.Set("x", x);
|
||||||
touch_button_params.Set("y", y);
|
touch_button_params.Set("y", y);
|
||||||
touch_button_params.Set("touch_id", static_cast<int>(index));
|
|
||||||
touch_params[index] = touch_button_params;
|
touch_params[index] = touch_button_params;
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
@ -178,12 +176,38 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) {
|
void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) {
|
||||||
if (index >= console.touch_values.size()) {
|
if (index >= MaxTouchDevices) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::unique_lock lock{mutex};
|
std::unique_lock lock{mutex};
|
||||||
|
|
||||||
console.touch_values[index] = TransformToTouch(callback);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_configuring) {
|
if (is_configuring) {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
@ -191,11 +215,15 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(german77): Remap touch id in sequential order
|
// Touch outside allowed range. Ignore input
|
||||||
console.touch_state[index] = {
|
if (touch_index.value() >= MaxActiveTouchInputs) {
|
||||||
.position = {console.touch_values[index].x.value, console.touch_values[index].y.value},
|
return;
|
||||||
.id = static_cast<u32>(console.touch_values[index].id),
|
}
|
||||||
.pressed = console.touch_values[index].pressed.value,
|
|
||||||
|
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,
|
||||||
};
|
};
|
||||||
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
@ -222,6 +250,28 @@ TouchFingerState EmulatedConsole::GetTouch() const {
|
||||||
return console.touch_state;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
|
void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
|
||||||
std::scoped_lock lock{callback_mutex};
|
std::scoped_lock lock{callback_mutex};
|
||||||
for (const auto& poller_pair : callback_list) {
|
for (const auto& poller_pair : callback_list) {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
@ -20,6 +21,8 @@
|
||||||
#include "core/hid/motion_input.h"
|
#include "core/hid/motion_input.h"
|
||||||
|
|
||||||
namespace Core::HID {
|
namespace Core::HID {
|
||||||
|
static constexpr std::size_t MaxTouchDevices = 32;
|
||||||
|
static constexpr std::size_t MaxActiveTouchInputs = 16;
|
||||||
|
|
||||||
struct ConsoleMotionInfo {
|
struct ConsoleMotionInfo {
|
||||||
Common::Input::MotionStatus raw_status{};
|
Common::Input::MotionStatus raw_status{};
|
||||||
|
@ -27,13 +30,13 @@ struct ConsoleMotionInfo {
|
||||||
};
|
};
|
||||||
|
|
||||||
using ConsoleMotionDevices = std::unique_ptr<Common::Input::InputDevice>;
|
using ConsoleMotionDevices = std::unique_ptr<Common::Input::InputDevice>;
|
||||||
using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, 16>;
|
using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, MaxTouchDevices>;
|
||||||
|
|
||||||
using ConsoleMotionParams = Common::ParamPackage;
|
using ConsoleMotionParams = Common::ParamPackage;
|
||||||
using TouchParams = std::array<Common::ParamPackage, 16>;
|
using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;
|
||||||
|
|
||||||
using ConsoleMotionValues = ConsoleMotionInfo;
|
using ConsoleMotionValues = ConsoleMotionInfo;
|
||||||
using TouchValues = std::array<Common::Input::TouchStatus, 16>;
|
using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;
|
||||||
|
|
||||||
struct TouchFinger {
|
struct TouchFinger {
|
||||||
u64 last_touch{};
|
u64 last_touch{};
|
||||||
|
@ -55,7 +58,7 @@ struct ConsoleMotion {
|
||||||
bool is_at_rest{};
|
bool is_at_rest{};
|
||||||
};
|
};
|
||||||
|
|
||||||
using TouchFingerState = std::array<TouchFinger, 16>;
|
using TouchFingerState = std::array<TouchFinger, MaxActiveTouchInputs>;
|
||||||
|
|
||||||
struct ConsoleStatus {
|
struct ConsoleStatus {
|
||||||
// Data from input_common
|
// Data from input_common
|
||||||
|
@ -166,6 +169,10 @@ private:
|
||||||
*/
|
*/
|
||||||
void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index);
|
void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index);
|
||||||
|
|
||||||
|
std::optional<std::size_t> GetIndexFromFingerId(std::size_t finger_id) const;
|
||||||
|
|
||||||
|
std::optional<std::size_t> GetNextFreeIndex() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers a callback that something has changed on the console status
|
* Triggers a callback that something has changed on the console status
|
||||||
* @param type Input type of the event to trigger
|
* @param type Input type of the event to trigger
|
||||||
|
|
|
@ -200,9 +200,6 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus&
|
||||||
x = std::clamp(x, 0.0f, 1.0f);
|
x = std::clamp(x, 0.0f, 1.0f);
|
||||||
y = std::clamp(y, 0.0f, 1.0f);
|
y = std::clamp(y, 0.0f, 1.0f);
|
||||||
|
|
||||||
// Limit id to maximum number of fingers
|
|
||||||
status.id = std::clamp(status.id, 0, 16);
|
|
||||||
|
|
||||||
if (status.pressed.inverted) {
|
if (status.pressed.inverted) {
|
||||||
status.pressed.value = !status.pressed.value;
|
status.pressed.value = !status.pressed.value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@ namespace InputCommon {
|
||||||
class TouchFromButtonDevice final : public Common::Input::InputDevice {
|
class TouchFromButtonDevice final : public Common::Input::InputDevice {
|
||||||
public:
|
public:
|
||||||
using Button = std::unique_ptr<Common::Input::InputDevice>;
|
using Button = std::unique_ptr<Common::Input::InputDevice>;
|
||||||
TouchFromButtonDevice(Button button_, int touch_id_, float x_, float y_)
|
TouchFromButtonDevice(Button button_, float x_, float y_)
|
||||||
: button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) {
|
: button(std::move(button_)), x(x_), y(y_) {
|
||||||
last_button_value = false;
|
last_button_value = false;
|
||||||
button->SetCallback({
|
button->SetCallback({
|
||||||
.on_change =
|
.on_change =
|
||||||
|
@ -34,7 +34,6 @@ public:
|
||||||
.pressed = button_status,
|
.pressed = button_status,
|
||||||
.x = {},
|
.x = {},
|
||||||
.y = {},
|
.y = {},
|
||||||
.id = touch_id,
|
|
||||||
};
|
};
|
||||||
status.x.properties = properties;
|
status.x.properties = properties;
|
||||||
status.y.properties = properties;
|
status.y.properties = properties;
|
||||||
|
@ -62,7 +61,6 @@ public:
|
||||||
private:
|
private:
|
||||||
Button button;
|
Button button;
|
||||||
bool last_button_value;
|
bool last_button_value;
|
||||||
const int touch_id;
|
|
||||||
const float x;
|
const float x;
|
||||||
const float y;
|
const float y;
|
||||||
const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false};
|
const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false};
|
||||||
|
@ -73,10 +71,9 @@ std::unique_ptr<Common::Input::InputDevice> TouchFromButton::Create(
|
||||||
const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize();
|
const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize();
|
||||||
auto button = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>(
|
auto button = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>(
|
||||||
params.Get("button", null_engine));
|
params.Get("button", null_engine));
|
||||||
const auto touch_id = params.Get("touch_id", 0);
|
|
||||||
const float x = params.Get("x", 0.0f) / 1280.0f;
|
const float x = params.Get("x", 0.0f) / 1280.0f;
|
||||||
const float y = params.Get("y", 0.0f) / 720.0f;
|
const float y = params.Get("y", 0.0f) / 720.0f;
|
||||||
return std::make_unique<TouchFromButtonDevice>(std::move(button), touch_id, x, y);
|
return std::make_unique<TouchFromButtonDevice>(std::move(button), x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace InputCommon
|
} // namespace InputCommon
|
||||||
|
|
|
@ -229,13 +229,12 @@ private:
|
||||||
|
|
||||||
class InputFromTouch final : public Common::Input::InputDevice {
|
class InputFromTouch final : public Common::Input::InputDevice {
|
||||||
public:
|
public:
|
||||||
explicit InputFromTouch(PadIdentifier identifier_, int touch_id_, int button_, bool toggle_,
|
explicit InputFromTouch(PadIdentifier identifier_, int button_, bool toggle_, bool inverted_,
|
||||||
bool inverted_, int axis_x_, int axis_y_,
|
int axis_x_, int axis_y_, Common::Input::AnalogProperties properties_x_,
|
||||||
Common::Input::AnalogProperties properties_x_,
|
|
||||||
Common::Input::AnalogProperties properties_y_,
|
Common::Input::AnalogProperties properties_y_,
|
||||||
InputEngine* input_engine_)
|
InputEngine* input_engine_)
|
||||||
: identifier(identifier_), touch_id(touch_id_), button(button_), toggle(toggle_),
|
: identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_),
|
||||||
inverted(inverted_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_),
|
axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_),
|
||||||
properties_y(properties_y_), input_engine(input_engine_) {
|
properties_y(properties_y_), input_engine(input_engine_) {
|
||||||
UpdateCallback engine_callback{[this]() { OnChange(); }};
|
UpdateCallback engine_callback{[this]() { OnChange(); }};
|
||||||
const InputIdentifier button_input_identifier{
|
const InputIdentifier button_input_identifier{
|
||||||
|
@ -271,8 +270,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::Input::TouchStatus GetStatus() const {
|
Common::Input::TouchStatus GetStatus() const {
|
||||||
Common::Input::TouchStatus status;
|
Common::Input::TouchStatus status{};
|
||||||
status.id = touch_id;
|
|
||||||
status.pressed = {
|
status.pressed = {
|
||||||
.value = input_engine->GetButton(identifier, button),
|
.value = input_engine->GetButton(identifier, button),
|
||||||
.inverted = inverted,
|
.inverted = inverted,
|
||||||
|
@ -307,7 +305,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const PadIdentifier identifier;
|
const PadIdentifier identifier;
|
||||||
const int touch_id;
|
|
||||||
const int button;
|
const int button;
|
||||||
const bool toggle;
|
const bool toggle;
|
||||||
const bool inverted;
|
const bool inverted;
|
||||||
|
@ -919,7 +916,6 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTriggerDevice(
|
||||||
|
|
||||||
std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice(
|
std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice(
|
||||||
const Common::ParamPackage& params) {
|
const Common::ParamPackage& params) {
|
||||||
const auto touch_id = params.Get("touch_id", 0);
|
|
||||||
const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
|
const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
|
||||||
const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f);
|
const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f);
|
||||||
const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f);
|
const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f);
|
||||||
|
@ -954,8 +950,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice(
|
||||||
input_engine->PreSetAxis(identifier, axis_x);
|
input_engine->PreSetAxis(identifier, axis_x);
|
||||||
input_engine->PreSetAxis(identifier, axis_y);
|
input_engine->PreSetAxis(identifier, axis_y);
|
||||||
input_engine->PreSetButton(identifier, button);
|
input_engine->PreSetButton(identifier, button);
|
||||||
return std::make_unique<InputFromTouch>(identifier, touch_id, button, toggle, inverted, axis_x,
|
return std::make_unique<InputFromTouch>(identifier, button, toggle, inverted, axis_x, axis_y,
|
||||||
axis_y, properties_x, properties_y, input_engine.get());
|
properties_x, properties_y, input_engine.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateBatteryDevice(
|
std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateBatteryDevice(
|
||||||
|
|
Reference in New Issue