diff -Naur a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt	2024-12-31 00:57:40.000000000 +0600
+++ b/CMakeLists.txt	2025-01-02 14:15:55.117335770 +0600
@@ -151,8 +151,8 @@
     PURPOSE "Required for building Tablet input KCM"
 )
 
-find_package(SDL2 2.0.16)
-set_package_properties(SDL2 PROPERTIES
+find_package(SDL3 2.0.16)
+set_package_properties(SDL3 PROPERTIES
         TYPE OPTIONAL
         PURPOSE "Required for building Game Controller KCM"
 )
diff -Naur a/kcms/CMakeLists.txt b/kcms/CMakeLists.txt
--- a/kcms/CMakeLists.txt	2024-12-31 00:57:40.000000000 +0600
+++ b/kcms/CMakeLists.txt	2025-01-02 14:18:48.724966040 +0600
@@ -15,7 +15,7 @@
 add_subdirectory( ksmserver )
 add_subdirectory( desktoppaths )
 
-if (TARGET SDL2::SDL2)
+if (TARGET SDL3::SDL3)
     add_subdirectory( gamecontroller )
 endif()
 
diff -Naur a/kcms/gamecontroller/axesmodel.cpp b/kcms/gamecontroller/axesmodel.cpp
--- a/kcms/gamecontroller/axesmodel.cpp	2024-12-31 00:57:40.000000000 +0600
+++ b/kcms/gamecontroller/axesmodel.cpp	2025-01-02 16:02:20.471505265 +0600
@@ -8,7 +8,7 @@
 
 #include "axesmodel.h"
 
-#include <SDL2/SDL_joystick.h>
+#include <SDL3/SDL_joystick.h>
 
 AxesModel::AxesModel(QObject *parent)
     : QAbstractTableModel(parent)
@@ -34,7 +34,7 @@
         return 0;
     }
 
-    return SDL_JoystickNumAxes(m_device->joystick());
+    return SDL_GetNumJoystickAxes(m_device->joystick());
 }
 
 int AxesModel::columnCount(const QModelIndex &parent) const
@@ -50,7 +50,7 @@
     }
 
     if (index.column() == 0 && role == Qt::DisplayRole) {
-        return SDL_JoystickGetAxis(m_device->joystick(), index.row());
+        return SDL_GetJoystickAxis(m_device->joystick(), index.row());
     }
 
     return {};
diff -Naur a/kcms/gamecontroller/buttonmodel.cpp b/kcms/gamecontroller/buttonmodel.cpp
--- a/kcms/gamecontroller/buttonmodel.cpp	2024-12-31 00:57:40.000000000 +0600
+++ b/kcms/gamecontroller/buttonmodel.cpp	2025-01-02 16:28:11.340276986 +0600
@@ -9,7 +9,7 @@
 #include "buttonmodel.h"
 #include "gamepad.h"
 
-#include <SDL2/SDL_joystick.h>
+#include <SDL3/SDL_joystick.h>
 
 #include <KLocalizedString>
 
@@ -29,10 +29,10 @@
         return;
     }
 
