mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 08:13:05 +00:00
Input mapping tabs UI, emulated touchpad, and rumble for non-PS5 controllers (#1541)
* Revamp input mapping dialog with tabs, gamepad remapping and gyro emulation toggle Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Add emulated touchpad (mouse/gamepad) with particle skins; widen input dialog Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Disable mouse touchpad mode when the cursor leaves the window Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Add touchpad hand-cursor toggle; share touchpad options across both tabs Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Hide touchpad trail and particles when the visual toggle is off Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Rename input mapping tabs Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Rumble non-DualSense gamepads from haptic audio Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Fix input mapping, touchpad transitions, and rumble fallback --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: nmzik <Nmzik@mail.ru>
This commit is contained in:
18 files changed
+1908
-209
No files matched your search
@@ -105,6 +105,7 @@ if(APPLE)
|
||||
install(TARGETS kyty_emulator DESTINATION "KytyPS5.app/Contents/MacOS")
|
||||
install(TARGETS kyty_updater DESTINATION "KytyPS5.app/Contents/MacOS")
|
||||
install(FILES "${KYTY_TROPHY_UNLOCK_SOUND}" DESTINATION "KytyPS5.app/Contents/Resources/assets/sounds")
|
||||
install(DIRECTORY "${CMAKE_SOURCE_DIR}/assets/cursors" DESTINATION "KytyPS5.app/Contents/Resources/assets")
|
||||
# Deploy and ad-hoc sign the Qt frameworks and plugins in the bundle.
|
||||
find_program(KYTY_MACDEPLOYQT NAMES macdeployqt PATHS "${Qt6_DIR}/../../../bin" NO_DEFAULT_PATH)
|
||||
if(NOT KYTY_MACDEPLOYQT)
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
void SetSuspended(bool suspended);
|
||||
|
||||
[[nodiscard]] const QSet<QString>& Pressed() const { return m_pressed; }
|
||||
[[nodiscard]] const QSet<QString>& RawPressed() const { return m_raw_pressed; }
|
||||
[[nodiscard]] QPointF LeftStick() const { return m_left_stick; }
|
||||
[[nodiscard]] QPointF RightStick() const { return m_right_stick; }
|
||||
[[nodiscard]] const QString& DeviceName() const { return m_device_name; }
|
||||
@@ -44,6 +45,7 @@ private:
|
||||
bool m_preview_enabled = false;
|
||||
bool m_suspended = false;
|
||||
QSet<QString> m_pressed;
|
||||
QSet<QString> m_raw_pressed;
|
||||
QPointF m_left_stick;
|
||||
QPointF m_right_stick;
|
||||
QString m_device_name;
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
#ifndef LAUNCHER_INCLUDE_INPUT_MAPPING_DIALOG_H_
|
||||
#ifndef LAUNCHER_INCLUDE_INPUT_MAPPING_DIALOG_H_
|
||||
#define LAUNCHER_INCLUDE_INPUT_MAPPING_DIALOG_H_
|
||||
|
||||
#include <QDialog>
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
#include <QStringList>
|
||||
|
||||
class ControllerPreview;
|
||||
class DualSenseWidget;
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QDoubleSpinBox;
|
||||
class QTabWidget;
|
||||
class QWidget;
|
||||
|
||||
class InputMappingDialog final: public QDialog {
|
||||
public:
|
||||
@@ -20,20 +25,30 @@ public:
|
||||
[[nodiscard]] QStringList Mapping() const;
|
||||
|
||||
private:
|
||||
void ChangeBinding(const QString& id);
|
||||
void RestoreDefaults();
|
||||
void UpdateButtons();
|
||||
void UpdatePreview();
|
||||
void UpdateHighlights();
|
||||
QWidget* BuildTab(bool pad);
|
||||
void ChangeKeyboardBinding(const QString& id);
|
||||
void ChangePadBinding(const QString& id);
|
||||
void ClearBinding(bool pad, const QString& id);
|
||||
void RestoreDefaults();
|
||||
void UpdateButtons();
|
||||
void UpdatePreview();
|
||||
void UpdateHighlights();
|
||||
|
||||
ControllerPreview* m_preview;
|
||||
DualSenseWidget* m_controller = nullptr;
|
||||
QTabWidget* m_tabs = nullptr;
|
||||
QHash<QString, QString> m_bindings;
|
||||
QHash<QString, QString> m_pad_bindings;
|
||||
QHash<QString, QPushButton*> m_buttons;
|
||||
QHash<QString, QPushButton*> m_pad_buttons;
|
||||
QSet<QString> m_pad_pressed;
|
||||
QString m_selected;
|
||||
QLabel* m_status = nullptr;
|
||||
QDoubleSpinBox* m_sensitivity = nullptr;
|
||||
QComboBox* m_particle_skin = nullptr;
|
||||
QCheckBox* m_touch_cursor = nullptr;
|
||||
bool m_custom_bindings = false;
|
||||
bool m_custom_pad = false;
|
||||
};
|
||||
|
||||
#endif /* LAUNCHER_INCLUDE_INPUT_MAPPING_DIALOG_H_ */
|
||||
@@ -20,6 +20,34 @@ constexpr struct {
|
||||
{SDL_GAMEPAD_BUTTON_START, "Options"},
|
||||
};
|
||||
|
||||
// Host-side names; they must match PAD_SOURCES in hostInput.cpp.
|
||||
constexpr struct {
|
||||
SDL_GamepadButton button;
|
||||
const char* name;
|
||||
} RAW_BUTTONS[] = {
|
||||
{SDL_GAMEPAD_BUTTON_SOUTH, "South"},
|
||||
{SDL_GAMEPAD_BUTTON_EAST, "East"},
|
||||
{SDL_GAMEPAD_BUTTON_WEST, "West"},
|
||||
{SDL_GAMEPAD_BUTTON_NORTH, "North"},
|
||||
{SDL_GAMEPAD_BUTTON_BACK, "Back"},
|
||||
{SDL_GAMEPAD_BUTTON_GUIDE, "Guide"},
|
||||
{SDL_GAMEPAD_BUTTON_START, "Start"},
|
||||
{SDL_GAMEPAD_BUTTON_LEFT_STICK, "LeftStick"},
|
||||
{SDL_GAMEPAD_BUTTON_RIGHT_STICK, "RightStick"},
|
||||
{SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, "LeftShoulder"},
|
||||
{SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, "RightShoulder"},
|
||||
{SDL_GAMEPAD_BUTTON_DPAD_UP, "DpadUp"},
|
||||
{SDL_GAMEPAD_BUTTON_DPAD_DOWN, "DpadDown"},
|
||||
{SDL_GAMEPAD_BUTTON_DPAD_LEFT, "DpadLeft"},
|
||||
{SDL_GAMEPAD_BUTTON_DPAD_RIGHT, "DpadRight"},
|
||||
{SDL_GAMEPAD_BUTTON_MISC1, "Misc1"},
|
||||
{SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1, "RightPaddle1"},
|
||||
{SDL_GAMEPAD_BUTTON_LEFT_PADDLE1, "LeftPaddle1"},
|
||||
{SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2, "RightPaddle2"},
|
||||
{SDL_GAMEPAD_BUTTON_LEFT_PADDLE2, "LeftPaddle2"},
|
||||
{SDL_GAMEPAD_BUTTON_TOUCHPAD, "Touchpad"},
|
||||
};
|
||||
|
||||
double Axis(SDL_Gamepad* gamepad, SDL_GamepadAxis axis) {
|
||||
const int value = SDL_GetGamepadAxis(gamepad, axis);
|
||||
return value / (value < 0 ? 32768.0 : 32767.0);
|
||||
@@ -100,6 +128,7 @@ void ControllerPreview::UpdateRunning() {
|
||||
SDL_QuitSubSystem(SDL_INIT_GAMEPAD);
|
||||
}
|
||||
m_pressed.clear();
|
||||
m_raw_pressed.clear();
|
||||
m_left_stick = {};
|
||||
m_right_stick = {};
|
||||
m_device_name.clear();
|
||||
@@ -131,12 +160,25 @@ void ControllerPreview::Refresh() {
|
||||
}
|
||||
|
||||
QSet<QString> pressed;
|
||||
QSet<QString> raw;
|
||||
QPointF left;
|
||||
QPointF right;
|
||||
QString name;
|
||||
if (!m_gamepads.isEmpty()) {
|
||||
auto* gamepad = m_gamepads.first();
|
||||
name = QString::fromUtf8(SDL_GetGamepadName(gamepad));
|
||||
for (const auto& binding: RAW_BUTTONS) {
|
||||
if (SDL_GamepadHasButton(gamepad, binding.button) &&
|
||||
SDL_GetGamepadButton(gamepad, binding.button)) {
|
||||
raw.insert(QString::fromLatin1(binding.name));
|
||||
}
|
||||
}
|
||||
if (Axis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) > 0.5) {
|
||||
raw.insert(QStringLiteral("LeftTrigger"));
|
||||
}
|
||||
if (Axis(gamepad, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) > 0.5) {
|
||||
raw.insert(QStringLiteral("RightTrigger"));
|
||||
}
|
||||
for (const auto& binding: BUTTONS) {
|
||||
if (SDL_GetGamepadButton(gamepad, binding.button)) {
|
||||
pressed.insert(QString::fromLatin1(binding.control));
|
||||
@@ -180,9 +222,10 @@ void ControllerPreview::Refresh() {
|
||||
pressed.insert(QStringLiteral("TouchPadRight"));
|
||||
}
|
||||
}
|
||||
if (pressed != m_pressed || left != m_left_stick || right != m_right_stick ||
|
||||
name != m_device_name) {
|
||||
if (pressed != m_pressed || raw != m_raw_pressed || left != m_left_stick ||
|
||||
right != m_right_stick || name != m_device_name) {
|
||||
m_pressed = pressed;
|
||||
m_raw_pressed = raw;
|
||||
m_left_stick = left;
|
||||
m_right_stick = right;
|
||||
m_device_name = name;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "inputMappingDialog.h"
|
||||
#include "inputMappingDialog.h"
|
||||
|
||||
#include "controllerPreview.h"
|
||||
#include "dualsenseWidget.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QGridLayout>
|
||||
@@ -16,56 +18,113 @@
|
||||
#include <QPushButton>
|
||||
#include <QScreen>
|
||||
#include <QScrollArea>
|
||||
#include <QSet>
|
||||
#include <QStringList>
|
||||
#include <QTabWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto DEFAULT_MOUSE_SENSITIVITY = 1.0;
|
||||
constexpr char MOUSE_SENSITIVITY[] = "MouseSensitivity=";
|
||||
constexpr char TOUCH_PARTICLE_SKIN[] = "TouchParticleSkin=";
|
||||
constexpr char TOUCH_CURSOR_OFF[] = "TouchCursorImage=Off";
|
||||
constexpr char KEYBOARD_DISABLED[] = "Keyboard=Disabled";
|
||||
constexpr char PAD_DISABLED[] = "Pad=Disabled";
|
||||
|
||||
enum Group { Dpad, LeftStick, RightStick, Face, Shoulders, Center, Shortcuts, GroupCount };
|
||||
constexpr char PAD_PREFIX[] = "Pad:";
|
||||
|
||||
enum Section { Face, Dpad, Shoulders, Sticks, System, LeftStick, RightStick, Shortcuts, SectionCount };
|
||||
|
||||
const char* const SECTION_TITLES[SectionCount] = {
|
||||
QT_TR_NOOP("Face buttons"), QT_TR_NOOP("D-pad"),
|
||||
QT_TR_NOOP("Shoulders && triggers"), QT_TR_NOOP("Stick clicks"),
|
||||
QT_TR_NOOP("System"), QT_TR_NOOP("Left stick"),
|
||||
QT_TR_NOOP("Right stick"), QT_TR_NOOP("In-game shortcuts (cycle)"),
|
||||
};
|
||||
|
||||
// pad_default is null for controls that have no gamepad equivalent.
|
||||
struct PadControl {
|
||||
const char* id;
|
||||
const char* label;
|
||||
const char* default_binding;
|
||||
Group group;
|
||||
int row;
|
||||
int column;
|
||||
const char* keyboard_default;
|
||||
const char* pad_default;
|
||||
Section section;
|
||||
};
|
||||
|
||||
constexpr PadControl PAD_CONTROLS[] = {
|
||||
{"Up", "Up", "Up", Dpad, 0, 1},
|
||||
{"Down", "Down", "Down", Dpad, 2, 1},
|
||||
{"Left", "Left", "Left", Dpad, 1, 0},
|
||||
{"Right", "Right", "Right", Dpad, 1, 2},
|
||||
{"LeftStickUp", "Up", "W", LeftStick, 0, 1},
|
||||
{"LeftStickDown", "Down", "S", LeftStick, 2, 1},
|
||||
{"LeftStickLeft", "Left", "A", LeftStick, 1, 0},
|
||||
{"LeftStickRight", "Right", "D", LeftStick, 1, 2},
|
||||
{"RightStickUp", "Up", "T", RightStick, 0, 1},
|
||||
{"RightStickDown", "Down", "G", RightStick, 2, 1},
|
||||
{"RightStickLeft", "Left", "F", RightStick, 1, 0},
|
||||
{"RightStickRight", "Right", "H", RightStick, 1, 2},
|
||||
{"Triangle", "Triangle", "I", Face, 0, 1},
|
||||
{"Circle", "Circle", "L", Face, 1, 2},
|
||||
{"Cross", "Cross", "J", Face, 2, 1},
|
||||
{"Square", "Square", "K", Face, 1, 0},
|
||||
{"L1", "L1", "Q", Shoulders, 0, 1},
|
||||
{"R1", "R1", "E", Shoulders, 0, 2},
|
||||
{"L2", "L2", "Z", Shoulders, 0, 0},
|
||||
{"R2", "R2", "C", Shoulders, 0, 3},
|
||||
{"L3", "Press / L3", "Left Shift", LeftStick, 1, 1},
|
||||
{"R3", "Press / R3", "Left Ctrl", RightStick, 1, 1},
|
||||
{"Options", "Options", "Return", Center, 0, 1},
|
||||
{"TouchPad", "Touch pad left", "Backspace", Center, 0, 0},
|
||||
{"TouchPadRight", "Touch pad right", "Tab", Center, 0, 2},
|
||||
{"SpeakerVolume", "Speaker volume", "1", Shortcuts, 0, 0},
|
||||
{"VibrationIntensity", "Vibration intensity", "2", Shortcuts, 0, 1},
|
||||
{"TriggerEffectIntensity", "Trigger intensity", "3", Shortcuts, 0, 2},
|
||||
{"Cross", "Cross", "J", "South", Face},
|
||||
{"Circle", "Circle", "L", "East", Face},
|
||||
{"Square", "Square", "K", "West", Face},
|
||||
{"Triangle", "Triangle", "I", "North", Face},
|
||||
{"Up", "Up", "Up", "DpadUp", Dpad},
|
||||
{"Down", "Down", "Down", "DpadDown", Dpad},
|
||||
{"Left", "Left", "Left", "DpadLeft", Dpad},
|
||||
{"Right", "Right", "Right", "DpadRight", Dpad},
|
||||
{"L1", "L1", "Q", "LeftShoulder", Shoulders},
|
||||
{"R1", "R1", "E", "RightShoulder", Shoulders},
|
||||
{"L2", "L2", "Z", "LeftTrigger", Shoulders},
|
||||
{"R2", "R2", "C", "RightTrigger", Shoulders},
|
||||
{"L3", "L3 (left stick click)", "Left Shift", "LeftStick", Sticks},
|
||||
{"R3", "R3 (right stick click)", "Left Ctrl", "RightStick", Sticks},
|
||||
{"Options", "Options", "Return", "Start", System},
|
||||
{"TouchPad", "Touch pad click", "Backspace", "Touchpad", System},
|
||||
{"TouchPadRight", "Touch pad right", "Tab", nullptr, System},
|
||||
{"GyroToggle", "Gyro emulation toggle", "", "Back", System},
|
||||
{"TouchPadMode", "Emulated touch pad mode", "F6", "", System},
|
||||
{"LeftStickUp", "Up", "W", nullptr, LeftStick},
|
||||
{"LeftStickDown", "Down", "S", nullptr, LeftStick},
|
||||
{"LeftStickLeft", "Left", "A", nullptr, LeftStick},
|
||||
{"LeftStickRight", "Right", "D", nullptr, LeftStick},
|
||||
{"RightStickUp", "Up", "T", nullptr, RightStick},
|
||||
{"RightStickDown", "Down", "G", nullptr, RightStick},
|
||||
{"RightStickLeft", "Left", "F", nullptr, RightStick},
|
||||
{"RightStickRight", "Right", "H", nullptr, RightStick},
|
||||
{"SpeakerVolume", "Speaker volume", "1", nullptr, Shortcuts},
|
||||
{"VibrationIntensity", "Vibration intensity", "2", nullptr, Shortcuts},
|
||||
{"TriggerEffectIntensity", "Trigger intensity", "3", nullptr, Shortcuts},
|
||||
};
|
||||
|
||||
struct PadSourceName {
|
||||
const char* id;
|
||||
const char* label;
|
||||
};
|
||||
|
||||
constexpr PadSourceName PAD_SOURCES[] = {
|
||||
{"South", "A / Cross"},
|
||||
{"East", "B / Circle"},
|
||||
{"West", "X / Square"},
|
||||
{"North", "Y / Triangle"},
|
||||
{"Back", "View / Back / Share"},
|
||||
{"Guide", "Guide / Home"},
|
||||
{"Start", "Menu / Start"},
|
||||
{"LeftStick", "Left stick click"},
|
||||
{"RightStick", "Right stick click"},
|
||||
{"LeftShoulder", "LB / L1"},
|
||||
{"RightShoulder", "RB / R1"},
|
||||
{"DpadUp", "D-pad Up"},
|
||||
{"DpadDown", "D-pad Down"},
|
||||
{"DpadLeft", "D-pad Left"},
|
||||
{"DpadRight", "D-pad Right"},
|
||||
{"Misc1", "Share / Misc"},
|
||||
{"RightPaddle1", "Right paddle 1"},
|
||||
{"LeftPaddle1", "Left paddle 1"},
|
||||
{"RightPaddle2", "Right paddle 2"},
|
||||
{"LeftPaddle2", "Left paddle 2"},
|
||||
{"Touchpad", "Touch pad click"},
|
||||
{"LeftTrigger", "LT / L2"},
|
||||
{"RightTrigger", "RT / R2"},
|
||||
};
|
||||
|
||||
QString PadSourceLabel(const QString& id) {
|
||||
for (const auto& source: PAD_SOURCES) {
|
||||
if (id == QLatin1String(source.id)) {
|
||||
return QObject::tr(source.label);
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
QString KeypadName(int key) {
|
||||
if (key >= Qt::Key_0 && key <= Qt::Key_9) {
|
||||
return QStringLiteral("Keypad %1").arg(key - Qt::Key_0);
|
||||
@@ -191,6 +250,54 @@ private:
|
||||
QString m_binding;
|
||||
};
|
||||
|
||||
class PadCaptureDialog final: public QDialog {
|
||||
public:
|
||||
PadCaptureDialog(ControllerPreview* preview, QWidget* parent): QDialog(parent) {
|
||||
setWindowTitle(tr("Set Binding"));
|
||||
setModal(true);
|
||||
setMinimumWidth(360);
|
||||
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
m_label = new QLabel(this);
|
||||
m_label->setAlignment(Qt::AlignCenter);
|
||||
m_label->setWordWrap(true);
|
||||
layout->addWidget(m_label);
|
||||
|
||||
if (preview == nullptr) {
|
||||
return;
|
||||
}
|
||||
// Inputs already held when the dialog opens must be released before they count.
|
||||
m_held = preview->RawPressed();
|
||||
connect(preview, &ControllerPreview::StateChanged, this, [this, preview] {
|
||||
const auto& pressed = preview->RawPressed();
|
||||
m_held.intersect(pressed);
|
||||
for (const auto& name: pressed) {
|
||||
if (!m_held.contains(name)) {
|
||||
m_binding = name;
|
||||
accept();
|
||||
return;
|
||||
}
|
||||
}
|
||||
UpdateText(preview);
|
||||
});
|
||||
UpdateText(preview);
|
||||
}
|
||||
|
||||
[[nodiscard]] const QString& Binding() const { return m_binding; }
|
||||
|
||||
private:
|
||||
void UpdateText(const ControllerPreview* preview) {
|
||||
m_label->setText(preview->DeviceName().isEmpty()
|
||||
? tr("No controller connected.\nConnect one, or press Esc to cancel.")
|
||||
: tr("Press a button or trigger on %1.\nEsc cancels.")
|
||||
.arg(preview->DeviceName()));
|
||||
}
|
||||
|
||||
QLabel* m_label = nullptr;
|
||||
QString m_binding;
|
||||
QSet<QString> m_held;
|
||||
};
|
||||
|
||||
void AssignBinding(QHash<QString, QString>& bindings, const QString& id, const QString& binding) {
|
||||
for (auto item = bindings.begin(); item != bindings.end();) {
|
||||
if (item.value().compare(binding, Qt::CaseInsensitive) == 0) {
|
||||
@@ -205,7 +312,11 @@ void AssignBinding(QHash<QString, QString>& bindings, const QString& id, const Q
|
||||
QHash<QString, QString> ParseMapping(const QStringList& mapping) {
|
||||
QHash<QString, QString> result;
|
||||
for (const auto& entry: mapping) {
|
||||
if (entry.startsWith(QLatin1String(MOUSE_SENSITIVITY))) {
|
||||
if (entry == QLatin1String(KEYBOARD_DISABLED) || entry == QLatin1String(PAD_DISABLED) ||
|
||||
entry.startsWith(QLatin1String(MOUSE_SENSITIVITY)) ||
|
||||
entry.startsWith(QLatin1String(TOUCH_PARTICLE_SKIN)) ||
|
||||
entry.startsWith(QLatin1String("TouchCursorImage=")) ||
|
||||
entry.startsWith(QLatin1String(PAD_PREFIX))) {
|
||||
continue;
|
||||
}
|
||||
const auto separator = entry.indexOf(QLatin1Char('='));
|
||||
@@ -216,6 +327,15 @@ QHash<QString, QString> ParseMapping(const QStringList& mapping) {
|
||||
return result;
|
||||
}
|
||||
|
||||
QString ParseTouchParticleSkin(const QStringList& mapping) {
|
||||
for (const auto& entry: mapping) {
|
||||
if (entry.startsWith(QLatin1String(TOUCH_PARTICLE_SKIN))) {
|
||||
return entry.mid(sizeof(TOUCH_PARTICLE_SKIN) - 1);
|
||||
}
|
||||
}
|
||||
return QStringLiteral("Classic");
|
||||
}
|
||||
|
||||
double ParseMouseSensitivity(const QStringList& mapping) {
|
||||
for (const auto& entry: mapping) {
|
||||
if (entry.startsWith(QLatin1String(MOUSE_SENSITIVITY))) {
|
||||
@@ -231,106 +351,67 @@ InputMappingDialog::InputMappingDialog(const QStringList& mapping, ControllerPre
|
||||
QWidget* parent)
|
||||
: QDialog(parent), m_preview(preview) {
|
||||
setWindowTitle(tr("Controls"));
|
||||
resize(QSize(1100, 820).boundedTo(screen()->availableGeometry().size()));
|
||||
resize(QSize(1360, 780).boundedTo(screen()->availableGeometry().size()));
|
||||
|
||||
m_bindings = ParseMapping(mapping);
|
||||
m_custom_bindings = !m_bindings.isEmpty() || mapping.contains(QLatin1String(KEYBOARD_DISABLED));
|
||||
m_custom_pad = mapping.contains(QLatin1String(PAD_DISABLED));
|
||||
for (const auto& entry: mapping) {
|
||||
if (!entry.startsWith(QLatin1String(PAD_PREFIX))) {
|
||||
continue;
|
||||
}
|
||||
const auto body = entry.mid(static_cast<int>(sizeof(PAD_PREFIX)) - 1);
|
||||
const auto separator = body.indexOf(QLatin1Char('='));
|
||||
if (separator > 0 && separator + 1 < body.size()) {
|
||||
AssignBinding(m_pad_bindings, body.left(separator), body.mid(separator + 1));
|
||||
m_custom_pad = true;
|
||||
}
|
||||
}
|
||||
for (const auto& control: PAD_CONTROLS) {
|
||||
const auto id = QString::fromLatin1(control.id);
|
||||
if (!m_custom_bindings && control.keyboard_default[0] != '\0') {
|
||||
m_bindings.insert(id, QString::fromLatin1(control.keyboard_default));
|
||||
}
|
||||
if (!m_custom_pad && control.pad_default != nullptr) {
|
||||
m_pad_bindings.insert(id, QString::fromLatin1(control.pad_default));
|
||||
}
|
||||
}
|
||||
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
layout->setSpacing(10);
|
||||
auto* title = new QLabel(tr("Controller setup"), this);
|
||||
auto font = title->font();
|
||||
font.setPointSize(font.pointSize() + 7);
|
||||
font.setBold(true);
|
||||
title->setFont(font);
|
||||
layout->addWidget(title);
|
||||
auto* hint = new QLabel(
|
||||
tr("Select a button to remap. Press controller buttons to test."), this);
|
||||
hint->setWordWrap(true);
|
||||
layout->addWidget(hint);
|
||||
m_status = new QLabel(this);
|
||||
m_status->setObjectName(QStringLiteral("controllerStatus"));
|
||||
m_status->setWordWrap(true);
|
||||
layout->addWidget(m_status);
|
||||
|
||||
auto* scroll = new QScrollArea(this);
|
||||
scroll->setWidgetResizable(true);
|
||||
scroll->setFrameShape(QFrame::NoFrame);
|
||||
auto* content = new QWidget(scroll);
|
||||
auto* grid = new QGridLayout(content);
|
||||
grid->setContentsMargins(0, 0, 0, 0);
|
||||
grid->setSpacing(12);
|
||||
QGroupBox* groups[GroupCount];
|
||||
QGridLayout* cells[GroupCount];
|
||||
const char* titles[] = {"D-Pad",
|
||||
"Left stick",
|
||||
"Right stick",
|
||||
"Face buttons",
|
||||
"Shoulders and triggers",
|
||||
"Touch pad and options",
|
||||
"In-game shortcuts (cycle)"};
|
||||
for (int index = 0; index < GroupCount; ++index) {
|
||||
groups[index] = new QGroupBox(tr(titles[index]), content);
|
||||
cells[index] = new QGridLayout(groups[index]);
|
||||
cells[index]->setSpacing(5);
|
||||
}
|
||||
|
||||
m_bindings = ParseMapping(mapping);
|
||||
m_custom_bindings = !m_bindings.isEmpty();
|
||||
for (const auto& control: PAD_CONTROLS) {
|
||||
const auto id = QString::fromLatin1(control.id);
|
||||
auto* cell = new QGroupBox(tr(control.label), groups[control.group]);
|
||||
auto* cell_layout = new QVBoxLayout(cell);
|
||||
cell_layout->setContentsMargins(3, 5, 3, 3);
|
||||
auto* button = new QPushButton(cell);
|
||||
button->setObjectName(QStringLiteral("binding_") + id);
|
||||
button->setAutoDefault(false);
|
||||
button->setMinimumWidth(64);
|
||||
button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
button->setAccessibleName(tr(titles[control.group]) + QStringLiteral(" / ") +
|
||||
tr(control.label));
|
||||
cell_layout->addWidget(button);
|
||||
cells[control.group]->addWidget(cell, control.row, control.column);
|
||||
m_buttons.insert(id, button);
|
||||
if (!m_custom_bindings) {
|
||||
m_bindings.insert(id, QString::fromLatin1(control.default_binding));
|
||||
}
|
||||
connect(button, &QPushButton::clicked, this, [this, id] { ChangeBinding(id); });
|
||||
}
|
||||
|
||||
auto* left = new QVBoxLayout;
|
||||
left->addWidget(groups[Dpad]);
|
||||
left->addWidget(groups[LeftStick]);
|
||||
left->addStretch();
|
||||
grid->addLayout(left, 0, 0);
|
||||
auto* center = new QVBoxLayout;
|
||||
center->addWidget(groups[Shoulders]);
|
||||
m_controller = new DualSenseWidget(content);
|
||||
m_controller->setObjectName(QStringLiteral("controllerDiagram"));
|
||||
center->addWidget(m_controller, 1);
|
||||
center->addWidget(groups[Center]);
|
||||
grid->addLayout(center, 0, 1);
|
||||
auto* right = new QVBoxLayout;
|
||||
right->addWidget(groups[Face]);
|
||||
right->addWidget(groups[RightStick]);
|
||||
right->addStretch();
|
||||
grid->addLayout(right, 0, 2);
|
||||
grid->setColumnStretch(1, 1);
|
||||
grid->addWidget(groups[Shortcuts], 1, 0, 1, 3);
|
||||
scroll->setWidget(content);
|
||||
layout->addWidget(scroll, 1);
|
||||
|
||||
auto* sensitivity_layout = new QHBoxLayout;
|
||||
sensitivity_layout->addWidget(new QLabel(tr("Mouse sensitivity"), this));
|
||||
m_sensitivity = new QDoubleSpinBox(this);
|
||||
m_sensitivity->setObjectName(QStringLiteral("mouseSensitivity"));
|
||||
m_sensitivity->setRange(0.1, 5.0);
|
||||
m_sensitivity->setSingleStep(0.1);
|
||||
m_sensitivity->setDecimals(1);
|
||||
m_sensitivity->setSuffix(QStringLiteral("×"));
|
||||
m_tabs = new QTabWidget(this);
|
||||
m_tabs->setObjectName(QStringLiteral("inputTabs"));
|
||||
m_tabs->setDocumentMode(true);
|
||||
m_tabs->addTab(BuildTab(true), tr("Gamepad"));
|
||||
m_tabs->addTab(BuildTab(false), tr("Keyboard && Mouse"));
|
||||
layout->addWidget(m_tabs, 1);
|
||||
m_sensitivity->setValue(ParseMouseSensitivity(mapping));
|
||||
sensitivity_layout->addWidget(m_sensitivity);
|
||||
sensitivity_layout->addWidget(
|
||||
new QLabel(tr("F7 in-game toggles mouse movement on the right stick."), this));
|
||||
sensitivity_layout->addStretch();
|
||||
layout->addLayout(sensitivity_layout);
|
||||
|
||||
auto* touch_group = new QGroupBox(tr("Emulated touch pad (shared by both tabs)"), this);
|
||||
auto* touch_layout = new QHBoxLayout(touch_group);
|
||||
touch_layout->addWidget(new QLabel(tr("Particle skin"), touch_group));
|
||||
m_particle_skin = new QComboBox(touch_group);
|
||||
m_particle_skin->setObjectName(QStringLiteral("touchParticleSkin"));
|
||||
m_particle_skin->addItem(tr("Classic"), QStringLiteral("Classic"));
|
||||
m_particle_skin->addItem(tr("Blue neon"), QStringLiteral("BlueNeon"));
|
||||
m_particle_skin->addItem(tr("Monochrome"), QStringLiteral("Monochrome"));
|
||||
m_particle_skin->addItem(tr("Crimson"), QStringLiteral("Crimson"));
|
||||
m_particle_skin->addItem(tr("Red/Blue"), QStringLiteral("RedBlue"));
|
||||
touch_layout->addWidget(m_particle_skin);
|
||||
m_touch_cursor = new QCheckBox(tr("Show hand cursor and trail"), touch_group);
|
||||
m_touch_cursor->setObjectName(QStringLiteral("touchCursorImage"));
|
||||
m_touch_cursor->setToolTip(tr("When off, the emulated touch pad still works but the hand "
|
||||
"image and drawing trail are not shown."));
|
||||
m_touch_cursor->setChecked(!mapping.contains(QLatin1String(TOUCH_CURSOR_OFF)));
|
||||
touch_layout->addWidget(m_touch_cursor);
|
||||
touch_layout->addStretch();
|
||||
touch_layout->addWidget(new QLabel(
|
||||
tr("Toggle with the touch pad mode key (F6 by default); draw with left mouse / Cross."),
|
||||
touch_group));
|
||||
layout->addWidget(touch_group);
|
||||
const auto skin_index = m_particle_skin->findData(ParseTouchParticleSkin(mapping));
|
||||
m_particle_skin->setCurrentIndex(skin_index >= 0 ? skin_index : 0);
|
||||
|
||||
auto* buttons = new QDialogButtonBox(QDialogButtonBox::RestoreDefaults |
|
||||
QDialogButtonBox::Save | QDialogButtonBox::Cancel,
|
||||
@@ -338,9 +419,14 @@ InputMappingDialog::InputMappingDialog(const QStringList& mapping, ControllerPre
|
||||
auto* defaults = buttons->button(QDialogButtonBox::RestoreDefaults);
|
||||
defaults->setObjectName(QStringLiteral("defaults"));
|
||||
defaults->setAutoDefault(false);
|
||||
layout->addWidget(buttons);
|
||||
connect(m_controller, &DualSenseWidget::ControlClicked, this,
|
||||
&InputMappingDialog::ChangeBinding);
|
||||
defaults->setToolTip(tr("Restore the defaults of the current tab."));
|
||||
auto* tip = new QLabel(tr("Tip: right-click a binding to unmap it."), this);
|
||||
auto* footer = new QHBoxLayout;
|
||||
footer->addWidget(tip);
|
||||
footer->addStretch();
|
||||
footer->addWidget(buttons);
|
||||
layout->addLayout(footer);
|
||||
|
||||
connect(defaults, &QPushButton::clicked, this, &InputMappingDialog::RestoreDefaults);
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
@@ -359,6 +445,128 @@ InputMappingDialog::~InputMappingDialog() {
|
||||
}
|
||||
}
|
||||
|
||||
QWidget* InputMappingDialog::BuildTab(bool pad) {
|
||||
auto* page = new QWidget(this);
|
||||
auto* layout = new QVBoxLayout(page);
|
||||
layout->setSpacing(10);
|
||||
|
||||
auto* hint = new QLabel(
|
||||
pad ? tr("Choose which button on your gamepad triggers each PS5 control. Click a "
|
||||
"binding, then press the button or trigger you want to use.")
|
||||
: tr("Choose which keyboard key or mouse button triggers each PS5 control. Click a "
|
||||
"binding, then press the key or mouse button."),
|
||||
page);
|
||||
hint->setWordWrap(true);
|
||||
layout->addWidget(hint);
|
||||
if (pad) {
|
||||
m_status = new QLabel(page);
|
||||
m_status->setObjectName(QStringLiteral("controllerStatus"));
|
||||
m_status->setWordWrap(true);
|
||||
layout->addWidget(m_status);
|
||||
}
|
||||
|
||||
auto* body = new QHBoxLayout;
|
||||
body->setSpacing(14);
|
||||
layout->addLayout(body, 1);
|
||||
|
||||
auto* scroll = new QScrollArea(page);
|
||||
scroll->setWidgetResizable(true);
|
||||
scroll->setFrameShape(QFrame::NoFrame);
|
||||
auto* content = new QWidget(scroll);
|
||||
auto* columns = new QGridLayout(content);
|
||||
columns->setContentsMargins(0, 0, 8, 0);
|
||||
columns->setSpacing(12);
|
||||
columns->setAlignment(Qt::AlignTop);
|
||||
|
||||
// Section order and the column each one lives in.
|
||||
static constexpr Section ORDER[] = {Face, Dpad, Shoulders, Sticks, System, LeftStick,
|
||||
RightStick, Shortcuts};
|
||||
int column_rows[2] = {0, 0};
|
||||
for (const auto section: ORDER) {
|
||||
QGroupBox* group = nullptr;
|
||||
QGridLayout* rows = nullptr;
|
||||
int row = 0;
|
||||
for (const auto& control: PAD_CONTROLS) {
|
||||
if (control.section != section || (pad && control.pad_default == nullptr)) {
|
||||
continue;
|
||||
}
|
||||
if (group == nullptr) {
|
||||
group = new QGroupBox(tr(SECTION_TITLES[section]), content);
|
||||
rows = new QGridLayout(group);
|
||||
rows->setHorizontalSpacing(12);
|
||||
rows->setVerticalSpacing(6);
|
||||
rows->setColumnStretch(0, 1);
|
||||
rows->setColumnMinimumWidth(1, 190);
|
||||
}
|
||||
const auto id = QString::fromLatin1(control.id);
|
||||
const auto label = !pad && id == QLatin1String("TouchPad") ? tr("Touch pad left")
|
||||
: tr(control.label);
|
||||
auto* name = new QLabel(label, group);
|
||||
auto* button = new QPushButton(group);
|
||||
button->setObjectName((pad ? QStringLiteral("padBinding_") : QStringLiteral("binding_")) +
|
||||
id);
|
||||
button->setAutoDefault(false);
|
||||
button->setMinimumWidth(190);
|
||||
button->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
button->setAccessibleName(tr(SECTION_TITLES[section]) + QStringLiteral(" / ") + label);
|
||||
rows->addWidget(name, row, 0);
|
||||
rows->addWidget(button, row, 1);
|
||||
++row;
|
||||
(pad ? m_pad_buttons : m_buttons).insert(id, button);
|
||||
connect(button, &QPushButton::clicked, this, [this, pad, id] {
|
||||
pad ? ChangePadBinding(id) : ChangeKeyboardBinding(id);
|
||||
});
|
||||
connect(button, &QPushButton::customContextMenuRequested, this,
|
||||
[this, pad, id] { ClearBinding(pad, id); });
|
||||
}
|
||||
if (group != nullptr) {
|
||||
const int target = column_rows[0] <= column_rows[1] ? 0 : 1;
|
||||
columns->addWidget(group, column_rows[target]++, target);
|
||||
}
|
||||
}
|
||||
columns->setColumnStretch(0, 1);
|
||||
columns->setColumnStretch(1, 1);
|
||||
scroll->setWidget(content);
|
||||
scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
scroll->setMinimumWidth(pad ? 640 : 700);
|
||||
body->addWidget(scroll, 3);
|
||||
|
||||
if (pad) {
|
||||
m_controller = new DualSenseWidget(page);
|
||||
m_controller->setObjectName(QStringLiteral("controllerDiagram"));
|
||||
m_controller->setMinimumWidth(320);
|
||||
body->addWidget(m_controller, 2);
|
||||
connect(m_controller, &DualSenseWidget::ControlClicked, this,
|
||||
[this](const QString& id) {
|
||||
ChangePadBinding(id == QLatin1String("TouchPadRight") ? QStringLiteral("TouchPad")
|
||||
: id);
|
||||
});
|
||||
auto* note = new QLabel(tr("The gyro emulation toggle activates tilt mode on gamepads "
|
||||
"without a gyroscope: the right stick then controls pitch and "
|
||||
"roll. It defaults to the View/Back button."),
|
||||
page);
|
||||
note->setWordWrap(true);
|
||||
layout->addWidget(note);
|
||||
} else {
|
||||
auto* sensitivity_layout = new QHBoxLayout;
|
||||
sensitivity_layout->addWidget(new QLabel(tr("Mouse sensitivity"), page));
|
||||
m_sensitivity = new QDoubleSpinBox(page);
|
||||
m_sensitivity->setObjectName(QStringLiteral("mouseSensitivity"));
|
||||
m_sensitivity->setRange(0.1, 5.0);
|
||||
m_sensitivity->setSingleStep(0.1);
|
||||
m_sensitivity->setDecimals(1);
|
||||
m_sensitivity->setSuffix(QStringLiteral("×"));
|
||||
m_sensitivity->setValue(DEFAULT_MOUSE_SENSITIVITY);
|
||||
sensitivity_layout->addWidget(m_sensitivity);
|
||||
sensitivity_layout->addWidget(
|
||||
new QLabel(tr("F7 in-game toggles mouse movement on the right stick."), page));
|
||||
sensitivity_layout->addStretch();
|
||||
layout->addLayout(sensitivity_layout);
|
||||
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
QStringList InputMappingDialog::Mapping() const {
|
||||
QStringList result;
|
||||
if (m_custom_bindings) {
|
||||
@@ -369,15 +577,38 @@ QStringList InputMappingDialog::Mapping() const {
|
||||
result.append(id + QLatin1Char('=') + binding);
|
||||
}
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
result.append(QLatin1String(KEYBOARD_DISABLED));
|
||||
}
|
||||
}
|
||||
if (m_custom_pad) {
|
||||
const auto start = result.size();
|
||||
for (const auto& control: PAD_CONTROLS) {
|
||||
const auto id = QString::fromLatin1(control.id);
|
||||
const auto source = m_pad_bindings.value(id);
|
||||
if (!source.isEmpty()) {
|
||||
result.append(QLatin1String(PAD_PREFIX) + id + QLatin1Char('=') + source);
|
||||
}
|
||||
}
|
||||
if (result.size() == start) {
|
||||
result.append(QLatin1String(PAD_DISABLED));
|
||||
}
|
||||
}
|
||||
if (m_sensitivity->value() != DEFAULT_MOUSE_SENSITIVITY) {
|
||||
result.append(QLatin1String(MOUSE_SENSITIVITY) +
|
||||
QString::number(m_sensitivity->value(), 'f', 1));
|
||||
}
|
||||
const auto skin = m_particle_skin->currentData().toString();
|
||||
if (skin != QLatin1String("Classic")) {
|
||||
result.append(QLatin1String(TOUCH_PARTICLE_SKIN) + skin);
|
||||
}
|
||||
if (!m_touch_cursor->isChecked()) {
|
||||
result.append(QLatin1String(TOUCH_CURSOR_OFF));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void InputMappingDialog::ChangeBinding(const QString& id) {
|
||||
void InputMappingDialog::ChangeKeyboardBinding(const QString& id) {
|
||||
if (!m_buttons.contains(id)) {
|
||||
return;
|
||||
}
|
||||
@@ -393,14 +624,54 @@ void InputMappingDialog::ChangeBinding(const QString& id) {
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
void InputMappingDialog::ChangePadBinding(const QString& id) {
|
||||
if (!m_pad_buttons.contains(id)) {
|
||||
return;
|
||||
}
|
||||
m_selected = id;
|
||||
UpdateHighlights();
|
||||
PadCaptureDialog dialog(m_preview, this);
|
||||
dialog.setWindowTitle(tr("Set binding — %1").arg(m_pad_buttons.value(id)->accessibleName()));
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
AssignBinding(m_pad_bindings, id, dialog.Binding());
|
||||
m_custom_pad = true;
|
||||
}
|
||||
m_selected.clear();
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
void InputMappingDialog::ClearBinding(bool pad, const QString& id) {
|
||||
if (pad) {
|
||||
m_pad_bindings.remove(id);
|
||||
m_custom_pad = true;
|
||||
} else {
|
||||
m_bindings.remove(id);
|
||||
m_custom_bindings = true;
|
||||
}
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
void InputMappingDialog::RestoreDefaults() {
|
||||
m_bindings.clear();
|
||||
for (const auto& control: PAD_CONTROLS) {
|
||||
m_bindings.insert(QString::fromLatin1(control.id),
|
||||
QString::fromLatin1(control.default_binding));
|
||||
if (m_tabs->currentIndex() == 0) {
|
||||
m_pad_bindings.clear();
|
||||
for (const auto& control: PAD_CONTROLS) {
|
||||
if (control.pad_default != nullptr) {
|
||||
m_pad_bindings.insert(QString::fromLatin1(control.id),
|
||||
QString::fromLatin1(control.pad_default));
|
||||
}
|
||||
}
|
||||
m_custom_pad = false;
|
||||
} else {
|
||||
m_bindings.clear();
|
||||
for (const auto& control: PAD_CONTROLS) {
|
||||
if (control.keyboard_default[0] != '\0') {
|
||||
m_bindings.insert(QString::fromLatin1(control.id),
|
||||
QString::fromLatin1(control.keyboard_default));
|
||||
}
|
||||
}
|
||||
m_sensitivity->setValue(DEFAULT_MOUSE_SENSITIVITY);
|
||||
m_custom_bindings = false;
|
||||
}
|
||||
m_sensitivity->setValue(DEFAULT_MOUSE_SENSITIVITY);
|
||||
m_custom_bindings = false;
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
@@ -410,14 +681,42 @@ void InputMappingDialog::UpdateButtons() {
|
||||
const auto binding = m_bindings.value(item.key());
|
||||
const auto label = binding.isEmpty() ? tr("None") : binding;
|
||||
button->setText(QString(label).replace(QLatin1Char('&'), QLatin1String("&&")));
|
||||
button->setToolTip(tr("%1: %2. Click to change.").arg(button->accessibleName(), label));
|
||||
button->setToolTip(
|
||||
tr("%1: %2. Click to change, right-click to clear.").arg(button->accessibleName(), label));
|
||||
}
|
||||
for (auto item = m_pad_buttons.begin(); item != m_pad_buttons.end(); ++item) {
|
||||
auto* button = item.value();
|
||||
const auto source = m_pad_bindings.value(item.key());
|
||||
const auto label = source.isEmpty() ? tr("None") : PadSourceLabel(source);
|
||||
button->setText(QString(label).replace(QLatin1Char('&'), QLatin1String("&&")));
|
||||
button->setToolTip(
|
||||
tr("%1: %2. Click to change, right-click to clear.").arg(button->accessibleName(), label));
|
||||
}
|
||||
UpdateHighlights();
|
||||
}
|
||||
|
||||
void InputMappingDialog::UpdatePreview() {
|
||||
const auto pressed = m_preview != nullptr ? m_preview->Pressed() : QSet<QString>();
|
||||
m_controller->SetPressed(pressed);
|
||||
m_pad_pressed.clear();
|
||||
if (m_preview != nullptr) {
|
||||
const auto& raw = m_preview->RawPressed();
|
||||
for (auto item = m_pad_bindings.begin(); item != m_pad_bindings.end(); ++item) {
|
||||
if (raw.contains(item.value())) {
|
||||
m_pad_pressed.insert(item.key());
|
||||
}
|
||||
}
|
||||
if (m_pad_pressed.contains(QStringLiteral("TouchPad"))) {
|
||||
m_pad_pressed.insert(QStringLiteral("TouchPadRight"));
|
||||
}
|
||||
for (const auto& name: m_preview->Pressed()) {
|
||||
// Stick directions and touch pad fingers are shown as the pad reports them.
|
||||
if (name.startsWith(QLatin1String("LeftStick")) ||
|
||||
name.startsWith(QLatin1String("RightStick")) ||
|
||||
name.startsWith(QLatin1String("TouchPad"))) {
|
||||
m_pad_pressed.insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_controller->SetPressed(m_pad_pressed);
|
||||
m_controller->SetSticks(m_preview != nullptr ? m_preview->LeftStick() : QPointF(),
|
||||
m_preview != nullptr ? m_preview->RightStick() : QPointF());
|
||||
UpdateHighlights();
|
||||
@@ -432,8 +731,8 @@ void InputMappingDialog::UpdatePreview() {
|
||||
|
||||
void InputMappingDialog::UpdateHighlights() {
|
||||
m_controller->SetSelected(m_selected);
|
||||
for (auto item = m_buttons.begin(); item != m_buttons.end(); ++item) {
|
||||
const bool down = m_preview != nullptr && m_preview->Pressed().contains(item.key());
|
||||
for (auto item = m_pad_buttons.begin(); item != m_pad_buttons.end(); ++item) {
|
||||
const bool down = m_pad_pressed.contains(item.key());
|
||||
auto colors = palette();
|
||||
if (down) {
|
||||
colors.setColor(QPalette::Button, colors.color(QPalette::Highlight));
|
||||
@@ -446,4 +745,11 @@ void InputMappingDialog::UpdateHighlights() {
|
||||
item.value()->setPalette(colors);
|
||||
item.value()->setFont(label_font);
|
||||
}
|
||||
for (auto item = m_buttons.begin(); item != m_buttons.end(); ++item) {
|
||||
auto colors = palette();
|
||||
if (item.key() == m_selected) {
|
||||
colors.setColor(QPalette::ButtonText, colors.color(QPalette::Highlight));
|
||||
}
|
||||
item.value()->setPalette(colors);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user