summaryrefslogtreecommitdiff
path: root/src/yuzu/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu/util')
-rw-r--r--src/yuzu/util/controller_navigation.cpp177
-rw-r--r--src/yuzu/util/controller_navigation.h51
-rw-r--r--src/yuzu/util/overlay_dialog.cpp27
-rw-r--r--src/yuzu/util/overlay_dialog.h10
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();