From 243404bf34b1470369e1d0f5f2dd18ac02435273 Mon Sep 17 00:00:00 2001 From: german77 Date: Fri, 16 Dec 2022 16:16:54 -0600 Subject: input_common: Add virtual gamepad --- src/input_common/CMakeLists.txt | 2 + src/input_common/drivers/virtual_gamepad.cpp | 78 ++++++++++++++++++++++++++++ src/input_common/drivers/virtual_gamepad.h | 73 ++++++++++++++++++++++++++ src/input_common/main.cpp | 23 ++++++++ src/input_common/main.h | 7 +++ 5 files changed, 183 insertions(+) create mode 100644 src/input_common/drivers/virtual_gamepad.cpp create mode 100644 src/input_common/drivers/virtual_gamepad.h (limited to 'src/input_common') diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 7932aaab0..f24c89b04 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -20,6 +20,8 @@ add_library(input_common STATIC drivers/udp_client.h drivers/virtual_amiibo.cpp drivers/virtual_amiibo.h + drivers/virtual_gamepad.cpp + drivers/virtual_gamepad.h helpers/stick_from_buttons.cpp helpers/stick_from_buttons.h helpers/touch_from_buttons.cpp diff --git a/src/input_common/drivers/virtual_gamepad.cpp b/src/input_common/drivers/virtual_gamepad.cpp new file mode 100644 index 000000000..7db945aa6 --- /dev/null +++ b/src/input_common/drivers/virtual_gamepad.cpp @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "input_common/drivers/virtual_gamepad.h" + +namespace InputCommon { +constexpr std::size_t PlayerIndexCount = 10; + +VirtualGamepad::VirtualGamepad(std::string input_engine_) : InputEngine(std::move(input_engine_)) { + for (std::size_t i = 0; i < PlayerIndexCount; i++) { + PreSetController(GetIdentifier(i)); + } +} + +void VirtualGamepad::SetButtonState(std::size_t player_index, int button_id, bool value) { + if (player_index > PlayerIndexCount) { + return; + } + const auto identifier = GetIdentifier(player_index); + SetButton(identifier, button_id, value); +} + +void VirtualGamepad::SetButtonState(std::size_t player_index, VirtualButton button_id, bool value) { + SetButtonState(player_index, static_cast(button_id), value); +} + +void VirtualGamepad::SetStickPosition(std::size_t player_index, int axis_id, float x_value, + float y_value) { + if (player_index > PlayerIndexCount) { + return; + } + const auto identifier = GetIdentifier(player_index); + SetAxis(identifier, axis_id * 2, x_value); + SetAxis(identifier, (axis_id * 2) + 1, y_value); +} + +void VirtualGamepad::SetStickPosition(std::size_t player_index, VirtualStick axis_id, float x_value, + float y_value) { + SetStickPosition(player_index, static_cast(axis_id), x_value, y_value); +} + +void VirtualGamepad::ResetControllers() { + for (std::size_t i = 0; i < PlayerIndexCount; i++) { + SetStickPosition(i, VirtualStick::Left, 0.0f, 0.0f); + SetStickPosition(i, VirtualStick::Right, 0.0f, 0.0f); + + SetButtonState(i, VirtualButton::ButtonA, false); + SetButtonState(i, VirtualButton::ButtonB, false); + SetButtonState(i, VirtualButton::ButtonX, false); + SetButtonState(i, VirtualButton::ButtonY, false); + SetButtonState(i, VirtualButton::StickL, false); + SetButtonState(i, VirtualButton::StickR, false); + SetButtonState(i, VirtualButton::TriggerL, false); + SetButtonState(i, VirtualButton::TriggerR, false); + SetButtonState(i, VirtualButton::TriggerZL, false); + SetButtonState(i, VirtualButton::TriggerZR, false); + SetButtonState(i, VirtualButton::ButtonPlus, false); + SetButtonState(i, VirtualButton::ButtonMinus, false); + SetButtonState(i, VirtualButton::ButtonLeft, false); + SetButtonState(i, VirtualButton::ButtonUp, false); + SetButtonState(i, VirtualButton::ButtonRight, false); + SetButtonState(i, VirtualButton::ButtonDown, false); + SetButtonState(i, VirtualButton::ButtonSL, false); + SetButtonState(i, VirtualButton::ButtonSR, false); + SetButtonState(i, VirtualButton::ButtonHome, false); + SetButtonState(i, VirtualButton::ButtonCapture, false); + } +} + +PadIdentifier VirtualGamepad::GetIdentifier(std::size_t player_index) const { + return { + .guid = Common::UUID{}, + .port = player_index, + .pad = 0, + }; +} + +} // namespace InputCommon diff --git a/src/input_common/drivers/virtual_gamepad.h b/src/input_common/drivers/virtual_gamepad.h new file mode 100644 index 000000000..3df91cc6f --- /dev/null +++ b/src/input_common/drivers/virtual_gamepad.h @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "input_common/input_engine.h" + +namespace InputCommon { + +/** + * A virtual controller that is always assigned to the game input + */ +class VirtualGamepad final : public InputEngine { +public: + enum class VirtualButton { + ButtonA, + ButtonB, + ButtonX, + ButtonY, + StickL, + StickR, + TriggerL, + TriggerR, + TriggerZL, + TriggerZR, + ButtonPlus, + ButtonMinus, + ButtonLeft, + ButtonUp, + ButtonRight, + ButtonDown, + ButtonSL, + ButtonSR, + ButtonHome, + ButtonCapture, + }; + + enum class VirtualStick { + Left = 0, + Right = 1, + }; + + explicit VirtualGamepad(std::string input_engine_); + + /** + * Sets the status of all buttons bound with the key to pressed + * @param player_index the player number that will take this action + * @param button_id the id of the button + * @param value indicates if the button is pressed or not + */ + void SetButtonState(std::size_t player_index, int button_id, bool value); + void SetButtonState(std::size_t player_index, VirtualButton button_id, bool value); + + /** + * Sets the status of all buttons bound with the key to released + * @param player_index the player number that will take this action + * @param axis_id the id of the axis to move + * @param x_value the position of the stick in the x axis + * @param y_value the position of the stick in the y axis + */ + void SetStickPosition(std::size_t player_index, int axis_id, float x_value, float y_value); + void SetStickPosition(std::size_t player_index, VirtualStick axis_id, float x_value, + float y_value); + + /// Restores all inputs into the neutral position + void ResetControllers(); + +private: + /// Returns the correct identifier corresponding to the player index + PadIdentifier GetIdentifier(std::size_t player_index) const; +}; + +} // namespace InputCommon diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 942a13535..75b856c95 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -12,6 +12,7 @@ #include "input_common/drivers/touch_screen.h" #include "input_common/drivers/udp_client.h" #include "input_common/drivers/virtual_amiibo.h" +#include "input_common/drivers/virtual_gamepad.h" #include "input_common/helpers/stick_from_buttons.h" #include "input_common/helpers/touch_from_buttons.h" #include "input_common/input_engine.h" @@ -85,6 +86,12 @@ struct InputSubsystem::Impl { Common::Input::RegisterOutputFactory(virtual_amiibo->GetEngineName(), virtual_amiibo_output_factory); + virtual_gamepad = std::make_shared("virtual_gamepad"); + virtual_gamepad->SetMappingCallback(mapping_callback); + virtual_gamepad_input_factory = std::make_shared(virtual_gamepad); + Common::Input::RegisterInputFactory(virtual_gamepad->GetEngineName(), + virtual_gamepad_input_factory); + #ifdef HAVE_SDL2 sdl = std::make_shared("sdl"); sdl->SetMappingCallback(mapping_callback); @@ -132,6 +139,9 @@ struct InputSubsystem::Impl { Common::Input::UnregisterOutputFactory(virtual_amiibo->GetEngineName()); virtual_amiibo.reset(); + Common::Input::UnregisterInputFactory(virtual_gamepad->GetEngineName()); + virtual_gamepad.reset(); + #ifdef HAVE_SDL2 Common::Input::UnregisterInputFactory(sdl->GetEngineName()); Common::Input::UnregisterOutputFactory(sdl->GetEngineName()); @@ -290,6 +300,9 @@ struct InputSubsystem::Impl { if (engine == tas_input->GetEngineName()) { return true; } + if (engine == virtual_gamepad->GetEngineName()) { + return true; + } #ifdef HAVE_SDL2 if (engine == sdl->GetEngineName()) { return true; @@ -338,6 +351,7 @@ struct InputSubsystem::Impl { std::shared_ptr udp_client; std::shared_ptr camera; std::shared_ptr virtual_amiibo; + std::shared_ptr virtual_gamepad; std::shared_ptr keyboard_factory; std::shared_ptr mouse_factory; @@ -347,6 +361,7 @@ struct InputSubsystem::Impl { std::shared_ptr tas_input_factory; std::shared_ptr camera_input_factory; std::shared_ptr virtual_amiibo_input_factory; + std::shared_ptr virtual_gamepad_input_factory; std::shared_ptr keyboard_output_factory; std::shared_ptr mouse_output_factory; @@ -423,6 +438,14 @@ const VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() const { return impl->virtual_amiibo.get(); } +VirtualGamepad* InputSubsystem::GetVirtualGamepad() { + return impl->virtual_gamepad.get(); +} + +const VirtualGamepad* InputSubsystem::GetVirtualGamepad() const { + return impl->virtual_gamepad.get(); +} + std::vector InputSubsystem::GetInputDevices() const { return impl->GetInputDevices(); } diff --git a/src/input_common/main.h b/src/input_common/main.h index 6218c37f6..1207d786c 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -34,6 +34,7 @@ class Keyboard; class Mouse; class TouchScreen; class VirtualAmiibo; +class VirtualGamepad; struct MappingData; } // namespace InputCommon @@ -108,6 +109,12 @@ public: /// Retrieves the underlying virtual amiibo input device. [[nodiscard]] const VirtualAmiibo* GetVirtualAmiibo() const; + /// Retrieves the underlying virtual gamepad input device. + [[nodiscard]] VirtualGamepad* GetVirtualGamepad(); + + /// Retrieves the underlying virtual gamepad input device. + [[nodiscard]] const VirtualGamepad* GetVirtualGamepad() 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 -- cgit v1.2.3