Merge pull request #7255 from german77/kraken

Project Kraken: Input rewrite
This commit is contained in:
Fernando S
2021-11-27 11:52:08 +01:00
committed by GitHub
146 changed files with 13935 additions and 11270 deletions

View File

@ -90,9 +90,6 @@ add_executable(yuzu
configuration/configure_motion_touch.cpp
configuration/configure_motion_touch.h
configuration/configure_motion_touch.ui
configuration/configure_mouse_advanced.cpp
configuration/configure_mouse_advanced.h
configuration/configure_mouse_advanced.ui
configuration/configure_per_game.cpp
configuration/configure_per_game.h
configuration/configure_per_game.ui

View File

@ -6,8 +6,12 @@
#include <thread>
#include "common/assert.h"
#include "common/param_package.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/lock.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/hid.h"
@ -23,49 +27,32 @@
namespace {
constexpr std::size_t HANDHELD_INDEX = 8;
constexpr std::array<std::array<bool, 4>, 8> led_patterns{{
{true, false, false, false},
{true, true, false, false},
{true, true, true, false},
{true, true, true, true},
{true, false, false, true},
{true, false, true, false},
{true, false, true, true},
{false, true, true, false},
}};
void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
bool connected, Core::System& system) {
if (!system.IsPoweredOn()) {
return;
void UpdateController(Core::HID::EmulatedController* controller,
Core::HID::NpadStyleIndex controller_type, bool connected) {
if (controller->IsConnected(true)) {
controller->Disconnect();
}
controller->SetNpadStyleIndex(controller_type);
if (connected) {
controller->Connect();
}
auto& npad =
system.ServiceManager()
.GetService<Service::HID::Hid>("hid")
->GetAppletResource()
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected);
}
// Returns true if the given controller type is compatible with the given parameters.
bool IsControllerCompatible(Settings::ControllerType controller_type,
bool IsControllerCompatible(Core::HID::NpadStyleIndex controller_type,
Core::Frontend::ControllerParameters parameters) {
switch (controller_type) {
case Settings::ControllerType::ProController:
case Core::HID::NpadStyleIndex::ProController:
return parameters.allow_pro_controller;
case Settings::ControllerType::DualJoyconDetached:
case Core::HID::NpadStyleIndex::JoyconDual:
return parameters.allow_dual_joycons;
case Settings::ControllerType::LeftJoycon:
case Core::HID::NpadStyleIndex::JoyconLeft:
return parameters.allow_left_joycon;
case Settings::ControllerType::RightJoycon:
case Core::HID::NpadStyleIndex::JoyconRight:
return parameters.allow_right_joycon;
case Settings::ControllerType::Handheld:
case Core::HID::NpadStyleIndex::Handheld:
return parameters.enable_single_mode && parameters.allow_handheld;
case Settings::ControllerType::GameCube:
case Core::HID::NpadStyleIndex::GameCube:
return parameters.allow_gamecube_controller;
default:
return false;
@ -152,6 +139,7 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
DisableUnsupportedPlayers();
for (std::size_t player_index = 0; player_index < NUM_PLAYERS; ++player_index) {
system.HIDCore().GetEmulatedControllerByIndex(player_index)->EnableConfiguration();
SetEmulatedControllers(player_index);
}
@ -196,7 +184,7 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
[this, i](int index) {
UpdateDockedState(GetControllerTypeFromIndex(index, i) ==
Settings::ControllerType::Handheld);
Core::HID::NpadStyleIndex::Handheld);
});
}
}
@ -246,20 +234,24 @@ void QtControllerSelectorDialog::ApplyConfiguration() {
Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked());
Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked());
for (std::size_t player_index = 0; player_index < NUM_PLAYERS; ++player_index) {
system.HIDCore().GetEmulatedControllerByIndex(player_index)->DisableConfiguration();
}
}
void QtControllerSelectorDialog::LoadConfiguration() {
const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index);
const auto connected =
Settings::values.players.GetValue()[index].connected ||
(index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected);
controller->IsConnected(true) || (index == 0 && handheld->IsConnected(true));
player_groupboxes[index]->setChecked(connected);
connected_controller_checkboxes[index]->setChecked(connected);
emulated_controllers[index]->setCurrentIndex(GetIndexFromControllerType(
Settings::values.players.GetValue()[index].controller_type, index));
emulated_controllers[index]->setCurrentIndex(
GetIndexFromControllerType(controller->GetNpadStyleIndex(true), index));
}
UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected);
UpdateDockedState(handheld->IsConnected(true));
ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
@ -415,33 +407,33 @@ void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index
emulated_controllers[player_index]->clear();
pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::ProController);
Core::HID::NpadStyleIndex::ProController);
emulated_controllers[player_index]->addItem(tr("Pro Controller"));
pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::DualJoyconDetached);
Core::HID::NpadStyleIndex::JoyconDual);
emulated_controllers[player_index]->addItem(tr("Dual Joycons"));
pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::LeftJoycon);
Core::HID::NpadStyleIndex::JoyconLeft);
emulated_controllers[player_index]->addItem(tr("Left Joycon"));
pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::RightJoycon);
Core::HID::NpadStyleIndex::JoyconRight);
emulated_controllers[player_index]->addItem(tr("Right Joycon"));
if (player_index == 0) {
pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::Handheld);
Core::HID::NpadStyleIndex::Handheld);
emulated_controllers[player_index]->addItem(tr("Handheld"));
}
pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::GameCube);
Core::HID::NpadStyleIndex::GameCube);
emulated_controllers[player_index]->addItem(tr("GameCube Controller"));
}
Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex(
Core::HID::NpadStyleIndex QtControllerSelectorDialog::GetControllerTypeFromIndex(
int index, std::size_t player_index) const {
const auto& pairs = index_controller_type_pairs[player_index];
@ -449,13 +441,13 @@ Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex(
[index](const auto& pair) { return pair.first == index; });
if (it == pairs.end()) {
return Settings::ControllerType::ProController;
return Core::HID::NpadStyleIndex::ProController;
}
return it->second;
}
int QtControllerSelectorDialog::GetIndexFromControllerType(Settings::ControllerType type,
int QtControllerSelectorDialog::GetIndexFromControllerType(Core::HID::NpadStyleIndex type,
std::size_t player_index) const {
const auto& pairs = index_controller_type_pairs[player_index];
@ -479,16 +471,16 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
const QString stylesheet = [this, player_index] {
switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
player_index)) {
case Settings::ControllerType::ProController:
case Settings::ControllerType::GameCube:
case Core::HID::NpadStyleIndex::ProController:
case Core::HID::NpadStyleIndex::GameCube:
return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
case Settings::ControllerType::DualJoyconDetached:
case Core::HID::NpadStyleIndex::JoyconDual:
return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ");
case Settings::ControllerType::LeftJoycon:
case Core::HID::NpadStyleIndex::JoyconLeft:
return QStringLiteral("image: url(:/controller/applet_joycon_left%0); ");
case Settings::ControllerType::RightJoycon:
case Core::HID::NpadStyleIndex::JoyconRight:
return QStringLiteral("image: url(:/controller/applet_joycon_right%0); ");
case Settings::ControllerType::Handheld:
case Core::HID::NpadStyleIndex::Handheld:
return QStringLiteral("image: url(:/controller/applet_handheld%0); ");
default:
return QString{};
@ -516,54 +508,38 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
}
void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) {
auto& player = Settings::values.players.GetValue()[player_index];
auto* controller = system.HIDCore().GetEmulatedControllerByIndex(player_index);
const auto controller_type = GetControllerTypeFromIndex(
emulated_controllers[player_index]->currentIndex(), player_index);
const auto player_connected = player_groupboxes[player_index]->isChecked() &&
controller_type != Settings::ControllerType::Handheld;
controller_type != Core::HID::NpadStyleIndex::Handheld;
if (player.controller_type == controller_type && player.connected == player_connected) {
// Set vibration devices in the event that the input device has changed.
ConfigureVibration::SetVibrationDevices(player_index);
if (controller->GetNpadStyleIndex(true) == controller_type &&
controller->IsConnected(true) == player_connected) {
return;
}
// Disconnect the controller first.
UpdateController(controller_type, player_index, false, system);
player.controller_type = controller_type;
player.connected = player_connected;
ConfigureVibration::SetVibrationDevices(player_index);
UpdateController(controller, controller_type, false);
// Handheld
if (player_index == 0) {
auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX];
if (controller_type == Settings::ControllerType::Handheld) {
handheld = player;
if (controller_type == Core::HID::NpadStyleIndex::Handheld) {
auto* handheld =
system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
UpdateController(handheld, Core::HID::NpadStyleIndex::Handheld,
player_groupboxes[player_index]->isChecked());
}
handheld.connected = player_groupboxes[player_index]->isChecked() &&
controller_type == Settings::ControllerType::Handheld;
UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected, system);
}
if (!player.connected) {
return;
}
// This emulates a delay between disconnecting and reconnecting controllers as some games
// do not respond to a change in controller type if it was instantaneous.
using namespace std::chrono_literals;
std::this_thread::sleep_for(60ms);
UpdateController(controller_type, player_index, player_connected, system);
UpdateController(controller, controller_type, player_connected);
}
void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
if (!player_groupboxes[player_index]->isChecked() ||
GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
player_index) == Settings::ControllerType::Handheld) {
player_index) == Core::HID::NpadStyleIndex::Handheld) {
led_patterns_boxes[player_index][0]->setChecked(false);
led_patterns_boxes[player_index][1]->setChecked(false);
led_patterns_boxes[player_index][2]->setChecked(false);
@ -571,10 +547,12 @@ void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
return;
}
led_patterns_boxes[player_index][0]->setChecked(led_patterns[player_index][0]);
led_patterns_boxes[player_index][1]->setChecked(led_patterns[player_index][1]);
led_patterns_boxes[player_index][2]->setChecked(led_patterns[player_index][2]);
led_patterns_boxes[player_index][3]->setChecked(led_patterns[player_index][3]);
const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(player_index);
const auto led_pattern = controller->GetLedPattern();
led_patterns_boxes[player_index][0]->setChecked(led_pattern.position1);
led_patterns_boxes[player_index][1]->setChecked(led_pattern.position2);
led_patterns_boxes[player_index][2]->setChecked(led_pattern.position3);
led_patterns_boxes[player_index][3]->setChecked(led_pattern.position4);
}
void QtControllerSelectorDialog::UpdateBorderColor(std::size_t player_index) {
@ -654,10 +632,9 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() {
}
for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) {
auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index);
// Disconnect any unsupported players here and disable or hide them if applicable.
Settings::values.players.GetValue()[index].connected = false;
UpdateController(Settings::values.players.GetValue()[index].controller_type, index, false,
system);
UpdateController(controller, controller->GetNpadStyleIndex(true), false);
// Hide the player widgets when max_supported_controllers is less than or equal to 4.
if (max_supported_players <= 4) {
player_widgets[index]->hide();

View File

@ -23,14 +23,18 @@ namespace InputCommon {
class InputSubsystem;
}
namespace Settings {
enum class ControllerType;
}
namespace Ui {
class QtControllerSelectorDialog;
}
namespace Core {
class System;
}
namespace Core::HID {
enum class NpadStyleIndex : u8;
}
class QtControllerSelectorDialog final : public QDialog {
Q_OBJECT
@ -70,10 +74,10 @@ private:
void SetEmulatedControllers(std::size_t player_index);
// Gets the Controller Type for a given controller combobox index per player.
Settings::ControllerType GetControllerTypeFromIndex(int index, std::size_t player_index) const;
Core::HID::NpadStyleIndex GetControllerTypeFromIndex(int index, std::size_t player_index) const;
// Gets the controller combobox index for a given Controller Type per player.
int GetIndexFromControllerType(Settings::ControllerType type, std::size_t player_index) const;
int GetIndexFromControllerType(Core::HID::NpadStyleIndex type, std::size_t player_index) const;
// Updates the controller icons per player.
void UpdateControllerIcon(std::size_t player_index);
@ -135,7 +139,7 @@ private:
std::array<QComboBox*, NUM_PLAYERS> emulated_controllers;
/// Pairs of emulated controller index and Controller Type enum per player.
std::array<std::vector<std::pair<int, Settings::ControllerType>>, NUM_PLAYERS>
std::array<std::vector<std::pair<int, Core::HID::NpadStyleIndex>>, NUM_PLAYERS>
index_controller_type_pairs;
// Labels representing the number of connected controllers

View File

@ -10,7 +10,10 @@
#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/frontend/input_interpreter.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hid/input_interpreter.h"
#include "ui_qt_software_keyboard.h"
#include "yuzu/applets/qt_software_keyboard.h"
#include "yuzu/main.h"
@ -484,7 +487,7 @@ void QtSoftwareKeyboardDialog::open() {
void QtSoftwareKeyboardDialog::reject() {
// Pressing the ESC key in a dialog calls QDialog::reject().
// We will override this behavior to the "Cancel" action on the software keyboard.
TranslateButtonPress(HIDButton::X);
TranslateButtonPress(Core::HID::NpadButton::X);
}
void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) {
@ -722,7 +725,7 @@ void QtSoftwareKeyboardDialog::SetTextDrawType() {
connect(
ui->line_edit_osk, &QLineEdit::returnPressed, this,
[this] { TranslateButtonPress(HIDButton::Plus); }, Qt::QueuedConnection);
[this] { TranslateButtonPress(Core::HID::NpadButton::Plus); }, Qt::QueuedConnection);
ui->line_edit_osk->setPlaceholderText(
QString::fromStdU16String(initialize_parameters.guide_text));
@ -795,9 +798,10 @@ void QtSoftwareKeyboardDialog::SetTextDrawType() {
}
void QtSoftwareKeyboardDialog::SetControllerImage() {
const auto controller_type = Settings::values.players.GetValue()[8].connected
? Settings::values.players.GetValue()[8].controller_type
: Settings::values.players.GetValue()[0].controller_type;
const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
const auto* player_1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
const auto controller_type =
handheld->IsConnected() ? handheld->GetNpadStyleIndex() : player_1->GetNpadStyleIndex();
const QString theme = [] {
if (QIcon::themeName().contains(QStringLiteral("dark")) ||
@ -809,8 +813,8 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
}();
switch (controller_type) {
case Settings::ControllerType::ProController:
case Settings::ControllerType::GameCube:
case Core::HID::NpadStyleIndex::ProController:
case Core::HID::NpadStyleIndex::GameCube:
ui->icon_controller->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));
ui->icon_controller_shift->setStyleSheet(
@ -818,7 +822,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
ui->icon_controller_num->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));
break;
case Settings::ControllerType::DualJoyconDetached:
case Core::HID::NpadStyleIndex::JoyconDual:
ui->icon_controller->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme));
ui->icon_controller_shift->setStyleSheet(
@ -826,7 +830,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
ui->icon_controller_num->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme));
break;
case Settings::ControllerType::LeftJoycon:
case Core::HID::NpadStyleIndex::JoyconLeft:
ui->icon_controller->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);")
.arg(theme));
@ -837,7 +841,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);")
.arg(theme));
break;
case Settings::ControllerType::RightJoycon:
case Core::HID::NpadStyleIndex::JoyconRight:
ui->icon_controller->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);")
.arg(theme));
@ -848,7 +852,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);")
.arg(theme));
break;
case Settings::ControllerType::Handheld:
case Core::HID::NpadStyleIndex::Handheld:
ui->icon_controller->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme));
ui->icon_controller_shift->setStyleSheet(
@ -1208,9 +1212,9 @@ void QtSoftwareKeyboardDialog::SetupMouseHover() {
}
}
template <HIDButton... T>
template <Core::HID::NpadButton... T>
void QtSoftwareKeyboardDialog::HandleButtonPressedOnce() {
const auto f = [this](HIDButton button) {
const auto f = [this](Core::HID::NpadButton button) {
if (input_interpreter->IsButtonPressedOnce(button)) {
TranslateButtonPress(button);
}
@ -1219,9 +1223,9 @@ void QtSoftwareKeyboardDialog::HandleButtonPressedOnce() {
(f(T), ...);
}
template <HIDButton... T>
template <Core::HID::NpadButton... T>
void QtSoftwareKeyboardDialog::HandleButtonHold() {
const auto f = [this](HIDButton button) {
const auto f = [this](Core::HID::NpadButton button) {
if (input_interpreter->IsButtonHeld(button)) {
TranslateButtonPress(button);
}
@ -1230,9 +1234,9 @@ void QtSoftwareKeyboardDialog::HandleButtonHold() {
(f(T), ...);
}
void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
void QtSoftwareKeyboardDialog::TranslateButtonPress(Core::HID::NpadButton button) {
switch (button) {
case HIDButton::A:
case Core::HID::NpadButton::A:
switch (bottom_osk_index) {
case BottomOSKIndex::LowerCase:
case BottomOSKIndex::UpperCase:
@ -1245,7 +1249,7 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
break;
}
break;
case HIDButton::B:
case Core::HID::NpadButton::B:
switch (bottom_osk_index) {
case BottomOSKIndex::LowerCase:
ui->button_backspace->click();
@ -1260,7 +1264,7 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
break;
}
break;
case HIDButton::X:
case Core::HID::NpadButton::X:
if (is_inline) {
emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position);
} else {
@ -1271,7 +1275,7 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
emit SubmitNormalText(SwkbdResult::Cancel, std::move(text));
}
break;
case HIDButton::Y:
case Core::HID::NpadButton::Y:
switch (bottom_osk_index) {
case BottomOSKIndex::LowerCase:
ui->button_space->click();
@ -1284,8 +1288,8 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
break;
}
break;
case HIDButton::LStick:
case HIDButton::RStick:
case Core::HID::NpadButton::StickL:
case Core::HID::NpadButton::StickR:
switch (bottom_osk_index) {
case BottomOSKIndex::LowerCase:
ui->button_shift->click();
@ -1298,13 +1302,13 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
break;
}
break;
case HIDButton::L:
case Core::HID::NpadButton::L:
MoveTextCursorDirection(Direction::Left);
break;
case HIDButton::R:
case Core::HID::NpadButton::R:
MoveTextCursorDirection(Direction::Right);
break;
case HIDButton::Plus:
case Core::HID::NpadButton::Plus:
switch (bottom_osk_index) {
case BottomOSKIndex::LowerCase:
ui->button_ok->click();
@ -1319,24 +1323,24 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
break;
}
break;
case HIDButton::DLeft:
case HIDButton::LStickLeft:
case HIDButton::RStickLeft:
case Core::HID::NpadButton::Left:
case Core::HID::NpadButton::StickLLeft:
case Core::HID::NpadButton::StickRLeft:
MoveButtonDirection(Direction::Left);
break;
case HIDButton::DUp:
case HIDButton::LStickUp:
case HIDButton::RStickUp:
case Core::HID::NpadButton::Up:
case Core::HID::NpadButton::StickLUp:
case Core::HID::NpadButton::StickRUp:
MoveButtonDirection(Direction::Up);
break;
case HIDButton::DRight:
case HIDButton::LStickRight:
case HIDButton::RStickRight:
case Core::HID::NpadButton::Right:
case Core::HID::NpadButton::StickLRight:
case Core::HID::NpadButton::StickRRight:
MoveButtonDirection(Direction::Right);
break;
case HIDButton::DDown:
case HIDButton::LStickDown:
case HIDButton::RStickDown:
case Core::HID::NpadButton::Down:
case Core::HID::NpadButton::StickLDown:
case Core::HID::NpadButton::StickRDown:
MoveButtonDirection(Direction::Down);
break;
default:
@ -1467,19 +1471,25 @@ void QtSoftwareKeyboardDialog::InputThread() {
while (input_thread_running) {
input_interpreter->PollInput();
HandleButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::X, HIDButton::Y,
HIDButton::LStick, HIDButton::RStick, HIDButton::L, HIDButton::R,
HIDButton::Plus, HIDButton::DLeft, HIDButton::DUp,
HIDButton::DRight, HIDButton::DDown, HIDButton::LStickLeft,
HIDButton::LStickUp, HIDButton::LStickRight, HIDButton::LStickDown,
HIDButton::RStickLeft, HIDButton::RStickUp, HIDButton::RStickRight,
HIDButton::RStickDown>();
HandleButtonPressedOnce<
Core::HID::NpadButton::A, Core::HID::NpadButton::B, Core::HID::NpadButton::X,
Core::HID::NpadButton::Y, Core::HID::NpadButton::StickL, Core::HID::NpadButton::StickR,
Core::HID::NpadButton::L, Core::HID::NpadButton::R, Core::HID::NpadButton::Plus,
Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right,
Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft,
Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight,
Core::HID::NpadButton::StickLDown, Core::HID::NpadButton::StickRLeft,
Core::HID::NpadButton::StickRUp, Core::HID::NpadButton::StickRRight,
Core::HID::NpadButton::StickRDown>();
HandleButtonHold<HIDButton::B, HIDButton::L, HIDButton::R, HIDButton::DLeft, HIDButton::DUp,
HIDButton::DRight, HIDButton::DDown, HIDButton::LStickLeft,
HIDButton::LStickUp, HIDButton::LStickRight, HIDButton::LStickDown,
HIDButton::RStickLeft, HIDButton::RStickUp, HIDButton::RStickRight,
HIDButton::RStickDown>();
HandleButtonHold<Core::HID::NpadButton::B, Core::HID::NpadButton::L,
Core::HID::NpadButton::R, Core::HID::NpadButton::Left,
Core::HID::NpadButton::Up, Core::HID::NpadButton::Right,
Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft,
Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight,
Core::HID::NpadButton::StickLDown, Core::HID::NpadButton::StickRLeft,
Core::HID::NpadButton::StickRUp, Core::HID::NpadButton::StickRRight,
Core::HID::NpadButton::StickRDown>();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}

View File

@ -14,14 +14,16 @@
#include "core/frontend/applets/software_keyboard.h"
enum class HIDButton : u8;
class InputInterpreter;
namespace Core {
class System;
}
namespace Core::HID {
enum class NpadButton : u64;
}
namespace Ui {
class QtSoftwareKeyboardDialog;
}
@ -146,7 +148,7 @@ private:
*
* @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/
template <HIDButton... T>
template <Core::HID::NpadButton... T>
void HandleButtonPressedOnce();
/**
@ -154,7 +156,7 @@ private:
*
* @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/
template <HIDButton... T>
template <Core::HID::NpadButton... T>
void HandleButtonHold();
/**
@ -162,7 +164,7 @@ private:
*
* @param button The button press to process.
*/
void TranslateButtonPress(HIDButton button);
void TranslateButtonPress(Core::HID::NpadButton button);
/**
* Moves the focus of a button in a certain direction.

View File

@ -14,9 +14,11 @@
#endif
#include "common/fs/path_util.h"
#include "common/param_package.h"
#include "core/core.h"
#include "core/frontend/input_interpreter.h"
#include "input_common/keyboard.h"
#include "core/hid/hid_types.h"
#include "core/hid/input_interpreter.h"
#include "input_common/drivers/keyboard.h"
#include "input_common/main.h"
#include "yuzu/applets/qt_web_browser.h"
#include "yuzu/applets/qt_web_browser_scripts.h"
@ -27,19 +29,19 @@
namespace {
constexpr int HIDButtonToKey(HIDButton button) {
constexpr int HIDButtonToKey(Core::HID::NpadButton button) {
switch (button) {
case HIDButton::DLeft:
case HIDButton::LStickLeft:
case Core::HID::NpadButton::Left:
case Core::HID::NpadButton::StickLLeft:
return Qt::Key_Left;
case HIDButton::DUp:
case HIDButton::LStickUp:
case Core::HID::NpadButton::Up:
case Core::HID::NpadButton::StickLUp:
return Qt::Key_Up;
case HIDButton::DRight:
case HIDButton::LStickRight:
case Core::HID::NpadButton::Right:
case Core::HID::NpadButton::StickLRight:
return Qt::Key_Right;
case HIDButton::DDown:
case HIDButton::LStickDown:
case Core::HID::NpadButton::Down:
case Core::HID::NpadButton::StickLDown:
return Qt::Key_Down;
default:
return 0;
@ -208,25 +210,25 @@ void QtNXWebEngineView::keyReleaseEvent(QKeyEvent* event) {
}
}
template <HIDButton... T>
template <Core::HID::NpadButton... T>
void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() {
const auto f = [this](HIDButton button) {
const auto f = [this](Core::HID::NpadButton button) {
if (input_interpreter->IsButtonPressedOnce(button)) {
page()->runJavaScript(
QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast<u8>(button)),
[this, button](const QVariant& variant) {
if (variant.toBool()) {
switch (button) {
case HIDButton::A:
case Core::HID::NpadButton::A:
SendMultipleKeyPressEvents<Qt::Key_A, Qt::Key_Space, Qt::Key_Return>();
break;
case HIDButton::B:
case Core::HID::NpadButton::B:
SendKeyPressEvent(Qt::Key_B);
break;
case HIDButton::X:
case Core::HID::NpadButton::X:
SendKeyPressEvent(Qt::Key_X);
break;
case HIDButton::Y:
case Core::HID::NpadButton::Y:
SendKeyPressEvent(Qt::Key_Y);
break;
default:
@ -244,9 +246,9 @@ void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() {
(f(T), ...);
}
template <HIDButton... T>
template <Core::HID::NpadButton... T>
void QtNXWebEngineView::HandleWindowKeyButtonPressedOnce() {
const auto f = [this](HIDButton button) {
const auto f = [this](Core::HID::NpadButton button) {
if (input_interpreter->IsButtonPressedOnce(button)) {
SendKeyPressEvent(HIDButtonToKey(button));
}
@ -255,9 +257,9 @@ void QtNXWebEngineView::HandleWindowKeyButtonPressedOnce() {
(f(T), ...);
}
template <HIDButton... T>
template <Core::HID::NpadButton... T>
void QtNXWebEngineView::HandleWindowKeyButtonHold() {
const auto f = [this](HIDButton button) {
const auto f = [this](Core::HID::NpadButton button) {
if (input_interpreter->IsButtonHeld(button)) {
SendKeyPressEvent(HIDButtonToKey(button));
}
@ -308,17 +310,21 @@ void QtNXWebEngineView::InputThread() {
while (input_thread_running) {
input_interpreter->PollInput();
HandleWindowFooterButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::X, HIDButton::Y,
HIDButton::L, HIDButton::R>();
HandleWindowFooterButtonPressedOnce<Core::HID::NpadButton::A, Core::HID::NpadButton::B,
Core::HID::NpadButton::X, Core::HID::NpadButton::Y,
Core::HID::NpadButton::L, Core::HID::NpadButton::R>();
HandleWindowKeyButtonPressedOnce<HIDButton::DLeft, HIDButton::DUp, HIDButton::DRight,
HIDButton::DDown, HIDButton::LStickLeft,
HIDButton::LStickUp, HIDButton::LStickRight,
HIDButton::LStickDown>();
HandleWindowKeyButtonPressedOnce<
Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right,
Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft,
Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight,
Core::HID::NpadButton::StickLDown>();
HandleWindowKeyButtonHold<HIDButton::DLeft, HIDButton::DUp, HIDButton::DRight,
HIDButton::DDown, HIDButton::LStickLeft, HIDButton::LStickUp,
HIDButton::LStickRight, HIDButton::LStickDown>();
HandleWindowKeyButtonHold<
Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right,
Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft,
Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight,
Core::HID::NpadButton::StickLDown>();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}

View File

@ -16,8 +16,6 @@
#include "core/frontend/applets/web_browser.h"
enum class HIDButton : u8;
class GMainWindow;
class InputInterpreter;
class UrlRequestInterceptor;
@ -26,6 +24,10 @@ namespace Core {
class System;
}
namespace Core::HID {
enum class NpadButton : u64;
}
namespace InputCommon {
class InputSubsystem;
}
@ -114,7 +116,7 @@ private:
*
* @tparam HIDButton The list of buttons contained in yuzu_key_callbacks
*/
template <HIDButton... T>
template <Core::HID::NpadButton... T>
void HandleWindowFooterButtonPressedOnce();
/**
@ -123,7 +125,7 @@ private:
*
* @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/
template <HIDButton... T>
template <Core::HID::NpadButton... T>
void HandleWindowKeyButtonPressedOnce();
/**
@ -132,7 +134,7 @@ private:
*
* @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/
template <HIDButton... T>
template <Core::HID::NpadButton... T>
void HandleWindowKeyButtonHold();
/**

View File

@ -32,10 +32,11 @@
#include "common/settings.h"
#include "core/core.h"
#include "core/frontend/framebuffer_layout.h"
#include "input_common/keyboard.h"
#include "input_common/drivers/keyboard.h"
#include "input_common/drivers/mouse.h"
#include "input_common/drivers/tas_input.h"
#include "input_common/drivers/touch_screen.h"
#include "input_common/main.h"
#include "input_common/mouse/mouse_input.h"
#include "input_common/tas/tas_input.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
#include "yuzu/bootmanager.h"
@ -296,7 +297,6 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
input_subsystem->Initialize();
this->setMouseTracking(true);
connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
@ -320,7 +320,8 @@ GRenderWindow::~GRenderWindow() {
void GRenderWindow::OnFrameDisplayed() {
input_subsystem->GetTas()->UpdateThread();
const TasInput::TasState new_tas_state = std::get<0>(input_subsystem->GetTas()->GetStatus());
const InputCommon::TasInput::TasState new_tas_state =
std::get<0>(input_subsystem->GetTas()->GetStatus());
if (!first_frame) {
last_tas_state = new_tas_state;
@ -392,34 +393,329 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
QWidget::closeEvent(event);
}
int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) {
switch (qt_key) {
case Qt::Key_A:
return Settings::NativeKeyboard::A;
case Qt::Key_B:
return Settings::NativeKeyboard::B;
case Qt::Key_C:
return Settings::NativeKeyboard::C;
case Qt::Key_D:
return Settings::NativeKeyboard::D;
case Qt::Key_E:
return Settings::NativeKeyboard::E;
case Qt::Key_F:
return Settings::NativeKeyboard::F;
case Qt::Key_G:
return Settings::NativeKeyboard::G;
case Qt::Key_H:
return Settings::NativeKeyboard::H;
case Qt::Key_I:
return Settings::NativeKeyboard::I;
case Qt::Key_J:
return Settings::NativeKeyboard::J;
case Qt::Key_K:
return Settings::NativeKeyboard::K;
case Qt::Key_L:
return Settings::NativeKeyboard::L;
case Qt::Key_M:
return Settings::NativeKeyboard::M;
case Qt::Key_N:
return Settings::NativeKeyboard::N;
case Qt::Key_O:
return Settings::NativeKeyboard::O;
case Qt::Key_P:
return Settings::NativeKeyboard::P;
case Qt::Key_Q:
return Settings::NativeKeyboard::Q;
case Qt::Key_R:
return Settings::NativeKeyboard::R;
case Qt::Key_S:
return Settings::NativeKeyboard::S;
case Qt::Key_T:
return Settings::NativeKeyboard::T;
case Qt::Key_U:
return Settings::NativeKeyboard::U;
case Qt::Key_V:
return Settings::NativeKeyboard::V;
case Qt::Key_W:
return Settings::NativeKeyboard::W;
case Qt::Key_X:
return Settings::NativeKeyboard::X;
case Qt::Key_Y:
return Settings::NativeKeyboard::Y;
case Qt::Key_Z:
return Settings::NativeKeyboard::Z;
case Qt::Key_1:
return Settings::NativeKeyboard::N1;
case Qt::Key_2:
return Settings::NativeKeyboard::N2;
case Qt::Key_3:
return Settings::NativeKeyboard::N3;
case Qt::Key_4:
return Settings::NativeKeyboard::N4;
case Qt::Key_5:
return Settings::NativeKeyboard::N5;
case Qt::Key_6:
return Settings::NativeKeyboard::N6;
case Qt::Key_7:
return Settings::NativeKeyboard::N7;
case Qt::Key_8:
return Settings::NativeKeyboard::N8;
case Qt::Key_9:
return Settings::NativeKeyboard::N9;
case Qt::Key_0:
return Settings::NativeKeyboard::N0;
case Qt::Key_Return:
return Settings::NativeKeyboard::Return;
case Qt::Key_Escape:
return Settings::NativeKeyboard::Escape;
case Qt::Key_Backspace:
return Settings::NativeKeyboard::Backspace;
case Qt::Key_Tab:
return Settings::NativeKeyboard::Tab;
case Qt::Key_Space:
return Settings::NativeKeyboard::Space;
case Qt::Key_Minus:
return Settings::NativeKeyboard::Minus;
case Qt::Key_Plus:
case Qt::Key_questiondown:
return Settings::NativeKeyboard::Plus;
case Qt::Key_BracketLeft:
case Qt::Key_BraceLeft:
return Settings::NativeKeyboard::OpenBracket;
case Qt::Key_BracketRight:
case Qt::Key_BraceRight:
return Settings::NativeKeyboard::CloseBracket;
case Qt::Key_Bar:
return Settings::NativeKeyboard::Pipe;
case Qt::Key_Dead_Tilde:
return Settings::NativeKeyboard::Tilde;
case Qt::Key_Ntilde:
case Qt::Key_Semicolon:
return Settings::NativeKeyboard::Semicolon;
case Qt::Key_Apostrophe:
return Settings::NativeKeyboard::Quote;
case Qt::Key_Dead_Grave:
return Settings::NativeKeyboard::Backquote;
case Qt::Key_Comma:
return Settings::NativeKeyboard::Comma;
case Qt::Key_Period:
return Settings::NativeKeyboard::Period;
case Qt::Key_Slash:
return Settings::NativeKeyboard::Slash;
case Qt::Key_CapsLock:
return Settings::NativeKeyboard::CapsLock;
case Qt::Key_F1:
return Settings::NativeKeyboard::F1;
case Qt::Key_F2:
return Settings::NativeKeyboard::F2;
case Qt::Key_F3:
return Settings::NativeKeyboard::F3;
case Qt::Key_F4:
return Settings::NativeKeyboard::F4;
case Qt::Key_F5:
return Settings::NativeKeyboard::F5;
case Qt::Key_F6:
return Settings::NativeKeyboard::F6;
case Qt::Key_F7:
return Settings::NativeKeyboard::F7;
case Qt::Key_F8:
return Settings::NativeKeyboard::F8;
case Qt::Key_F9:
return Settings::NativeKeyboard::F9;
case Qt::Key_F10:
return Settings::NativeKeyboard::F10;
case Qt::Key_F11:
return Settings::NativeKeyboard::F11;
case Qt::Key_F12:
return Settings::NativeKeyboard::F12;
case Qt::Key_Print:
return Settings::NativeKeyboard::PrintScreen;
case Qt::Key_ScrollLock:
return Settings::NativeKeyboard::ScrollLock;
case Qt::Key_Pause:
return Settings::NativeKeyboard::Pause;
case Qt::Key_Insert:
return Settings::NativeKeyboard::Insert;
case Qt::Key_Home:
return Settings::NativeKeyboard::Home;
case Qt::Key_PageUp:
return Settings::NativeKeyboard::PageUp;
case Qt::Key_Delete:
return Settings::NativeKeyboard::Delete;
case Qt::Key_End:
return Settings::NativeKeyboard::End;
case Qt::Key_PageDown:
return Settings::NativeKeyboard::PageDown;
case Qt::Key_Right:
return Settings::NativeKeyboard::Right;
case Qt::Key_Left:
return Settings::NativeKeyboard::Left;
case Qt::Key_Down:
return Settings::NativeKeyboard::Down;
case Qt::Key_Up:
return Settings::NativeKeyboard::Up;
case Qt::Key_NumLock:
return Settings::NativeKeyboard::NumLock;
// Numpad keys are missing here
case Qt::Key_F13:
return Settings::NativeKeyboard::F13;
case Qt::Key_F14:
return Settings::NativeKeyboard::F14;
case Qt::Key_F15:
return Settings::NativeKeyboard::F15;
case Qt::Key_F16:
return Settings::NativeKeyboard::F16;
case Qt::Key_F17:
return Settings::NativeKeyboard::F17;
case Qt::Key_F18:
return Settings::NativeKeyboard::F18;
case Qt::Key_F19:
return Settings::NativeKeyboard::F19;
case Qt::Key_F20:
return Settings::NativeKeyboard::F20;
case Qt::Key_F21:
return Settings::NativeKeyboard::F21;
case Qt::Key_F22:
return Settings::NativeKeyboard::F22;
case Qt::Key_F23:
return Settings::NativeKeyboard::F23;
case Qt::Key_F24:
return Settings::NativeKeyboard::F24;
// case Qt:::
// return Settings::NativeKeyboard::KPComma;
// case Qt:::
// return Settings::NativeKeyboard::Ro;
case Qt::Key_Hiragana_Katakana:
return Settings::NativeKeyboard::KatakanaHiragana;
case Qt::Key_yen:
return Settings::NativeKeyboard::Yen;
case Qt::Key_Henkan:
return Settings::NativeKeyboard::Henkan;
case Qt::Key_Muhenkan:
return Settings::NativeKeyboard::Muhenkan;
// case Qt:::
// return Settings::NativeKeyboard::NumPadCommaPc98;
case Qt::Key_Hangul:
return Settings::NativeKeyboard::HangulEnglish;
case Qt::Key_Hangul_Hanja:
return Settings::NativeKeyboard::Hanja;
case Qt::Key_Katakana:
return Settings::NativeKeyboard::KatakanaKey;
case Qt::Key_Hiragana:
return Settings::NativeKeyboard::HiraganaKey;
case Qt::Key_Zenkaku_Hankaku:
return Settings::NativeKeyboard::ZenkakuHankaku;
// Modifier keys are handled by the modifier property
default:
return Settings::NativeKeyboard::None;
}
}
int GRenderWindow::QtModifierToSwitchModifier(Qt::KeyboardModifiers qt_modifiers) {
int modifier = 0;
if ((qt_modifiers & Qt::KeyboardModifier::ShiftModifier) != 0) {
modifier |= 1 << Settings::NativeKeyboard::LeftShift;
}
if ((qt_modifiers & Qt::KeyboardModifier::ControlModifier) != 0) {
modifier |= 1 << Settings::NativeKeyboard::LeftControl;
}
if ((qt_modifiers & Qt::KeyboardModifier::AltModifier) != 0) {
modifier |= 1 << Settings::NativeKeyboard::LeftAlt;
}
if ((qt_modifiers & Qt::KeyboardModifier::MetaModifier) != 0) {
modifier |= 1 << Settings::NativeKeyboard::LeftMeta;
}
// TODO: These keys can't be obtained with Qt::KeyboardModifier
// if ((qt_modifiers & 0x10) != 0) {
// modifier |= 1 << Settings::NativeKeyboard::RightShift;
// }
// if ((qt_modifiers & 0x20) != 0) {
// modifier |= 1 << Settings::NativeKeyboard::RightControl;
// }
// if ((qt_modifiers & 0x40) != 0) {
// modifier |= 1 << Settings::NativeKeyboard::RightAlt;
// }
// if ((qt_modifiers & 0x80) != 0) {
// modifier |= 1 << Settings::NativeKeyboard::RightMeta;
// }
// if ((qt_modifiers & 0x100) != 0) {
// modifier |= 1 << Settings::NativeKeyboard::CapsLock;
// }
// if ((qt_modifiers & 0x200) != 0) {
// modifier |= 1 << Settings::NativeKeyboard::NumLock;
// }
// if ((qt_modifiers & ???) != 0) {
// modifier |= 1 << Settings::NativeKeyboard::ScrollLock;
// }
// if ((qt_modifiers & ???) != 0) {
// modifier |= 1 << Settings::NativeKeyboard::Katakana;
// }
// if ((qt_modifiers & ???) != 0) {
// modifier |= 1 << Settings::NativeKeyboard::Hiragana;
// }
return modifier;
}
void GRenderWindow::keyPressEvent(QKeyEvent* event) {
/**
* This feature can be enhanced with the following functions, but they do not provide
* cross-platform behavior.
*
* event->nativeVirtualKey() can distinguish between keys on the numpad.
* event->nativeModifiers() can distinguish between left and right keys and numlock,
* capslock, scroll lock.
*/
if (!event->isAutoRepeat()) {
const auto modifier = QtModifierToSwitchModifier(event->modifiers());
const auto key = QtKeyToSwitchKey(Qt::Key(event->key()));
input_subsystem->GetKeyboard()->SetKeyboardModifiers(modifier);
input_subsystem->GetKeyboard()->PressKeyboardKey(key);
// This is used for gamepads that can have any key mapped
input_subsystem->GetKeyboard()->PressKey(event->key());
}
}
void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
/**
* This feature can be enhanced with the following functions, but they do not provide
* cross-platform behavior.
*
* event->nativeVirtualKey() can distinguish between keys on the numpad.
* event->nativeModifiers() can distinguish between left and right buttons and numlock,
* capslock, scroll lock.
*/
if (!event->isAutoRepeat()) {
const auto modifier = QtModifierToSwitchModifier(event->modifiers());
const auto key = QtKeyToSwitchKey(Qt::Key(event->key()));
input_subsystem->GetKeyboard()->SetKeyboardModifiers(modifier);
input_subsystem->GetKeyboard()->ReleaseKeyboardKey(key);
// This is used for gamepads that can have any key mapped
input_subsystem->GetKeyboard()->ReleaseKey(event->key());
}
}
MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) {
InputCommon::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) {
switch (button) {
case Qt::LeftButton:
return MouseInput::MouseButton::Left;
return InputCommon::MouseButton::Left;
case Qt::RightButton:
return MouseInput::MouseButton::Right;
return InputCommon::MouseButton::Right;
case Qt::MiddleButton:
return MouseInput::MouseButton::Wheel;
return InputCommon::MouseButton::Wheel;
case Qt::BackButton:
return MouseInput::MouseButton::Backward;
return InputCommon::MouseButton::Backward;
case Qt::ForwardButton:
return MouseInput::MouseButton::Forward;
return InputCommon::MouseButton::Forward;
case Qt::TaskButton:
return MouseInput::MouseButton::Task;
return InputCommon::MouseButton::Task;
default:
return MouseInput::MouseButton::Extra;
return InputCommon::MouseButton::Extra;
}
}
@ -432,12 +728,9 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) {
// coordinates and map them to the current render area
const auto pos = mapFromGlobal(QCursor::pos());
const auto [x, y] = ScaleTouch(pos);
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
const auto button = QtButtonToMouseButton(event->button());
input_subsystem->GetMouse()->PressButton(x, y, button);
if (event->button() == Qt::LeftButton) {
this->TouchPressed(x, y, 0);
}
input_subsystem->GetMouse()->PressButton(x, y, touch_x, touch_y, button);
emit MouseActivity();
}
@ -451,12 +744,12 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
// coordinates and map them to the current render area
const auto pos = mapFromGlobal(QCursor::pos());
const auto [x, y] = ScaleTouch(pos);
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
const int center_x = width() / 2;
const int center_y = height() / 2;
input_subsystem->GetMouse()->MouseMove(x, y, center_x, center_y);
this->TouchMoved(x, y, 0);
input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, center_x, center_y);
if (Settings::values.mouse_panning) {
if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) {
QCursor::setPos(mapToGlobal({center_x, center_y}));
}
@ -471,10 +764,12 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
const auto button = QtButtonToMouseButton(event->button());
input_subsystem->GetMouse()->ReleaseButton(button);
}
if (event->button() == Qt::LeftButton) {
this->TouchReleased(0);
}
void GRenderWindow::wheelEvent(QWheelEvent* event) {
const int x = event->angleDelta().x();
const int y = event->angleDelta().y();
input_subsystem->GetMouse()->MouseWheelChange(x, y);
}
void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) {
@ -497,7 +792,7 @@ void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) {
for (std::size_t id = 0; id < touch_ids.size(); ++id) {
if (!TouchExist(touch_ids[id], touch_points)) {
touch_ids[id] = 0;
this->TouchReleased(id + 1);
input_subsystem->GetTouchScreen()->TouchReleased(id);
}
}
}
@ -506,28 +801,28 @@ void GRenderWindow::TouchEndEvent() {
for (std::size_t id = 0; id < touch_ids.size(); ++id) {
if (touch_ids[id] != 0) {
touch_ids[id] = 0;
this->TouchReleased(id + 1);
input_subsystem->GetTouchScreen()->TouchReleased(id);
}
}
}
bool GRenderWindow::TouchStart(const QTouchEvent::TouchPoint& touch_point) {
void GRenderWindow::TouchStart(const QTouchEvent::TouchPoint& touch_point) {
for (std::size_t id = 0; id < touch_ids.size(); ++id) {
if (touch_ids[id] == 0) {
touch_ids[id] = touch_point.id() + 1;
const auto [x, y] = ScaleTouch(touch_point.pos());
this->TouchPressed(x, y, id + 1);
return true;
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, id);
}
}
return false;
}
bool GRenderWindow::TouchUpdate(const QTouchEvent::TouchPoint& touch_point) {
for (std::size_t id = 0; id < touch_ids.size(); ++id) {
if (touch_ids[id] == static_cast<std::size_t>(touch_point.id() + 1)) {
const auto [x, y] = ScaleTouch(touch_point.pos());
this->TouchMoved(x, y, id + 1);
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, id);
return true;
}
}
@ -560,7 +855,7 @@ void GRenderWindow::focusOutEvent(QFocusEvent* event) {
QWidget::focusOutEvent(event);
input_subsystem->GetKeyboard()->ReleaseAllKeys();
input_subsystem->GetMouse()->ReleaseAllButtons();
this->TouchReleased(0);
input_subsystem->GetTouchScreen()->ReleaseAllTouch();
}
void GRenderWindow::resizeEvent(QResizeEvent* event) {
@ -769,7 +1064,7 @@ void GRenderWindow::showEvent(QShowEvent* event) {
bool GRenderWindow::eventFilter(QObject* object, QEvent* event) {
if (event->type() == QEvent::HoverMove) {
if (Settings::values.mouse_panning) {
if (Settings::values.mouse_panning || Settings::values.mouse_enabled) {
auto* hover_event = static_cast<QMouseEvent*>(event);
mouseMoveEvent(hover_event);
return false;

View File

@ -30,21 +30,18 @@ class System;
namespace InputCommon {
class InputSubsystem;
}
namespace MouseInput {
enum class MouseButton;
}
} // namespace InputCommon
namespace InputCommon::TasInput {
enum class TasState;
} // namespace InputCommon::TasInput
namespace VideoCore {
enum class LoadCallbackStage;
class RendererBase;
} // namespace VideoCore
namespace TasInput {
enum class TasState;
}
class EmuThread final : public QThread {
Q_OBJECT
@ -161,15 +158,22 @@ public:
void resizeEvent(QResizeEvent* event) override;
/// Converts a Qt keybard key into NativeKeyboard key
static int QtKeyToSwitchKey(Qt::Key qt_keys);
/// Converts a Qt modifier keys into NativeKeyboard modifier keys
static int QtModifierToSwitchModifier(Qt::KeyboardModifiers qt_modifiers);
void keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override;
/// Converts a Qt mouse button into MouseInput mouse button
static MouseInput::MouseButton QtButtonToMouseButton(Qt::MouseButton button);
static InputCommon::MouseButton QtButtonToMouseButton(Qt::MouseButton button);
void mousePressEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void wheelEvent(QWheelEvent* event) override;
bool event(QEvent* event) override;
@ -214,7 +218,7 @@ private:
void TouchUpdateEvent(const QTouchEvent* event);
void TouchEndEvent();
bool TouchStart(const QTouchEvent::TouchPoint& touch_point);
void TouchStart(const QTouchEvent::TouchPoint& touch_point);
bool TouchUpdate(const QTouchEvent::TouchPoint& touch_point);
bool TouchExist(std::size_t id, const QList<QTouchEvent::TouchPoint>& touch_points) const;
@ -241,7 +245,7 @@ private:
QWidget* child_widget = nullptr;
bool first_frame = false;
TasInput::TasState last_tas_state;
InputCommon::TasInput::TasState last_tas_state;
std::array<std::size_t, 16> touch_ids{};

View File

@ -11,7 +11,6 @@
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "input_common/main.h"
#include "input_common/udp/client.h"
#include "yuzu/configuration/config.h"
namespace FS = Common::FS;
@ -61,162 +60,6 @@ const std::array<int, 2> Config::default_stick_mod = {
0,
};
const std::array<int, Settings::NativeMouseButton::NumMouseButtons> Config::default_mouse_buttons =
{
Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal,
};
const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> Config::default_keyboard_keys = {
0,
0,
0,
0,
Qt::Key_A,
Qt::Key_B,
Qt::Key_C,
Qt::Key_D,
Qt::Key_E,
Qt::Key_F,
Qt::Key_G,
Qt::Key_H,
Qt::Key_I,
Qt::Key_J,
Qt::Key_K,
Qt::Key_L,
Qt::Key_M,
Qt::Key_N,
Qt::Key_O,
Qt::Key_P,
Qt::Key_Q,
Qt::Key_R,
Qt::Key_S,
Qt::Key_T,
Qt::Key_U,
Qt::Key_V,
Qt::Key_W,
Qt::Key_X,
Qt::Key_Y,
Qt::Key_Z,
Qt::Key_1,
Qt::Key_2,
Qt::Key_3,
Qt::Key_4,
Qt::Key_5,
Qt::Key_6,
Qt::Key_7,
Qt::Key_8,
Qt::Key_9,
Qt::Key_0,
Qt::Key_Enter,
Qt::Key_Escape,
Qt::Key_Backspace,
Qt::Key_Tab,
Qt::Key_Space,
Qt::Key_Minus,
Qt::Key_Equal,
Qt::Key_BracketLeft,
Qt::Key_BracketRight,
Qt::Key_Backslash,
Qt::Key_Dead_Tilde,
Qt::Key_Semicolon,
Qt::Key_Apostrophe,
Qt::Key_Dead_Grave,
Qt::Key_Comma,
Qt::Key_Period,
Qt::Key_Slash,
Qt::Key_CapsLock,
Qt::Key_F1,
Qt::Key_F2,
Qt::Key_F3,
Qt::Key_F4,
Qt::Key_F5,
Qt::Key_F6,
Qt::Key_F7,
Qt::Key_F8,
Qt::Key_F9,
Qt::Key_F10,
Qt::Key_F11,
Qt::Key_F12,
Qt::Key_SysReq,
Qt::Key_ScrollLock,
Qt::Key_Pause,
Qt::Key_Insert,
Qt::Key_Home,
Qt::Key_PageUp,
Qt::Key_Delete,
Qt::Key_End,
Qt::Key_PageDown,
Qt::Key_Right,
Qt::Key_Left,
Qt::Key_Down,
Qt::Key_Up,
Qt::Key_NumLock,
Qt::Key_Slash,
Qt::Key_Asterisk,
Qt::Key_Minus,
Qt::Key_Plus,
Qt::Key_Enter,
Qt::Key_1,
Qt::Key_2,
Qt::Key_3,
Qt::Key_4,
Qt::Key_5,
Qt::Key_6,
Qt::Key_7,
Qt::Key_8,
Qt::Key_9,
Qt::Key_0,
Qt::Key_Period,
0,
0,
Qt::Key_PowerOff,
Qt::Key_Equal,
Qt::Key_F13,
Qt::Key_F14,
Qt::Key_F15,
Qt::Key_F16,
Qt::Key_F17,
Qt::Key_F18,
Qt::Key_F19,
Qt::Key_F20,
Qt::Key_F21,
Qt::Key_F22,
Qt::Key_F23,
Qt::Key_F24,
Qt::Key_Open,
Qt::Key_Help,
Qt::Key_Menu,
0,
Qt::Key_Stop,
Qt::Key_AudioRepeat,
Qt::Key_Undo,
Qt::Key_Cut,
Qt::Key_Copy,
Qt::Key_Paste,
Qt::Key_Find,
Qt::Key_VolumeMute,
Qt::Key_VolumeUp,
Qt::Key_VolumeDown,
Qt::Key_CapsLock,
Qt::Key_NumLock,
Qt::Key_ScrollLock,
Qt::Key_Comma,
Qt::Key_ParenLeft,
Qt::Key_ParenRight,
};
const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> Config::default_keyboard_mods = {
Qt::Key_Control, Qt::Key_Shift, Qt::Key_Alt, Qt::Key_ApplicationLeft,
Qt::Key_Control, Qt::Key_Shift, Qt::Key_AltGr, Qt::Key_ApplicationRight,
};
// This shouldn't have anything except static initializers (no functions). So
// QKeySequence(...).toString() is NOT ALLOWED HERE.
// This must be in alphabetical order according to action name as it must have the same order as
@ -430,18 +273,6 @@ void Config::ReadPlayerValue(std::size_t player_index) {
}
}
for (int i = 0; i < Settings::NativeVibration::NumVibrations; ++i) {
auto& player_vibrations = player.vibrations[i];
player_vibrations =
qt_config
->value(QStringLiteral("%1").arg(player_prefix) +
QString::fromUtf8(Settings::NativeVibration::mapping[i]),
QString{})
.toString()
.toStdString();
}
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
auto& player_motions = player.motions[i];
@ -496,35 +327,10 @@ void Config::ReadDebugValues() {
void Config::ReadKeyboardValues() {
ReadBasicSetting(Settings::values.keyboard_enabled);
std::transform(default_keyboard_keys.begin(), default_keyboard_keys.end(),
Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(),
Settings::values.keyboard_keys.begin() +
Settings::NativeKeyboard::LeftControlKey,
InputCommon::GenerateKeyboardParam);
std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(),
Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam);
}
void Config::ReadMouseValues() {
ReadBasicSetting(Settings::values.mouse_enabled);
for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
const std::string default_param =
InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]);
auto& mouse_buttons = Settings::values.mouse_buttons[i];
mouse_buttons = qt_config
->value(QStringLiteral("mouse_") +
QString::fromUtf8(Settings::NativeMouseButton::mapping[i]),
QString::fromStdString(default_param))
.toString()
.toStdString();
if (mouse_buttons.empty()) {
mouse_buttons = default_param;
}
}
}
void Config::ReadTouchscreenValues() {
@ -574,7 +380,6 @@ void Config::ReadControlValues() {
ReadBasicSetting(Settings::values.tas_enable);
ReadBasicSetting(Settings::values.tas_loop);
ReadBasicSetting(Settings::values.tas_swap_controllers);
ReadBasicSetting(Settings::values.pause_tas_on_load);
ReadGlobalSetting(Settings::values.use_docked_mode);
@ -625,13 +430,12 @@ void Config::ReadMotionTouchValues() {
}
qt_config->endArray();
ReadBasicSetting(Settings::values.motion_device);
ReadBasicSetting(Settings::values.touch_device);
ReadBasicSetting(Settings::values.use_touch_from_button);
ReadBasicSetting(Settings::values.touch_from_button_map_index);
Settings::values.touch_from_button_map_index = std::clamp(
Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
ReadBasicSetting(Settings::values.udp_input_servers);
ReadBasicSetting(Settings::values.enable_udp_controller);
}
void Config::ReadCoreValues() {
@ -1075,11 +879,6 @@ void Config::SavePlayerValue(std::size_t player_index) {
QString::fromStdString(player.analogs[i]),
QString::fromStdString(default_param));
}
for (int i = 0; i < Settings::NativeVibration::NumVibrations; ++i) {
WriteSetting(QStringLiteral("%1").arg(player_prefix) +
QString::fromStdString(Settings::NativeVibration::mapping[i]),
QString::fromStdString(player.vibrations[i]), QString{});
}
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
WriteSetting(QStringLiteral("%1").arg(player_prefix) +
@ -1111,15 +910,6 @@ void Config::SaveDebugValues() {
void Config::SaveMouseValues() {
WriteBasicSetting(Settings::values.mouse_enabled);
for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
const std::string default_param =
InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]);
WriteSetting(QStringLiteral("mouse_") +
QString::fromStdString(Settings::NativeMouseButton::mapping[i]),
QString::fromStdString(Settings::values.mouse_buttons[i]),
QString::fromStdString(default_param));
}
}
void Config::SaveTouchscreenValues() {
@ -1133,11 +923,10 @@ void Config::SaveTouchscreenValues() {
}
void Config::SaveMotionTouchValues() {
WriteBasicSetting(Settings::values.motion_device);
WriteBasicSetting(Settings::values.touch_device);
WriteBasicSetting(Settings::values.use_touch_from_button);
WriteBasicSetting(Settings::values.touch_from_button_map_index);
WriteBasicSetting(Settings::values.udp_input_servers);
WriteBasicSetting(Settings::values.enable_udp_controller);
qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps"));
for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
@ -1210,7 +999,6 @@ void Config::SaveControlValues() {
WriteBasicSetting(Settings::values.tas_enable);
WriteBasicSetting(Settings::values.tas_loop);
WriteBasicSetting(Settings::values.tas_swap_controllers);
WriteBasicSetting(Settings::values.pause_tas_on_load);
qt_config->endGroup();

View File

@ -2,17 +2,18 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/core.h"
#include "core/hid/hid_core.h"
#include "ui_configure_debug_controller.h"
#include "yuzu/configuration/configure_debug_controller.h"
#include "yuzu/configuration/configure_input_player.h"
ConfigureDebugController::ConfigureDebugController(QWidget* parent,
InputCommon::InputSubsystem* input_subsystem,
InputProfiles* profiles, Core::System& system)
InputProfiles* profiles,
Core::HID::HIDCore& hid_core, bool is_powered_on)
: QDialog(parent), ui(std::make_unique<Ui::ConfigureDebugController>()),
debug_controller(
new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, system, true)) {
debug_controller(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles,
hid_core, is_powered_on, true)) {
ui->setupUi(this);
ui->controllerLayout->addWidget(debug_controller);

View File

@ -13,8 +13,8 @@ class ConfigureInputPlayer;
class InputProfiles;
namespace Core {
class System;
namespace Core::HID {
class HIDCore;
}
namespace InputCommon {
@ -30,7 +30,8 @@ class ConfigureDebugController : public QDialog {
public:
explicit ConfigureDebugController(QWidget* parent, InputCommon::InputSubsystem* input_subsystem,
InputProfiles* profiles, Core::System& system);
InputProfiles* profiles, Core::HID::HIDCore& hid_core,
bool is_powered_on);
~ConfigureDebugController() override;
void ApplyConfiguration();

View File

@ -10,6 +10,8 @@
#include <QTimer>
#include "core/core.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
@ -22,7 +24,6 @@
#include "yuzu/configuration/configure_input_advanced.h"
#include "yuzu/configuration/configure_input_player.h"
#include "yuzu/configuration/configure_motion_touch.h"
#include "yuzu/configuration/configure_mouse_advanced.h"
#include "yuzu/configuration/configure_touchscreen_advanced.h"
#include "yuzu/configuration/configure_vibration.h"
#include "yuzu/configuration/input_profiles.h"
@ -75,23 +76,25 @@ ConfigureInput::~ConfigureInput() = default;
void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
std::size_t max_players) {
const bool is_powered_on = system.IsPoweredOn();
auto& hid_core = system.HIDCore();
player_controllers = {
new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem, profiles.get(),
system),
hid_core, is_powered_on),
new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem, profiles.get(),
system),
hid_core, is_powered_on),
new ConfigureInputPlayer(this, 2, ui->consoleInputSettings, input_subsystem, profiles.get(),
system),
hid_core, is_powered_on),
new ConfigureInputPlayer(this, 3, ui->consoleInputSettings, input_subsystem, profiles.get(),
system),
hid_core, is_powered_on),
new ConfigureInputPlayer(this, 4, ui->consoleInputSettings, input_subsystem, profiles.get(),
system),
hid_core, is_powered_on),
new ConfigureInputPlayer(this, 5, ui->consoleInputSettings, input_subsystem, profiles.get(),
system),
hid_core, is_powered_on),
new ConfigureInputPlayer(this, 6, ui->consoleInputSettings, input_subsystem, profiles.get(),
system),
hid_core, is_powered_on),
new ConfigureInputPlayer(this, 7, ui->consoleInputSettings, input_subsystem, profiles.get(),
system),
hid_core, is_powered_on),
};
player_tabs = {
@ -114,6 +117,7 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i]));
player_tabs[i]->layout()->addWidget(player_controllers[i]);
connect(player_controllers[i], &ConfigureInputPlayer::Connected, [&, i](bool is_connected) {
// Ensures that the controllers are always connected in sequential order
if (is_connected) {
for (std::size_t index = 0; index <= i; ++index) {
player_connected[index]->setChecked(is_connected);
@ -146,13 +150,12 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
advanced = new ConfigureInputAdvanced(this);
ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced));
ui->tabAdvanced->layout()->addWidget(advanced);
connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, [this, input_subsystem] {
CallConfigureDialog<ConfigureDebugController>(*this, input_subsystem, profiles.get(),
system);
});
connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] {
CallConfigureDialog<ConfigureMouseAdvanced>(*this, input_subsystem);
});
connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog,
[this, input_subsystem, &hid_core, is_powered_on] {
CallConfigureDialog<ConfigureDebugController>(
*this, input_subsystem, profiles.get(), hid_core, is_powered_on);
});
connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog,
[this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
connect(advanced, &ConfigureInputAdvanced::CallMotionTouchConfigDialog,
@ -184,22 +187,8 @@ QList<QWidget*> ConfigureInput::GetSubTabs() const {
void ConfigureInput::ApplyConfiguration() {
for (auto* controller : player_controllers) {
controller->ApplyConfiguration();
controller->TryDisconnectSelectedController();
}
// This emulates a delay between disconnecting and reconnecting controllers as some games
// do not respond to a change in controller type if it was instantaneous.
using namespace std::chrono_literals;
std::this_thread::sleep_for(150ms);
for (auto* controller : player_controllers) {
controller->TryConnectSelectedController();
}
// This emulates a delay between disconnecting and reconnecting controllers as some games
// do not respond to a change in controller type if it was instantaneous.
std::this_thread::sleep_for(150ms);
advanced->ApplyConfiguration();
const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue();
@ -223,8 +212,10 @@ void ConfigureInput::RetranslateUI() {
}
void ConfigureInput::LoadConfiguration() {
const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
LoadPlayerControllerIndices();
UpdateDockedState(Settings::values.players.GetValue()[8].connected);
UpdateDockedState(handheld->IsConnected());
ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
@ -232,9 +223,16 @@ void ConfigureInput::LoadConfiguration() {
void ConfigureInput::LoadPlayerControllerIndices() {
for (std::size_t i = 0; i < player_connected.size(); ++i) {
const auto connected = Settings::values.players.GetValue()[i].connected ||
(i == 0 && Settings::values.players.GetValue()[8].connected);
player_connected[i]->setChecked(connected);
if (i == 0) {
auto* handheld =
system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
if (handheld->IsConnected()) {
player_connected[i]->setChecked(true);
continue;
}
}
const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(i);
player_connected[i]->setChecked(controller->IsConnected());
}
}

View File

@ -82,7 +82,6 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent)
connect(ui->debug_configure, &QPushButton::clicked, this,
[this] { CallDebugControllerDialog(); });
connect(ui->mouse_advanced, &QPushButton::clicked, this, [this] { CallMouseConfigDialog(); });
connect(ui->touchscreen_advanced, &QPushButton::clicked, this,
[this] { CallTouchscreenConfigDialog(); });
connect(ui->buttonMotionTouch, &QPushButton::clicked, this,
@ -131,6 +130,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() {
static_cast<float>(ui->mouse_panning_sensitivity->value());
Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
Settings::values.enable_raw_input = ui->enable_raw_input->isChecked();
Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked();
}
void ConfigureInputAdvanced::LoadConfiguration() {
@ -161,6 +161,7 @@ void ConfigureInputAdvanced::LoadConfiguration() {
ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue());
ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue());
ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue());
UpdateUIEnabled();
}
@ -178,7 +179,8 @@ void ConfigureInputAdvanced::RetranslateUI() {
}
void ConfigureInputAdvanced::UpdateUIEnabled() {
ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked());
ui->debug_configure->setEnabled(ui->debug_enabled->isChecked());
ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked());
ui->mouse_panning->setEnabled(!ui->mouse_enabled->isChecked());
ui->mouse_panning_sensitivity->setEnabled(!ui->mouse_enabled->isChecked());
}

View File

@ -2528,11 +2528,11 @@
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="gridGroupBox_3">
<widget class="QGroupBox" name="emulatedDevicesGroupBox">
<property name="title">
<string>Other</string>
<string>Emulated Devices</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<layout class="QGridLayout" name="emulatedDevicesGridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="keyboard_enabled">
<property name="minimumSize">
@ -2547,7 +2547,7 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="emulate_analog_keyboard">
<widget class="QCheckBox" name="mouse_enabled">
<property name="minimumSize">
<size>
<width>0</width>
@ -2555,53 +2555,18 @@
</size>
</property>
<property name="text">
<string>Emulate Analog with Keyboard Input</string>
<string>Mouse</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="mouse_panning">
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<widget class="QCheckBox" name="touchscreen_enabled">
<property name="text">
<string>Enable mouse panning</string>
<string>Touchscreen</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QSpinBox" name="mouse_panning_sensitivity">
<property name="toolTip">
<string>Mouse sensitivity</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QPushButton" name="touchscreen_advanced">
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="2" column="1">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -2617,80 +2582,130 @@
</property>
</spacer>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="mouse_advanced">
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="touchscreen_enabled">
<property name="text">
<string>Touchscreen</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="touchscreen_advanced">
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="mouse_enabled">
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Mouse</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="motion_touch">
<property name="text">
<string>Motion / Touch</string>
</property>
</widget>
</item>
<item row="8" column="2">
<widget class="QPushButton" name="buttonMotionTouch">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="debug_enabled">
<property name="text">
<string>Debug Controller</string>
</property>
</widget>
</item>
<item row="7" column="2">
<item row="3" column="2">
<widget class="QPushButton" name="debug_configure">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="enable_raw_input">
<property name="toolTip">
<string>Requires restarting yuzu</string>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Enable XInput 8 player support (disables web applet)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="otherGroupBox">
<property name="title">
<string>Other</string>
</property>
<layout class="QGridLayout" name="OtherGridLayout">
<item row="1" column="0">
<widget class="QCheckBox" name="emulate_analog_keyboard">
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Emulate Analog with Keyboard Input</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="enable_raw_input">
<property name="toolTip">
<string>Requires restarting yuzu</string>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Enable XInput 8 player support (disables web applet)</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="enable_udp_controller">
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Enable UDP controllers (not needed for motion)</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="mouse_panning">
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Enable mouse panning</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QSpinBox" name="mouse_panning_sensitivity">
<property name="toolTip">
<string>Mouse sensitivity</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="motion_touch">
<property name="text">
<string>Motion / Touch</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QPushButton" name="buttonMotionTouch">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">

File diff suppressed because it is too large Load Diff

View File

@ -29,48 +29,37 @@ class QWidget;
class InputProfiles;
namespace Core {
class System;
}
namespace InputCommon {
class InputSubsystem;
}
namespace InputCommon::Polling {
class DevicePoller;
enum class DeviceType;
enum class InputType;
} // namespace InputCommon::Polling
namespace Ui {
class ConfigureInputPlayer;
}
namespace Core::HID {
class HIDCore;
class EmulatedController;
enum class NpadStyleIndex : u8;
} // namespace Core::HID
class ConfigureInputPlayer : public QWidget {
Q_OBJECT
public:
explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row,
InputCommon::InputSubsystem* input_subsystem_,
InputProfiles* profiles_, Core::System& system_,
bool debug = false);
InputProfiles* profiles_, Core::HID::HIDCore& hid_core_,
bool is_powered_on_, bool debug = false);
~ConfigureInputPlayer() override;
/// Save all button configurations to settings file.
void ApplyConfiguration();
/**
* Attempts to connect the currently selected controller in the HID backend.
* This function will not do anything if it is not connected in the frontend.
*/
void TryConnectSelectedController();
/**
* Attempts to disconnect the currently selected controller in the HID backend.
* This function will not do anything if the configuration has not changed.
*/
void TryDisconnectSelectedController();
/// Set the connection state checkbox (used to sync state).
void ConnectPlayer(bool connected);
@ -104,6 +93,10 @@ protected:
void showEvent(QShowEvent* event) override;
private:
QString ButtonToText(const Common::ParamPackage& param);
QString AnalogToText(const Common::ParamPackage& param, const std::string& dir);
void changeEvent(QEvent* event) override;
void RetranslateUI();
@ -113,7 +106,7 @@ private:
/// Called when the button was pressed.
void HandleClick(QPushButton* button, std::size_t button_id,
std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type);
InputCommon::Polling::InputType type);
/// Finish polling and configure input using the input_setter.
void SetPollingResult(const Common::ParamPackage& params, bool abort);
@ -134,17 +127,14 @@ private:
void SetConnectableControllers();
/// Gets the Controller Type for a given controller combobox index.
Settings::ControllerType GetControllerTypeFromIndex(int index) const;
Core::HID::NpadStyleIndex GetControllerTypeFromIndex(int index) const;
/// Gets the controller combobox index for a given Controller Type.
int GetIndexFromControllerType(Settings::ControllerType type) const;
int GetIndexFromControllerType(Core::HID::NpadStyleIndex type) const;
/// Update the available input devices.
void UpdateInputDevices();
/// Update the current controller icon.
void UpdateControllerIcon();
/// Hides and disables controller settings based on the current controller type.
void UpdateControllerAvailableButtons();
@ -176,6 +166,7 @@ private:
std::size_t player_index;
bool debug;
bool is_powered_on;
InputCommon::InputSubsystem* input_subsystem;
@ -185,7 +176,7 @@ private:
std::unique_ptr<QTimer> poll_timer;
/// Stores a pair of "Connected Controllers" combobox index and Controller Type enum.
std::vector<std::pair<int, Settings::ControllerType>> index_controller_type_pairs;
std::vector<std::pair<int, Core::HID::NpadStyleIndex>> index_controller_type_pairs;
static constexpr int PLAYER_COUNT = 8;
std::array<QCheckBox*, PLAYER_COUNT> player_connected_checkbox;
@ -193,9 +184,7 @@ private:
/// This will be the the setting function when an input is awaiting configuration.
std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param;
std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions> motions_param;
Core::HID::EmulatedController* emulated_controller;
static constexpr int ANALOG_SUB_BUTTONS_NUM = 4;
@ -221,15 +210,9 @@ private:
static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons;
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
/// A flag to indicate that the "Map Analog Stick" pop-up has been shown and accepted once.
bool map_analog_stick_accepted{};
/// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
/// keyboard events are ignored.
bool want_keyboard_mouse{};
/// List of physical devices users can map with. If a SDL backed device is selected, then you
/// can use this device to get a default mapping.
std::vector<Common::ParamPackage> input_devices;
@ -239,5 +222,5 @@ private:
/// parent of the widget to this widget (but thats fine).
QWidget* bottom_row;
Core::System& system;
Core::HID::HIDCore& hid_core;
};

