mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-08 07:05:40 +12:00
First step towards configurable keyboard mappings (#464)
* Configurable keyboard mappings * Cleanup * Cleanup * Biggest mistake of my career * format * Fix naming convention --------- Co-authored-by: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com>
This commit is contained in:
parent
5488e9ca7c
commit
3270cfe602
9 changed files with 162 additions and 126 deletions
|
@ -201,7 +201,7 @@ set(AUDIO_SOURCE_FILES src/core/audio/dsp_core.cpp src/core/audio/null_core.cpp
|
|||
)
|
||||
set(RENDERER_SW_SOURCE_FILES src/core/renderer_sw/renderer_sw.cpp)
|
||||
|
||||
set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp
|
||||
set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp include/input_mappings.hpp
|
||||
include/cpu.hpp include/cpu_dynarmic.hpp include/memory.hpp include/renderer.hpp include/kernel/kernel.hpp
|
||||
include/dynarmic_cp15.hpp include/kernel/resource_limits.hpp include/kernel/kernel_types.hpp
|
||||
include/kernel/config_mem.hpp include/services/service_manager.hpp include/services/apt.hpp
|
||||
|
@ -439,7 +439,7 @@ if(NOT BUILD_HYDRA_CORE)
|
|||
endif()
|
||||
|
||||
set(FRONTEND_SOURCE_FILES src/panda_qt/main.cpp src/panda_qt/screen.cpp src/panda_qt/main_window.cpp src/panda_qt/about_window.cpp
|
||||
src/panda_qt/config_window.cpp src/panda_qt/zep.cpp src/panda_qt/text_editor.cpp src/panda_qt/cheats_window.cpp
|
||||
src/panda_qt/config_window.cpp src/panda_qt/zep.cpp src/panda_qt/text_editor.cpp src/panda_qt/cheats_window.cpp src/panda_qt/mappings.cpp
|
||||
)
|
||||
set(FRONTEND_HEADER_FILES include/panda_qt/screen.hpp include/panda_qt/main_window.hpp include/panda_qt/about_window.hpp
|
||||
include/panda_qt/config_window.hpp include/panda_qt/text_editor.hpp include/panda_qt/cheats_window.hpp
|
||||
|
@ -478,7 +478,7 @@ if(NOT BUILD_HYDRA_CORE)
|
|||
docs/img/rsob_icon.png docs/img/rstarstruck_icon.png
|
||||
)
|
||||
else()
|
||||
set(FRONTEND_SOURCE_FILES src/panda_sdl/main.cpp src/panda_sdl/frontend_sdl.cpp)
|
||||
set(FRONTEND_SOURCE_FILES src/panda_sdl/main.cpp src/panda_sdl/frontend_sdl.cpp src/panda_sdl/mappings.cpp)
|
||||
set(FRONTEND_HEADER_FILES "")
|
||||
endif()
|
||||
|
||||
|
|
22
include/input_mappings.hpp
Normal file
22
include/input_mappings.hpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "services/hid.hpp"
|
||||
|
||||
struct InputMappings {
|
||||
using Scancode = u32;
|
||||
using Container = std::unordered_map<Scancode, u32>;
|
||||
|
||||
u32 getMapping(Scancode scancode) const {
|
||||
auto it = container.find(scancode);
|
||||
return it != container.end() ? it->second : HID::Keys::Null;
|
||||
}
|
||||
|
||||
void setMapping(Scancode scancode, u32 key) { container[scancode] = key; }
|
||||
static InputMappings defaultKeyboardMappings();
|
||||
|
||||
private:
|
||||
Container container;
|
||||
};
|
|
@ -11,6 +11,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "emulator.hpp"
|
||||
#include "input_mappings.hpp"
|
||||
#include "panda_qt/about_window.hpp"
|
||||
#include "panda_qt/config_window.hpp"
|
||||
#include "panda_qt/cheats_window.hpp"
|
||||
|
@ -87,6 +88,7 @@ class MainWindow : public QMainWindow {
|
|||
std::mutex messageQueueMutex;
|
||||
std::vector<EmulatorMessage> messageQueue;
|
||||
|
||||
InputMappings keyboardMappings;
|
||||
ScreenWidget screen;
|
||||
AboutWindow* aboutWindow;
|
||||
ConfigWindow* configWindow;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <filesystem>
|
||||
|
||||
#include "emulator.hpp"
|
||||
#include "input_mappings.hpp"
|
||||
|
||||
class FrontendSDL {
|
||||
Emulator emu;
|
||||
|
@ -16,9 +17,12 @@ class FrontendSDL {
|
|||
FrontendSDL();
|
||||
bool loadROM(const std::filesystem::path& path);
|
||||
void run();
|
||||
u32 getMapping(InputMappings::Scancode scancode) { return keyboardMappings.getMapping(scancode); }
|
||||
|
||||
SDL_Window* window = nullptr;
|
||||
SDL_GameController* gameController = nullptr;
|
||||
InputMappings keyboardMappings;
|
||||
|
||||
int gameControllerID;
|
||||
bool programRunning = true;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
namespace HID::Keys {
|
||||
enum : u32 {
|
||||
Null = 0,
|
||||
A = 1 << 0,
|
||||
B = 1 << 1,
|
||||
Select = 1 << 2,
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
#include <fstream>
|
||||
|
||||
#include "cheats.hpp"
|
||||
#include "input_mappings.hpp"
|
||||
|
||||
MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent), screen(this) {
|
||||
MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent), keyboardMappings(InputMappings::defaultKeyboardMappings()), screen(this) {
|
||||
setWindowTitle("Alber");
|
||||
// Enable drop events for loading ROMs
|
||||
setAcceptDrops(true);
|
||||
|
@ -298,29 +299,21 @@ void MainWindow::keyPressEvent(QKeyEvent* event) {
|
|||
sendMessage(message);
|
||||
};
|
||||
|
||||
switch (event->key()) {
|
||||
case Qt::Key_L: pressKey(HID::Keys::A); break;
|
||||
case Qt::Key_K: pressKey(HID::Keys::B); break;
|
||||
case Qt::Key_O: pressKey(HID::Keys::X); break;
|
||||
case Qt::Key_I: pressKey(HID::Keys::Y); break;
|
||||
u32 key = keyboardMappings.getMapping(event->key());
|
||||
if (key != HID::Keys::Null) {
|
||||
switch (key) {
|
||||
case HID::Keys::CirclePadUp: setCirclePad(MessageType::SetCirclePadY, 0x9C); break;
|
||||
case HID::Keys::CirclePadDown: setCirclePad(MessageType::SetCirclePadY, -0x9C); break;
|
||||
case HID::Keys::CirclePadLeft: setCirclePad(MessageType::SetCirclePadX, -0x9C); break;
|
||||
case HID::Keys::CirclePadRight: setCirclePad(MessageType::SetCirclePadX, 0x9C); break;
|
||||
|
||||
case Qt::Key_Q: pressKey(HID::Keys::L); break;
|
||||
case Qt::Key_P: pressKey(HID::Keys::R); break;
|
||||
|
||||
case Qt::Key_W: setCirclePad(MessageType::SetCirclePadY, 0x9C); break;
|
||||
case Qt::Key_A: setCirclePad(MessageType::SetCirclePadX, -0x9C); break;
|
||||
case Qt::Key_S: setCirclePad(MessageType::SetCirclePadY, -0x9C); break;
|
||||
case Qt::Key_D: setCirclePad(MessageType::SetCirclePadX, 0x9C); break;
|
||||
|
||||
case Qt::Key_Right: pressKey(HID::Keys::Right); break;
|
||||
case Qt::Key_Left: pressKey(HID::Keys::Left); break;
|
||||
case Qt::Key_Up: pressKey(HID::Keys::Up); break;
|
||||
case Qt::Key_Down: pressKey(HID::Keys::Down); break;
|
||||
|
||||
case Qt::Key_Return: pressKey(HID::Keys::Start); break;
|
||||
case Qt::Key_Backspace: pressKey(HID::Keys::Select); break;
|
||||
case Qt::Key_F4: sendMessage(EmulatorMessage{.type = MessageType::TogglePause}); break;
|
||||
case Qt::Key_F5: sendMessage(EmulatorMessage{.type = MessageType::Reset}); break;
|
||||
default: pressKey(key); break;
|
||||
}
|
||||
} else {
|
||||
switch (event->key()) {
|
||||
case Qt::Key_F4: sendMessage(EmulatorMessage{.type = MessageType::TogglePause}); break;
|
||||
case Qt::Key_F5: sendMessage(EmulatorMessage{.type = MessageType::Reset}); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,28 +330,16 @@ void MainWindow::keyReleaseEvent(QKeyEvent* event) {
|
|||
sendMessage(message);
|
||||
};
|
||||
|
||||
switch (event->key()) {
|
||||
case Qt::Key_L: releaseKey(HID::Keys::A); break;
|
||||
case Qt::Key_K: releaseKey(HID::Keys::B); break;
|
||||
case Qt::Key_O: releaseKey(HID::Keys::X); break;
|
||||
case Qt::Key_I: releaseKey(HID::Keys::Y); break;
|
||||
u32 key = keyboardMappings.getMapping(event->key());
|
||||
if (key != HID::Keys::Null) {
|
||||
switch (key) {
|
||||
case HID::Keys::CirclePadUp: releaseCirclePad(MessageType::SetCirclePadY); break;
|
||||
case HID::Keys::CirclePadDown: releaseCirclePad(MessageType::SetCirclePadY); break;
|
||||
case HID::Keys::CirclePadLeft: releaseCirclePad(MessageType::SetCirclePadX); break;
|
||||
case HID::Keys::CirclePadRight: releaseCirclePad(MessageType::SetCirclePadX); break;
|
||||
|
||||
case Qt::Key_Q: releaseKey(HID::Keys::L); break;
|
||||
case Qt::Key_P: releaseKey(HID::Keys::R); break;
|
||||
|
||||
case Qt::Key_W:
|
||||
case Qt::Key_S: releaseCirclePad(MessageType::SetCirclePadY); break;
|
||||
|
||||
case Qt::Key_A:
|
||||
case Qt::Key_D: releaseCirclePad(MessageType::SetCirclePadX); break;
|
||||
|
||||
case Qt::Key_Right: releaseKey(HID::Keys::Right); break;
|
||||
case Qt::Key_Left: releaseKey(HID::Keys::Left); break;
|
||||
case Qt::Key_Up: releaseKey(HID::Keys::Up); break;
|
||||
case Qt::Key_Down: releaseKey(HID::Keys::Down); break;
|
||||
|
||||
case Qt::Key_Return: releaseKey(HID::Keys::Start); break;
|
||||
case Qt::Key_Backspace: releaseKey(HID::Keys::Select); break;
|
||||
default: releaseKey(key); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
25
src/panda_qt/mappings.cpp
Normal file
25
src/panda_qt/mappings.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "input_mappings.hpp"
|
||||
|
||||
#include <QKeyEvent>
|
||||
|
||||
InputMappings InputMappings::defaultKeyboardMappings() {
|
||||
InputMappings mappings;
|
||||
mappings.setMapping(Qt::Key_L, HID::Keys::A);
|
||||
mappings.setMapping(Qt::Key_K, HID::Keys::B);
|
||||
mappings.setMapping(Qt::Key_O, HID::Keys::X);
|
||||
mappings.setMapping(Qt::Key_I, HID::Keys::Y);
|
||||
mappings.setMapping(Qt::Key_Q, HID::Keys::L);
|
||||
mappings.setMapping(Qt::Key_P, HID::Keys::R);
|
||||
mappings.setMapping(Qt::Key_Up, HID::Keys::Up);
|
||||
mappings.setMapping(Qt::Key_Down, HID::Keys::Down);
|
||||
mappings.setMapping(Qt::Key_Right, HID::Keys::Right);
|
||||
mappings.setMapping(Qt::Key_Left, HID::Keys::Left);
|
||||
mappings.setMapping(Qt::Key_Return, HID::Keys::Start);
|
||||
mappings.setMapping(Qt::Key_Backspace, HID::Keys::Select);
|
||||
mappings.setMapping(Qt::Key_W, HID::Keys::CirclePadUp);
|
||||
mappings.setMapping(Qt::Key_S, HID::Keys::CirclePadDown);
|
||||
mappings.setMapping(Qt::Key_D, HID::Keys::CirclePadRight);
|
||||
mappings.setMapping(Qt::Key_A, HID::Keys::CirclePadLeft);
|
||||
|
||||
return mappings;
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <glad/gl.h>
|
||||
|
||||
FrontendSDL::FrontendSDL() {
|
||||
FrontendSDL::FrontendSDL() : keyboardMappings(InputMappings::defaultKeyboardMappings()) {
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) {
|
||||
Helpers::panic("Failed to initialize SDL2");
|
||||
}
|
||||
|
@ -92,95 +92,71 @@ void FrontendSDL::run() {
|
|||
programRunning = false;
|
||||
return;
|
||||
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYDOWN: {
|
||||
if (emu.romType == ROMType::None) break;
|
||||
|
||||
switch (event.key.keysym.sym) {
|
||||
case SDLK_l: hid.pressKey(Keys::A); break;
|
||||
case SDLK_k: hid.pressKey(Keys::B); break;
|
||||
case SDLK_o: hid.pressKey(Keys::X); break;
|
||||
case SDLK_i: hid.pressKey(Keys::Y); break;
|
||||
|
||||
case SDLK_q: hid.pressKey(Keys::L); break;
|
||||
case SDLK_p: hid.pressKey(Keys::R); break;
|
||||
|
||||
case SDLK_RIGHT: hid.pressKey(Keys::Right); break;
|
||||
case SDLK_LEFT: hid.pressKey(Keys::Left); break;
|
||||
case SDLK_UP: hid.pressKey(Keys::Up); break;
|
||||
case SDLK_DOWN: hid.pressKey(Keys::Down); break;
|
||||
|
||||
case SDLK_w:
|
||||
hid.setCirclepadY(0x9C);
|
||||
keyboardAnalogY = true;
|
||||
break;
|
||||
|
||||
case SDLK_a:
|
||||
hid.setCirclepadX(-0x9C);
|
||||
keyboardAnalogX = true;
|
||||
break;
|
||||
|
||||
case SDLK_s:
|
||||
hid.setCirclepadY(-0x9C);
|
||||
keyboardAnalogY = true;
|
||||
break;
|
||||
|
||||
case SDLK_d:
|
||||
hid.setCirclepadX(0x9C);
|
||||
keyboardAnalogX = true;
|
||||
break;
|
||||
|
||||
case SDLK_RETURN: hid.pressKey(Keys::Start); break;
|
||||
case SDLK_BACKSPACE: hid.pressKey(Keys::Select); break;
|
||||
|
||||
// Use the F4 button as a hot-key to pause or resume the emulator
|
||||
// We can't use the audio play/pause buttons because it's annoying
|
||||
case SDLK_F4: {
|
||||
emu.togglePause();
|
||||
break;
|
||||
u32 key = getMapping(event.key.keysym.scancode);
|
||||
if (key != HID::Keys::Null) {
|
||||
switch (key) {
|
||||
case HID::Keys::CirclePadRight:
|
||||
hid.setCirclepadX(0x9C);
|
||||
keyboardAnalogX = true;
|
||||
break;
|
||||
case HID::Keys::CirclePadLeft:
|
||||
hid.setCirclepadX(-0x9C);
|
||||
keyboardAnalogX = true;
|
||||
break;
|
||||
case HID::Keys::CirclePadUp:
|
||||
hid.setCirclepadY(0x9C);
|
||||
keyboardAnalogY = true;
|
||||
break;
|
||||
case HID::Keys::CirclePadDown:
|
||||
hid.setCirclepadY(-0x9C);
|
||||
keyboardAnalogY = true;
|
||||
break;
|
||||
default: hid.pressKey(key); break;
|
||||
}
|
||||
} else {
|
||||
switch (event.key.keysym.sym) {
|
||||
// Use the F4 button as a hot-key to pause or resume the emulator
|
||||
// We can't use the audio play/pause buttons because it's annoying
|
||||
case SDLK_F4: {
|
||||
emu.togglePause();
|
||||
break;
|
||||
}
|
||||
|
||||
// Use F5 as a reset button
|
||||
case SDLK_F5: {
|
||||
emu.reset(Emulator::ReloadOption::Reload);
|
||||
break;
|
||||
// Use F5 as a reset button
|
||||
case SDLK_F5: {
|
||||
emu.reset(Emulator::ReloadOption::Reload);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_KEYUP:
|
||||
case SDL_KEYUP: {
|
||||
if (emu.romType == ROMType::None) break;
|
||||
|
||||
switch (event.key.keysym.sym) {
|
||||
case SDLK_l: hid.releaseKey(Keys::A); break;
|
||||
case SDLK_k: hid.releaseKey(Keys::B); break;
|
||||
case SDLK_o: hid.releaseKey(Keys::X); break;
|
||||
case SDLK_i: hid.releaseKey(Keys::Y); break;
|
||||
|
||||
case SDLK_q: hid.releaseKey(Keys::L); break;
|
||||
case SDLK_p: hid.releaseKey(Keys::R); break;
|
||||
|
||||
case SDLK_RIGHT: hid.releaseKey(Keys::Right); break;
|
||||
case SDLK_LEFT: hid.releaseKey(Keys::Left); break;
|
||||
case SDLK_UP: hid.releaseKey(Keys::Up); break;
|
||||
case SDLK_DOWN: hid.releaseKey(Keys::Down); break;
|
||||
|
||||
// Err this is probably not ideal
|
||||
case SDLK_w:
|
||||
case SDLK_s:
|
||||
hid.setCirclepadY(0);
|
||||
keyboardAnalogY = false;
|
||||
break;
|
||||
|
||||
case SDLK_a:
|
||||
case SDLK_d:
|
||||
hid.setCirclepadX(0);
|
||||
keyboardAnalogX = false;
|
||||
break;
|
||||
|
||||
case SDLK_RETURN: hid.releaseKey(Keys::Start); break;
|
||||
case SDLK_BACKSPACE: hid.releaseKey(Keys::Select); break;
|
||||
u32 key = getMapping(event.key.keysym.scancode);
|
||||
if (key != HID::Keys::Null) {
|
||||
switch (key) {
|
||||
// Err this is probably not ideal
|
||||
case HID::Keys::CirclePadRight:
|
||||
case HID::Keys::CirclePadLeft:
|
||||
hid.setCirclepadX(0);
|
||||
keyboardAnalogX = false;
|
||||
break;
|
||||
case HID::Keys::CirclePadUp:
|
||||
case HID::Keys::CirclePadDown:
|
||||
hid.setCirclepadY(0);
|
||||
keyboardAnalogY = false;
|
||||
break;
|
||||
default: hid.releaseKey(key); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (emu.romType == ROMType::None) break;
|
||||
|
|
25
src/panda_sdl/mappings.cpp
Normal file
25
src/panda_sdl/mappings.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "input_mappings.hpp"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
InputMappings InputMappings::defaultKeyboardMappings() {
|
||||
InputMappings mappings;
|
||||
mappings.setMapping(SDLK_l, HID::Keys::A);
|
||||
mappings.setMapping(SDLK_k, HID::Keys::B);
|
||||
mappings.setMapping(SDLK_o, HID::Keys::X);
|
||||
mappings.setMapping(SDLK_i, HID::Keys::Y);
|
||||
mappings.setMapping(SDLK_q, HID::Keys::L);
|
||||
mappings.setMapping(SDLK_p, HID::Keys::R);
|
||||
mappings.setMapping(SDLK_UP, HID::Keys::Up);
|
||||
mappings.setMapping(SDLK_DOWN, HID::Keys::Down);
|
||||
mappings.setMapping(SDLK_RIGHT, HID::Keys::Right);
|
||||
mappings.setMapping(SDLK_LEFT, HID::Keys::Left);
|
||||
mappings.setMapping(SDLK_RETURN, HID::Keys::Start);
|
||||
mappings.setMapping(SDLK_BACKSPACE, HID::Keys::Select);
|
||||
mappings.setMapping(SDLK_w, HID::Keys::CirclePadUp);
|
||||
mappings.setMapping(SDLK_s, HID::Keys::CirclePadDown);
|
||||
mappings.setMapping(SDLK_d, HID::Keys::CirclePadRight);
|
||||
mappings.setMapping(SDLK_a, HID::Keys::CirclePadLeft);
|
||||
|
||||
return mappings;
|
||||
}
|
Loading…
Add table
Reference in a new issue