summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/yuzu/CMakeLists.txt2
-rw-r--r--src/yuzu/applets/qt_controller.h4
-rw-r--r--src/yuzu/applets/qt_profile_select.cpp17
-rw-r--r--src/yuzu/applets/qt_profile_select.h8
-rw-r--r--src/yuzu/game_list.cpp20
-rw-r--r--src/yuzu/game_list.h5
-rw-r--r--src/yuzu/main.cpp9
-rw-r--r--src/yuzu/util/controller_navigation.cpp177
-rw-r--r--src/yuzu/util/controller_navigation.h51
9 files changed, 285 insertions, 8 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index a44815e71..732e8c276 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -152,6 +152,8 @@ add_executable(yuzu
152 main.ui 152 main.ui
153 uisettings.cpp 153 uisettings.cpp
154 uisettings.h 154 uisettings.h
155 util/controller_navigation.cpp
156 util/controller_navigation.h
155 util/limitable_input_dialog.cpp 157 util/limitable_input_dialog.cpp
156 util/limitable_input_dialog.h 158 util/limitable_input_dialog.h
157 util/overlay_dialog.cpp 159 util/overlay_dialog.cpp
diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h
index cc343e5ae..7ab9ced3d 100644
--- a/src/yuzu/applets/qt_controller.h
+++ b/src/yuzu/applets/qt_controller.h
@@ -7,7 +7,6 @@
7#include <array> 7#include <array>
8#include <memory> 8#include <memory>
9#include <QDialog> 9#include <QDialog>
10#include "core/core.h"
11#include "core/frontend/applets/controller.h" 10#include "core/frontend/applets/controller.h"
12 11
13class GMainWindow; 12class GMainWindow;
@@ -32,8 +31,9 @@ class System;
32} 31}
33 32
34namespace Core::HID { 33namespace Core::HID {
34class HIDCore;
35enum class NpadStyleIndex : u8; 35enum class NpadStyleIndex : u8;
36} 36} // namespace Core::HID
37 37
38class QtControllerSelectorDialog final : public QDialog { 38class QtControllerSelectorDialog final : public QDialog {
39 Q_OBJECT 39 Q_OBJECT
diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp
index a56638e21..7b19f1f8d 100644
--- a/src/yuzu/applets/qt_profile_select.cpp
+++ b/src/yuzu/applets/qt_profile_select.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <mutex> 5#include <mutex>
6#include <QApplication>
6#include <QDialogButtonBox> 7#include <QDialogButtonBox>
7#include <QHeaderView> 8#include <QHeaderView>
8#include <QLabel> 9#include <QLabel>
@@ -16,6 +17,7 @@
16#include "core/hle/lock.h" 17#include "core/hle/lock.h"
17#include "yuzu/applets/qt_profile_select.h" 18#include "yuzu/applets/qt_profile_select.h"
18#include "yuzu/main.h" 19#include "yuzu/main.h"
20#include "yuzu/util/controller_navigation.h"
19 21
20namespace { 22namespace {
21QString FormatUserEntryText(const QString& username, Common::UUID uuid) { 23QString FormatUserEntryText(const QString& username, Common::UUID uuid) {
@@ -45,7 +47,7 @@ QPixmap GetIcon(Common::UUID uuid) {
45} 47}
46} // Anonymous namespace 48} // Anonymous namespace
47 49
48QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent) 50QtProfileSelectionDialog::QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent)
49 : QDialog(parent), profile_manager(std::make_unique<Service::Account::ProfileManager>()) { 51 : QDialog(parent), profile_manager(std::make_unique<Service::Account::ProfileManager>()) {
50 outer_layout = new QVBoxLayout; 52 outer_layout = new QVBoxLayout;
51 53
@@ -65,6 +67,7 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)
65 tree_view = new QTreeView; 67 tree_view = new QTreeView;
66 item_model = new QStandardItemModel(tree_view); 68 item_model = new QStandardItemModel(tree_view);
67 tree_view->setModel(item_model); 69 tree_view->setModel(item_model);
70 controller_navigation = new ControllerNavigation(hid_core, this);
68 71
69 tree_view->setAlternatingRowColors(true); 72 tree_view->setAlternatingRowColors(true);
70 tree_view->setSelectionMode(QHeaderView::SingleSelection); 73 tree_view->setSelectionMode(QHeaderView::SingleSelection);
@@ -91,6 +94,14 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)
91 scroll_area->setLayout(layout); 94 scroll_area->setLayout(layout);
92 95
93 connect(tree_view, &QTreeView::clicked, this, &QtProfileSelectionDialog::SelectUser); 96 connect(tree_view, &QTreeView::clicked, this, &QtProfileSelectionDialog::SelectUser);
97 connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
98 [this](Qt::Key key) {
99 if (!this->isActiveWindow()) {
100 return;
101 }
102 QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
103 QCoreApplication::postEvent(tree_view, event);
104 });
94 105
95 const auto& profiles = profile_manager->GetAllUsers(); 106 const auto& profiles = profile_manager->GetAllUsers();
96 for (const auto& user : profiles) { 107 for (const auto& user : profiles) {
@@ -113,7 +124,9 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)
113 resize(550, 400); 124 resize(550, 400);
114} 125}
115 126
116QtProfileSelectionDialog::~QtProfileSelectionDialog() = default; 127QtProfileSelectionDialog::~QtProfileSelectionDialog() {
128 controller_navigation->UnloadController();
129};
117 130
118int QtProfileSelectionDialog::exec() { 131int QtProfileSelectionDialog::exec() {
119 // Skip profile selection when there's only one. 132 // Skip profile selection when there's only one.
diff --git a/src/yuzu/applets/qt_profile_select.h b/src/yuzu/applets/qt_profile_select.h
index 4e9037488..56496ed31 100644
--- a/src/yuzu/applets/qt_profile_select.h
+++ b/src/yuzu/applets/qt_profile_select.h
@@ -11,6 +11,7 @@
11#include "core/frontend/applets/profile_select.h" 11#include "core/frontend/applets/profile_select.h"
12#include "core/hle/service/acc/profile_manager.h" 12#include "core/hle/service/acc/profile_manager.h"
13 13
14class ControllerNavigation;
14class GMainWindow; 15class GMainWindow;
15class QDialogButtonBox; 16class QDialogButtonBox;
16class QGraphicsScene; 17class QGraphicsScene;
@@ -20,11 +21,15 @@ class QStandardItem;
20class QStandardItemModel; 21class QStandardItemModel;
21class QVBoxLayout; 22class QVBoxLayout;
22 23
24namespace Core::HID {
25class HIDCore;
26} // namespace Core::HID
27
23class QtProfileSelectionDialog final : public QDialog { 28class QtProfileSelectionDialog final : public QDialog {
24 Q_OBJECT 29 Q_OBJECT
25 30
26public: 31public:
27 explicit QtProfileSelectionDialog(QWidget* parent); 32 explicit QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent);
28 ~QtProfileSelectionDialog() override; 33 ~QtProfileSelectionDialog() override;
29 34
30 int exec() override; 35 int exec() override;
@@ -51,6 +56,7 @@ private:
51 QDialogButtonBox* buttons; 56 QDialogButtonBox* buttons;
52 57
53 std::unique_ptr<Service::Account::ProfileManager> profile_manager; 58 std::unique_ptr<Service::Account::ProfileManager> profile_manager;
59 ControllerNavigation* controller_navigation = nullptr;
54}; 60};
55 61
56class QtProfileSelector final : public QObject, public Core::Frontend::ProfileSelectApplet { 62class QtProfileSelector final : public QObject, public Core::Frontend::ProfileSelectApplet {
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 2af95dbe5..1a5e41588 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -17,6 +17,7 @@
17#include <fmt/format.h> 17#include <fmt/format.h>
18#include "common/common_types.h" 18#include "common/common_types.h"
19#include "common/logging/log.h" 19#include "common/logging/log.h"
20#include "core/core.h"
20#include "core/file_sys/patch_manager.h" 21#include "core/file_sys/patch_manager.h"
21#include "core/file_sys/registered_cache.h" 22#include "core/file_sys/registered_cache.h"
22#include "yuzu/compatibility_list.h" 23#include "yuzu/compatibility_list.h"
@@ -25,6 +26,7 @@
25#include "yuzu/game_list_worker.h" 26#include "yuzu/game_list_worker.h"
26#include "yuzu/main.h" 27#include "yuzu/main.h"
27#include "yuzu/uisettings.h" 28#include "yuzu/uisettings.h"
29#include "yuzu/util/controller_navigation.h"
28 30
29GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist, QObject* parent) 31GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist, QObject* parent)
30 : QObject(parent), gamelist{gamelist} {} 32 : QObject(parent), gamelist{gamelist} {}
@@ -312,6 +314,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide
312 this->main_window = parent; 314 this->main_window = parent;
313 layout = new QVBoxLayout; 315 layout = new QVBoxLayout;
314 tree_view = new QTreeView; 316 tree_view = new QTreeView;
317 controller_navigation = new ControllerNavigation(system.HIDCore(), this);
315 search_field = new GameListSearchField(this); 318 search_field = new GameListSearchField(this);
316 item_model = new QStandardItemModel(tree_view); 319 item_model = new QStandardItemModel(tree_view);
317 tree_view->setModel(item_model); 320 tree_view->setModel(item_model);
@@ -341,6 +344,18 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide
341 connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu); 344 connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu);
342 connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded); 345 connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded);
343 connect(tree_view, &QTreeView::collapsed, this, &GameList::OnItemExpanded); 346 connect(tree_view, &QTreeView::collapsed, this, &GameList::OnItemExpanded);
347 connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
348 [this](Qt::Key key) {
349 // Avoid pressing buttons while playing
350 if (system.IsPoweredOn()) {
351 return;
352 }
353 if (!this->isActiveWindow()) {
354 return;
355 }
356 QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
357 QCoreApplication::postEvent(tree_view, event);
358 });
344 359
345 // We must register all custom types with the Qt Automoc system so that we are able to use 360 // We must register all custom types with the Qt Automoc system so that we are able to use
346 // it with signals/slots. In this case, QList falls under the umbrells of custom types. 361 // it with signals/slots. In this case, QList falls under the umbrells of custom types.
@@ -353,7 +368,12 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide
353 setLayout(layout); 368 setLayout(layout);
354} 369}
355 370
371void GameList::UnloadController() {
372 controller_navigation->UnloadController();
373}
374
356GameList::~GameList() { 375GameList::~GameList() {
376 UnloadController();
357 emit ShouldCancelWorker(); 377 emit ShouldCancelWorker();
358} 378}
359 379
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index 675469e66..a94ea1477 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -24,6 +24,7 @@
24#include "uisettings.h" 24#include "uisettings.h"
25#include "yuzu/compatibility_list.h" 25#include "yuzu/compatibility_list.h"
26 26
27class ControllerNavigation;
27class GameListWorker; 28class GameListWorker;
28class GameListSearchField; 29class GameListSearchField;
29class GameListDir; 30class GameListDir;
@@ -88,6 +89,9 @@ public:
88 void SaveInterfaceLayout(); 89 void SaveInterfaceLayout();
89 void LoadInterfaceLayout(); 90 void LoadInterfaceLayout();
90 91
92 /// Disables events from the emulated controller
93 void UnloadController();
94
91 static const QStringList supported_file_extensions; 95 static const QStringList supported_file_extensions;
92 96
93signals: 97signals:
@@ -143,6 +147,7 @@ private:
143 QStandardItemModel* item_model = nullptr; 147 QStandardItemModel* item_model = nullptr;
144 GameListWorker* current_worker = nullptr; 148 GameListWorker* current_worker = nullptr;
145 QFileSystemWatcher* watcher = nullptr; 149 QFileSystemWatcher* watcher = nullptr;
150 ControllerNavigation* controller_navigation = nullptr;
146 CompatibilityList compatibility_list; 151 CompatibilityList compatibility_list;
147 152
148 friend class GameListSearchField; 153 friend class GameListSearchField;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 9bd0db10a..f266fd963 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -449,7 +449,7 @@ void GMainWindow::ControllerSelectorReconfigureControllers(
449} 449}
450 450
451void GMainWindow::ProfileSelectorSelectProfile() { 451void GMainWindow::ProfileSelectorSelectProfile() {
452 QtProfileSelectionDialog dialog(this); 452 QtProfileSelectionDialog dialog(system->HIDCore(), this);
453 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | 453 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
454 Qt::WindowTitleHint | Qt::WindowSystemMenuHint | 454 Qt::WindowTitleHint | Qt::WindowSystemMenuHint |
455 Qt::WindowCloseButtonHint); 455 Qt::WindowCloseButtonHint);
@@ -1346,7 +1346,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
1346} 1346}
1347 1347
1348void GMainWindow::SelectAndSetCurrentUser() { 1348void GMainWindow::SelectAndSetCurrentUser() {
1349 QtProfileSelectionDialog dialog(this); 1349 QtProfileSelectionDialog dialog(system->HIDCore(), this);
1350 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | 1350 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
1351 Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); 1351 Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
1352 dialog.setWindowModality(Qt::WindowModal); 1352 dialog.setWindowModality(Qt::WindowModal);
@@ -1608,7 +1608,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
1608 if (has_user_save) { 1608 if (has_user_save) {
1609 // User save data 1609 // User save data
1610 const auto select_profile = [this] { 1610 const auto select_profile = [this] {
1611 QtProfileSelectionDialog dialog(this); 1611 QtProfileSelectionDialog dialog(system->HIDCore(), this);
1612 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | 1612 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
1613 Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); 1613 Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
1614 dialog.setWindowModality(Qt::WindowModal); 1614 dialog.setWindowModality(Qt::WindowModal);
@@ -3376,7 +3376,10 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
3376 UpdateUISettings(); 3376 UpdateUISettings();
3377 game_list->SaveInterfaceLayout(); 3377 game_list->SaveInterfaceLayout();
3378 hotkey_registry.SaveHotkeys(); 3378 hotkey_registry.SaveHotkeys();
3379
3380 // Unload controllers early
3379 controller_dialog->UnloadController(); 3381 controller_dialog->UnloadController();
3382 game_list->UnloadController();
3380 system->HIDCore().UnloadInputDevices(); 3383 system->HIDCore().UnloadInputDevices();
3381 3384
3382 // Shutdown session if the emu thread is active... 3385 // Shutdown session if the emu thread is active...
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 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included
4
5#include "common/settings_input.h"
6#include "core/hid/emulated_controller.h"
7#include "core/hid/hid_core.h"
8#include "yuzu/util/controller_navigation.h"
9
10ControllerNavigation::ControllerNavigation(Core::HID::HIDCore& hid_core, QWidget* parent) {
11 player1_controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
12 handheld_controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
13 Core::HID::ControllerUpdateCallback engine_callback{
14 .on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdateEvent(type); },
15 .is_npad_service = false,
16 };
17 player1_callback_key = player1_controller->SetCallback(engine_callback);
18 handheld_callback_key = handheld_controller->SetCallback(engine_callback);
19 is_controller_set = true;
20}
21
22ControllerNavigation::~ControllerNavigation() {
23 UnloadController();
24}
25
26void ControllerNavigation::UnloadController() {
27 if (is_controller_set) {
28 player1_controller->DeleteCallback(player1_callback_key);
29 handheld_controller->DeleteCallback(handheld_callback_key);
30 is_controller_set = false;
31 }
32}
33
34void ControllerNavigation::TriggerButton(Settings::NativeButton::Values native_button,
35 Qt::Key key) {
36 if (button_values[native_button].value && !button_values[native_button].locked) {
37 emit TriggerKeyboardEvent(key);
38 }
39}
40
41void ControllerNavigation::ControllerUpdateEvent(Core::HID::ControllerTriggerType type) {
42 std::lock_guard lock{mutex};
43 if (type == Core::HID::ControllerTriggerType::Button) {
44 ControllerUpdateButton();
45 return;
46 }
47
48 if (type == Core::HID::ControllerTriggerType::Stick) {
49 ControllerUpdateStick();
50 return;
51 }
52}
53
54void ControllerNavigation::ControllerUpdateButton() {
55 const auto controller_type = player1_controller->GetNpadStyleIndex();
56 const auto& player1_buttons = player1_controller->GetButtonsValues();
57 const auto& handheld_buttons = handheld_controller->GetButtonsValues();
58
59 for (std::size_t i = 0; i < player1_buttons.size(); ++i) {
60 const bool button = player1_buttons[i].value || handheld_buttons[i].value;
61 // Trigger only once
62 button_values[i].locked = button == button_values[i].value;
63 button_values[i].value = button;
64 }
65
66 switch (controller_type) {
67 case Core::HID::NpadStyleIndex::ProController:
68 case Core::HID::NpadStyleIndex::JoyconDual:
69 case Core::HID::NpadStyleIndex::Handheld:
70 case Core::HID::NpadStyleIndex::GameCube:
71 TriggerButton(Settings::NativeButton::A, Qt::Key_Enter);
72 TriggerButton(Settings::NativeButton::B, Qt::Key_Escape);
73 TriggerButton(Settings::NativeButton::DDown, Qt::Key_Down);
74 TriggerButton(Settings::NativeButton::DLeft, Qt::Key_Left);
75 TriggerButton(Settings::NativeButton::DRight, Qt::Key_Right);
76 TriggerButton(Settings::NativeButton::DUp, Qt::Key_Up);
77 break;
78 case Core::HID::NpadStyleIndex::JoyconLeft:
79 TriggerButton(Settings::NativeButton::DDown, Qt::Key_Enter);
80 TriggerButton(Settings::NativeButton::DLeft, Qt::Key_Escape);
81 break;
82 case Core::HID::NpadStyleIndex::JoyconRight:
83 TriggerButton(Settings::NativeButton::X, Qt::Key_Enter);
84 TriggerButton(Settings::NativeButton::A, Qt::Key_Escape);
85 break;
86 default:
87 break;
88 }
89}
90
91void ControllerNavigation::ControllerUpdateStick() {
92 const auto controller_type = player1_controller->GetNpadStyleIndex();
93 const auto& player1_sticks = player1_controller->GetSticksValues();
94 const auto& handheld_sticks = player1_controller->GetSticksValues();
95 bool update = false;
96
97 for (std::size_t i = 0; i < player1_sticks.size(); ++i) {
98 const Common::Input::StickStatus stick{
99 .left = player1_sticks[i].left || handheld_sticks[i].left,
100 .right = player1_sticks[i].right || handheld_sticks[i].right,
101 .up = player1_sticks[i].up || handheld_sticks[i].up,
102 .down = player1_sticks[i].down || handheld_sticks[i].down,
103 };
104 // Trigger only once
105 if (stick.down != stick_values[i].down || stick.left != stick_values[i].left ||
106 stick.right != stick_values[i].right || stick.up != stick_values[i].up) {
107 update = true;
108 }
109 stick_values[i] = stick;
110 }
111
112 if (!update) {
113 return;
114 }
115
116 switch (controller_type) {
117 case Core::HID::NpadStyleIndex::ProController:
118 case Core::HID::NpadStyleIndex::JoyconDual:
119 case Core::HID::NpadStyleIndex::Handheld:
120 case Core::HID::NpadStyleIndex::GameCube:
121 if (stick_values[Settings::NativeAnalog::LStick].down) {
122 emit TriggerKeyboardEvent(Qt::Key_Down);
123 return;
124 }
125 if (stick_values[Settings::NativeAnalog::LStick].left) {
126 emit TriggerKeyboardEvent(Qt::Key_Left);
127 return;
128 }
129 if (stick_values[Settings::NativeAnalog::LStick].right) {
130 emit TriggerKeyboardEvent(Qt::Key_Right);
131 return;
132 }
133 if (stick_values[Settings::NativeAnalog::LStick].up) {
134 emit TriggerKeyboardEvent(Qt::Key_Up);
135 return;
136 }
137 break;
138 case Core::HID::NpadStyleIndex::JoyconLeft:
139 if (stick_values[Settings::NativeAnalog::LStick].left) {
140 emit TriggerKeyboardEvent(Qt::Key_Down);
141 return;
142 }
143 if (stick_values[Settings::NativeAnalog::LStick].up) {
144 emit TriggerKeyboardEvent(Qt::Key_Left);
145 return;
146 }
147 if (stick_values[Settings::NativeAnalog::LStick].down) {
148 emit TriggerKeyboardEvent(Qt::Key_Right);
149 return;
150 }
151 if (stick_values[Settings::NativeAnalog::LStick].right) {
152 emit TriggerKeyboardEvent(Qt::Key_Up);
153 return;
154 }
155 break;
156 case Core::HID::NpadStyleIndex::JoyconRight:
157 if (stick_values[Settings::NativeAnalog::RStick].right) {
158 emit TriggerKeyboardEvent(Qt::Key_Down);
159 return;
160 }
161 if (stick_values[Settings::NativeAnalog::RStick].down) {
162 emit TriggerKeyboardEvent(Qt::Key_Left);
163 return;
164 }
165 if (stick_values[Settings::NativeAnalog::RStick].up) {
166 emit TriggerKeyboardEvent(Qt::Key_Right);
167 return;
168 }
169 if (stick_values[Settings::NativeAnalog::RStick].left) {
170 emit TriggerKeyboardEvent(Qt::Key_Up);
171 return;
172 }
173 break;
174 default:
175 break;
176 }
177}
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 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included
4
5#pragma once
6
7#include <QKeyEvent>
8#include <QObject>
9
10#include "common/input.h"
11#include "common/settings_input.h"
12
13namespace Core::HID {
14using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>;
15using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>;
16enum class ControllerTriggerType;
17class EmulatedController;
18class HIDCore;
19} // namespace Core::HID
20
21class ControllerNavigation : public QObject {
22 Q_OBJECT
23
24public:
25 explicit ControllerNavigation(Core::HID::HIDCore& hid_core, QWidget* parent = nullptr);
26 ~ControllerNavigation();
27
28 /// Disables events from the emulated controller
29 void UnloadController();
30
31signals:
32 void TriggerKeyboardEvent(Qt::Key key);
33
34private:
35 void TriggerButton(Settings::NativeButton::Values native_button, Qt::Key key);
36 void ControllerUpdateEvent(Core::HID::ControllerTriggerType type);
37
38 void ControllerUpdateButton();
39
40 void ControllerUpdateStick();
41
42 Core::HID::ButtonValues button_values{};
43 Core::HID::SticksValues stick_values{};
44
45 int player1_callback_key{};
46 int handheld_callback_key{};
47 bool is_controller_set{};
48 mutable std::mutex mutex;
49 Core::HID::EmulatedController* player1_controller;
50 Core::HID::EmulatedController* handheld_controller;
51};