mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-06-11 13:13:15 +00:00
Added keyboard and mouse input remapping, mouse movement to joystick logic, GUI and more (#1356)
* added support for loading keyboard config from file * final minor update before pull request * fix messing up the merge * fix waitEvent to correctly handle mouse inputs * add license * Applied coding style fixes * clang-format fucked up the .ini file * actually fix clang changing ini syntax use relative path for the ini file * remove big commented out code blocks, and fixed platform-dependent code * fix windows hating me * added mouse config option * added toggle for mouse movement input (f7) * fix license and style * add numpad support i accidentally left out * added support for mouse wheel (to buttons only) * if keyboard config doesn't exist, autogenerate it * added keybinds for "walk mode" * Mouse movement input is now off by default * code cleanup and misc fixes * delete config file since it is now autogenerated * F6 = F7 + F9 * added better mouse handling with config options * Added capslock support * fix clang-format * Added support for mod key toggle key * F6 and F7 are removed, F9 captures and enables the mouse * Encapsulated globals and new classes in a new namespace * Added mouse side button support * Added per-game config * relocated input parser to the new namespace * changed parser parameters to make it possible to use it from the gui * added home, end, pgup and pgdown * Resolved merge conflict and refactored code * Updated default keybindings * Changed input handling to be single-threaded * General code cleanup * Start working on new backend * Mouse polling, CMakeLists, and basic framework * Output update handling, and reworked file creating, reading and parsing * Parsing works now * Single key button inputs work now * Axis outputs work now * Wheel works now (for me), l2/r2 handling improvements, and misc bugfixes * Downgraded prints to log_debug, and implemented input hierarchy * Implemented key toggle * Added mouse parameter parsing * clang-format * Fixed clang and added a const keyword for mac * Fix input hierarchy * Fixed joysick halfmodes, and possibly the last update on input hierarchy * clang-format * Rewrote the default config to reflect new changes * clang * Update code style * Updated sorting to accomodate for that one specific edge case * Fix default config and the latest bug with input hiearchy * Fix typo * Temporarily added my GUI * Update cmakelists * Possible fix for Gravity Rush * Update Help text, default config, and clang * Updated README with the new keybind info * okay so maybe the gravity rush fix might have slightly broken the joystick halfmode and key toggle * Fixed mistakenly overwriting the last opened config with the default one if the GUI is opened multiple times in a session * Updated Help descriptions and fixed mouse movement default parameters * Fix crash if the Help dialog was opened a second time If it's closed with the top right close button instead of clicking the Help button again, a required flag wasn't reset, making the next click on Help try to close a nonexistent window and segfault * Added closing the config also closing the Help window, and fixed more segfaults due to mismatched flags * Initial controller support * clang and debug print cleanup * Initial axis-to-button logic * Updated Help text * Added 'Reset to Default' button in GUI * Minor text and description updates + fixed an issue with Help text box rendering * Fix button-to-touchpad logic and l2/r2 handling, as they are both axes and buttons The touchpad's button state was correctly handled, so games that use that were fine, but the touchDown flag was always set to true, so games that use this flag had problems, like Gravity Rush * Fix merge conflict * Clang * Added back back button to touchpad binding * Added touchpad button handling * Added end-of-line comments and fixed some crashes happening with the VS debugger * Apply recent changes from kbm-only * Deadzone + initial directional axis-to-button mapping * Added that one missing space in the README. Are you all happy now? * Fixups from making everything use SDL * Revert directional joystick code and fix a memory leak * Change config directory name again to conform to project standards * Clang * Revert the old deeadzone code and properly add the new one * Clang
This commit is contained in:
parent
f3810cebea
commit
c4bfaa6031
17 changed files with 1996 additions and 286 deletions
237
src/qt_gui/kbm_config_dialog.cpp
Normal file
237
src/qt_gui/kbm_config_dialog.cpp
Normal file
|
@ -0,0 +1,237 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "kbm_config_dialog.h"
|
||||
#include "kbm_help_dialog.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "common/config.h"
|
||||
#include "common/path_util.h"
|
||||
#include "game_info.h"
|
||||
#include "src/sdl_window.h"
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QComboBox>
|
||||
#include <QFile>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QTextStream>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
QString previous_game = "default";
|
||||
bool isHelpOpen = false;
|
||||
HelpDialog* helpDialog;
|
||||
|
||||
EditorDialog::EditorDialog(QWidget* parent) : QDialog(parent) {
|
||||
|
||||
setWindowTitle("Edit Keyboard + Mouse and Controller input bindings");
|
||||
resize(600, 400);
|
||||
|
||||
// Create the editor widget
|
||||
editor = new QPlainTextEdit(this);
|
||||
editorFont.setPointSize(10); // Set default text size
|
||||
editor->setFont(editorFont); // Apply font to the editor
|
||||
|
||||
// Create the game selection combo box
|
||||
gameComboBox = new QComboBox(this);
|
||||
gameComboBox->addItem("default"); // Add default option
|
||||
/*
|
||||
gameComboBox = new QComboBox(this);
|
||||
layout->addWidget(gameComboBox); // Add the combobox for selecting game configurations
|
||||
|
||||
// Populate the combo box with game configurations
|
||||
QStringList gameConfigs = GameInfoClass::GetGameInfo(this);
|
||||
gameComboBox->addItems(gameConfigs);
|
||||
gameComboBox->setCurrentText("default.ini"); // Set the default selection
|
||||
*/
|
||||
// Load all installed games
|
||||
loadInstalledGames();
|
||||
|
||||
// Create Save, Cancel, and Help buttons
|
||||
QPushButton* saveButton = new QPushButton("Save", this);
|
||||
QPushButton* cancelButton = new QPushButton("Cancel", this);
|
||||
QPushButton* helpButton = new QPushButton("Help", this);
|
||||
QPushButton* defaultButton = new QPushButton("Default", this);
|
||||
|
||||
// Layout for the game selection and buttons
|
||||
QHBoxLayout* topLayout = new QHBoxLayout();
|
||||
topLayout->addWidget(gameComboBox);
|
||||
topLayout->addStretch();
|
||||
topLayout->addWidget(saveButton);
|
||||
topLayout->addWidget(cancelButton);
|
||||
topLayout->addWidget(defaultButton);
|
||||
topLayout->addWidget(helpButton);
|
||||
|
||||
// Main layout with editor and buttons
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->addLayout(topLayout);
|
||||
layout->addWidget(editor);
|
||||
|
||||
// Load the default config file content into the editor
|
||||
loadFile(gameComboBox->currentText());
|
||||
|
||||
// Connect button and combo box signals
|
||||
connect(saveButton, &QPushButton::clicked, this, &EditorDialog::onSaveClicked);
|
||||
connect(cancelButton, &QPushButton::clicked, this, &EditorDialog::onCancelClicked);
|
||||
connect(helpButton, &QPushButton::clicked, this, &EditorDialog::onHelpClicked);
|
||||
connect(defaultButton, &QPushButton::clicked, this, &EditorDialog::onResetToDefaultClicked);
|
||||
connect(gameComboBox, &QComboBox::currentTextChanged, this,
|
||||
&EditorDialog::onGameSelectionChanged);
|
||||
}
|
||||
|
||||
void EditorDialog::loadFile(QString game) {
|
||||
|
||||
const auto config_file = Config::GetFoolproofKbmConfigFile(game.toStdString());
|
||||
QFile file(config_file);
|
||||
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QTextStream in(&file);
|
||||
editor->setPlainText(in.readAll());
|
||||
originalConfig = editor->toPlainText();
|
||||
file.close();
|
||||
} else {
|
||||
QMessageBox::warning(this, "Error", "Could not open the file for reading");
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDialog::saveFile(QString game) {
|
||||
|
||||
const auto config_file = Config::GetFoolproofKbmConfigFile(game.toStdString());
|
||||
QFile file(config_file);
|
||||
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream out(&file);
|
||||
out << editor->toPlainText();
|
||||
file.close();
|
||||
} else {
|
||||
QMessageBox::warning(this, "Error", "Could not open the file for writing");
|
||||
}
|
||||
}
|
||||
|
||||
// Override the close event to show the save confirmation dialog only if changes were made
|
||||
void EditorDialog::closeEvent(QCloseEvent* event) {
|
||||
if (isHelpOpen) {
|
||||
helpDialog->close();
|
||||
isHelpOpen = false;
|
||||
// at this point I might have to add this flag and the help dialog to the class itself
|
||||
}
|
||||
if (hasUnsavedChanges()) {
|
||||
QMessageBox::StandardButton reply;
|
||||
reply = QMessageBox::question(this, "Save Changes", "Do you want to save changes?",
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||
|
||||
if (reply == QMessageBox::Yes) {
|
||||
saveFile(gameComboBox->currentText());
|
||||
event->accept(); // Close the dialog
|
||||
} else if (reply == QMessageBox::No) {
|
||||
event->accept(); // Close the dialog without saving
|
||||
} else {
|
||||
event->ignore(); // Cancel the close event
|
||||
}
|
||||
} else {
|
||||
event->accept(); // No changes, close the dialog without prompting
|
||||
}
|
||||
}
|
||||
void EditorDialog::keyPressEvent(QKeyEvent* event) {
|
||||
if (event->key() == Qt::Key_Escape) {
|
||||
if (isHelpOpen) {
|
||||
helpDialog->close();
|
||||
isHelpOpen = false;
|
||||
}
|
||||
close(); // Trigger the close action, same as pressing the close button
|
||||
} else {
|
||||
QDialog::keyPressEvent(event); // Call the base class implementation for other keys
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDialog::onSaveClicked() {
|
||||
if (isHelpOpen) {
|
||||
helpDialog->close();
|
||||
isHelpOpen = false;
|
||||
}
|
||||
saveFile(gameComboBox->currentText());
|
||||
reject(); // Close the dialog
|
||||
}
|
||||
|
||||
void EditorDialog::onCancelClicked() {
|
||||
if (isHelpOpen) {
|
||||
helpDialog->close();
|
||||
isHelpOpen = false;
|
||||
}
|
||||
reject(); // Close the dialog
|
||||
}
|
||||
|
||||
void EditorDialog::onHelpClicked() {
|
||||
if (!isHelpOpen) {
|
||||
helpDialog = new HelpDialog(&isHelpOpen, this);
|
||||
helpDialog->setWindowTitle("Help");
|
||||
helpDialog->setAttribute(Qt::WA_DeleteOnClose); // Clean up on close
|
||||
// Get the position and size of the Config window
|
||||
QRect configGeometry = this->geometry();
|
||||
int helpX = configGeometry.x() + configGeometry.width() + 10; // 10 pixels offset
|
||||
int helpY = configGeometry.y();
|
||||
// Move the Help dialog to the right side of the Config window
|
||||
helpDialog->move(helpX, helpY);
|
||||
helpDialog->show();
|
||||
isHelpOpen = true;
|
||||
} else {
|
||||
helpDialog->close();
|
||||
isHelpOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDialog::onResetToDefaultClicked() {
|
||||
bool default_default = gameComboBox->currentText() == "default";
|
||||
QString prompt =
|
||||
default_default
|
||||
? "Do you want to reset your custom default config to the original default config?"
|
||||
: "Do you want to reset this config to your custom default config?";
|
||||
QMessageBox::StandardButton reply =
|
||||
QMessageBox::question(this, "Reset to Default", prompt, QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (reply == QMessageBox::Yes) {
|
||||
if (default_default) {
|
||||
const auto default_file = Config::GetFoolproofKbmConfigFile("default");
|
||||
std::filesystem::remove(default_file);
|
||||
}
|
||||
const auto config_file = Config::GetFoolproofKbmConfigFile("default");
|
||||
QFile file(config_file);
|
||||
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QTextStream in(&file);
|
||||
editor->setPlainText(in.readAll());
|
||||
file.close();
|
||||
} else {
|
||||
QMessageBox::warning(this, "Error", "Could not open the file for reading");
|
||||
}
|
||||
// saveFile(gameComboBox->currentText());
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorDialog::hasUnsavedChanges() {
|
||||
// Compare the current content with the original content to check if there are unsaved changes
|
||||
return editor->toPlainText() != originalConfig;
|
||||
}
|
||||
void EditorDialog::loadInstalledGames() {
|
||||
previous_game = "default";
|
||||
QStringList filePaths;
|
||||
for (const auto& installLoc : Config::getGameInstallDirs()) {
|
||||
QString installDir;
|
||||
Common::FS::PathToQString(installDir, installLoc);
|
||||
QDir parentFolder(installDir);
|
||||
QFileInfoList fileList = parentFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
for (const auto& fileInfo : fileList) {
|
||||
if (fileInfo.isDir() && !fileInfo.filePath().endsWith("-UPDATE")) {
|
||||
gameComboBox->addItem(fileInfo.fileName()); // Add game name to combo box
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void EditorDialog::onGameSelectionChanged(const QString& game) {
|
||||
saveFile(previous_game);
|
||||
loadFile(gameComboBox->currentText()); // Reload file based on the selected game
|
||||
previous_game = gameComboBox->currentText();
|
||||
}
|
38
src/qt_gui/kbm_config_dialog.h
Normal file
38
src/qt_gui/kbm_config_dialog.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDialog>
|
||||
#include <QPlainTextEdit>
|
||||
#include "string"
|
||||
|
||||
class EditorDialog : public QDialog {
|
||||
Q_OBJECT // Necessary for using Qt's meta-object system (signals/slots)
|
||||
public : explicit EditorDialog(QWidget* parent = nullptr); // Constructor
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event) override; // Override close event
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
|
||||
private:
|
||||
QPlainTextEdit* editor; // Editor widget for the config file
|
||||
QFont editorFont; // To handle the text size
|
||||
QString originalConfig; // Starting config string
|
||||
std::string gameId;
|
||||
|
||||
QComboBox* gameComboBox; // Combo box for selecting game configurations
|
||||
|
||||
void loadFile(QString game); // Function to load the config file
|
||||
void saveFile(QString game); // Function to save the config file
|
||||
void loadInstalledGames(); // Helper to populate gameComboBox
|
||||
bool hasUnsavedChanges(); // Checks for unsaved changes
|
||||
|
||||
private slots:
|
||||
void onSaveClicked(); // Save button slot
|
||||
void onCancelClicked(); // Slot for handling cancel button
|
||||
void onHelpClicked(); // Slot for handling help button
|
||||
void onResetToDefaultClicked();
|
||||
void onGameSelectionChanged(const QString& game); // Slot for game selection changes
|
||||
};
|
112
src/qt_gui/kbm_help_dialog.cpp
Normal file
112
src/qt_gui/kbm_help_dialog.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "kbm_help_dialog.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDialog>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QPushButton>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
ExpandableSection::ExpandableSection(const QString& title, const QString& content,
|
||||
QWidget* parent = nullptr)
|
||||
: QWidget(parent) {
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
|
||||
// Button to toggle visibility of content
|
||||
toggleButton = new QPushButton(title);
|
||||
layout->addWidget(toggleButton);
|
||||
|
||||
// QTextBrowser for content (initially hidden)
|
||||
contentBrowser = new QTextBrowser();
|
||||
contentBrowser->setPlainText(content);
|
||||
contentBrowser->setVisible(false);
|
||||
|
||||
// Remove scrollbars from QTextBrowser
|
||||
contentBrowser->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
contentBrowser->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
// Set size policy to allow vertical stretching only
|
||||
contentBrowser->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
|
||||
// Calculate and set initial height based on content
|
||||
updateContentHeight();
|
||||
|
||||
layout->addWidget(contentBrowser);
|
||||
|
||||
// Connect button click to toggle visibility
|
||||
connect(toggleButton, &QPushButton::clicked, [this]() {
|
||||
contentBrowser->setVisible(!contentBrowser->isVisible());
|
||||
if (contentBrowser->isVisible()) {
|
||||
updateContentHeight(); // Update height when expanding
|
||||
}
|
||||
emit expandedChanged(); // Notify for layout adjustments
|
||||
});
|
||||
|
||||
// Connect to update height if content changes
|
||||
connect(contentBrowser->document(), &QTextDocument::contentsChanged, this,
|
||||
&ExpandableSection::updateContentHeight);
|
||||
|
||||
// Minimal layout settings for spacing
|
||||
layout->setSpacing(2);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void HelpDialog::closeEvent(QCloseEvent* event) {
|
||||
*help_open_ptr = false;
|
||||
close();
|
||||
}
|
||||
void HelpDialog::reject() {
|
||||
*help_open_ptr = false;
|
||||
close();
|
||||
}
|
||||
|
||||
HelpDialog::HelpDialog(bool* open_flag, QWidget* parent) : QDialog(parent) {
|
||||
help_open_ptr = open_flag;
|
||||
// Main layout for the help dialog
|
||||
QVBoxLayout* mainLayout = new QVBoxLayout(this);
|
||||
|
||||
// Container widget for the scroll area
|
||||
QWidget* containerWidget = new QWidget;
|
||||
QVBoxLayout* containerLayout = new QVBoxLayout(containerWidget);
|
||||
|
||||
// Add expandable sections to container layout
|
||||
auto* quickstartSection = new ExpandableSection("Quickstart", quickstart());
|
||||
auto* faqSection = new ExpandableSection("FAQ", faq());
|
||||
auto* syntaxSection = new ExpandableSection("Syntax", syntax());
|
||||
auto* specialSection = new ExpandableSection("Special Bindings", special());
|
||||
auto* bindingsSection = new ExpandableSection("Keybindings", bindings());
|
||||
|
||||
containerLayout->addWidget(quickstartSection);
|
||||
containerLayout->addWidget(faqSection);
|
||||
containerLayout->addWidget(syntaxSection);
|
||||
containerLayout->addWidget(specialSection);
|
||||
containerLayout->addWidget(bindingsSection);
|
||||
containerLayout->addStretch(1);
|
||||
|
||||
// Scroll area wrapping the container
|
||||
QScrollArea* scrollArea = new QScrollArea;
|
||||
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
scrollArea->setWidgetResizable(true);
|
||||
scrollArea->setWidget(containerWidget);
|
||||
|
||||
// Add the scroll area to the main dialog layout
|
||||
mainLayout->addWidget(scrollArea);
|
||||
setLayout(mainLayout);
|
||||
|
||||
// Minimum size for the dialog
|
||||
setMinimumSize(500, 400);
|
||||
|
||||
// Re-adjust dialog layout when any section expands/collapses
|
||||
connect(quickstartSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize);
|
||||
connect(faqSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize);
|
||||
connect(syntaxSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize);
|
||||
connect(specialSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize);
|
||||
connect(bindingsSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize);
|
||||
}
|
169
src/qt_gui/kbm_help_dialog.h
Normal file
169
src/qt_gui/kbm_help_dialog.h
Normal file
|
@ -0,0 +1,169 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDialog>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QTextBrowser>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class ExpandableSection : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ExpandableSection(const QString& title, const QString& content, QWidget* parent);
|
||||
|
||||
signals:
|
||||
void expandedChanged(); // Signal to indicate layout size change
|
||||
|
||||
private:
|
||||
QPushButton* toggleButton;
|
||||
QTextBrowser* contentBrowser; // Changed from QLabel to QTextBrowser
|
||||
QPropertyAnimation* animation;
|
||||
int contentHeight;
|
||||
void updateContentHeight() {
|
||||
int contentHeight = contentBrowser->document()->size().height();
|
||||
contentBrowser->setMinimumHeight(contentHeight + 5);
|
||||
contentBrowser->setMaximumHeight(contentHeight + 50);
|
||||
}
|
||||
};
|
||||
|
||||
class HelpDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HelpDialog(bool* open_flag = nullptr, QWidget* parent = nullptr);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
void reject() override;
|
||||
|
||||
private:
|
||||
bool* help_open_ptr;
|
||||
|
||||
QString quickstart() {
|
||||
return
|
||||
R"(The keyboard and controller remapping backend, GUI and documentation have been written by kalaposfos
|
||||
|
||||
In this section, you will find information about the project, its features and help on setting up your ideal setup.
|
||||
To view the config file's syntax, check out the Syntax tab, for keybind names, visit Normal Keybinds and Special Bindings, and if you are here to view emulator-wide keybinds, you can find it in the FAQ section.
|
||||
This project started out because I didn't like the original unchangeable keybinds, but rather than waiting for someone else to do it, I implemented this myself. From the default keybinds, you can clearly tell this was a project built for Bloodborne, but ovbiously you can make adjustments however you like.
|
||||
)";
|
||||
}
|
||||
QString faq() {
|
||||
return
|
||||
R"(Q: What are the emulator-wide keybinds?
|
||||
A: -F12: Triggers Renderdoc capture
|
||||
-F11: Toggles fullscreen
|
||||
-F10: Toggles FPS counter
|
||||
-Ctrl F10: Open the debug menu
|
||||
-F9: Pauses emultor, if the debug menu is open
|
||||
-F8: Reparses the config file while in-game
|
||||
-F7: Toggles mouse capture and mouse input
|
||||
|
||||
Q: How do I change between mouse and controller joystick input, and why is it even required?
|
||||
A: You can switch between them with F7, and it is required, because mouse input is done with polling, which means mouse movement is checked every frame, and if it didn't move, the code manually sets the emulator's virtual controller to 0 (back to the center), even if other input devices would update it.
|
||||
|
||||
Q: What happens if I accidentally make a typo in the config?
|
||||
A: The code recognises the line as wrong, and skip it, so the rest of the file will get parsed, but that line in question will be treated like a comment line. You can find these lines in the log, if you search for 'input_handler'.
|
||||
|
||||
Q: I want to bind <input> to <output>, but your code doesn't support <input>!
|
||||
A: Some keys are intentionally omitted, but if you read the bindings through, and you're sure it is not there and isn't one of the intentionally disabled ones, open an issue on https://github.com/shadps4-emu/shadPS4.
|
||||
)";
|
||||
}
|
||||
QString syntax() {
|
||||
return
|
||||
R"(This is the full list of currently supported mouse, keyboard and controller inputs, and how to use them.
|
||||
Emulator-reserved keys: F1 through F12
|
||||
|
||||
Syntax (aka how a line can look like):
|
||||
#Comment line
|
||||
<controller_button> = <input>, <input>, <input>;
|
||||
<controller_button> = <input>, <input>;
|
||||
<controller_button> = <input>;
|
||||
|
||||
Examples:
|
||||
#Interact
|
||||
cross = e;
|
||||
#Heavy attack (in BB)
|
||||
r2 = leftbutton, lshift;
|
||||
#Move forward
|
||||
axis_left_y_minus = w;
|
||||
|
||||
You can make a comment line by putting # as the first character.
|
||||
Whitespace doesn't matter, <output>=<input>; is just as valid as <output> = <input>;
|
||||
';' at the ends of lines is also optional.
|
||||
)";
|
||||
}
|
||||
QString bindings() {
|
||||
return
|
||||
R"(The following names should be interpreted without the '' around them, and for inputs that have left and right versions, only the left one is shown, but the right can be inferred from that.
|
||||
Example: 'lshift', 'rshift'
|
||||
|
||||
Keyboard:
|
||||
Alphabet: 'a', 'b', ..., 'z'
|
||||
Numbers: '0', '1', ..., '9'
|
||||
Keypad: 'kp0', kp1', ..., 'kp9', 'kpperiod', 'kpcomma',
|
||||
'kpdivide', 'kpmultiply', 'kpdivide', 'kpplus', 'kpminus', 'kpenter'
|
||||
Punctuation and misc:
|
||||
'space', 'comma', 'period', 'question', 'semicolon', 'minus', 'plus', 'lparenthesis', 'lbracket', 'lbrace', 'backslash', 'dash',
|
||||
'enter', 'tab', backspace', 'escape'
|
||||
Arrow keys: 'up', 'down', 'left', 'right'
|
||||
Modifier keys:
|
||||
'lctrl', 'lshift', 'lalt', 'lwin' = 'lmeta' (same input, different names, so if you are not on Windows and don't like calling this the Windows key, there is an alternative)
|
||||
|
||||
Mouse:
|
||||
'leftbutton', 'rightbutton', 'middlebutton', 'sidebuttonforward', 'sidebuttonback'
|
||||
The following wheel inputs cannot be bound to axis input, only button:
|
||||
'mousewheelup', 'mousewheeldown', 'mousewheelleft', 'mousewheelright'
|
||||
|
||||
Controller:
|
||||
The touchpad currently can't be rebound to anything else, but you can bind buttons to it.
|
||||
If you have a controller that has different names for buttons, it will still work, just look up what are the equivalent names for that controller
|
||||
The same left-right rule still applies here.
|
||||
Buttons:
|
||||
'triangle', 'circle', 'cross', 'square', 'l1', 'l3',
|
||||
'options', touchpad', 'up', 'down', 'left', 'right'
|
||||
Axes if you bind them to a button input:
|
||||
'axis_left_x_plus', 'axis_left_x_minus', 'axis_left_y_plus', 'axis_left_y_minus',
|
||||
'axis_right_x_plus', ..., 'axis_right_y_minus',
|
||||
'l2'
|
||||
Axes if you bind them to another axis input:
|
||||
'axis_left_x' 'axis_left_y' 'axis_right_x' 'axis_right_y',
|
||||
'l2'
|
||||
)";
|
||||
}
|
||||
QString special() {
|
||||
return
|
||||
R"(There are some extra bindings you can put into the config file, that don't correspond to a controller input, but rather something else.
|
||||
You can find these here, with detailed comments, examples and suggestions for most of them.
|
||||
|
||||
'leftjoystick_halfmode' and 'rightjoystick_halfmode' = <key>;
|
||||
These are a pair of input modifiers, that change the way keyboard button bound axes work. By default, those push the joystick to the max in their respective direction, but if their respective joystick_halfmode modifier value is true, they only push it... halfway. With this, you can change from run to walk in games like Bloodborne.
|
||||
|
||||
'mouse_to_joystick' = 'none', 'left' or 'right';
|
||||
This binds the mouse movement to either joystick. If it recieves a value that is not 'left' or 'right', it defaults to 'none'.
|
||||
|
||||
'mouse_movement_params' = float, float, float;
|
||||
(If you don't know what a float is, it is a data type that stores non-whole numbers.)
|
||||
Default values: 0.5, 1, 0.125
|
||||
Let's break each parameter down:
|
||||
1st: mouse_deadzone_offset: this value should have a value between 0 and 1 (It gets clamped to that range anyway), with 0 being no offset and 1 being pushing the joystick to the max in the direction the mouse moved.
|
||||
This controls the minimum distance the joystick gets moved, when moving the mouse. If set to 0, it will emulate raw mouse input, which doesn't work very well due to deadzones preventing input if the movement is not large enough.
|
||||
2nd: mouse_speed: It's just a standard multiplier to the mouse input speed.
|
||||
If you input a negative number, the axis directions get reversed (Keep in mind that the offset can still push it back to positive, if it's big enough)
|
||||
3rd: mouse_speed_offset: This also should be in the 0 to 1 range, with 0 being no offset and 1 being offsetting to the max possible value.
|
||||
This is best explained through an example: Let's set mouse_deadzone to 0.5, and this to 0: This means that if we move the mousevery slowly, it still inputs a half-strength joystick input, and if we increase the speed, it would stay that way until we move faster than half the max speed. If we instead set this to 0.25, we now only need to move the mouse faster than the 0.5-0.25=0.25=quarter of the max speed, to get an increase in joystick speed. If we set it to 0.5, then even moving the mouse at 1 pixel per frame will result in a faster-than-minimum speed.
|
||||
|
||||
'key_toggle' = <key>, <key_to_toggle>;
|
||||
This assigns a key to another key, and if pressed, toggles that key's virtual value. If it's on, then it doesn't matter if the key is pressed or not, the input handler will treat it as if it's pressed.
|
||||
You can make an input toggleable with this, for example: Let's say we want to be able to toggle l1 with t. You can then bind l1 to a key you won't use, like kpenter, then bind t to toggle that, so you will end up with this:
|
||||
l1 = kpenter;
|
||||
key_toggle = t, kpenter;
|
||||
'analog_deadzone' = <device>, <value>;
|
||||
value goes from 1 to 127 (no deadzone to max deadzone)
|
||||
devices: leftjoystick, rightjoystick, l2, r2
|
||||
)";
|
||||
}
|
||||
};
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QDockWidget>
|
||||
#include <QKeyEvent>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QProgressDialog>
|
||||
|
||||
#include "about_dialog.h"
|
||||
|
@ -21,6 +22,9 @@
|
|||
#include "install_dir_select.h"
|
||||
#include "main_window.h"
|
||||
#include "settings_dialog.h"
|
||||
|
||||
#include "kbm_config_dialog.h"
|
||||
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
#ifdef ENABLE_DISCORD_RPC
|
||||
#include "common/discord_rpc_handler.h"
|
||||
|
@ -291,6 +295,12 @@ void MainWindow::CreateConnects() {
|
|||
settingsDialog->exec();
|
||||
});
|
||||
|
||||
// this is the editor for kbm keybinds
|
||||
connect(ui->controllerButton, &QPushButton::clicked, this, [this]() {
|
||||
EditorDialog* editorWindow = new EditorDialog(this);
|
||||
editorWindow->exec(); // Show the editor window modally
|
||||
});
|
||||
|
||||
#ifdef ENABLE_UPDATER
|
||||
connect(ui->updaterAct, &QAction::triggered, this, [this]() {
|
||||
auto checkUpdate = new CheckUpdate(true);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue