Browse Source
Merge pull request #1634 from DarkLordZach/better-hid-2
Merge pull request #1634 from DarkLordZach/better-hid-2
hid: Add support for multiplayer and multilayout controllerspull/15/merge
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 4618 additions and 1321 deletions
-
7src/core/frontend/input.h
-
42src/core/hle/service/hid/controllers/debug_pad.cpp
-
41src/core/hle/service/hid/controllers/debug_pad.h
-
20src/core/hle/service/hid/controllers/keyboard.cpp
-
7src/core/hle/service/hid/controllers/keyboard.h
-
25src/core/hle/service/hid/controllers/mouse.cpp
-
9src/core/hle/service/hid/controllers/mouse.h
-
464src/core/hle/service/hid/controllers/npad.cpp
-
45src/core/hle/service/hid/controllers/npad.h
-
13src/core/hle/service/hid/controllers/touchscreen.cpp
-
12src/core/hle/service/hid/controllers/touchscreen.h
-
4src/core/hle/service/hid/hid.cpp
-
50src/core/settings.cpp
-
318src/core/settings.h
-
9src/yuzu/CMakeLists.txt
-
385src/yuzu/configuration/config.cpp
-
14src/yuzu/configuration/config.h
-
36src/yuzu/configuration/configure_general.cpp
-
1src/yuzu/configuration/configure_general.h
-
9src/yuzu/configuration/configure_general.ui
-
436src/yuzu/configuration/configure_input.cpp
-
52src/yuzu/configuration/configure_input.h
-
1064src/yuzu/configuration/configure_input.ui
-
508src/yuzu/configuration/configure_input_player.cpp
-
103src/yuzu/configuration/configure_input_player.h
-
1164src/yuzu/configuration/configure_input_player.ui
-
213src/yuzu/configuration/configure_mouse_advanced.cpp
-
68src/yuzu/configuration/configure_mouse_advanced.h
-
261src/yuzu/configuration/configure_mouse_advanced.ui
-
42src/yuzu/configuration/configure_touchscreen_advanced.cpp
-
32src/yuzu/configuration/configure_touchscreen_advanced.h
-
199src/yuzu/configuration/configure_touchscreen_advanced.ui
-
286src/yuzu_cmd/config.cpp
1064
src/yuzu/configuration/configure_input.ui
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,508 @@ |
|||
// Copyright 2016 Citra Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <algorithm>
|
|||
#include <memory>
|
|||
#include <utility>
|
|||
#include <QColorDialog>
|
|||
#include <QMenu>
|
|||
#include <QMessageBox>
|
|||
#include <QTimer>
|
|||
#include "common/assert.h"
|
|||
#include "common/param_package.h"
|
|||
#include "input_common/main.h"
|
|||
#include "ui_configure_input_player.h"
|
|||
#include "yuzu/configuration/config.h"
|
|||
#include "yuzu/configuration/configure_input_player.h"
|
|||
|
|||
const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM> |
|||
ConfigureInputPlayer::analog_sub_buttons{{ |
|||
"up", |
|||
"down", |
|||
"left", |
|||
"right", |
|||
"modifier", |
|||
}}; |
|||
|
|||
static void MoveGridElement(QGridLayout* grid, int row_old, int column_old, int row_new, |
|||
int column_new) { |
|||
const auto item = grid->itemAtPosition(row_old, column_old); |
|||
// grid->removeItem(item);
|
|||
grid->addItem(item, row_new, column_new); |
|||
} |
|||
|
|||
static void LayerGridElements(QGridLayout* grid, QWidget* item, QWidget* onTopOf) { |
|||
const int index1 = grid->indexOf(item); |
|||
const int index2 = grid->indexOf(onTopOf); |
|||
int row, column, rowSpan, columnSpan; |
|||
grid->getItemPosition(index2, &row, &column, &rowSpan, &columnSpan); |
|||
grid->takeAt(index1); |
|||
grid->addWidget(item, row, column, rowSpan, columnSpan); |
|||
} |
|||
|
|||
static QString GetKeyName(int key_code) { |
|||
switch (key_code) { |
|||
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 void SetAnalogButton(const Common::ParamPackage& input_param, |
|||
Common::ParamPackage& analog_param, const std::string& button_name) { |
|||
if (analog_param.Get("engine", "") != "analog_from_button") { |
|||
analog_param = { |
|||
{"engine", "analog_from_button"}, |
|||
{"modifier_scale", "0.5"}, |
|||
}; |
|||
} |
|||
analog_param.Set(button_name, input_param.Serialize()); |
|||
} |
|||
|
|||
static QString ButtonToText(const Common::ParamPackage& param) { |
|||
if (!param.Has("engine")) { |
|||
return QObject::tr("[not set]"); |
|||
} else if (param.Get("engine", "") == "keyboard") { |
|||
return GetKeyName(param.Get("code", 0)); |
|||
} else if (param.Get("engine", "") == "sdl") { |
|||
if (param.Has("hat")) { |
|||
return QString(QObject::tr("Hat %1 %2")) |
|||
.arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str()); |
|||
} |
|||
if (param.Has("axis")) { |
|||
return QString(QObject::tr("Axis %1%2")) |
|||
.arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str()); |
|||
} |
|||
if (param.Has("button")) { |
|||
return QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str()); |
|||
} |
|||
return QString(); |
|||
} else { |
|||
return QObject::tr("[unknown]"); |
|||
} |
|||
}; |
|||
|
|||
static QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) { |
|||
if (!param.Has("engine")) { |
|||
return QObject::tr("[not set]"); |
|||
} else if (param.Get("engine", "") == "analog_from_button") { |
|||
return ButtonToText(Common::ParamPackage{param.Get(dir, "")}); |
|||
} else if (param.Get("engine", "") == "sdl") { |
|||
if (dir == "modifier") { |
|||
return QString(QObject::tr("[unused]")); |
|||
} |
|||
|
|||
if (dir == "left" || dir == "right") { |
|||
return QString(QObject::tr("Axis %1")).arg(param.Get("axis_x", "").c_str()); |
|||
} else if (dir == "up" || dir == "down") { |
|||
return QString(QObject::tr("Axis %1")).arg(param.Get("axis_y", "").c_str()); |
|||
} |
|||
return QString(); |
|||
} else { |
|||
return QObject::tr("[unknown]"); |
|||
} |
|||
}; |
|||
|
|||
ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, u8 player_index, bool debug) |
|||
: QDialog(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), |
|||
timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()), |
|||
player_index(player_index), debug(debug) { |
|||
|
|||
ui->setupUi(this); |
|||
setFocusPolicy(Qt::ClickFocus); |
|||
|
|||
button_map = { |
|||
ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, |
|||
ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR, |
|||
ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus, |
|||
ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown, |
|||
ui->buttonLStickLeft, ui->buttonLStickUp, ui->buttonLStickRight, ui->buttonLStickDown, |
|||
ui->buttonRStickLeft, ui->buttonRStickUp, ui->buttonRStickRight, ui->buttonRStickDown, |
|||
ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot, |
|||
}; |
|||
|
|||
analog_map_buttons = {{ |
|||
{ |
|||
ui->buttonLStickUp, |
|||
ui->buttonLStickDown, |
|||
ui->buttonLStickLeft, |
|||
ui->buttonLStickRight, |
|||
ui->buttonLStickMod, |
|||
}, |
|||
{ |
|||
ui->buttonRStickUp, |
|||
ui->buttonRStickDown, |
|||
ui->buttonRStickLeft, |
|||
ui->buttonRStickRight, |
|||
ui->buttonRStickMod, |
|||
}, |
|||
}}; |
|||
|
|||
debug_hidden = { |
|||
ui->buttonSL, ui->labelSL, |
|||
ui->buttonSR, ui->labelSR, |
|||
ui->buttonLStick, ui->labelLStickPressed, |
|||
ui->buttonRStick, ui->labelRStickPressed, |
|||
ui->buttonHome, ui->labelHome, |
|||
ui->buttonScreenshot, ui->labelScreenshot, |
|||
}; |
|||
|
|||
auto layout = Settings::values.players[player_index].type; |
|||
if (debug) |
|||
layout = Settings::ControllerType::DualJoycon; |
|||
|
|||
switch (layout) { |
|||
case Settings::ControllerType::ProController: |
|||
case Settings::ControllerType::DualJoycon: |
|||
layout_hidden = { |
|||
ui->buttonSL, |
|||
ui->labelSL, |
|||
ui->buttonSR, |
|||
ui->labelSR, |
|||
}; |
|||
break; |
|||
case Settings::ControllerType::LeftJoycon: |
|||
layout_hidden = { |
|||
ui->right_body_button, |
|||
ui->right_buttons_button, |
|||
ui->right_body_label, |
|||
ui->right_buttons_label, |
|||
ui->buttonR, |
|||
ui->labelR, |
|||
ui->buttonZR, |
|||
ui->labelZR, |
|||
ui->labelHome, |
|||
ui->buttonHome, |
|||
ui->buttonPlus, |
|||
ui->labelPlus, |
|||
ui->RStick, |
|||
ui->faceButtons, |
|||
}; |
|||
break; |
|||
case Settings::ControllerType::RightJoycon: |
|||
layout_hidden = { |
|||
ui->left_body_button, ui->left_buttons_button, |
|||
ui->left_body_label, ui->left_buttons_label, |
|||
ui->buttonL, ui->labelL, |
|||
ui->buttonZL, ui->labelZL, |
|||
ui->labelScreenshot, ui->buttonScreenshot, |
|||
ui->buttonMinus, ui->labelMinus, |
|||
ui->LStick, ui->Dpad, |
|||
}; |
|||
break; |
|||
} |
|||
|
|||
if (debug || layout == Settings::ControllerType::ProController) { |
|||
ui->controller_color->hide(); |
|||
} else { |
|||
if (layout == Settings::ControllerType::LeftJoycon || |
|||
layout == Settings::ControllerType::RightJoycon) { |
|||
ui->horizontalSpacer_4->setGeometry({0, 0, 0, 0}); |
|||
|
|||
LayerGridElements(ui->buttons, ui->shoulderButtons, ui->Dpad); |
|||
LayerGridElements(ui->buttons, ui->misc, ui->RStick); |
|||
LayerGridElements(ui->buttons, ui->Dpad, ui->faceButtons); |
|||
LayerGridElements(ui->buttons, ui->RStick, ui->LStick); |
|||
} |
|||
} |
|||
|
|||
for (auto* widget : layout_hidden) |
|||
widget->setVisible(false); |
|||
|
|||
analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog}; |
|||
|
|||
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { |
|||
if (!button_map[button_id]) |
|||
continue; |
|||
button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu); |
|||
connect(button_map[button_id], &QPushButton::released, [=]() { |
|||
handleClick( |
|||
button_map[button_id], |
|||
[=](const Common::ParamPackage& params) { buttons_param[button_id] = params; }, |
|||
InputCommon::Polling::DeviceType::Button); |
|||
}); |
|||
connect(button_map[button_id], &QPushButton::customContextMenuRequested, |
|||
[=](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_buttons[button_id])}; |
|||
button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); |
|||
}); |
|||
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); |
|||
}); |
|||
} |
|||
|
|||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { |
|||
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { |
|||
if (!analog_map_buttons[analog_id][sub_button_id]) |
|||
continue; |
|||
analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy( |
|||
Qt::CustomContextMenu); |
|||
connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::released, [=]() { |
|||
handleClick(analog_map_buttons[analog_id][sub_button_id], |
|||
[=](const Common::ParamPackage& params) { |
|||
SetAnalogButton(params, analogs_param[analog_id], |
|||
analog_sub_buttons[sub_button_id]); |
|||
}, |
|||
InputCommon::Polling::DeviceType::Button); |
|||
}); |
|||
connect(analog_map_buttons[analog_id][sub_button_id], |
|||
&QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) { |
|||
QMenu context_menu; |
|||
context_menu.addAction(tr("Clear"), [&] { |
|||
analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); |
|||
analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); |
|||
}); |
|||
context_menu.addAction(tr("Restore Default"), [&] { |
|||
Common::ParamPackage params{InputCommon::GenerateKeyboardParam( |
|||
Config::default_analogs[analog_id][sub_button_id])}; |
|||
SetAnalogButton(params, analogs_param[analog_id], |
|||
analog_sub_buttons[sub_button_id]); |
|||
analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText( |
|||
analogs_param[analog_id], analog_sub_buttons[sub_button_id])); |
|||
}); |
|||
context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal( |
|||
menu_location)); |
|||
}); |
|||
} |
|||
connect(analog_map_stick[analog_id], &QPushButton::released, [=]() { |
|||
QMessageBox::information(this, tr("Information"), |
|||
tr("After pressing OK, first move your joystick horizontally, " |
|||
"and then vertically.")); |
|||
handleClick( |
|||
analog_map_stick[analog_id], |
|||
[=](const Common::ParamPackage& params) { analogs_param[analog_id] = params; }, |
|||
InputCommon::Polling::DeviceType::Analog); |
|||
}); |
|||
} |
|||
|
|||
connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); }); |
|||
connect(ui->buttonRestoreDefaults, &QPushButton::released, [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; |
|||
} |
|||
} |
|||
}); |
|||
|
|||
controller_color_buttons = { |
|||
ui->left_body_button, |
|||
ui->left_buttons_button, |
|||
ui->right_body_button, |
|||
ui->right_buttons_button, |
|||
}; |
|||
|
|||
for (std::size_t i = 0; i < controller_color_buttons.size(); ++i) { |
|||
connect(controller_color_buttons[i], &QPushButton::clicked, this, |
|||
std::bind(&ConfigureInputPlayer::OnControllerButtonClick, this, i)); |
|||
} |
|||
|
|||
this->loadConfiguration(); |
|||
this->resize(0, 0); |
|||
|
|||
// TODO(wwylele): enable this when we actually emulate it
|
|||
ui->buttonHome->setEnabled(false); |
|||
} |
|||
|
|||
ConfigureInputPlayer::~ConfigureInputPlayer() = default; |
|||
|
|||
void ConfigureInputPlayer::applyConfiguration() { |
|||
auto& buttons = |
|||
debug ? Settings::values.debug_pad_buttons : Settings::values.players[player_index].buttons; |
|||
auto& analogs = |
|||
debug ? Settings::values.debug_pad_analogs : Settings::values.players[player_index].analogs; |
|||
|
|||
std::transform(buttons_param.begin(), buttons_param.end(), buttons.begin(), |
|||
[](const Common::ParamPackage& param) { return param.Serialize(); }); |
|||
std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(), |
|||
[](const Common::ParamPackage& param) { return param.Serialize(); }); |
|||
|
|||
if (debug) |
|||
return; |
|||
|
|||
std::array<u32, 4> colors{}; |
|||
std::transform(controller_colors.begin(), controller_colors.end(), colors.begin(), |
|||
[](QColor color) { return color.rgb(); }); |
|||
|
|||
Settings::values.players[player_index].body_color_left = colors[0]; |
|||
Settings::values.players[player_index].button_color_left = colors[1]; |
|||
Settings::values.players[player_index].body_color_right = colors[2]; |
|||
Settings::values.players[player_index].button_color_right = colors[3]; |
|||
} |
|||
|
|||
void ConfigureInputPlayer::OnControllerButtonClick(int i) { |
|||
const QColor new_bg_color = QColorDialog::getColor(controller_colors[i]); |
|||
if (!new_bg_color.isValid()) |
|||
return; |
|||
controller_colors[i] = new_bg_color; |
|||
controller_color_buttons[i]->setStyleSheet( |
|||
QString("QPushButton { background-color: %1 }").arg(controller_colors[i].name())); |
|||
} |
|||
|
|||
void ConfigureInputPlayer::loadConfiguration() { |
|||
if (debug) { |
|||
std::transform(Settings::values.debug_pad_buttons.begin(), |
|||
Settings::values.debug_pad_buttons.end(), buttons_param.begin(), |
|||
[](const std::string& str) { return Common::ParamPackage(str); }); |
|||
std::transform(Settings::values.debug_pad_analogs.begin(), |
|||
Settings::values.debug_pad_analogs.end(), analogs_param.begin(), |
|||
[](const std::string& str) { return Common::ParamPackage(str); }); |
|||
} else { |
|||
std::transform(Settings::values.players[player_index].buttons.begin(), |
|||
Settings::values.players[player_index].buttons.end(), buttons_param.begin(), |
|||
[](const std::string& str) { return Common::ParamPackage(str); }); |
|||
std::transform(Settings::values.players[player_index].analogs.begin(), |
|||
Settings::values.players[player_index].analogs.end(), analogs_param.begin(), |
|||
[](const std::string& str) { return Common::ParamPackage(str); }); |
|||
} |
|||
|
|||
updateButtonLabels(); |
|||
|
|||
if (debug) |
|||
return; |
|||
|
|||
std::array<u32, 4> colors = { |
|||
Settings::values.players[player_index].body_color_left, |
|||
Settings::values.players[player_index].button_color_left, |
|||
Settings::values.players[player_index].body_color_right, |
|||
Settings::values.players[player_index].button_color_right, |
|||
}; |
|||
|
|||
std::transform(colors.begin(), colors.end(), controller_colors.begin(), |
|||
[](u32 rgb) { return QColor::fromRgb(rgb); }); |
|||
|
|||
for (std::size_t i = 0; i < colors.size(); ++i) { |
|||
controller_color_buttons[i]->setStyleSheet( |
|||
QString("QPushButton { background-color: %1 }").arg(controller_colors[i].name())); |
|||
} |
|||
} |
|||
|
|||
void ConfigureInputPlayer::restoreDefaults() { |
|||
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { |
|||
buttons_param[button_id] = Common::ParamPackage{ |
|||
InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; |
|||
} |
|||
|
|||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { |
|||
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { |
|||
Common::ParamPackage params{InputCommon::GenerateKeyboardParam( |
|||
Config::default_analogs[analog_id][sub_button_id])}; |
|||
SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]); |
|||
} |
|||
} |
|||
updateButtonLabels(); |
|||
} |
|||
|
|||
void ConfigureInputPlayer::ClearAll() { |
|||
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { |
|||
if (button_map[button_id] && button_map[button_id]->isEnabled()) |
|||
buttons_param[button_id].Clear(); |
|||
} |
|||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { |
|||
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { |
|||
if (analog_map_buttons[analog_id][sub_button_id] && |
|||
analog_map_buttons[analog_id][sub_button_id]->isEnabled()) |
|||
analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); |
|||
} |
|||
} |
|||
|
|||
updateButtonLabels(); |
|||
} |
|||
|
|||
void ConfigureInputPlayer::updateButtonLabels() { |
|||
for (int button = 0; button < Settings::NativeButton::NumButtons; button++) { |
|||
button_map[button]->setText(ButtonToText(buttons_param[button])); |
|||
} |
|||
|
|||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { |
|||
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { |
|||
if (analog_map_buttons[analog_id][sub_button_id]) { |
|||
analog_map_buttons[analog_id][sub_button_id]->setText( |
|||
AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id])); |
|||
} |
|||
} |
|||
analog_map_stick[analog_id]->setText(tr("Set Analog Stick")); |
|||
} |
|||
} |
|||
|
|||
void ConfigureInputPlayer::handleClick( |
|||
QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter, |
|||
InputCommon::Polling::DeviceType type) { |
|||
button->setText(tr("[press key]")); |
|||
button->setFocus(); |
|||
|
|||
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 = InputCommon::Polling::GetPollers(type); |
|||
|
|||
// Keyboard keys can only be used as button devices
|
|||
want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button; |
|||
|
|||
for (auto& poller : device_pollers) { |
|||
poller->Start(); |
|||
} |
|||
|
|||
grabKeyboard(); |
|||
grabMouse(); |
|||
timeout_timer->start(5000); // Cancel after 5 seconds
|
|||
poll_timer->start(200); // Check for new inputs every 200ms
|
|||
} |
|||
|
|||
void ConfigureInputPlayer::setPollingResult(const Common::ParamPackage& params, bool abort) { |
|||
releaseKeyboard(); |
|||
releaseMouse(); |
|||
timeout_timer->stop(); |
|||
poll_timer->stop(); |
|||
for (auto& poller : device_pollers) { |
|||
poller->Stop(); |
|||
} |
|||
|
|||
if (!abort) { |
|||
(*input_setter)(params); |
|||
} |
|||
|
|||
updateButtonLabels(); |
|||
input_setter = std::nullopt; |
|||
} |
|||
|
|||
void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) { |
|||
if (!input_setter || !event) |
|||
return; |
|||
|
|||
if (event->key() != Qt::Key_Escape) { |
|||
if (want_keyboard_keys) { |
|||
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); |
|||
} |
|||
@ -0,0 +1,103 @@ |
|||
// Copyright 2016 Citra Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <array> |
|||
#include <functional> |
|||
#include <memory> |
|||
#include <optional> |
|||
#include <string> |
|||
#include <unordered_map> |
|||
#include <QDialog> |
|||
#include <QKeyEvent> |
|||
#include "common/param_package.h" |
|||
#include "core/settings.h" |
|||
#include "input_common/main.h" |
|||
#include "ui_configure_input.h" |
|||
|
|||
class QPushButton; |
|||
class QString; |
|||
class QTimer; |
|||
|
|||
namespace Ui { |
|||
class ConfigureInputPlayer; |
|||
} |
|||
|
|||
class ConfigureInputPlayer : public QDialog { |
|||
Q_OBJECT |
|||
|
|||
public: |
|||
explicit ConfigureInputPlayer(QWidget* parent, u8 player_index, bool debug = false); |
|||
~ConfigureInputPlayer() override; |
|||
|
|||
/// Save all button configurations to settings file |
|||
void applyConfiguration(); |
|||
|
|||
private: |
|||
std::unique_ptr<Ui::ConfigureInputPlayer> ui; |
|||
|
|||
u8 player_index; |
|||
bool debug; |
|||
|
|||
std::unique_ptr<QTimer> timeout_timer; |
|||
std::unique_ptr<QTimer> poll_timer; |
|||
|
|||
/// 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; |
|||
|
|||
static constexpr int ANALOG_SUB_BUTTONS_NUM = 5; |
|||
|
|||
/// Each button input is represented by a QPushButton. |
|||
std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map; |
|||
|
|||
std::vector<QWidget*> debug_hidden; |
|||
std::vector<QWidget*> layout_hidden; |
|||
|
|||
/// A group of five QPushButtons represent one analog input. The buttons each represent up, |
|||
/// down, left, right, and modifier, respectively. |
|||
std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs> |
|||
analog_map_buttons; |
|||
|
|||
/// Analog inputs are also represented each with a single button, used to configure with an |
|||
/// actual analog stick |
|||
std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick; |
|||
|
|||
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 if keyboard keys are okay when configuring an input. If this is false, |
|||
/// keyboard events are ignored. |
|||
bool want_keyboard_keys = false; |
|||
|
|||
std::array<QPushButton*, 4> controller_color_buttons; |
|||
std::array<QColor, 4> controller_colors; |
|||
|
|||
void OnControllerButtonClick(int i); |
|||
|
|||
/// 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 key press events. |
|||
void keyPressEvent(QKeyEvent* event) override; |
|||
}; |
|||
1164
src/yuzu/configuration/configure_input_player.ui
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,213 @@ |
|||
// Copyright 2016 Citra Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <algorithm>
|
|||
#include <memory>
|
|||
#include <utility>
|
|||
#include <QKeyEvent>
|
|||
#include <QMenu>
|
|||
#include <QMessageBox>
|
|||
#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::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]"); |
|||
} else if (param.Get("engine", "") == "keyboard") { |
|||
return GetKeyName(param.Get("code", 0)); |
|||
} else if (param.Get("engine", "") == "sdl") { |
|||
if (param.Has("hat")) { |
|||
return QString(QObject::tr("Hat %1 %2")) |
|||
.arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str()); |
|||
} |
|||
if (param.Has("axis")) { |
|||
return QString(QObject::tr("Axis %1%2")) |
|||
.arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str()); |
|||
} |
|||
if (param.Has("button")) { |
|||
return QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str()); |
|||
} |
|||
return QString(); |
|||
} else { |
|||
return QObject::tr("[unknown]"); |
|||
} |
|||
} |
|||
|
|||
ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent) |
|||
: QDialog(parent), ui(std::make_unique<Ui::ConfigureMouseAdvanced>()), |
|||
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++) { |
|||
if (!button_map[button_id]) |
|||
continue; |
|||
button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu); |
|||
connect(button_map[button_id], &QPushButton::released, [=]() { |
|||
handleClick( |
|||
button_map[button_id], |
|||
[=](const Common::ParamPackage& params) { buttons_param[button_id] = params; }, |
|||
InputCommon::Polling::DeviceType::Button); |
|||
}); |
|||
connect(button_map[button_id], &QPushButton::customContextMenuRequested, |
|||
[=](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::released, [this] { ClearAll(); }); |
|||
connect(ui->buttonRestoreDefaults, &QPushButton::released, [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::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) { |
|||
if (button_map[i] && button_map[i]->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(); |
|||
|
|||
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 = InputCommon::Polling::GetPollers(type); |
|||
|
|||
// Keyboard keys can only be used as button devices
|
|||
want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button; |
|||
|
|||
for (auto& poller : device_pollers) { |
|||
poller->Start(); |
|||
} |
|||
|
|||
grabKeyboard(); |
|||
grabMouse(); |
|||
timeout_timer->start(5000); // Cancel after 5 seconds
|
|||
poll_timer->start(200); // Check for new inputs every 200ms
|
|||
} |
|||
|
|||
void ConfigureMouseAdvanced::setPollingResult(const Common::ParamPackage& params, bool abort) { |
|||
releaseKeyboard(); |
|||
releaseMouse(); |
|||
timeout_timer->stop(); |
|||
poll_timer->stop(); |
|||
for (auto& poller : device_pollers) { |
|||
poller->Stop(); |
|||
} |
|||
|
|||
if (!abort) { |
|||
(*input_setter)(params); |
|||
} |
|||
|
|||
updateButtonLabels(); |
|||
input_setter = std::nullopt; |
|||
} |
|||
|
|||
void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) { |
|||
if (!input_setter || !event) |
|||
return; |
|||
|
|||
if (event->key() != Qt::Key_Escape) { |
|||
if (want_keyboard_keys) { |
|||
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); |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
// 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> |
|||
#include <QWidget> |
|||
#include "core/settings.h" |
|||
|
|||
class QCheckBox; |
|||
class QPushButton; |
|||
class QTimer; |
|||
|
|||
namespace Ui { |
|||
class ConfigureMouseAdvanced; |
|||
} |
|||
|
|||
class ConfigureMouseAdvanced : public QDialog { |
|||
Q_OBJECT |
|||
|
|||
public: |
|||
explicit ConfigureMouseAdvanced(QWidget* parent); |
|||
~ConfigureMouseAdvanced() override; |
|||
|
|||
void applyConfiguration(); |
|||
|
|||
private: |
|||
std::unique_ptr<Ui::ConfigureMouseAdvanced> ui; |
|||
|
|||
/// 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_keys = false; |
|||
|
|||
/// 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 key press events. |
|||
void keyPressEvent(QKeyEvent* event) override; |
|||
}; |
|||
@ -0,0 +1,261 @@ |
|||
<?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>250</width> |
|||
<height>261</height> |
|||
</rect> |
|||
</property> |
|||
<property name="windowTitle"> |
|||
<string>Configure Mouse</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="0" column="4"> |
|||
<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>20</width> |
|||
<height>20</height> |
|||
</size> |
|||
</property> |
|||
</spacer> |
|||
</item> |
|||
<item row="0" column="3"> |
|||
<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>75</width> |
|||
<height>0</height> |
|||
</size> |
|||
</property> |
|||
<property name="text"> |
|||
<string/> |
|||
</property> |
|||
</widget> |
|||
</item> |
|||
</layout> |
|||
</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>20</width> |
|||
<height>20</height> |
|||
</size> |
|||
</property> |
|||
</spacer> |
|||
</item> |
|||
<item row="2" column="1"> |
|||
<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="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="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>75</width> |
|||
<height>0</height> |
|||
</size> |
|||
</property> |
|||
<property name="text"> |
|||
<string/> |
|||
</property> |
|||
</widget> |
|||
</item> |
|||
</layout> |
|||
</item> |
|||
<item row="3" column="3"> |
|||
<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="text"> |
|||
<string/> |
|||
</property> |
|||
</widget> |
|||
</item> |
|||
</layout> |
|||
</item> |
|||
</layout> |
|||
</widget> |
|||
</item> |
|||
<item> |
|||
<layout class="QHBoxLayout" name="horizontalLayout_6"> |
|||
<item> |
|||
<widget class="QPushButton" name="buttonClearAll"> |
|||
<property name="text"> |
|||
<string>Clear All</string> |
|||
</property> |
|||
</widget> |
|||
</item> |
|||
<item> |
|||
<widget class="QPushButton" name="buttonRestoreDefaults"> |
|||
<property name="text"> |
|||
<string>Restore 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>40</width> |
|||
<height>20</height> |
|||
</size> |
|||
</property> |
|||
</spacer> |
|||
</item> |
|||
</layout> |
|||
</item> |
|||
<item> |
|||
<widget class="QDialogButtonBox" name="buttonBox"> |
|||
<property name="standardButtons"> |
|||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> |
|||
</property> |
|||
</widget> |
|||
</item> |
|||
</layout> |
|||
</widget> |
|||
<resources/> |
|||
<connections> |
|||
<connection> |
|||
<sender>buttonBox</sender> |
|||
<signal>accepted()</signal> |
|||
<receiver>ConfigureMouseAdvanced</receiver> |
|||
<slot>accept()</slot> |
|||
<hints> |
|||
<hint type="sourcelabel"> |
|||
<x>124</x> |
|||
<y>266</y> |
|||
</hint> |
|||
<hint type="destinationlabel"> |
|||
<x>124</x> |
|||
<y>143</y> |
|||
</hint> |
|||
</hints> |
|||
</connection> |
|||
<connection> |
|||
<sender>buttonBox</sender> |
|||
<signal>rejected()</signal> |
|||
<receiver>ConfigureMouseAdvanced</receiver> |
|||
<slot>reject()</slot> |
|||
<hints> |
|||
<hint type="sourcelabel"> |
|||
<x>124</x> |
|||
<y>266</y> |
|||
</hint> |
|||
<hint type="destinationlabel"> |
|||
<x>124</x> |
|||
<y>143</y> |
|||
</hint> |
|||
</hints> |
|||
</connection> |
|||
</connections> |
|||
</ui> |
|||
@ -0,0 +1,42 @@ |
|||
// Copyright 2016 Citra Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <memory>
|
|||
#include "ui_configure_touchscreen_advanced.h"
|
|||
#include "yuzu/configuration/config.h"
|
|||
#include "yuzu/configuration/configure_touchscreen_advanced.h"
|
|||
|
|||
ConfigureTouchscreenAdvanced::ConfigureTouchscreenAdvanced(QWidget* parent) |
|||
: QDialog(parent), ui(std::make_unique<Ui::ConfigureTouchscreenAdvanced>()) { |
|||
ui->setupUi(this); |
|||
|
|||
connect(ui->restore_defaults_button, &QPushButton::pressed, this, |
|||
&ConfigureTouchscreenAdvanced::restoreDefaults); |
|||
|
|||
loadConfiguration(); |
|||
resize(0, 0); |
|||
} |
|||
|
|||
ConfigureTouchscreenAdvanced::~ConfigureTouchscreenAdvanced() = default; |
|||
|
|||
void ConfigureTouchscreenAdvanced::applyConfiguration() { |
|||
Settings::values.touchscreen.finger = ui->finger_box->value(); |
|||
Settings::values.touchscreen.diameter_x = ui->diameter_x_box->value(); |
|||
Settings::values.touchscreen.diameter_y = ui->diameter_y_box->value(); |
|||
Settings::values.touchscreen.rotation_angle = ui->angle_box->value(); |
|||
} |
|||
|
|||
void ConfigureTouchscreenAdvanced::loadConfiguration() { |
|||
ui->finger_box->setValue(Settings::values.touchscreen.finger); |
|||
ui->diameter_x_box->setValue(Settings::values.touchscreen.diameter_x); |
|||
ui->diameter_y_box->setValue(Settings::values.touchscreen.diameter_y); |
|||
ui->angle_box->setValue(Settings::values.touchscreen.rotation_angle); |
|||
} |
|||
|
|||
void ConfigureTouchscreenAdvanced::restoreDefaults() { |
|||
ui->finger_box->setValue(0); |
|||
ui->diameter_x_box->setValue(15); |
|||
ui->diameter_y_box->setValue(15); |
|||
ui->angle_box->setValue(0); |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
// Copyright 2016 Citra Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include <QDialog> |
|||
#include <QWidget> |
|||
#include "yuzu/configuration/config.h" |
|||
|
|||
namespace Ui { |
|||
class ConfigureTouchscreenAdvanced; |
|||
} |
|||
|
|||
class ConfigureTouchscreenAdvanced : public QDialog { |
|||
Q_OBJECT |
|||
|
|||
public: |
|||
explicit ConfigureTouchscreenAdvanced(QWidget* parent); |
|||
~ConfigureTouchscreenAdvanced() override; |
|||
|
|||
void applyConfiguration(); |
|||
|
|||
private: |
|||
/// Load configuration settings. |
|||
void loadConfiguration(); |
|||
/// Restore all buttons to their default values. |
|||
void restoreDefaults(); |
|||
|
|||
std::unique_ptr<Ui::ConfigureTouchscreenAdvanced> ui; |
|||
}; |
|||
@ -0,0 +1,199 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<ui version="4.0"> |
|||
<class>ConfigureTouchscreenAdvanced</class> |
|||
<widget class="QDialog" name="ConfigureTouchscreenAdvanced"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>0</x> |
|||
<y>0</y> |
|||
<width>298</width> |
|||
<height>339</height> |
|||
</rect> |
|||
</property> |
|||
<property name="windowTitle"> |
|||
<string>Configure Touchscreen</string> |
|||
</property> |
|||
<layout class="QVBoxLayout" name="verticalLayout"> |
|||
<item> |
|||
<widget class="QLabel" name="label_2"> |
|||
<property name="minimumSize"> |
|||
<size> |
|||
<width>280</width> |
|||
<height>0</height> |
|||
</size> |
|||
</property> |
|||
<property name="text"> |
|||
<string>Warning: The settings in this page affect the inner workings of yuzu's emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</string> |
|||
</property> |
|||
<property name="wordWrap"> |
|||
<bool>true</bool> |
|||
</property> |
|||
</widget> |
|||
</item> |
|||
<item> |
|||
<spacer name="verticalSpacer_2"> |
|||
<property name="orientation"> |
|||
<enum>Qt::Vertical</enum> |
|||
</property> |
|||
<property name="sizeType"> |
|||
<enum>QSizePolicy::Fixed</enum> |
|||
</property> |
|||
<property name="sizeHint" stdset="0"> |
|||
<size> |
|||
<width>20</width> |
|||
<height>20</height> |
|||
</size> |
|||
</property> |
|||
</spacer> |
|||
</item> |
|||
<item> |
|||
<widget class="QGroupBox" name="gridGroupBox"> |
|||
<property name="title"> |
|||
<string>Touch Parameters</string> |
|||
</property> |
|||
<layout class="QGridLayout" name="gridLayout"> |
|||
<item row="0" column="0"> |
|||
<spacer name="horizontalSpacer"> |
|||
<property name="orientation"> |
|||
<enum>Qt::Horizontal</enum> |
|||
</property> |
|||
<property name="sizeHint" stdset="0"> |
|||
<size> |
|||
<width>40</width> |
|||
<height>20</height> |
|||
</size> |
|||
</property> |
|||
</spacer> |
|||
</item> |
|||
<item row="2" column="1"> |
|||
<widget class="QLabel" name="label_4"> |
|||
<property name="text"> |
|||
<string>Touch Diameter Y</string> |
|||
</property> |
|||
</widget> |
|||
</item> |
|||
<item row="0" column="1"> |
|||
<widget class="QLabel" name="label"> |
|||
<property name="text"> |
|||
<string>Finger</string> |
|||
</property> |
|||
</widget> |
|||
</item> |
|||
<item row="0" column="3"> |
|||
<spacer name="horizontalSpacer_2"> |
|||
<property name="orientation"> |
|||
<enum>Qt::Horizontal</enum> |
|||
</property> |
|||
<property name="sizeHint" stdset="0"> |
|||
<size> |
|||
<width>40</width> |
|||
<height>20</height> |
|||
</size> |
|||
</property> |
|||
</spacer> |
|||
</item> |
|||
<item row="1" column="1"> |
|||
<widget class="QLabel" name="label_3"> |
|||
<property name="text"> |
|||
<string>Touch Diameter X</string> |
|||
</property> |
|||
</widget> |
|||
</item> |
|||
<item row="0" column="2"> |
|||
<widget class="QSpinBox" name="finger_box"> |
|||
<property name="minimumSize"> |
|||
<size> |
|||
<width>80</width> |
|||
<height>0</height> |
|||
</size> |
|||
</property> |
|||
</widget> |
|||
</item> |
|||
<item row="3" column="1"> |
|||
<widget class="QLabel" name="label_5"> |
|||
<property name="text"> |
|||
<string>Rotational Angle</string> |
|||
</property> |
|||
</widget> |
|||
</item> |
|||
<item row="1" column="2"> |
|||
<widget class="QSpinBox" name="diameter_x_box"/> |
|||
</item> |
|||
<item row="2" column="2"> |
|||
<widget class="QSpinBox" name="diameter_y_box"/> |
|||
</item> |
|||
<item row="3" column="2"> |
|||
<widget class="QSpinBox" name="angle_box"/> |
|||
</item> |
|||
</layout> |
|||
</widget> |
|||
</item> |
|||
<item> |
|||
<spacer name="verticalSpacer"> |
|||
<property name="orientation"> |
|||
<enum>Qt::Vertical</enum> |
|||
</property> |
|||
<property name="sizeHint" stdset="0"> |
|||
<size> |
|||
<width>20</width> |
|||
<height>40</height> |
|||
</size> |
|||
</property> |
|||
</spacer> |
|||
</item> |
|||
<item> |
|||
<layout class="QHBoxLayout" name="horizontalLayout"> |
|||
<item> |
|||
<widget class="QPushButton" name="restore_defaults_button"> |
|||
<property name="text"> |
|||
<string>Restore Defaults</string> |
|||
</property> |
|||
</widget> |
|||
</item> |
|||
<item> |
|||
<widget class="QDialogButtonBox" name="buttonBox"> |
|||
<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>ConfigureTouchscreenAdvanced</receiver> |
|||
<slot>accept()</slot> |
|||
<hints> |
|||
<hint type="sourcelabel"> |
|||
<x>140</x> |
|||
<y>318</y> |
|||
</hint> |
|||
<hint type="destinationlabel"> |
|||
<x>140</x> |
|||
<y>169</y> |
|||
</hint> |
|||
</hints> |
|||
</connection> |
|||
<connection> |
|||
<sender>buttonBox</sender> |
|||
<signal>rejected()</signal> |
|||
<receiver>ConfigureTouchscreenAdvanced</receiver> |
|||
<slot>reject()</slot> |
|||
<hints> |
|||
<hint type="sourcelabel"> |
|||
<x>140</x> |
|||
<y>318</y> |
|||
</hint> |
|||
<hint type="destinationlabel"> |
|||
<x>140</x> |
|||
<y>169</y> |
|||
</hint> |
|||
</hints> |
|||
</connection> |
|||
</connections> |
|||
</ui> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue