WIP: - Initial gamepad support.
- Initial keyboard mapping support using config.toml
This commit is contained in:
parent
7ad44317f8
commit
cc943db117
|
@ -466,6 +466,11 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
|
|||
|
||||
set(INPUT src/input/controller.cpp
|
||||
src/input/controller.h
|
||||
src/input/gamepad.cpp
|
||||
src/input/gamepad.h
|
||||
src/input/keyboard.cpp
|
||||
src/input/keyboard.h
|
||||
src/input/input_manager.h
|
||||
)
|
||||
|
||||
set(EMULATOR src/emulator.cpp
|
||||
|
|
|
@ -42,6 +42,33 @@ std::vector<std::string> m_pkg_viewer;
|
|||
std::vector<std::string> m_elf_viewer;
|
||||
std::vector<std::string> m_recent_files;
|
||||
|
||||
// Keyboard
|
||||
static std::string Up = "UP";
|
||||
static std::string Down = "DOWN";
|
||||
static std::string Left = "LEFT";
|
||||
static std::string Right = "RIGHT";
|
||||
static std::string Cross = "S";
|
||||
static std::string Triangle = "W";
|
||||
static std::string Square = "D";
|
||||
static std::string Circle = "A";
|
||||
static std::string L1 = "Q";
|
||||
static std::string R1 = "E";
|
||||
static std::string L2 = "R";
|
||||
static std::string R2 = "F";
|
||||
static std::string L3 = "LCTRL";
|
||||
static std::string R3 = "LSHIFT";
|
||||
static std::string Options = "1";
|
||||
static std::string LStickUp = "I";
|
||||
static std::string LStickDown = "K";
|
||||
static std::string LStickLeft = "J";
|
||||
static std::string LStickRight = "L";
|
||||
static std::string RStickUp = "V";
|
||||
static std::string RStickDown = "B";
|
||||
static std::string RStickLeft = "N";
|
||||
static std::string RStickRight = "M";
|
||||
std::unordered_map<std::string, std::string> keyMappings;
|
||||
static u32 controller = 0;
|
||||
|
||||
bool isLleLibc() {
|
||||
return isLibc;
|
||||
}
|
||||
|
@ -102,6 +129,18 @@ bool vkValidationSyncEnabled() {
|
|||
return vkValidationSync;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> getKeyMap() {
|
||||
return keyMappings;
|
||||
}
|
||||
|
||||
void setControllerType(u32 type) {
|
||||
controller = type;
|
||||
}
|
||||
|
||||
u32 getControllerType() {
|
||||
return controller;
|
||||
}
|
||||
|
||||
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
|
||||
main_window_geometry_x = x;
|
||||
main_window_geometry_y = y;
|
||||
|
@ -224,6 +263,7 @@ void load(const std::filesystem::path& path) {
|
|||
logFilter = toml::find_or<toml::string>(general, "logFilter", "");
|
||||
logType = toml::find_or<toml::string>(general, "logType", "sync");
|
||||
isShowSplash = toml::find_or<toml::boolean>(general, "showSplash", true);
|
||||
controller = toml::find_or<toml::integer>(general, "controller", 0);
|
||||
}
|
||||
}
|
||||
if (data.contains("GPU")) {
|
||||
|
@ -287,6 +327,35 @@ void load(const std::filesystem::path& path) {
|
|||
m_table_mode = toml::find_or<toml::integer>(gui, "gameTableMode", 0);
|
||||
}
|
||||
}
|
||||
if (data.contains("Controller")) {
|
||||
auto generalResult = toml::expect<toml::value>(data.at("Controller"));
|
||||
if (generalResult.is_ok()) {
|
||||
auto general = generalResult.unwrap();
|
||||
keyMappings["Up"] = (toml::find_or<toml::string>(general, "Up", ""));
|
||||
keyMappings["Down"] = (toml::find_or<toml::string>(general, "Down", ""));
|
||||
keyMappings["Left"] = toml::find_or<toml::string>(general, "Left", "");
|
||||
keyMappings["Right"] = toml::find_or<toml::string>(general, "Right", "");
|
||||
keyMappings["Cross"] = toml::find_or<toml::string>(general, "Cross", "");
|
||||
keyMappings["Triangle"] = toml::find_or<toml::string>(general, "Triangle", "");
|
||||
keyMappings["Square"] = toml::find_or<toml::string>(general, "Square", "");
|
||||
keyMappings["Circle"] = toml::find_or<toml::string>(general, "Circle", "");
|
||||
keyMappings["L1"] = toml::find_or<toml::string>(general, "L1", "");
|
||||
keyMappings["R1"] = toml::find_or<toml::string>(general, "R1", "");
|
||||
keyMappings["L2"] = toml::find_or<toml::string>(general, "L2", "");
|
||||
keyMappings["R2"] = toml::find_or<toml::string>(general, "R2", "");
|
||||
keyMappings["L3"] = toml::find_or<toml::string>(general, "L3", "");
|
||||
keyMappings["R3"] = toml::find_or<toml::string>(general, "R3", "");
|
||||
keyMappings["Options"] = toml::find_or<toml::string>(general, "Options", "");
|
||||
keyMappings["LStickUp"] = toml::find_or<toml::string>(general, "LStickUp", "");
|
||||
keyMappings["LStickDown"] = toml::find_or<toml::string>(general, "LStickDown", "");
|
||||
keyMappings["LStickLeft"] = toml::find_or<toml::string>(general, "LStickLeft", "");
|
||||
keyMappings["LStickRight"] = toml::find_or<toml::string>(general, "LStickRight", "");
|
||||
keyMappings["RStickUp"] = toml::find_or<toml::string>(general, "RStickUp", "");
|
||||
keyMappings["RStickDown"] = toml::find_or<toml::string>(general, "RStickDown", "");
|
||||
keyMappings["RStickLeft"] = toml::find_or<toml::string>(general, "RStickLeft", "");
|
||||
keyMappings["RStickRight"] = toml::find_or<toml::string>(general, "RStickRight", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
void save(const std::filesystem::path& path) {
|
||||
toml::basic_value<toml::preserve_comments> data;
|
||||
|
@ -338,6 +407,29 @@ void save(const std::filesystem::path& path) {
|
|||
data["GUI"]["pkgDirs"] = m_pkg_viewer;
|
||||
data["GUI"]["elfDirs"] = m_elf_viewer;
|
||||
data["GUI"]["recentFiles"] = m_recent_files;
|
||||
data["Controller"]["Up"] = Up;
|
||||
data["Controller"]["Down"] = Down;
|
||||
data["Controller"]["Left"] = Left;
|
||||
data["Controller"]["Right"] = Right;
|
||||
data["Controller"]["Cross"] = Cross;
|
||||
data["Controller"]["Triangle"] = Triangle;
|
||||
data["Controller"]["Square"] = Square;
|
||||
data["Controller"]["Circle"] = Circle;
|
||||
data["Controller"]["L1"] = L1;
|
||||
data["Controller"]["R1"] = R1;
|
||||
data["Controller"]["L2"] = L2;
|
||||
data["Controller"]["R2"] = R2;
|
||||
data["Controller"]["L3"] = L3;
|
||||
data["Controller"]["R3"] = R3;
|
||||
data["Controller"]["Options"] = Options;
|
||||
data["Controller"]["LStickUp"] = LStickUp;
|
||||
data["Controller"]["LStickDown"] = LStickDown;
|
||||
data["Controller"]["LStickLeft"] = LStickLeft;
|
||||
data["Controller"]["LStickRight"] = LStickRight;
|
||||
data["Controller"]["RStickUp"] = RStickUp;
|
||||
data["Controller"]["RStickDown"] = RStickDown;
|
||||
data["Controller"]["RStickLeft"] = RStickLeft;
|
||||
data["Controller"]["RStickRight"] = RStickRight;
|
||||
|
||||
std::ofstream file(path, std::ios::out);
|
||||
file << data;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "types.h"
|
||||
|
||||
|
@ -30,6 +31,11 @@ bool dumpPM4();
|
|||
bool vkValidationEnabled();
|
||||
bool vkValidationSyncEnabled();
|
||||
|
||||
// Controllers
|
||||
std::unordered_map<std::string, std::string> getKeyMap();
|
||||
void setControllerType(u32 type);
|
||||
u32 getControllerType();
|
||||
|
||||
// Gui
|
||||
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
|
||||
void setGameInstallDir(const std::string& dir);
|
||||
|
|
|
@ -5,11 +5,17 @@
|
|||
#include <common/singleton.h>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/time_management.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "input/controller.h"
|
||||
#include "input/gamepad.h"
|
||||
#include "input/input_manager.h"
|
||||
#include "input/keyboard.h"
|
||||
#include "pad.h"
|
||||
|
||||
namespace Libraries::Pad {
|
||||
std::unique_ptr<InputManager> controller;
|
||||
OrbisPadData oldData;
|
||||
|
||||
int PS4_SYSV_ABI scePadClose(s32 handle) {
|
||||
LOG_ERROR(Lib_Pad, "(STUBBED) called");
|
||||
|
@ -174,6 +180,13 @@ int PS4_SYSV_ABI scePadGetVersionInfo() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI scePadInit() {
|
||||
bool is_keyboard = (Config::getControllerType() == 0);
|
||||
if (is_keyboard) {
|
||||
controller = std::unique_ptr<InputManager>(Common::Singleton<Keyboard>::Instance());
|
||||
} else {
|
||||
controller = std::unique_ptr<InputManager>(Common::Singleton<Gamepad>::Instance());
|
||||
}
|
||||
controller->Init();
|
||||
LOG_ERROR(Lib_Pad, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -239,25 +252,18 @@ int PS4_SYSV_ABI scePadOutputReport() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
|
||||
//LOG_ERROR(Lib_Pad, "(STUBBED) called");
|
||||
// Temporary implementation. will be fixed and accurate later.
|
||||
std::memset(pData, 0, sizeof(OrbisPadData));
|
||||
int connected_count = 0;
|
||||
bool connected = false;
|
||||
Input::State states[64];
|
||||
auto* controller = Common::Singleton<Input::GameController>::Instance();
|
||||
int ret_num = controller->ReadStates(states, num, &connected, &connected_count);
|
||||
|
||||
if (!connected) {
|
||||
ret_num = 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ret_num; i++) {
|
||||
pData[i].buttons = states[i].buttonsState;
|
||||
pData[i].leftStick.x = states[i].axes[static_cast<int>(Input::Axis::LeftX)];
|
||||
pData[i].leftStick.y = states[i].axes[static_cast<int>(Input::Axis::LeftY)];
|
||||
pData[i].rightStick.x = states[i].axes[static_cast<int>(Input::Axis::RightX)];
|
||||
pData[i].rightStick.y = states[i].axes[static_cast<int>(Input::Axis::RightY)];
|
||||
pData[i].analogButtons.l2 = states[i].axes[static_cast<int>(Input::Axis::TriggerLeft)];
|
||||
pData[i].analogButtons.r2 = states[i].axes[static_cast<int>(Input::Axis::TriggerRight)];
|
||||
InputState state;
|
||||
for (int i = 0; i < num; i++) {
|
||||
pData[i].buttons = controller->getButtonState(&state);
|
||||
pData[i].leftStick.x = state.lx;
|
||||
pData[i].leftStick.y = state.ly;
|
||||
pData[i].rightStick.x = state.rx;
|
||||
pData[i].rightStick.y = state.ry;
|
||||
pData[i].analogButtons.l2 = state.lt;
|
||||
pData[i].analogButtons.r2 = state.rt;
|
||||
pData[i].orientation.x = 0.0f;
|
||||
pData[i].orientation.y = 0.0f;
|
||||
pData[i].orientation.z = 0.0f;
|
||||
|
@ -275,12 +281,22 @@ int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
|
|||
pData[i].touchData.touch[1].x = 0;
|
||||
pData[i].touchData.touch[1].y = 0;
|
||||
pData[i].touchData.touch[1].id = 2;
|
||||
pData[i].connected = connected;
|
||||
pData[i].timestamp = states[i].time;
|
||||
pData[i].connectedCount = connected_count;
|
||||
pData[i].connected = true;
|
||||
pData[i].timestamp = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
pData[i].connectedCount = 1;
|
||||
pData[i].deviceUniqueDataLen = 0;
|
||||
}
|
||||
// temp ugly return. will be fixed.
|
||||
int ret_num = 0;
|
||||
const u8* d1 = reinterpret_cast<u8*>(&pData[0]);
|
||||
const u8* d2 = reinterpret_cast<u8*>(&oldData);
|
||||
|
||||
for (int j = 0; j < sizeof(OrbisPadData); j++) {
|
||||
if (d1[j] != d2[j]) {
|
||||
ret_num++;
|
||||
}
|
||||
}
|
||||
oldData = pData[0];
|
||||
return ret_num;
|
||||
}
|
||||
|
||||
|
@ -305,24 +321,20 @@ int PS4_SYSV_ABI scePadReadHistory() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
||||
auto* controller = Common::Singleton<Input::GameController>::Instance();
|
||||
|
||||
int connectedCount = 0;
|
||||
bool isConnected = false;
|
||||
Input::State state;
|
||||
LOG_ERROR(Lib_Pad, "(STUBBED) called");
|
||||
std::memset(pData, 0, sizeof(OrbisPadData));
|
||||
controller->ReadState(&state, &isConnected, &connectedCount);
|
||||
pData->buttons = state.buttonsState;
|
||||
pData->leftStick.x = state.axes[static_cast<int>(Input::Axis::LeftX)];
|
||||
pData->leftStick.y = state.axes[static_cast<int>(Input::Axis::LeftY)];
|
||||
pData->rightStick.x = state.axes[static_cast<int>(Input::Axis::RightX)];
|
||||
pData->rightStick.y = state.axes[static_cast<int>(Input::Axis::RightY)];
|
||||
pData->analogButtons.l2 = state.axes[static_cast<int>(Input::Axis::TriggerLeft)];
|
||||
pData->analogButtons.r2 = state.axes[static_cast<int>(Input::Axis::TriggerRight)];
|
||||
pData->orientation.x = 0;
|
||||
pData->orientation.y = 0;
|
||||
pData->orientation.z = 0;
|
||||
pData->orientation.w = 0;
|
||||
InputState state;
|
||||
pData->buttons = controller->getButtonState(&state);
|
||||
pData->leftStick.x = state.lx;
|
||||
pData->leftStick.y = state.ly;
|
||||
pData->rightStick.x = state.rx;
|
||||
pData->rightStick.y = state.ry;
|
||||
pData->analogButtons.l2 = state.lt;
|
||||
pData->analogButtons.r2 = state.rt;
|
||||
pData->orientation.x = 0.0f;
|
||||
pData->orientation.y = 0.0f;
|
||||
pData->orientation.z = 0.0f;
|
||||
pData->orientation.w = 1.0f;
|
||||
pData->acceleration.x = 0.0f;
|
||||
pData->acceleration.y = 0.0f;
|
||||
pData->acceleration.z = 0.0f;
|
||||
|
@ -336,9 +348,9 @@ int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
|||
pData->touchData.touch[1].x = 0;
|
||||
pData->touchData.touch[1].y = 0;
|
||||
pData->touchData.touch[1].id = 2;
|
||||
pData->timestamp = state.time;
|
||||
pData->connected = true; // isConnected; //TODO fix me proper
|
||||
pData->connectedCount = 1; // connectedCount;
|
||||
pData->connected = true;
|
||||
pData->timestamp = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
pData->connectedCount = 1;
|
||||
pData->deviceUniqueDataLen = 0;
|
||||
|
||||
return SCE_OK;
|
||||
|
@ -470,8 +482,14 @@ int PS4_SYSV_ABI scePadSetUserColor() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI scePadSetVibration(s32 handle, const OrbisPadVibrationParam* pParam) {
|
||||
LOG_ERROR(Lib_Pad, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int result = 0x80920001;
|
||||
if (pParam != nullptr) {
|
||||
LOG_INFO(Lib_Pad, "scePadSetVibration called handle = {}", handle);
|
||||
u16 smallFreq = (u16)(((float)pParam->smallMotor / 255.0f) * 65535.0f);
|
||||
u16 bigFreq = (u16)(((float)pParam->largeMotor / 255.0f) * 65535.0f);
|
||||
result = (Config::getControllerType() == 1) ? controller->GetRumble(smallFreq, bigFreq) : 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePadSetVibrationForce() {
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <input/gamepad.h>
|
||||
|
||||
Gamepad::Gamepad() {}
|
||||
|
||||
void Gamepad::Init() {
|
||||
int count;
|
||||
SDL_JoystickID* joysticks = SDL_GetJoysticks(&count);
|
||||
SDL_JoystickID instance_id = joysticks[0];
|
||||
gamepad = SDL_OpenGamepad(instance_id);
|
||||
}
|
||||
|
||||
int Gamepad::GetRumble(u16 smallFreq, u16 bigFreq) {
|
||||
return gamepad ? SDL_RumbleGamepad(gamepad, smallFreq, bigFreq, -1) : 0;
|
||||
}
|
||||
|
||||
u32 Gamepad::getButtonState(InputState* state) {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
u32 buttons = 0;
|
||||
if (gamepad) {
|
||||
buttons |= SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_LEFT_STICK)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3)
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_RIGHT_STICK)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3)
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_START)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS)
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_UP)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP)
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_RIGHT)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT)
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_DOWN)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN)
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_LEFT)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT)
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1)
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2)
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1)
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2)
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_NORTH)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE)
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_EAST)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE)
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_SOUTH)
|
||||
? Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS
|
||||
: 0;
|
||||
buttons |= SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_WEST)
|
||||
? (Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE)
|
||||
: 0;
|
||||
}
|
||||
u16 deadzone = 0; // leave as 0 for now.
|
||||
s16 leftx = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX);
|
||||
s16 lefty = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY);
|
||||
s16 rightx = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX);
|
||||
s16 righty = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY);
|
||||
s16 triggerL = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER);
|
||||
s16 triggerR = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER);
|
||||
|
||||
state->lx = static_cast<u8>((((std::abs(leftx) > deadzone) ? leftx : 128) + 32768) / 257);
|
||||
state->ly = static_cast<u8>((((std::abs(lefty) > deadzone) ? lefty : 128) + 32768) / 257);
|
||||
state->rx = static_cast<u8>((((std::abs(rightx) > deadzone) ? rightx : 128) + 32768) / 257);
|
||||
state->ry = static_cast<u8>((((std::abs(righty) > deadzone) ? righty : 128) + 32768) / 257);
|
||||
state->lt = static_cast<u8>((triggerL + 32768) / 65535) * 255;
|
||||
state->rt = static_cast<u8>((triggerR + 32768) / 65535) * 255;
|
||||
return buttons;
|
||||
}
|
||||
|
||||
// use this later. maybe.
|
||||
void Gamepad::getAxis(InputState* state) {
|
||||
u16 deadzone = 2500; // Tested with my pdp Xbox One Controller. maybe this should be an option.
|
||||
s16 leftx = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX);
|
||||
s16 lefty = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY);
|
||||
s16 rightx = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX);
|
||||
s16 righty = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY);
|
||||
s16 triggerL = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER);
|
||||
s16 triggerR = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER);
|
||||
|
||||
state->lx = static_cast<u8>((((std::abs(leftx) > deadzone) ? leftx : 128) + 32768) / 257);
|
||||
state->ly = static_cast<u8>((((std::abs(lefty) > deadzone) ? lefty : 128) + 32768) / 257);
|
||||
state->rx = static_cast<u8>((((std::abs(rightx) > deadzone) ? rightx : 128) + 32768) / 257);
|
||||
state->ry = static_cast<u8>((((std::abs(righty) > deadzone) ? righty : 128) + 32768) / 257);
|
||||
state->lt = static_cast<u8>((triggerL + 32768) / 65535) * 255;
|
||||
state->rt = static_cast<u8>((triggerR + 32768) / 65535) * 255;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <SDL3/SDL_events.h>
|
||||
#include <SDL3/SDL_init.h>
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/io_file.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/path_util.h"
|
||||
#include "core/libraries/pad/pad.h"
|
||||
#include "input_manager.h"
|
||||
|
||||
class Gamepad : public InputManager {
|
||||
public:
|
||||
Gamepad();
|
||||
virtual ~Gamepad() = default;
|
||||
|
||||
virtual void Init() override;
|
||||
virtual u32 getButtonState(InputState* state) override;
|
||||
virtual void getAxis(InputState* state) override;
|
||||
virtual int GetRumble(u16 smallFreq, u16 bigFreq) override;
|
||||
|
||||
private:
|
||||
SDL_Gamepad* gamepad;
|
||||
std::mutex m_mutex;
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SDL3/SDL.h>
|
||||
#include "common/types.h"
|
||||
|
||||
struct InputState {
|
||||
u8 lx = 128, ly = 128, rx = 128, ry = 128, lt = 0, rt = 0;
|
||||
};
|
||||
|
||||
class InputManager {
|
||||
public:
|
||||
virtual ~InputManager() = default;
|
||||
|
||||
virtual u32 getButtonState(InputState* state) = 0;
|
||||
virtual void getAxis(InputState* state) = 0;
|
||||
virtual void Init() = 0;
|
||||
virtual int GetRumble(u16 smallFreq, u16 bigFreq) = 0;
|
||||
};
|
|
@ -0,0 +1,188 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <SDL3/SDL_events.h>
|
||||
#include <SDL3/SDL_init.h>
|
||||
#include <input/keyboard.h>
|
||||
|
||||
SDL_Keycode GetKeyFromString(const std::string& keyString) {
|
||||
const std::unordered_map<std::string, SDL_Scancode> keyMap = {
|
||||
{"0", SDL_SCANCODE_0},
|
||||
{"1", SDL_SCANCODE_1},
|
||||
{"2", SDL_SCANCODE_2},
|
||||
{"3", SDL_SCANCODE_3},
|
||||
{"4", SDL_SCANCODE_4},
|
||||
{"5", SDL_SCANCODE_5},
|
||||
{"6", SDL_SCANCODE_6},
|
||||
{"7", SDL_SCANCODE_7},
|
||||
{"8", SDL_SCANCODE_8},
|
||||
{"9", SDL_SCANCODE_9},
|
||||
{"KP_0", SDL_SCANCODE_KP_0},
|
||||
{"KP_1", SDL_SCANCODE_KP_1},
|
||||
{"KP_2", SDL_SCANCODE_KP_2},
|
||||
{"KP_3", SDL_SCANCODE_KP_3},
|
||||
{"KP_4", SDL_SCANCODE_KP_4},
|
||||
{"KP_5", SDL_SCANCODE_KP_5},
|
||||
{"KP_6", SDL_SCANCODE_KP_6},
|
||||
{"KP_7", SDL_SCANCODE_KP_7},
|
||||
{"KP_8", SDL_SCANCODE_KP_8},
|
||||
{"KP_9", SDL_SCANCODE_KP_9},
|
||||
{"A", SDL_SCANCODE_A},
|
||||
{"B", SDL_SCANCODE_B},
|
||||
{"C", SDL_SCANCODE_C},
|
||||
{"D", SDL_SCANCODE_D},
|
||||
{"E", SDL_SCANCODE_E},
|
||||
{"F", SDL_SCANCODE_F},
|
||||
{"G", SDL_SCANCODE_G},
|
||||
{"H", SDL_SCANCODE_H},
|
||||
{"I", SDL_SCANCODE_I},
|
||||
{"J", SDL_SCANCODE_J},
|
||||
{"K", SDL_SCANCODE_K},
|
||||
{"L", SDL_SCANCODE_L},
|
||||
{"M", SDL_SCANCODE_M},
|
||||
{"N", SDL_SCANCODE_N},
|
||||
{"O", SDL_SCANCODE_O},
|
||||
{"P", SDL_SCANCODE_P},
|
||||
{"Q", SDL_SCANCODE_Q},
|
||||
{"R", SDL_SCANCODE_R},
|
||||
{"S", SDL_SCANCODE_S},
|
||||
{"T", SDL_SCANCODE_T},
|
||||
{"U", SDL_SCANCODE_U},
|
||||
{"V", SDL_SCANCODE_V},
|
||||
{"W", SDL_SCANCODE_W},
|
||||
{"X", SDL_SCANCODE_X},
|
||||
{"Y", SDL_SCANCODE_Y},
|
||||
{"Z", SDL_SCANCODE_Z},
|
||||
{"Left Ctrl", SDL_SCANCODE_LCTRL},
|
||||
{"Left Shift", SDL_SCANCODE_LSHIFT},
|
||||
{"Right Ctrl", SDL_SCANCODE_RCTRL},
|
||||
{"Right Shift", SDL_SCANCODE_RSHIFT},
|
||||
{"Up", SDL_SCANCODE_UP},
|
||||
{"Down", SDL_SCANCODE_DOWN},
|
||||
{"Left", SDL_SCANCODE_LEFT},
|
||||
{"Right", SDL_SCANCODE_RIGHT},
|
||||
};
|
||||
|
||||
auto it = keyMap.find(keyString);
|
||||
if (it != keyMap.end()) {
|
||||
return SDL_GetKeyFromScancode(it->second, SDL_KMOD_NONE);
|
||||
} else {
|
||||
return SDL_GetKeyFromName(keyString.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Keyboard::initializeSdlKeyMappings(
|
||||
const std::unordered_map<std::string, std::string>& mappings,
|
||||
std::unordered_map<std::string, SDL_Keycode>& keyMappings) {
|
||||
const std::array<std::string, 23> actions = {
|
||||
"Up", "Down", "Left", "Right", "Cross", "Square",
|
||||
"Triangle", "Circle", "L1", "R1", "L2", "R2",
|
||||
"L3", "R3", "Options", "LStickUp", "LStickDown", "LStickLeft",
|
||||
"LStickRight", "RStickUp", "RStickDown", "RStickLeft", "RStickRight"};
|
||||
|
||||
for (const auto& action : actions) {
|
||||
auto it = mappings.find(action);
|
||||
if (it != mappings.end()) {
|
||||
keyMappings[action] = GetKeyFromString(it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Keyboard::Init() {
|
||||
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||
Config::load(config_dir / "config.toml");
|
||||
config_key_map = Config::getKeyMap();
|
||||
initializeSdlKeyMappings(config_key_map, sdl_key_map);
|
||||
}
|
||||
|
||||
Keyboard::Keyboard() {}
|
||||
|
||||
u32 Keyboard::getButtonState(InputState* state) {
|
||||
const Uint8* keystate = SDL_GetKeyboardState(NULL);
|
||||
u32 buttons = 0;
|
||||
u8 lx = 128, ly = 128, rx = 128, ry = 128;
|
||||
|
||||
if (keystate) {
|
||||
for (const auto& key : sdl_key_map) {
|
||||
if (keystate[SDL_GetScancodeFromKey(key.second, SDL_KMOD_NONE)]) {
|
||||
if (key.first == "Up")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP;
|
||||
else if (key.first == "Right")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT;
|
||||
else if (key.first == "Down")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN;
|
||||
else if (key.first == "Left")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT;
|
||||
else if (key.first == "Cross") {
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS;
|
||||
} else if (key.first == "Square")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE;
|
||||
else if (key.first == "Triangle")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE;
|
||||
else if (key.first == "Circle")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE;
|
||||
else if (key.first == "L1")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1;
|
||||
else if (key.first == "R1")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1;
|
||||
else if (key.first == "L2")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2;
|
||||
else if (key.first == "R2")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2;
|
||||
else if (key.first == "L3")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3;
|
||||
else if (key.first == "R3")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3;
|
||||
else if (key.first == "Options")
|
||||
buttons |= Libraries::Pad::OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS;
|
||||
else if (key.first == "LStickUp")
|
||||
state->ly = 0;
|
||||
else if (key.first == "LStickDown")
|
||||
state->ly = 255;
|
||||
else if (key.first == "LStickLeft")
|
||||
state->lx = 0;
|
||||
else if (key.first == "LStickRight")
|
||||
state->lx = 255;
|
||||
else if (key.first == "RStickUp")
|
||||
state->ry = 0;
|
||||
else if (key.first == "RStickDown")
|
||||
state->ry = 255;
|
||||
else if (key.first == "RStickLeft")
|
||||
state->rx = 0;
|
||||
else if (key.first == "RStickRight")
|
||||
state->rx = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
return buttons;
|
||||
}
|
||||
|
||||
void Keyboard::getAxis(InputState* state) {
|
||||
const Uint8* keystate = SDL_GetKeyboardState(NULL);
|
||||
if (keystate) {
|
||||
for (const auto& key : sdl_key_map) {
|
||||
if (keystate[SDL_GetScancodeFromKey(key.second, SDL_KMOD_NONE)]) {
|
||||
if (key.first == "LStickUp")
|
||||
state->ly = 0;
|
||||
else if (key.first == "LStickDown")
|
||||
state->ly = 255;
|
||||
else if (key.first == "LStickLeft")
|
||||
state->lx = 0;
|
||||
else if (key.first == "LStickRight")
|
||||
state->lx = 255;
|
||||
else if (key.first == "RStickUp")
|
||||
state->ry = 0;
|
||||
else if (key.first == "RStickDown")
|
||||
state->ry = 255;
|
||||
else if (key.first == "RStickLeft")
|
||||
state->rx = 0;
|
||||
else if (key.first == "RStickRight")
|
||||
state->rx = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Keyboard::GetRumble(u16 smallFreq, u16 bigFreq) {
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include "core/libraries/pad/pad.h"
|
||||
#include "input_manager.h"
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/io_file.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/path_util.h"
|
||||
|
||||
class Keyboard : public InputManager {
|
||||
public:
|
||||
Keyboard();
|
||||
virtual ~Keyboard() = default;
|
||||
|
||||
virtual u32 getButtonState(InputState* state) override;
|
||||
virtual void getAxis(InputState* state) override;
|
||||
virtual void Init() override;
|
||||
virtual int GetRumble(u16 smallFreq, u16 bigFreq) override;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::string> config_key_map;
|
||||
void initializeSdlKeyMappings(const std::unordered_map<std::string, std::string>& mappings,
|
||||
std::unordered_map<std::string, SDL_Keycode>& keyMappings);
|
||||
std::unordered_map<std::string, SDL_Keycode> sdl_key_map;
|
||||
};
|
|
@ -19,7 +19,7 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_
|
|||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
UNREACHABLE_MSG("Failed to initialize SDL video subsystem: {}", SDL_GetError());
|
||||
}
|
||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
SDL_InitSubSystem(SDL_INIT_AUDIO | SDL_INIT_GAMEPAD | SDL_INIT_JOYSTICK);
|
||||
|
||||
const std::string title = "shadPS4 v" + std::string(Common::VERSION);
|
||||
SDL_PropertiesID props = SDL_CreateProperties();
|
||||
|
@ -63,7 +63,7 @@ WindowSDL::~WindowSDL() = default;
|
|||
void WindowSDL::waitEvent() {
|
||||
// Called on main thread
|
||||
SDL_Event event;
|
||||
|
||||
SDL_PumpEvents();
|
||||
if (!SDL_PollEvent(&event)) {
|
||||
return;
|
||||
}
|
||||
|
@ -79,10 +79,10 @@ void WindowSDL::waitEvent() {
|
|||
is_shown = event.type == SDL_EVENT_WINDOW_EXPOSED;
|
||||
onResize();
|
||||
break;
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
onKeyPress(&event);
|
||||
break;
|
||||
// case SDL_EVENT_KEY_DOWN:
|
||||
// case SDL_EVENT_KEY_UP:
|
||||
// onKeyPress(&event);
|
||||
// break;
|
||||
case SDL_EVENT_QUIT:
|
||||
is_open = false;
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue