summaryrefslogtreecommitdiffstats
path: root/src/input_common
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/input_common/CMakeLists.txt2
-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.h17
-rw-r--r--src/input_common/input_poller.cpp64
-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
9 files changed, 320 insertions, 0 deletions
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 4b91b88ce..2cf9eb97f 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -18,6 +18,8 @@ add_library(input_common STATIC
drivers/touch_screen.h
drivers/udp_client.cpp
drivers/udp_client.h
+ drivers/virtual_amiibo.cpp
+ drivers/virtual_amiibo.h
helpers/stick_from_buttons.cpp
helpers/stick_from_buttons.h
helpers/touch_from_buttons.cpp
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 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <cstring>
+#include <fmt/format.h>
+
+#include "common/fs/file.h"
+#include "common/fs/fs.h"
+#include "common/fs/path_util.h"
+#include "common/logging/log.h"
+#include "common/settings.h"
+#include "input_common/drivers/virtual_amiibo.h"
+
+namespace InputCommon {
+constexpr PadIdentifier identifier = {
+ .guid = Common::UUID{},
+ .port = 0,
+ .pad = 0,
+};
+
+VirtualAmiibo::VirtualAmiibo(std::string input_engine_) : InputEngine(std::move(input_engine_)) {}
+
+VirtualAmiibo::~VirtualAmiibo() = default;
+
+Common::Input::PollingError VirtualAmiibo::SetPollingMode(
+ [[maybe_unused]] const PadIdentifier& identifier_,
+ const Common::Input::PollingMode polling_mode_) {
+ polling_mode = polling_mode_;
+
+ if (polling_mode == Common::Input::PollingMode::NFC) {
+ if (state == State::Initialized) {
+ state = State::WaitingForAmiibo;
+ }
+ } else {
+ if (state == State::AmiiboIsOpen) {
+ CloseAmiibo();
+ }
+ }
+
+ return Common::Input::PollingError::None;
+}
+
+Common::Input::NfcState VirtualAmiibo::SupportsNfc(
+ [[maybe_unused]] const PadIdentifier& identifier_) const {
+ return Common::Input::NfcState::Success;
+}
+
+Common::Input::NfcState VirtualAmiibo::WriteNfcData(
+ [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) {
+ const Common::FS::IOFile amiibo_file{file_path, Common::FS::FileAccessMode::ReadWrite,
+ Common::FS::FileType::BinaryFile};
+
+ if (!amiibo_file.IsOpen()) {
+ LOG_ERROR(Core, "Amiibo is already on use");
+ return Common::Input::NfcState::WriteFailed;
+ }
+
+ if (!amiibo_file.Write(data)) {
+ LOG_ERROR(Service_NFP, "Error writting to file");
+ return Common::Input::NfcState::WriteFailed;
+ }
+
+ return Common::Input::NfcState::Success;
+}
+
+VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const {
+ return state;
+}
+
+VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) {
+ const Common::FS::IOFile amiibo_file{filename, Common::FS::FileAccessMode::Read,
+ Common::FS::FileType::BinaryFile};
+
+ if (state != State::WaitingForAmiibo) {
+ return Info::WrongDeviceState;
+ }
+
+ if (!amiibo_file.IsOpen()) {
+ return Info::UnableToLoad;
+ }
+
+ amiibo_data.resize(amiibo_size);
+
+ if (amiibo_file.Read(amiibo_data) < amiibo_size_without_password) {
+ return Info::NotAnAmiibo;
+ }
+
+ file_path = filename;
+ state = State::AmiiboIsOpen;
+ SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data});
+ return Info::Success;
+}
+
+VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() {
+ state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo
+ : State::Initialized;
+ SetNfc(identifier, {Common::Input::NfcState::AmiiboRemoved, {}});
+ return Info::Success;
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <array>
+#include <string>
+#include <vector>
+
+#include "common/common_types.h"
+#include "input_common/input_engine.h"
+
+namespace Common::FS {
+class IOFile;
+}
+
+namespace InputCommon {
+
+class VirtualAmiibo final : public InputEngine {
+public:
+ enum class State {
+ Initialized,
+ WaitingForAmiibo,
+ AmiiboIsOpen,
+ };
+
+ enum class Info {
+ Success,
+ UnableToLoad,
+ NotAnAmiibo,
+ WrongDeviceState,
+ Unknown,
+ };
+
+ explicit VirtualAmiibo(std::string input_engine_);
+ ~VirtualAmiibo() override;
+
+ // Sets polling mode to a controller
+ Common::Input::PollingError SetPollingMode(
+ const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override;
+
+ Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override;
+
+ Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_,
+ const std::vector<u8>& data) override;
+
+ State GetCurrentState() const;
+
+ Info LoadAmiibo(const std::string& amiibo_file);
+ Info CloseAmiibo();
+
+private:
+ static constexpr std::size_t amiibo_size = 0x21C;
+ static constexpr std::size_t amiibo_size_without_password = amiibo_size - 0x8;
+
+ std::string file_path{};
+ State state{State::Initialized};
+ std::vector<u8> amiibo_data;
+ Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Pasive};
+};
+} // 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,
TriggerOnCameraChange(identifier, value);
}
+void InputEngine::SetNfc(const PadIdentifier& identifier, const Common::Input::NfcStatus& value) {
+ {
+ std::scoped_lock lock{mutex};
+ ControllerData& controller = controller_list.at(identifier);
+ if (!configuring) {
+ controller.nfc = value;
+ }
+ }
+ TriggerOnNfcChange(identifier, value);
+}
+
bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const {
std::scoped_lock lock{mutex};
const auto controller_iter = controller_list.find(identifier);
@@ -189,6 +200,18 @@ Common::Input::CameraStatus InputEngine::GetCamera(const PadIdentifier& identifi
return controller.camera;
}
+Common::Input::NfcStatus InputEngine::GetNfc(const PadIdentifier& identifier) const {
+ std::scoped_lock lock{mutex};
+ const auto controller_iter = controller_list.find(identifier);
+ if (controller_iter == controller_list.cend()) {
+ LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(),
+ identifier.pad, identifier.port);
+ return {};
+ }
+ const ControllerData& controller = controller_iter->second;
+ return controller.nfc;
+}
+
void InputEngine::ResetButtonState() {
for (const auto& controller : controller_list) {
for (const auto& button : controller.second.buttons) {
@@ -355,6 +378,20 @@ void InputEngine::TriggerOnCameraChange(const PadIdentifier& identifier,
}
}
+void InputEngine::TriggerOnNfcChange(const PadIdentifier& identifier,
+ [[maybe_unused]] const Common::Input::NfcStatus& value) {
+ std::scoped_lock lock{mutex_callback};
+ for (const auto& poller_pair : callback_list) {
+ const InputIdentifier& poller = poller_pair.second;
+ if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Nfc, 0)) {
+ continue;
+ }
+ if (poller.callback.on_change) {
+ poller.callback.on_change();
+ }
+ }
+}
+
bool InputEngine::IsInputIdentifierEqual(const InputIdentifier& input_identifier,
const PadIdentifier& identifier, EngineInputType type,
int index) const {
diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h
index f6b3c4610..cfbdb26bd 100644
--- a/src/input_common/input_engine.h
+++ b/src/input_common/input_engine.h
@@ -42,6 +42,7 @@ enum class EngineInputType {
Camera,
HatButton,
Motion,
+ Nfc,
};
namespace std {
@@ -127,6 +128,18 @@ public:
return Common::Input::CameraError::NotSupported;
}
+ // Request nfc data from a controller
+ virtual Common::Input::NfcState SupportsNfc(
+ [[maybe_unused]] const PadIdentifier& identifier) const {
+ return Common::Input::NfcState::NotSupported;
+ }
+
+ // Writes data to an nfc tag
+ virtual Common::Input::NfcState WriteNfcData([[maybe_unused]] const PadIdentifier& identifier,
+ [[maybe_unused]] const std::vector<u8>& data) {
+ return Common::Input::NfcState::NotSupported;
+ }
+
// Returns the engine name
[[nodiscard]] const std::string& GetEngineName() const;
@@ -183,6 +196,7 @@ public:
Common::Input::BatteryLevel GetBattery(const PadIdentifier& identifier) const;
BasicMotion GetMotion(const PadIdentifier& identifier, int motion) const;
Common::Input::CameraStatus GetCamera(const PadIdentifier& identifier) const;
+ Common::Input::NfcStatus GetNfc(const PadIdentifier& identifier) const;
int SetCallback(InputIdentifier input_identifier);
void SetMappingCallback(MappingCallback callback);
@@ -195,6 +209,7 @@ protected:
void SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value);
void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value);
void SetCamera(const PadIdentifier& identifier, const Common::Input::CameraStatus& value);
+ void SetNfc(const PadIdentifier& identifier, const Common::Input::NfcStatus& value);
virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const {
return "Unknown";
@@ -208,6 +223,7 @@ private:
std::unordered_map<int, BasicMotion> motions;
Common::Input::BatteryLevel battery{};
Common::Input::CameraStatus camera{};
+ Common::Input::NfcStatus nfc{};
};
void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value);
@@ -218,6 +234,7 @@ private:
const BasicMotion& value);
void TriggerOnCameraChange(const PadIdentifier& identifier,
const Common::Input::CameraStatus& value);
+ void TriggerOnNfcChange(const PadIdentifier& identifier, const Common::Input::NfcStatus& value);
bool IsInputIdentifierEqual(const InputIdentifier& input_identifier,
const PadIdentifier& identifier, EngineInputType type,
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp
index ffb9b945e..75705b67e 100644
--- a/src/input_common/input_poller.cpp
+++ b/src/input_common/input_poller.cpp
@@ -705,6 +705,47 @@ private:
InputEngine* input_engine;
};
+class InputFromNfc final : public Common::Input::InputDevice {
+public:
+ explicit InputFromNfc(PadIdentifier identifier_, InputEngine* input_engine_)
+ : identifier(identifier_), input_engine(input_engine_) {
+ UpdateCallback engine_callback{[this]() { OnChange(); }};
+ const InputIdentifier input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Nfc,
+ .index = 0,
+ .callback = engine_callback,
+ };
+ callback_key = input_engine->SetCallback(input_identifier);
+ }
+
+ ~InputFromNfc() override {
+ input_engine->DeleteCallback(callback_key);
+ }
+
+ Common::Input::NfcStatus GetStatus() const {
+ return input_engine->GetNfc(identifier);
+ }
+
+ void ForceUpdate() override {
+ OnChange();
+ }
+
+ void OnChange() {
+ const Common::Input::CallbackStatus status{
+ .type = Common::Input::InputType::Nfc,
+ .nfc_status = GetStatus(),
+ };
+
+ TriggerOnChange(status);
+ }
+
+private:
+ const PadIdentifier identifier;
+ int callback_key;
+ InputEngine* input_engine;
+};
+
class OutputFromIdentifier final : public Common::Input::OutputDevice {
public:
explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_)
@@ -727,6 +768,14 @@ public:
return input_engine->SetCameraFormat(identifier, camera_format);
}
+ Common::Input::NfcState SupportsNfc() const override {
+ return input_engine->SupportsNfc(identifier);
+ }
+
+ Common::Input::NfcState WriteNfcData(const std::vector<u8>& data) override {
+ return input_engine->WriteNfcData(identifier, data);
+ }
+
private:
const PadIdentifier identifier;
InputEngine* input_engine;
@@ -978,6 +1027,18 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateCameraDevice(
return std::make_unique<InputFromCamera>(identifier, input_engine.get());
}
+std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateNfcDevice(
+ const Common::ParamPackage& params) {
+ const PadIdentifier identifier = {
+ .guid = Common::UUID{params.Get("guid", "")},
+ .port = static_cast<std::size_t>(params.Get("port", 0)),
+ .pad = static_cast<std::size_t>(params.Get("pad", 0)),
+ };
+
+ input_engine->PreSetController(identifier);
+ return std::make_unique<InputFromNfc>(identifier, input_engine.get());
+}
+
InputFactory::InputFactory(std::shared_ptr<InputEngine> input_engine_)
: input_engine(std::move(input_engine_)) {}
@@ -989,6 +1050,9 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::Create(
if (params.Has("camera")) {
return CreateCameraDevice(params);
}
+ if (params.Has("nfc")) {
+ return CreateNfcDevice(params);
+ }
if (params.Has("button") && params.Has("axis")) {
return CreateTriggerDevice(params);
}
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:
std::unique_ptr<Common::Input::InputDevice> CreateCameraDevice(
const Common::ParamPackage& params);
+ /**
+ * Creates a nfc device from the parameters given.
+ * @param params contains parameters for creating the device:
+ * - "guid": text string for identifying controllers
+ * - "port": port of the connected device
+ * - "pad": slot of the connected controller
+ * @returns a unique input device with the parameters specified
+ */
+ std::unique_ptr<Common::Input::InputDevice> CreateNfcDevice(const Common::ParamPackage& params);
+
std::shared_ptr<InputEngine> input_engine;
};
} // 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 @@
#include "input_common/drivers/tas_input.h"
#include "input_common/drivers/touch_screen.h"
#include "input_common/drivers/udp_client.h"
+#include "input_common/drivers/virtual_amiibo.h"
#include "input_common/helpers/stick_from_buttons.h"
#include "input_common/helpers/touch_from_buttons.h"
#include "input_common/input_engine.h"
@@ -87,6 +88,15 @@ struct InputSubsystem::Impl {
Common::Input::RegisterFactory<Common::Input::OutputDevice>(camera->GetEngineName(),
camera_output_factory);
+ virtual_amiibo = std::make_shared<VirtualAmiibo>("virtual_amiibo");
+ virtual_amiibo->SetMappingCallback(mapping_callback);
+ virtual_amiibo_input_factory = std::make_shared<InputFactory>(virtual_amiibo);
+ virtual_amiibo_output_factory = std::make_shared<OutputFactory>(virtual_amiibo);
+ Common::Input::RegisterFactory<Common::Input::InputDevice>(virtual_amiibo->GetEngineName(),
+ virtual_amiibo_input_factory);
+ Common::Input::RegisterFactory<Common::Input::OutputDevice>(virtual_amiibo->GetEngineName(),
+ virtual_amiibo_output_factory);
+
#ifdef HAVE_SDL2
sdl = std::make_shared<SDLDriver>("sdl");
sdl->SetMappingCallback(mapping_callback);
@@ -327,6 +337,7 @@ struct InputSubsystem::Impl {
std::shared_ptr<TasInput::Tas> tas_input;
std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
std::shared_ptr<Camera> camera;
+ std::shared_ptr<VirtualAmiibo> virtual_amiibo;
std::shared_ptr<InputFactory> keyboard_factory;
std::shared_ptr<InputFactory> mouse_factory;
@@ -335,6 +346,7 @@ struct InputSubsystem::Impl {
std::shared_ptr<InputFactory> udp_client_input_factory;
std::shared_ptr<InputFactory> tas_input_factory;
std::shared_ptr<InputFactory> camera_input_factory;
+ std::shared_ptr<InputFactory> virtual_amiibo_input_factory;
std::shared_ptr<OutputFactory> keyboard_output_factory;
std::shared_ptr<OutputFactory> mouse_output_factory;
@@ -342,6 +354,7 @@ struct InputSubsystem::Impl {
std::shared_ptr<OutputFactory> udp_client_output_factory;
std::shared_ptr<OutputFactory> tas_output_factory;
std::shared_ptr<OutputFactory> camera_output_factory;
+ std::shared_ptr<OutputFactory> virtual_amiibo_output_factory;
#ifdef HAVE_SDL2
std::shared_ptr<SDLDriver> sdl;
@@ -402,6 +415,14 @@ const Camera* InputSubsystem::GetCamera() const {
return impl->camera.get();
}
+VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() {
+ return impl->virtual_amiibo.get();
+}
+
+const VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() const {
+ return impl->virtual_amiibo.get();
+}
+
std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const {
return impl->GetInputDevices();
}
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;
class Keyboard;
class Mouse;
class TouchScreen;
+class VirtualAmiibo;
struct MappingData;
} // namespace InputCommon
@@ -101,6 +102,12 @@ public:
/// Retrieves the underlying camera input device.
[[nodiscard]] const Camera* GetCamera() const;
+ /// Retrieves the underlying virtual amiibo input device.
+ [[nodiscard]] VirtualAmiibo* GetVirtualAmiibo();
+
+ /// Retrieves the underlying virtual amiibo input device.
+ [[nodiscard]] const VirtualAmiibo* GetVirtualAmiibo() const;
+
/**
* Returns all available input devices that this Factory can create a new device with.
* Each returned ParamPackage should have a `display` field used for display, a `engine` field