configure_input.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Copyright 2016 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <memory>
  6. #include <QSignalBlocker>
  7. #include <QTimer>
  8. #include "configuration/configure_touchscreen_advanced.h"
  9. #include "core/core.h"
  10. #include "core/hle/service/am/am.h"
  11. #include "core/hle/service/am/applet_ae.h"
  12. #include "core/hle/service/am/applet_oe.h"
  13. #include "core/hle/service/hid/controllers/npad.h"
  14. #include "core/hle/service/sm/sm.h"
  15. #include "ui_configure_input.h"
  16. #include "ui_configure_input_player.h"
  17. #include "yuzu/configuration/configure_input.h"
  18. #include "yuzu/configuration/configure_input_player.h"
  19. #include "yuzu/configuration/configure_mouse_advanced.h"
  20. void OnDockedModeChanged(bool last_state, bool new_state) {
  21. if (last_state == new_state) {
  22. return;
  23. }
  24. Core::System& system{Core::System::GetInstance()};
  25. if (!system.IsPoweredOn()) {
  26. return;
  27. }
  28. Service::SM::ServiceManager& sm = system.ServiceManager();
  29. // Message queue is shared between these services, we just need to signal an operation
  30. // change to one and it will handle both automatically
  31. auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
  32. auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
  33. bool has_signalled = false;
  34. if (applet_oe != nullptr) {
  35. applet_oe->GetMessageQueue()->OperationModeChanged();
  36. has_signalled = true;
  37. }
  38. if (applet_ae != nullptr && !has_signalled) {
  39. applet_ae->GetMessageQueue()->OperationModeChanged();
  40. }
  41. }
  42. namespace {
  43. template <typename Dialog, typename... Args>
  44. void CallConfigureDialog(ConfigureInput& parent, Args&&... args) {
  45. parent.ApplyConfiguration();
  46. Dialog dialog(&parent, std::forward<Args>(args)...);
  47. const auto res = dialog.exec();
  48. if (res == QDialog::Accepted) {
  49. dialog.ApplyConfiguration();
  50. }
  51. }
  52. } // Anonymous namespace
  53. ConfigureInput::ConfigureInput(QWidget* parent)
  54. : QDialog(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
  55. ui->setupUi(this);
  56. players_controller = {
  57. ui->player1_combobox, ui->player2_combobox, ui->player3_combobox, ui->player4_combobox,
  58. ui->player5_combobox, ui->player6_combobox, ui->player7_combobox, ui->player8_combobox,
  59. };
  60. players_configure = {
  61. ui->player1_configure, ui->player2_configure, ui->player3_configure, ui->player4_configure,
  62. ui->player5_configure, ui->player6_configure, ui->player7_configure, ui->player8_configure,
  63. };
  64. RetranslateUI();
  65. LoadConfiguration();
  66. UpdateUIEnabled();
  67. connect(ui->restore_defaults_button, &QPushButton::pressed, this,
  68. &ConfigureInput::RestoreDefaults);
  69. for (auto* enabled : players_controller) {
  70. connect(enabled, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
  71. &ConfigureInput::UpdateUIEnabled);
  72. }
  73. connect(ui->use_docked_mode, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
  74. connect(ui->handheld_connected, &QCheckBox::stateChanged, this,
  75. &ConfigureInput::UpdateUIEnabled);
  76. connect(ui->mouse_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
  77. connect(ui->keyboard_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
  78. connect(ui->debug_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
  79. connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this,
  80. &ConfigureInput::UpdateUIEnabled);
  81. for (std::size_t i = 0; i < players_configure.size(); ++i) {
  82. connect(players_configure[i], &QPushButton::pressed, this,
  83. [this, i] { CallConfigureDialog<ConfigureInputPlayer>(*this, i, false); });
  84. }
  85. connect(ui->handheld_configure, &QPushButton::pressed, this,
  86. [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 8, false); });
  87. connect(ui->debug_configure, &QPushButton::pressed, this,
  88. [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 9, true); });
  89. connect(ui->mouse_advanced, &QPushButton::pressed, this,
  90. [this] { CallConfigureDialog<ConfigureMouseAdvanced>(*this); });
  91. connect(ui->touchscreen_advanced, &QPushButton::pressed, this,
  92. [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
  93. }
  94. ConfigureInput::~ConfigureInput() = default;
  95. void ConfigureInput::ApplyConfiguration() {
  96. for (std::size_t i = 0; i < players_controller.size(); ++i) {
  97. const auto controller_type_index = players_controller[i]->currentIndex();
  98. Settings::values.players[i].connected = controller_type_index != 0;
  99. if (controller_type_index > 0) {
  100. Settings::values.players[i].type =
  101. static_cast<Settings::ControllerType>(controller_type_index - 1);
  102. } else {
  103. Settings::values.players[i].type = Settings::ControllerType::DualJoycon;
  104. }
  105. }
  106. const bool pre_docked_mode = Settings::values.use_docked_mode;
  107. Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
  108. OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
  109. Settings::values
  110. .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)]
  111. .connected = ui->handheld_connected->isChecked();
  112. Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked();
  113. Settings::values.mouse_enabled = ui->mouse_enabled->isChecked();
  114. Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked();
  115. Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
  116. }
  117. void ConfigureInput::changeEvent(QEvent* event) {
  118. if (event->type() == QEvent::LanguageChange) {
  119. RetranslateUI();
  120. }
  121. QDialog::changeEvent(event);
  122. }
  123. void ConfigureInput::RetranslateUI() {
  124. ui->retranslateUi(this);
  125. RetranslateControllerComboBoxes();
  126. }
  127. void ConfigureInput::RetranslateControllerComboBoxes() {
  128. for (auto* controller_box : players_controller) {
  129. [[maybe_unused]] const QSignalBlocker blocker(controller_box);
  130. controller_box->clear();
  131. controller_box->addItems({tr("None"), tr("Pro Controller"), tr("Dual Joycons"),
  132. tr("Single Right Joycon"), tr("Single Left Joycon")});
  133. }
  134. LoadPlayerControllerIndices();
  135. }
  136. void ConfigureInput::UpdateUIEnabled() {
  137. bool hit_disabled = false;
  138. for (auto* player : players_controller) {
  139. player->setDisabled(hit_disabled);
  140. if (hit_disabled) {
  141. player->setCurrentIndex(0);
  142. }
  143. if (!hit_disabled && player->currentIndex() == 0) {
  144. hit_disabled = true;
  145. }
  146. }
  147. for (std::size_t i = 0; i < players_controller.size(); ++i) {
  148. players_configure[i]->setEnabled(players_controller[i]->currentIndex() != 0);
  149. }
  150. ui->handheld_connected->setEnabled(!ui->use_docked_mode->isChecked());
  151. ui->handheld_configure->setEnabled(ui->handheld_connected->isChecked() &&
  152. !ui->use_docked_mode->isChecked());
  153. ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked());
  154. ui->debug_configure->setEnabled(ui->debug_enabled->isChecked());
  155. ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked());
  156. }
  157. void ConfigureInput::LoadConfiguration() {
  158. std::stable_partition(
  159. Settings::values.players.begin(),
  160. Settings::values.players.begin() +
  161. Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD),
  162. [](const auto& player) { return player.connected; });
  163. LoadPlayerControllerIndices();
  164. ui->use_docked_mode->setChecked(Settings::values.use_docked_mode);
  165. ui->handheld_connected->setChecked(
  166. Settings::values
  167. .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)]
  168. .connected);
  169. ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled);
  170. ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
  171. ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
  172. ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
  173. UpdateUIEnabled();
  174. }
  175. void ConfigureInput::LoadPlayerControllerIndices() {
  176. for (std::size_t i = 0; i < players_controller.size(); ++i) {
  177. const auto connected = Settings::values.players[i].connected;
  178. players_controller[i]->setCurrentIndex(
  179. connected ? static_cast<u8>(Settings::values.players[i].type) + 1 : 0);
  180. }
  181. }
  182. void ConfigureInput::RestoreDefaults() {
  183. players_controller[0]->setCurrentIndex(2);
  184. for (std::size_t i = 1; i < players_controller.size(); ++i) {
  185. players_controller[i]->setCurrentIndex(0);
  186. }
  187. ui->use_docked_mode->setCheckState(Qt::Unchecked);
  188. ui->handheld_connected->setCheckState(Qt::Unchecked);
  189. ui->mouse_enabled->setCheckState(Qt::Unchecked);
  190. ui->keyboard_enabled->setCheckState(Qt::Unchecked);
  191. ui->debug_enabled->setCheckState(Qt::Unchecked);
  192. ui->touchscreen_enabled->setCheckState(Qt::Checked);
  193. UpdateUIEnabled();
  194. }