mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2026-04-01 18:45:21 -06:00
configuration dialog for controller hotkeys
This commit is contained in:
parent
f354fd8c27
commit
43ead51b50
@ -189,6 +189,8 @@ add_library(citra_qt STATIC EXCLUDE_FROM_ALL
|
||||
util/graphics_device_info.h
|
||||
util/sequence_dialog/sequence_dialog.cpp
|
||||
util/sequence_dialog/sequence_dialog.h
|
||||
util/sequence_dialog/controller_sequence_dialog.cpp
|
||||
util/sequence_dialog/controller_sequence_dialog.h
|
||||
util/spinbox.cpp
|
||||
util/spinbox.h
|
||||
util/util.cpp
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#include "citra_qt/configuration/config.h"
|
||||
#include "citra_qt/configuration/configure_hotkeys_controller.h"
|
||||
#include "citra_qt/hotkeys.h"
|
||||
#include "citra_qt/util/sequence_dialog/sequence_dialog.h"
|
||||
#include "citra_qt/util/sequence_dialog/controller_sequence_dialog.h"
|
||||
#include "ui_configure_hotkeys_controller.h"
|
||||
|
||||
constexpr int name_column = 0;
|
||||
@ -24,7 +24,7 @@ ConfigureControllerHotkeys::ConfigureControllerHotkeys(QWidget* parent)
|
||||
model->setColumnCount(2);
|
||||
model->setHorizontalHeaderLabels({tr("Action"), tr("Controller Hotkey")});
|
||||
// TODO: re-enable and get profiles workin
|
||||
ui->horizontalLayout_5->setEnabled(false);
|
||||
ui->profileGroup->setEnabled(false);
|
||||
connect(ui->hotkey_list, &QTreeView::doubleClicked, this,
|
||||
&ConfigureControllerHotkeys::Configure);
|
||||
connect(ui->hotkey_list, &QTreeView::customContextMenuRequested, this,
|
||||
@ -60,7 +60,27 @@ void ConfigureControllerHotkeys::Populate(const HotkeyRegistry& registry) {
|
||||
ui->hotkey_list->expandAll();
|
||||
}
|
||||
|
||||
void ConfigureControllerHotkeys::Configure(QModelIndex index) {}
|
||||
void ConfigureControllerHotkeys::Configure(QModelIndex index) {
|
||||
if (!index.parent().isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Swap to the hotkey column
|
||||
index = index.sibling(index.row(), hotkey_column);
|
||||
QModelIndex readableIndex = index.sibling(index.row(), readable_hotkey_column);
|
||||
|
||||
const auto previous_key = model->data(index);
|
||||
|
||||
ControllerSequenceDialog hotkey_dialog{this};
|
||||
|
||||
const int return_code = hotkey_dialog.exec();
|
||||
const auto key_sequence = hotkey_dialog.GetSequence();
|
||||
if (return_code == QDialog::Rejected || key_sequence.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
model->setData(index, key_sequence);
|
||||
model->setData(readableIndex, CleanSequence(key_sequence));
|
||||
}
|
||||
|
||||
void ConfigureControllerHotkeys::ApplyConfiguration(HotkeyRegistry& registry) {
|
||||
for (int key_id = 0; key_id < model->rowCount(); key_id++) {
|
||||
|
||||
@ -30,12 +30,12 @@ public:
|
||||
* @param registry The HotkeyRegistry whose data is used to populate the list.
|
||||
*/
|
||||
void Populate(const HotkeyRegistry& registry);
|
||||
static QString CleanSequence(QString controller_keyseq);
|
||||
|
||||
private:
|
||||
void Configure(QModelIndex index);
|
||||
void ClearAll();
|
||||
void PopupContextMenu(const QPoint& menu_location);
|
||||
QString CleanSequence(QString controller_keyseq);
|
||||
|
||||
std::unique_ptr<Ui::ConfigureControllerHotkeys> ui;
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="profileGroup">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
@ -61,6 +62,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
|
||||
@ -407,7 +407,8 @@ ConfigureInput::ConfigureInput(Core::System& _system, QWidget* parent)
|
||||
Common::ParamPackage params;
|
||||
for (auto& poller : device_pollers) {
|
||||
params = poller->GetNextInput();
|
||||
if (params.Has("engine")) {
|
||||
// skip button downs and only process button ups to maintain former behavior
|
||||
if (params.Has("engine") && !params.Has("down")) {
|
||||
SetPollingResult(params, false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -0,0 +1,96 @@
|
||||
// Copyright 2026 Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <iostream>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
#include "common/param_package.h"
|
||||
#include "configuration/configure_hotkeys_controller.h"
|
||||
#include "controller_sequence_dialog.h"
|
||||
#include "util/sequence_dialog/controller_sequence_dialog.h"
|
||||
|
||||
ControllerSequenceDialog::ControllerSequenceDialog(QWidget* parent)
|
||||
: QDialog(parent), poll_timer(std::make_unique<QTimer>()) {
|
||||
setWindowTitle(tr("Press then release one or two controller buttons"));
|
||||
|
||||
auto* const buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
buttons->setCenterButtons(true);
|
||||
|
||||
textBox = new QLabel(QStringLiteral("Waiting..."), this);
|
||||
auto* const layout = new QVBoxLayout(this);
|
||||
layout->addWidget(textBox);
|
||||
layout->addWidget(buttons);
|
||||
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
LaunchPollers(); // Fixed: added semicolon
|
||||
}
|
||||
|
||||
ControllerSequenceDialog::~ControllerSequenceDialog() = default;
|
||||
|
||||
QString ControllerSequenceDialog::GetSequence() {
|
||||
return key_sequence;
|
||||
}
|
||||
|
||||
void ControllerSequenceDialog::closeEvent(QCloseEvent*) {
|
||||
reject();
|
||||
}
|
||||
|
||||
bool ControllerSequenceDialog::focusNextPrevChild(bool next) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ControllerSequenceDialog::LaunchPollers() {
|
||||
device_pollers = InputCommon::Polling::GetPollers(InputCommon::Polling::DeviceType::Button);
|
||||
|
||||
for (auto& poller : device_pollers) {
|
||||
poller->Start();
|
||||
}
|
||||
|
||||
connect(poll_timer.get(), &QTimer::timeout, this, [this, downCount = 0]() mutable {
|
||||
Common::ParamPackage params;
|
||||
for (auto& poller : device_pollers) {
|
||||
params = poller->GetNextInput();
|
||||
if (params.Has("engine") && params.Has("button")) { // for now, no analog inputs
|
||||
if (params.Has("down")) {
|
||||
std::cerr << "button " + params.Get("button", "") + " down" << std::endl;
|
||||
downCount++;
|
||||
if (downCount > 2) {
|
||||
// ignore third and fourth and fifth buttons
|
||||
} else if (downCount == 1) {
|
||||
key_sequence = QStringLiteral("");
|
||||
params1 = params;
|
||||
params2 = Common::ParamPackage();
|
||||
textBox->setText(ConfigureControllerHotkeys::CleanSequence(
|
||||
QString::fromStdString(params1.Serialize())) +
|
||||
QStringLiteral("..."));
|
||||
} else if (downCount == 2) {
|
||||
// this is a second button while the first one is held down,
|
||||
// go ahead and set the key_sequence as the chord and clear params
|
||||
params2 = params;
|
||||
key_sequence = QString::fromStdString(params1.Serialize() + "||" +
|
||||
params2.Serialize());
|
||||
textBox->setText(ConfigureControllerHotkeys::CleanSequence(key_sequence));
|
||||
}
|
||||
} else { // button release
|
||||
downCount--;
|
||||
std::cerr << "button " + params.Get("button", "") + " up" << std::endl;
|
||||
if (downCount == 0) {
|
||||
// all released, clear all saved params
|
||||
params1 = Common::ParamPackage();
|
||||
params2 = Common::ParamPackage();
|
||||
}
|
||||
if (key_sequence.isEmpty()) {
|
||||
key_sequence = QString::fromStdString(params.Serialize());
|
||||
textBox->setText(ConfigureControllerHotkeys::CleanSequence(key_sequence));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
poll_timer->start(100);
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
// Copyright 2018 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include "common/param_package.h"
|
||||
#include "input_common/main.h"
|
||||
|
||||
class ControllerSequenceDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ControllerSequenceDialog(QWidget* parent = nullptr);
|
||||
~ControllerSequenceDialog();
|
||||
|
||||
QString GetSequence();
|
||||
void closeEvent(QCloseEvent*) override;
|
||||
|
||||
private:
|
||||
void LaunchPollers();
|
||||
QLabel* textBox;
|
||||
QString key_sequence;
|
||||
Common::ParamPackage params1, params2;
|
||||
bool focusNextPrevChild(bool next) override;
|
||||
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
|
||||
std::unique_ptr<QTimer> poll_timer;
|
||||
};
|
||||
@ -894,12 +894,12 @@ SDLState::~SDLState() {
|
||||
}
|
||||
}
|
||||
|
||||
Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
|
||||
Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event,
|
||||
const bool down = false) {
|
||||
Common::ParamPackage params({{"engine", "sdl"}});
|
||||
|
||||
auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
|
||||
switch (event.type) {
|
||||
case SDL_JOYAXISMOTION: {
|
||||
auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
|
||||
params.Set("port", joystick->GetPort());
|
||||
params.Set("guid", joystick->GetGUID());
|
||||
params.Set("axis", event.jaxis.axis);
|
||||
@ -912,15 +912,14 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_JOYBUTTONUP: {
|
||||
auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
|
||||
case SDL_JOYBUTTONUP:
|
||||
case SDL_JOYBUTTONDOWN: {
|
||||
params.Set("port", joystick->GetPort());
|
||||
params.Set("guid", joystick->GetGUID());
|
||||
params.Set("button", event.jbutton.button);
|
||||
break;
|
||||
}
|
||||
case SDL_JOYHATMOTION: {
|
||||
auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
|
||||
params.Set("port", joystick->GetPort());
|
||||
params.Set("guid", joystick->GetGUID());
|
||||
params.Set("hat", event.jhat.hat);
|
||||
@ -943,6 +942,8 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (down)
|
||||
params.Set("down", 1);
|
||||
return params;
|
||||
}
|
||||
|
||||
@ -971,6 +972,7 @@ public:
|
||||
|
||||
Common::ParamPackage GetNextInput() override {
|
||||
SDL_Event event;
|
||||
bool down = false;
|
||||
while (state.event_queue.Pop(event)) {
|
||||
switch (event.type) {
|
||||
case SDL_JOYAXISMOTION:
|
||||
@ -978,7 +980,11 @@ public:
|
||||
!axis_memory[event.jaxis.which].count(event.jaxis.axis)) {
|
||||
axis_memory[event.jaxis.which][event.jaxis.axis] = event.jaxis.value;
|
||||
axis_event_count[event.jaxis.which][event.jaxis.axis] = 1;
|
||||
break;
|
||||
if (IsAxisAtPole(event.jaxis.value)) {
|
||||
down = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
axis_event_count[event.jaxis.which][event.jaxis.axis]++;
|
||||
// The joystick and axis exist in our map if we take this branch, so no checks
|
||||
@ -1010,9 +1016,11 @@ public:
|
||||
axis_event_count.clear();
|
||||
}
|
||||
}
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
down = true;
|
||||
case SDL_JOYBUTTONUP:
|
||||
case SDL_JOYHATMOTION:
|
||||
return SDLEventToButtonParamPackage(state, event);
|
||||
return SDLEventToButtonParamPackage(state, event, down);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user