input_common: Move touch and analog from button. Move udp protocol

merge-requests/60/head
german77 2021-09-20 16:57:55 +07:00 committed by Narr the Reg
parent 854c933716
commit 4c6f2c2547
10 changed files with 173 additions and 133 deletions

@ -1,8 +1,12 @@
add_library(input_common STATIC
analog_from_button.cpp
analog_from_button.h
keyboard.cpp
keyboard.h
helpers/stick_from_buttons.cpp
helpers/stick_from_buttons.h
helpers/touch_from_buttons.cpp
helpers/touch_from_buttons.h
helpers/udp_protocol.cpp
helpers/udp_protocol.h
input_engine.cpp
input_engine.h
input_mapping.cpp
@ -15,8 +19,6 @@ add_library(input_common STATIC
motion_from_button.h
motion_input.cpp
motion_input.h
touch_from_button.cpp
touch_from_button.h
gcadapter/gc_adapter.cpp
gcadapter/gc_adapter.h
gcadapter/gc_poller.cpp
@ -33,8 +35,6 @@ add_library(input_common STATIC
tas/tas_poller.h
udp/client.cpp
udp/client.h
udp/protocol.cpp
udp/protocol.h
udp/udp.cpp
udp/udp.h
)

@ -2,32 +2,38 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <atomic>
#include <chrono>
#include <cmath>
#include <thread>
#include "common/math_util.h"
#include "common/settings.h"
#include "input_common/analog_from_button.h"
#include "input_common/helpers/stick_from_buttons.h"
namespace InputCommon {
class Analog final : public Input::AnalogDevice {
class Stick final : public Input::InputDevice {
public:
using Button = std::unique_ptr<Input::ButtonDevice>;
using Button = std::unique_ptr<Input::InputDevice>;
Analog(Button up_, Button down_, Button left_, Button right_, Button modifier_,
float modifier_scale_, float modifier_angle_)
Stick(Button up_, Button down_, Button left_, Button right_, Button modifier_,
float modifier_scale_, float modifier_angle_)
: up(std::move(up_)), down(std::move(down_)), left(std::move(left_)),
right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_),
modifier_angle(modifier_angle_) {
Input::InputCallback<bool> callbacks{
[this]([[maybe_unused]] bool status) { UpdateStatus(); }};
up->SetCallback(callbacks);
down->SetCallback(callbacks);
left->SetCallback(callbacks);
right->SetCallback(callbacks);
modifier->SetCallback(callbacks);
Input::InputCallback button_up_callback{
[this](Input::CallbackStatus callback_) { UpdateUpButtonStatus(callback_); }};
Input::InputCallback button_down_callback{
[this](Input::CallbackStatus callback_) { UpdateDownButtonStatus(callback_); }};
Input::InputCallback button_left_callback{
[this](Input::CallbackStatus callback_) { UpdateLeftButtonStatus(callback_); }};
Input::InputCallback button_right_callback{
[this](Input::CallbackStatus callback_) { UpdateRightButtonStatus(callback_); }};
Input::InputCallback button_modifier_callback{
[this](Input::CallbackStatus callback_) { UpdateModButtonStatus(callback_); }};
up->SetCallback(button_up_callback);
down->SetCallback(button_down_callback);
left->SetCallback(button_left_callback);
right->SetCallback(button_right_callback);
modifier->SetCallback(button_modifier_callback);
}
bool IsAngleGreater(float old_angle, float new_angle) const {
@ -123,13 +129,38 @@ public:
}
}
void UpdateStatus() {
const float coef = modifier->GetStatus() ? modifier_scale : 1.0f;
void UpdateUpButtonStatus(Input::CallbackStatus button_callback) {
up_status = button_callback.button_status.value;
UpdateStatus();
}
bool r = right->GetStatus();
bool l = left->GetStatus();
bool u = up->GetStatus();
bool d = down->GetStatus();
void UpdateDownButtonStatus(Input::CallbackStatus button_callback) {
down_status = button_callback.button_status.value;
UpdateStatus();
}
void UpdateLeftButtonStatus(Input::CallbackStatus button_callback) {
left_status = button_callback.button_status.value;
UpdateStatus();
}
void UpdateRightButtonStatus(Input::CallbackStatus button_callback) {
right_status = button_callback.button_status.value;
UpdateStatus();
}
void UpdateModButtonStatus(Input::CallbackStatus button_callback) {
modifier_status = button_callback.button_status.value;
UpdateStatus();
}
void UpdateStatus() {
const float coef = modifier_status ? modifier_scale : 1.0f;
bool r = right_status;
bool l = left_status;
bool u = up_status;
bool d = down_status;
// Eliminate contradictory movements
if (r && l) {
@ -162,49 +193,42 @@ public:
}
last_update = now;
Input::CallbackStatus status{
.type = Input::InputType::Stick,
.stick_status = GetStatus(),
};
TriggerOnChange(status);
}
std::tuple<float, float> GetStatus() const override {
Input::StickStatus GetStatus() const {
Input::StickStatus status{};
status.x.properties = properties;
status.y.properties = properties;
if (Settings::values.emulate_analog_keyboard) {
const auto now = std::chrono::steady_clock::now();
float angle_ = GetAngle(now);
return std::make_tuple(std::cos(angle_) * amplitude, std::sin(angle_) * amplitude);
status.x.raw_value = std::cos(angle_) * amplitude;
status.y.raw_value = std::sin(angle_) * amplitude;
return status;
}
constexpr float SQRT_HALF = 0.707106781f;
int x = 0, y = 0;
if (right->GetStatus()) {
if (right_status) {
++x;
}
if (left->GetStatus()) {
if (left_status) {
--x;
}
if (up->GetStatus()) {
if (up_status) {
++y;
}
if (down->GetStatus()) {
if (down_status) {
--y;
}
const float coef = modifier->GetStatus() ? modifier_scale : 1.0f;
return std::make_tuple(static_cast<float>(x) * coef * (y == 0 ? 1.0f : SQRT_HALF),
static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF));
}
Input::AnalogProperties GetAnalogProperties() const override {
return {modifier_scale, 1.0f, 0.5f};
}
bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
switch (direction) {
case Input::AnalogDirection::RIGHT:
return right->GetStatus();
case Input::AnalogDirection::LEFT:
return left->GetStatus();
case Input::AnalogDirection::UP:
return up->GetStatus();
case Input::AnalogDirection::DOWN:
return down->GetStatus();
}
return false;
const float coef = modifier_status ? modifier_scale : 1.0f;
status.x.raw_value = static_cast<float>(x) * coef * (y == 0 ? 1.0f : SQRT_HALF);
status.y.raw_value = static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF);
return status;
}
private:
@ -218,21 +242,29 @@ private:
float angle{};
float goal_angle{};
float amplitude{};
bool up_status;
bool down_status;
bool left_status;
bool right_status;
bool modifier_status;
const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false};
std::chrono::time_point<std::chrono::steady_clock> last_update;
};
std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) {
std::unique_ptr<Input::InputDevice> StickFromButton::Create(const Common::ParamPackage& params) {
const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize();
auto up = Input::CreateDevice<Input::ButtonDevice>(params.Get("up", null_engine));
auto down = Input::CreateDevice<Input::ButtonDevice>(params.Get("down", null_engine));
auto left = Input::CreateDevice<Input::ButtonDevice>(params.Get("left", null_engine));
auto right = Input::CreateDevice<Input::ButtonDevice>(params.Get("right", null_engine));
auto modifier = Input::CreateDevice<Input::ButtonDevice>(params.Get("modifier", null_engine));
auto up = Input::CreateDeviceFromString<Input::InputDevice>(params.Get("up", null_engine));
auto down = Input::CreateDeviceFromString<Input::InputDevice>(params.Get("down", null_engine));
auto left = Input::CreateDeviceFromString<Input::InputDevice>(params.Get("left", null_engine));
auto right =
Input::CreateDeviceFromString<Input::InputDevice>(params.Get("right", null_engine));
auto modifier =
Input::CreateDeviceFromString<Input::InputDevice>(params.Get("modifier", null_engine));
auto modifier_scale = params.Get("modifier_scale", 0.5f);
auto modifier_angle = params.Get("modifier_angle", 5.5f);
return std::make_unique<Analog>(std::move(up), std::move(down), std::move(left),
std::move(right), std::move(modifier), modifier_scale,
modifier_angle);
return std::make_unique<Stick>(std::move(up), std::move(down), std::move(left),
std::move(right), std::move(modifier), modifier_scale,
modifier_angle);
}
} // namespace InputCommon

@ -1,11 +1,11 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include "core/frontend/input.h"
#include "common/input.h"
namespace InputCommon {
@ -13,7 +13,7 @@ namespace InputCommon {
* An analog device factory that takes direction button devices and combines them into a analog
* device.
*/
class AnalogFromButton final : public Input::Factory<Input::AnalogDevice> {
class StickFromButton final : public Input::Factory<Input::InputDevice> {
public:
/**
* Creates an analog device from direction button devices
@ -25,7 +25,7 @@ public:
* - "modifier": a serialized ParamPackage for creating a button device as the modifier
* - "modifier_scale": a float for the multiplier the modifier gives to the position
*/
std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override;
std::unique_ptr<Input::InputDevice> Create(const Common::ParamPackage& params) override;
};
} // namespace InputCommon

@ -0,0 +1,70 @@
// Copyright 2020 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include "common/settings.h"
#include "core/frontend/framebuffer_layout.h"
#include "input_common/helpers/touch_from_buttons.h"
namespace InputCommon {
class TouchFromButtonDevice final : public Input::InputDevice {
public:
using Button = std::unique_ptr<Input::InputDevice>;
TouchFromButtonDevice(Button button_, u32 touch_id_, float x_, float y_)
: button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) {
Input::InputCallback button_up_callback{
[this](Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }};
button->SetCallback(button_up_callback);
}
Input::TouchStatus GetStatus(bool pressed) const {
const Input::ButtonStatus button_status{
.value = pressed,
};
Input::TouchStatus status{
.pressed = button_status,
.x = {},
.y = {},
.id = touch_id,
};
status.x.properties = properties;
status.y.properties = properties;
if (!pressed) {
return status;
}
status.x.raw_value = x;
status.y.raw_value = y;
return status;
}
void UpdateButtonStatus(Input::CallbackStatus button_callback) {
const Input::CallbackStatus status{
.type = Input::InputType::Touch,
.touch_status = GetStatus(button_callback.button_status.value),
};
TriggerOnChange(status);
}
private:
Button button;
const u32 touch_id;
const float x;
const float y;
const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false};
};
std::unique_ptr<Input::InputDevice> TouchFromButton::Create(const Common::ParamPackage& params) {
const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize();
auto button =
Input::CreateDeviceFromString<Input::InputDevice>(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 y = params.Get("y", 0.0f) / 720.0f;
return std::make_unique<TouchFromButtonDevice>(std::move(button), touch_id, x, y);
}
} // namespace InputCommon

@ -4,20 +4,19 @@
#pragma once
#include <memory>
#include "core/frontend/input.h"
#include "common/input.h"
namespace InputCommon {
/**
* A touch device factory that takes a list of button devices and combines them into a touch device.
*/
class TouchFromButtonFactory final : public Input::Factory<Input::TouchDevice> {
class TouchFromButton final : public Input::Factory<Input::InputDevice> {
public:
/**
* Creates a touch device from a list of button devices
*/
std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override;
std::unique_ptr<Input::InputDevice> Create(const Common::ParamPackage& params) override;
};
} // namespace InputCommon

@ -5,7 +5,7 @@
#include <cstddef>
#include <cstring>
#include "common/logging/log.h"
#include "input_common/udp/protocol.h"
#include "input_common/helpers/udp_protocol.h"
namespace InputCommon::CemuhookUDP {

@ -6,7 +6,6 @@
#include <thread>
#include "common/param_package.h"
#include "common/settings.h"
#include "input_common/analog_from_button.h"
#include "input_common/gcadapter/gc_adapter.h"
#include "input_common/gcadapter/gc_poller.h"
#include "input_common/keyboard.h"
@ -16,7 +15,6 @@
#include "input_common/mouse/mouse_poller.h"
#include "input_common/tas/tas_input.h"
#include "input_common/tas/tas_poller.h"
#include "input_common/touch_from_button.h"
#include "input_common/udp/client.h"
#include "input_common/udp/udp.h"
#ifdef HAVE_SDL2
@ -37,12 +35,8 @@ struct InputSubsystem::Impl {
keyboard = std::make_shared<Keyboard>();
Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
Input::RegisterFactory<Input::AnalogDevice>("analog_from_button",
std::make_shared<AnalogFromButton>());
Input::RegisterFactory<Input::MotionDevice>("keyboard",
std::make_shared<MotionFromButton>());
Input::RegisterFactory<Input::TouchDevice>("touch_from_button",
std::make_shared<TouchFromButtonFactory>());
#ifdef HAVE_SDL2
sdl = SDL::Init();
@ -75,8 +69,6 @@ struct InputSubsystem::Impl {
Input::UnregisterFactory<Input::ButtonDevice>("keyboard");
Input::UnregisterFactory<Input::MotionDevice>("keyboard");
keyboard.reset();
Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
Input::UnregisterFactory<Input::TouchDevice>("touch_from_button");
#ifdef HAVE_SDL2
sdl.reset();
#endif

@ -1,53 +0,0 @@
// Copyright 2020 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include "common/settings.h"
#include "core/frontend/framebuffer_layout.h"
#include "input_common/touch_from_button.h"
namespace InputCommon {
class TouchFromButtonDevice final : public Input::TouchDevice {
public:
TouchFromButtonDevice() {
const auto button_index =
static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
const auto& buttons = Settings::values.touch_from_button_maps[button_index].buttons;
for (const auto& config_entry : buttons) {
const Common::ParamPackage package{config_entry};
map.emplace_back(
Input::CreateDevice<Input::ButtonDevice>(config_entry),
std::clamp(package.Get("x", 0), 0, static_cast<int>(Layout::ScreenUndocked::Width)),
std::clamp(package.Get("y", 0), 0,
static_cast<int>(Layout::ScreenUndocked::Height)));
}
}
Input::TouchStatus GetStatus() const override {
Input::TouchStatus touch_status{};
for (std::size_t id = 0; id < map.size() && id < touch_status.size(); ++id) {
const bool state = std::get<0>(map[id])->GetStatus();
if (state) {
const float x = static_cast<float>(std::get<1>(map[id])) /
static_cast<int>(Layout::ScreenUndocked::Width);
const float y = static_cast<float>(std::get<2>(map[id])) /
static_cast<int>(Layout::ScreenUndocked::Height);
touch_status[id] = {x, y, true};
}
}
return touch_status;
}
private:
// A vector of the mapped button, its x and its y-coordinate
std::vector<std::tuple<std::unique_ptr<Input::ButtonDevice>, int, int>> map;
};
std::unique_ptr<Input::TouchDevice> TouchFromButtonFactory::Create(const Common::ParamPackage&) {
return std::make_unique<TouchFromButtonDevice>();
}
} // namespace InputCommon

@ -11,7 +11,7 @@
#include "common/logging/log.h"
#include "common/settings.h"
#include "input_common/udp/client.h"
#include "input_common/udp/protocol.h"
#include "input_common/helpers/udp_protocol.h"
using boost::asio::ip::udp;