Add UI to configure keyboard-to-controller mapping
This commit is contained in:
parent
132ca9c5a8
commit
221eb28815
|
@ -23,7 +23,13 @@ jobs:
|
||||||
|
|
||||||
- name: Install misc packages
|
- name: Install misc packages
|
||||||
run: >
|
run: >
|
||||||
sudo apt-get update && sudo apt install libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential qt6-base-dev
|
sudo apt-get update && sudo apt install libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential
|
||||||
|
|
||||||
|
- name: Setup Qt
|
||||||
|
uses: jurplel/install-qt-action@v4
|
||||||
|
with:
|
||||||
|
arch: linux_gcc_64
|
||||||
|
version: 6.7.1
|
||||||
|
|
||||||
- name: Configure CMake
|
- name: Configure CMake
|
||||||
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DENABLE_QT_GUI=ON
|
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DENABLE_QT_GUI=ON
|
||||||
|
|
|
@ -17,6 +17,7 @@ Files: CMakeSettings.json
|
||||||
scripts/ps4_names.txt
|
scripts/ps4_names.txt
|
||||||
src/images/about_icon.png
|
src/images/about_icon.png
|
||||||
src/images/controller_icon.png
|
src/images/controller_icon.png
|
||||||
|
src/images/keyboard_icon.png
|
||||||
src/images/exit_icon.png
|
src/images/exit_icon.png
|
||||||
src/images/file_icon.png
|
src/images/file_icon.png
|
||||||
src/images/flag_china.png
|
src/images/flag_china.png
|
||||||
|
|
|
@ -542,6 +542,9 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
|
||||||
|
|
||||||
set(INPUT src/input/controller.cpp
|
set(INPUT src/input/controller.cpp
|
||||||
src/input/controller.h
|
src/input/controller.h
|
||||||
|
src/input/keysmappingprovider.h
|
||||||
|
src/input/keysmappingprovider.cpp
|
||||||
|
src/input/keys_constants.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(EMULATOR src/emulator.cpp
|
set(EMULATOR src/emulator.cpp
|
||||||
|
@ -582,6 +585,9 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
|
||||||
src/qt_gui/settings_dialog.cpp
|
src/qt_gui/settings_dialog.cpp
|
||||||
src/qt_gui/settings_dialog.h
|
src/qt_gui/settings_dialog.h
|
||||||
src/qt_gui/settings_dialog.ui
|
src/qt_gui/settings_dialog.ui
|
||||||
|
src/qt_gui/keyboardcontrolswindow.h
|
||||||
|
src/qt_gui/keyboardcontrolswindow.cpp
|
||||||
|
src/qt_gui/keyboardcontrolswindow.ui
|
||||||
src/qt_gui/main.cpp
|
src/qt_gui/main.cpp
|
||||||
${EMULATOR}
|
${EMULATOR}
|
||||||
${RESOURCE_FILES}
|
${RESOURCE_FILES}
|
||||||
|
|
|
@ -48,6 +48,7 @@ std::vector<std::string> m_elf_viewer;
|
||||||
std::vector<std::string> m_recent_files;
|
std::vector<std::string> m_recent_files;
|
||||||
// Settings
|
// Settings
|
||||||
u32 m_language = 1; // english
|
u32 m_language = 1; // english
|
||||||
|
std::map<Uint32, KeysMapping> m_keyboard_binding_map;
|
||||||
|
|
||||||
bool isLleLibc() {
|
bool isLleLibc() {
|
||||||
return isLibc;
|
return isLibc;
|
||||||
|
@ -247,6 +248,14 @@ void setRecentFiles(std::vector<std::string> recentFiles) {
|
||||||
m_recent_files = recentFiles;
|
m_recent_files = recentFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setKeyboardBindingMap(std::map<Uint32, KeysMapping> map) {
|
||||||
|
m_keyboard_binding_map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<Uint32, KeysMapping> getKeyboardBindingMap() {
|
||||||
|
return m_keyboard_binding_map;
|
||||||
|
}
|
||||||
|
|
||||||
u32 getMainWindowGeometryX() {
|
u32 getMainWindowGeometryX() {
|
||||||
return main_window_geometry_x;
|
return main_window_geometry_x;
|
||||||
}
|
}
|
||||||
|
@ -386,6 +395,34 @@ void load(const std::filesystem::path& path) {
|
||||||
|
|
||||||
m_language = toml::find_or<int>(settings, "consoleLanguage", 1);
|
m_language = toml::find_or<int>(settings, "consoleLanguage", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.contains("Controls")) {
|
||||||
|
auto controls = toml::find<toml::table>(data, "Controls");
|
||||||
|
|
||||||
|
toml::table keyboardBindings{};
|
||||||
|
auto it = controls.find("keyboardBindings");
|
||||||
|
if (it != controls.end() && it->second.is_table()) {
|
||||||
|
keyboardBindings = it->second.as_table();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert TOML table to std::map<Uint32, KeysMapping>
|
||||||
|
for (const auto& [key, value] : keyboardBindings) {
|
||||||
|
try {
|
||||||
|
Uint32 int_key = static_cast<Uint32>(std::stoll(key));
|
||||||
|
if (value.is_integer()) {
|
||||||
|
// Convert the TOML integer value to KeysMapping (int)
|
||||||
|
int int_value = value.as_integer();
|
||||||
|
|
||||||
|
// Add to the map
|
||||||
|
m_keyboard_binding_map[int_key] = static_cast<KeysMapping>(int_value);
|
||||||
|
} else {
|
||||||
|
fmt::print("Unexpected type for value: expected integer, got other type\n");
|
||||||
|
}
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
fmt::print("Error processing key-value pair: {}\n", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void save(const std::filesystem::path& path) {
|
void save(const std::filesystem::path& path) {
|
||||||
toml::value data;
|
toml::value data;
|
||||||
|
@ -443,6 +480,15 @@ void save(const std::filesystem::path& path) {
|
||||||
data["GUI"]["elfDirs"] = m_elf_viewer;
|
data["GUI"]["elfDirs"] = m_elf_viewer;
|
||||||
data["GUI"]["recentFiles"] = m_recent_files;
|
data["GUI"]["recentFiles"] = m_recent_files;
|
||||||
|
|
||||||
|
// Create a TOML table with keyboard bindings
|
||||||
|
toml::table keyboardBindingsTable;
|
||||||
|
// Serialize the map to the TOML table
|
||||||
|
for (const auto& [key, value] : m_keyboard_binding_map) {
|
||||||
|
keyboardBindingsTable[std::to_string(key)] = static_cast<int>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
data["Controls"]["keyboardBindings"] = keyboardBindingsTable;
|
||||||
|
|
||||||
data["Settings"]["consoleLanguage"] = m_language;
|
data["Settings"]["consoleLanguage"] = m_language;
|
||||||
|
|
||||||
std::ofstream file(path, std::ios::out);
|
std::ofstream file(path, std::ios::out);
|
||||||
|
|
|
@ -4,7 +4,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "SDL3/SDL_stdinc.h"
|
||||||
|
#include "input/keys_constants.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
namespace Config {
|
namespace Config {
|
||||||
|
@ -70,6 +73,8 @@ void setMainWindowHeight(u32 height);
|
||||||
void setPkgViewer(std::vector<std::string> pkgList);
|
void setPkgViewer(std::vector<std::string> pkgList);
|
||||||
void setElfViewer(std::vector<std::string> elfList);
|
void setElfViewer(std::vector<std::string> elfList);
|
||||||
void setRecentFiles(std::vector<std::string> recentFiles);
|
void setRecentFiles(std::vector<std::string> recentFiles);
|
||||||
|
void setKeyboardBindingMap(std::map<Uint32, KeysMapping> map);
|
||||||
|
std::map<Uint32, KeysMapping> getKeyboardBindingMap();
|
||||||
|
|
||||||
u32 getMainWindowGeometryX();
|
u32 getMainWindowGeometryX();
|
||||||
u32 getMainWindowGeometryY();
|
u32 getMainWindowGeometryY();
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "core/linker.h"
|
#include "core/linker.h"
|
||||||
#include "input/controller.h"
|
#include "input/controller.h"
|
||||||
|
#include "input/keysmappingprovider.h"
|
||||||
#include "sdl_window.h"
|
#include "sdl_window.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -34,6 +35,6 @@ private:
|
||||||
Input::GameController* controller;
|
Input::GameController* controller;
|
||||||
Core::Linker* linker;
|
Core::Linker* linker;
|
||||||
std::unique_ptr<Frontend::WindowSDL> window;
|
std::unique_ptr<Frontend::WindowSDL> window;
|
||||||
|
std::unique_ptr<KeysMappingProvider> m_keysMappingProvider;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 26.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
-->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 868.8 514" style="enable-background:new 0 0 868.8 514;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:none;stroke:#747474;stroke-width:2;stroke-linecap:round;}
|
||||||
|
.st1{opacity:0.5;}
|
||||||
|
.st2{fill:none;stroke:#747474;stroke-width:4;}
|
||||||
|
.st3{fill:none;stroke:#747474;stroke-width:3;}
|
||||||
|
.st4{fill:none;stroke:#747474;stroke-width:2;}
|
||||||
|
.st5{fill:none;}
|
||||||
|
</style>
|
||||||
|
<g id="Layer_2_00000097496210553772954770000012093511300866492585_">
|
||||||
|
<g id="Layer_1-2">
|
||||||
|
<g id="ps4_android">
|
||||||
|
<path id="路径_4780" class="st0" d="M1,1h170.8"/>
|
||||||
|
<path id="路径_4820" class="st0" d="M1,69.3h170.8"/>
|
||||||
|
<path id="路径_4865" class="st0" d="M1,197h152.1"/>
|
||||||
|
<path id="路径_4894_00000013184940780502961700000014303813344279000497_" class="st0" d="M270.1,296"/>
|
||||||
|
<path id="路径_4894_00000017504210865169069830000017699973930485000372_" class="st0" d="M1,296"/>
|
||||||
|
<path id="路径_3656" class="st0" d="M659.3,195.7l65.7,78.6"/>
|
||||||
|
<path id="路径_3657" class="st0" d="M734.3,198.7l6.7,7.4"/>
|
||||||
|
<path id="路径_4866" class="st0" d="M866.3,137.7H689.1"/>
|
||||||
|
<path id="路径_4867" class="st0" d="M866.3,206H741.1"/>
|
||||||
|
<path id="路径_4868" class="st0" d="M659.1,196h-27"/>
|
||||||
|
<path id="路径_4895" class="st0" d="M867.8,274.3H725.1"/>
|
||||||
|
<path id="路径_4896" class="st0" d="M867.8,342.7H734.1"/>
|
||||||
|
<path id="路径_4869" class="st0" d="M682.5,144.1l6.6-6.5"/>
|
||||||
|
<path id="路径_3658" class="st0" d="M671.6,270.6l62.5,72"/>
|
||||||
|
<path id="路径_4821" class="st0" d="M185.2,84.2l-13.4-14.9"/>
|
||||||
|
<path id="路径_4781" class="st0" d="M172.6,1.7L235,73"/>
|
||||||
|
<path id="路径_4782" class="st0" d="M866.3,1H695.5"/>
|
||||||
|
<path id="路径_4822" class="st0" d="M866.3,69.3H695.5"/>
|
||||||
|
<path id="路径_4823" class="st0" d="M682.1,84.2l13.4-14.9"/>
|
||||||
|
<path id="路径_4783" class="st0" d="M694.7,1.7L632.3,73"/>
|
||||||
|
<path id="路径_4897" class="st0" d="M322.9,304v96.5"/>
|
||||||
|
<path id="路径_4824" class="st0" d="M294.9,28v96.6"/>
|
||||||
|
<path id="路径_4825" class="st0" d="M581.9,28v96.6"/>
|
||||||
|
<path id="路径_4898" class="st0" d="M434.8,323.4v78.7"/>
|
||||||
|
<path id="路径_4899" class="st0" d="M547.2,304v98"/>
|
||||||
|
<path id="路径_4934_00000028290396629278709680000017707286295783229854_" class="st0" d="M697.1,410.7"/>
|
||||||
|
<path id="路径_4934_00000083058795991008605930000003412791582934853814_" class="st0" d="M867.8,410.7"/>
|
||||||
|
<path id="路径_3659_00000059269749574209402570000011115938241451306122_" class="st0" d="M697.6,410.6"/>
|
||||||
|
<path id="路径_3659_00000060009886666316406710000007170877077051697029_" class="st0" d="M597.6,295.6"/>
|
||||||
|
<g id="ps4pro">
|
||||||
|
<g id="组_4415" class="st1">
|
||||||
|
<g id="组_4404">
|
||||||
|
<path id="路径_3" class="st2" d="M322.1,94.8c0,0-23.6,11.6-58.7,0V83.3c-5.8-2.6-13.7-5.2-27.5-6.4
|
||||||
|
c-24-2.1-41.2,0.1-58,11.3v4.3c-2.5,1.6-4.7,3.6-6.6,5.8c-12.2,14.3-47.3,74.3-66.1,179.6c-9.7,54.2-16.9,97.4-18.8,130
|
||||||
|
c-4,42.2,11.4,65.9,11.4,65.9c33,47.9,79.6,37.1,79.6,37.1c16.9-3.8,43.9-15,53.2-49.4c0,0,22.7-92.4,33.9-99.1
|
||||||
|
c12.2-7.4,11.7-8.9,15.4-8s18.8,13.1,37,13.6s32.5-2.2,40-7s12.4-11.1,14.1-11.2c0.9,0,23.2,0,44.5,0l0,0h19.6"/>
|
||||||
|
<path id="路径_3398" class="st3" d="M337.6,85.9h193.9c9.9,0,17.8,8,17.8,17.9c0,0,0,0,0,0V195c0,9.9-7.9,17.9-17.8,17.9
|
||||||
|
c0,0,0,0,0,0H337.6c-9.9,0-17.9-8-17.8-17.9c0,0,0,0,0,0v-91.2C319.7,93.9,327.7,85.9,337.6,85.9
|
||||||
|
C337.6,85.9,337.6,85.9,337.6,85.9z"/>
|
||||||
|
<circle id="椭圆_5" class="st4" cx="323.2" cy="292" r="27.6"/>
|
||||||
|
<circle id="椭圆_8" class="st4" cx="546.3" cy="292" r="27.7"/>
|
||||||
|
<circle id="椭圆_9" class="st3" cx="655.2" cy="145.4" r="21.8"/>
|
||||||
|
<circle id="椭圆_10" class="st3" cx="707.4" cy="195.6" r="21.8"/>
|
||||||
|
<circle id="椭圆_11" class="st3" cx="657.2" cy="248.2" r="21.8"/>
|
||||||
|
<circle id="椭圆_12" class="st3" cx="604.5" cy="195.6" r="21.8"/>
|
||||||
|
<path id="路径_11" class="st4" d="M201.1,140.7h22.4c4.1,0,7.5,3.4,7.5,7.5v19.6c0,2-0.8,3.9-2.2,5.3L218,184
|
||||||
|
c-2.9,2.9-7.7,2.9-10.6,0l-11.2-11.2c-1.4-1.4-2.2-3.2-2.2-5.2l-0.3-19.3C193.6,144.2,196.9,140.8,201.1,140.7L201.1,140.7z"
|
||||||
|
/>
|
||||||
|
<path id="路径_12" class="st4" d="M267.7,185.8v22.4c0,4.1-3.4,7.5-7.5,7.5h-19.6c-2,0-3.9-0.8-5.3-2.2l-10.9-10.9
|
||||||
|
c-2.9-2.9-2.9-7.7,0-10.6c0,0,0,0,0,0l11.2-11.2c1.4-1.4,3.2-2.2,5.2-2.2l19.3-0.3c4.1-0.1,7.6,3.2,7.6,7.4c0,0,0,0,0,0V185.8
|
||||||
|
z"/>
|
||||||
|
<path id="路径_13" class="st4" d="M156.7,208.2v-22.4c0-4.1,3.4-7.5,7.5-7.5h19.6c2,0,3.9,0.8,5.3,2.2l10.9,10.9
|
||||||
|
c2.9,2.9,2.9,7.7,0,10.6c0,0,0,0,0,0l-11.2,11.2c-1.4,1.4-3.2,2.2-5.2,2.2l-19.3,0.3c-4.1,0.1-7.6-3.2-7.6-7.4c0,0,0,0,0,0
|
||||||
|
V208.2z"/>
|
||||||
|
<path id="路径_14" class="st4" d="M223.5,253.1h-22.4c-4.1,0-7.5-3.4-7.5-7.5V226c0-2,0.8-3.9,2.2-5.3l10.9-10.9
|
||||||
|
c2.9-2.9,7.7-2.9,10.6,0l11.2,11.2c1.4,1.4,2.2,3.2,2.2,5.2l0.3,19.3c0.1,4.1-3.2,7.5-7.4,7.6L223.5,253.1z"/>
|
||||||
|
<path id="矩形_23" class="st4" d="M581.2,107.2L581.2,107.2c6.5,0,11.7,5.2,11.7,11.7c0,0,0,0,0,0V135
|
||||||
|
c0,6.5-5.2,11.7-11.7,11.7l0,0l0,0c-6.5,0-11.7-5.2-11.7-11.7c0,0,0,0,0,0v-16.1C569.5,112.5,574.7,107.2,581.2,107.2
|
||||||
|
C581.2,107.2,581.2,107.2,581.2,107.2z"/>
|
||||||
|
<path id="路径_3404" class="st2" d="M546.2,94.8c0,0,23.6,11.6,58.7,0V83.3c5.8-2.6,13.7-5.2,27.5-6.4
|
||||||
|
c24-2.1,41.2,0.1,58,11.3v4.3c2.5,1.6,4.7,3.6,6.6,5.8c12.2,14.3,47.3,74.3,66.1,179.6c9.7,54.2,16.9,97.4,18.8,130
|
||||||
|
c4,42.2-11.4,65.9-11.4,65.9C737.6,521.7,691,511,691,511c-16.9-3.8-43.9-15-53.2-49.4c0,0-22.7-92.4-33.8-99.1
|
||||||
|
c-12.2-7.4-11.7-8.9-15.4-8s-18.8,13-37,13.5s-32.5-2.2-40-7s-12.4-11.1-14.1-11.2c-0.9,0-23.2,0-44.5,0l0,0h-19.6"/>
|
||||||
|
<circle id="椭圆_2218" class="st4" cx="434.1" cy="297.5" r="20"/>
|
||||||
|
<path id="矩形_742" class="st4" d="M295,109.9L295,109.9c6.5,0,11.7,5.2,11.7,11.7c0,0,0,0,0,0v16.1
|
||||||
|
c0,6.5-5.2,11.7-11.7,11.7l0,0l0,0c-6.5,0-11.7-5.2-11.7-11.7c0,0,0,0,0,0v-16.1C283.3,115.2,288.5,109.9,295,109.9z"/>
|
||||||
|
</g>
|
||||||
|
<g id="椭圆_2190">
|
||||||
|
<circle class="st5" cx="321.7" cy="292.4" r="47.8"/>
|
||||||
|
<circle class="st2" cx="321.7" cy="292.4" r="45.8"/>
|
||||||
|
</g>
|
||||||
|
<g id="椭圆_2209">
|
||||||
|
<circle class="st5" cx="545.6" cy="292.4" r="47.8"/>
|
||||||
|
<circle class="st2" cx="545.6" cy="292.4" r="45.8"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,30 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum KeysMapping : int {
|
||||||
|
Start_Key = 0,
|
||||||
|
Select_Key,
|
||||||
|
LAnalogDown_Key,
|
||||||
|
LAnalogLeft_Key,
|
||||||
|
LAnalogUp_Key,
|
||||||
|
LAnalogRight_Key,
|
||||||
|
PS_Key,
|
||||||
|
RAnalogDown_Key,
|
||||||
|
RAnalogLeft_Key,
|
||||||
|
RAnalogUp_Key,
|
||||||
|
RAnalogRight_Key,
|
||||||
|
DPadLeft_Key,
|
||||||
|
DPadRight_Key,
|
||||||
|
DPadUp_Key,
|
||||||
|
DPadDown_Key,
|
||||||
|
L2_Key,
|
||||||
|
L1_Key,
|
||||||
|
Cross_Key,
|
||||||
|
R2_Key,
|
||||||
|
Circle_Key,
|
||||||
|
R1_Key,
|
||||||
|
Square_Key,
|
||||||
|
Triangle_Key
|
||||||
|
};
|
|
@ -0,0 +1,16 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "input/keysmappingprovider.h"
|
||||||
|
|
||||||
|
KeysMappingProvider::KeysMappingProvider(std::map<Uint32, KeysMapping> bindingsMap)
|
||||||
|
: m_bindingsMap{bindingsMap} {}
|
||||||
|
|
||||||
|
std::optional<KeysMapping> KeysMappingProvider::mapKey(SDL_Keycode sdkKey) {
|
||||||
|
auto foundIt = m_bindingsMap.find(sdkKey);
|
||||||
|
if (foundIt != m_bindingsMap.end()) {
|
||||||
|
return foundIt->second;
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL_keycode.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "input/keys_constants.h"
|
||||||
|
|
||||||
|
class KeysMappingProvider {
|
||||||
|
public:
|
||||||
|
KeysMappingProvider(std::map<Uint32, KeysMapping> bindingsMap);
|
||||||
|
|
||||||
|
std::optional<KeysMapping> mapKey(SDL_Keycode sdkKey);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<Uint32, KeysMapping> m_bindingsMap;
|
||||||
|
};
|
|
@ -0,0 +1,524 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "./ui_keyboardcontrolswindow.h"
|
||||||
|
#include "common/config.h"
|
||||||
|
#include "keyboardcontrolswindow.h"
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
static constexpr auto keyBindingsSettingsKey = "ShadPS4_Keyboard_Settings_KEY";
|
||||||
|
static constexpr auto inputErrorTimerTimeout = 2000;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void showError(const QString& message) {
|
||||||
|
QMessageBox::critical(nullptr, "Error", message, QMessageBox::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
void showWarning(const QString& message) {
|
||||||
|
QMessageBox::warning(nullptr, "Warning", message, QMessageBox::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
void showInfo(const QString& message) {
|
||||||
|
QMessageBox::information(nullptr, "Info", message, QMessageBox::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardControlsWindow::KeyboardControlsWindow(QWidget* parent)
|
||||||
|
: QDialog(parent), ui(new Ui::KeyboardControlsWindow) {
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
m_keysMap = Config::getKeyboardBindingMap();
|
||||||
|
|
||||||
|
for (auto& pair : m_keysMap) {
|
||||||
|
m_reverseKeysMap.emplace(pair.second, pair.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_listOfKeySequenceEdits = {ui->StartKeySequenceEdit, ui->SelectKeySequenceEdit,
|
||||||
|
ui->LAnalogDownkeySequenceEdit, ui->LAnalogLeftkeySequenceEdit,
|
||||||
|
ui->LAnalogUpkeySequenceEdit, ui->LAnalogRightkeySequenceEdit,
|
||||||
|
ui->PSkeySequenceEdit, ui->RAnalogDownkeySequenceEdit,
|
||||||
|
ui->RAnalogLeftkeySequenceEdit, ui->RAnalogUpkeySequenceEdit,
|
||||||
|
ui->RAnalogRightkeySequenceEdit, ui->DPadLeftkeySequenceEdit,
|
||||||
|
ui->DPadRightkeySequenceEdit, ui->DPadUpkeySequenceEdit,
|
||||||
|
ui->DPadDownkeySequenceEdit, ui->L2keySequenceEdit,
|
||||||
|
ui->L1keySequenceEdit, ui->CrossKeySequenceEdit,
|
||||||
|
ui->R2KeySequenceEdit, ui->CircleKeySequenceEdit,
|
||||||
|
ui->R1KeySequenceEdit, ui->SquareKeySequenceEdit,
|
||||||
|
ui->TriangleKeySequenceEdit};
|
||||||
|
|
||||||
|
for (auto edit : m_listOfKeySequenceEdits) {
|
||||||
|
edit->setStyleSheet("QLineEdit { qproperty-alignment: AlignCenter; }");
|
||||||
|
QObject::connect(edit, &QKeySequenceEdit::editingFinished, this,
|
||||||
|
&KeyboardControlsWindow::onEditingFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->StartKeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::Start_Key]));
|
||||||
|
ui->SelectKeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::Select_Key]));
|
||||||
|
ui->LAnalogDownkeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::LAnalogDown_Key]));
|
||||||
|
ui->LAnalogLeftkeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::LAnalogLeft_Key]));
|
||||||
|
ui->LAnalogUpkeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::LAnalogUp_Key]));
|
||||||
|
ui->LAnalogRightkeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::LAnalogRight_Key]));
|
||||||
|
ui->PSkeySequenceEdit->setKeySequence(convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::PS_Key]));
|
||||||
|
ui->RAnalogDownkeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::RAnalogDown_Key]));
|
||||||
|
ui->RAnalogLeftkeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::RAnalogLeft_Key]));
|
||||||
|
ui->RAnalogUpkeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::RAnalogUp_Key]));
|
||||||
|
ui->RAnalogRightkeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::RAnalogRight_Key]));
|
||||||
|
ui->DPadLeftkeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::DPadLeft_Key]));
|
||||||
|
ui->DPadRightkeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::DPadRight_Key]));
|
||||||
|
ui->DPadUpkeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::DPadUp_Key]));
|
||||||
|
ui->DPadDownkeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::DPadDown_Key]));
|
||||||
|
ui->L2keySequenceEdit->setKeySequence(convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::L2_Key]));
|
||||||
|
ui->L1keySequenceEdit->setKeySequence(convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::L1_Key]));
|
||||||
|
ui->CrossKeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::Cross_Key]));
|
||||||
|
ui->R2KeySequenceEdit->setKeySequence(convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::R2_Key]));
|
||||||
|
ui->CircleKeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::Circle_Key]));
|
||||||
|
ui->R1KeySequenceEdit->setKeySequence(convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::R1_Key]));
|
||||||
|
ui->SquareKeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::Square_Key]));
|
||||||
|
ui->TriangleKeySequenceEdit->setKeySequence(
|
||||||
|
convertSDLKeyToQt(m_reverseKeysMap[KeysMapping::Triangle_Key]));
|
||||||
|
|
||||||
|
QObject::connect(ui->applyButton, &QPushButton::clicked,
|
||||||
|
[this]() { validateAndSaveKeyBindings(); });
|
||||||
|
|
||||||
|
QObject::connect(ui->cancelButton, &QPushButton::clicked, [this]() { this->close(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardControlsWindow::~KeyboardControlsWindow() {
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::map<Uint32, KeysMapping>& KeyboardControlsWindow::getKeysMapping() const {
|
||||||
|
return m_keysMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardControlsWindow::validateAndSaveKeyBindings() {
|
||||||
|
int nOfUnconfiguredButtons = 0;
|
||||||
|
for (auto& keyEdit : m_listOfKeySequenceEdits) {
|
||||||
|
auto keySequence = keyEdit->keySequence();
|
||||||
|
// If key sequence is empty (i.e. there is no key assigned to it) we highlight it in red
|
||||||
|
if (keySequence.isEmpty()) {
|
||||||
|
keyEdit->setStyleSheet("background-color: red; qproperty-alignment: AlignCenter;");
|
||||||
|
QTimer::singleShot(inputErrorTimerTimeout, keyEdit, [keyEdit]() {
|
||||||
|
keyEdit->setStyleSheet("qproperty-alignment: AlignCenter;"); // Reset to default
|
||||||
|
});
|
||||||
|
|
||||||
|
++nOfUnconfiguredButtons;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nOfUnconfiguredButtons > 0) {
|
||||||
|
showError("Some of the buttons were not configured");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_keysMap.clear();
|
||||||
|
m_reverseKeysMap.clear();
|
||||||
|
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->LAnalogDownkeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::LAnalogDown_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->LAnalogLeftkeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::LAnalogLeft_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->LAnalogUpkeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::LAnalogUp_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->LAnalogRightkeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::LAnalogRight_Key);
|
||||||
|
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->PSkeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::PS_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->StartKeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::Start_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->SelectKeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::Select_Key);
|
||||||
|
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->RAnalogDownkeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::RAnalogDown_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->RAnalogLeftkeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::RAnalogLeft_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->RAnalogUpkeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::RAnalogUp_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->RAnalogRightkeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::RAnalogRight_Key);
|
||||||
|
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->DPadLeftkeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::DPadLeft_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->DPadRightkeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::DPadRight_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->DPadUpkeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::DPadUp_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->DPadDownkeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::DPadDown_Key);
|
||||||
|
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->L1keySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::L1_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->L2keySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::L2_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->R1KeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::R1_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->R2KeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::R2_Key);
|
||||||
|
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->CrossKeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::Cross_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->CircleKeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::Circle_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->SquareKeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::Square_Key);
|
||||||
|
m_keysMap.emplace(convertQtKeyToSDL(ui->TriangleKeySequenceEdit->keySequence()[0].key()),
|
||||||
|
KeysMapping::Triangle_Key);
|
||||||
|
|
||||||
|
for (auto& pair : m_keysMap) {
|
||||||
|
m_reverseKeysMap.emplace(pair.second, pair.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Saving into settings (for permanent storage)
|
||||||
|
Config::setKeyboardBindingMap(m_keysMap);
|
||||||
|
|
||||||
|
this->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::Key KeyboardControlsWindow::convertSDLKeyToQt(SDL_Keycode sdlKey) {
|
||||||
|
switch (sdlKey) {
|
||||||
|
case SDLK_A:
|
||||||
|
return Qt::Key_A;
|
||||||
|
case SDLK_B:
|
||||||
|
return Qt::Key_B;
|
||||||
|
case SDLK_C:
|
||||||
|
return Qt::Key_C;
|
||||||
|
case SDLK_D:
|
||||||
|
return Qt::Key_D;
|
||||||
|
case SDLK_E:
|
||||||
|
return Qt::Key_E;
|
||||||
|
case SDLK_F:
|
||||||
|
return Qt::Key_F;
|
||||||
|
case SDLK_G:
|
||||||
|
return Qt::Key_G;
|
||||||
|
case SDLK_H:
|
||||||
|
return Qt::Key_H;
|
||||||
|
case SDLK_I:
|
||||||
|
return Qt::Key_I;
|
||||||
|
case SDLK_J:
|
||||||
|
return Qt::Key_J;
|
||||||
|
case SDLK_K:
|
||||||
|
return Qt::Key_K;
|
||||||
|
case SDLK_L:
|
||||||
|
return Qt::Key_L;
|
||||||
|
case SDLK_M:
|
||||||
|
return Qt::Key_M;
|
||||||
|
case SDLK_N:
|
||||||
|
return Qt::Key_N;
|
||||||
|
case SDLK_O:
|
||||||
|
return Qt::Key_O;
|
||||||
|
case SDLK_P:
|
||||||
|
return Qt::Key_P;
|
||||||
|
case SDLK_Q:
|
||||||
|
return Qt::Key_Q;
|
||||||
|
case SDLK_R:
|
||||||
|
return Qt::Key_R;
|
||||||
|
case SDLK_S:
|
||||||
|
return Qt::Key_S;
|
||||||
|
case SDLK_T:
|
||||||
|
return Qt::Key_T;
|
||||||
|
case SDLK_U:
|
||||||
|
return Qt::Key_U;
|
||||||
|
case SDLK_V:
|
||||||
|
return Qt::Key_V;
|
||||||
|
case SDLK_W:
|
||||||
|
return Qt::Key_W;
|
||||||
|
case SDLK_X:
|
||||||
|
return Qt::Key_X;
|
||||||
|
case SDLK_Y:
|
||||||
|
return Qt::Key_Y;
|
||||||
|
case SDLK_Z:
|
||||||
|
return Qt::Key_Z;
|
||||||
|
case SDLK_0:
|
||||||
|
return Qt::Key_0;
|
||||||
|
case SDLK_1:
|
||||||
|
return Qt::Key_1;
|
||||||
|
case SDLK_2:
|
||||||
|
return Qt::Key_2;
|
||||||
|
case SDLK_3:
|
||||||
|
return Qt::Key_3;
|
||||||
|
case SDLK_4:
|
||||||
|
return Qt::Key_4;
|
||||||
|
case SDLK_5:
|
||||||
|
return Qt::Key_5;
|
||||||
|
case SDLK_6:
|
||||||
|
return Qt::Key_6;
|
||||||
|
case SDLK_7:
|
||||||
|
return Qt::Key_7;
|
||||||
|
case SDLK_8:
|
||||||
|
return Qt::Key_8;
|
||||||
|
case SDLK_9:
|
||||||
|
return Qt::Key_9;
|
||||||
|
case SDLK_SPACE:
|
||||||
|
return Qt::Key_Space;
|
||||||
|
case SDLK_RETURN:
|
||||||
|
return Qt::Key_Return;
|
||||||
|
case SDLK_ESCAPE:
|
||||||
|
return Qt::Key_Escape;
|
||||||
|
case SDLK_TAB:
|
||||||
|
return Qt::Key_Tab;
|
||||||
|
case SDLK_BACKSPACE:
|
||||||
|
return Qt::Key_Backspace;
|
||||||
|
case SDLK_DELETE:
|
||||||
|
return Qt::Key_Delete;
|
||||||
|
case SDLK_INSERT:
|
||||||
|
return Qt::Key_Insert;
|
||||||
|
case SDLK_HOME:
|
||||||
|
return Qt::Key_Home;
|
||||||
|
case SDLK_END:
|
||||||
|
return Qt::Key_End;
|
||||||
|
case SDLK_PAGEUP:
|
||||||
|
return Qt::Key_PageUp;
|
||||||
|
case SDLK_PAGEDOWN:
|
||||||
|
return Qt::Key_PageDown;
|
||||||
|
case SDLK_LEFT:
|
||||||
|
return Qt::Key_Left;
|
||||||
|
case SDLK_RIGHT:
|
||||||
|
return Qt::Key_Right;
|
||||||
|
case SDLK_UP:
|
||||||
|
return Qt::Key_Up;
|
||||||
|
case SDLK_DOWN:
|
||||||
|
return Qt::Key_Down;
|
||||||
|
case SDLK_CAPSLOCK:
|
||||||
|
return Qt::Key_CapsLock;
|
||||||
|
case SDLK_NUMLOCKCLEAR:
|
||||||
|
return Qt::Key_NumLock;
|
||||||
|
case SDLK_SCROLLLOCK:
|
||||||
|
return Qt::Key_ScrollLock;
|
||||||
|
case SDLK_F1:
|
||||||
|
return Qt::Key_F1;
|
||||||
|
case SDLK_F2:
|
||||||
|
return Qt::Key_F2;
|
||||||
|
case SDLK_F3:
|
||||||
|
return Qt::Key_F3;
|
||||||
|
case SDLK_F4:
|
||||||
|
return Qt::Key_F4;
|
||||||
|
case SDLK_F5:
|
||||||
|
return Qt::Key_F5;
|
||||||
|
case SDLK_F6:
|
||||||
|
return Qt::Key_F6;
|
||||||
|
case SDLK_F7:
|
||||||
|
return Qt::Key_F7;
|
||||||
|
case SDLK_F8:
|
||||||
|
return Qt::Key_F8;
|
||||||
|
case SDLK_F9:
|
||||||
|
return Qt::Key_F9;
|
||||||
|
case SDLK_F10:
|
||||||
|
return Qt::Key_F10;
|
||||||
|
case SDLK_F11:
|
||||||
|
return Qt::Key_F11;
|
||||||
|
case SDLK_F12:
|
||||||
|
return Qt::Key_F12;
|
||||||
|
case SDLK_LSHIFT:
|
||||||
|
return Qt::Key_Shift;
|
||||||
|
case SDLK_LCTRL:
|
||||||
|
return Qt::Key_Control;
|
||||||
|
case SDLK_LALT:
|
||||||
|
return Qt::Key_Alt;
|
||||||
|
case SDLK_LGUI:
|
||||||
|
return Qt::Key_Meta;
|
||||||
|
default:
|
||||||
|
return Qt::Key_unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Keycode KeyboardControlsWindow::convertQtKeyToSDL(Qt::Key qtKey) {
|
||||||
|
switch (qtKey) {
|
||||||
|
case Qt::Key_A:
|
||||||
|
return SDLK_A;
|
||||||
|
case Qt::Key_B:
|
||||||
|
return SDLK_B;
|
||||||
|
case Qt::Key_C:
|
||||||
|
return SDLK_C;
|
||||||
|
case Qt::Key_D:
|
||||||
|
return SDLK_D;
|
||||||
|
case Qt::Key_E:
|
||||||
|
return SDLK_E;
|
||||||
|
case Qt::Key_F:
|
||||||
|
return SDLK_F;
|
||||||
|
case Qt::Key_G:
|
||||||
|
return SDLK_G;
|
||||||
|
case Qt::Key_H:
|
||||||
|
return SDLK_H;
|
||||||
|
case Qt::Key_I:
|
||||||
|
return SDLK_I;
|
||||||
|
case Qt::Key_J:
|
||||||
|
return SDLK_J;
|
||||||
|
case Qt::Key_K:
|
||||||
|
return SDLK_K;
|
||||||
|
case Qt::Key_L:
|
||||||
|
return SDLK_L;
|
||||||
|
case Qt::Key_M:
|
||||||
|
return SDLK_M;
|
||||||
|
case Qt::Key_N:
|
||||||
|
return SDLK_N;
|
||||||
|
case Qt::Key_O:
|
||||||
|
return SDLK_O;
|
||||||
|
case Qt::Key_P:
|
||||||
|
return SDLK_P;
|
||||||
|
case Qt::Key_Q:
|
||||||
|
return SDLK_Q;
|
||||||
|
case Qt::Key_R:
|
||||||
|
return SDLK_R;
|
||||||
|
case Qt::Key_S:
|
||||||
|
return SDLK_S;
|
||||||
|
case Qt::Key_T:
|
||||||
|
return SDLK_T;
|
||||||
|
case Qt::Key_U:
|
||||||
|
return SDLK_U;
|
||||||
|
case Qt::Key_V:
|
||||||
|
return SDLK_V;
|
||||||
|
case Qt::Key_W:
|
||||||
|
return SDLK_W;
|
||||||
|
case Qt::Key_X:
|
||||||
|
return SDLK_X;
|
||||||
|
case Qt::Key_Y:
|
||||||
|
return SDLK_Y;
|
||||||
|
case Qt::Key_Z:
|
||||||
|
return SDLK_Z;
|
||||||
|
case Qt::Key_0:
|
||||||
|
return SDLK_0;
|
||||||
|
case Qt::Key_1:
|
||||||
|
return SDLK_1;
|
||||||
|
case Qt::Key_2:
|
||||||
|
return SDLK_2;
|
||||||
|
case Qt::Key_3:
|
||||||
|
return SDLK_3;
|
||||||
|
case Qt::Key_4:
|
||||||
|
return SDLK_4;
|
||||||
|
case Qt::Key_5:
|
||||||
|
return SDLK_5;
|
||||||
|
case Qt::Key_6:
|
||||||
|
return SDLK_6;
|
||||||
|
case Qt::Key_7:
|
||||||
|
return SDLK_7;
|
||||||
|
case Qt::Key_8:
|
||||||
|
return SDLK_8;
|
||||||
|
case Qt::Key_9:
|
||||||
|
return SDLK_9;
|
||||||
|
case Qt::Key_Space:
|
||||||
|
return SDLK_SPACE;
|
||||||
|
case Qt::Key_Enter:
|
||||||
|
return SDLK_RETURN;
|
||||||
|
case Qt::Key_Return:
|
||||||
|
return SDLK_RETURN;
|
||||||
|
case Qt::Key_Escape:
|
||||||
|
return SDLK_ESCAPE;
|
||||||
|
case Qt::Key_Tab:
|
||||||
|
return SDLK_TAB;
|
||||||
|
case Qt::Key_Backspace:
|
||||||
|
return SDLK_BACKSPACE;
|
||||||
|
case Qt::Key_Delete:
|
||||||
|
return SDLK_DELETE;
|
||||||
|
case Qt::Key_Insert:
|
||||||
|
return SDLK_INSERT;
|
||||||
|
case Qt::Key_Home:
|
||||||
|
return SDLK_HOME;
|
||||||
|
case Qt::Key_End:
|
||||||
|
return SDLK_END;
|
||||||
|
case Qt::Key_PageUp:
|
||||||
|
return SDLK_PAGEUP;
|
||||||
|
case Qt::Key_PageDown:
|
||||||
|
return SDLK_PAGEDOWN;
|
||||||
|
case Qt::Key_Left:
|
||||||
|
return SDLK_LEFT;
|
||||||
|
case Qt::Key_Right:
|
||||||
|
return SDLK_RIGHT;
|
||||||
|
case Qt::Key_Up:
|
||||||
|
return SDLK_UP;
|
||||||
|
case Qt::Key_Down:
|
||||||
|
return SDLK_DOWN;
|
||||||
|
case Qt::Key_CapsLock:
|
||||||
|
return SDLK_CAPSLOCK;
|
||||||
|
case Qt::Key_NumLock:
|
||||||
|
return SDLK_NUMLOCKCLEAR;
|
||||||
|
case Qt::Key_ScrollLock:
|
||||||
|
return SDLK_SCROLLLOCK;
|
||||||
|
case Qt::Key_F1:
|
||||||
|
return SDLK_F1;
|
||||||
|
case Qt::Key_F2:
|
||||||
|
return SDLK_F2;
|
||||||
|
case Qt::Key_F3:
|
||||||
|
return SDLK_F3;
|
||||||
|
case Qt::Key_F4:
|
||||||
|
return SDLK_F4;
|
||||||
|
case Qt::Key_F5:
|
||||||
|
return SDLK_F5;
|
||||||
|
case Qt::Key_F6:
|
||||||
|
return SDLK_F6;
|
||||||
|
case Qt::Key_F7:
|
||||||
|
return SDLK_F7;
|
||||||
|
case Qt::Key_F8:
|
||||||
|
return SDLK_F8;
|
||||||
|
case Qt::Key_F9:
|
||||||
|
return SDLK_F9;
|
||||||
|
case Qt::Key_F10:
|
||||||
|
return SDLK_F10;
|
||||||
|
case Qt::Key_F11:
|
||||||
|
return SDLK_F11;
|
||||||
|
case Qt::Key_F12:
|
||||||
|
return SDLK_F12;
|
||||||
|
case Qt::Key_Shift:
|
||||||
|
return SDLK_LSHIFT;
|
||||||
|
case Qt::Key_Control:
|
||||||
|
return SDLK_LCTRL;
|
||||||
|
case Qt::Key_Alt:
|
||||||
|
return SDLK_LALT;
|
||||||
|
case Qt::Key_Meta:
|
||||||
|
return SDLK_LGUI;
|
||||||
|
default:
|
||||||
|
return SDLK_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardControlsWindow::onEditingFinished() {
|
||||||
|
auto sender = qobject_cast<QKeySequenceEdit*>(QObject::sender());
|
||||||
|
auto new_keySequence = sender->keySequence();
|
||||||
|
|
||||||
|
// If new key sequence is empty (i.e. there is no key assigned to it) - skip 'duplicate' checks
|
||||||
|
// Two checks are needed for the sake of robustness (when we click on a widget but don't type
|
||||||
|
// anything it might no longer be "empty")
|
||||||
|
if (new_keySequence.isEmpty() || new_keySequence.toString().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if sequance is not already used (i.e. making sure there are not duplicates)
|
||||||
|
for (auto& keyEdit : m_listOfKeySequenceEdits) {
|
||||||
|
if (keyEdit != sender && new_keySequence == keyEdit->keySequence()) {
|
||||||
|
sender->clear();
|
||||||
|
sender->setStyleSheet("background-color: red; qproperty-alignment: AlignCenter;");
|
||||||
|
QTimer::singleShot(inputErrorTimerTimeout, sender, [sender]() {
|
||||||
|
sender->setStyleSheet(
|
||||||
|
"QLineEdit { qproperty-alignment: AlignCenter; }"); // Reset to default
|
||||||
|
});
|
||||||
|
|
||||||
|
keyEdit->setStyleSheet("background-color: red; qproperty-alignment: AlignCenter;");
|
||||||
|
QTimer::singleShot(inputErrorTimerTimeout, keyEdit, [keyEdit]() {
|
||||||
|
keyEdit->setStyleSheet(
|
||||||
|
"QLineEdit { qproperty-alignment: AlignCenter; }"); // Reset to default
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QKeySequenceEdit>
|
||||||
|
#include <QMainWindow>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_keycode.h>
|
||||||
|
#include "input/keys_constants.h"
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
namespace Ui {
|
||||||
|
class KeyboardControlsWindow;
|
||||||
|
}
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class KeyboardControlsWindow : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
KeyboardControlsWindow(QWidget* parent = nullptr);
|
||||||
|
~KeyboardControlsWindow();
|
||||||
|
|
||||||
|
const std::map<Uint32, KeysMapping>& getKeysMapping() const;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onEditingFinished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void validateAndSaveKeyBindings();
|
||||||
|
SDL_Keycode convertQtKeyToSDL(Qt::Key qtKey);
|
||||||
|
Qt::Key convertSDLKeyToQt(SDL_Keycode qtKey);
|
||||||
|
|
||||||
|
Ui::KeyboardControlsWindow* ui;
|
||||||
|
QSet<QKeySequenceEdit*> m_listOfKeySequenceEdits;
|
||||||
|
std::map<Uint32, KeysMapping> m_keysMap;
|
||||||
|
std::map<KeysMapping, Uint32> m_reverseKeysMap;
|
||||||
|
};
|
|
@ -0,0 +1,427 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
-->
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>KeyboardControlsWindow</class>
|
||||||
|
<widget class="QDialog" name="KeyboardControlsWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1148</width>
|
||||||
|
<height>731</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>1148</width>
|
||||||
|
<height>731</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>1148</width>
|
||||||
|
<height>731</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Configure Keyboard Bindings</string>
|
||||||
|
</property>
|
||||||
|
<property name="modal">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget" native="true">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1151</width>
|
||||||
|
<height>722</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="bgWidget" native="true">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>170</x>
|
||||||
|
<y>50</y>
|
||||||
|
<width>870</width>
|
||||||
|
<height>522</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="autoFillBackground">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QWidget {
|
||||||
|
background-image: url(:/images/PS4_controller_scheme_final.svg);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
}</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QKeySequenceEdit" name="StartKeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>550</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="SelectKeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>260</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="LAnalogDownkeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>280</x>
|
||||||
|
<y>480</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="LAnalogLeftkeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>240</x>
|
||||||
|
<y>440</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="LAnalogUpkeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>280</x>
|
||||||
|
<y>400</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="LAnalogRightkeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>320</x>
|
||||||
|
<y>440</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="PSkeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>400</x>
|
||||||
|
<y>400</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="RAnalogDownkeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>520</x>
|
||||||
|
<y>480</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="RAnalogLeftkeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>480</x>
|
||||||
|
<y>440</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="RAnalogUpkeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>520</x>
|
||||||
|
<y>400</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="RAnalogRightkeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>560</x>
|
||||||
|
<y>440</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="DPadLeftkeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>230</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="DPadRightkeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>90</x>
|
||||||
|
<y>230</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="DPadUpkeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>50</x>
|
||||||
|
<y>190</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="DPadDownkeySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>50</x>
|
||||||
|
<y>270</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="L2keySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>90</x>
|
||||||
|
<y>40</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="L1keySequenceEdit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>90</x>
|
||||||
|
<y>110</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="CrossKeySequenceEdit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1050</x>
|
||||||
|
<y>380</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="R2KeySequenceEdit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1050</x>
|
||||||
|
<y>30</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="CircleKeySequenceEdit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1050</x>
|
||||||
|
<y>240</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="R1KeySequenceEdit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1050</x>
|
||||||
|
<y>100</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="SquareKeySequenceEdit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1050</x>
|
||||||
|
<y>310</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QKeySequenceEdit" name="TriangleKeySequenceEdit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1050</x>
|
||||||
|
<y>170</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSequenceLength">
|
||||||
|
<longLong>1</longLong>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="cancelButton">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>890</x>
|
||||||
|
<y>670</y>
|
||||||
|
<width>100</width>
|
||||||
|
<height>32</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cancel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="applyButton">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1000</x>
|
||||||
|
<y>670</y>
|
||||||
|
<width>100</width>
|
||||||
|
<height>32</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Apply</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>20</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -52,6 +52,7 @@ bool MainWindow::Init() {
|
||||||
auto end = std::chrono::steady_clock::now();
|
auto end = std::chrono::steady_clock::now();
|
||||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
||||||
statusBar.reset(new QStatusBar);
|
statusBar.reset(new QStatusBar);
|
||||||
|
m_keyboardControlsDialog.reset(new KeyboardControlsWindow());
|
||||||
this->setStatusBar(statusBar.data());
|
this->setStatusBar(statusBar.data());
|
||||||
// Update status bar
|
// Update status bar
|
||||||
int numGames = m_game_info->m_games.size();
|
int numGames = m_game_info->m_games.size();
|
||||||
|
@ -92,6 +93,10 @@ void MainWindow::AddUiWidgets() {
|
||||||
ui->toolBar->addWidget(ui->stopButton);
|
ui->toolBar->addWidget(ui->stopButton);
|
||||||
ui->toolBar->addWidget(ui->settingsButton);
|
ui->toolBar->addWidget(ui->settingsButton);
|
||||||
ui->toolBar->addWidget(ui->controllerButton);
|
ui->toolBar->addWidget(ui->controllerButton);
|
||||||
|
auto connection = QObject::connect(ui->keyboardButton, &QPushButton::clicked, this,
|
||||||
|
&MainWindow::KeyboardConfigurationButtonPressed);
|
||||||
|
|
||||||
|
ui->toolBar->addWidget(ui->keyboardButton);
|
||||||
QFrame* line = new QFrame(this);
|
QFrame* line = new QFrame(this);
|
||||||
line->setFrameShape(QFrame::StyledPanel);
|
line->setFrameShape(QFrame::StyledPanel);
|
||||||
line->setFrameShadow(QFrame::Sunken);
|
line->setFrameShadow(QFrame::Sunken);
|
||||||
|
@ -100,6 +105,10 @@ void MainWindow::AddUiWidgets() {
|
||||||
ui->toolBar->addWidget(ui->mw_searchbar);
|
ui->toolBar->addWidget(ui->mw_searchbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::KeyboardConfigurationButtonPressed() {
|
||||||
|
m_keyboardControlsDialog->show();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::CreateDockWindows() {
|
void MainWindow::CreateDockWindows() {
|
||||||
// place holder widget is needed for good health they say :)
|
// place holder widget is needed for good health they say :)
|
||||||
QWidget* phCentralWidget = new QWidget(this);
|
QWidget* phCentralWidget = new QWidget(this);
|
||||||
|
@ -650,6 +659,10 @@ void MainWindow::InstallDirectory() {
|
||||||
RefreshGameTable();
|
RefreshGameTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<Uint32, KeysMapping> MainWindow::getKeysMapping() {
|
||||||
|
return m_keyboardControlsDialog->getKeysMapping();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::SetLastUsedTheme() {
|
void MainWindow::SetLastUsedTheme() {
|
||||||
Theme lastTheme = static_cast<Theme>(Config::getMainWindowTheme());
|
Theme lastTheme = static_cast<Theme>(Config::getMainWindowTheme());
|
||||||
m_window_themes.SetWindowTheme(lastTheme, ui->mw_searchbar);
|
m_window_themes.SetWindowTheme(lastTheme, ui->mw_searchbar);
|
||||||
|
@ -725,6 +738,7 @@ void MainWindow::SetUiIcons(bool isWhite) {
|
||||||
ui->stopButton->setIcon(RecolorIcon(ui->stopButton->icon(), isWhite));
|
ui->stopButton->setIcon(RecolorIcon(ui->stopButton->icon(), isWhite));
|
||||||
ui->settingsButton->setIcon(RecolorIcon(ui->settingsButton->icon(), isWhite));
|
ui->settingsButton->setIcon(RecolorIcon(ui->settingsButton->icon(), isWhite));
|
||||||
ui->controllerButton->setIcon(RecolorIcon(ui->controllerButton->icon(), isWhite));
|
ui->controllerButton->setIcon(RecolorIcon(ui->controllerButton->icon(), isWhite));
|
||||||
|
ui->keyboardButton->setIcon(RecolorIcon(ui->keyboardButton->icon(), isWhite));
|
||||||
ui->refreshGameListAct->setIcon(RecolorIcon(ui->refreshGameListAct->icon(), isWhite));
|
ui->refreshGameListAct->setIcon(RecolorIcon(ui->refreshGameListAct->icon(), isWhite));
|
||||||
ui->menuGame_List_Mode->setIcon(RecolorIcon(ui->menuGame_List_Mode->icon(), isWhite));
|
ui->menuGame_List_Mode->setIcon(RecolorIcon(ui->menuGame_List_Mode->icon(), isWhite));
|
||||||
ui->pkgViewerAct->setIcon(RecolorIcon(ui->pkgViewerAct->icon(), isWhite));
|
ui->pkgViewerAct->setIcon(RecolorIcon(ui->pkgViewerAct->icon(), isWhite));
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "game_info.h"
|
#include "game_info.h"
|
||||||
#include "game_list_frame.h"
|
#include "game_list_frame.h"
|
||||||
#include "game_list_utils.h"
|
#include "game_list_utils.h"
|
||||||
|
#include "keyboardcontrolswindow.h"
|
||||||
#include "main_window_themes.h"
|
#include "main_window_themes.h"
|
||||||
#include "main_window_ui.h"
|
#include "main_window_ui.h"
|
||||||
#include "pkg_viewer.h"
|
#include "pkg_viewer.h"
|
||||||
|
@ -41,6 +42,8 @@ public:
|
||||||
void InstallDirectory();
|
void InstallDirectory();
|
||||||
void StartGame();
|
void StartGame();
|
||||||
|
|
||||||
|
std::map<Uint32, KeysMapping> getKeysMapping();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void ConfigureGuiFromSettings();
|
void ConfigureGuiFromSettings();
|
||||||
void SaveWindowState() const;
|
void SaveWindowState() const;
|
||||||
|
@ -48,6 +51,7 @@ private Q_SLOTS:
|
||||||
void ShowGameList();
|
void ShowGameList();
|
||||||
void RefreshGameTable();
|
void RefreshGameTable();
|
||||||
void HandleResize(QResizeEvent* event);
|
void HandleResize(QResizeEvent* event);
|
||||||
|
void KeyboardConfigurationButtonPressed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui_MainWindow* ui;
|
Ui_MainWindow* ui;
|
||||||
|
@ -82,6 +86,7 @@ private:
|
||||||
QScopedPointer<ElfViewer> m_elf_viewer;
|
QScopedPointer<ElfViewer> m_elf_viewer;
|
||||||
// Status Bar.
|
// Status Bar.
|
||||||
QScopedPointer<QStatusBar> statusBar;
|
QScopedPointer<QStatusBar> statusBar;
|
||||||
|
QScopedPointer<KeyboardControlsWindow> m_keyboardControlsDialog;
|
||||||
// Available GPU devices
|
// Available GPU devices
|
||||||
std::vector<QString> m_physical_devices;
|
std::vector<QString> m_physical_devices;
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ public:
|
||||||
QPushButton* stopButton;
|
QPushButton* stopButton;
|
||||||
QPushButton* settingsButton;
|
QPushButton* settingsButton;
|
||||||
QPushButton* controllerButton;
|
QPushButton* controllerButton;
|
||||||
|
QPushButton* keyboardButton;
|
||||||
|
|
||||||
QWidget* sizeSliderContainer;
|
QWidget* sizeSliderContainer;
|
||||||
QHBoxLayout* sizeSliderContainer_layout;
|
QHBoxLayout* sizeSliderContainer_layout;
|
||||||
|
@ -202,6 +203,10 @@ public:
|
||||||
controllerButton->setFlat(true);
|
controllerButton->setFlat(true);
|
||||||
controllerButton->setIcon(QIcon(":images/controller_icon.png"));
|
controllerButton->setIcon(QIcon(":images/controller_icon.png"));
|
||||||
controllerButton->setIconSize(QSize(40, 40));
|
controllerButton->setIconSize(QSize(40, 40));
|
||||||
|
keyboardButton = new QPushButton(centralWidget);
|
||||||
|
keyboardButton->setFlat(true);
|
||||||
|
keyboardButton->setIcon(QIcon(":images/keyboard_icon.png"));
|
||||||
|
keyboardButton->setIconSize(QSize(40, 40));
|
||||||
|
|
||||||
sizeSliderContainer = new QWidget(centralWidget);
|
sizeSliderContainer = new QWidget(centralWidget);
|
||||||
sizeSliderContainer->setObjectName("sizeSliderContainer");
|
sizeSliderContainer->setObjectName("sizeSliderContainer");
|
||||||
|
|
|
@ -108,31 +108,71 @@ void WindowSDL::waitEvent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowSDL::setKeysMappingProvider(KeysMappingProvider* provider) {
|
||||||
|
keysMappingProvider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
void WindowSDL::onResize() {
|
void WindowSDL::onResize() {
|
||||||
SDL_GetWindowSizeInPixels(window, &width, &height);
|
SDL_GetWindowSizeInPixels(window, &width, &height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowSDL::onKeyPress(const SDL_Event* event) {
|
|
||||||
using Libraries::Pad::OrbisPadButtonDataOffset;
|
using Libraries::Pad::OrbisPadButtonDataOffset;
|
||||||
|
|
||||||
#ifdef __APPLE__
|
void WindowSDL::onKeyPress(const SDL_Event* event) {
|
||||||
// Use keys that are more friendly for keyboards without a keypad.
|
|
||||||
// Once there are key binding options this won't be necessary.
|
|
||||||
constexpr SDL_Keycode CrossKey = SDLK_N;
|
|
||||||
constexpr SDL_Keycode CircleKey = SDLK_B;
|
|
||||||
constexpr SDL_Keycode SquareKey = SDLK_V;
|
|
||||||
constexpr SDL_Keycode TriangleKey = SDLK_C;
|
|
||||||
#else
|
|
||||||
constexpr SDL_Keycode CrossKey = SDLK_KP_2;
|
|
||||||
constexpr SDL_Keycode CircleKey = SDLK_KP_6;
|
|
||||||
constexpr SDL_Keycode SquareKey = SDLK_KP_4;
|
|
||||||
constexpr SDL_Keycode TriangleKey = SDLK_KP_8;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
u32 button = 0;
|
u32 button = 0;
|
||||||
Input::Axis axis = Input::Axis::AxisMax;
|
Input::Axis axis = Input::Axis::AxisMax;
|
||||||
int axisvalue = 0;
|
int axisvalue = 0;
|
||||||
int ax = 0;
|
int ax = 0;
|
||||||
|
|
||||||
|
bool keyHandlingPending = true;
|
||||||
|
if (keysMappingProvider != nullptr) {
|
||||||
|
auto ps4KeyOpt = keysMappingProvider->mapKey(event->key.key);
|
||||||
|
|
||||||
|
// No support for modifiers (yet)
|
||||||
|
if (ps4KeyOpt.has_value() && (event->key.mod == SDL_KMOD_NONE)) {
|
||||||
|
keyHandlingPending = false;
|
||||||
|
|
||||||
|
auto ps4Key = ps4KeyOpt.value();
|
||||||
|
if (ps4Key == KeysMapping::Start_Key)
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS;
|
||||||
|
if (ps4Key == KeysMapping::Triangle_Key)
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE;
|
||||||
|
if (ps4Key == KeysMapping::Circle_Key)
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE;
|
||||||
|
if (ps4Key == KeysMapping::Cross_Key)
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS;
|
||||||
|
if (ps4Key == KeysMapping::Square_Key)
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE;
|
||||||
|
if (ps4Key == KeysMapping::R1_Key)
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1;
|
||||||
|
if (ps4Key == KeysMapping::R2_Key)
|
||||||
|
handleR2Key(event, button, axis, axisvalue, ax);
|
||||||
|
if (ps4Key == KeysMapping::DPadLeft_Key)
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT;
|
||||||
|
if (ps4Key == KeysMapping::DPadRight_Key)
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT;
|
||||||
|
if (ps4Key == KeysMapping::DPadDown_Key)
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN;
|
||||||
|
if (ps4Key == KeysMapping::DPadUp_Key)
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP;
|
||||||
|
if (ps4Key == KeysMapping::LAnalogLeft_Key)
|
||||||
|
handleLAnalogLeftKey(event, button, axis, axisvalue, ax);
|
||||||
|
if (ps4Key == KeysMapping::LAnalogUp_Key)
|
||||||
|
handleLAnalogUpKey(event, button, axis, axisvalue, ax);
|
||||||
|
if (ps4Key == KeysMapping::LAnalogDown_Key)
|
||||||
|
handleLAnalogDownKey(event, button, axis, axisvalue, ax);
|
||||||
|
if (ps4Key == KeysMapping::RAnalogLeft_Key)
|
||||||
|
handleRAnalogLeftKey(event, button, axis, axisvalue, ax);
|
||||||
|
if (ps4Key == KeysMapping::RAnalogRight_Key)
|
||||||
|
handleRAnalogRightKey(event, button, axis, axisvalue, ax);
|
||||||
|
if (ps4Key == KeysMapping::RAnalogUp_Key)
|
||||||
|
handleRAnalogUpKey(event, button, axis, axisvalue, ax);
|
||||||
|
if (ps4Key == KeysMapping::RAnalogDown_Key)
|
||||||
|
handleRAnalogDownKey(event, button, axis, axisvalue, ax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyHandlingPending) {
|
||||||
switch (event->key.key) {
|
switch (event->key.key) {
|
||||||
case SDLK_UP:
|
case SDLK_UP:
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP;
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP;
|
||||||
|
@ -146,97 +186,60 @@ void WindowSDL::onKeyPress(const SDL_Event* event) {
|
||||||
case SDLK_RIGHT:
|
case SDLK_RIGHT:
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT;
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT;
|
||||||
break;
|
break;
|
||||||
case TriangleKey:
|
case Triangle_Key:
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE;
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE;
|
||||||
break;
|
break;
|
||||||
case CircleKey:
|
case Circle_Key:
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE;
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE;
|
||||||
break;
|
break;
|
||||||
case CrossKey:
|
case Cross_Key:
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS;
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS;
|
||||||
break;
|
break;
|
||||||
case SquareKey:
|
case Square_Key:
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE;
|
||||||
|
break;
|
||||||
|
case SDLK_KP_8:
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE;
|
||||||
|
break;
|
||||||
|
case SDLK_KP_6:
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE;
|
||||||
|
break;
|
||||||
|
case SDLK_KP_2:
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS;
|
||||||
|
break;
|
||||||
|
case SDLK_KP_4:
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE;
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE;
|
||||||
break;
|
break;
|
||||||
case SDLK_RETURN:
|
case SDLK_RETURN:
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS;
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS;
|
||||||
break;
|
break;
|
||||||
case SDLK_A:
|
case SDLK_A:
|
||||||
axis = Input::Axis::LeftX;
|
handleLAnalogLeftKey(event, button, axis, axisvalue, ax);
|
||||||
if (event->type == SDL_EVENT_KEY_DOWN) {
|
|
||||||
axisvalue += -127;
|
|
||||||
} else {
|
|
||||||
axisvalue = 0;
|
|
||||||
}
|
|
||||||
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
|
||||||
break;
|
break;
|
||||||
case SDLK_D:
|
case SDLK_D:
|
||||||
axis = Input::Axis::LeftX;
|
handleLAnalogRightKey(event, button, axis, axisvalue, ax);
|
||||||
if (event->type == SDL_EVENT_KEY_DOWN) {
|
|
||||||
axisvalue += 127;
|
|
||||||
} else {
|
|
||||||
axisvalue = 0;
|
|
||||||
}
|
|
||||||
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
|
||||||
break;
|
break;
|
||||||
case SDLK_W:
|
case SDLK_W:
|
||||||
axis = Input::Axis::LeftY;
|
handleLAnalogUpKey(event, button, axis, axisvalue, ax);
|
||||||
if (event->type == SDL_EVENT_KEY_DOWN) {
|
|
||||||
axisvalue += -127;
|
|
||||||
} else {
|
|
||||||
axisvalue = 0;
|
|
||||||
}
|
|
||||||
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
|
||||||
break;
|
break;
|
||||||
case SDLK_S:
|
case SDLK_S:
|
||||||
|
handleLAnalogDownKey(event, button, axis, axisvalue, ax);
|
||||||
if (event->key.mod == SDL_KMOD_LCTRL) {
|
if (event->key.mod == SDL_KMOD_LCTRL) {
|
||||||
// Trigger rdoc capture
|
// Trigger rdoc capture
|
||||||
VideoCore::TriggerCapture();
|
VideoCore::TriggerCapture();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
axis = Input::Axis::LeftY;
|
|
||||||
if (event->type == SDL_EVENT_KEY_DOWN) {
|
|
||||||
axisvalue += 127;
|
|
||||||
} else {
|
|
||||||
axisvalue = 0;
|
|
||||||
}
|
|
||||||
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
|
||||||
break;
|
break;
|
||||||
case SDLK_J:
|
case SDLK_J:
|
||||||
axis = Input::Axis::RightX;
|
handleRAnalogLeftKey(event, button, axis, axisvalue, ax);
|
||||||
if (event->type == SDL_EVENT_KEY_DOWN) {
|
|
||||||
axisvalue += -127;
|
|
||||||
} else {
|
|
||||||
axisvalue = 0;
|
|
||||||
}
|
|
||||||
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
|
||||||
break;
|
break;
|
||||||
case SDLK_L:
|
case SDLK_L:
|
||||||
axis = Input::Axis::RightX;
|
handleRAnalogRightKey(event, button, axis, axisvalue, ax);
|
||||||
if (event->type == SDL_EVENT_KEY_DOWN) {
|
|
||||||
axisvalue += 127;
|
|
||||||
} else {
|
|
||||||
axisvalue = 0;
|
|
||||||
}
|
|
||||||
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
|
||||||
break;
|
break;
|
||||||
case SDLK_I:
|
case SDLK_I:
|
||||||
axis = Input::Axis::RightY;
|
handleRAnalogUpKey(event, button, axis, axisvalue, ax);
|
||||||
if (event->type == SDL_EVENT_KEY_DOWN) {
|
|
||||||
axisvalue += -127;
|
|
||||||
} else {
|
|
||||||
axisvalue = 0;
|
|
||||||
}
|
|
||||||
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
|
||||||
break;
|
break;
|
||||||
case SDLK_K:
|
case SDLK_K:
|
||||||
axis = Input::Axis::RightY;
|
handleRAnalogDownKey(event, button, axis, axisvalue, ax);
|
||||||
if (event->type == SDL_EVENT_KEY_DOWN) {
|
|
||||||
axisvalue += 127;
|
|
||||||
} else {
|
|
||||||
axisvalue = 0;
|
|
||||||
}
|
|
||||||
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
|
||||||
break;
|
break;
|
||||||
case SDLK_X:
|
case SDLK_X:
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3;
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3;
|
||||||
|
@ -251,24 +254,10 @@ void WindowSDL::onKeyPress(const SDL_Event* event) {
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1;
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1;
|
||||||
break;
|
break;
|
||||||
case SDLK_E:
|
case SDLK_E:
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2;
|
handleL2Key(event, button, axis, axisvalue, ax);
|
||||||
axis = Input::Axis::TriggerLeft;
|
|
||||||
if (event->type == SDL_EVENT_KEY_DOWN) {
|
|
||||||
axisvalue += 255;
|
|
||||||
} else {
|
|
||||||
axisvalue = 0;
|
|
||||||
}
|
|
||||||
ax = Input::GetAxis(0, 0x80, axisvalue);
|
|
||||||
break;
|
break;
|
||||||
case SDLK_O:
|
case SDLK_O:
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2;
|
handleR2Key(event, button, axis, axisvalue, ax);
|
||||||
axis = Input::Axis::TriggerRight;
|
|
||||||
if (event->type == SDL_EVENT_KEY_DOWN) {
|
|
||||||
axisvalue += 255;
|
|
||||||
} else {
|
|
||||||
axisvalue = 0;
|
|
||||||
}
|
|
||||||
ax = Input::GetAxis(0, 0x80, axisvalue);
|
|
||||||
break;
|
break;
|
||||||
case SDLK_SPACE:
|
case SDLK_SPACE:
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD;
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD;
|
||||||
|
@ -276,6 +265,8 @@ void WindowSDL::onKeyPress(const SDL_Event* event) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (button != 0) {
|
if (button != 0) {
|
||||||
controller->CheckButton(0, button, event->type == SDL_EVENT_KEY_DOWN);
|
controller->CheckButton(0, button, event->type == SDL_EVENT_KEY_DOWN);
|
||||||
}
|
}
|
||||||
|
@ -284,71 +275,116 @@ void WindowSDL::onKeyPress(const SDL_Event* event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowSDL::onGamepadEvent(const SDL_Event* event) {
|
void WindowSDL::handleR2Key(const SDL_Event* event, u32& button, Input::Axis& axis, int& axisvalue,
|
||||||
using Libraries::Pad::OrbisPadButtonDataOffset;
|
int& ax) {
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2;
|
||||||
u32 button = 0;
|
axis = Input::Axis::TriggerRight;
|
||||||
Input::Axis axis = Input::Axis::AxisMax;
|
if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||||
switch (event->type) {
|
axisvalue += 255;
|
||||||
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
} else {
|
||||||
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
axisvalue = 0;
|
||||||
button = sdlGamepadToOrbisButton(event->gbutton.button);
|
|
||||||
if (button != 0) {
|
|
||||||
controller->CheckButton(0, button, event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
|
||||||
axis = event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFTX ? Input::Axis::LeftX
|
|
||||||
: event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFTY ? Input::Axis::LeftY
|
|
||||||
: event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHTX ? Input::Axis::RightX
|
|
||||||
: event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHTY ? Input::Axis::RightY
|
|
||||||
: event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER ? Input::Axis::TriggerLeft
|
|
||||||
: event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER ? Input::Axis::TriggerRight
|
|
||||||
: Input::Axis::AxisMax;
|
|
||||||
if (axis != Input::Axis::AxisMax) {
|
|
||||||
controller->Axis(0, axis, Input::GetAxis(-0x8000, 0x8000, event->gaxis.value));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
ax = Input::GetAxis(0, 0x80, axisvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
int WindowSDL::sdlGamepadToOrbisButton(u8 button) {
|
void WindowSDL::handleL2Key(const SDL_Event* event, u32& button, Input::Axis& axis, int& axisvalue,
|
||||||
using Libraries::Pad::OrbisPadButtonDataOffset;
|
int& ax) {
|
||||||
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2;
|
||||||
switch (button) {
|
axis = Input::Axis::TriggerLeft;
|
||||||
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
|
if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN;
|
axisvalue += 255;
|
||||||
case SDL_GAMEPAD_BUTTON_DPAD_UP:
|
} else {
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP;
|
axisvalue = 0;
|
||||||
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT;
|
|
||||||
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT;
|
|
||||||
case SDL_GAMEPAD_BUTTON_SOUTH:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS;
|
|
||||||
case SDL_GAMEPAD_BUTTON_NORTH:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE;
|
|
||||||
case SDL_GAMEPAD_BUTTON_WEST:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE;
|
|
||||||
case SDL_GAMEPAD_BUTTON_EAST:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE;
|
|
||||||
case SDL_GAMEPAD_BUTTON_START:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS;
|
|
||||||
case SDL_GAMEPAD_BUTTON_TOUCHPAD:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD;
|
|
||||||
case SDL_GAMEPAD_BUTTON_BACK:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD;
|
|
||||||
case SDL_GAMEPAD_BUTTON_LEFT_SHOULDER:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1;
|
|
||||||
case SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1;
|
|
||||||
case SDL_GAMEPAD_BUTTON_LEFT_STICK:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3;
|
|
||||||
case SDL_GAMEPAD_BUTTON_RIGHT_STICK:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
ax = Input::GetAxis(0, 0x80, axisvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSDL::handleLAnalogRightKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax) {
|
||||||
|
axis = Input::Axis::LeftX;
|
||||||
|
if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
axisvalue += 127;
|
||||||
|
} else {
|
||||||
|
axisvalue = 0;
|
||||||
|
}
|
||||||
|
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSDL::handleLAnalogLeftKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax) {
|
||||||
|
axis = Input::Axis::LeftX;
|
||||||
|
if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
axisvalue += -127;
|
||||||
|
} else {
|
||||||
|
axisvalue = 0;
|
||||||
|
}
|
||||||
|
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSDL::handleLAnalogUpKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax) {
|
||||||
|
axis = Input::Axis::LeftY;
|
||||||
|
if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
axisvalue += -127;
|
||||||
|
} else {
|
||||||
|
axisvalue = 0;
|
||||||
|
}
|
||||||
|
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSDL::handleLAnalogDownKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax) {
|
||||||
|
axis = Input::Axis::LeftY;
|
||||||
|
if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
axisvalue += 127;
|
||||||
|
} else {
|
||||||
|
axisvalue = 0;
|
||||||
|
}
|
||||||
|
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSDL::handleRAnalogRightKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax) {
|
||||||
|
axis = Input::Axis::RightX;
|
||||||
|
if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
axisvalue += 127;
|
||||||
|
} else {
|
||||||
|
axisvalue = 0;
|
||||||
|
}
|
||||||
|
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSDL::handleRAnalogLeftKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax) {
|
||||||
|
axis = Input::Axis::RightX;
|
||||||
|
if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
axisvalue += -127;
|
||||||
|
} else {
|
||||||
|
axisvalue = 0;
|
||||||
|
}
|
||||||
|
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSDL::handleRAnalogUpKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax) {
|
||||||
|
axis = Input::Axis::RightY;
|
||||||
|
if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
axisvalue += -127;
|
||||||
|
} else {
|
||||||
|
axisvalue = 0;
|
||||||
|
}
|
||||||
|
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSDL::handleRAnalogDownKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax) {
|
||||||
|
axis = Input::Axis::RightY;
|
||||||
|
if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
axisvalue += 127;
|
||||||
|
} else {
|
||||||
|
axisvalue = 0;
|
||||||
|
}
|
||||||
|
ax = Input::GetAxis(-0x80, 0x80, axisvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Frontend
|
} // namespace Frontend
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
#include "input/keysmappingprovider.h"
|
||||||
|
|
||||||
struct SDL_Window;
|
struct SDL_Window;
|
||||||
struct SDL_Gamepad;
|
struct SDL_Gamepad;
|
||||||
|
@ -12,7 +13,8 @@ union SDL_Event;
|
||||||
|
|
||||||
namespace Input {
|
namespace Input {
|
||||||
class GameController;
|
class GameController;
|
||||||
}
|
enum class Axis;
|
||||||
|
} // namespace Input
|
||||||
|
|
||||||
namespace Frontend {
|
namespace Frontend {
|
||||||
|
|
||||||
|
@ -64,6 +66,8 @@ public:
|
||||||
|
|
||||||
void waitEvent();
|
void waitEvent();
|
||||||
|
|
||||||
|
void setKeysMappingProvider(KeysMappingProvider* provider);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onResize();
|
void onResize();
|
||||||
void onKeyPress(const SDL_Event* event);
|
void onKeyPress(const SDL_Event* event);
|
||||||
|
@ -71,12 +75,34 @@ private:
|
||||||
|
|
||||||
int sdlGamepadToOrbisButton(u8 button);
|
int sdlGamepadToOrbisButton(u8 button);
|
||||||
|
|
||||||
|
void handleR2Key(const SDL_Event* event, u32& button, Input::Axis& axis, int& axisvalue,
|
||||||
|
int& ax);
|
||||||
|
void handleL2Key(const SDL_Event* event, u32& button, Input::Axis& axis, int& axisvalue,
|
||||||
|
int& ax);
|
||||||
|
void handleLAnalogRightKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax);
|
||||||
|
void handleLAnalogLeftKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax);
|
||||||
|
void handleLAnalogUpKey(const SDL_Event* event, u32& button, Input::Axis& axis, int& axisvalue,
|
||||||
|
int& ax);
|
||||||
|
void handleLAnalogDownKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax);
|
||||||
|
void handleRAnalogRightKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax);
|
||||||
|
void handleRAnalogLeftKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax);
|
||||||
|
void handleRAnalogUpKey(const SDL_Event* event, u32& button, Input::Axis& axis, int& axisvalue,
|
||||||
|
int& ax);
|
||||||
|
void handleRAnalogDownKey(const SDL_Event* event, u32& button, Input::Axis& axis,
|
||||||
|
int& axisvalue, int& ax);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
s32 width;
|
s32 width;
|
||||||
s32 height;
|
s32 height;
|
||||||
Input::GameController* controller;
|
Input::GameController* controller;
|
||||||
WindowSystemInfo window_info{};
|
WindowSystemInfo window_info{};
|
||||||
SDL_Window* window{};
|
SDL_Window* window{};
|
||||||
|
KeysMappingProvider* keysMappingProvider = nullptr;
|
||||||
bool is_shown{};
|
bool is_shown{};
|
||||||
bool is_open{true};
|
bool is_open{true};
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
<file>images/exit_icon.png</file>
|
<file>images/exit_icon.png</file>
|
||||||
<file>images/settings_icon.png</file>
|
<file>images/settings_icon.png</file>
|
||||||
<file>images/controller_icon.png</file>
|
<file>images/controller_icon.png</file>
|
||||||
|
<file>images/keyboard_icon.png</file>
|
||||||
|
<file>images/PS4_controller_scheme_final.svg</file>
|
||||||
<file>images/refresh_icon.png</file>
|
<file>images/refresh_icon.png</file>
|
||||||
<file>images/list_mode_icon.png</file>
|
<file>images/list_mode_icon.png</file>
|
||||||
<file>images/flag_jp.png</file>
|
<file>images/flag_jp.png</file>
|
||||||
|
|
Loading…
Reference in New Issue