mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
feat(input): add host input remapping
Add compact keyboard and mouse mapping with analog-stick defaults and integrate a global remapping editor into the Qt launcher. Based on the host input remapping work from PR #109. Co-authored-by: DistantMyth <thetarun3@gmail.com>
This commit is contained in:
@@ -16,6 +16,7 @@ file(GLOB launcher_forms
|
||||
add_executable(launcher WIN32
|
||||
${launcher_src}
|
||||
${launcher_forms}
|
||||
resources.qrc
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -69,6 +69,31 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="input_mapping_button">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>36</width>
|
||||
<height>36</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Edit input mapping</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="edit_button">
|
||||
<property name="minimumSize">
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<g fill="none" stroke="#e8f1ff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||
<path d="M8 4h11l5 5v7M24 9h-5V4M16 27H8a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2"/>
|
||||
<path d="m15 24 1-4 8-8 4 4-8 8-4 1Z"/>
|
||||
<path d="m22 14 4 4" opacity=".8"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 336 B |
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<g fill="none" stroke="#e8f1ff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||
<path d="M5 8h3M14 8h13M5 16h13M24 16h3M5 24h6M17 24h10"/>
|
||||
<circle cx="11" cy="8" r="3"/>
|
||||
<circle cx="21" cy="16" r="3"/>
|
||||
<circle cx="14" cy="24" r="3"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 344 B |
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<g fill="none" stroke="#e8f1ff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||
<path d="M10 10h12c3.6 0 5.8 2.3 6.6 6.8l.9 5.1c.4 2.4-.8 4.1-2.8 4.1-1.4 0-2.5-.7-3.6-2.3L21.3 21H10.7l-1.8 2.7C7.8 25.3 6.7 26 5.3 26c-2 0-3.2-1.7-2.8-4.1l.9-5.1C4.2 12.3 6.4 10 10 10Z"/>
|
||||
<path d="M8 16h6M11 13v6"/>
|
||||
<circle cx="22" cy="15" r="1" fill="#e8f1ff" stroke="none"/>
|
||||
<circle cx="25" cy="18" r="1" fill="#e8f1ff" stroke="none"/>
|
||||
<path d="M13 7h6M16 4v6" opacity=".8"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 574 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<g fill="none" stroke="#e8f1ff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||
<path d="M6 9h20M12 9V5h8v4M9 9l1 18h12l1-18"/>
|
||||
<path d="M14 14v8M18 14v8" opacity=".8"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 272 B |
@@ -99,6 +99,7 @@ public:
|
||||
QString printf_output_file = "_kyty.txt";
|
||||
ProfilerDirection profiler_direction = ProfilerDirection::None;
|
||||
bool renderdoc_enabled = false;
|
||||
QStringList host_input_mapping;
|
||||
|
||||
QString elf = QStringLiteral("eboot.bin");
|
||||
|
||||
@@ -118,6 +119,7 @@ public:
|
||||
printf_output_file = other.printf_output_file;
|
||||
profiler_direction = other.profiler_direction;
|
||||
renderdoc_enabled = other.renderdoc_enabled;
|
||||
host_input_mapping = other.host_input_mapping;
|
||||
}
|
||||
|
||||
void CopyFrom(const Configuration& other) {
|
||||
@@ -154,6 +156,7 @@ public:
|
||||
KYTY_CFG_SET(printf_output_file);
|
||||
KYTY_CFG_SET(profiler_direction);
|
||||
KYTY_CFG_SET(renderdoc_enabled);
|
||||
s->setValue("host_input_mapping", host_input_mapping);
|
||||
KYTY_CFG_SET(elf);
|
||||
}
|
||||
|
||||
@@ -180,7 +183,8 @@ public:
|
||||
KYTY_CFG_GET(printf_output_file);
|
||||
KYTY_CFG_GET(profiler_direction);
|
||||
KYTY_CFG_GET(renderdoc_enabled);
|
||||
elf = s->value("elf", elf).toString();
|
||||
host_input_mapping = s->value("host_input_mapping", host_input_mapping).toStringList();
|
||||
elf = s->value("elf", elf).toString();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -38,7 +38,10 @@ public:
|
||||
|
||||
[[nodiscard]] const QString& GetSettingsFile() const { return m_settings_file; }
|
||||
[[nodiscard]] const QStringList& GetGameDirectories() const { return m_game_dirs; }
|
||||
[[nodiscard]] bool CanViewSelectedTrophies() const;
|
||||
[[nodiscard]] const QStringList& GetHostInputMapping() const {
|
||||
return m_global_info.host_input_mapping;
|
||||
}
|
||||
[[nodiscard]] bool CanViewSelectedTrophies() const;
|
||||
|
||||
bool EnsureGameDirectory();
|
||||
void ScanGameDirectory();
|
||||
@@ -58,6 +61,7 @@ protected slots:
|
||||
void edit_configuration();
|
||||
void delete_configuartion();
|
||||
void edit_global_settings();
|
||||
void edit_input_mapping();
|
||||
void run_configuration();
|
||||
void list_currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
|
||||
void list_itemDoubleClicked(QTreeWidgetItem* witem, int column);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef LAUNCHER_INCLUDE_INPUT_MAPPING_DIALOG_H_
|
||||
#define LAUNCHER_INCLUDE_INPUT_MAPPING_DIALOG_H_
|
||||
|
||||
#include <QDialog>
|
||||
#include <QStringList>
|
||||
|
||||
class QPushButton;
|
||||
class QTreeWidget;
|
||||
class QTreeWidgetItem;
|
||||
class QWidget;
|
||||
|
||||
class InputMappingDialog final: public QDialog {
|
||||
public:
|
||||
explicit InputMappingDialog(const QStringList& mapping, QWidget* parent = nullptr);
|
||||
|
||||
[[nodiscard]] QStringList Mapping() const;
|
||||
|
||||
private:
|
||||
void ChangeBinding();
|
||||
void ClearBinding();
|
||||
void RestoreDefaults();
|
||||
void SetBinding(QTreeWidgetItem* item, const QString& binding);
|
||||
void UpdateButtons();
|
||||
|
||||
QTreeWidget* m_bindings = nullptr;
|
||||
QPushButton* m_change_button = nullptr;
|
||||
QPushButton* m_clear_button = nullptr;
|
||||
bool m_customized = false;
|
||||
};
|
||||
|
||||
#endif /* LAUNCHER_INCLUDE_INPUT_MAPPING_DIALOG_H_ */
|
||||
@@ -0,0 +1,8 @@
|
||||
<RCC>
|
||||
<qresource prefix="/icons">
|
||||
<file alias="edit-configuration.svg">icons/edit-configuration.svg</file>
|
||||
<file alias="global-settings.svg">icons/global-settings.svg</file>
|
||||
<file alias="input-mapping.svg">icons/input-mapping.svg</file>
|
||||
<file alias="remove-configuration.svg">icons/remove-configuration.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "configurationEditDialog.h"
|
||||
#include "configurationItem.h"
|
||||
#include "gameListTreeWidget.h"
|
||||
#include "inputMappingDialog.h"
|
||||
#include "mainDialog.h"
|
||||
#include "patchesDialog.h"
|
||||
#include "trophyViewerDialog.h"
|
||||
@@ -169,6 +170,7 @@ static void ApplyGameListStyle(Ui::ConfigurationListWidget* ui) {
|
||||
"QToolButton:disabled { background: transparent; }"));
|
||||
ui->edit_button->setStyleSheet(ui->global_settings_button->styleSheet());
|
||||
ui->delete_button->setStyleSheet(ui->global_settings_button->styleSheet());
|
||||
ui->input_mapping_button->setStyleSheet(ui->global_settings_button->styleSheet());
|
||||
}
|
||||
|
||||
static void AddSaveDataDir(QStringList* dirs, QSet<QString>* seen, const QString& root,
|
||||
@@ -226,10 +228,12 @@ ConfigurationListWidget::ConfigurationListWidget(QWidget* parent)
|
||||
m_ui->setupUi(this);
|
||||
ApplyGameListStyle(m_ui);
|
||||
|
||||
m_ui->global_settings_button->setIcon(style()->standardIcon(QStyle::SP_FileDialogDetailedView));
|
||||
m_ui->global_settings_button->setIcon(QIcon(QStringLiteral(":/icons/global-settings.svg")));
|
||||
m_ui->global_settings_button->setToolTip(tr("Edit global settings and game folders"));
|
||||
m_ui->edit_button->setIcon(style()->standardIcon(QStyle::SP_FileIcon));
|
||||
m_ui->delete_button->setIcon(style()->standardIcon(QStyle::SP_DialogDiscardButton));
|
||||
m_ui->input_mapping_button->setIcon(QIcon(QStringLiteral(":/icons/input-mapping.svg")));
|
||||
m_ui->input_mapping_button->setToolTip(tr("Edit global input mapping"));
|
||||
m_ui->edit_button->setIcon(QIcon(QStringLiteral(":/icons/edit-configuration.svg")));
|
||||
m_ui->delete_button->setIcon(QIcon(QStringLiteral(":/icons/remove-configuration.svg")));
|
||||
|
||||
m_ui->delete_button->setEnabled(false);
|
||||
m_ui->edit_button->setEnabled(false);
|
||||
@@ -249,6 +253,8 @@ ConfigurationListWidget::ConfigurationListWidget(QWidget* parent)
|
||||
|
||||
connect(m_ui->global_settings_button, &QToolButton::clicked, this,
|
||||
&ConfigurationListWidget::edit_global_settings);
|
||||
connect(m_ui->input_mapping_button, &QToolButton::clicked, this,
|
||||
&ConfigurationListWidget::edit_input_mapping);
|
||||
connect(m_ui->edit_button, &QToolButton::clicked, this,
|
||||
&ConfigurationListWidget::edit_configuration);
|
||||
connect(m_ui->delete_button, &QToolButton::clicked, this,
|
||||
@@ -717,6 +723,14 @@ void ConfigurationListWidget::edit_global_settings() {
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigurationListWidget::edit_input_mapping() {
|
||||
InputMappingDialog dialog(m_global_info.host_input_mapping, this);
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
m_global_info.host_input_mapping = dialog.Mapping();
|
||||
WriteSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigurationListWidget::ClearCustomSettings(ConfigurationItem* item) {
|
||||
delete m_custom_infos.take(item->GetInfo().game_path);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
#include "inputMappingDialog.h"
|
||||
|
||||
#include <QAbstractItemView>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHash>
|
||||
#include <QHeaderView>
|
||||
#include <QKeyEvent>
|
||||
#include <QKeySequence>
|
||||
#include <QLabel>
|
||||
#include <QMouseEvent>
|
||||
#include <QPushButton>
|
||||
#include <QStringList>
|
||||
#include <QTreeWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int BINDING_COLUMN = 1;
|
||||
|
||||
struct PadButton {
|
||||
const char* id;
|
||||
const char* label;
|
||||
const char* default_binding;
|
||||
};
|
||||
|
||||
constexpr PadButton PAD_BUTTONS[] = {
|
||||
{"Up", "D-pad Up", "Up"},
|
||||
{"Down", "D-pad Down", "Down"},
|
||||
{"Left", "D-pad Left", "Left"},
|
||||
{"Right", "D-pad Right", "Right"},
|
||||
{"Triangle", "Triangle", "I"},
|
||||
{"Circle", "Circle", "L"},
|
||||
{"Cross", "Cross", "J"},
|
||||
{"Square", "Square", "K"},
|
||||
{"L1", "L1", "Q"},
|
||||
{"R1", "R1", "E"},
|
||||
{"L2", "L2", ""},
|
||||
{"R2", "R2", ""},
|
||||
{"L3", "L3", "Left Shift"},
|
||||
{"R3", "R3", "Left Ctrl"},
|
||||
{"Options", "Options", "Return"},
|
||||
{"TouchPad", "Touch pad", "Backspace"},
|
||||
};
|
||||
|
||||
QString KeypadName(int key) {
|
||||
if (key >= Qt::Key_0 && key <= Qt::Key_9) {
|
||||
return QStringLiteral("Keypad %1").arg(key - Qt::Key_0);
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter: return QStringLiteral("Keypad Enter");
|
||||
case Qt::Key_Slash: return QStringLiteral("Keypad /");
|
||||
case Qt::Key_Asterisk: return QStringLiteral("Keypad *");
|
||||
case Qt::Key_Minus: return QStringLiteral("Keypad -");
|
||||
case Qt::Key_Plus: return QStringLiteral("Keypad +");
|
||||
case Qt::Key_Period: return QStringLiteral("Keypad .");
|
||||
case Qt::Key_Equal: return QStringLiteral("Keypad =");
|
||||
case Qt::Key_Comma: return QStringLiteral("Keypad ,");
|
||||
default: return {};
|
||||
}
|
||||
}
|
||||
|
||||
QString KeyName(const QKeyEvent& event) {
|
||||
const int key = event.key();
|
||||
if (event.modifiers().testFlag(Qt::KeypadModifier)) {
|
||||
return KeypadName(key);
|
||||
}
|
||||
if (key >= Qt::Key_A && key <= Qt::Key_Z) {
|
||||
return QChar(key);
|
||||
}
|
||||
if (key >= Qt::Key_0 && key <= Qt::Key_9) {
|
||||
return QChar(key);
|
||||
}
|
||||
if (key >= Qt::Key_F1 && key <= Qt::Key_F24) {
|
||||
return QStringLiteral("F%1").arg(key - Qt::Key_F1 + 1);
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter: return QStringLiteral("Return");
|
||||
case Qt::Key_Backspace: return QStringLiteral("Backspace");
|
||||
case Qt::Key_Tab: return QStringLiteral("Tab");
|
||||
case Qt::Key_Shift: return QStringLiteral("Left Shift");
|
||||
case Qt::Key_Control: return QStringLiteral("Left Ctrl");
|
||||
case Qt::Key_Alt: return QStringLiteral("Left Alt");
|
||||
case Qt::Key_Meta: return QStringLiteral("Left GUI");
|
||||
case Qt::Key_Insert: return QStringLiteral("Insert");
|
||||
case Qt::Key_Delete: return QStringLiteral("Delete");
|
||||
case Qt::Key_Home: return QStringLiteral("Home");
|
||||
case Qt::Key_End: return QStringLiteral("End");
|
||||
case Qt::Key_PageUp: return QStringLiteral("PageUp");
|
||||
case Qt::Key_PageDown: return QStringLiteral("PageDown");
|
||||
case Qt::Key_Left: return QStringLiteral("Left");
|
||||
case Qt::Key_Right: return QStringLiteral("Right");
|
||||
case Qt::Key_Up: return QStringLiteral("Up");
|
||||
case Qt::Key_Down: return QStringLiteral("Down");
|
||||
case Qt::Key_CapsLock: return QStringLiteral("CapsLock");
|
||||
case Qt::Key_NumLock: return QStringLiteral("Numlock");
|
||||
case Qt::Key_ScrollLock: return QStringLiteral("ScrollLock");
|
||||
case Qt::Key_Pause: return QStringLiteral("Pause");
|
||||
case Qt::Key_Print: return QStringLiteral("PrintScreen");
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (event.modifiers() != Qt::NoModifier) {
|
||||
return {};
|
||||
}
|
||||
const auto name = QKeySequence(key).toString(QKeySequence::PortableText);
|
||||
return name.size() == 1 ? name : QString();
|
||||
}
|
||||
|
||||
class InputCaptureDialog final: public QDialog {
|
||||
public:
|
||||
explicit InputCaptureDialog(QWidget* parent): QDialog(parent) {
|
||||
setWindowTitle(tr("Set Binding"));
|
||||
setModal(true);
|
||||
setMinimumWidth(360);
|
||||
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
m_label = new QLabel(
|
||||
tr("Press a key or mouse button.\nSpace and F1 are reserved; Esc cancels."), this);
|
||||
m_label->setAlignment(Qt::AlignCenter);
|
||||
layout->addWidget(m_label);
|
||||
}
|
||||
|
||||
[[nodiscard]] const QString& Binding() const { return m_binding; }
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent* event) override {
|
||||
if (event->isAutoRepeat()) {
|
||||
return;
|
||||
}
|
||||
if (event->key() == Qt::Key_Escape) {
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
if (event->key() == Qt::Key_Space || event->key() == Qt::Key_F1) {
|
||||
m_label->setText(tr("That key is reserved by the emulator."));
|
||||
return;
|
||||
}
|
||||
|
||||
m_binding = KeyName(*event);
|
||||
if (!m_binding.isEmpty()) {
|
||||
accept();
|
||||
} else {
|
||||
m_label->setText(tr("That key is not supported."));
|
||||
}
|
||||
}
|
||||
|
||||
void mousePressEvent(QMouseEvent* event) override {
|
||||
switch (event->button()) {
|
||||
case Qt::LeftButton: m_binding = QStringLiteral("Mouse:Left"); break;
|
||||
case Qt::RightButton: m_binding = QStringLiteral("Mouse:Right"); break;
|
||||
case Qt::MiddleButton: m_binding = QStringLiteral("Mouse:Middle"); break;
|
||||
case Qt::BackButton: m_binding = QStringLiteral("Mouse:X1"); break;
|
||||
case Qt::ForwardButton: m_binding = QStringLiteral("Mouse:X2"); break;
|
||||
default: return;
|
||||
}
|
||||
accept();
|
||||
}
|
||||
|
||||
private:
|
||||
QLabel* m_label = nullptr;
|
||||
QString m_binding;
|
||||
};
|
||||
|
||||
QHash<QString, QString> ParseMapping(const QStringList& mapping) {
|
||||
QHash<QString, QString> result;
|
||||
for (const auto& entry: mapping) {
|
||||
const auto separator = entry.indexOf(QLatin1Char('='));
|
||||
if (separator > 0 && separator + 1 < entry.size()) {
|
||||
const auto binding = entry.mid(separator + 1);
|
||||
for (auto item = result.begin(); item != result.end();) {
|
||||
if (item.value().compare(binding, Qt::CaseInsensitive) == 0) {
|
||||
item = result.erase(item);
|
||||
} else {
|
||||
++item;
|
||||
}
|
||||
}
|
||||
result.insert(entry.left(separator), binding);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
InputMappingDialog::InputMappingDialog(const QStringList& mapping, QWidget* parent)
|
||||
: QDialog(parent), m_customized(!mapping.isEmpty()) {
|
||||
setWindowTitle(tr("Input Mapping"));
|
||||
resize(440, 520);
|
||||
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
layout->addWidget(new QLabel(tr("Map keyboard or mouse input to DualSense buttons.\n"
|
||||
"Defaults: left stick W/A/S/D, right stick T/F/G/H."),
|
||||
this));
|
||||
|
||||
m_bindings = new QTreeWidget(this);
|
||||
m_bindings->setColumnCount(2);
|
||||
m_bindings->setHeaderLabels({tr("DualSense button"), tr("Host input")});
|
||||
m_bindings->setRootIsDecorated(false);
|
||||
m_bindings->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_bindings->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
m_bindings->header()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||
layout->addWidget(m_bindings);
|
||||
|
||||
const auto parsed = ParseMapping(mapping);
|
||||
for (const auto& button: PAD_BUTTONS) {
|
||||
auto* item = new QTreeWidgetItem(m_bindings);
|
||||
item->setText(0, tr(button.label));
|
||||
item->setData(0, Qt::UserRole, QString::fromLatin1(button.id));
|
||||
SetBinding(item, m_customized ? parsed.value(QString::fromLatin1(button.id))
|
||||
: QString::fromLatin1(button.default_binding));
|
||||
}
|
||||
m_bindings->setCurrentItem(m_bindings->topLevelItem(0));
|
||||
|
||||
auto* controls = new QHBoxLayout;
|
||||
m_change_button = new QPushButton(tr("Change..."), this);
|
||||
m_clear_button = new QPushButton(tr("Clear"), this);
|
||||
auto* defaults = new QPushButton(tr("Defaults"), this);
|
||||
controls->addWidget(m_change_button);
|
||||
controls->addWidget(m_clear_button);
|
||||
controls->addWidget(defaults);
|
||||
controls->addStretch();
|
||||
layout->addLayout(controls);
|
||||
|
||||
auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||
layout->addWidget(buttons);
|
||||
|
||||
connect(m_bindings, &QTreeWidget::itemDoubleClicked, this,
|
||||
[this](QTreeWidgetItem*, int) { ChangeBinding(); });
|
||||
connect(m_bindings, &QTreeWidget::itemSelectionChanged, this, [this]() { UpdateButtons(); });
|
||||
connect(m_change_button, &QPushButton::clicked, this, [this]() { ChangeBinding(); });
|
||||
connect(m_clear_button, &QPushButton::clicked, this, [this]() { ClearBinding(); });
|
||||
connect(defaults, &QPushButton::clicked, this, [this]() { RestoreDefaults(); });
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
QStringList InputMappingDialog::Mapping() const {
|
||||
QStringList result;
|
||||
if (!m_customized) {
|
||||
return result;
|
||||
}
|
||||
for (int index = 0; index < m_bindings->topLevelItemCount(); index++) {
|
||||
const auto* item = m_bindings->topLevelItem(index);
|
||||
const auto binding = item->data(BINDING_COLUMN, Qt::UserRole).toString();
|
||||
if (!binding.isEmpty()) {
|
||||
result.append(item->data(0, Qt::UserRole).toString() + QLatin1Char('=') + binding);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void InputMappingDialog::ChangeBinding() {
|
||||
auto* item = m_bindings->currentItem();
|
||||
if (item == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
InputCaptureDialog dialog(this);
|
||||
if (dialog.exec() != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int index = 0; index < m_bindings->topLevelItemCount(); index++) {
|
||||
auto* other = m_bindings->topLevelItem(index);
|
||||
if (other != item && other->data(BINDING_COLUMN, Qt::UserRole)
|
||||
.toString()
|
||||
.compare(dialog.Binding(), Qt::CaseInsensitive) == 0) {
|
||||
SetBinding(other, {});
|
||||
}
|
||||
}
|
||||
SetBinding(item, dialog.Binding());
|
||||
m_customized = true;
|
||||
}
|
||||
|
||||
void InputMappingDialog::ClearBinding() {
|
||||
SetBinding(m_bindings->currentItem(), {});
|
||||
m_customized = true;
|
||||
}
|
||||
|
||||
void InputMappingDialog::RestoreDefaults() {
|
||||
for (int index = 0; index < m_bindings->topLevelItemCount(); index++) {
|
||||
SetBinding(m_bindings->topLevelItem(index),
|
||||
QString::fromLatin1(PAD_BUTTONS[index].default_binding));
|
||||
}
|
||||
m_customized = false;
|
||||
}
|
||||
|
||||
void InputMappingDialog::SetBinding(QTreeWidgetItem* item, const QString& binding) {
|
||||
if (item == nullptr) {
|
||||
return;
|
||||
}
|
||||
item->setData(BINDING_COLUMN, Qt::UserRole, binding);
|
||||
item->setText(BINDING_COLUMN, binding.isEmpty() ? tr("None") : binding);
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
void InputMappingDialog::UpdateButtons() {
|
||||
if (m_change_button == nullptr) {
|
||||
return;
|
||||
}
|
||||
const auto* item = m_bindings->currentItem();
|
||||
m_change_button->setEnabled(item != nullptr);
|
||||
m_clear_button->setEnabled(item != nullptr &&
|
||||
!item->data(BINDING_COLUMN, Qt::UserRole).toString().isEmpty());
|
||||
}
|
||||
@@ -218,6 +218,9 @@ static QStringList CreateEmulatorArgs(const Configuration& info) {
|
||||
args << "--printf-output-file" << info.printf_output_file;
|
||||
args << "--profiler-direction" << EnumToText(info.profiler_direction);
|
||||
args << "--spirv-debug-printf" << "false";
|
||||
for (const auto& binding: info.host_input_mapping) {
|
||||
args << "--keymap" << binding;
|
||||
}
|
||||
if (info.renderdoc_enabled) {
|
||||
args << "--rd";
|
||||
}
|
||||
@@ -428,7 +431,10 @@ void MainDialogPrivate::Run() {
|
||||
|
||||
m_running_item->SetRunning(true);
|
||||
|
||||
m_main_dialog->RunInterpreter(&m_process, m_running_item->GetInfo());
|
||||
Configuration info;
|
||||
info.CopyFrom(m_running_item->GetInfo());
|
||||
info.host_input_mapping = m_ui->widget->GetHostInputMapping();
|
||||
m_main_dialog->RunInterpreter(&m_process, info);
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user