citra-qt: Add input settings configuration
This commit is contained in:
parent
09f43c0975
commit
77a68e0607
10 changed files with 263 additions and 16 deletions
|
@ -41,12 +41,12 @@ bool Config::LoadINI(INIReader* config, const char* location, const std::string&
|
|||
}
|
||||
|
||||
static const std::array<int, Settings::NativeInput::NUM_INPUTS> defaults = {
|
||||
GLFW_KEY_A, GLFW_KEY_S, GLFW_KEY_Z, GLFW_KEY_X,
|
||||
GLFW_KEY_X, GLFW_KEY_Z, GLFW_KEY_S, GLFW_KEY_A,
|
||||
GLFW_KEY_Q, GLFW_KEY_W, GLFW_KEY_1, GLFW_KEY_2,
|
||||
GLFW_KEY_M, GLFW_KEY_N, GLFW_KEY_B,
|
||||
GLFW_KEY_I, GLFW_KEY_K, GLFW_KEY_J, GLFW_KEY_L,
|
||||
GLFW_KEY_T, GLFW_KEY_G, GLFW_KEY_F, GLFW_KEY_H,
|
||||
GLFW_KEY_UP, GLFW_KEY_DOWN, GLFW_KEY_LEFT, GLFW_KEY_RIGHT,
|
||||
GLFW_KEY_I, GLFW_KEY_K, GLFW_KEY_J, GLFW_KEY_L
|
||||
GLFW_KEY_M, GLFW_KEY_N, GLFW_KEY_B
|
||||
};
|
||||
|
||||
void Config::ReadValues() {
|
||||
|
|
|
@ -4,6 +4,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
|||
set(SRCS
|
||||
config/controller_config.cpp
|
||||
config/controller_config_util.cpp
|
||||
config/inputs.cpp
|
||||
config.cpp
|
||||
debugger/callstack.cpp
|
||||
debugger/disassembler.cpp
|
||||
|
@ -28,6 +29,7 @@ set(SRCS
|
|||
set(HEADERS
|
||||
config/controller_config.h
|
||||
config/controller_config_util.h
|
||||
config/inputs.h
|
||||
config.h
|
||||
debugger/callstack.h
|
||||
debugger/disassembler.h
|
||||
|
|
|
@ -21,13 +21,13 @@ Config::Config() {
|
|||
Reload();
|
||||
}
|
||||
|
||||
static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults = {
|
||||
Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X,
|
||||
const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> Config::defaults = {
|
||||
Qt::Key_X, Qt::Key_Z, Qt::Key_S, Qt::Key_A,
|
||||
Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2,
|
||||
Qt::Key_M, Qt::Key_N, Qt::Key_B,
|
||||
Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L,
|
||||
Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H,
|
||||
Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right,
|
||||
Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L
|
||||
Qt::Key_M, Qt::Key_N, Qt::Key_B
|
||||
};
|
||||
|
||||
void Config::ReadValues() {
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#include "core/settings.h"
|
||||
|
||||
class QSettings;
|
||||
|
||||
class Config {
|
||||
|
@ -20,4 +23,5 @@ public:
|
|||
|
||||
void Reload();
|
||||
void Save();
|
||||
static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults;
|
||||
};
|
||||
|
|
170
src/citra_qt/config/inputs.cpp
Normal file
170
src/citra_qt/config/inputs.cpp
Normal file
|
@ -0,0 +1,170 @@
|
|||
// Copyright 2015 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QKeySequence>
|
||||
#include <QLabel>
|
||||
#include <QSettings>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "citra_qt/config.h"
|
||||
#include "citra_qt/config/inputs.h"
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
InputsDialog::InputsDialog(QWidget* parent) : QDialog(parent) {
|
||||
// create a copy of the current settings
|
||||
temp_settings = Settings::Values(Settings::values);
|
||||
signal_mapper = new QSignalMapper(this);
|
||||
|
||||
// create the QPushButtons
|
||||
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
|
||||
push_buttons[i] = new QPushButton(this);
|
||||
push_buttons[i]->setCheckable(true);
|
||||
push_buttons[i]->setDefault(false);
|
||||
push_buttons[i]->setAutoDefault(false);
|
||||
}
|
||||
|
||||
static const std::string label_array[] = {
|
||||
"Y:", "X:", "B:", "A:",
|
||||
"L:", "R:", "ZL:", "ZR:",
|
||||
"Left:", "Right:", "Up:", "Down:",
|
||||
"Left:", "Right:", "Up:", "Down:",
|
||||
"Left:", "Right:", "Up:", "Down:",
|
||||
"Start:", "Select:", "Home:"
|
||||
};
|
||||
|
||||
static const std::string group_names[] = {
|
||||
"Face Buttons", "Shoulder Buttons", "C-Stick",
|
||||
"Directional Pad", "Circle Pad", "System Buttons"
|
||||
};
|
||||
|
||||
QGridLayout* grid = new QGridLayout();
|
||||
int id = 0;
|
||||
for (int i = 0; i < ARRAY_SIZE(group_names); ++i) {
|
||||
QGroupBox* group = new QGroupBox(tr(group_names[i].c_str()));
|
||||
QGridLayout* box = new QGridLayout;
|
||||
for (int x = 0; x <= (Settings::NativeInput::NUM_INPUTS / ARRAY_SIZE(group_names)); ++x) {
|
||||
QLabel* label = new QLabel(tr(label_array[id].c_str()));
|
||||
box->addWidget(label, (int) x / 2 * 2, (int) x % 2 * 2);
|
||||
box->addWidget(push_buttons[id], (int) x / 2 * 2 + 1, (int) x % 2 * 2);
|
||||
signal_mapper->setMapping(push_buttons[id], id);
|
||||
connect(push_buttons[id], SIGNAL(clicked()), signal_mapper, SLOT(map()));
|
||||
++id;
|
||||
if (id >= Settings::NativeInput::NUM_INPUTS)
|
||||
break;
|
||||
}
|
||||
group->setLayout(box);
|
||||
grid->addWidget(group, (int) i % 3, (int) i / 3 * 2);
|
||||
}
|
||||
|
||||
connect(signal_mapper, SIGNAL(mapped(int)), this, SLOT(ChangeValue(int)));
|
||||
|
||||
// the button box that contains the restore default/ok/cancel buttons
|
||||
QVBoxLayout* verticalLayout = new QVBoxLayout();
|
||||
QDialogButtonBox* buttonBox = new QDialogButtonBox();
|
||||
buttonBox->setOrientation(Qt::Horizontal);
|
||||
buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok | QDialogButtonBox::RestoreDefaults);
|
||||
|
||||
verticalLayout->addLayout(grid);
|
||||
verticalLayout->addWidget(buttonBox);
|
||||
|
||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(SaveSettings()));
|
||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
|
||||
setLayout(verticalLayout);
|
||||
setWindowTitle(tr("Input Settings"));
|
||||
|
||||
// set up event handlers for the buttons
|
||||
QPushButton* defaultButton = buttonBox->button(QDialogButtonBox::RestoreDefaults);
|
||||
connect(defaultButton, SIGNAL(clicked()), this, SLOT(RestoreDefaultSettings()));
|
||||
|
||||
// display current key settings
|
||||
UpdateKeyLabels();
|
||||
}
|
||||
|
||||
void InputsDialog::ChangeValue(int id) {
|
||||
|
||||
if (current_button_id > -1)
|
||||
push_buttons[current_button_id]->setChecked(false);
|
||||
|
||||
if (current_button_id == id) {
|
||||
push_buttons[current_button_id]->setChecked(false);
|
||||
current_button_id = -1;
|
||||
} else {
|
||||
push_buttons[id]->setChecked(true);
|
||||
current_button_id = id;
|
||||
}
|
||||
}
|
||||
|
||||
void InputsDialog::UpdateValue(int key) {
|
||||
|
||||
bool update = std::none_of(std::begin(Settings::NativeInput::All), std::end(Settings::NativeInput::All),
|
||||
[&](Settings::NativeInput::Values val) { return key == temp_settings.input_mappings[val]; });
|
||||
|
||||
if (update) {
|
||||
temp_settings.input_mappings[Settings::NativeInput::All[current_button_id]] = key;
|
||||
push_buttons[current_button_id]->setChecked(false);
|
||||
push_buttons[current_button_id]->setText(GetKeyName(temp_settings.input_mappings[Settings::NativeInput::All[current_button_id]]));
|
||||
current_button_id = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void InputsDialog::UpdateKeyLabels() {
|
||||
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
|
||||
push_buttons[i]->setText(GetKeyName(temp_settings.input_mappings[Settings::NativeInput::All[i]]));
|
||||
}
|
||||
}
|
||||
|
||||
QString InputsDialog::GetKeyName(int key_code) {
|
||||
if (key_code == Qt::Key_Shift)
|
||||
return tr("Shift");
|
||||
|
||||
if (key_code == Qt::Key_Control)
|
||||
return tr("Ctrl");
|
||||
|
||||
if (key_code == Qt::Key_Alt)
|
||||
return tr("Alt");
|
||||
|
||||
if (key_code == Qt::Key_Meta)
|
||||
return tr("Meta");
|
||||
|
||||
return QKeySequence(key_code).toString();
|
||||
}
|
||||
|
||||
void InputsDialog::RestoreDefaultSettings() {
|
||||
// load the default button settings into temp_settings
|
||||
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
|
||||
temp_settings.input_mappings[Settings::NativeInput::All[i]] = Config::defaults[i].toInt();
|
||||
}
|
||||
|
||||
// then display it
|
||||
UpdateKeyLabels();
|
||||
}
|
||||
|
||||
void InputsDialog::SaveSettings() {
|
||||
Config config;
|
||||
|
||||
// load the temporary settings into our real settings
|
||||
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
|
||||
Settings::values.input_mappings[Settings::NativeInput::All[i]] =
|
||||
temp_settings.input_mappings[Settings::NativeInput::All[i]];
|
||||
}
|
||||
|
||||
// then save it
|
||||
config.Save();
|
||||
|
||||
// Close the dialog after save the bindings
|
||||
accept();
|
||||
}
|
||||
|
||||
void InputsDialog::keyPressEvent(QKeyEvent* key) {
|
||||
if (current_button_id != -1 && key->key() != Qt::Key_Escape)
|
||||
UpdateValue(key->key());
|
||||
else
|
||||
QDialog::keyPressEvent(key);
|
||||
}
|
56
src/citra_qt/config/inputs.h
Normal file
56
src/citra_qt/config/inputs.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2015 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QKeyEvent>
|
||||
#include <QPushButton>
|
||||
#include <QSignalMapper>
|
||||
|
||||
#include "core/settings.h"
|
||||
|
||||
/// The input configuration dialog
|
||||
class InputsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
InputsDialog(QWidget* parent = nullptr);
|
||||
|
||||
/**
|
||||
* Given a key code, return the key name.
|
||||
* @note This function is conceptually similar to "QKeySequence(key_code).toString()", which however returns gibberish strings for modifier keys (e.g. Ctrl). Hence this function provides special cases for these keys.
|
||||
*/
|
||||
static QString GetKeyName(int key_code);
|
||||
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
|
||||
private:
|
||||
/// Update QPushButton labels to reflect current button mapping.
|
||||
void UpdateKeyLabels();
|
||||
|
||||
/// An array of all the QPushButtons for easy iteration over them
|
||||
std::array<QPushButton*, 23> push_buttons;
|
||||
|
||||
/// Temporary settings used when configuration is changed but not saved yet
|
||||
Settings::Values temp_settings;
|
||||
|
||||
/// Map of all the QPushButtons signals
|
||||
QSignalMapper* signal_mapper;
|
||||
|
||||
/// Current QPushButton id, it's -1 as default value since it's an incorrect id, right ones are from 0 to 22.
|
||||
int current_button_id = -1;
|
||||
|
||||
private slots:
|
||||
void SaveSettings();
|
||||
void RestoreDefaultSettings();
|
||||
|
||||
/// Set/Unset the QPushButton with the given id to allow it to modify his bind key. Discards previous selected button.
|
||||
void ChangeValue(int id);
|
||||
|
||||
/// Update the QPushButton & key binding of the current_button_id with the given key if it's possible (Unused and allowed key).
|
||||
void UpdateValue(int key);
|
||||
};
|
|
@ -15,6 +15,8 @@
|
|||
#include "citra_qt/hotkeys.h"
|
||||
#include "citra_qt/main.h"
|
||||
|
||||
#include "citra_qt/config/inputs.h"
|
||||
|
||||
// Debugger
|
||||
#include "citra_qt/debugger/callstack.h"
|
||||
#include "citra_qt/debugger/disassembler.h"
|
||||
|
@ -169,6 +171,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
|
|||
connect(ui.action_Use_Shader_JIT, SIGNAL(triggered(bool)), this, SLOT(SetShaderJITEnabled(bool)));
|
||||
connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode()));
|
||||
connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog()));
|
||||
connect(ui.action_Inputs, SIGNAL(triggered()), this, SLOT(OnOpenInputsDialog()));
|
||||
|
||||
connect(this, SIGNAL(EmulationStarting(EmuThread*)), disasmWidget, SLOT(OnEmulationStarting(EmuThread*)));
|
||||
connect(this, SIGNAL(EmulationStopping()), disasmWidget, SLOT(OnEmulationStopping()));
|
||||
|
@ -418,6 +421,11 @@ void GMainWindow::SetShaderJITEnabled(bool enabled) {
|
|||
VideoCore::g_shader_jit_enabled = enabled;
|
||||
}
|
||||
|
||||
void GMainWindow::OnOpenInputsDialog() {
|
||||
InputsDialog dialog(this);
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
void GMainWindow::ToggleWindowMode() {
|
||||
if (ui.action_Single_Window_Mode->isChecked()) {
|
||||
// Render in the main window...
|
||||
|
|
|
@ -95,6 +95,7 @@ private slots:
|
|||
void OnDisplayTitleBars(bool);
|
||||
void SetHardwareRendererEnabled(bool);
|
||||
void SetShaderJITEnabled(bool);
|
||||
void OnOpenInputsDialog();
|
||||
void ToggleWindowMode();
|
||||
|
||||
private:
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
<addaction name="action_Use_Hardware_Renderer"/>
|
||||
<addaction name="action_Use_Shader_JIT"/>
|
||||
<addaction name="action_Configure"/>
|
||||
<addaction name="action_Inputs"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_View">
|
||||
<property name="title">
|
||||
|
@ -153,6 +154,11 @@
|
|||
<string>Configure &Hotkeys ...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Inputs">
|
||||
<property name="text">
|
||||
<string>Configure &Controls</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Use_Hardware_Renderer">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
|
|
|
@ -11,29 +11,29 @@ namespace Settings {
|
|||
|
||||
namespace NativeInput {
|
||||
enum Values {
|
||||
A, B, X, Y,
|
||||
Y, X, B, A,
|
||||
L, R, ZL, ZR,
|
||||
START, SELECT, HOME,
|
||||
CUP, CDOWN, CLEFT, CRIGHT,
|
||||
DUP, DDOWN, DLEFT, DRIGHT,
|
||||
SUP, SDOWN, SLEFT, SRIGHT,
|
||||
CUP, CDOWN, CLEFT, CRIGHT,
|
||||
START, SELECT, HOME,
|
||||
NUM_INPUTS
|
||||
};
|
||||
static const std::array<const char*, NUM_INPUTS> Mapping = {{
|
||||
"pad_a", "pad_b", "pad_x", "pad_y",
|
||||
"pad_y", "pad_x", "pad_b", "pad_a",
|
||||
"pad_l", "pad_r", "pad_zl", "pad_zr",
|
||||
"pad_start", "pad_select", "pad_home",
|
||||
"pad_cup", "pad_cdown", "pad_cleft", "pad_cright",
|
||||
"pad_dup", "pad_ddown", "pad_dleft", "pad_dright",
|
||||
"pad_sup", "pad_sdown", "pad_sleft", "pad_sright",
|
||||
"pad_cup", "pad_cdown", "pad_cleft", "pad_cright"
|
||||
"pad_start", "pad_select", "pad_home"
|
||||
}};
|
||||
static const std::array<Values, NUM_INPUTS> All = {{
|
||||
A, B, X, Y,
|
||||
Y, X, B, A,
|
||||
L, R, ZL, ZR,
|
||||
START, SELECT, HOME,
|
||||
CUP, CDOWN, CLEFT, CRIGHT,
|
||||
DUP, DDOWN, DLEFT, DRIGHT,
|
||||
SUP, SDOWN, SLEFT, SRIGHT,
|
||||
CUP, CDOWN, CLEFT, CRIGHT
|
||||
START, SELECT, HOME
|
||||
}};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue