Merge pull request #4594 from german77/MotionHID

hid/configuration: Implement motion controls to HID
This commit is contained in:
bunnei
2020-09-17 12:39:01 -07:00
committed by GitHub
23 changed files with 940 additions and 156 deletions

View File

@ -18,6 +18,7 @@
#include "core/hle/service/sm/sm.h"
#include "input_common/gcadapter/gc_poller.h"
#include "input_common/main.h"
#include "input_common/udp/udp.h"
#include "ui_configure_input_player.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configure_input_player.h"
@ -149,6 +150,14 @@ QString ButtonToText(const Common::ParamPackage& param) {
return GetKeyName(param.Get("code", 0));
}
if (param.Get("engine", "") == "cemuhookudp") {
if (param.Has("pad_index")) {
const QString motion_str = QString::fromStdString(param.Get("pad_index", ""));
return QObject::tr("Motion %1").arg(motion_str);
}
return GetKeyName(param.Get("code", 0));
}
if (param.Get("engine", "") == "sdl") {
if (param.Has("hat")) {
const QString hat_str = QString::fromStdString(param.Get("hat", ""));
@ -262,6 +271,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
},
}};
motion_map = {
ui->buttonMotionLeft,
ui->buttonMotionRight,
};
analog_map_deadzone_label = {ui->labelLStickDeadzone, ui->labelRStickDeadzone};
analog_map_deadzone_slider = {ui->sliderLStickDeadzone, ui->sliderRStickDeadzone};
analog_map_modifier_groupbox = {ui->buttonLStickModGroup, ui->buttonRStickModGroup};
@ -304,6 +318,32 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
Config::default_buttons[button_id]);
}
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
auto* const button = motion_map[motion_id];
if (button == nullptr) {
continue;
}
button->setContextMenuPolicy(Qt::CustomContextMenu);
connect(button, &QPushButton::clicked, [=, this] {
HandleClick(
motion_map[motion_id],
[=, this](Common::ParamPackage params) {
motions_param[motion_id] = std::move(params);
},
InputCommon::Polling::DeviceType::Motion);
});
connect(button, &QPushButton::customContextMenuRequested,
[=, this](const QPoint& menu_location) {
QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] {
motions_param[motion_id].Clear();
motion_map[motion_id]->setText(tr("[not set]"));
});
context_menu.exec(motion_map[motion_id]->mapToGlobal(menu_location));
});
}
// Handle clicks for the modifier buttons as well.
ConfigureButtonClick(ui->buttonLStickMod, &lstick_mod, Config::default_stick_mod[0]);
ConfigureButtonClick(ui->buttonRStickMod, &rstick_mod, Config::default_stick_mod[1]);
@ -385,9 +425,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
UpdateControllerIcon();
UpdateControllerAvailableButtons();
UpdateMotionButtons();
connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), [this](int) {
UpdateControllerIcon();
UpdateControllerAvailableButtons();
UpdateMotionButtons();
});
connect(ui->comboDevices, qOverload<int>(&QComboBox::currentIndexChanged), this,
@ -417,6 +459,13 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
return;
}
}
if (input_subsystem->GetUDPMotions()->IsPolling()) {
params = input_subsystem->GetUDPMotions()->GetNextInput();
if (params.Has("engine")) {
SetPollingResult(params, false);
return;
}
}
for (auto& poller : device_pollers) {
params = poller->GetNextInput();
if (params.Has("engine")) {
@ -448,6 +497,10 @@ void ConfigureInputPlayer::ApplyConfiguration() {
return;
}
auto& motions = player.motions;
std::transform(motions_param.begin(), motions_param.end(), motions.begin(),
[](const Common::ParamPackage& param) { return param.Serialize(); });
player.controller_type =
static_cast<Settings::ControllerType>(ui->comboControllerType->currentIndex());
player.connected = ui->groupConnectedController->isChecked();
@ -501,6 +554,8 @@ void ConfigureInputPlayer::LoadConfiguration() {
[](const std::string& str) { return Common::ParamPackage(str); });
std::transform(player.analogs.begin(), player.analogs.end(), analogs_param.begin(),
[](const std::string& str) { return Common::ParamPackage(str); });
std::transform(player.motions.begin(), player.motions.end(), motions_param.begin(),
[](const std::string& str) { return Common::ParamPackage(str); });
}
UpdateUI();
@ -544,6 +599,12 @@ void ConfigureInputPlayer::RestoreDefaults() {
SetAnalogParam(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
}
}
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
motions_param[motion_id] = Common::ParamPackage{
InputCommon::GenerateKeyboardParam(Config::default_motions[motion_id])};
}
UpdateUI();
UpdateInputDevices();
ui->comboControllerType->setCurrentIndex(0);
@ -573,6 +634,15 @@ void ConfigureInputPlayer::ClearAll() {
}
}
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
const auto* const button = motion_map[motion_id];
if (button == nullptr || !button->isEnabled()) {
continue;
}
motions_param[motion_id].Clear();
}
UpdateUI();
UpdateInputDevices();
}
@ -582,6 +652,10 @@ void ConfigureInputPlayer::UpdateUI() {
button_map[button]->setText(ButtonToText(buttons_param[button]));
}
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
motion_map[motion_id]->setText(ButtonToText(motions_param[motion_id]));
}
ui->buttonLStickMod->setText(ButtonToText(lstick_mod));
ui->buttonRStickMod->setText(ButtonToText(rstick_mod));
@ -659,7 +733,11 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
void ConfigureInputPlayer::HandleClick(
QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type) {
button->setText(tr("[waiting]"));
if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) {
button->setText(tr("Shake!"));
} else {
button->setText(tr("[waiting]"));
}
button->setFocus();
// The first two input devices are always Any and Keyboard/Mouse. If the user filtered to a
@ -683,6 +761,10 @@ void ConfigureInputPlayer::HandleClick(
input_subsystem->GetGCAnalogs()->BeginConfiguration();
}
if (type == InputCommon::Polling::DeviceType::Motion) {
input_subsystem->GetUDPMotions()->BeginConfiguration();
}
timeout_timer->start(2500); // Cancel after 2.5 seconds
poll_timer->start(50); // Check for new inputs every 50ms
}
@ -700,6 +782,8 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params,
input_subsystem->GetGCButtons()->EndConfiguration();
input_subsystem->GetGCAnalogs()->EndConfiguration();
input_subsystem->GetUDPMotions()->EndConfiguration();
if (!abort) {
(*input_setter)(params);
}
@ -832,6 +916,37 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
}
}
void ConfigureInputPlayer::UpdateMotionButtons() {
if (debug) {
// Motion isn't used with the debug controller, hide both groupboxes.
ui->buttonMotionLeftGroup->hide();
ui->buttonMotionRightGroup->hide();
return;
}
// Show/hide the "Motion 1/2" groupboxes depending on the currently selected controller.
switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) {
case Settings::ControllerType::ProController:
case Settings::ControllerType::LeftJoycon:
case Settings::ControllerType::Handheld:
// Show "Motion 1" and hide "Motion 2".
ui->buttonMotionLeftGroup->show();
ui->buttonMotionRightGroup->hide();
break;
case Settings::ControllerType::RightJoycon:
// Show "Motion 2" and hide "Motion 1".
ui->buttonMotionLeftGroup->hide();
ui->buttonMotionRightGroup->show();
break;
case Settings::ControllerType::DualJoyconDetached:
default:
// Show both "Motion 1/2".
ui->buttonMotionLeftGroup->show();
ui->buttonMotionRightGroup->show();
break;
}
}
void ConfigureInputPlayer::showEvent(QShowEvent* event) {
if (bottom_row == nullptr) {
return;