summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hid/emulated_controller.cpp82
-rw-r--r--src/core/hid/emulated_controller.h9
-rw-r--r--src/input_common/CMakeLists.txt2
-rw-r--r--src/input_common/drivers/virtual_gamepad.cpp78
-rw-r--r--src/input_common/drivers/virtual_gamepad.h73
-rw-r--r--src/input_common/main.cpp23
-rw-r--r--src/input_common/main.h7
7 files changed, 274 insertions, 0 deletions
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 67969e938..f238d6ccd 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -145,6 +145,7 @@ void EmulatedController::LoadDevices() {
145 output_params[3].Set("output", true); 145 output_params[3].Set("output", true);
146 146
147 LoadTASParams(); 147 LoadTASParams();
148 LoadVirtualGamepadParams();
148 149
149 std::ranges::transform(button_params, button_devices.begin(), Common::Input::CreateInputDevice); 150 std::ranges::transform(button_params, button_devices.begin(), Common::Input::CreateInputDevice);
150 std::ranges::transform(stick_params, stick_devices.begin(), Common::Input::CreateInputDevice); 151 std::ranges::transform(stick_params, stick_devices.begin(), Common::Input::CreateInputDevice);
@@ -163,6 +164,12 @@ void EmulatedController::LoadDevices() {
163 Common::Input::CreateInputDevice); 164 Common::Input::CreateInputDevice);
164 std::ranges::transform(tas_stick_params, tas_stick_devices.begin(), 165 std::ranges::transform(tas_stick_params, tas_stick_devices.begin(),
165 Common::Input::CreateInputDevice); 166 Common::Input::CreateInputDevice);
167
168 // Initialize virtual gamepad devices
169 std::ranges::transform(virtual_button_params, virtual_button_devices.begin(),
170 Common::Input::CreateInputDevice);
171 std::ranges::transform(virtual_stick_params, virtual_stick_devices.begin(),
172 Common::Input::CreateInputDevice);
166} 173}
167 174
168void EmulatedController::LoadTASParams() { 175void EmulatedController::LoadTASParams() {
@@ -205,6 +212,46 @@ void EmulatedController::LoadTASParams() {
205 tas_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3); 212 tas_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3);
206} 213}
207 214
215void EmulatedController::LoadVirtualGamepadParams() {
216 const auto player_index = NpadIdTypeToIndex(npad_id_type);
217 Common::ParamPackage common_params{};
218 common_params.Set("engine", "virtual_gamepad");
219 common_params.Set("port", static_cast<int>(player_index));
220 for (auto& param : virtual_button_params) {
221 param = common_params;
222 }
223 for (auto& param : virtual_stick_params) {
224 param = common_params;
225 }
226
227 // TODO(german77): Replace this with an input profile or something better
228 virtual_button_params[Settings::NativeButton::A].Set("button", 0);
229 virtual_button_params[Settings::NativeButton::B].Set("button", 1);
230 virtual_button_params[Settings::NativeButton::X].Set("button", 2);
231 virtual_button_params[Settings::NativeButton::Y].Set("button", 3);
232 virtual_button_params[Settings::NativeButton::LStick].Set("button", 4);
233 virtual_button_params[Settings::NativeButton::RStick].Set("button", 5);
234 virtual_button_params[Settings::NativeButton::L].Set("button", 6);
235 virtual_button_params[Settings::NativeButton::R].Set("button", 7);
236 virtual_button_params[Settings::NativeButton::ZL].Set("button", 8);
237 virtual_button_params[Settings::NativeButton::ZR].Set("button", 9);
238 virtual_button_params[Settings::NativeButton::Plus].Set("button", 10);
239 virtual_button_params[Settings::NativeButton::Minus].Set("button", 11);
240 virtual_button_params[Settings::NativeButton::DLeft].Set("button", 12);
241 virtual_button_params[Settings::NativeButton::DUp].Set("button", 13);
242 virtual_button_params[Settings::NativeButton::DRight].Set("button", 14);
243 virtual_button_params[Settings::NativeButton::DDown].Set("button", 15);
244 virtual_button_params[Settings::NativeButton::SL].Set("button", 16);
245 virtual_button_params[Settings::NativeButton::SR].Set("button", 17);
246 virtual_button_params[Settings::NativeButton::Home].Set("button", 18);
247 virtual_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
248
249 virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
250 virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
251 virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2);
252 virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3);
253}
254
208void EmulatedController::ReloadInput() { 255void EmulatedController::ReloadInput() {
209 // If you load any device here add the equivalent to the UnloadInput() function 256 // If you load any device here add the equivalent to the UnloadInput() function
210 LoadDevices(); 257 LoadDevices();
@@ -322,6 +369,35 @@ void EmulatedController::ReloadInput() {
322 }, 369 },
323 }); 370 });
324 } 371 }
372
373 // Use a common UUID for Virtual Gamepad
374 static constexpr Common::UUID VIRTUAL_UUID = Common::UUID{
375 {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
376
377 // Register virtual devices. No need to force update
378 for (std::size_t index = 0; index < virtual_button_devices.size(); ++index) {
379 if (!virtual_button_devices[index]) {
380 continue;
381 }
382 virtual_button_devices[index]->SetCallback({
383 .on_change =
384 [this, index](const Common::Input::CallbackStatus& callback) {
385 SetButton(callback, index, VIRTUAL_UUID);
386 },
387 });
388 }
389
390 for (std::size_t index = 0; index < virtual_stick_devices.size(); ++index) {
391 if (!virtual_stick_devices[index]) {
392 continue;
393 }
394 virtual_stick_devices[index]->SetCallback({
395 .on_change =
396 [this, index](const Common::Input::CallbackStatus& callback) {
397 SetStick(callback, index, VIRTUAL_UUID);
398 },
399 });
400 }
325} 401}
326 402
327void EmulatedController::UnloadInput() { 403void EmulatedController::UnloadInput() {
@@ -349,6 +425,12 @@ void EmulatedController::UnloadInput() {
349 for (auto& stick : tas_stick_devices) { 425 for (auto& stick : tas_stick_devices) {
350 stick.reset(); 426 stick.reset();
351 } 427 }
428 for (auto& button : virtual_button_devices) {
429 button.reset();
430 }
431 for (auto& stick : virtual_stick_devices) {
432 stick.reset();
433 }
352 camera_devices.reset(); 434 camera_devices.reset();
353 nfc_devices.reset(); 435 nfc_devices.reset();
354} 436}
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index fa7a34278..a398543a6 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -385,6 +385,9 @@ private:
385 /// Set the params for TAS devices 385 /// Set the params for TAS devices
386 void LoadTASParams(); 386 void LoadTASParams();
387 387
388 /// Set the params for virtual pad devices
389 void LoadVirtualGamepadParams();
390
388 /** 391 /**
389 * @param use_temporary_value If true tmp_npad_type will be used 392 * @param use_temporary_value If true tmp_npad_type will be used
390 * @return true if the controller style is fullkey 393 * @return true if the controller style is fullkey
@@ -500,6 +503,12 @@ private:
500 ButtonDevices tas_button_devices; 503 ButtonDevices tas_button_devices;
501 StickDevices tas_stick_devices; 504 StickDevices tas_stick_devices;
502 505
506 // Virtual gamepad related variables
507 ButtonParams virtual_button_params;
508 StickParams virtual_stick_params;
509 ButtonDevices virtual_button_devices;
510 StickDevices virtual_stick_devices;
511
503 mutable std::mutex mutex; 512 mutable std::mutex mutex;
504 mutable std::mutex callback_mutex; 513 mutable std::mutex callback_mutex;
505 std::unordered_map<int, ControllerUpdateCallback> callback_list; 514 std::unordered_map<int, ControllerUpdateCallback> callback_list;
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 7932aaab0..f24c89b04 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -20,6 +20,8 @@ add_library(input_common STATIC
20 drivers/udp_client.h 20 drivers/udp_client.h
21 drivers/virtual_amiibo.cpp 21 drivers/virtual_amiibo.cpp
22 drivers/virtual_amiibo.h 22 drivers/virtual_amiibo.h
23 drivers/virtual_gamepad.cpp
24 drivers/virtual_gamepad.h
23 helpers/stick_from_buttons.cpp 25 helpers/stick_from_buttons.cpp
24 helpers/stick_from_buttons.h 26 helpers/stick_from_buttons.h
25 helpers/touch_from_buttons.cpp 27 helpers/touch_from_buttons.cpp
diff --git a/src/input_common/drivers/virtual_gamepad.cpp b/src/input_common/drivers/virtual_gamepad.cpp
new file mode 100644
index 000000000..7db945aa6
--- /dev/null
+++ b/src/input_common/drivers/virtual_gamepad.cpp
@@ -0,0 +1,78 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "input_common/drivers/virtual_gamepad.h"
5
6namespace InputCommon {
7constexpr std::size_t PlayerIndexCount = 10;
8
9VirtualGamepad::VirtualGamepad(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
10 for (std::size_t i = 0; i < PlayerIndexCount; i++) {
11 PreSetController(GetIdentifier(i));
12 }
13}
14
15void VirtualGamepad::SetButtonState(std::size_t player_index, int button_id, bool value) {
16 if (player_index > PlayerIndexCount) {
17 return;
18 }
19 const auto identifier = GetIdentifier(player_index);
20 SetButton(identifier, button_id, value);
21}
22
23void VirtualGamepad::SetButtonState(std::size_t player_index, VirtualButton button_id, bool value) {
24 SetButtonState(player_index, static_cast<int>(button_id), value);
25}
26
27void VirtualGamepad::SetStickPosition(std::size_t player_index, int axis_id, float x_value,
28 float y_value) {
29 if (player_index > PlayerIndexCount) {
30 return;
31 }
32 const auto identifier = GetIdentifier(player_index);
33 SetAxis(identifier, axis_id * 2, x_value);
34 SetAxis(identifier, (axis_id * 2) + 1, y_value);
35}
36
37void VirtualGamepad::SetStickPosition(std::size_t player_index, VirtualStick axis_id, float x_value,
38 float y_value) {
39 SetStickPosition(player_index, static_cast<int>(axis_id), x_value, y_value);
40}
41
42void VirtualGamepad::ResetControllers() {
43 for (std::size_t i = 0; i < PlayerIndexCount; i++) {
44 SetStickPosition(i, VirtualStick::Left, 0.0f, 0.0f);
45 SetStickPosition(i, VirtualStick::Right, 0.0f, 0.0f);
46
47 SetButtonState(i, VirtualButton::ButtonA, false);
48 SetButtonState(i, VirtualButton::ButtonB, false);
49 SetButtonState(i, VirtualButton::ButtonX, false);
50 SetButtonState(i, VirtualButton::ButtonY, false);
51 SetButtonState(i, VirtualButton::StickL, false);
52 SetButtonState(i, VirtualButton::StickR, false);
53 SetButtonState(i, VirtualButton::TriggerL, false);
54 SetButtonState(i, VirtualButton::TriggerR, false);
55 SetButtonState(i, VirtualButton::TriggerZL, false);
56 SetButtonState(i, VirtualButton::TriggerZR, false);
57 SetButtonState(i, VirtualButton::ButtonPlus, false);
58 SetButtonState(i, VirtualButton::ButtonMinus, false);
59 SetButtonState(i, VirtualButton::ButtonLeft, false);
60 SetButtonState(i, VirtualButton::ButtonUp, false);
61 SetButtonState(i, VirtualButton::ButtonRight, false);
62 SetButtonState(i, VirtualButton::ButtonDown, false);
63 SetButtonState(i, VirtualButton::ButtonSL, false);
64 SetButtonState(i, VirtualButton::ButtonSR, false);
65 SetButtonState(i, VirtualButton::ButtonHome, false);
66 SetButtonState(i, VirtualButton::ButtonCapture, false);
67 }
68}
69
70PadIdentifier VirtualGamepad::GetIdentifier(std::size_t player_index) const {
71 return {
72 .guid = Common::UUID{},
73 .port = player_index,
74 .pad = 0,
75 };
76}
77
78} // namespace InputCommon
diff --git a/src/input_common/drivers/virtual_gamepad.h b/src/input_common/drivers/virtual_gamepad.h
new file mode 100644
index 000000000..3df91cc6f
--- /dev/null
+++ b/src/input_common/drivers/virtual_gamepad.h
@@ -0,0 +1,73 @@
1// SPDX-FileCopyrightText: Copyright 2022 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 virtual controller that is always assigned to the game input
12 */
13class VirtualGamepad final : public InputEngine {
14public:
15 enum class VirtualButton {
16 ButtonA,
17 ButtonB,
18 ButtonX,
19 ButtonY,
20 StickL,
21 StickR,
22 TriggerL,
23 TriggerR,
24 TriggerZL,
25 TriggerZR,
26 ButtonPlus,
27 ButtonMinus,
28 ButtonLeft,
29 ButtonUp,
30 ButtonRight,
31 ButtonDown,
32 ButtonSL,
33 ButtonSR,
34 ButtonHome,
35 ButtonCapture,
36 };
37
38 enum class VirtualStick {
39 Left = 0,
40 Right = 1,
41 };
42
43 explicit VirtualGamepad(std::string input_engine_);
44
45 /**
46 * Sets the status of all buttons bound with the key to pressed
47 * @param player_index the player number that will take this action
48 * @param button_id the id of the button
49 * @param value indicates if the button is pressed or not
50 */
51 void SetButtonState(std::size_t player_index, int button_id, bool value);
52 void SetButtonState(std::size_t player_index, VirtualButton button_id, bool value);
53
54 /**
55 * Sets the status of all buttons bound with the key to released
56 * @param player_index the player number that will take this action
57 * @param axis_id the id of the axis to move
58 * @param x_value the position of the stick in the x axis
59 * @param y_value the position of the stick in the y axis
60 */
61 void SetStickPosition(std::size_t player_index, int axis_id, float x_value, float y_value);
62 void SetStickPosition(std::size_t player_index, VirtualStick axis_id, float x_value,
63 float y_value);
64
65 /// Restores all inputs into the neutral position
66 void ResetControllers();
67
68private:
69 /// Returns the correct identifier corresponding to the player index
70 PadIdentifier GetIdentifier(std::size_t player_index) const;
71};
72
73} // namespace InputCommon
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 942a13535..75b856c95 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -12,6 +12,7 @@
12#include "input_common/drivers/touch_screen.h" 12#include "input_common/drivers/touch_screen.h"
13#include "input_common/drivers/udp_client.h" 13#include "input_common/drivers/udp_client.h"
14#include "input_common/drivers/virtual_amiibo.h" 14#include "input_common/drivers/virtual_amiibo.h"
15#include "input_common/drivers/virtual_gamepad.h"
15#include "input_common/helpers/stick_from_buttons.h" 16#include "input_common/helpers/stick_from_buttons.h"
16#include "input_common/helpers/touch_from_buttons.h" 17#include "input_common/helpers/touch_from_buttons.h"
17#include "input_common/input_engine.h" 18#include "input_common/input_engine.h"
@@ -85,6 +86,12 @@ struct InputSubsystem::Impl {
85 Common::Input::RegisterOutputFactory(virtual_amiibo->GetEngineName(), 86 Common::Input::RegisterOutputFactory(virtual_amiibo->GetEngineName(),
86 virtual_amiibo_output_factory); 87 virtual_amiibo_output_factory);
87 88
89 virtual_gamepad = std::make_shared<VirtualGamepad>("virtual_gamepad");
90 virtual_gamepad->SetMappingCallback(mapping_callback);
91 virtual_gamepad_input_factory = std::make_shared<InputFactory>(virtual_gamepad);
92 Common::Input::RegisterInputFactory(virtual_gamepad->GetEngineName(),
93 virtual_gamepad_input_factory);
94
88#ifdef HAVE_SDL2 95#ifdef HAVE_SDL2
89 sdl = std::make_shared<SDLDriver>("sdl"); 96 sdl = std::make_shared<SDLDriver>("sdl");
90 sdl->SetMappingCallback(mapping_callback); 97 sdl->SetMappingCallback(mapping_callback);
@@ -132,6 +139,9 @@ struct InputSubsystem::Impl {
132 Common::Input::UnregisterOutputFactory(virtual_amiibo->GetEngineName()); 139 Common::Input::UnregisterOutputFactory(virtual_amiibo->GetEngineName());
133 virtual_amiibo.reset(); 140 virtual_amiibo.reset();
134 141
142 Common::Input::UnregisterInputFactory(virtual_gamepad->GetEngineName());
143 virtual_gamepad.reset();
144
135#ifdef HAVE_SDL2 145#ifdef HAVE_SDL2
136 Common::Input::UnregisterInputFactory(sdl->GetEngineName()); 146 Common::Input::UnregisterInputFactory(sdl->GetEngineName());
137 Common::Input::UnregisterOutputFactory(sdl->GetEngineName()); 147 Common::Input::UnregisterOutputFactory(sdl->GetEngineName());
@@ -290,6 +300,9 @@ struct InputSubsystem::Impl {
290 if (engine == tas_input->GetEngineName()) { 300 if (engine == tas_input->GetEngineName()) {
291 return true; 301 return true;
292 } 302 }
303 if (engine == virtual_gamepad->GetEngineName()) {
304 return true;
305 }
293#ifdef HAVE_SDL2 306#ifdef HAVE_SDL2
294 if (engine == sdl->GetEngineName()) { 307 if (engine == sdl->GetEngineName()) {
295 return true; 308 return true;
@@ -338,6 +351,7 @@ struct InputSubsystem::Impl {
338 std::shared_ptr<CemuhookUDP::UDPClient> udp_client; 351 std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
339 std::shared_ptr<Camera> camera; 352 std::shared_ptr<Camera> camera;
340 std::shared_ptr<VirtualAmiibo> virtual_amiibo; 353 std::shared_ptr<VirtualAmiibo> virtual_amiibo;
354 std::shared_ptr<VirtualGamepad> virtual_gamepad;
341 355
342 std::shared_ptr<InputFactory> keyboard_factory; 356 std::shared_ptr<InputFactory> keyboard_factory;
343 std::shared_ptr<InputFactory> mouse_factory; 357 std::shared_ptr<InputFactory> mouse_factory;
@@ -347,6 +361,7 @@ struct InputSubsystem::Impl {
347 std::shared_ptr<InputFactory> tas_input_factory; 361 std::shared_ptr<InputFactory> tas_input_factory;
348 std::shared_ptr<InputFactory> camera_input_factory; 362 std::shared_ptr<InputFactory> camera_input_factory;
349 std::shared_ptr<InputFactory> virtual_amiibo_input_factory; 363 std::shared_ptr<InputFactory> virtual_amiibo_input_factory;
364 std::shared_ptr<InputFactory> virtual_gamepad_input_factory;
350 365
351 std::shared_ptr<OutputFactory> keyboard_output_factory; 366 std::shared_ptr<OutputFactory> keyboard_output_factory;
352 std::shared_ptr<OutputFactory> mouse_output_factory; 367 std::shared_ptr<OutputFactory> mouse_output_factory;
@@ -423,6 +438,14 @@ const VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() const {
423 return impl->virtual_amiibo.get(); 438 return impl->virtual_amiibo.get();
424} 439}
425 440
441VirtualGamepad* InputSubsystem::GetVirtualGamepad() {
442 return impl->virtual_gamepad.get();
443}
444
445const VirtualGamepad* InputSubsystem::GetVirtualGamepad() const {
446 return impl->virtual_gamepad.get();
447}
448
426std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const { 449std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const {
427 return impl->GetInputDevices(); 450 return impl->GetInputDevices();
428} 451}
diff --git a/src/input_common/main.h b/src/input_common/main.h
index 6218c37f6..1207d786c 100644
--- a/src/input_common/main.h
+++ b/src/input_common/main.h
@@ -34,6 +34,7 @@ class Keyboard;
34class Mouse; 34class Mouse;
35class TouchScreen; 35class TouchScreen;
36class VirtualAmiibo; 36class VirtualAmiibo;
37class VirtualGamepad;
37struct MappingData; 38struct MappingData;
38} // namespace InputCommon 39} // namespace InputCommon
39 40
@@ -108,6 +109,12 @@ public:
108 /// Retrieves the underlying virtual amiibo input device. 109 /// Retrieves the underlying virtual amiibo input device.
109 [[nodiscard]] const VirtualAmiibo* GetVirtualAmiibo() const; 110 [[nodiscard]] const VirtualAmiibo* GetVirtualAmiibo() const;
110 111
112 /// Retrieves the underlying virtual gamepad input device.
113 [[nodiscard]] VirtualGamepad* GetVirtualGamepad();
114
115 /// Retrieves the underlying virtual gamepad input device.
116 [[nodiscard]] const VirtualGamepad* GetVirtualGamepad() const;
117
111 /** 118 /**
112 * Returns all available input devices that this Factory can create a new device with. 119 * Returns all available input devices that this Factory can create a new device with.
113 * Each returned ParamPackage should have a `display` field used for display, a `engine` field 120 * Each returned ParamPackage should have a `display` field used for display, a `engine` field