View File

@ -89,31 +89,6 @@
<height>21</height>
</size>
</property>
<item>
<property name="text">
<string>Pro Controller</string>
</property>
</item>
<item>
<property name="text">
<string>Dual Joycons</string>
</property>
</item>
<item>
<property name="text">
<string>Left Joycon</string>
</property>
</item>
<item>
<property name="text">
<string>Right Joycon</string>
</property>
</item>
<item>
<property name="text">
<string>Handheld</string>
</property>
</item>
</widget>
</item>
</layout>
@ -142,22 +117,9 @@
</property>
<item>
<widget class="QComboBox" name="comboDevices">
<property name="minimumSize">
<size>
<width>0</width>
<height>21</height>
</size>
<property name="minimumContentsLength">
<number>60</number>
</property>
<item>
<property name="text">
<string>Any</string>
</property>
</item>
<item>
<property name="text">
<string>Keyboard/Mouse</string>
</property>
</item>
</widget>
</item>
<item>
@ -342,7 +304,7 @@
<number>3</number>
</property>
<property name="topMargin">
<number>0</number>
<number>6</number>
</property>
<property name="rightMargin">
<number>3</number>
@ -918,7 +880,7 @@
<number>3</number>
</property>
<property name="topMargin">
<number>0</number>
<number>6</number>
</property>
<property name="rightMargin">
<number>3</number>
@ -2221,7 +2183,7 @@
<number>3</number>
</property>
<property name="topMargin">
<number>0</number>
<number>6</number>
</property>
<property name="rightMargin">
<number>3</number>
@ -2570,7 +2532,7 @@
<number>3</number>
</property>
<property name="topMargin">
<number>0</number>
<number>6</number>
</property>
<property name="rightMargin">
<number>3</number>

File diff suppressed because it is too large Load Diff

View File

@ -7,9 +7,11 @@
#include <array>
#include <QFrame>
#include <QPointer>
#include "common/settings.h"
#include "core/frontend/input.h"
#include "yuzu/debugger/controller.h"
#include "common/input.h"
#include "common/settings_input.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_types.h"
class QLabel;
@ -24,17 +26,26 @@ public:
explicit PlayerControlPreview(QWidget* parent);
~PlayerControlPreview() override;
void SetPlayerInput(std::size_t index, const ButtonParam& buttons_param,
const AnalogParam& analogs_param);
void SetPlayerInputRaw(std::size_t index, const Settings::ButtonsRaw& buttons_,
Settings::AnalogsRaw analogs_);
void SetConnectedStatus(bool checked);
void SetControllerType(Settings::ControllerType type);
// Sets the emulated controller to be displayed
void SetController(Core::HID::EmulatedController* controller);
// Disables events from the emulated controller
void UnloadController();
// Starts blinking animation at the button specified
void BeginMappingButton(std::size_t button_id);
void BeginMappingAnalog(std::size_t button_id);
// Starts moving animation at the stick specified
void BeginMappingAnalog(std::size_t stick_id);
// Stops any ongoing animation
void EndMapping();
// Handles emulated controller events
void ControllerUpdate(Core::HID::ControllerTriggerType type);
// Updates input on sheduled interval
void UpdateInput();
void SetCallBack(ControllerCallback callback_);
protected:
void paintEvent(QPaintEvent* event) override;
@ -63,22 +74,6 @@ private:
SR,
};
struct AxisValue {
QPointF value{};
QPointF raw_value{};
Input::AnalogProperties properties{};
int size{};
QPoint offset{};
bool active{};
};
struct LedPattern {
bool position1;
bool position2;
bool position3;
bool position4;
};
struct ColorMapping {
QColor outline{};
QColor primary{};
@ -101,7 +96,6 @@ private:
QColor deadzone{};
};
static LedPattern GetColorPattern(std::size_t index, bool player_on);
void UpdateColors();
void ResetInputs();
@ -122,47 +116,75 @@ private:
void DrawGCBody(QPainter& p, QPointF center);
// Draw triggers functions
void DrawProTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed);
void DrawGCTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed);
void DrawHandheldTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed);
void DrawDualTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed);
void DrawDualTriggersTopView(QPainter& p, QPointF center, bool left_pressed,
bool right_pressed);
void DrawDualZTriggersTopView(QPainter& p, QPointF center, bool left_pressed,
bool right_pressed);
void DrawLeftTriggers(QPainter& p, QPointF center, bool left_pressed);
void DrawLeftZTriggers(QPainter& p, QPointF center, bool left_pressed);
void DrawLeftTriggersTopView(QPainter& p, QPointF center, bool left_pressed);
void DrawLeftZTriggersTopView(QPainter& p, QPointF center, bool left_pressed);
void DrawRightTriggers(QPainter& p, QPointF center, bool right_pressed);
void DrawRightZTriggers(QPainter& p, QPointF center, bool right_pressed);
void DrawRightTriggersTopView(QPainter& p, QPointF center, bool right_pressed);
void DrawRightZTriggersTopView(QPainter& p, QPointF center, bool right_pressed);
void DrawProTriggers(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& left_pressed,
const Common::Input::ButtonStatus& right_pressed);
void DrawGCTriggers(QPainter& p, QPointF center, Common::Input::TriggerStatus left_trigger,
Common::Input::TriggerStatus right_trigger);
void DrawHandheldTriggers(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& left_pressed,
const Common::Input::ButtonStatus& right_pressed);
void DrawDualTriggers(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& left_pressed,
const Common::Input::ButtonStatus& right_pressed);
void DrawDualTriggersTopView(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& left_pressed,
const Common::Input::ButtonStatus& right_pressed);
void DrawDualZTriggersTopView(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& left_pressed,
const Common::Input::ButtonStatus& right_pressed);
void DrawLeftTriggers(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& left_pressed);
void DrawLeftZTriggers(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& left_pressed);
void DrawLeftTriggersTopView(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& left_pressed);
void DrawLeftZTriggersTopView(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& left_pressed);
void DrawRightTriggers(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& right_pressed);
void DrawRightZTriggers(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& right_pressed);
void DrawRightTriggersTopView(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& right_pressed);
void DrawRightZTriggersTopView(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& right_pressed);
// Draw joystick functions
void DrawJoystick(QPainter& p, QPointF center, float size, bool pressed);
void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, bool pressed);
void DrawJoystick(QPainter& p, QPointF center, float size,
const Common::Input::ButtonStatus& pressed);
void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size,
const Common::Input::ButtonStatus& pressed);
void DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right);
void DrawJoystickProperties(QPainter& p, QPointF center,
const Input::AnalogProperties& properties);
void DrawJoystickDot(QPainter& p, QPointF center, QPointF value,
const Input::AnalogProperties& properties);
void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar, bool pressed);
void DrawGCJoystick(QPainter& p, QPointF center, bool pressed);
const Common::Input::AnalogProperties& properties);
void DrawJoystickDot(QPainter& p, QPointF center, const Common::Input::StickStatus& stick,
bool raw);
void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar,
const Common::Input::ButtonStatus& pressed);
void DrawGCJoystick(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed);
// Draw button functions
void DrawCircleButton(QPainter& p, QPointF center, bool pressed, float button_size);
void DrawRoundButton(QPainter& p, QPointF center, bool pressed, float width, float height,
Direction direction = Direction::None, float radius = 2);
void DrawMinusButton(QPainter& p, QPointF center, bool pressed, int button_size);
void DrawPlusButton(QPainter& p, QPointF center, bool pressed, int button_size);
void DrawGCButtonX(QPainter& p, QPointF center, bool pressed);
void DrawGCButtonY(QPainter& p, QPointF center, bool pressed);
void DrawGCButtonZ(QPainter& p, QPointF center, bool pressed);
void DrawCircleButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed,
float button_size);
void DrawRoundButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed,
float width, float height, Direction direction = Direction::None,
float radius = 2);
void DrawMinusButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed,
int button_size);
void DrawPlusButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed,
int button_size);
void DrawGCButtonX(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed);
void DrawGCButtonY(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed);
void DrawGCButtonZ(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed);
void DrawArrowButtonOutline(QPainter& p, const QPointF center, float size = 1.0f);
void DrawArrowButton(QPainter& p, QPointF center, Direction direction, bool pressed,
float size = 1.0f);
void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, bool pressed);
void DrawArrowButton(QPainter& p, QPointF center, Direction direction,
const Common::Input::ButtonStatus& pressed, float size = 1.0f);
void DrawTriggerButton(QPainter& p, QPointF center, Direction direction,
const Common::Input::ButtonStatus& pressed);
// Draw battery functions
void DrawBattery(QPainter& p, QPointF center, Common::Input::BatteryLevel battery);
// Draw icon functions
void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size);
@ -178,24 +200,23 @@ private:
void SetTextFont(QPainter& p, float text_size,
const QString& font_family = QStringLiteral("sans-serif"));
using ButtonArray =
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::BUTTON_NS_END>;
using StickArray =
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>;
bool is_controller_set{};
bool is_connected{};
bool needs_redraw{};
Core::HID::NpadStyleIndex controller_type;
ControllerCallback controller_callback;
bool is_enabled{};
bool mapping_active{};
int blink_counter{};
int callback_key;
QColor button_color{};
ColorMapping colors{};
std::array<QColor, 4> led_color{};
ButtonArray buttons{};
StickArray sticks{};
Core::HID::LedPattern led_pattern{0, 0, 0, 0};
std::size_t player_index{};
std::size_t button_mapping_index{Settings::NativeButton::BUTTON_NS_END};
std::size_t analog_mapping_index{Settings::NativeAnalog::NUM_STICKS_HID};
std::array<AxisValue, Settings::NativeAnalog::NUM_STICKS_HID> axis_values{};
std::array<bool, Settings::NativeButton::NumButtons> button_values{};
Settings::ControllerType controller_type{Settings::ControllerType::ProController};
Core::HID::EmulatedController* controller;
std::size_t button_mapping_index{Settings::NativeButton::NumButtons};
std::size_t analog_mapping_index{Settings::NativeAnalog::NumAnalogs};
Core::HID::ButtonValues button_values{};
Core::HID::SticksValues stick_values{};
Core::HID::TriggerValues trigger_values{};
Core::HID::BatteryValues battery_values{};
};