-    const int numButtons = SDL_JoystickNumButtons(m_device->joystick());
-    for (int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++) {
-        const SDL_GameControllerButton button = static_cast<SDL_GameControllerButton>(i);
-        if (SDL_GameControllerHasButton(m_device->gamecontroller(), button)) {
+    const int numButtons = SDL_GetNumJoystickButtons(m_device->joystick());
+    for (int i = 0; i < SDL_GAMEPAD_BUTTON_COUNT; i++) {
+        const SDL_GamepadButton button = static_cast<SDL_GamepadButton>(i);
+        if (SDL_GamepadHasButton(m_device->gamecontroller(), button)) {
             m_buttons << button;
             if (m_buttons.count() == numButtons) {
                 break;
@@ -42,7 +42,7 @@
 
     endResetModel();
 
-    connect(m_device, &Gamepad::buttonStateChanged, this, [this](SDL_GameControllerButton button) {
+    connect(m_device, &Gamepad::buttonStateChanged, this, [this](SDL_GamepadButton button) {
         const int row = m_buttons.indexOf(button);
         if (row >= 0) {
             const QModelIndex changedIndex = index(row, 0);
@@ -70,7 +70,7 @@
     }
 
     if (index.column() == 0 && role == Qt::DisplayRole) {
-        const int pressed = SDL_GameControllerGetButton(m_device->gamecontroller(), m_buttons.at(index.row()));
+        const int pressed = SDL_GetGamepadButton(m_device->gamecontroller(), m_buttons.at(index.row()));
         return pressed ? i18nc("Status of a gamepad button", "PRESSED") : QStringLiteral("-");
     }
 
diff -Naur a/kcms/gamecontroller/buttonmodel.h b/kcms/gamecontroller/buttonmodel.h
--- a/kcms/gamecontroller/buttonmodel.h	2024-12-31 00:57:40.000000000 +0600
+++ b/kcms/gamecontroller/buttonmodel.h	2025-01-02 15:23:51.720545464 +0600
@@ -9,7 +9,7 @@
 #pragma once
 
 #include <QAbstractTableModel>
-#include <SDL2/SDL_gamecontroller.h>
+#include <SDL3/SDL_gamepad.h>
 
 class Gamepad;
 
@@ -37,5 +37,5 @@
 
 private:
     Gamepad *m_device = nullptr;
-    QList<SDL_GameControllerButton> m_buttons;
+    QList<SDL_GamepadButton> m_buttons;
 };
diff -Naur a/kcms/gamecontroller/CMakeLists.txt b/kcms/gamecontroller/CMakeLists.txt
--- a/kcms/gamecontroller/CMakeLists.txt	2024-12-31 00:57:40.000000000 +0600
+++ b/kcms/gamecontroller/CMakeLists.txt	2025-01-02 14:18:25.805149400 +0600
@@ -40,5 +40,5 @@
     KF6::I18n
     Qt6::Quick
     Qt6::QuickWidgets
-    SDL2::SDL2
+    SDL3::SDL3
 )
diff -Naur a/kcms/gamecontroller/devicemodel.cpp b/kcms/gamecontroller/devicemodel.cpp
--- a/kcms/gamecontroller/devicemodel.cpp	2024-12-31 00:57:40.000000000 +0600
+++ b/kcms/gamecontroller/devicemodel.cpp	2025-01-02 15:49:50.615986733 +0600
@@ -11,8 +11,8 @@
 #include <KLocalizedString>
 #include <QTimer>
 
-#include <SDL2/SDL.h>
-#include <SDL2/SDL_joystick.h>
+#include <SDL3/SDL.h>
+#include <SDL3/SDL_joystick.h>
 
 #include "gamepad.h"
 #include "logging.h"
@@ -79,25 +79,25 @@
 {
     if (!initialized) {
         qCDebug(KCM_GAMECONTROLLER) << "Calling SDL_Init";
-        SDL_Init(SDL_INIT_GAMECONTROLLER);
+        SDL_Init(SDL_INIT_GAMEPAD);
         initialized = true;
     }
 
     SDL_Event event{};
     while (SDL_PollEvent(&event)) {
         switch (event.type) {
-        case SDL_CONTROLLERDEVICEADDED:
+        case SDL_EVENT_GAMEPAD_ADDED:
             addDevice(event.cdevice.which);
             break;
-        case SDL_CONTROLLERDEVICEREMOVED:
+        case SDL_EVENT_GAMEPAD_REMOVED:
             removeDevice(event.cdevice.which);
             break;
-        case SDL_CONTROLLERBUTTONDOWN:
-        case SDL_CONTROLLERBUTTONUP:
-            m_devices.value(event.cbutton.which)->onButtonEvent(event.cbutton);
+        case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
+        case SDL_EVENT_GAMEPAD_BUTTON_UP:
+            m_devices.value(event.gbutton.which)->onButtonEvent(event.gbutton);
             break;
-        case SDL_CONTROLLERAXISMOTION:
-            m_devices.value(event.caxis.which)->onAxisEvent(event.caxis);
+        case SDL_EVENT_GAMEPAD_AXIS_MOTION:
+            m_devices.value(event.gaxis.which)->onAxisEvent(event.gaxis);
             break;
         }
     }
@@ -105,16 +105,16 @@
 
 void DeviceModel::addDevice(const int deviceIndex)
 {
-    const auto joystick = SDL_JoystickOpen(deviceIndex);
-    const auto id = SDL_JoystickInstanceID(joystick);
+    const auto joystick = SDL_OpenJoystick(deviceIndex);
+    const auto id = SDL_GetJoystickID(joystick);
 
     if (m_devices.contains(id)) {
         qCWarning(KCM_GAMECONTROLLER) << "Got a duplicate add event, ignoring. Index: " << deviceIndex;
         return;
     }
 
-    const auto gamepad = SDL_GameControllerOpen(deviceIndex);
-    if (SDL_GameControllerTypeForIndex(deviceIndex) == SDL_CONTROLLER_TYPE_VIRTUAL) {
+    const auto gamepad = SDL_OpenGamepad(deviceIndex);
+    if (SDL_IsJoystickVirtual(deviceIndex)) {
         qCWarning(KCM_GAMECONTROLLER) << "Skipping gamepad since it is virtual. Index: " << deviceIndex;
         return;
     }
diff -Naur a/kcms/gamecontroller/.directory b/kcms/gamecontroller/.directory
--- a/kcms/gamecontroller/.directory	1970-01-01 06:00:00.000000000 +0600
+++ b/kcms/gamecontroller/.directory	2025-01-02 15:22:58.745886681 +0600
@@ -0,0 +1,6 @@
+[Dolphin]
+Timestamp=2025,1,2,15,22,58.583
+Version=4
+
+[Settings]
+HiddenFilesShown=true
diff -Naur a/kcms/gamecontroller/gamepad.cpp b/kcms/gamecontroller/gamepad.cpp
--- a/kcms/gamecontroller/gamepad.cpp	2024-12-31 00:57:40.000000000 +0600
+++ b/kcms/gamecontroller/gamepad.cpp	2025-01-02 15:56:23.652646967 +0600
@@ -9,16 +9,16 @@
 #include "gamepad.h"
 
 #include <QTimer>
-#include <SDL2/SDL.h>
-#include <SDL2/SDL_gamecontroller.h>
+#include <SDL3/SDL.h>
+#include <SDL3/SDL_gamepad.h>
 
-Gamepad::Gamepad(SDL_Joystick *joystick, SDL_GameController *controller, QObject *parent)
+Gamepad::Gamepad(SDL_Joystick *joystick, SDL_Gamepad *controller, QObject *parent)
     : QObject(parent)
     , m_joystick(joystick)
     , m_gameController(controller)
 {
-    m_name = QString::fromLocal8Bit(SDL_JoystickName(m_joystick));
-    m_path = QString::fromLocal8Bit(SDL_JoystickPath(m_joystick));
+    m_name = QString::fromLocal8Bit(SDL_GetJoystickName(m_joystick));
+    m_path = QString::fromLocal8Bit(SDL_GetJoystickPath(m_joystick));
 }
 
 QString Gamepad::name() const
@@ -31,18 +31,18 @@
     return m_path;
 }
 
-void Gamepad::onButtonEvent(const SDL_ControllerButtonEvent sdlEvent)
+void Gamepad::onButtonEvent(const SDL_GamepadButtonEvent sdlEvent)
 {
-    Q_EMIT buttonStateChanged(static_cast<SDL_GameControllerButton>(sdlEvent.button));
+    Q_EMIT buttonStateChanged(static_cast<SDL_GamepadButton>(sdlEvent.button));
 }
 
-void Gamepad::onAxisEvent(const SDL_ControllerAxisEvent sdlEvent)
+void Gamepad::onAxisEvent(const SDL_GamepadAxisEvent sdlEvent)
 {
     const float value = static_cast<float>(sdlEvent.value) / std::numeric_limits<Sint16>::max();
-    if (sdlEvent.axis == SDL_CONTROLLER_AXIS_LEFTX) {
+    if (sdlEvent.axis == SDL_GAMEPAD_AXIS_LEFTX) {
         m_axis.setX(value);
         Q_EMIT axisValueChanged();
-    } else if (sdlEvent.axis == SDL_CONTROLLER_AXIS_LEFTY) {
+    } else if (sdlEvent.axis == SDL_GAMEPAD_AXIS_LEFTY) {
         m_axis.setY(value);
         Q_EMIT axisValueChanged();
     }
@@ -55,7 +55,7 @@
     return m_joystick;
 }
 
-SDL_GameController *Gamepad::gamecontroller() const
+SDL_Gamepad *Gamepad::gamecontroller() const
 {
     return m_gameController;
 }
diff -Naur a/kcms/gamecontroller/gamepad.h b/kcms/gamecontroller/gamepad.h
--- a/kcms/gamecontroller/gamepad.h	2024-12-31 00:57:40.000000000 +0600
+++ b/kcms/gamecontroller/gamepad.h	2025-01-02 15:22:53.919917766 +0600
@@ -15,9 +15,9 @@
 
 #include <KLocalizedString>
 
-#include <SDL2/SDL_events.h>
-#include <SDL2/SDL_gamecontroller.h>
-#include <SDL2/SDL_joystick.h>
+#include <SDL3/SDL_events.h>
+#include <SDL3/SDL_gamepad.h>
+#include <SDL3/SDL_joystick.h>
 
 class Gamepad : public QObject
 {
@@ -26,29 +26,29 @@
     Q_PROPERTY(QVector2D axisValue READ axisValue NOTIFY axisValueChanged)
 
 public:
-    Gamepad(SDL_Joystick *joystick, SDL_GameController *controller, QObject *parent = nullptr);
+    Gamepad(SDL_Joystick *joystick, SDL_Gamepad *controller, QObject *parent = nullptr);
 
     QString name() const;
     QString path() const;
 
     SDL_Joystick *joystick() const;
-    SDL_GameController *gamecontroller() const;
+    SDL_Gamepad *gamecontroller() const;
 
     QVector2D axisValue() const;
 
 Q_SIGNALS:
-    void buttonStateChanged(SDL_GameControllerButton button);
+    void buttonStateChanged(SDL_GamepadButton button);
     void axisStateChanged(int index);
     void axisValueChanged();
 
 private:
     friend class DeviceModel;
 
-    void onButtonEvent(SDL_ControllerButtonEvent sdlEvent);
-    void onAxisEvent(SDL_ControllerAxisEvent sdlEvent);
+    void onButtonEvent(SDL_GamepadButtonEvent sdlEvent);
+    void onAxisEvent(SDL_GamepadAxisEvent sdlEvent);
 
     SDL_Joystick *m_joystick = nullptr;
-    SDL_GameController *m_gameController = nullptr;
+    SDL_Gamepad *m_gameController = nullptr;
 
     QString m_name;
     QString m_path;
