summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/input_common/main.cpp6
-rw-r--r--src/yuzu/configuration/configure_input.cpp2
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp318
-rw-r--r--src/yuzu/configuration/configure_input_player.h17
4 files changed, 205 insertions, 138 deletions
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index d32fd8b81..354c734fe 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -78,7 +78,7 @@ struct InputSubsystem::Impl {
78 [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const { 78 [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const {
79 std::vector<Common::ParamPackage> devices = { 79 std::vector<Common::ParamPackage> devices = {
80 Common::ParamPackage{{"display", "Any"}, {"class", "any"}}, 80 Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
81 Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "key"}}, 81 Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "keyboard"}},
82 }; 82 };
83#ifdef HAVE_SDL2 83#ifdef HAVE_SDL2
84 auto sdl_devices = sdl->GetInputDevices(); 84 auto sdl_devices = sdl->GetInputDevices();
@@ -96,7 +96,7 @@ struct InputSubsystem::Impl {
96 if (!params.Has("class") || params.Get("class", "") == "any") { 96 if (!params.Has("class") || params.Get("class", "") == "any") {
97 return {}; 97 return {};
98 } 98 }
99 if (params.Get("class", "") == "key") { 99 if (params.Get("class", "") == "keyboard") {
100 // TODO consider returning the SDL key codes for the default keybindings 100 // TODO consider returning the SDL key codes for the default keybindings
101 return {}; 101 return {};
102 } 102 }
@@ -116,7 +116,7 @@ struct InputSubsystem::Impl {
116 if (!params.Has("class") || params.Get("class", "") == "any") { 116 if (!params.Has("class") || params.Get("class", "") == "any") {
117 return {}; 117 return {};
118 } 118 }
119 if (params.Get("class", "") == "key") { 119 if (params.Get("class", "") == "keyboard") {
120 // TODO consider returning the SDL key codes for the default keybindings 120 // TODO consider returning the SDL key codes for the default keybindings
121 return {}; 121 return {};
122 } 122 }
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 2725fcb2b..f2932aa0b 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -242,6 +242,6 @@ void ConfigureInput::UpdateDockedState(bool is_handheld) {
242 242
243void ConfigureInput::UpdateAllInputDevices() { 243void ConfigureInput::UpdateAllInputDevices() {
244 for (const auto& player : player_controllers) { 244 for (const auto& player : player_controllers) {
245 player->UpdateInputDevices(); 245 player->UpdateInputDeviceCombobox();
246 } 246 }
247} 247}
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index f58ca29d7..0de0c6999 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -477,11 +477,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
477 UpdateMotionButtons(); 477 UpdateMotionButtons();
478 }); 478 });
479 479
480 connect(ui->comboDevices, qOverload<int>(&QComboBox::currentIndexChanged), this, 480 connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this,
481 &ConfigureInputPlayer::UpdateMappingWithDefaults); 481 &ConfigureInputPlayer::UpdateMappingWithDefaults);
482 482
483 ui->comboDevices->setCurrentIndex(-1);
484
483 ui->buttonRefreshDevices->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); 485 ui->buttonRefreshDevices->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
484 UpdateInputDevices();
485 connect(ui->buttonRefreshDevices, &QPushButton::clicked, 486 connect(ui->buttonRefreshDevices, &QPushButton::clicked,
486 [this] { emit RefreshInputDevices(); }); 487 [this] { emit RefreshInputDevices(); });
487 488
@@ -492,14 +493,14 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
492 Common::ParamPackage params; 493 Common::ParamPackage params;
493 if (input_subsystem->GetGCButtons()->IsPolling()) { 494 if (input_subsystem->GetGCButtons()->IsPolling()) {
494 params = input_subsystem->GetGCButtons()->GetNextInput(); 495 params = input_subsystem->GetGCButtons()->GetNextInput();
495 if (params.Has("engine")) { 496 if (params.Has("engine") && IsInputAcceptable(params)) {
496 SetPollingResult(params, false); 497 SetPollingResult(params, false);
497 return; 498 return;
498 } 499 }
499 } 500 }
500 if (input_subsystem->GetGCAnalogs()->IsPolling()) { 501 if (input_subsystem->GetGCAnalogs()->IsPolling()) {
501 params = input_subsystem->GetGCAnalogs()->GetNextInput(); 502 params = input_subsystem->GetGCAnalogs()->GetNextInput();
502 if (params.Has("engine")) { 503 if (params.Has("engine") && IsInputAcceptable(params)) {
503 SetPollingResult(params, false); 504 SetPollingResult(params, false);
504 return; 505 return;
505 } 506 }
@@ -513,7 +514,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
513 } 514 }
514 for (auto& poller : device_pollers) { 515 for (auto& poller : device_pollers) {
515 params = poller->GetNextInput(); 516 params = poller->GetNextInput();
516 if (params.Has("engine")) { 517 if (params.Has("engine") && IsInputAcceptable(params)) {
517 SetPollingResult(params, false); 518 SetPollingResult(params, false);
518 return; 519 return;
519 } 520 }
@@ -572,6 +573,14 @@ void ConfigureInputPlayer::ApplyConfiguration() {
572 UpdateController(Settings::ControllerType::Handheld, HANDHELD_INDEX, handheld.connected); 573 UpdateController(Settings::ControllerType::Handheld, HANDHELD_INDEX, handheld.connected);
573} 574}
574 575
576void ConfigureInputPlayer::showEvent(QShowEvent* event) {
577 if (bottom_row == nullptr) {
578 return;
579 }
580 QWidget::showEvent(event);
581 ui->main->addWidget(bottom_row);
582}
583
575void ConfigureInputPlayer::changeEvent(QEvent* event) { 584void ConfigureInputPlayer::changeEvent(QEvent* event) {
576 if (event->type() == QEvent::LanguageChange) { 585 if (event->type() == QEvent::LanguageChange) {
577 RetranslateUI(); 586 RetranslateUI();
@@ -604,6 +613,7 @@ void ConfigureInputPlayer::LoadConfiguration() {
604 } 613 }
605 614
606 UpdateUI(); 615 UpdateUI();
616 UpdateInputDeviceCombobox();
607 617
608 if (debug) { 618 if (debug) {
609 return; 619 return;
@@ -615,11 +625,56 @@ void ConfigureInputPlayer::LoadConfiguration() {
615 (player_index == 0 && Settings::values.players[HANDHELD_INDEX].connected)); 625 (player_index == 0 && Settings::values.players[HANDHELD_INDEX].connected));
616} 626}
617 627
618void ConfigureInputPlayer::UpdateInputDevices() { 628void ConfigureInputPlayer::ConnectPlayer(bool connected) {
619 input_devices = input_subsystem->GetInputDevices(); 629 ui->groupConnectedController->setChecked(connected);
620 ui->comboDevices->clear(); 630}
621 for (auto device : input_devices) { 631
622 ui->comboDevices->addItem(QString::fromStdString(device.Get("display", "Unknown")), {}); 632void ConfigureInputPlayer::UpdateInputDeviceCombobox() {
633 // Skip input device persistence if "Input Devices" is set to "Any".
634 if (ui->comboDevices->currentIndex() == 0) {
635 UpdateInputDevices();
636 return;
637 }
638
639 // Find the first button that isn't empty.
640 const auto button_param =
641 std::find_if(buttons_param.begin(), buttons_param.end(),
642 [](const Common::ParamPackage param) { return param.Has("engine"); });
643 const bool buttons_empty = button_param == buttons_param.end();
644
645 const auto current_engine = button_param->Get("engine", "");
646 const auto current_guid = button_param->Get("guid", "");
647 const auto current_port = button_param->Get("port", "");
648
649 UpdateInputDevices();
650
651 if (buttons_empty) {
652 return;
653 }
654
655 const bool all_one_device =
656 std::all_of(buttons_param.begin(), buttons_param.end(),
657 [current_engine, current_guid, current_port](const Common::ParamPackage param) {
658 return !param.Has("engine") || (param.Get("engine", "") == current_engine &&
659 param.Get("guid", "") == current_guid &&
660 param.Get("port", "") == current_port);
661 });
662
663 if (all_one_device) {
664 const auto devices_it = std::find_if(
665 input_devices.begin(), input_devices.end(),
666 [current_engine, current_guid, current_port](const Common::ParamPackage param) {
667 return param.Get("class", "") == current_engine &&
668 param.Get("guid", "") == current_guid &&
669 param.Get("port", "") == current_port;
670 });
671 const int device_index =
672 devices_it != input_devices.end()
673 ? static_cast<int>(std::distance(input_devices.begin(), devices_it))
674 : 0;
675 ui->comboDevices->setCurrentIndex(device_index);
676 } else {
677 ui->comboDevices->setCurrentIndex(0);
623 } 678 }
624} 679}
625 680
@@ -648,7 +703,7 @@ void ConfigureInputPlayer::RestoreDefaults() {
648 } 703 }
649 704
650 UpdateUI(); 705 UpdateUI();
651 UpdateInputDevices(); 706 UpdateInputDeviceCombobox();
652 ui->comboControllerType->setCurrentIndex(0); 707 ui->comboControllerType->setCurrentIndex(0);
653} 708}
654 709
@@ -752,117 +807,12 @@ void ConfigureInputPlayer::UpdateUI() {
752 } 807 }
753} 808}
754 809
755void ConfigureInputPlayer::UpdateMappingWithDefaults() { 810void ConfigureInputPlayer::UpdateInputDevices() {
756 if (ui->comboDevices->currentIndex() < 2) { 811 input_devices = input_subsystem->GetInputDevices();
757 return; 812 ui->comboDevices->clear();
758 } 813 for (auto device : input_devices) {
759 const auto& device = input_devices[ui->comboDevices->currentIndex()]; 814 ui->comboDevices->addItem(QString::fromStdString(device.Get("display", "Unknown")), {});
760 auto button_mapping = input_subsystem->GetButtonMappingForDevice(device);
761 auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device);
762 for (std::size_t i = 0; i < buttons_param.size(); ++i) {
763 buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)];
764 }
765 for (std::size_t i = 0; i < analogs_param.size(); ++i) {
766 analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)];
767 }
768
769 UpdateUI();
770}
771
772void ConfigureInputPlayer::HandleClick(
773 QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
774 InputCommon::Polling::DeviceType type) {
775 if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) {
776 button->setText(tr("Shake!"));
777 } else {
778 button->setText(tr("[waiting]"));
779 }
780 button->setFocus();
781
782 // The first two input devices are always Any and Keyboard/Mouse. If the user filtered to a
783 // controller, then they don't want keyboard/mouse input
784 want_keyboard_mouse = ui->comboDevices->currentIndex() < 2;
785
786 input_setter = new_input_setter;
787
788 device_pollers = input_subsystem->GetPollers(type);
789
790 for (auto& poller : device_pollers) {
791 poller->Start();
792 }
793
794 QWidget::grabMouse();
795 QWidget::grabKeyboard();
796
797 if (type == InputCommon::Polling::DeviceType::Button) {
798 input_subsystem->GetGCButtons()->BeginConfiguration();
799 } else {
800 input_subsystem->GetGCAnalogs()->BeginConfiguration();
801 }
802
803 if (type == InputCommon::Polling::DeviceType::Motion) {
804 input_subsystem->GetUDPMotions()->BeginConfiguration();
805 }
806
807 timeout_timer->start(2500); // Cancel after 2.5 seconds
808 poll_timer->start(50); // Check for new inputs every 50ms
809}
810
811void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, bool abort) {
812 timeout_timer->stop();
813 poll_timer->stop();
814 for (auto& poller : device_pollers) {
815 poller->Stop();
816 }
817
818 QWidget::releaseMouse();
819 QWidget::releaseKeyboard();
820
821 input_subsystem->GetGCButtons()->EndConfiguration();
822 input_subsystem->GetGCAnalogs()->EndConfiguration();
823
824 input_subsystem->GetUDPMotions()->EndConfiguration();
825
826 if (!abort) {
827 (*input_setter)(params);
828 }
829
830 UpdateUI();
831 input_setter = std::nullopt;
832}
833
834void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) {
835 if (!input_setter || !event) {
836 return;
837 }
838
839 if (want_keyboard_mouse) {
840 SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())},
841 false);
842 } else {
843 // We don't want any mouse buttons, so don't stop polling
844 return;
845 }
846
847 SetPollingResult({}, true);
848}
849
850void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
851 if (!input_setter || !event) {
852 return;
853 }
854
855 if (event->key() != Qt::Key_Escape) {
856 if (want_keyboard_mouse) {
857 SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
858 false);
859 } else {
860 // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
861 return;
862 }
863 } 815 }
864
865 SetPollingResult({}, true);
866} 816}
867 817
868void ConfigureInputPlayer::UpdateControllerIcon() { 818void ConfigureInputPlayer::UpdateControllerIcon() {
@@ -986,14 +936,128 @@ void ConfigureInputPlayer::UpdateMotionButtons() {
986 } 936 }
987} 937}
988 938
989void ConfigureInputPlayer::showEvent(QShowEvent* event) { 939void ConfigureInputPlayer::UpdateMappingWithDefaults() {
990 if (bottom_row == nullptr) { 940 if (ui->comboDevices->currentIndex() < 2) {
991 return; 941 return;
992 } 942 }
993 QWidget::showEvent(event); 943 const auto& device = input_devices[ui->comboDevices->currentIndex()];
994 ui->main->addWidget(bottom_row); 944 auto button_mapping = input_subsystem->GetButtonMappingForDevice(device);
945 auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device);
946 for (std::size_t i = 0; i < buttons_param.size(); ++i) {
947 buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)];
948 }
949 for (std::size_t i = 0; i < analogs_param.size(); ++i) {
950 analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)];
951 }
952
953 UpdateUI();
995} 954}
996 955
997void ConfigureInputPlayer::ConnectPlayer(bool connected) { 956void ConfigureInputPlayer::HandleClick(
998 ui->groupConnectedController->setChecked(connected); 957 QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
958 InputCommon::Polling::DeviceType type) {
959 if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) {
960 button->setText(tr("Shake!"));
961 } else {
962 button->setText(tr("[waiting]"));
963 }
964 button->setFocus();
965
966 // The first two input devices are always Any and Keyboard/Mouse. If the user filtered to a
967 // controller, then they don't want keyboard/mouse input
968 want_keyboard_mouse = ui->comboDevices->currentIndex() < 2;
969
970 input_setter = new_input_setter;
971
972 device_pollers = input_subsystem->GetPollers(type);
973
974 for (auto& poller : device_pollers) {
975 poller->Start();
976 }
977
978 QWidget::grabMouse();
979 QWidget::grabKeyboard();
980
981 if (type == InputCommon::Polling::DeviceType::Button) {
982 input_subsystem->GetGCButtons()->BeginConfiguration();
983 } else {
984 input_subsystem->GetGCAnalogs()->BeginConfiguration();
985 }
986
987 if (type == InputCommon::Polling::DeviceType::Motion) {
988 input_subsystem->GetUDPMotions()->BeginConfiguration();
989 }
990
991 timeout_timer->start(2500); // Cancel after 2.5 seconds
992 poll_timer->start(50); // Check for new inputs every 50ms
993}
994
995void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, bool abort) {
996 timeout_timer->stop();
997 poll_timer->stop();
998 for (auto& poller : device_pollers) {
999 poller->Stop();
1000 }
1001
1002 QWidget::releaseMouse();
1003 QWidget::releaseKeyboard();
1004
1005 input_subsystem->GetGCButtons()->EndConfiguration();
1006 input_subsystem->GetGCAnalogs()->EndConfiguration();
1007
1008 input_subsystem->GetUDPMotions()->EndConfiguration();
1009
1010 if (!abort) {
1011 (*input_setter)(params);
1012 }
1013
1014 UpdateUI();
1015 UpdateInputDeviceCombobox();
1016
1017 input_setter = std::nullopt;
1018}
1019
1020bool ConfigureInputPlayer::IsInputAcceptable(const Common::ParamPackage& params) const {
1021 if (ui->comboDevices->currentIndex() == 0) {
1022 return true;
1023 }
1024
1025 const auto current_input_device = input_devices[ui->comboDevices->currentIndex()];
1026 return params.Get("engine", "") == current_input_device.Get("class", "") &&
1027 params.Get("guid", "") == current_input_device.Get("guid", "") &&
1028 params.Get("port", "") == current_input_device.Get("port", "");
1029}
1030
1031void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) {
1032 if (!input_setter || !event) {
1033 return;
1034 }
1035
1036 if (want_keyboard_mouse) {
1037 SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())},
1038 false);
1039 } else {
1040 // We don't want any mouse buttons, so don't stop polling
1041 return;
1042 }
1043
1044 SetPollingResult({}, true);
1045}
1046
1047void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
1048 if (!input_setter || !event) {
1049 return;
1050 }
1051
1052 if (event->key() != Qt::Key_Escape) {
1053 if (want_keyboard_mouse) {
1054 SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
1055 false);
1056 } else {
1057 // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
1058 return;
1059 }
1060 }
1061
1062 SetPollingResult({}, true);
999} 1063}
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index c19aefffa..a5414e624 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -51,8 +51,11 @@ public:
51 /// Save all button configurations to settings file. 51 /// Save all button configurations to settings file.
52 void ApplyConfiguration(); 52 void ApplyConfiguration();
53 53
54 /// Set the connection state checkbox (used to sync state).
55 void ConnectPlayer(bool connected);
56
54 /// Update the input devices combobox. 57 /// Update the input devices combobox.
55 void UpdateInputDevices(); 58 void UpdateInputDeviceCombobox();
56 59
57 /// Restore all buttons to their default values. 60 /// Restore all buttons to their default values.
58 void RestoreDefaults(); 61 void RestoreDefaults();
@@ -60,9 +63,6 @@ public:
60 /// Clear all input configuration. 63 /// Clear all input configuration.
61 void ClearAll(); 64 void ClearAll();
62 65
63 /// Set the connection state checkbox (used to sync state).
64 void ConnectPlayer(bool connected);
65
66signals: 66signals:
67 /// Emitted when this controller is connected by the user. 67 /// Emitted when this controller is connected by the user.
68 void Connected(bool connected); 68 void Connected(bool connected);
@@ -89,6 +89,9 @@ private:
89 /// Finish polling and configure input using the input_setter. 89 /// Finish polling and configure input using the input_setter.
90 void SetPollingResult(const Common::ParamPackage& params, bool abort); 90 void SetPollingResult(const Common::ParamPackage& params, bool abort);
91 91
92 /// Checks whether a given input can be accepted.
93 bool IsInputAcceptable(const Common::ParamPackage& params) const;
94
92 /// Handle mouse button press events. 95 /// Handle mouse button press events.
93 void mousePressEvent(QMouseEvent* event) override; 96 void mousePressEvent(QMouseEvent* event) override;
94 97
@@ -98,8 +101,8 @@ private:
98 /// Update UI to reflect current configuration. 101 /// Update UI to reflect current configuration.
99 void UpdateUI(); 102 void UpdateUI();
100 103
101 /// Update the controller selection combobox 104 /// Update the available input devices.
102 void UpdateControllerCombobox(); 105 void UpdateInputDevices();
103 106
104 /// Update the current controller icon. 107 /// Update the current controller icon.
105 void UpdateControllerIcon(); 108 void UpdateControllerIcon();
@@ -164,7 +167,7 @@ private:
164 bool want_keyboard_mouse = false; 167 bool want_keyboard_mouse = false;
165 168
166 /// List of physical devices users can map with. If a SDL backed device is selected, then you 169 /// List of physical devices users can map with. If a SDL backed device is selected, then you
167 /// can usue this device to get a default mapping. 170 /// can use this device to get a default mapping.
168 std::vector<Common::ParamPackage> input_devices; 171 std::vector<Common::ParamPackage> input_devices;
169 172
170 /// Bottom row is where console wide settings are held, and its "owned" by the parent 173 /// Bottom row is where console wide settings are held, and its "owned" by the parent