View File

@ -11,8 +11,8 @@ ConfigureInputProfileDialog::ConfigureInputProfileDialog(
QWidget* parent, InputCommon::InputSubsystem* input_subsystem, InputProfiles* profiles,
Core::System& system)
: QDialog(parent), ui(std::make_unique<Ui::ConfigureInputProfileDialog>()),
profile_widget(
new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, system, false)) {
profile_widget(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles,
system.HIDCore(), system.IsPoweredOn(), false)) {
ui->setupUi(this);
ui->controllerLayout->addWidget(profile_widget);

View File

@ -15,9 +15,9 @@
#include "common/logging/log.h"
#include "common/settings.h"
#include "input_common/drivers/udp_client.h"
#include "input_common/helpers/udp_protocol.h"
#include "input_common/main.h"
#include "input_common/udp/client.h"
#include "input_common/udp/udp.h"
#include "ui_configure_motion_touch.h"
#include "yuzu/configuration/configure_motion_touch.h"
#include "yuzu/configuration/configure_touch_from_button.h"
@ -93,6 +93,7 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent,
"using-a-controller-or-android-phone-for-motion-or-touch-input'><span "
"style=\"text-decoration: underline; color:#039be5;\">Learn More</span></a>"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
SetConfiguration();
UpdateUiDisplay();
ConnectEvents();
@ -101,17 +102,14 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent,
ConfigureMotionTouch::~ConfigureMotionTouch() = default;
void ConfigureMotionTouch::SetConfiguration() {
const Common::ParamPackage motion_param(Settings::values.motion_device.GetValue());
const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button.GetValue());
touch_from_button_maps = Settings::values.touch_from_button_maps;
for (const auto& touch_map : touch_from_button_maps) {
ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name));
}
ui->touch_from_button_map->setCurrentIndex(
Settings::values.touch_from_button_map_index.GetValue());
ui->motion_sensitivity->setValue(motion_param.Get("sensitivity", 0.01f));
min_x = touch_param.Get("min_x", 100);
min_y = touch_param.Get("min_y", 50);
@ -139,9 +137,6 @@ void ConfigureMotionTouch::SetConfiguration() {
void ConfigureMotionTouch::UpdateUiDisplay() {
const QString cemuhook_udp = QStringLiteral("cemuhookudp");
ui->motion_sensitivity_label->setVisible(true);
ui->motion_sensitivity->setVisible(true);
ui->touch_calibration->setVisible(true);
ui->touch_calibration_config->setVisible(true);
ui->touch_calibration_label->setVisible(true);
@ -312,7 +307,6 @@ void ConfigureMotionTouch::ApplyConfiguration() {
touch_param.Set("max_y", max_y);
Settings::values.touch_device = touch_param.Serialize();
Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked();
Settings::values.touch_from_button_map_index = ui->touch_from_button_map->currentIndex();
Settings::values.touch_from_button_maps = touch_from_button_maps;
Settings::values.udp_input_servers = GetUDPServerString();

View File

@ -2,14 +2,6 @@
<ui version="4.0">
<class>ConfigureMotionTouch</class>
<widget class="QDialog" name="ConfigureMotionTouch">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>482</height>
</rect>
</property>
<property name="windowTitle">
<string>Configure Motion / Touch</string>
</property>
@ -17,48 +9,6 @@
<string notr="true"/>
</property>
<layout class="QVBoxLayout">
<item>
<widget class="QGroupBox" name="motion_group_box">
<property name="title">
<string>Mouse Motion</string>
</property>
<layout class="QVBoxLayout">
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="motion_sensitivity_label">
<property name="text">
<string>Sensitivity:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="motion_sensitivity">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>0.010000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="touch_group_box">
<property name="title">
@ -101,19 +51,13 @@
</item>
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QCheckBox" name="touch_from_button_checkbox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Use button mapping:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="touch_from_button_label">
<property name="text">
<string>Touch from button profile:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="touch_from_button_map"/>
</item>

View File

@ -1,276 +0,0 @@
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <memory>
#include <QKeyEvent>
#include <QMenu>
#include <QTimer>
#include "common/assert.h"
#include "common/param_package.h"
#include "input_common/main.h"
#include "ui_configure_mouse_advanced.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configure_mouse_advanced.h"
static QString GetKeyName(int key_code) {
switch (key_code) {
case Qt::LeftButton:
return QObject::tr("Click 0");
case Qt::RightButton:
return QObject::tr("Click 1");
case Qt::MiddleButton:
return QObject::tr("Click 2");
case Qt::BackButton:
return QObject::tr("Click 3");
case Qt::ForwardButton:
return QObject::tr("Click 4");
case Qt::Key_Shift:
return QObject::tr("Shift");
case Qt::Key_Control:
return QObject::tr("Ctrl");
case Qt::Key_Alt:
return QObject::tr("Alt");
case Qt::Key_Meta:
return {};
default:
return QKeySequence(key_code).toString();
}
}
static QString ButtonToText(const Common::ParamPackage& param) {
if (!param.Has("engine")) {
return QObject::tr("[not set]");
}
if (param.Get("engine", "") == "keyboard") {
return GetKeyName(param.Get("code", 0));
}
if (param.Get("engine", "") == "sdl") {
if (param.Has("hat")) {
const QString hat_str = QString::fromStdString(param.Get("hat", ""));
const QString direction_str = QString::fromStdString(param.Get("direction", ""));
return QObject::tr("Hat %1 %2").arg(hat_str, direction_str);
}
if (param.Has("axis")) {
const QString axis_str = QString::fromStdString(param.Get("axis", ""));
const QString direction_str = QString::fromStdString(param.Get("direction", ""));
return QObject::tr("Axis %1%2").arg(axis_str, direction_str);
}
if (param.Has("button")) {
const QString button_str = QString::fromStdString(param.Get("button", ""));
return QObject::tr("Button %1").arg(button_str);
}
return {};
}
return QObject::tr("[unknown]");
}
ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent,
InputCommon::InputSubsystem* input_subsystem_)
: QDialog(parent),
ui(std::make_unique<Ui::ConfigureMouseAdvanced>()), input_subsystem{input_subsystem_},
timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
ui->setupUi(this);
setFocusPolicy(Qt::ClickFocus);
button_map = {
ui->left_button, ui->right_button, ui->middle_button, ui->forward_button, ui->back_button,
};
for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) {
auto* const button = button_map[button_id];
if (button == nullptr) {
continue;
}
button->setContextMenuPolicy(Qt::CustomContextMenu);
connect(button, &QPushButton::clicked, [=, this] {
HandleClick(
button_map[button_id],
[=, this](const Common::ParamPackage& params) {
buttons_param[button_id] = params;
},
InputCommon::Polling::DeviceType::Button);
});
connect(button, &QPushButton::customContextMenuRequested,
[=, this](const QPoint& menu_location) {
QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] {
buttons_param[button_id].Clear();
button_map[button_id]->setText(tr("[not set]"));
});
context_menu.addAction(tr("Restore Default"), [&] {
buttons_param[button_id] =
Common::ParamPackage{InputCommon::GenerateKeyboardParam(
Config::default_mouse_buttons[button_id])};
button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
});
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
});
}
connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); });
connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); });
timeout_timer->setSingleShot(true);
connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); });
connect(poll_timer.get(), &QTimer::timeout, [this] {
Common::ParamPackage params;
for (auto& poller : device_pollers) {
params = poller->GetNextInput();
if (params.Has("engine")) {
SetPollingResult(params, false);
return;
}
}
});
LoadConfiguration();
resize(0, 0);
}
ConfigureMouseAdvanced::~ConfigureMouseAdvanced() = default;
void ConfigureMouseAdvanced::ApplyConfiguration() {
std::transform(buttons_param.begin(), buttons_param.end(),
Settings::values.mouse_buttons.begin(),
[](const Common::ParamPackage& param) { return param.Serialize(); });
}
void ConfigureMouseAdvanced::LoadConfiguration() {
std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(),
buttons_param.begin(),
[](const std::string& str) { return Common::ParamPackage(str); });
UpdateButtonLabels();
}
void ConfigureMouseAdvanced::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QDialog::changeEvent(event);
}
void ConfigureMouseAdvanced::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureMouseAdvanced::RestoreDefaults() {
for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) {
buttons_param[button_id] = Common::ParamPackage{
InputCommon::GenerateKeyboardParam(Config::default_mouse_buttons[button_id])};
}
UpdateButtonLabels();
}
void ConfigureMouseAdvanced::ClearAll() {
for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
const auto* const button = button_map[i];
if (button != nullptr && button->isEnabled()) {
buttons_param[i].Clear();
}
}
UpdateButtonLabels();
}
void ConfigureMouseAdvanced::UpdateButtonLabels() {
for (int button = 0; button < Settings::NativeMouseButton::NumMouseButtons; button++) {
button_map[button]->setText(ButtonToText(buttons_param[button]));
}
}
void ConfigureMouseAdvanced::HandleClick(
QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type) {
button->setText(tr("[press key]"));
button->setFocus();
// Keyboard keys or mouse buttons can only be used as button devices
want_keyboard_mouse = type == InputCommon::Polling::DeviceType::Button;
if (want_keyboard_mouse) {
const auto iter = std::find(button_map.begin(), button_map.end(), button);
ASSERT(iter != button_map.end());
const auto index = std::distance(button_map.begin(), iter);
ASSERT(index < Settings::NativeButton::NumButtons && index >= 0);
}
input_setter = new_input_setter;
device_pollers = input_subsystem->GetPollers(type);
for (auto& poller : device_pollers) {
poller->Start();
}
QWidget::grabMouse();
QWidget::grabKeyboard();
timeout_timer->start(2500); // Cancel after 2.5 seconds
poll_timer->start(50); // Check for new inputs every 50ms
}
void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params, bool abort) {
timeout_timer->stop();
poll_timer->stop();
for (auto& poller : device_pollers) {
poller->Stop();
}
QWidget::releaseMouse();
QWidget::releaseKeyboard();
if (!abort) {
(*input_setter)(params);
}
UpdateButtonLabels();
input_setter = std::nullopt;
}
void ConfigureMouseAdvanced::mousePressEvent(QMouseEvent* event) {
if (!input_setter || !event) {
return;
}
if (want_keyboard_mouse) {
SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())},
false);
} else {
// We don't want any mouse buttons, so don't stop polling
return;
}
SetPollingResult({}, true);
}
void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) {
if (!input_setter || !event) {
return;
}
if (event->key() != Qt::Key_Escape) {
if (want_keyboard_mouse) {
SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
false);
} else {
// Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
return;
}
}
SetPollingResult({}, true);
}

