summaryrefslogtreecommitdiff
path: root/src/input_common/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/drivers')
-rw-r--r--src/input_common/drivers/camera.cpp82
-rw-r--r--src/input_common/drivers/camera.h29
-rw-r--r--src/input_common/drivers/gc_adapter.cpp25
-rw-r--r--src/input_common/drivers/gc_adapter.h8
-rw-r--r--src/input_common/drivers/keyboard.cpp5
-rw-r--r--src/input_common/drivers/keyboard.h5
-rw-r--r--src/input_common/drivers/mouse.cpp7
-rw-r--r--src/input_common/drivers/mouse.h5
-rw-r--r--src/input_common/drivers/sdl_driver.cpp167
-rw-r--r--src/input_common/drivers/sdl_driver.h35
-rw-r--r--src/input_common/drivers/tas_input.cpp5
-rw-r--r--src/input_common/drivers/tas_input.h5
-rw-r--r--src/input_common/drivers/touch_screen.cpp94
-rw-r--r--src/input_common/drivers/touch_screen.h57
-rw-r--r--src/input_common/drivers/udp_client.cpp35
-rw-r--r--src/input_common/drivers/udp_client.h9
-rw-r--r--src/input_common/drivers/virtual_amiibo.cpp101
-rw-r--r--src/input_common/drivers/virtual_amiibo.h61
18 files changed, 597 insertions, 138 deletions
diff --git a/src/input_common/drivers/camera.cpp b/src/input_common/drivers/camera.cpp
new file mode 100644
index 000000000..dceea67e0
--- /dev/null
+++ b/src/input_common/drivers/camera.cpp
@@ -0,0 +1,82 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <fmt/format.h>
5
6#include "common/param_package.h"
7#include "input_common/drivers/camera.h"
8
9namespace InputCommon {
10constexpr PadIdentifier identifier = {
11 .guid = Common::UUID{},
12 .port = 0,
13 .pad = 0,
14};
15
16Camera::Camera(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
17 PreSetController(identifier);
18}
19
20void Camera::SetCameraData(std::size_t width, std::size_t height, std::vector<u32> data) {
21 const std::size_t desired_width = getImageWidth();
22 const std::size_t desired_height = getImageHeight();
23 status.data.resize(desired_width * desired_height);
24
25 // Resize image to desired format
26 for (std::size_t y = 0; y < desired_height; y++) {
27 for (std::size_t x = 0; x < desired_width; x++) {
28 const std::size_t pixel_index = y * desired_width + x;
29 const std::size_t old_x = width * x / desired_width;
30 const std::size_t old_y = height * y / desired_height;
31 const std::size_t data_pixel_index = old_y * width + old_x;
32 status.data[pixel_index] = static_cast<u8>(data[data_pixel_index] & 0xFF);
33 }
34 }
35
36 SetCamera(identifier, status);
37}
38
39std::size_t Camera::getImageWidth() const {
40 switch (status.format) {
41 case Common::Input::CameraFormat::Size320x240:
42 return 320;
43 case Common::Input::CameraFormat::Size160x120:
44 return 160;
45 case Common::Input::CameraFormat::Size80x60:
46 return 80;
47 case Common::Input::CameraFormat::Size40x30:
48 return 40;
49 case Common::Input::CameraFormat::Size20x15:
50 return 20;
51 case Common::Input::CameraFormat::None:
52 default:
53 return 0;
54 }
55}
56
57std::size_t Camera::getImageHeight() const {
58 switch (status.format) {
59 case Common::Input::CameraFormat::Size320x240:
60 return 240;
61 case Common::Input::CameraFormat::Size160x120:
62 return 120;
63 case Common::Input::CameraFormat::Size80x60:
64 return 60;
65 case Common::Input::CameraFormat::Size40x30:
66 return 30;
67 case Common::Input::CameraFormat::Size20x15:
68 return 15;
69 case Common::Input::CameraFormat::None:
70 default:
71 return 0;
72 }
73}
74
75Common::Input::CameraError Camera::SetCameraFormat(
76 [[maybe_unused]] const PadIdentifier& identifier_,
77 const Common::Input::CameraFormat camera_format) {
78 status.format = camera_format;
79 return Common::Input::CameraError::None;
80}
81
82} // namespace InputCommon
diff --git a/src/input_common/drivers/camera.h b/src/input_common/drivers/camera.h
new file mode 100644
index 000000000..b8a7c75e5
--- /dev/null
+++ b/src/input_common/drivers/camera.h
@@ -0,0 +1,29 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "input_common/input_engine.h"
7
8namespace InputCommon {
9
10/**
11 * A button device factory representing a keyboard. It receives keyboard events and forward them
12 * to all button devices it created.
13 */
14class Camera final : public InputEngine {
15public:
16 explicit Camera(std::string input_engine_);
17
18 void SetCameraData(std::size_t width, std::size_t height, std::vector<u32> data);
19
20 std::size_t getImageWidth() const;
21 std::size_t getImageHeight() const;
22
23 Common::Input::CameraError SetCameraFormat(const PadIdentifier& identifier_,
24 Common::Input::CameraFormat camera_format) override;
25
26 Common::Input::CameraStatus status{};
27};
28
29} // namespace InputCommon
diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp
index 155caae42..f4dd24e7d 100644
--- a/src/input_common/drivers/gc_adapter.cpp
+++ b/src/input_common/drivers/gc_adapter.cpp
@@ -1,6 +1,5 @@
1// Copyright 2014 Dolphin Emulator Project 1// SPDX-FileCopyrightText: 2014 Dolphin Emulator Project
2// Licensed under GPLv2+ 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included.
4 3
5#include <fmt/format.h> 4#include <fmt/format.h>
6#include <libusb.h> 5#include <libusb.h>
@@ -91,7 +90,7 @@ GCAdapter::~GCAdapter() {
91 90
92void GCAdapter::AdapterInputThread(std::stop_token stop_token) { 91void GCAdapter::AdapterInputThread(std::stop_token stop_token) {
93 LOG_DEBUG(Input, "Input thread started"); 92 LOG_DEBUG(Input, "Input thread started");
94 Common::SetCurrentThreadName("yuzu:input:GCAdapter"); 93 Common::SetCurrentThreadName("GCAdapter");
95 s32 payload_size{}; 94 s32 payload_size{};
96 AdapterPayload adapter_payload{}; 95 AdapterPayload adapter_payload{};
97 96
@@ -215,7 +214,7 @@ void GCAdapter::UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_
215} 214}
216 215
217void GCAdapter::AdapterScanThread(std::stop_token stop_token) { 216void GCAdapter::AdapterScanThread(std::stop_token stop_token) {
218 Common::SetCurrentThreadName("yuzu:input:ScanGCAdapter"); 217 Common::SetCurrentThreadName("ScanGCAdapter");
219 usb_adapter_handle = nullptr; 218 usb_adapter_handle = nullptr;
220 pads = {}; 219 pads = {};
221 while (!stop_token.stop_requested() && !Setup()) { 220 while (!stop_token.stop_requested() && !Setup()) {
@@ -524,4 +523,20 @@ Common::Input::ButtonNames GCAdapter::GetUIName(const Common::ParamPackage& para
524 return Common::Input::ButtonNames::Invalid; 523 return Common::Input::ButtonNames::Invalid;
525} 524}
526 525
526bool GCAdapter::IsStickInverted(const Common::ParamPackage& params) {
527 if (!params.Has("port")) {
528 return false;
529 }
530
531 const auto x_axis = static_cast<PadAxes>(params.Get("axis_x", 0));
532 const auto y_axis = static_cast<PadAxes>(params.Get("axis_y", 0));
533 if (x_axis != PadAxes::StickY && x_axis != PadAxes::SubstickY) {
534 return false;
535 }
536 if (y_axis != PadAxes::StickX && y_axis != PadAxes::SubstickX) {
537 return false;
538 }
539 return true;
540}
541
527} // namespace InputCommon 542} // namespace InputCommon
diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h
index 7ce1912a3..8682da847 100644
--- a/src/input_common/drivers/gc_adapter.h
+++ b/src/input_common/drivers/gc_adapter.h
@@ -1,12 +1,10 @@
1// Copyright 2014 Dolphin Emulator Project 1// SPDX-FileCopyrightText: 2014 Dolphin Emulator Project
2// Licensed under GPLv2+ 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included.
4 3
5#pragma once 4#pragma once
6 5
7#include <array> 6#include <array>
8#include <memory> 7#include <memory>
9#include <mutex>
10#include <stop_token> 8#include <stop_token>
11#include <string> 9#include <string>
12#include <thread> 10#include <thread>
@@ -36,6 +34,8 @@ public:
36 AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; 34 AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
37 Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override; 35 Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override;
38 36
37 bool IsStickInverted(const Common::ParamPackage& params) override;
38
39private: 39private:
40 enum class PadButton { 40 enum class PadButton {
41 Undefined = 0x0000, 41 Undefined = 0x0000,
diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp
index 59e3d9cc0..71e612fbf 100644
--- a/src/input_common/drivers/keyboard.cpp
+++ b/src/input_common/drivers/keyboard.cpp
@@ -1,6 +1,5 @@
1// Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included
4 3
5#include "common/param_package.h" 4#include "common/param_package.h"
6#include "common/settings_input.h" 5#include "common/settings_input.h"
diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h
index 3856c882c..62436dba4 100644
--- a/src/input_common/drivers/keyboard.h
+++ b/src/input_common/drivers/keyboard.h
@@ -1,6 +1,5 @@
1// Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included
4 3
5#pragma once 4#pragma once
6 5
diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp
index 3c9a4e747..98c3157a8 100644
--- a/src/input_common/drivers/mouse.cpp
+++ b/src/input_common/drivers/mouse.cpp
@@ -1,6 +1,5 @@
1// Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included
4 3
5#include <stop_token> 4#include <stop_token>
6#include <thread> 5#include <thread>
@@ -38,7 +37,7 @@ Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_))
38} 37}
39 38
40void Mouse::UpdateThread(std::stop_token stop_token) { 39void Mouse::UpdateThread(std::stop_token stop_token) {
41 Common::SetCurrentThreadName("yuzu:input:Mouse"); 40 Common::SetCurrentThreadName("Mouse");
42 constexpr int update_time = 10; 41 constexpr int update_time = 10;
43 while (!stop_token.stop_requested()) { 42 while (!stop_token.stop_requested()) {
44 if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { 43 if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) {
diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h
index c5833b8ed..286ce1cf6 100644
--- a/src/input_common/drivers/mouse.h
+++ b/src/input_common/drivers/mouse.h
@@ -1,6 +1,5 @@
1// Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included
4 3
5#pragma once 4#pragma once
6 5
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 5cf1987ad..b72e4b397 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -1,6 +1,5 @@
1// Copyright 2018 Citra Emulator Project 1// SPDX-FileCopyrightText: 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included.
4 3
5#include "common/logging/log.h" 4#include "common/logging/log.h"
6#include "common/math_util.h" 5#include "common/math_util.h"
@@ -13,11 +12,11 @@
13namespace InputCommon { 12namespace InputCommon {
14 13
15namespace { 14namespace {
16std::string GetGUID(SDL_Joystick* joystick) { 15Common::UUID GetGUID(SDL_Joystick* joystick) {
17 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); 16 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
18 char guid_str[33]; 17 std::array<u8, 16> data{};
19 SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); 18 std::memcpy(data.data(), guid.data, sizeof(data));
20 return guid_str; 19 return Common::UUID{data};
21} 20}
22} // Anonymous namespace 21} // Anonymous namespace
23 22
@@ -31,9 +30,9 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) {
31 30
32class SDLJoystick { 31class SDLJoystick {
33public: 32public:
34 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, 33 SDLJoystick(Common::UUID guid_, int port_, SDL_Joystick* joystick,
35 SDL_GameController* game_controller) 34 SDL_GameController* game_controller)
36 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, 35 : guid{guid_}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
37 sdl_controller{game_controller, &SDL_GameControllerClose} { 36 sdl_controller{game_controller, &SDL_GameControllerClose} {
38 EnableMotion(); 37 EnableMotion();
39 } 38 }
@@ -41,13 +40,13 @@ public:
41 void EnableMotion() { 40 void EnableMotion() {
42 if (sdl_controller) { 41 if (sdl_controller) {
43 SDL_GameController* controller = sdl_controller.get(); 42 SDL_GameController* controller = sdl_controller.get();
44 if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) { 43 has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL);
44 has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO);
45 if (has_accel) {
45 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); 46 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
46 has_accel = true;
47 } 47 }
48 if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) { 48 if (has_gyro) {
49 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); 49 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE);
50 has_gyro = true;
51 } 50 }
52 } 51 }
53 } 52 }
@@ -62,7 +61,7 @@ public:
62 61
63 bool UpdateMotion(SDL_ControllerSensorEvent event) { 62 bool UpdateMotion(SDL_ControllerSensorEvent event) {
64 constexpr float gravity_constant = 9.80665f; 63 constexpr float gravity_constant = 9.80665f;
65 std::lock_guard lock{mutex}; 64 std::scoped_lock lock{mutex};
66 const u64 time_difference = event.timestamp - last_motion_update; 65 const u64 time_difference = event.timestamp - last_motion_update;
67 last_motion_update = event.timestamp; 66 last_motion_update = event.timestamp;
68 switch (event.sensor) { 67 switch (event.sensor) {
@@ -120,7 +119,7 @@ public:
120 */ 119 */
121 const PadIdentifier GetPadIdentifier() const { 120 const PadIdentifier GetPadIdentifier() const {
122 return { 121 return {
123 .guid = Common::UUID{guid}, 122 .guid = guid,
124 .port = static_cast<std::size_t>(port), 123 .port = static_cast<std::size_t>(port),
125 .pad = 0, 124 .pad = 0,
126 }; 125 };
@@ -129,7 +128,7 @@ public:
129 /** 128 /**
130 * The guid of the joystick 129 * The guid of the joystick
131 */ 130 */
132 const std::string& GetGUID() const { 131 const Common::UUID& GetGUID() const {
133 return guid; 132 return guid;
134 } 133 }
135 134
@@ -175,22 +174,23 @@ public:
175 return false; 174 return false;
176 } 175 }
177 176
178 BatteryLevel GetBatteryLevel() { 177 Common::Input::BatteryLevel GetBatteryLevel() {
179 const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get()); 178 const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get());
180 switch (level) { 179 switch (level) {
181 case SDL_JOYSTICK_POWER_EMPTY: 180 case SDL_JOYSTICK_POWER_EMPTY:
182 return BatteryLevel::Empty; 181 return Common::Input::BatteryLevel::Empty;
183 case SDL_JOYSTICK_POWER_LOW: 182 case SDL_JOYSTICK_POWER_LOW:
184 return BatteryLevel::Low; 183 return Common::Input::BatteryLevel::Low;
185 case SDL_JOYSTICK_POWER_MEDIUM: 184 case SDL_JOYSTICK_POWER_MEDIUM:
186 return BatteryLevel::Medium; 185 return Common::Input::BatteryLevel::Medium;
187 case SDL_JOYSTICK_POWER_FULL: 186 case SDL_JOYSTICK_POWER_FULL:
188 case SDL_JOYSTICK_POWER_MAX: 187 case SDL_JOYSTICK_POWER_MAX:
189 return BatteryLevel::Full; 188 return Common::Input::BatteryLevel::Full;
190 case SDL_JOYSTICK_POWER_UNKNOWN:
191 case SDL_JOYSTICK_POWER_WIRED: 189 case SDL_JOYSTICK_POWER_WIRED:
190 return Common::Input::BatteryLevel::Charging;
191 case SDL_JOYSTICK_POWER_UNKNOWN:
192 default: 192 default:
193 return BatteryLevel::Charging; 193 return Common::Input::BatteryLevel::None;
194 } 194 }
195 } 195 }
196 196
@@ -227,7 +227,7 @@ public:
227 } 227 }
228 228
229private: 229private:
230 std::string guid; 230 Common::UUID guid;
231 int port; 231 int port;
232 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; 232 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
233 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; 233 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
@@ -239,8 +239,8 @@ private:
239 BasicMotion motion; 239 BasicMotion motion;
240}; 240};
241 241
242std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) { 242std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const Common::UUID& guid, int port) {
243 std::lock_guard lock{joystick_map_mutex}; 243 std::scoped_lock lock{joystick_map_mutex};
244 const auto it = joystick_map.find(guid); 244 const auto it = joystick_map.find(guid);
245 245
246 if (it != joystick_map.end()) { 246 if (it != joystick_map.end()) {
@@ -258,11 +258,15 @@ std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string&
258 return joystick_map[guid].emplace_back(std::move(joystick)); 258 return joystick_map[guid].emplace_back(std::move(joystick));
259} 259}
260 260
261std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) {
262 return GetSDLJoystickByGUID(Common::UUID{guid}, port);
263}
264
261std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { 265std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
262 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); 266 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
263 const std::string guid = GetGUID(sdl_joystick); 267 const auto guid = GetGUID(sdl_joystick);
264 268
265 std::lock_guard lock{joystick_map_mutex}; 269 std::scoped_lock lock{joystick_map_mutex};
266 const auto map_it = joystick_map.find(guid); 270 const auto map_it = joystick_map.find(guid);
267 271
268 if (map_it == joystick_map.end()) { 272 if (map_it == joystick_map.end()) {
@@ -294,13 +298,14 @@ void SDLDriver::InitJoystick(int joystick_index) {
294 return; 298 return;
295 } 299 }
296 300
297 const std::string guid = GetGUID(sdl_joystick); 301 const auto guid = GetGUID(sdl_joystick);
298 302
299 std::lock_guard lock{joystick_map_mutex}; 303 std::scoped_lock lock{joystick_map_mutex};
300 if (joystick_map.find(guid) == joystick_map.end()) { 304 if (joystick_map.find(guid) == joystick_map.end()) {
301 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); 305 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
302 PreSetController(joystick->GetPadIdentifier()); 306 PreSetController(joystick->GetPadIdentifier());
303 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); 307 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
308 joystick->EnableMotion();
304 joystick_map[guid].emplace_back(std::move(joystick)); 309 joystick_map[guid].emplace_back(std::move(joystick));
305 return; 310 return;
306 } 311 }
@@ -312,6 +317,7 @@ void SDLDriver::InitJoystick(int joystick_index) {
312 317
313 if (joystick_it != joystick_guid_list.end()) { 318 if (joystick_it != joystick_guid_list.end()) {
314 (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller); 319 (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
320 (*joystick_it)->EnableMotion();
315 return; 321 return;
316 } 322 }
317 323
@@ -319,13 +325,14 @@ void SDLDriver::InitJoystick(int joystick_index) {
319 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller); 325 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
320 PreSetController(joystick->GetPadIdentifier()); 326 PreSetController(joystick->GetPadIdentifier());
321 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); 327 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
328 joystick->EnableMotion();
322 joystick_guid_list.emplace_back(std::move(joystick)); 329 joystick_guid_list.emplace_back(std::move(joystick));
323} 330}
324 331
325void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) { 332void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) {
326 const std::string guid = GetGUID(sdl_joystick); 333 const auto guid = GetGUID(sdl_joystick);
327 334
328 std::lock_guard lock{joystick_map_mutex}; 335 std::scoped_lock lock{joystick_map_mutex};
329 // This call to guid is safe since the joystick is guaranteed to be in the map 336 // This call to guid is safe since the joystick is guaranteed to be in the map
330 const auto& joystick_guid_list = joystick_map[guid]; 337 const auto& joystick_guid_list = joystick_map[guid];
331 const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), 338 const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
@@ -351,6 +358,8 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
351 if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { 358 if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
352 const PadIdentifier identifier = joystick->GetPadIdentifier(); 359 const PadIdentifier identifier = joystick->GetPadIdentifier();
353 SetButton(identifier, event.jbutton.button, true); 360 SetButton(identifier, event.jbutton.button, true);
361 // Battery doesn't trigger an event so just update every button press
362 SetBattery(identifier, joystick->GetBatteryLevel());
354 } 363 }
355 break; 364 break;
356 } 365 }
@@ -389,7 +398,7 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
389} 398}
390 399
391void SDLDriver::CloseJoysticks() { 400void SDLDriver::CloseJoysticks() {
392 std::lock_guard lock{joystick_map_mutex}; 401 std::scoped_lock lock{joystick_map_mutex};
393 joystick_map.clear(); 402 joystick_map.clear();
394} 403}
395 404
@@ -427,13 +436,21 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
427 initialized = true; 436 initialized = true;
428 if (start_thread) { 437 if (start_thread) {
429 poll_thread = std::thread([this] { 438 poll_thread = std::thread([this] {
430 Common::SetCurrentThreadName("yuzu:input:SDL"); 439 Common::SetCurrentThreadName("SDL_MainLoop");
431 using namespace std::chrono_literals; 440 using namespace std::chrono_literals;
432 while (initialized) { 441 while (initialized) {
433 SDL_PumpEvents(); 442 SDL_PumpEvents();
434 std::this_thread::sleep_for(1ms); 443 std::this_thread::sleep_for(1ms);
435 } 444 }
436 }); 445 });
446 vibration_thread = std::thread([this] {
447 Common::SetCurrentThreadName("SDL_Vibration");
448 using namespace std::chrono_literals;
449 while (initialized) {
450 SendVibrations();
451 std::this_thread::sleep_for(10ms);
452 }
453 });
437 } 454 }
438 // Because the events for joystick connection happens before we have our event watcher added, we 455 // Because the events for joystick connection happens before we have our event watcher added, we
439 // can just open all the joysticks right here 456 // can just open all the joysticks right here
@@ -449,6 +466,7 @@ SDLDriver::~SDLDriver() {
449 initialized = false; 466 initialized = false;
450 if (start_thread) { 467 if (start_thread) {
451 poll_thread.join(); 468 poll_thread.join();
469 vibration_thread.join();
452 SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); 470 SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
453 } 471 }
454} 472}
@@ -466,7 +484,7 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
466 devices.emplace_back(Common::ParamPackage{ 484 devices.emplace_back(Common::ParamPackage{
467 {"engine", GetEngineName()}, 485 {"engine", GetEngineName()},
468 {"display", std::move(name)}, 486 {"display", std::move(name)},
469 {"guid", joystick->GetGUID()}, 487 {"guid", joystick->GetGUID().RawString()},
470 {"port", std::to_string(joystick->GetPort())}, 488 {"port", std::to_string(joystick->GetPort())},
471 }); 489 });
472 if (joystick->IsJoyconLeft()) { 490 if (joystick->IsJoyconLeft()) {
@@ -489,8 +507,8 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
489 devices.emplace_back(Common::ParamPackage{ 507 devices.emplace_back(Common::ParamPackage{
490 {"engine", GetEngineName()}, 508 {"engine", GetEngineName()},
491 {"display", std::move(name)}, 509 {"display", std::move(name)},
492 {"guid", joystick->GetGUID()}, 510 {"guid", joystick->GetGUID().RawString()},
493 {"guid2", joystick2->GetGUID()}, 511 {"guid2", joystick2->GetGUID().RawString()},
494 {"port", std::to_string(joystick->GetPort())}, 512 {"port", std::to_string(joystick->GetPort())},
495 }); 513 });
496 } 514 }
@@ -528,57 +546,75 @@ Common::Input::VibrationError SDLDriver::SetRumble(
528 .type = Common::Input::VibrationAmplificationType::Exponential, 546 .type = Common::Input::VibrationAmplificationType::Exponential,
529 }; 547 };
530 548
531 if (!joystick->RumblePlay(new_vibration)) { 549 if (vibration.type == Common::Input::VibrationAmplificationType::Test) {
532 return Common::Input::VibrationError::Unknown; 550 if (!joystick->RumblePlay(new_vibration)) {
551 return Common::Input::VibrationError::Unknown;
552 }
553 return Common::Input::VibrationError::None;
533 } 554 }
534 555
556 vibration_queue.Push(VibrationRequest{
557 .identifier = identifier,
558 .vibration = new_vibration,
559 });
560
535 return Common::Input::VibrationError::None; 561 return Common::Input::VibrationError::None;
536} 562}
537 563
538Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, 564void SDLDriver::SendVibrations() {
565 while (!vibration_queue.Empty()) {
566 VibrationRequest request;
567 vibration_queue.Pop(request);
568 const auto joystick = GetSDLJoystickByGUID(request.identifier.guid.RawString(),
569 static_cast<int>(request.identifier.port));
570 joystick->RumblePlay(request.vibration);
571 }
572}
573
574Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, const Common::UUID& guid,
539 s32 axis, float value) const { 575 s32 axis, float value) const {
540 Common::ParamPackage params{}; 576 Common::ParamPackage params{};
541 params.Set("engine", GetEngineName()); 577 params.Set("engine", GetEngineName());
542 params.Set("port", port); 578 params.Set("port", port);
543 params.Set("guid", std::move(guid)); 579 params.Set("guid", guid.RawString());
544 params.Set("axis", axis); 580 params.Set("axis", axis);
545 params.Set("threshold", "0.5"); 581 params.Set("threshold", "0.5");
546 params.Set("invert", value < 0 ? "-" : "+"); 582 params.Set("invert", value < 0 ? "-" : "+");
547 return params; 583 return params;
548} 584}
549 585
550Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, std::string guid, 586Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, const Common::UUID& guid,
551 s32 button) const { 587 s32 button) const {
552 Common::ParamPackage params{}; 588 Common::ParamPackage params{};
553 params.Set("engine", GetEngineName()); 589 params.Set("engine", GetEngineName());
554 params.Set("port", port); 590 params.Set("port", port);
555 params.Set("guid", std::move(guid)); 591 params.Set("guid", guid.RawString());
556 params.Set("button", button); 592 params.Set("button", button);
557 return params; 593 return params;
558} 594}
559 595
560Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, std::string guid, s32 hat, 596Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, const Common::UUID& guid,
561 u8 value) const { 597 s32 hat, u8 value) const {
562 Common::ParamPackage params{}; 598 Common::ParamPackage params{};
563 params.Set("engine", GetEngineName()); 599 params.Set("engine", GetEngineName());
564 params.Set("port", port); 600 params.Set("port", port);
565 params.Set("guid", std::move(guid)); 601 params.Set("guid", guid.RawString());
566 params.Set("hat", hat); 602 params.Set("hat", hat);
567 params.Set("direction", GetHatButtonName(value)); 603 params.Set("direction", GetHatButtonName(value));
568 return params; 604 return params;
569} 605}
570 606
571Common::ParamPackage SDLDriver::BuildMotionParam(int port, std::string guid) const { 607Common::ParamPackage SDLDriver::BuildMotionParam(int port, const Common::UUID& guid) const {
572 Common::ParamPackage params{}; 608 Common::ParamPackage params{};
573 params.Set("engine", GetEngineName()); 609 params.Set("engine", GetEngineName());
574 params.Set("motion", 0); 610 params.Set("motion", 0);
575 params.Set("port", port); 611 params.Set("port", port);
576 params.Set("guid", std::move(guid)); 612 params.Set("guid", guid.RawString());
577 return params; 613 return params;
578} 614}
579 615
580Common::ParamPackage SDLDriver::BuildParamPackageForBinding( 616Common::ParamPackage SDLDriver::BuildParamPackageForBinding(
581 int port, const std::string& guid, const SDL_GameControllerButtonBind& binding) const { 617 int port, const Common::UUID& guid, const SDL_GameControllerButtonBind& binding) const {
582 switch (binding.bindType) { 618 switch (binding.bindType) {
583 case SDL_CONTROLLER_BINDTYPE_NONE: 619 case SDL_CONTROLLER_BINDTYPE_NONE:
584 break; 620 break;
@@ -931,4 +967,37 @@ u8 SDLDriver::GetHatButtonId(const std::string& direction_name) const {
931 return direction; 967 return direction;
932} 968}
933 969
970bool SDLDriver::IsStickInverted(const Common::ParamPackage& params) {
971 if (!params.Has("guid") || !params.Has("port")) {
972 return false;
973 }
974 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
975 if (joystick == nullptr) {
976 return false;
977 }
978 auto* controller = joystick->GetSDLGameController();
979 if (controller == nullptr) {
980 return false;
981 }
982
983 const auto& axis_x = params.Get("axis_x", 0);
984 const auto& axis_y = params.Get("axis_y", 0);
985 const auto& binding_left_x =
986 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
987 const auto& binding_right_x =
988 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
989 const auto& binding_left_y =
990 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
991 const auto& binding_right_y =
992 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
993
994 if (axis_x != binding_left_y.value.axis && axis_x != binding_right_y.value.axis) {
995 return false;
996 }
997 if (axis_y != binding_left_x.value.axis && axis_y != binding_right_x.value.axis) {
998 return false;
999 }
1000 return true;
1001}
1002
934} // namespace InputCommon 1003} // namespace InputCommon
diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h
index 4cde3606f..fc3a44572 100644
--- a/src/input_common/drivers/sdl_driver.h
+++ b/src/input_common/drivers/sdl_driver.h
@@ -1,6 +1,5 @@
1// Copyright 2018 Citra Emulator Project 1// SPDX-FileCopyrightText: 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included.
4 3
5#pragma once 4#pragma once
6 5
@@ -12,6 +11,7 @@
12#include <SDL.h> 11#include <SDL.h>
13 12
14#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/threadsafe_queue.h"
15#include "input_common/input_engine.h" 15#include "input_common/input_engine.h"
16 16
17union SDL_Event; 17union SDL_Event;
@@ -46,6 +46,7 @@ public:
46 * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so 46 * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so
47 * tie it to a SDLJoystick with the same guid and that port 47 * tie it to a SDLJoystick with the same guid and that port
48 */ 48 */
49 std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const Common::UUID& guid, int port);
49 std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port); 50 std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port);
50 51
51 std::vector<Common::ParamPackage> GetInputDevices() const override; 52 std::vector<Common::ParamPackage> GetInputDevices() const override;
@@ -58,28 +59,38 @@ public:
58 std::string GetHatButtonName(u8 direction_value) const override; 59 std::string GetHatButtonName(u8 direction_value) const override;
59 u8 GetHatButtonId(const std::string& direction_name) const override; 60 u8 GetHatButtonId(const std::string& direction_name) const override;
60 61
62 bool IsStickInverted(const Common::ParamPackage& params) override;
63
61 Common::Input::VibrationError SetRumble( 64 Common::Input::VibrationError SetRumble(
62 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; 65 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
63 66
64private: 67private:
68 struct VibrationRequest {
69 PadIdentifier identifier;
70 Common::Input::VibrationStatus vibration;
71 };
72
65 void InitJoystick(int joystick_index); 73 void InitJoystick(int joystick_index);
66 void CloseJoystick(SDL_Joystick* sdl_joystick); 74 void CloseJoystick(SDL_Joystick* sdl_joystick);
67 75
68 /// Needs to be called before SDL_QuitSubSystem. 76 /// Needs to be called before SDL_QuitSubSystem.
69 void CloseJoysticks(); 77 void CloseJoysticks();
70 78
71 Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, 79 /// Takes all vibrations from the queue and sends the command to the controller
72 float value = 0.1f) const; 80 void SendVibrations();
73 Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, 81
82 Common::ParamPackage BuildAnalogParamPackageForButton(int port, const Common::UUID& guid,
83 s32 axis, float value = 0.1f) const;
84 Common::ParamPackage BuildButtonParamPackageForButton(int port, const Common::UUID& guid,
74 s32 button) const; 85 s32 button) const;
75 86
76 Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat, 87 Common::ParamPackage BuildHatParamPackageForButton(int port, const Common::UUID& guid, s32 hat,
77 u8 value) const; 88 u8 value) const;
78 89
79 Common::ParamPackage BuildMotionParam(int port, std::string guid) const; 90 Common::ParamPackage BuildMotionParam(int port, const Common::UUID& guid) const;
80 91
81 Common::ParamPackage BuildParamPackageForBinding( 92 Common::ParamPackage BuildParamPackageForBinding(
82 int port, const std::string& guid, const SDL_GameControllerButtonBind& binding) const; 93 int port, const Common::UUID& guid, const SDL_GameControllerButtonBind& binding) const;
83 94
84 Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x, 95 Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x,
85 int axis_y, float offset_x, 96 int axis_y, float offset_x,
@@ -105,13 +116,17 @@ private:
105 /// Returns true if the button is on the left joycon 116 /// Returns true if the button is on the left joycon
106 bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const; 117 bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const;
107 118
119 /// Queue of vibration request to controllers
120 Common::SPSCQueue<VibrationRequest> vibration_queue;
121
108 /// Map of GUID of a list of corresponding virtual Joysticks 122 /// Map of GUID of a list of corresponding virtual Joysticks
109 std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map; 123 std::unordered_map<Common::UUID, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
110 std::mutex joystick_map_mutex; 124 std::mutex joystick_map_mutex;
111 125
112 bool start_thread = false; 126 bool start_thread = false;
113 std::atomic<bool> initialized = false; 127 std::atomic<bool> initialized = false;
114 128
115 std::thread poll_thread; 129 std::thread poll_thread;
130 std::thread vibration_thread;
116}; 131};
117} // namespace InputCommon 132} // namespace InputCommon
diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp
index 944e141bf..21c6ed405 100644
--- a/src/input_common/drivers/tas_input.cpp
+++ b/src/input_common/drivers/tas_input.cpp
@@ -1,6 +1,5 @@
1// Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2+ 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included.
4 3
5#include <cstring> 4#include <cstring>
6#include <fmt/format.h> 5#include <fmt/format.h>
diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h
index 4b4e6c417..38a27a230 100644
--- a/src/input_common/drivers/tas_input.h
+++ b/src/input_common/drivers/tas_input.h
@@ -1,6 +1,5 @@
1// Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included.
4 3
5#pragma once 4#pragma once
6 5
diff --git a/src/input_common/drivers/touch_screen.cpp b/src/input_common/drivers/touch_screen.cpp
index 30c727df4..1753e0893 100644
--- a/src/input_common/drivers/touch_screen.cpp
+++ b/src/input_common/drivers/touch_screen.cpp
@@ -1,6 +1,5 @@
1// Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included
4 3
5#include "common/param_package.h" 4#include "common/param_package.h"
6#include "input_common/drivers/touch_screen.h" 5#include "input_common/drivers/touch_screen.h"
@@ -15,38 +14,93 @@ constexpr PadIdentifier identifier = {
15 14
16TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) { 15TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
17 PreSetController(identifier); 16 PreSetController(identifier);
17 ReleaseAllTouch();
18} 18}
19 19
20void TouchScreen::TouchMoved(float x, float y, std::size_t finger) { 20void TouchScreen::TouchMoved(float x, float y, std::size_t finger_id) {
21 if (finger >= 16) { 21 const auto index = GetIndexFromFingerId(finger_id);
22 if (!index) {
23 // Touch doesn't exist handle it as a new one
24 TouchPressed(x, y, finger_id);
22 return; 25 return;
23 } 26 }
24 TouchPressed(x, y, finger); 27 const auto i = index.value();
28 fingers[i].is_active = true;
29 SetButton(identifier, static_cast<int>(i), true);
30 SetAxis(identifier, static_cast<int>(i * 2), x);
31 SetAxis(identifier, static_cast<int>(i * 2 + 1), y);
25} 32}
26 33
27void TouchScreen::TouchPressed(float x, float y, std::size_t finger) { 34void TouchScreen::TouchPressed(float x, float y, std::size_t finger_id) {
28 if (finger >= 16) { 35 if (GetIndexFromFingerId(finger_id)) {
36 // Touch already exist. Just update the data
37 TouchMoved(x, y, finger_id);
29 return; 38 return;
30 } 39 }
31 SetButton(identifier, static_cast<int>(finger), true); 40 const auto index = GetNextFreeIndex();
32 SetAxis(identifier, static_cast<int>(finger * 2), x); 41 if (!index) {
33 SetAxis(identifier, static_cast<int>(finger * 2 + 1), y); 42 // No free entries. Ignore input
43 return;
44 }
45 const auto i = index.value();
46 fingers[i].is_enabled = true;
47 fingers[i].finger_id = finger_id;
48 TouchMoved(x, y, finger_id);
34} 49}
35 50
36void TouchScreen::TouchReleased(std::size_t finger) { 51void TouchScreen::TouchReleased(std::size_t finger_id) {
37 if (finger >= 16) { 52 const auto index = GetIndexFromFingerId(finger_id);
53 if (!index) {
38 return; 54 return;
39 } 55 }
40 SetButton(identifier, static_cast<int>(finger), false); 56 const auto i = index.value();
41 SetAxis(identifier, static_cast<int>(finger * 2), 0.0f); 57 fingers[i].is_enabled = false;
42 SetAxis(identifier, static_cast<int>(finger * 2 + 1), 0.0f); 58 SetButton(identifier, static_cast<int>(i), false);
59 SetAxis(identifier, static_cast<int>(i * 2), 0.0f);
60 SetAxis(identifier, static_cast<int>(i * 2 + 1), 0.0f);
61}
62
63std::optional<std::size_t> TouchScreen::GetIndexFromFingerId(std::size_t finger_id) const {
64 for (std::size_t index = 0; index < MAX_FINGER_COUNT; ++index) {
65 const auto& finger = fingers[index];
66 if (!finger.is_enabled) {
67 continue;
68 }
69 if (finger.finger_id == finger_id) {
70 return index;
71 }
72 }
73 return std::nullopt;
74}
75
76std::optional<std::size_t> TouchScreen::GetNextFreeIndex() const {
77 for (std::size_t index = 0; index < MAX_FINGER_COUNT; ++index) {
78 if (!fingers[index].is_enabled) {
79 return index;
80 }
81 }
82 return std::nullopt;
83}
84
85void TouchScreen::ClearActiveFlag() {
86 for (auto& finger : fingers) {
87 finger.is_active = false;
88 }
89}
90
91void TouchScreen::ReleaseInactiveTouch() {
92 for (const auto& finger : fingers) {
93 if (!finger.is_active) {
94 TouchReleased(finger.finger_id);
95 }
96 }
43} 97}
44 98
45void TouchScreen::ReleaseAllTouch() { 99void TouchScreen::ReleaseAllTouch() {
46 for (int index = 0; index < 16; ++index) { 100 for (const auto& finger : fingers) {
47 SetButton(identifier, index, false); 101 if (finger.is_enabled) {
48 SetAxis(identifier, index * 2, 0.0f); 102 TouchReleased(finger.finger_id);
49 SetAxis(identifier, index * 2 + 1, 0.0f); 103 }
50 } 104 }
51} 105}
52 106
diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h
index bf395c40b..f46036ffd 100644
--- a/src/input_common/drivers/touch_screen.h
+++ b/src/input_common/drivers/touch_screen.h
@@ -1,44 +1,67 @@
1// Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included
4 3
5#pragma once 4#pragma once
6 5
6#include <optional>
7
7#include "input_common/input_engine.h" 8#include "input_common/input_engine.h"
8 9
9namespace InputCommon { 10namespace InputCommon {
10 11
11/** 12/**
12 * A button device factory representing a keyboard. It receives keyboard events and forward them 13 * A touch device factory representing a touch screen. It receives touch events and forward them
13 * to all button devices it created. 14 * to all touch devices it created.
14 */ 15 */
15class TouchScreen final : public InputEngine { 16class TouchScreen final : public InputEngine {
16public: 17public:
17 explicit TouchScreen(std::string input_engine_); 18 explicit TouchScreen(std::string input_engine_);
18 19
19 /** 20 /**
20 * Signals that mouse has moved. 21 * Signals that touch has moved and marks this touch point as active
21 * @param x the x-coordinate of the cursor 22 * @param x new horizontal position
22 * @param y the y-coordinate of the cursor 23 * @param y new vertical position
23 * @param center_x the x-coordinate of the middle of the screen 24 * @param finger_id of the touch point to be updated
24 * @param center_y the y-coordinate of the middle of the screen
25 */ 25 */
26 void TouchMoved(float x, float y, std::size_t finger); 26 void TouchMoved(float x, float y, std::size_t finger_id);
27 27
28 /** 28 /**
29 * Sets the status of all buttons bound with the key to pressed 29 * Signals and creates a new touch point with this finger id
30 * @param key_code the code of the key to press 30 * @param x starting horizontal position
31 * @param y starting vertical position
32 * @param finger_id to be assigned to the new touch point
31 */ 33 */
32 void TouchPressed(float x, float y, std::size_t finger); 34 void TouchPressed(float x, float y, std::size_t finger_id);
33 35
34 /** 36 /**
35 * Sets the status of all buttons bound with the key to released 37 * Signals and resets the touch point related to the this finger id
36 * @param key_code the code of the key to release 38 * @param finger_id to be released
37 */ 39 */
38 void TouchReleased(std::size_t finger); 40 void TouchReleased(std::size_t finger_id);
41
42 /// Resets the active flag for each touch point
43 void ClearActiveFlag();
44
45 /// Releases all touch that haven't been marked as active
46 void ReleaseInactiveTouch();
39 47
40 /// Resets all inputs to their initial value 48 /// Resets all inputs to their initial value
41 void ReleaseAllTouch(); 49 void ReleaseAllTouch();
50
51private:
52 static constexpr std::size_t MAX_FINGER_COUNT = 16;
53
54 struct TouchStatus {
55 std::size_t finger_id{};
56 bool is_enabled{};
57 bool is_active{};
58 };
59
60 std::optional<std::size_t> GetIndexFromFingerId(std::size_t finger_id) const;
61
62 std::optional<std::size_t> GetNextFreeIndex() const;
63
64 std::array<TouchStatus, MAX_FINGER_COUNT> fingers{};
42}; 65};
43 66
44} // namespace InputCommon 67} // namespace InputCommon
diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp
index 64162f431..808b21069 100644
--- a/src/input_common/drivers/udp_client.cpp
+++ b/src/input_common/drivers/udp_client.cpp
@@ -1,6 +1,5 @@
1// Copyright 2018 Citra Emulator Project 1// SPDX-FileCopyrightText: 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included.
4 3
5#include <random> 4#include <random>
6#include <boost/asio.hpp> 5#include <boost/asio.hpp>
@@ -192,22 +191,22 @@ std::size_t UDPClient::GetClientNumber(std::string_view host, u16 port) const {
192 return MAX_UDP_CLIENTS; 191 return MAX_UDP_CLIENTS;
193} 192}
194 193
195BatteryLevel UDPClient::GetBatteryLevel(Response::Battery battery) const { 194Common::Input::BatteryLevel UDPClient::GetBatteryLevel(Response::Battery battery) const {
196 switch (battery) { 195 switch (battery) {
197 case Response::Battery::Dying: 196 case Response::Battery::Dying:
198 return BatteryLevel::Empty; 197 return Common::Input::BatteryLevel::Empty;
199 case Response::Battery::Low: 198 case Response::Battery::Low:
200 return BatteryLevel::Critical; 199 return Common::Input::BatteryLevel::Critical;
201 case Response::Battery::Medium: 200 case Response::Battery::Medium:
202 return BatteryLevel::Low; 201 return Common::Input::BatteryLevel::Low;
203 case Response::Battery::High: 202 case Response::Battery::High:
204 return BatteryLevel::Medium; 203 return Common::Input::BatteryLevel::Medium;
205 case Response::Battery::Full: 204 case Response::Battery::Full:
206 case Response::Battery::Charged: 205 case Response::Battery::Charged:
207 return BatteryLevel::Full; 206 return Common::Input::BatteryLevel::Full;
208 case Response::Battery::Charging: 207 case Response::Battery::Charging:
209 default: 208 default:
210 return BatteryLevel::Charging; 209 return Common::Input::BatteryLevel::Charging;
211 } 210 }
212} 211}
213 212
@@ -547,6 +546,22 @@ Common::Input::ButtonNames UDPClient::GetUIName(const Common::ParamPackage& para
547 return Common::Input::ButtonNames::Invalid; 546 return Common::Input::ButtonNames::Invalid;
548} 547}
549 548
549bool UDPClient::IsStickInverted(const Common::ParamPackage& params) {
550 if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) {
551 return false;
552 }
553
554 const auto x_axis = static_cast<PadAxes>(params.Get("axis_x", 0));
555 const auto y_axis = static_cast<PadAxes>(params.Get("axis_y", 0));
556 if (x_axis != PadAxes::LeftStickY && x_axis != PadAxes::RightStickY) {
557 return false;
558 }
559 if (y_axis != PadAxes::LeftStickX && y_axis != PadAxes::RightStickX) {
560 return false;
561 }
562 return true;
563}
564
550void TestCommunication(const std::string& host, u16 port, 565void TestCommunication(const std::string& host, u16 port,
551 const std::function<void()>& success_callback, 566 const std::function<void()>& success_callback,
552 const std::function<void()>& failure_callback) { 567 const std::function<void()>& failure_callback) {
diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h
index 76e32bd04..cea9f579a 100644
--- a/src/input_common/drivers/udp_client.h
+++ b/src/input_common/drivers/udp_client.h
@@ -1,6 +1,5 @@
1// Copyright 2018 Citra Emulator Project 1// SPDX-FileCopyrightText: 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version 2// SPDX-License-Identifier: GPL-2.0-or-later
3// Refer to the license.txt file included.
4 3
5#pragma once 4#pragma once
6 5
@@ -64,6 +63,8 @@ public:
64 MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override; 63 MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override;
65 Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override; 64 Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override;
66 65
66 bool IsStickInverted(const Common::ParamPackage& params) override;
67
67private: 68private:
68 enum class PadButton { 69 enum class PadButton {
69 Undefined = 0x0000, 70 Undefined = 0x0000,
@@ -141,7 +142,7 @@ private:
141 std::size_t GetClientNumber(std::string_view host, u16 port) const; 142 std::size_t GetClientNumber(std::string_view host, u16 port) const;
142 143
143 // Translates UDP battery level to input engine battery level 144 // Translates UDP battery level to input engine battery level
144 BatteryLevel GetBatteryLevel(Response::Battery battery) const; 145 Common::Input::BatteryLevel GetBatteryLevel(Response::Battery battery) const;
145 146
146 void OnVersion(Response::Version); 147 void OnVersion(Response::Version);
147 void OnPortInfo(Response::PortInfo); 148 void OnPortInfo(Response::PortInfo);
diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp
new file mode 100644
index 000000000..0cd5129da
--- /dev/null
+++ b/src/input_common/drivers/virtual_amiibo.cpp
@@ -0,0 +1,101 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <cstring>
5#include <fmt/format.h>
6
7#include "common/fs/file.h"
8#include "common/fs/fs.h"
9#include "common/fs/path_util.h"
10#include "common/logging/log.h"
11#include "common/settings.h"
12#include "input_common/drivers/virtual_amiibo.h"
13
14namespace InputCommon {
15constexpr PadIdentifier identifier = {
16 .guid = Common::UUID{},
17 .port = 0,
18 .pad = 0,
19};
20
21VirtualAmiibo::VirtualAmiibo(std::string input_engine_) : InputEngine(std::move(input_engine_)) {}
22
23VirtualAmiibo::~VirtualAmiibo() = default;
24
25Common::Input::PollingError VirtualAmiibo::SetPollingMode(
26 [[maybe_unused]] const PadIdentifier& identifier_,
27 const Common::Input::PollingMode polling_mode_) {
28 polling_mode = polling_mode_;
29
30 if (polling_mode == Common::Input::PollingMode::NFC) {
31 if (state == State::Initialized) {
32 state = State::WaitingForAmiibo;
33 }
34 } else {
35 if (state == State::AmiiboIsOpen) {
36 CloseAmiibo();
37 }
38 }
39
40 return Common::Input::PollingError::None;
41}
42
43Common::Input::NfcState VirtualAmiibo::SupportsNfc(
44 [[maybe_unused]] const PadIdentifier& identifier_) const {
45 return Common::Input::NfcState::Success;
46}
47
48Common::Input::NfcState VirtualAmiibo::WriteNfcData(
49 [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) {
50 const Common::FS::IOFile amiibo_file{file_path, Common::FS::FileAccessMode::ReadWrite,
51 Common::FS::FileType::BinaryFile};
52
53 if (!amiibo_file.IsOpen()) {
54 LOG_ERROR(Core, "Amiibo is already on use");
55 return Common::Input::NfcState::WriteFailed;
56 }
57
58 if (!amiibo_file.Write(data)) {
59 LOG_ERROR(Service_NFP, "Error writting to file");
60 return Common::Input::NfcState::WriteFailed;
61 }
62
63 return Common::Input::NfcState::Success;
64}
65
66VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const {
67 return state;
68}
69
70VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) {
71 const Common::FS::IOFile amiibo_file{filename, Common::FS::FileAccessMode::Read,
72 Common::FS::FileType::BinaryFile};
73
74 if (state != State::WaitingForAmiibo) {
75 return Info::WrongDeviceState;
76 }
77
78 if (!amiibo_file.IsOpen()) {
79 return Info::UnableToLoad;
80 }
81
82 amiibo_data.resize(amiibo_size);
83
84 if (amiibo_file.Read(amiibo_data) < amiibo_size_without_password) {
85 return Info::NotAnAmiibo;
86 }
87
88 file_path = filename;
89 state = State::AmiiboIsOpen;
90 SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data});
91 return Info::Success;
92}
93
94VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() {
95 state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo
96 : State::Initialized;
97 SetNfc(identifier, {Common::Input::NfcState::AmiiboRemoved, {}});
98 return Info::Success;
99}
100
101} // namespace InputCommon
diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h
new file mode 100644
index 000000000..9eac07544
--- /dev/null
+++ b/src/input_common/drivers/virtual_amiibo.h
@@ -0,0 +1,61 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include <string>
8#include <vector>
9
10#include "common/common_types.h"
11#include "input_common/input_engine.h"
12
13namespace Common::FS {
14class IOFile;
15}
16
17namespace InputCommon {
18
19class VirtualAmiibo final : public InputEngine {
20public:
21 enum class State {
22 Initialized,
23 WaitingForAmiibo,
24 AmiiboIsOpen,
25 };
26
27 enum class Info {
28 Success,
29 UnableToLoad,
30 NotAnAmiibo,
31 WrongDeviceState,
32 Unknown,
33 };
34
35 explicit VirtualAmiibo(std::string input_engine_);
36 ~VirtualAmiibo() override;
37
38 // Sets polling mode to a controller
39 Common::Input::PollingError SetPollingMode(
40 const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override;
41
42 Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override;
43
44 Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_,
45 const std::vector<u8>& data) override;
46
47 State GetCurrentState() const;
48
49 Info LoadAmiibo(const std::string& amiibo_file);
50 Info CloseAmiibo();
51
52private:
53 static constexpr std::size_t amiibo_size = 0x21C;
54 static constexpr std::size_t amiibo_size_without_password = amiibo_size - 0x8;
55
56 std::string file_path{};
57 State state{State::Initialized};
58 std::vector<u8> amiibo_data;
59 Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Pasive};
60};
61} // namespace InputCommon