diff options
Diffstat (limited to 'src/input_common/drivers')
| -rw-r--r-- | src/input_common/drivers/camera.cpp | 82 | ||||
| -rw-r--r-- | src/input_common/drivers/camera.h | 29 | ||||
| -rw-r--r-- | src/input_common/drivers/gc_adapter.cpp | 25 | ||||
| -rw-r--r-- | src/input_common/drivers/gc_adapter.h | 8 | ||||
| -rw-r--r-- | src/input_common/drivers/keyboard.cpp | 5 | ||||
| -rw-r--r-- | src/input_common/drivers/keyboard.h | 5 | ||||
| -rw-r--r-- | src/input_common/drivers/mouse.cpp | 7 | ||||
| -rw-r--r-- | src/input_common/drivers/mouse.h | 5 | ||||
| -rw-r--r-- | src/input_common/drivers/sdl_driver.cpp | 167 | ||||
| -rw-r--r-- | src/input_common/drivers/sdl_driver.h | 35 | ||||
| -rw-r--r-- | src/input_common/drivers/tas_input.cpp | 5 | ||||
| -rw-r--r-- | src/input_common/drivers/tas_input.h | 5 | ||||
| -rw-r--r-- | src/input_common/drivers/touch_screen.cpp | 94 | ||||
| -rw-r--r-- | src/input_common/drivers/touch_screen.h | 57 | ||||
| -rw-r--r-- | src/input_common/drivers/udp_client.cpp | 35 | ||||
| -rw-r--r-- | src/input_common/drivers/udp_client.h | 9 | ||||
| -rw-r--r-- | src/input_common/drivers/virtual_amiibo.cpp | 101 | ||||
| -rw-r--r-- | src/input_common/drivers/virtual_amiibo.h | 61 |
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 | |||
| 9 | namespace InputCommon { | ||
| 10 | constexpr PadIdentifier identifier = { | ||
| 11 | .guid = Common::UUID{}, | ||
| 12 | .port = 0, | ||
| 13 | .pad = 0, | ||
| 14 | }; | ||
| 15 | |||
| 16 | Camera::Camera(std::string input_engine_) : InputEngine(std::move(input_engine_)) { | ||
| 17 | PreSetController(identifier); | ||
| 18 | } | ||
| 19 | |||
| 20 | void 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 | |||
| 39 | std::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 | |||
| 57 | std::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 | |||
| 75 | Common::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 | |||
| 8 | namespace 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 | */ | ||
| 14 | class Camera final : public InputEngine { | ||
| 15 | public: | ||
| 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 | ||
| 92 | void GCAdapter::AdapterInputThread(std::stop_token stop_token) { | 91 | void 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 | ||
| 217 | void GCAdapter::AdapterScanThread(std::stop_token stop_token) { | 216 | void 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 | ||
| 526 | bool 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 | |||
| 39 | private: | 39 | private: |
| 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 | ||
| 40 | void Mouse::UpdateThread(std::stop_token stop_token) { | 39 | void 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 @@ | |||
| 13 | namespace InputCommon { | 12 | namespace InputCommon { |
| 14 | 13 | ||
| 15 | namespace { | 14 | namespace { |
| 16 | std::string GetGUID(SDL_Joystick* joystick) { | 15 | Common::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 | ||
| 32 | class SDLJoystick { | 31 | class SDLJoystick { |
| 33 | public: | 32 | public: |
| 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 | ||
| 229 | private: | 229 | private: |
| 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 | ||
| 242 | std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) { | 242 | std::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 | ||
| 261 | std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) { | ||
| 262 | return GetSDLJoystickByGUID(Common::UUID{guid}, port); | ||
| 263 | } | ||
| 264 | |||
| 261 | std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { | 265 | std::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 | ||
| 325 | void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) { | 332 | void 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 | ||
| 391 | void SDLDriver::CloseJoysticks() { | 400 | void 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 | ||
| 538 | Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, | 564 | void 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 | |||
| 574 | Common::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 | ||
| 550 | Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, std::string guid, | 586 | Common::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 | ||
| 560 | Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, std::string guid, s32 hat, | 596 | Common::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 | ||
| 571 | Common::ParamPackage SDLDriver::BuildMotionParam(int port, std::string guid) const { | 607 | Common::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 | ||
| 580 | Common::ParamPackage SDLDriver::BuildParamPackageForBinding( | 616 | Common::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 | ||
| 970 | bool 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 | ||
| 17 | union SDL_Event; | 17 | union 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 | ||
| 64 | private: | 67 | private: |
| 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 | ||
| 16 | TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) { | 15 | TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) { |
| 17 | PreSetController(identifier); | 16 | PreSetController(identifier); |
| 17 | ReleaseAllTouch(); | ||
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | void TouchScreen::TouchMoved(float x, float y, std::size_t finger) { | 20 | void 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 | ||
| 27 | void TouchScreen::TouchPressed(float x, float y, std::size_t finger) { | 34 | void 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 | ||
| 36 | void TouchScreen::TouchReleased(std::size_t finger) { | 51 | void 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 | |||
| 63 | std::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 | |||
| 76 | std::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 | |||
| 85 | void TouchScreen::ClearActiveFlag() { | ||
| 86 | for (auto& finger : fingers) { | ||
| 87 | finger.is_active = false; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | void TouchScreen::ReleaseInactiveTouch() { | ||
| 92 | for (const auto& finger : fingers) { | ||
| 93 | if (!finger.is_active) { | ||
| 94 | TouchReleased(finger.finger_id); | ||
| 95 | } | ||
| 96 | } | ||
| 43 | } | 97 | } |
| 44 | 98 | ||
| 45 | void TouchScreen::ReleaseAllTouch() { | 99 | void 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 | ||
| 9 | namespace InputCommon { | 10 | namespace 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 | */ |
| 15 | class TouchScreen final : public InputEngine { | 16 | class TouchScreen final : public InputEngine { |
| 16 | public: | 17 | public: |
| 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 | |||
| 51 | private: | ||
| 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 | ||
| 195 | BatteryLevel UDPClient::GetBatteryLevel(Response::Battery battery) const { | 194 | Common::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 | ||
| 549 | bool 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 | |||
| 550 | void TestCommunication(const std::string& host, u16 port, | 565 | void 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 | |||
| 67 | private: | 68 | private: |
| 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 | |||
| 14 | namespace InputCommon { | ||
| 15 | constexpr PadIdentifier identifier = { | ||
| 16 | .guid = Common::UUID{}, | ||
| 17 | .port = 0, | ||
| 18 | .pad = 0, | ||
| 19 | }; | ||
| 20 | |||
| 21 | VirtualAmiibo::VirtualAmiibo(std::string input_engine_) : InputEngine(std::move(input_engine_)) {} | ||
| 22 | |||
| 23 | VirtualAmiibo::~VirtualAmiibo() = default; | ||
| 24 | |||
| 25 | Common::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 | |||
| 43 | Common::Input::NfcState VirtualAmiibo::SupportsNfc( | ||
| 44 | [[maybe_unused]] const PadIdentifier& identifier_) const { | ||
| 45 | return Common::Input::NfcState::Success; | ||
| 46 | } | ||
| 47 | |||
| 48 | Common::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 | |||
| 66 | VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const { | ||
| 67 | return state; | ||
| 68 | } | ||
| 69 | |||
| 70 | VirtualAmiibo::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 | |||
| 94 | VirtualAmiibo::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 | |||
| 13 | namespace Common::FS { | ||
| 14 | class IOFile; | ||
| 15 | } | ||
| 16 | |||
| 17 | namespace InputCommon { | ||
| 18 | |||
| 19 | class VirtualAmiibo final : public InputEngine { | ||
| 20 | public: | ||
| 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 | |||
| 52 | private: | ||
| 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 | ||