configure_mouse_advanced.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 <QKeyEvent>
  7. #include <QMenu>
  8. #include <QTimer>
  9. #include "common/assert.h"
  10. #include "common/param_package.h"
  11. #include "input_common/main.h"
  12. #include "ui_configure_mouse_advanced.h"
  13. #include "yuzu/configuration/config.h"
  14. #include "yuzu/configuration/configure_mouse_advanced.h"
  15. static QString GetKeyName(int key_code) {
  16. switch (key_code) {
  17. case Qt::Key_Shift:
  18. return QObject::tr("Shift");
  19. case Qt::Key_Control:
  20. return QObject::tr("Ctrl");
  21. case Qt::Key_Alt:
  22. return QObject::tr("Alt");
  23. case Qt::Key_Meta:
  24. return {};
  25. default:
  26. return QKeySequence(key_code).toString();
  27. }
  28. }
  29. static QString ButtonToText(const Common::ParamPackage& param) {
  30. if (!param.Has("engine")) {
  31. return QObject::tr("[not set]");
  32. }
  33. if (param.Get("engine", "") == "keyboard") {
  34. return GetKeyName(param.Get("code", 0));
  35. }
  36. if (param.Get("engine", "") == "sdl") {
  37. if (param.Has("hat")) {
  38. const QString hat_str = QString::fromStdString(param.Get("hat", ""));
  39. const QString direction_str = QString::fromStdString(param.Get("direction", ""));
  40. return QObject::tr("Hat %1 %2").arg(hat_str, direction_str);
  41. }
  42. if (param.Has("axis")) {
  43. const QString axis_str = QString::fromStdString(param.Get("axis", ""));
  44. const QString direction_str = QString::fromStdString(param.Get("direction", ""));
  45. return QObject::tr("Axis %1%2").arg(axis_str, direction_str);
  46. }
  47. if (param.Has("button")) {
  48. const QString button_str = QString::fromStdString(param.Get("button", ""));
  49. return QObject::tr("Button %1").arg(button_str);
  50. }
  51. return {};
  52. }
  53. return QObject::tr("[unknown]");
  54. }
  55. ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent)
  56. : QDialog(parent), ui(std::make_unique<Ui::ConfigureMouseAdvanced>()),
  57. timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
  58. ui->setupUi(this);
  59. setFocusPolicy(Qt::ClickFocus);
  60. button_map = {
  61. ui->left_button, ui->right_button, ui->middle_button, ui->forward_button, ui->back_button,
  62. };
  63. for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) {
  64. auto* const button = button_map[button_id];
  65. if (button == nullptr) {
  66. continue;
  67. }
  68. button->setContextMenuPolicy(Qt::CustomContextMenu);
  69. connect(button, &QPushButton::clicked, [=] {
  70. HandleClick(
  71. button_map[button_id],
  72. [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
  73. InputCommon::Polling::DeviceType::Button);
  74. });
  75. connect(button, &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
  76. QMenu context_menu;
  77. context_menu.addAction(tr("Clear"), [&] {
  78. buttons_param[button_id].Clear();
  79. button_map[button_id]->setText(tr("[not set]"));
  80. });
  81. context_menu.addAction(tr("Restore Default"), [&] {
  82. buttons_param[button_id] = Common::ParamPackage{
  83. InputCommon::GenerateKeyboardParam(Config::default_mouse_buttons[button_id])};
  84. button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
  85. });
  86. context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
  87. });
  88. }
  89. connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); });
  90. connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); });
  91. timeout_timer->setSingleShot(true);
  92. connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); });
  93. connect(poll_timer.get(), &QTimer::timeout, [this] {
  94. Common::ParamPackage params;
  95. for (auto& poller : device_pollers) {
  96. params = poller->GetNextInput();
  97. if (params.Has("engine")) {
  98. SetPollingResult(params, false);
  99. return;
  100. }
  101. }
  102. });
  103. LoadConfiguration();
  104. resize(0, 0);
  105. }
  106. ConfigureMouseAdvanced::~ConfigureMouseAdvanced() = default;
  107. void ConfigureMouseAdvanced::ApplyConfiguration() {
  108. std::transform(buttons_param.begin(), buttons_param.end(),
  109. Settings::values.mouse_buttons.begin(),
  110. [](const Common::ParamPackage& param) { return param.Serialize(); });
  111. }
  112. void ConfigureMouseAdvanced::LoadConfiguration() {
  113. std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(),
  114. buttons_param.begin(),
  115. [](const std::string& str) { return Common::ParamPackage(str); });
  116. UpdateButtonLabels();
  117. }
  118. void ConfigureMouseAdvanced::changeEvent(QEvent* event) {
  119. if (event->type() == QEvent::LanguageChange) {
  120. RetranslateUI();
  121. }
  122. QDialog::changeEvent(event);
  123. }
  124. void ConfigureMouseAdvanced::RetranslateUI() {
  125. ui->retranslateUi(this);
  126. }
  127. void ConfigureMouseAdvanced::RestoreDefaults() {
  128. for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) {
  129. buttons_param[button_id] = Common::ParamPackage{
  130. InputCommon::GenerateKeyboardParam(Config::default_mouse_buttons[button_id])};
  131. }
  132. UpdateButtonLabels();
  133. }
  134. void ConfigureMouseAdvanced::ClearAll() {
  135. for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
  136. const auto* const button = button_map[i];
  137. if (button != nullptr && button->isEnabled()) {
  138. buttons_param[i].Clear();
  139. }
  140. }
  141. UpdateButtonLabels();
  142. }
  143. void ConfigureMouseAdvanced::UpdateButtonLabels() {
  144. for (int button = 0; button < Settings::NativeMouseButton::NumMouseButtons; button++) {
  145. button_map[button]->setText(ButtonToText(buttons_param[button]));
  146. }
  147. }
  148. void ConfigureMouseAdvanced::HandleClick(
  149. QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
  150. InputCommon::Polling::DeviceType type) {
  151. button->setText(tr("[press key]"));
  152. button->setFocus();
  153. const auto iter = std::find(button_map.begin(), button_map.end(), button);
  154. ASSERT(iter != button_map.end());
  155. const auto index = std::distance(button_map.begin(), iter);
  156. ASSERT(index < Settings::NativeButton::NumButtons && index >= 0);
  157. input_setter = new_input_setter;
  158. device_pollers = InputCommon::Polling::GetPollers(type);
  159. // Keyboard keys can only be used as button devices
  160. want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button;
  161. for (auto& poller : device_pollers) {
  162. poller->Start();
  163. }
  164. grabKeyboard();
  165. grabMouse();
  166. timeout_timer->start(5000); // Cancel after 5 seconds
  167. poll_timer->start(200); // Check for new inputs every 200ms
  168. }
  169. void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params, bool abort) {
  170. releaseKeyboard();
  171. releaseMouse();
  172. timeout_timer->stop();
  173. poll_timer->stop();
  174. for (auto& poller : device_pollers) {
  175. poller->Stop();
  176. }
  177. if (!abort) {
  178. (*input_setter)(params);
  179. }
  180. UpdateButtonLabels();
  181. input_setter = std::nullopt;
  182. }
  183. void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) {
  184. if (!input_setter || !event) {
  185. return;
  186. }
  187. if (event->key() != Qt::Key_Escape) {
  188. if (want_keyboard_keys) {
  189. SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
  190. false);
  191. } else {
  192. // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
  193. return;
  194. }
  195. }
  196. SetPollingResult({}, true);
  197. }