1 // Copyright 2020 yuzu Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4 
5 #include <mutex>
6 #include <utility>
7 #include "common/assert.h"
8 #include "common/threadsafe_queue.h"
9 #include "input_common/udp/client.h"
10 #include "input_common/udp/udp.h"
11 
12 namespace InputCommon {
13 
14 class UDPMotion final : public Input::MotionDevice {
15 public:
UDPMotion(std::string ip_,u16 port_,u16 pad_,CemuhookUDP::Client * client_)16     explicit UDPMotion(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_)
17         : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {}
18 
GetStatus() const19     Input::MotionStatus GetStatus() const override {
20         return client->GetPadState(ip, port, pad).motion_status;
21     }
22 
23 private:
24     const std::string ip;
25     const u16 port;
26     const u16 pad;
27     CemuhookUDP::Client* client;
28     mutable std::mutex mutex;
29 };
30 
31 /// A motion device factory that creates motion devices from JC Adapter
UDPMotionFactory(std::shared_ptr<CemuhookUDP::Client> client_)32 UDPMotionFactory::UDPMotionFactory(std::shared_ptr<CemuhookUDP::Client> client_)
33     : client(std::move(client_)) {}
34 
35 /**
36  * Creates motion device
37  * @param params contains parameters for creating the device:
38  *     - "port": the nth jcpad on the adapter
39  */
Create(const Common::ParamPackage & params)40 std::unique_ptr<Input::MotionDevice> UDPMotionFactory::Create(const Common::ParamPackage& params) {
41     auto ip = params.Get("ip", "127.0.0.1");
42     const auto port = static_cast<u16>(params.Get("port", 26760));
43     const auto pad = static_cast<u16>(params.Get("pad_index", 0));
44 
45     return std::make_unique<UDPMotion>(std::move(ip), port, pad, client.get());
46 }
47 
BeginConfiguration()48 void UDPMotionFactory::BeginConfiguration() {
49     polling = true;
50     client->BeginConfiguration();
51 }
52 
EndConfiguration()53 void UDPMotionFactory::EndConfiguration() {
54     polling = false;
55     client->EndConfiguration();
56 }
57 
GetNextInput()58 Common::ParamPackage UDPMotionFactory::GetNextInput() {
59     Common::ParamPackage params;
60     CemuhookUDP::UDPPadStatus pad;
61     auto& queue = client->GetPadQueue();
62     while (queue.Pop(pad)) {
63         if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) {
64             continue;
65         }
66         params.Set("engine", "cemuhookudp");
67         params.Set("ip", pad.host);
68         params.Set("port", static_cast<u16>(pad.port));
69         params.Set("pad_index", static_cast<u16>(pad.pad_index));
70         params.Set("motion", static_cast<u16>(pad.motion));
71         return params;
72     }
73     return params;
74 }
75 
76 class UDPTouch final : public Input::TouchDevice {
77 public:
UDPTouch(std::string ip_,u16 port_,u16 pad_,CemuhookUDP::Client * client_)78     explicit UDPTouch(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_)
79         : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {}
80 
GetStatus() const81     std::tuple<float, float, bool> GetStatus() const override {
82         return client->GetPadState(ip, port, pad).touch_status;
83     }
84 
85 private:
86     const std::string ip;
87     const u16 port;
88     const u16 pad;
89     CemuhookUDP::Client* client;
90     mutable std::mutex mutex;
91 };
92 
93 /// A motion device factory that creates motion devices from JC Adapter
UDPTouchFactory(std::shared_ptr<CemuhookUDP::Client> client_)94 UDPTouchFactory::UDPTouchFactory(std::shared_ptr<CemuhookUDP::Client> client_)
95     : client(std::move(client_)) {}
96 
97 /**
98  * Creates motion device
99  * @param params contains parameters for creating the device:
100  *     - "port": the nth jcpad on the adapter
101  */
Create(const Common::ParamPackage & params)102 std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamPackage& params) {
103     auto ip = params.Get("ip", "127.0.0.1");
104     const auto port = static_cast<u16>(params.Get("port", 26760));
105     const auto pad = static_cast<u16>(params.Get("pad_index", 0));
106 
107     return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get());
108 }
109 
BeginConfiguration()110 void UDPTouchFactory::BeginConfiguration() {
111     polling = true;
112     client->BeginConfiguration();
113 }
114 
EndConfiguration()115 void UDPTouchFactory::EndConfiguration() {
116     polling = false;
117     client->EndConfiguration();
118 }
119 
GetNextInput()120 Common::ParamPackage UDPTouchFactory::GetNextInput() {
121     Common::ParamPackage params;
122     CemuhookUDP::UDPPadStatus pad;
123     auto& queue = client->GetPadQueue();
124     while (queue.Pop(pad)) {
125         if (pad.touch == CemuhookUDP::PadTouch::Undefined) {
126             continue;
127         }
128         params.Set("engine", "cemuhookudp");
129         params.Set("ip", pad.host);
130         params.Set("port", static_cast<u16>(pad.port));
131         params.Set("pad_index", static_cast<u16>(pad.pad_index));
132         params.Set("touch", static_cast<u16>(pad.touch));
133         return params;
134     }
135     return params;
136 }
137 
138 } // namespace InputCommon
139