View File

@ -1,78 +0,0 @@
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <optional>
#include <QDialog>
class QCheckBox;
class QPushButton;
class QTimer;
namespace InputCommon {
class InputSubsystem;
}
namespace Ui {
class ConfigureMouseAdvanced;
}
class ConfigureMouseAdvanced : public QDialog {
Q_OBJECT
public:
explicit ConfigureMouseAdvanced(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_);
~ConfigureMouseAdvanced() override;
void ApplyConfiguration();
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
/// Load configuration settings.
void LoadConfiguration();
/// Restore all buttons to their default values.
void RestoreDefaults();
/// Clear all input configuration
void ClearAll();
/// Update UI to reflect current configuration.
void UpdateButtonLabels();
/// Called when the button was pressed.
void HandleClick(QPushButton* button,
std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type);
/// Finish polling and configure input using the input_setter
void SetPollingResult(const Common::ParamPackage& params, bool abort);
/// Handle mouse button press events.
void mousePressEvent(QMouseEvent* event) override;
/// Handle key press events.
void keyPressEvent(QKeyEvent* event) override;
std::unique_ptr<Ui::ConfigureMouseAdvanced> ui;
InputCommon::InputSubsystem* input_subsystem;
/// This will be the the setting function when an input is awaiting configuration.
std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
std::array<QPushButton*, Settings::NativeMouseButton::NumMouseButtons> button_map;
std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons> buttons_param;
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
std::unique_ptr<QTimer> timeout_timer;
std::unique_ptr<QTimer> poll_timer;
/// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
/// keyboard events are ignored.
bool want_keyboard_mouse = false;
};

