mirror of
https://github.com/citra-emu/citra.git
synced 2024-12-18 23:00:04 +00:00
input_common, common: Add a few functions
These functions include reloading udp client, testing communication and configuring calibration. I also added a function to common/thread.h to use WaitFor.
This commit is contained in:
parent
58639220a0
commit
8af89b6979
@ -55,6 +55,15 @@ public:
|
||||
is_set = false;
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
bool WaitFor(const std::chrono::duration<Duration>& time) {
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
if (!condvar.wait_for(lk, time, [this] { return is_set; }))
|
||||
return false;
|
||||
is_set = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
bool WaitUntil(const std::chrono::time_point<Clock, Duration>& time) {
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
|
@ -76,6 +76,11 @@ std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left,
|
||||
return circle_pad_param.Serialize();
|
||||
}
|
||||
|
||||
void ReloadInputDevices() {
|
||||
if (udp)
|
||||
udp->ReloadUDPClient();
|
||||
}
|
||||
|
||||
namespace Polling {
|
||||
|
||||
std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
|
||||
|
@ -37,6 +37,9 @@ std::string GenerateKeyboardParam(int key_code);
|
||||
std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
|
||||
int key_modifier, float modifier_scale);
|
||||
|
||||
/// Reloads the input devices
|
||||
void ReloadInputDevices();
|
||||
|
||||
namespace Polling {
|
||||
|
||||
enum class DeviceType { Button, Analog };
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include "common/logging/log.h"
|
||||
#include "common/vector_math.h"
|
||||
#include "input_common/udp/client.h"
|
||||
#include "input_common/udp/protocol.h"
|
||||
|
||||
@ -128,12 +127,7 @@ static void SocketLoop(Socket* socket) {
|
||||
Client::Client(std::shared_ptr<DeviceStatus> status, const std::string& host, u16 port,
|
||||
u8 pad_index, u32 client_id)
|
||||
: status(status) {
|
||||
SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
|
||||
[this](Response::PortInfo info) { OnPortInfo(info); },
|
||||
[this](Response::PadData data) { OnPadData(data); }};
|
||||
LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port);
|
||||
socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback);
|
||||
thread = std::thread{SocketLoop, this->socket.get()};
|
||||
StartCommunication(host, port, pad_index, client_id);
|
||||
}
|
||||
|
||||
Client::~Client() {
|
||||
@ -141,6 +135,12 @@ Client::~Client() {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
void Client::ReloadSocket(const std::string& host, u16 port, u8 pad_index, u32 client_id) {
|
||||
socket->Stop();
|
||||
thread.join();
|
||||
StartCommunication(host, port, pad_index, client_id);
|
||||
}
|
||||
|
||||
void Client::OnVersion(Response::Version data) {
|
||||
LOG_TRACE(Input, "Version packet received: {}", data.version);
|
||||
}
|
||||
@ -192,4 +192,93 @@ void Client::OnPadData(Response::PadData data) {
|
||||
}
|
||||
}
|
||||
|
||||
void Client::StartCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id) {
|
||||
SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
|
||||
[this](Response::PortInfo info) { OnPortInfo(info); },
|
||||
[this](Response::PadData data) { OnPadData(data); }};
|
||||
LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port);
|
||||
socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback);
|
||||
thread = std::thread{SocketLoop, this->socket.get()};
|
||||
}
|
||||
|
||||
void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id,
|
||||
std::function<void()> success_callback,
|
||||
std::function<void()> failure_callback) {
|
||||
std::thread([=] {
|
||||
Common::Event success_event;
|
||||
SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {},
|
||||
[&](Response::PadData data) { success_event.Set(); }};
|
||||
Socket socket{host, port, pad_index, client_id, callback};
|
||||
std::thread worker_thread{SocketLoop, &socket};
|
||||
bool result = success_event.WaitFor(std::chrono::seconds(8));
|
||||
socket.Stop();
|
||||
worker_thread.join();
|
||||
if (result)
|
||||
success_callback();
|
||||
else
|
||||
failure_callback();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
CalibrationConfigurationJob::CalibrationConfigurationJob(
|
||||
const std::string& host, u16 port, u8 pad_index, u32 client_id,
|
||||
std::function<void(Status)> status_callback,
|
||||
std::function<void(u16, u16, u16, u16)> data_callback) {
|
||||
|
||||
std::thread([=] {
|
||||
constexpr u16 CALIBRATION_THRESHOLD = 100;
|
||||
|
||||
u16 min_x{UINT16_MAX}, min_y{UINT16_MAX};
|
||||
u16 max_x, max_y;
|
||||
|
||||
Status current_status{Status::Initialized};
|
||||
SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {},
|
||||
[&](Response::PadData data) {
|
||||
if (current_status == Status::Initialized) {
|
||||
// Receiving data means the communication is ready now
|
||||
current_status = Status::Ready;
|
||||
status_callback(current_status);
|
||||
}
|
||||
if (!data.touch_1.is_active)
|
||||
return;
|
||||
LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x,
|
||||
data.touch_1.y);
|
||||
min_x = std::min(min_x, static_cast<u16>(data.touch_1.x));
|
||||
min_y = std::min(min_y, static_cast<u16>(data.touch_1.y));
|
||||
if (current_status == Status::Ready) {
|
||||
// First touch - min data (min_x/min_y)
|
||||
current_status = Status::Stage1Completed;
|
||||
status_callback(current_status);
|
||||
}
|
||||
if (data.touch_1.x - min_x > CALIBRATION_THRESHOLD &&
|
||||
data.touch_1.y - min_y > CALIBRATION_THRESHOLD) {
|
||||
// Set the current position as max value and finishes
|
||||
// configuration
|
||||
max_x = data.touch_1.x;
|
||||
max_y = data.touch_1.y;
|
||||
current_status = Status::Completed;
|
||||
data_callback(min_x, min_y, max_x, max_y);
|
||||
status_callback(current_status);
|
||||
|
||||
complete_event.Set();
|
||||
}
|
||||
}};
|
||||
Socket socket{host, port, pad_index, client_id, callback};
|
||||
std::thread worker_thread{SocketLoop, &socket};
|
||||
complete_event.Wait();
|
||||
socket.Stop();
|
||||
worker_thread.join();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
CalibrationConfigurationJob::~CalibrationConfigurationJob() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void CalibrationConfigurationJob::Stop() {
|
||||
complete_event.Set();
|
||||
}
|
||||
|
||||
} // namespace InputCommon::CemuhookUDP
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <vector>
|
||||
#include <boost/optional.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/thread.h"
|
||||
#include "common/vector_math.h"
|
||||
|
||||
namespace InputCommon::CemuhookUDP {
|
||||
@ -47,15 +48,48 @@ public:
|
||||
explicit Client(std::shared_ptr<DeviceStatus> status, const std::string& host = DEFAULT_ADDR,
|
||||
u16 port = DEFAULT_PORT, u8 pad_index = 0, u32 client_id = 24872);
|
||||
~Client();
|
||||
void ReloadSocket(const std::string& host = "127.0.0.1", u16 port = 26760, u8 pad_index = 0,
|
||||
u32 client_id = 24872);
|
||||
|
||||
private:
|
||||
void OnVersion(Response::Version);
|
||||
void OnPortInfo(Response::PortInfo);
|
||||
void OnPadData(Response::PadData);
|
||||
void StartCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id);
|
||||
|
||||
std::unique_ptr<Socket> socket;
|
||||
std::shared_ptr<DeviceStatus> status;
|
||||
std::thread thread;
|
||||
u64 packet_sequence = 0;
|
||||
};
|
||||
|
||||
/// An async job allowing configuration of the touchpad calibration.
|
||||
class CalibrationConfigurationJob {
|
||||
public:
|
||||
enum class Status {
|
||||
Initialized,
|
||||
Ready,
|
||||
Stage1Completed,
|
||||
Completed,
|
||||
};
|
||||
/**
|
||||
* Constructs and starts the job with the specified parameter.
|
||||
*
|
||||
* @param status_callback Callback for job status updates
|
||||
* @param data_callback Called when calibration data is ready
|
||||
*/
|
||||
explicit CalibrationConfigurationJob(const std::string& host, u16 port, u8 pad_index,
|
||||
u32 client_id, std::function<void(Status)> status_callback,
|
||||
std::function<void(u16, u16, u16, u16)> data_callback);
|
||||
~CalibrationConfigurationJob();
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
Common::Event complete_event;
|
||||
};
|
||||
|
||||
void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id,
|
||||
std::function<void()> success_callback,
|
||||
std::function<void()> failure_callback);
|
||||
|
||||
} // namespace InputCommon::CemuhookUDP
|
||||
|
@ -85,6 +85,11 @@ State::~State() {
|
||||
Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
|
||||
}
|
||||
|
||||
void State::ReloadUDPClient() {
|
||||
client->ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port,
|
||||
Settings::values.udp_pad_index);
|
||||
}
|
||||
|
||||
std::unique_ptr<State> Init() {
|
||||
return std::make_unique<State>();
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ class State {
|
||||
public:
|
||||
State();
|
||||
~State();
|
||||
void ReloadUDPClient();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Client> client;
|
||||
|
Loading…
Reference in New Issue
Block a user