summaryrefslogtreecommitdiff
path: root/src/input_common
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common')
-rw-r--r--src/input_common/CMakeLists.txt11
-rw-r--r--src/input_common/drivers/gc_adapter.cpp10
-rw-r--r--src/input_common/drivers/gc_adapter.h4
-rw-r--r--src/input_common/drivers/mouse.cpp2
-rw-r--r--src/input_common/drivers/sdl_driver.cpp72
-rw-r--r--src/input_common/drivers/sdl_driver.h4
-rw-r--r--src/input_common/drivers/virtual_amiibo.cpp101
-rw-r--r--src/input_common/drivers/virtual_amiibo.h61
-rw-r--r--src/input_common/input_engine.cpp37
-rw-r--r--src/input_common/input_engine.h24
-rw-r--r--src/input_common/input_poller.cpp96
-rw-r--r--src/input_common/input_poller.h10
-rw-r--r--src/input_common/main.cpp21
-rw-r--r--src/input_common/main.h7
14 files changed, 422 insertions, 38 deletions
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 4b91b88ce..cc6f0ffc0 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -18,6 +18,8 @@ add_library(input_common STATIC
18 drivers/touch_screen.h 18 drivers/touch_screen.h
19 drivers/udp_client.cpp 19 drivers/udp_client.cpp
20 drivers/udp_client.h 20 drivers/udp_client.h
21 drivers/virtual_amiibo.cpp
22 drivers/virtual_amiibo.h
21 helpers/stick_from_buttons.cpp 23 helpers/stick_from_buttons.cpp
22 helpers/stick_from_buttons.h 24 helpers/stick_from_buttons.h
23 helpers/touch_from_buttons.cpp 25 helpers/touch_from_buttons.cpp
@@ -37,21 +39,14 @@ add_library(input_common STATIC
37if (MSVC) 39if (MSVC)
38 target_compile_options(input_common PRIVATE 40 target_compile_options(input_common PRIVATE
39 /W4 41 /W4
40 /WX
41 42
42 /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data 43 /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data
43 /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data
44 /we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch
45 /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data 44 /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
45 /we4800 # Implicit conversion from 'type' to bool. Possible information loss
46 ) 46 )
47else() 47else()
48 target_compile_options(input_common PRIVATE 48 target_compile_options(input_common PRIVATE
49 -Werror
50 -Werror=conversion 49 -Werror=conversion
51 -Werror=ignored-qualifiers
52 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
53 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
54 -Werror=unused-variable
55 ) 50 )
56endif() 51endif()
57 52
diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp
index 27a0ffb0d..826fa2109 100644
--- a/src/input_common/drivers/gc_adapter.cpp
+++ b/src/input_common/drivers/gc_adapter.cpp
@@ -90,7 +90,7 @@ GCAdapter::~GCAdapter() {
90 90
91void GCAdapter::AdapterInputThread(std::stop_token stop_token) { 91void GCAdapter::AdapterInputThread(std::stop_token stop_token) {
92 LOG_DEBUG(Input, "Input thread started"); 92 LOG_DEBUG(Input, "Input thread started");
93 Common::SetCurrentThreadName("yuzu:input:GCAdapter"); 93 Common::SetCurrentThreadName("GCAdapter");
94 s32 payload_size{}; 94 s32 payload_size{};
95 AdapterPayload adapter_payload{}; 95 AdapterPayload adapter_payload{};
96 96
@@ -214,7 +214,7 @@ void GCAdapter::UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_
214} 214}
215 215
216void GCAdapter::AdapterScanThread(std::stop_token stop_token) { 216void GCAdapter::AdapterScanThread(std::stop_token stop_token) {
217 Common::SetCurrentThreadName("yuzu:input:ScanGCAdapter"); 217 Common::SetCurrentThreadName("ScanGCAdapter");
218 usb_adapter_handle = nullptr; 218 usb_adapter_handle = nullptr;
219 pads = {}; 219 pads = {};
220 while (!stop_token.stop_requested() && !Setup()) { 220 while (!stop_token.stop_requested() && !Setup()) {
@@ -324,7 +324,7 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) {
324 return true; 324 return true;
325} 325}
326 326
327Common::Input::VibrationError GCAdapter::SetRumble( 327Common::Input::VibrationError GCAdapter::SetVibration(
328 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { 328 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
329 const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; 329 const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f;
330 const auto processed_amplitude = 330 const auto processed_amplitude =
@@ -338,6 +338,10 @@ Common::Input::VibrationError GCAdapter::SetRumble(
338 return Common::Input::VibrationError::None; 338 return Common::Input::VibrationError::None;
339} 339}
340 340
341bool GCAdapter::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) {
342 return rumble_enabled;
343}
344
341void GCAdapter::UpdateVibrations() { 345void GCAdapter::UpdateVibrations() {
342 // Use 8 states to keep the switching between on/off fast enough for 346 // Use 8 states to keep the switching between on/off fast enough for
343 // a human to feel different vibration strenght 347 // a human to feel different vibration strenght
diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h
index 8682da847..7f81767f7 100644
--- a/src/input_common/drivers/gc_adapter.h
+++ b/src/input_common/drivers/gc_adapter.h
@@ -25,9 +25,11 @@ public:
25 explicit GCAdapter(std::string input_engine_); 25 explicit GCAdapter(std::string input_engine_);
26 ~GCAdapter() override; 26 ~GCAdapter() override;
27 27
28 Common::Input::VibrationError SetRumble( 28 Common::Input::VibrationError SetVibration(
29 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; 29 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
30 30
31 bool IsVibrationEnabled(const PadIdentifier& identifier) override;
32
31 /// Used for automapping features 33 /// Used for automapping features
32 std::vector<Common::ParamPackage> GetInputDevices() const override; 34 std::vector<Common::ParamPackage> GetInputDevices() const override;
33 ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; 35 ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp
index 4909fa8d7..98c3157a8 100644
--- a/src/input_common/drivers/mouse.cpp
+++ b/src/input_common/drivers/mouse.cpp
@@ -37,7 +37,7 @@ Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_))
37} 37}
38 38
39void Mouse::UpdateThread(std::stop_token stop_token) { 39void Mouse::UpdateThread(std::stop_token stop_token) {
40 Common::SetCurrentThreadName("yuzu:input:Mouse"); 40 Common::SetCurrentThreadName("Mouse");
41 constexpr int update_time = 10; 41 constexpr int update_time = 10;
42 while (!stop_token.stop_requested()) { 42 while (!stop_token.stop_requested()) {
43 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/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 5cc1ccbd9..45ce588f0 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -40,8 +40,8 @@ public:
40 void EnableMotion() { 40 void EnableMotion() {
41 if (sdl_controller) { 41 if (sdl_controller) {
42 SDL_GameController* controller = sdl_controller.get(); 42 SDL_GameController* controller = sdl_controller.get();
43 has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL); 43 has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) == SDL_TRUE;
44 has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO); 44 has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) == SDL_TRUE;
45 if (has_accel) { 45 if (has_accel) {
46 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); 46 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
47 } 47 }
@@ -114,6 +114,20 @@ public:
114 } 114 }
115 return false; 115 return false;
116 } 116 }
117
118 void EnableVibration(bool is_enabled) {
119 has_vibration = is_enabled;
120 is_vibration_tested = true;
121 }
122
123 bool HasVibration() const {
124 return has_vibration;
125 }
126
127 bool IsVibrationTested() const {
128 return is_vibration_tested;
129 }
130
117 /** 131 /**
118 * The Pad identifier of the joystick 132 * The Pad identifier of the joystick
119 */ 133 */
@@ -236,6 +250,8 @@ private:
236 u64 last_motion_update{}; 250 u64 last_motion_update{};
237 bool has_gyro{false}; 251 bool has_gyro{false};
238 bool has_accel{false}; 252 bool has_accel{false};
253 bool has_vibration{false};
254 bool is_vibration_tested{false};
239 BasicMotion motion; 255 BasicMotion motion;
240}; 256};
241 257
@@ -436,7 +452,7 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
436 initialized = true; 452 initialized = true;
437 if (start_thread) { 453 if (start_thread) {
438 poll_thread = std::thread([this] { 454 poll_thread = std::thread([this] {
439 Common::SetCurrentThreadName("yuzu:input:SDL"); 455 Common::SetCurrentThreadName("SDL_MainLoop");
440 using namespace std::chrono_literals; 456 using namespace std::chrono_literals;
441 while (initialized) { 457 while (initialized) {
442 SDL_PumpEvents(); 458 SDL_PumpEvents();
@@ -444,7 +460,7 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
444 } 460 }
445 }); 461 });
446 vibration_thread = std::thread([this] { 462 vibration_thread = std::thread([this] {
447 Common::SetCurrentThreadName("yuzu:input:SDL_Vibration"); 463 Common::SetCurrentThreadName("SDL_Vibration");
448 using namespace std::chrono_literals; 464 using namespace std::chrono_literals;
449 while (initialized) { 465 while (initialized) {
450 SendVibrations(); 466 SendVibrations();
@@ -517,7 +533,7 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
517 return devices; 533 return devices;
518} 534}
519 535
520Common::Input::VibrationError SDLDriver::SetRumble( 536Common::Input::VibrationError SDLDriver::SetVibration(
521 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { 537 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
522 const auto joystick = 538 const auto joystick =
523 GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); 539 GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port));
@@ -546,13 +562,6 @@ Common::Input::VibrationError SDLDriver::SetRumble(
546 .type = Common::Input::VibrationAmplificationType::Exponential, 562 .type = Common::Input::VibrationAmplificationType::Exponential,
547 }; 563 };
548 564
549 if (vibration.type == Common::Input::VibrationAmplificationType::Test) {
550 if (!joystick->RumblePlay(new_vibration)) {
551 return Common::Input::VibrationError::Unknown;
552 }
553 return Common::Input::VibrationError::None;
554 }
555
556 vibration_queue.Push(VibrationRequest{ 565 vibration_queue.Push(VibrationRequest{
557 .identifier = identifier, 566 .identifier = identifier,
558 .vibration = new_vibration, 567 .vibration = new_vibration,
@@ -561,6 +570,45 @@ Common::Input::VibrationError SDLDriver::SetRumble(
561 return Common::Input::VibrationError::None; 570 return Common::Input::VibrationError::None;
562} 571}
563 572
573bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) {
574 const auto joystick =
575 GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port));
576
577 constexpr Common::Input::VibrationStatus test_vibration{
578 .low_amplitude = 1,
579 .low_frequency = 160.0f,
580 .high_amplitude = 1,
581 .high_frequency = 320.0f,
582 .type = Common::Input::VibrationAmplificationType::Exponential,
583 };
584
585 constexpr Common::Input::VibrationStatus zero_vibration{
586 .low_amplitude = 0,
587 .low_frequency = 160.0f,
588 .high_amplitude = 0,
589 .high_frequency = 320.0f,
590 .type = Common::Input::VibrationAmplificationType::Exponential,
591 };
592
593 if (joystick->IsVibrationTested()) {
594 return joystick->HasVibration();
595 }
596
597 // First vibration might fail
598 joystick->RumblePlay(test_vibration);
599
600 // Wait for about 15ms to ensure the controller is ready for the stop command
601 std::this_thread::sleep_for(std::chrono::milliseconds(15));
602
603 if (!joystick->RumblePlay(zero_vibration)) {
604 joystick->EnableVibration(false);
605 return false;
606 }
607
608 joystick->EnableVibration(true);
609 return true;
610}
611
564void SDLDriver::SendVibrations() { 612void SDLDriver::SendVibrations() {
565 while (!vibration_queue.Empty()) { 613 while (!vibration_queue.Empty()) {
566 VibrationRequest request; 614 VibrationRequest request;
diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h
index fc3a44572..d1b4471cf 100644
--- a/src/input_common/drivers/sdl_driver.h
+++ b/src/input_common/drivers/sdl_driver.h
@@ -61,9 +61,11 @@ public:
61 61
62 bool IsStickInverted(const Common::ParamPackage& params) override; 62 bool IsStickInverted(const Common::ParamPackage& params) override;
63 63
64 Common::Input::VibrationError SetRumble( 64 Common::Input::VibrationError SetVibration(
65 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; 65 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
66 66
67 bool IsVibrationEnabled(const PadIdentifier& identifier) override;
68
67private: 69private:
68 struct VibrationRequest { 70 struct VibrationRequest {
69 PadIdentifier identifier; 71 PadIdentifier identifier;
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
diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp
index 6ede0e4b0..61cfd0911 100644
--- a/src/input_common/input_engine.cpp
+++ b/src/input_common/input_engine.cpp
@@ -102,6 +102,17 @@ void InputEngine::SetCamera(const PadIdentifier& identifier,
102 TriggerOnCameraChange(identifier, value); 102 TriggerOnCameraChange(identifier, value);
103} 103}
104 104
105void InputEngine::SetNfc(const PadIdentifier& identifier, const Common::Input::NfcStatus& value) {
106 {
107 std::scoped_lock lock{mutex};
108 ControllerData& controller = controller_list.at(identifier);
109 if (!configuring) {
110 controller.nfc = value;
111 }
112 }
113 TriggerOnNfcChange(identifier, value);
114}
115
105bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const { 116bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const {
106 std::scoped_lock lock{mutex}; 117 std::scoped_lock lock{mutex};
107 const auto controller_iter = controller_list.find(identifier); 118 const auto controller_iter = controller_list.find(identifier);
@@ -189,6 +200,18 @@ Common::Input::CameraStatus InputEngine::GetCamera(const PadIdentifier& identifi
189 return controller.camera; 200 return controller.camera;
190} 201}
191 202
203Common::Input::NfcStatus InputEngine::GetNfc(const PadIdentifier& identifier) const {
204 std::scoped_lock lock{mutex};
205 const auto controller_iter = controller_list.find(identifier);
206 if (controller_iter == controller_list.cend()) {
207 LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(),
208 identifier.pad, identifier.port);
209 return {};
210 }
211 const ControllerData& controller = controller_iter->second;
212 return controller.nfc;
213}
214
192void InputEngine::ResetButtonState() { 215void InputEngine::ResetButtonState() {
193 for (const auto& controller : controller_list) { 216 for (const auto& controller : controller_list) {
194 for (const auto& button : controller.second.buttons) { 217 for (const auto& button : controller.second.buttons) {
@@ -355,6 +378,20 @@ void InputEngine::TriggerOnCameraChange(const PadIdentifier& identifier,
355 } 378 }
356} 379}
357 380
381void InputEngine::TriggerOnNfcChange(const PadIdentifier& identifier,
382 [[maybe_unused]] const Common::Input::NfcStatus& value) {
383 std::scoped_lock lock{mutex_callback};
384 for (const auto& poller_pair : callback_list) {
385 const InputIdentifier& poller = poller_pair.second;
386 if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Nfc, 0)) {
387 continue;
388 }
389 if (poller.callback.on_change) {
390 poller.callback.on_change();
391 }
392 }
393}
394
358bool InputEngine::IsInputIdentifierEqual(const InputIdentifier& input_identifier, 395bool InputEngine::IsInputIdentifierEqual(const InputIdentifier& input_identifier,
359 const PadIdentifier& identifier, EngineInputType type, 396 const PadIdentifier& identifier, EngineInputType type,
360 int index) const { 397 int index) const {
diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h
index f6b3c4610..d4c264a8e 100644
--- a/src/input_common/input_engine.h
+++ b/src/input_common/input_engine.h
@@ -42,6 +42,7 @@ enum class EngineInputType {
42 Camera, 42 Camera,
43 HatButton, 43 HatButton,
44 Motion, 44 Motion,
45 Nfc,
45}; 46};
46 47
47namespace std { 48namespace std {
@@ -107,12 +108,17 @@ public:
107 [[maybe_unused]] const Common::Input::LedStatus& led_status) {} 108 [[maybe_unused]] const Common::Input::LedStatus& led_status) {}
108 109
109 // Sets rumble to a controller 110 // Sets rumble to a controller
110 virtual Common::Input::VibrationError SetRumble( 111 virtual Common::Input::VibrationError SetVibration(
111 [[maybe_unused]] const PadIdentifier& identifier, 112 [[maybe_unused]] const PadIdentifier& identifier,
112 [[maybe_unused]] const Common::Input::VibrationStatus& vibration) { 113 [[maybe_unused]] const Common::Input::VibrationStatus& vibration) {
113 return Common::Input::VibrationError::NotSupported; 114 return Common::Input::VibrationError::NotSupported;
114 } 115 }
115 116
117 // Returns true if device supports vibrations
118 virtual bool IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) {
119 return false;
120 }
121
116 // Sets polling mode to a controller 122 // Sets polling mode to a controller
117 virtual Common::Input::PollingError SetPollingMode( 123 virtual Common::Input::PollingError SetPollingMode(
118 [[maybe_unused]] const PadIdentifier& identifier, 124 [[maybe_unused]] const PadIdentifier& identifier,
@@ -127,6 +133,18 @@ public:
127 return Common::Input::CameraError::NotSupported; 133 return Common::Input::CameraError::NotSupported;
128 } 134 }
129 135
136 // Request nfc data from a controller
137 virtual Common::Input::NfcState SupportsNfc(
138 [[maybe_unused]] const PadIdentifier& identifier) const {
139 return Common::Input::NfcState::NotSupported;
140 }
141
142 // Writes data to an nfc tag
143 virtual Common::Input::NfcState WriteNfcData([[maybe_unused]] const PadIdentifier& identifier,
144 [[maybe_unused]] const std::vector<u8>& data) {
145 return Common::Input::NfcState::NotSupported;
146 }
147
130 // Returns the engine name 148 // Returns the engine name
131 [[nodiscard]] const std::string& GetEngineName() const; 149 [[nodiscard]] const std::string& GetEngineName() const;
132 150
@@ -183,6 +201,7 @@ public:
183 Common::Input::BatteryLevel GetBattery(const PadIdentifier& identifier) const; 201 Common::Input::BatteryLevel GetBattery(const PadIdentifier& identifier) const;
184 BasicMotion GetMotion(const PadIdentifier& identifier, int motion) const; 202 BasicMotion GetMotion(const PadIdentifier& identifier, int motion) const;
185 Common::Input::CameraStatus GetCamera(const PadIdentifier& identifier) const; 203 Common::Input::CameraStatus GetCamera(const PadIdentifier& identifier) const;
204 Common::Input::NfcStatus GetNfc(const PadIdentifier& identifier) const;
186 205
187 int SetCallback(InputIdentifier input_identifier); 206 int SetCallback(InputIdentifier input_identifier);
188 void SetMappingCallback(MappingCallback callback); 207 void SetMappingCallback(MappingCallback callback);
@@ -195,6 +214,7 @@ protected:
195 void SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value); 214 void SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value);
196 void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value); 215 void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value);
197 void SetCamera(const PadIdentifier& identifier, const Common::Input::CameraStatus& value); 216 void SetCamera(const PadIdentifier& identifier, const Common::Input::CameraStatus& value);
217 void SetNfc(const PadIdentifier& identifier, const Common::Input::NfcStatus& value);
198 218
199 virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const { 219 virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const {
200 return "Unknown"; 220 return "Unknown";
@@ -208,6 +228,7 @@ private:
208 std::unordered_map<int, BasicMotion> motions; 228 std::unordered_map<int, BasicMotion> motions;
209 Common::Input::BatteryLevel battery{}; 229 Common::Input::BatteryLevel battery{};
210 Common::Input::CameraStatus camera{}; 230 Common::Input::CameraStatus camera{};
231 Common::Input::NfcStatus nfc{};
211 }; 232 };
212 233
213 void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value); 234 void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value);
@@ -218,6 +239,7 @@ private:
218 const BasicMotion& value); 239 const BasicMotion& value);
219 void TriggerOnCameraChange(const PadIdentifier& identifier, 240 void TriggerOnCameraChange(const PadIdentifier& identifier,
220 const Common::Input::CameraStatus& value); 241 const Common::Input::CameraStatus& value);
242 void TriggerOnNfcChange(const PadIdentifier& identifier, const Common::Input::NfcStatus& value);
221 243
222 bool IsInputIdentifierEqual(const InputIdentifier& input_identifier, 244 bool IsInputIdentifierEqual(const InputIdentifier& input_identifier,
223 const PadIdentifier& identifier, EngineInputType type, 245 const PadIdentifier& identifier, EngineInputType type,
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp
index ffb9b945e..4ac182147 100644
--- a/src/input_common/input_poller.cpp
+++ b/src/input_common/input_poller.cpp
@@ -691,9 +691,56 @@ public:
691 } 691 }
692 692
693 void OnChange() { 693 void OnChange() {
694 const auto camera_status = GetStatus();
695
694 const Common::Input::CallbackStatus status{ 696 const Common::Input::CallbackStatus status{
695 .type = Common::Input::InputType::IrSensor, 697 .type = Common::Input::InputType::IrSensor,
696 .camera_status = GetStatus(), 698 .camera_status = camera_status.format,
699 .raw_data = camera_status.data,
700 };
701
702 TriggerOnChange(status);
703 }
704
705private:
706 const PadIdentifier identifier;
707 int callback_key;
708 InputEngine* input_engine;
709};
710
711class InputFromNfc final : public Common::Input::InputDevice {
712public:
713 explicit InputFromNfc(PadIdentifier identifier_, InputEngine* input_engine_)
714 : identifier(identifier_), input_engine(input_engine_) {
715 UpdateCallback engine_callback{[this]() { OnChange(); }};
716 const InputIdentifier input_identifier{
717 .identifier = identifier,
718 .type = EngineInputType::Nfc,
719 .index = 0,
720 .callback = engine_callback,
721 };
722 callback_key = input_engine->SetCallback(input_identifier);
723 }
724
725 ~InputFromNfc() override {
726 input_engine->DeleteCallback(callback_key);
727 }
728
729 Common::Input::NfcStatus GetStatus() const {
730 return input_engine->GetNfc(identifier);
731 }
732
733 void ForceUpdate() override {
734 OnChange();
735 }
736
737 void OnChange() {
738 const auto nfc_status = GetStatus();
739
740 const Common::Input::CallbackStatus status{
741 .type = Common::Input::InputType::Nfc,
742 .nfc_status = nfc_status.state,
743 .raw_data = nfc_status.data,
697 }; 744 };
698 745
699 TriggerOnChange(status); 746 TriggerOnChange(status);
@@ -716,7 +763,11 @@ public:
716 763
717 Common::Input::VibrationError SetVibration( 764 Common::Input::VibrationError SetVibration(
718 const Common::Input::VibrationStatus& vibration_status) override { 765 const Common::Input::VibrationStatus& vibration_status) override {
719 return input_engine->SetRumble(identifier, vibration_status); 766 return input_engine->SetVibration(identifier, vibration_status);
767 }
768
769 bool IsVibrationEnabled() override {
770 return input_engine->IsVibrationEnabled(identifier);
720 } 771 }
721 772
722 Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) override { 773 Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) override {
@@ -727,6 +778,14 @@ public:
727 return input_engine->SetCameraFormat(identifier, camera_format); 778 return input_engine->SetCameraFormat(identifier, camera_format);
728 } 779 }
729 780
781 Common::Input::NfcState SupportsNfc() const override {
782 return input_engine->SupportsNfc(identifier);
783 }
784
785 Common::Input::NfcState WriteNfcData(const std::vector<u8>& data) override {
786 return input_engine->WriteNfcData(identifier, data);
787 }
788
730private: 789private:
731 const PadIdentifier identifier; 790 const PadIdentifier identifier;
732 InputEngine* input_engine; 791 InputEngine* input_engine;
@@ -742,8 +801,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateButtonDevice(
742 801
743 const auto button_id = params.Get("button", 0); 802 const auto button_id = params.Get("button", 0);
744 const auto keyboard_key = params.Get("code", 0); 803 const auto keyboard_key = params.Get("code", 0);
745 const auto toggle = params.Get("toggle", false); 804 const auto toggle = params.Get("toggle", false) != 0;
746 const auto inverted = params.Get("inverted", false); 805 const auto inverted = params.Get("inverted", false) != 0;
747 input_engine->PreSetController(identifier); 806 input_engine->PreSetController(identifier);
748 input_engine->PreSetButton(identifier, button_id); 807 input_engine->PreSetButton(identifier, button_id);
749 input_engine->PreSetButton(identifier, keyboard_key); 808 input_engine->PreSetButton(identifier, keyboard_key);
@@ -765,8 +824,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateHatButtonDevice(
765 824
766 const auto button_id = params.Get("hat", 0); 825 const auto button_id = params.Get("hat", 0);
767 const auto direction = input_engine->GetHatButtonId(params.Get("direction", "")); 826 const auto direction = input_engine->GetHatButtonId(params.Get("direction", ""));
768 const auto toggle = params.Get("toggle", false); 827 const auto toggle = params.Get("toggle", false) != 0;
769 const auto inverted = params.Get("inverted", false); 828 const auto inverted = params.Get("inverted", false) != 0;
770 829
771 input_engine->PreSetController(identifier); 830 input_engine->PreSetController(identifier);
772 input_engine->PreSetHatButton(identifier, button_id); 831 input_engine->PreSetHatButton(identifier, button_id);
@@ -824,7 +883,7 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateAnalogDevice(
824 .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f), 883 .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f),
825 .offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f), 884 .offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f),
826 .inverted = params.Get("invert", "+") == "-", 885 .inverted = params.Get("invert", "+") == "-",
827 .toggle = static_cast<bool>(params.Get("toggle", false)), 886 .toggle = params.Get("toggle", false) != 0,
828 }; 887 };
829 input_engine->PreSetController(identifier); 888 input_engine->PreSetController(identifier);
830 input_engine->PreSetAxis(identifier, axis); 889 input_engine->PreSetAxis(identifier, axis);
@@ -840,8 +899,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTriggerDevice(
840 }; 899 };
841 900
842 const auto button = params.Get("button", 0); 901 const auto button = params.Get("button", 0);
843 const auto toggle = params.Get("toggle", false); 902 const auto toggle = params.Get("toggle", false) != 0;
844 const auto inverted = params.Get("inverted", false); 903 const auto inverted = params.Get("inverted", false) != 0;
845 904
846 const auto axis = params.Get("axis", 0); 905 const auto axis = params.Get("axis", 0);
847 const Common::Input::AnalogProperties properties = { 906 const Common::Input::AnalogProperties properties = {
@@ -871,8 +930,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice(
871 }; 930 };
872 931
873 const auto button = params.Get("button", 0); 932 const auto button = params.Get("button", 0);
874 const auto toggle = params.Get("toggle", false); 933 const auto toggle = params.Get("toggle", false) != 0;
875 const auto inverted = params.Get("inverted", false); 934 const auto inverted = params.Get("inverted", false) != 0;
876 935
877 const auto axis_x = params.Get("axis_x", 0); 936 const auto axis_x = params.Get("axis_x", 0);
878 const Common::Input::AnalogProperties properties_x = { 937 const Common::Input::AnalogProperties properties_x = {
@@ -978,6 +1037,18 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateCameraDevice(
978 return std::make_unique<InputFromCamera>(identifier, input_engine.get()); 1037 return std::make_unique<InputFromCamera>(identifier, input_engine.get());
979} 1038}
980 1039
1040std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateNfcDevice(
1041 const Common::ParamPackage& params) {
1042 const PadIdentifier identifier = {
1043 .guid = Common::UUID{params.Get("guid", "")},
1044 .port = static_cast<std::size_t>(params.Get("port", 0)),
1045 .pad = static_cast<std::size_t>(params.Get("pad", 0)),
1046 };
1047
1048 input_engine->PreSetController(identifier);
1049 return std::make_unique<InputFromNfc>(identifier, input_engine.get());
1050}
1051
981InputFactory::InputFactory(std::shared_ptr<InputEngine> input_engine_) 1052InputFactory::InputFactory(std::shared_ptr<InputEngine> input_engine_)
982 : input_engine(std::move(input_engine_)) {} 1053 : input_engine(std::move(input_engine_)) {}
983 1054
@@ -989,6 +1060,9 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::Create(
989 if (params.Has("camera")) { 1060 if (params.Has("camera")) {
990 return CreateCameraDevice(params); 1061 return CreateCameraDevice(params);
991 } 1062 }
1063 if (params.Has("nfc")) {
1064 return CreateNfcDevice(params);
1065 }
992 if (params.Has("button") && params.Has("axis")) { 1066 if (params.Has("button") && params.Has("axis")) {
993 return CreateTriggerDevice(params); 1067 return CreateTriggerDevice(params);
994 } 1068 }
diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h
index 4410a8415..d7db13ce4 100644
--- a/src/input_common/input_poller.h
+++ b/src/input_common/input_poller.h
@@ -222,6 +222,16 @@ private:
222 std::unique_ptr<Common::Input::InputDevice> CreateCameraDevice( 222 std::unique_ptr<Common::Input::InputDevice> CreateCameraDevice(
223 const Common::ParamPackage& params); 223 const Common::ParamPackage& params);
224 224
225 /**
226 * Creates a nfc device from the parameters given.
227 * @param params contains parameters for creating the device:
228 * - "guid": text string for identifying controllers
229 * - "port": port of the connected device
230 * - "pad": slot of the connected controller
231 * @returns a unique input device with the parameters specified
232 */
233 std::unique_ptr<Common::Input::InputDevice> CreateNfcDevice(const Common::ParamPackage& params);
234
225 std::shared_ptr<InputEngine> input_engine; 235 std::shared_ptr<InputEngine> input_engine;
226}; 236};
227} // namespace InputCommon 237} // namespace InputCommon
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 75a57b9fc..b2064ef95 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -11,6 +11,7 @@
11#include "input_common/drivers/tas_input.h" 11#include "input_common/drivers/tas_input.h"
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/helpers/stick_from_buttons.h" 15#include "input_common/helpers/stick_from_buttons.h"
15#include "input_common/helpers/touch_from_buttons.h" 16#include "input_common/helpers/touch_from_buttons.h"
16#include "input_common/input_engine.h" 17#include "input_common/input_engine.h"
@@ -87,6 +88,15 @@ struct InputSubsystem::Impl {
87 Common::Input::RegisterFactory<Common::Input::OutputDevice>(camera->GetEngineName(), 88 Common::Input::RegisterFactory<Common::Input::OutputDevice>(camera->GetEngineName(),
88 camera_output_factory); 89 camera_output_factory);
89 90
91 virtual_amiibo = std::make_shared<VirtualAmiibo>("virtual_amiibo");
92 virtual_amiibo->SetMappingCallback(mapping_callback);
93 virtual_amiibo_input_factory = std::make_shared<InputFactory>(virtual_amiibo);
94 virtual_amiibo_output_factory = std::make_shared<OutputFactory>(virtual_amiibo);
95 Common::Input::RegisterFactory<Common::Input::InputDevice>(virtual_amiibo->GetEngineName(),
96 virtual_amiibo_input_factory);
97 Common::Input::RegisterFactory<Common::Input::OutputDevice>(virtual_amiibo->GetEngineName(),
98 virtual_amiibo_output_factory);
99
90#ifdef HAVE_SDL2 100#ifdef HAVE_SDL2
91 sdl = std::make_shared<SDLDriver>("sdl"); 101 sdl = std::make_shared<SDLDriver>("sdl");
92 sdl->SetMappingCallback(mapping_callback); 102 sdl->SetMappingCallback(mapping_callback);
@@ -327,6 +337,7 @@ struct InputSubsystem::Impl {
327 std::shared_ptr<TasInput::Tas> tas_input; 337 std::shared_ptr<TasInput::Tas> tas_input;
328 std::shared_ptr<CemuhookUDP::UDPClient> udp_client; 338 std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
329 std::shared_ptr<Camera> camera; 339 std::shared_ptr<Camera> camera;
340 std::shared_ptr<VirtualAmiibo> virtual_amiibo;
330 341
331 std::shared_ptr<InputFactory> keyboard_factory; 342 std::shared_ptr<InputFactory> keyboard_factory;
332 std::shared_ptr<InputFactory> mouse_factory; 343 std::shared_ptr<InputFactory> mouse_factory;
@@ -335,6 +346,7 @@ struct InputSubsystem::Impl {
335 std::shared_ptr<InputFactory> udp_client_input_factory; 346 std::shared_ptr<InputFactory> udp_client_input_factory;
336 std::shared_ptr<InputFactory> tas_input_factory; 347 std::shared_ptr<InputFactory> tas_input_factory;
337 std::shared_ptr<InputFactory> camera_input_factory; 348 std::shared_ptr<InputFactory> camera_input_factory;
349 std::shared_ptr<InputFactory> virtual_amiibo_input_factory;
338 350
339 std::shared_ptr<OutputFactory> keyboard_output_factory; 351 std::shared_ptr<OutputFactory> keyboard_output_factory;
340 std::shared_ptr<OutputFactory> mouse_output_factory; 352 std::shared_ptr<OutputFactory> mouse_output_factory;
@@ -342,6 +354,7 @@ struct InputSubsystem::Impl {
342 std::shared_ptr<OutputFactory> udp_client_output_factory; 354 std::shared_ptr<OutputFactory> udp_client_output_factory;
343 std::shared_ptr<OutputFactory> tas_output_factory; 355 std::shared_ptr<OutputFactory> tas_output_factory;
344 std::shared_ptr<OutputFactory> camera_output_factory; 356 std::shared_ptr<OutputFactory> camera_output_factory;
357 std::shared_ptr<OutputFactory> virtual_amiibo_output_factory;
345 358
346#ifdef HAVE_SDL2 359#ifdef HAVE_SDL2
347 std::shared_ptr<SDLDriver> sdl; 360 std::shared_ptr<SDLDriver> sdl;
@@ -402,6 +415,14 @@ const Camera* InputSubsystem::GetCamera() const {
402 return impl->camera.get(); 415 return impl->camera.get();
403} 416}
404 417
418VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() {
419 return impl->virtual_amiibo.get();
420}
421
422const VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() const {
423 return impl->virtual_amiibo.get();
424}
425
405std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const { 426std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const {
406 return impl->GetInputDevices(); 427 return impl->GetInputDevices();
407} 428}
diff --git a/src/input_common/main.h b/src/input_common/main.h
index 9a969e747..ced252383 100644
--- a/src/input_common/main.h
+++ b/src/input_common/main.h
@@ -33,6 +33,7 @@ class Camera;
33class Keyboard; 33class Keyboard;
34class Mouse; 34class Mouse;
35class TouchScreen; 35class TouchScreen;
36class VirtualAmiibo;
36struct MappingData; 37struct MappingData;
37} // namespace InputCommon 38} // namespace InputCommon
38 39
@@ -101,6 +102,12 @@ public:
101 /// Retrieves the underlying camera input device. 102 /// Retrieves the underlying camera input device.
102 [[nodiscard]] const Camera* GetCamera() const; 103 [[nodiscard]] const Camera* GetCamera() const;
103 104
105 /// Retrieves the underlying virtual amiibo input device.
106 [[nodiscard]] VirtualAmiibo* GetVirtualAmiibo();
107
108 /// Retrieves the underlying virtual amiibo input device.
109 [[nodiscard]] const VirtualAmiibo* GetVirtualAmiibo() const;
110
104 /** 111 /**
105 * Returns all available input devices that this Factory can create a new device with. 112 * Returns all available input devices that this Factory can create a new device with.
106 * Each returned ParamPackage should have a `display` field used for display, a `engine` field 113 * Each returned ParamPackage should have a `display` field used for display, a `engine` field