View File

@ -1,335 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConfigureMouseAdvanced</class>
<widget class="QDialog" name="ConfigureMouseAdvanced">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>310</width>
<height>193</height>
</rect>
</property>
<property name="windowTitle">
<string>Configure Mouse</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
min-width: 60px;
}</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="gridGroupBox">
<property name="title">
<string>Mouse Buttons</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="5">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Forward:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="forward_button">
<property name="minimumSize">
<size>
<width>68</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>68</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="1">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_4">
<property name="minimumSize">
<size>
<width>54</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Back:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="back_button">
<property name="minimumSize">
<size>
<width>68</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Left:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="left_button">
<property name="minimumSize">
<size>
<width>68</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="3">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Middle:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="middle_button">
<property name="minimumSize">
<size>
<width>68</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>68</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="6">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="5">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Right:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="right_button">
<property name="minimumSize">
<size>
<width>68</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>68</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="4">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QPushButton" name="buttonClearAll">
<property name="minimumSize">
<size>
<width>68</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>68</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonRestoreDefaults">
<property name="minimumSize">
<size>
<width>68</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>68</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Defaults</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ConfigureMouseAdvanced</receiver>
<slot>accept()</slot>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ConfigureMouseAdvanced</receiver>
<slot>reject()</slot>
</connection>
</connections>
</ui>

