From cc943db117646f1297889f1ca582c01a3ff4d64a Mon Sep 17 00:00:00 2001
From: raziel1000 <ckraziel@gmail.com>
Date: Tue, 16 Jul 2024 23:58:30 -0600
Subject: [PATCH] WIP: - Initial gamepad support. - Initial keyboard mapping
 support using config.toml

---
 CMakeLists.txt                 |   5 +
 src/common/config.cpp          |  92 ++++++++++++++++
 src/common/config.h            |   6 ++
 src/core/libraries/pad/pad.cpp | 104 ++++++++++--------
 src/input/gamepad.cpp          | 102 ++++++++++++++++++
 src/input/gamepad.h            |  32 ++++++
 src/input/input_manager.h      |  20 ++++
 src/input/keyboard.cpp         | 188 +++++++++++++++++++++++++++++++++
 src/input/keyboard.h           |  31 ++++++
 src/sdl_window.cpp             |  12 +--
 10 files changed, 543 insertions(+), 49 deletions(-)
 create mode 100644 src/input/gamepad.cpp
 create mode 100644 src/input/gamepad.h
 create mode 100644 src/input/input_manager.h
 create mode 100644 src/input/keyboard.cpp
 create mode 100644 src/input/keyboard.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0bd38f64..c7a06540 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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
diff --git a/src/common/config.cpp b/src/common/config.cpp
index a577b143..864f6a97 100644
--- a/src/common/config.cpp
+++ b/src/common/config.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;
diff --git a/src/common/config.h b/src/common/config.h
index 0a3b4905..cc564e30 100644
--- a/src/common/config.h
+++ b/src/common/config.h
@@ -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);
diff --git a/src/core/libraries/pad/pad.cpp b/src/core/libraries/pad/pad.cpp
index e318e152..7ee6ffe6 100644
--- a/src/core/libraries/pad/pad.cpp
+++ b/src/core/libraries/pad/pad.cpp
@@ -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() {
diff --git a/src/input/gamepad.cpp b/src/input/gamepad.cpp
new file mode 100644
index 00000000..f01dcfa5
--- /dev/null
+++ b/src/input/gamepad.cpp
@@ -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;
+}
\ No newline at end of file
diff --git a/src/input/gamepad.h b/src/input/gamepad.h
new file mode 100644
index 00000000..c8ceb394
--- /dev/null
+++ b/src/input/gamepad.h
@@ -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;
+};
diff --git a/src/input/input_manager.h b/src/input/input_manager.h
new file mode 100644
index 00000000..4f65b6b6
--- /dev/null
+++ b/src/input/input_manager.h
@@ -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;
+};
\ No newline at end of file
diff --git a/src/input/keyboard.cpp b/src/input/keyboard.cpp
new file mode 100644
index 00000000..ac940005
--- /dev/null
+++ b/src/input/keyboard.cpp
@@ -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;
+}
\ No newline at end of file
diff --git a/src/input/keyboard.h b/src/input/keyboard.h
new file mode 100644
index 00000000..8e94bb74
--- /dev/null
+++ b/src/input/keyboard.h
@@ -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;
+};
diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp
index d4da268a..2c39147b 100644
--- a/src/sdl_window.cpp
+++ b/src/sdl_window.cpp
@@ -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;