diff options
Diffstat (limited to 'src/yuzu/util')
-rw-r--r-- | src/yuzu/util/controller_navigation.cpp | 177 | ||||
-rw-r--r-- | src/yuzu/util/controller_navigation.h | 51 | ||||
-rw-r--r-- | src/yuzu/util/overlay_dialog.cpp | 27 | ||||
-rw-r--r-- | src/yuzu/util/overlay_dialog.h | 10 |
4 files changed, 249 insertions, 16 deletions
diff --git a/src/yuzu/util/controller_navigation.cpp b/src/yuzu/util/controller_navigation.cpp new file mode 100644 index 000000000..86fb28b9f --- /dev/null +++ b/src/yuzu/util/controller_navigation.cpp @@ -0,0 +1,177 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include "common/settings_input.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" +#include "yuzu/util/controller_navigation.h" + +ControllerNavigation::ControllerNavigation(Core::HID::HIDCore& hid_core, QWidget* parent) { + player1_controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); + handheld_controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); + Core::HID::ControllerUpdateCallback engine_callback{ + .on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdateEvent(type); }, + .is_npad_service = false, + }; + player1_callback_key = player1_controller->SetCallback(engine_callback); + handheld_callback_key = handheld_controller->SetCallback(engine_callback); + is_controller_set = true; +} + +ControllerNavigation::~ControllerNavigation() { + UnloadController(); +} + +void ControllerNavigation::UnloadController() { + if (is_controller_set) { + player1_controller->DeleteCallback(player1_callback_key); + handheld_controller->DeleteCallback(handheld_callback_key); + is_controller_set = false; + } +} + +void ControllerNavigation::TriggerButton(Settings::NativeButton::Values native_button, + Qt::Key key) { + if (button_values[native_button].value && !button_values[native_button].locked) { + emit TriggerKeyboardEvent(key); + } +} + +void ControllerNavigation::ControllerUpdateEvent(Core::HID::ControllerTriggerType type) { + std::lock_guard lock{mutex}; + if (type == Core::HID::ControllerTriggerType::Button) { + ControllerUpdateButton(); + return; + } + + if (type == Core::HID::ControllerTriggerType::Stick) { + ControllerUpdateStick(); + return; + } +} + +void ControllerNavigation::ControllerUpdateButton() { + const auto controller_type = player1_controller->GetNpadStyleIndex(); + const auto& player1_buttons = player1_controller->GetButtonsValues(); + const auto& handheld_buttons = handheld_controller->GetButtonsValues(); + + for (std::size_t i = 0; i < player1_buttons.size(); ++i) { + const bool button = player1_buttons[i].value || handheld_buttons[i].value; + // Trigger only once + button_values[i].locked = button == button_values[i].value; + button_values[i].value = button; + } + + switch (controller_type) { + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::JoyconDual: + case Core::HID::NpadStyleIndex::Handheld: + case Core::HID::NpadStyleIndex::GameCube: + TriggerButton(Settings::NativeButton::A, Qt::Key_Enter); + TriggerButton(Settings::NativeButton::B, Qt::Key_Escape); + TriggerButton(Settings::NativeButton::DDown, Qt::Key_Down); + TriggerButton(Settings::NativeButton::DLeft, Qt::Key_Left); + TriggerButton(Settings::NativeButton::DRight, Qt::Key_Right); + TriggerButton(Settings::NativeButton::DUp, Qt::Key_Up); + break; + case Core::HID::NpadStyleIndex::JoyconLeft: + TriggerButton(Settings::NativeButton::DDown, Qt::Key_Enter); + TriggerButton(Settings::NativeButton::DLeft, Qt::Key_Escape); + break; + case Core::HID::NpadStyleIndex::JoyconRight: + TriggerButton(Settings::NativeButton::X, Qt::Key_Enter); + TriggerButton(Settings::NativeButton::A, Qt::Key_Escape); + break; + default: + break; + } +} + +void ControllerNavigation::ControllerUpdateStick() { + const auto controller_type = player1_controller->GetNpadStyleIndex(); + const auto& player1_sticks = player1_controller->GetSticksValues(); + const auto& handheld_sticks = player1_controller->GetSticksValues(); + bool update = false; + + for (std::size_t i = 0; i < player1_sticks.size(); ++i) { + const Common::Input::StickStatus stick{ + .left = player1_sticks[i].left || handheld_sticks[i].left, + .right = player1_sticks[i].right || handheld_sticks[i].right, + .up = player1_sticks[i].up || handheld_sticks[i].up, + .down = player1_sticks[i].down || handheld_sticks[i].down, + }; + // Trigger only once + if (stick.down != stick_values[i].down || stick.left != stick_values[i].left || + stick.right != stick_values[i].right || stick.up != stick_values[i].up) { + update = true; + } + stick_values[i] = stick; + } + + if (!update) { + return; + } + + switch (controller_type) { + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::JoyconDual: + case Core::HID::NpadStyleIndex::Handheld: + case Core::HID::NpadStyleIndex::GameCube: + if (stick_values[Settings::NativeAnalog::LStick].down) { + emit TriggerKeyboardEvent(Qt::Key_Down); + return; + } + if (stick_values[Settings::NativeAnalog::LStick].left) { + emit TriggerKeyboardEvent(Qt::Key_Left); + return; + } + if (stick_values[Settings::NativeAnalog::LStick].right) { + emit TriggerKeyboardEvent(Qt::Key_Right); + return; + } + if (stick_values[Settings::NativeAnalog::LStick].up) { + emit TriggerKeyboardEvent(Qt::Key_Up); + return; + } + break; + case Core::HID::NpadStyleIndex::JoyconLeft: + if (stick_values[Settings::NativeAnalog::LStick].left) { + emit TriggerKeyboardEvent(Qt::Key_Down); + return; + } + if (stick_values[Settings::NativeAnalog::LStick].up) { + emit TriggerKeyboardEvent(Qt::Key_Left); + return; + } + if (stick_values[Settings::NativeAnalog::LStick].down) { + emit TriggerKeyboardEvent(Qt::Key_Right); + return; + } + if (stick_values[Settings::NativeAnalog::LStick].right) { + emit TriggerKeyboardEvent(Qt::Key_Up); + return; + } + break; + case Core::HID::NpadStyleIndex::JoyconRight: + if (stick_values[Settings::NativeAnalog::RStick].right) { + emit TriggerKeyboardEvent(Qt::Key_Down); + return; + } + if (stick_values[Settings::NativeAnalog::RStick].down) { + emit TriggerKeyboardEvent(Qt::Key_Left); + return; + } + if (stick_values[Settings::NativeAnalog::RStick].up) { + emit TriggerKeyboardEvent(Qt::Key_Right); + return; + } + if (stick_values[Settings::NativeAnalog::RStick].left) { + emit TriggerKeyboardEvent(Qt::Key_Up); + return; + } + break; + default: + break; + } +} diff --git a/src/yuzu/util/controller_navigation.h b/src/yuzu/util/controller_navigation.h new file mode 100644 index 000000000..7c616a088 --- /dev/null +++ b/src/yuzu/util/controller_navigation.h @@ -0,0 +1,51 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +#include <QKeyEvent> +#include <QObject> + +#include "common/input.h" +#include "common/settings_input.h" + +namespace Core::HID { +using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>; +using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>; +enum class ControllerTriggerType; +class EmulatedController; +class HIDCore; +} // namespace Core::HID + +class ControllerNavigation : public QObject { + Q_OBJECT + +public: + explicit ControllerNavigation(Core::HID::HIDCore& hid_core, QWidget* parent = nullptr); + ~ControllerNavigation(); + + /// Disables events from the emulated controller + void UnloadController(); + +signals: + void TriggerKeyboardEvent(Qt::Key key); + +private: + void TriggerButton(Settings::NativeButton::Values native_button, Qt::Key key); + void ControllerUpdateEvent(Core::HID::ControllerTriggerType type); + + void ControllerUpdateButton(); + + void ControllerUpdateStick(); + + Core::HID::ButtonValues button_values{}; + Core::HID::SticksValues stick_values{}; + + int player1_callback_key{}; + int handheld_callback_key{}; + bool is_controller_set{}; + mutable std::mutex mutex; + Core::HID::EmulatedController* player1_controller; + Core::HID::EmulatedController* handheld_controller; +}; diff --git a/src/yuzu/util/overlay_dialog.cpp b/src/yuzu/util/overlay_dialog.cpp index 95b148545..c66dfbdff 100644 --- a/src/yuzu/util/overlay_dialog.cpp +++ b/src/yuzu/util/overlay_dialog.cpp @@ -6,7 +6,8 @@ #include <QScreen> #include "core/core.h" -#include "core/frontend/input_interpreter.h" +#include "core/hid/hid_types.h" +#include "core/hid/input_interpreter.h" #include "ui_overlay_dialog.h" #include "yuzu/util/overlay_dialog.h" @@ -179,9 +180,9 @@ void OverlayDialog::MoveAndResizeWindow() { QDialog::resize(width, height); } -template <HIDButton... T> +template <Core::HID::NpadButton... T> void OverlayDialog::HandleButtonPressedOnce() { - const auto f = [this](HIDButton button) { + const auto f = [this](Core::HID::NpadButton button) { if (input_interpreter->IsButtonPressedOnce(button)) { TranslateButtonPress(button); } @@ -190,7 +191,7 @@ void OverlayDialog::HandleButtonPressedOnce() { (f(T), ...); } -void OverlayDialog::TranslateButtonPress(HIDButton button) { +void OverlayDialog::TranslateButtonPress(Core::HID::NpadButton button) { QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel; QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok_label; @@ -198,20 +199,20 @@ void OverlayDialog::TranslateButtonPress(HIDButton button) { // TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it switch (button) { - case HIDButton::A: - case HIDButton::B: + case Core::HID::NpadButton::A: + case Core::HID::NpadButton::B: if (left_button->hasFocus()) { left_button->click(); } else if (right_button->hasFocus()) { right_button->click(); } break; - case HIDButton::DLeft: - case HIDButton::LStickLeft: + case Core::HID::NpadButton::Left: + case Core::HID::NpadButton::StickLLeft: focusPreviousChild(); break; - case HIDButton::DRight: - case HIDButton::LStickRight: + case Core::HID::NpadButton::Right: + case Core::HID::NpadButton::StickLRight: focusNextChild(); break; default: @@ -241,8 +242,10 @@ void OverlayDialog::InputThread() { while (input_thread_running) { input_interpreter->PollInput(); - HandleButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::DLeft, HIDButton::DRight, - HIDButton::LStickLeft, HIDButton::LStickRight>(); + HandleButtonPressedOnce<Core::HID::NpadButton::A, Core::HID::NpadButton::B, + Core::HID::NpadButton::Left, Core::HID::NpadButton::Right, + Core::HID::NpadButton::StickLLeft, + Core::HID::NpadButton::StickLRight>(); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } diff --git a/src/yuzu/util/overlay_dialog.h b/src/yuzu/util/overlay_dialog.h index e8c388bd0..d8a140ff3 100644 --- a/src/yuzu/util/overlay_dialog.h +++ b/src/yuzu/util/overlay_dialog.h @@ -13,14 +13,16 @@ #include "common/common_types.h" -enum class HIDButton : u8; - class InputInterpreter; namespace Core { class System; } +namespace Core::HID { +enum class NpadButton : u64; +} + namespace Ui { class OverlayDialog; } @@ -79,7 +81,7 @@ private: * * @tparam HIDButton The list of buttons that can be converted into keyboard input. */ - template <HIDButton... T> + template <Core::HID::NpadButton... T> void HandleButtonPressedOnce(); /** @@ -87,7 +89,7 @@ private: * * @param button The button press to process. */ - void TranslateButtonPress(HIDButton button); + void TranslateButtonPress(Core::HID::NpadButton button); void StartInputThread(); void StopInputThread(); |