View File

@ -32,7 +32,6 @@ void ConfigureTasDialog::LoadConfiguration() {
ui->tas_path_edit->setText(
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir)));
ui->tas_enable->setChecked(Settings::values.tas_enable.GetValue());
ui->tas_control_swap->setChecked(Settings::values.tas_swap_controllers.GetValue());
ui->tas_loop_script->setChecked(Settings::values.tas_loop.GetValue());
ui->tas_pause_on_load->setChecked(Settings::values.pause_tas_on_load.GetValue());
}
@ -40,7 +39,6 @@ void ConfigureTasDialog::LoadConfiguration() {
void ConfigureTasDialog::ApplyConfiguration() {
Common::FS::SetYuzuPath(Common::FS::YuzuPath::TASDir, ui->tas_path_edit->text().toStdString());
Settings::values.tas_enable.SetValue(ui->tas_enable->isChecked());
Settings::values.tas_swap_controllers.SetValue(ui->tas_control_swap->isChecked());
Settings::values.tas_loop.SetValue(ui->tas_loop_script->isChecked());
Settings::values.pause_tas_on_load.SetValue(ui->tas_pause_on_load->isChecked());
}

View File

@ -59,20 +59,13 @@
</widget>
</item>
<item row="1" column="0" colspan="4">
<widget class="QCheckBox" name="tas_control_swap">
<property name="text">
<string>Automatic controller profile swapping</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<widget class="QCheckBox" name="tas_loop_script">
<property name="text">
<string>Loop script</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="4">
<item row="2" column="0" colspan="4">
<widget class="QCheckBox" name="tas_pause_on_load">
<property name="enabled">
<bool>false</bool>

View File

@ -163,13 +163,10 @@ void ConfigureTouchFromButton::ConnectEvents() {
connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); });
connect(poll_timer.get(), &QTimer::timeout, [this]() {
Common::ParamPackage params;
for (auto& poller : device_pollers) {
params = poller->GetNextInput();
if (params.Has("engine")) {
SetPollingResult(params, false);
return;
}
const auto& params = input_subsystem->GetNextInput();
if (params.Has("engine")) {
SetPollingResult(params, false);
return;
}
});
}
@ -248,11 +245,7 @@ void ConfigureTouchFromButton::GetButtonInput(const int row_index, const bool is
}
};
device_pollers = input_subsystem->GetPollers(InputCommon::Polling::DeviceType::Button);
for (auto& poller : device_pollers) {
poller->Start();
}
input_subsystem->BeginMapping(InputCommon::Polling::InputType::Button);
grabKeyboard();
grabMouse();
@ -365,14 +358,14 @@ void ConfigureTouchFromButton::SetCoordinates(const int dot_id, const QPoint& po
void ConfigureTouchFromButton::SetPollingResult(const Common::ParamPackage& params,
const bool cancel) {
timeout_timer->stop();
poll_timer->stop();
input_subsystem->StopMapping();
releaseKeyboard();
releaseMouse();
qApp->restoreOverrideCursor();
timeout_timer->stop();
poll_timer->stop();
for (auto& poller : device_pollers) {
poller->Stop();
}
if (input_setter) {
(*input_setter)(params, cancel);
input_setter.reset();

View File

@ -24,10 +24,6 @@ namespace InputCommon {
class InputSubsystem;
}
namespace InputCommon::Polling {
class DevicePoller;
}
namespace Settings {
struct TouchFromButtonMap;
}
@ -85,7 +81,6 @@ private:
std::unique_ptr<QTimer> timeout_timer;
std::unique_ptr<QTimer> poll_timer;
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
std::optional<std::function<void(const Common::ParamPackage&, bool)>> input_setter;
static constexpr int DataRoleDot = Qt::ItemDataRole::UserRole + 2;

View File

@ -59,80 +59,6 @@ void ConfigureVibration::ApplyConfiguration() {
ui->checkBoxAccurateVibration->isChecked());
}
void ConfigureVibration::SetVibrationDevices(std::size_t player_index) {
using namespace Settings::NativeButton;
static constexpr std::array<std::array<Settings::NativeButton::Values, 6>, 2> buttons{{
{DLeft, DUp, DRight, DDown, L, ZL}, // Left Buttons
{A, B, X, Y, R, ZR}, // Right Buttons
}};
auto& player = Settings::values.players.GetValue()[player_index];
for (std::size_t device_idx = 0; device_idx < buttons.size(); ++device_idx) {
std::unordered_map<std::string, int> params_count;
for (const auto button_index : buttons[device_idx]) {
const auto& player_button = player.buttons[button_index];
if (params_count.find(player_button) != params_count.end()) {
++params_count[player_button];
continue;
}
params_count.insert_or_assign(player_button, 1);
}
const auto it = std::max_element(
params_count.begin(), params_count.end(),
[](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; });
auto& vibration_param_str = player.vibrations[device_idx];
vibration_param_str.clear();
if (it->first.empty()) {
continue;
}
const auto param = Common::ParamPackage(it->first);
const auto engine = param.Get("engine", "");
const auto guid = param.Get("guid", "");
const auto port = param.Get("port", "");
if (engine.empty() || engine == "keyboard" || engine == "mouse" || engine == "tas") {
continue;
}
vibration_param_str += fmt::format("engine:{}", engine);
if (!port.empty()) {
vibration_param_str += fmt::format(",port:{}", port);
}
if (!guid.empty()) {
vibration_param_str += fmt::format(",guid:{}", guid);
}
}
if (player.vibrations[0] != player.vibrations[1]) {
return;
}
if (!player.vibrations[0].empty() &&
player.controller_type != Settings::ControllerType::RightJoycon) {
player.vibrations[1].clear();
} else if (!player.vibrations[1].empty() &&
player.controller_type == Settings::ControllerType::RightJoycon) {
player.vibrations[0].clear();
}
}
void ConfigureVibration::SetAllVibrationDevices() {
// Set vibration devices for all player indices including handheld
for (std::size_t player_idx = 0; player_idx < NUM_PLAYERS + 1; ++player_idx) {
SetVibrationDevices(player_idx);
}
}
void ConfigureVibration::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();

View File

@ -24,9 +24,6 @@ public:
void ApplyConfiguration();
static void SetVibrationDevices(std::size_t player_index);
static void SetAllVibrationDevices();
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();

View File

@ -6,13 +6,17 @@
#include <QLayout>
#include <QString>
#include "common/settings.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "input_common/drivers/tas_input.h"
#include "input_common/main.h"
#include "input_common/tas/tas_input.h"
#include "yuzu/configuration/configure_input_player_widget.h"
#include "yuzu/debugger/controller.h"
ControllerDialog::ControllerDialog(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_)
: QWidget(parent, Qt::Dialog), input_subsystem{input_subsystem_} {
ControllerDialog::ControllerDialog(Core::HID::HIDCore& hid_core_,
std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_,
QWidget* parent)
: QWidget(parent, Qt::Dialog), hid_core{hid_core_}, input_subsystem{input_subsystem_} {
setObjectName(QStringLiteral("Controller"));
setWindowTitle(tr("Controller P1"));
resize(500, 350);
@ -31,20 +35,24 @@ ControllerDialog::ControllerDialog(QWidget* parent, InputCommon::InputSubsystem*
// Configure focus so that widget is focusable and the dialog automatically forwards focus to
// it.
setFocusProxy(widget);
widget->SetConnectedStatus(false);
widget->setFocusPolicy(Qt::StrongFocus);
widget->setFocus();
}
void ControllerDialog::refreshConfiguration() {
const auto& players = Settings::values.players.GetValue();
constexpr std::size_t player = 0;
widget->SetPlayerInputRaw(player, players[player].buttons, players[player].analogs);
widget->SetControllerType(players[player].controller_type);
ControllerCallback callback{[this](ControllerInput input) { InputController(input); }};
widget->SetCallBack(callback);
widget->repaint();
widget->SetConnectedStatus(players[player].connected);
UnloadController();
auto* player_1 = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
// Display the correct controller
controller = handheld->IsConnected() ? handheld : player_1;
Core::HID::ControllerUpdateCallback engine_callback{
.on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdate(type); },
.is_npad_service = true,
};
callback_key = controller->SetCallback(engine_callback);
widget->SetController(controller);
is_controller_set = true;
}
QAction* ControllerDialog::toggleViewAction() {
@ -58,11 +66,18 @@ QAction* ControllerDialog::toggleViewAction() {
return toggle_view_action;
}
void ControllerDialog::UnloadController() {
widget->UnloadController();
if (is_controller_set) {
controller->DeleteCallback(callback_key);
is_controller_set = false;
}
}
void ControllerDialog::showEvent(QShowEvent* ev) {
if (toggle_view_action) {
toggle_view_action->setChecked(isVisible());
}
refreshConfiguration();
QWidget::showEvent(ev);
}
@ -70,16 +85,34 @@ void ControllerDialog::hideEvent(QHideEvent* ev) {
if (toggle_view_action) {
toggle_view_action->setChecked(isVisible());
}
widget->SetConnectedStatus(false);
QWidget::hideEvent(ev);
}
void ControllerDialog::InputController(ControllerInput input) {
u32 buttons = 0;
int index = 0;
for (bool btn : input.button_values) {
buttons |= (btn ? 1U : 0U) << index;
index++;
void ControllerDialog::ControllerUpdate(Core::HID::ControllerTriggerType type) {
// TODO(german77): Remove TAS from here
switch (type) {
case Core::HID::ControllerTriggerType::Button:
case Core::HID::ControllerTriggerType::Stick: {
const auto buttons_values = controller->GetButtonsValues();
const auto stick_values = controller->GetSticksValues();
u64 buttons = 0;
std::size_t index = 0;
for (const auto& button : buttons_values) {
buttons |= button.value ? 1LLU << index : 0;
index++;
}
const InputCommon::TasInput::TasAnalog left_axis = {
.x = stick_values[Settings::NativeAnalog::LStick].x.value,
.y = stick_values[Settings::NativeAnalog::LStick].y.value,
};
const InputCommon::TasInput::TasAnalog right_axis = {
.x = stick_values[Settings::NativeAnalog::RStick].x.value,
.y = stick_values[Settings::NativeAnalog::RStick].y.value,
};
input_subsystem->GetTas()->RecordInput(buttons, left_axis, right_axis);
break;
}
default:
break;
}
input_subsystem->GetTas()->RecordInput(buttons, input.axis_values);
}

View File

@ -4,9 +4,7 @@
#pragma once
#include <QFileSystemWatcher>
#include <QWidget>
#include "common/settings.h"
class QAction;
class QHideEvent;
@ -17,35 +15,43 @@ namespace InputCommon {
class InputSubsystem;
}
struct ControllerInput {
std::array<std::pair<float, float>, Settings::NativeAnalog::NUM_STICKS_HID> axis_values{};
std::array<bool, Settings::NativeButton::NumButtons> button_values{};
bool changed{};
};
struct ControllerCallback {
std::function<void(ControllerInput)> input;
};
namespace Core::HID {
class HIDCore;
class EmulatedController;
enum class ControllerTriggerType;
} // namespace Core::HID
class ControllerDialog : public QWidget {
Q_OBJECT
public:
explicit ControllerDialog(QWidget* parent = nullptr,
InputCommon::InputSubsystem* input_subsystem_ = nullptr);
explicit ControllerDialog(Core::HID::HIDCore& hid_core_,
std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_,
QWidget* parent = nullptr);
/// Returns a QAction that can be used to toggle visibility of this dialog.
QAction* toggleViewAction();
/// Reloads the widget to apply any changes in the configuration
void refreshConfiguration();
/// Disables events from the emulated controller
void UnloadController();
protected:
void showEvent(QShowEvent* ev) override;
void hideEvent(QHideEvent* ev) override;
private:
void InputController(ControllerInput input);
/// Redirects input from the widget to the TAS driver
void ControllerUpdate(Core::HID::ControllerTriggerType type);
int callback_key;
bool is_controller_set{};
Core::HID::EmulatedController* controller;
QAction* toggle_view_action = nullptr;
QFileSystemWatcher* watcher = nullptr;
PlayerControlPreview* widget;
InputCommon::InputSubsystem* input_subsystem;
Core::HID::HIDCore& hid_core;
std::shared_ptr<InputCommon::InputSubsystem> input_subsystem;
};

View File

@ -26,6 +26,8 @@
#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
@ -106,8 +108,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "core/loader/loader.h"
#include "core/perf_stats.h"
#include "core/telemetry_session.h"
#include "input_common/drivers/tas_input.h"
#include "input_common/main.h"
#include "input_common/tas/tas_input.h"
#include "ui_main.h"
#include "util/overlay_dialog.h"
#include "video_core/gpu.h"
@ -227,6 +229,9 @@ GMainWindow::GMainWindow()
ConnectMenuEvents();
ConnectWidgetEvents();
system->HIDCore().ReloadInputDevices();
controller_dialog->refreshConfiguration();
const auto branch_name = std::string(Common::g_scm_branch);
const auto description = std::string(Common::g_scm_desc);
const auto build_id = std::string(Common::g_build_id);
@ -829,15 +834,16 @@ void GMainWindow::InitializeWidgets() {
dock_status_button->setFocusPolicy(Qt::NoFocus);
connect(dock_status_button, &QPushButton::clicked, [&] {
const bool is_docked = Settings::values.use_docked_mode.GetValue();
auto& controller_type = Settings::values.players.GetValue()[0].controller_type;
auto* player_1 = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
auto* handheld = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
if (!is_docked && controller_type == Settings::ControllerType::Handheld) {
if (!is_docked && handheld->IsConnected()) {
QMessageBox::warning(this, tr("Invalid config detected"),
tr("Handheld controller can't be used on docked mode. Pro "
"controller will be selected."));
controller_type = Settings::ControllerType::ProController;
ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), *system);
configure_dialog.ApplyConfiguration();
handheld->Disconnect();
player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
player_1->Connect();
controller_dialog->refreshConfiguration();
}
@ -922,7 +928,7 @@ void GMainWindow::InitializeDebugWidgets() {
waitTreeWidget->hide();
debug_menu->addAction(waitTreeWidget->toggleViewAction());
controller_dialog = new ControllerDialog(this, input_subsystem.get());
controller_dialog = new ControllerDialog(system->HIDCore(), input_subsystem, this);
controller_dialog->hide();
debug_menu->addAction(controller_dialog->toggleViewAction());
@ -1374,8 +1380,6 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
Config per_game_config(*system, config_file_name, Config::ConfigType::PerGameConfig);
}
ConfigureVibration::SetAllVibrationDevices();
// Disable fps limit toggle when booting a new title
Settings::values.disable_fps_limit.SetValue(false);
@ -2708,7 +2712,6 @@ void GMainWindow::OnConfigure() {
ShowTelemetryCallout();
}
controller_dialog->refreshConfiguration();
InitializeHotkeys();
if (UISettings::values.theme != old_theme) {
@ -2741,6 +2744,7 @@ void GMainWindow::OnConfigure() {
}
UpdateStatusButtons();
controller_dialog->refreshConfiguration();
}
void GMainWindow::OnConfigureTas() {
@ -2971,11 +2975,11 @@ void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_vie
QString GMainWindow::GetTasStateDescription() const {
auto [tas_status, current_tas_frame, total_tas_frames] = input_subsystem->GetTas()->GetStatus();
switch (tas_status) {
case TasInput::TasState::Running:
case InputCommon::TasInput::TasState::Running:
return tr("TAS state: Running %1/%2").arg(current_tas_frame).arg(total_tas_frames);
case TasInput::TasState::Recording:
case InputCommon::TasInput::TasState::Recording:
return tr("TAS state: Recording %1").arg(total_tas_frames);
case TasInput::TasState::Stopped:
case InputCommon::TasInput::TasState::Stopped:
return tr("TAS state: Idle %1/%2").arg(current_tas_frame).arg(total_tas_frames);
default:
return tr("TAS State: Invalid");
@ -2986,9 +2990,10 @@ void GMainWindow::OnTasStateChanged() {
bool is_running = false;
bool is_recording = false;
if (emulation_running) {
const TasInput::TasState tas_status = std::get<0>(input_subsystem->GetTas()->GetStatus());
is_running = tas_status == TasInput::TasState::Running;
is_recording = tas_status == TasInput::TasState::Recording;
const InputCommon::TasInput::TasState tas_status =
std::get<0>(input_subsystem->GetTas()->GetStatus());
is_running = tas_status == InputCommon::TasInput::TasState::Running;
is_recording = tas_status == InputCommon::TasInput::TasState::Recording;
}
ui->action_TAS_Start->setText(is_running ? tr("&Stop Running") : tr("&Start"));
@ -3371,6 +3376,8 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
UpdateUISettings();
game_list->SaveInterfaceLayout();
hotkey_registry.SaveHotkeys();
controller_dialog->UnloadController();
system->HIDCore().UnloadInputDevices();
// Shutdown session if the emu thread is active...
if (emu_thread != nullptr) {

View File

@ -6,7 +6,8 @@
#include <QScreen>
#include "core/core.h"
#include "core/frontend/input_interpreter.h"
#include "core/hid/hid_types.h"
#include "core/hid/input_interpreter.h"
#include "ui_overlay_dialog.h"
#include "yuzu/util/overlay_dialog.h"
@ -179,9 +180,9 @@ void OverlayDialog::MoveAndResizeWindow() {
QDialog::resize(width, height);
}
template <HIDButton... T>
template <Core::HID::NpadButton... T>
void OverlayDialog::HandleButtonPressedOnce() {
const auto f = [this](HIDButton button) {
const auto f = [this](Core::HID::NpadButton button) {
if (input_interpreter->IsButtonPressedOnce(button)) {
TranslateButtonPress(button);
}
@ -190,7 +191,7 @@ void OverlayDialog::HandleButtonPressedOnce() {
(f(T), ...);
}
void OverlayDialog::TranslateButtonPress(HIDButton button) {
void OverlayDialog::TranslateButtonPress(Core::HID::NpadButton button) {
QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel;
QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok_label;
@ -198,20 +199,20 @@ void OverlayDialog::TranslateButtonPress(HIDButton button) {
// TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it
switch (button) {
case HIDButton::A:
case HIDButton::B:
case Core::HID::NpadButton::A:
case Core::HID::NpadButton::B:
if (left_button->hasFocus()) {
left_button->click();
} else if (right_button->hasFocus()) {
right_button->click();
}
break;
case HIDButton::DLeft:
case HIDButton::LStickLeft:
case Core::HID::NpadButton::Left:
case Core::HID::NpadButton::StickLLeft:
focusPreviousChild();
break;
case HIDButton::DRight:
case HIDButton::LStickRight:
case Core::HID::NpadButton::Right:
case Core::HID::NpadButton::StickLRight:
focusNextChild();
break;
default:
@ -241,8 +242,10 @@ void OverlayDialog::InputThread() {
while (input_thread_running) {
input_interpreter->PollInput();
HandleButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::DLeft, HIDButton::DRight,
HIDButton::LStickLeft, HIDButton::LStickRight>();
HandleButtonPressedOnce<Core::HID::NpadButton::A, Core::HID::NpadButton::B,
Core::HID::NpadButton::Left, Core::HID::NpadButton::Right,
Core::HID::NpadButton::StickLLeft,
Core::HID::NpadButton::StickLRight>();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}

View File

@ -13,14 +13,16 @@
#include "common/common_types.h"
enum class HIDButton : u8;
class InputInterpreter;
namespace Core {
class System;
}
namespace Core::HID {
enum class NpadButton : u64;
}
namespace Ui {
class OverlayDialog;
}
@ -79,7 +81,7 @@ private:
*
* @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/
template <HIDButton... T>
template <Core::HID::NpadButton... T>
void HandleButtonPressedOnce();
/**
@ -87,7 +89,7 @@ private:
*
* @param button The button press to process.
*/
void TranslateButtonPress(HIDButton button);
void TranslateButtonPress(Core::HID::NpadButton button);
void StartInputThread();
void StopInputThread();