diff --git a/Directory.Packages.props b/Directory.Packages.props
index e722dd8838..8fb1c261f8 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -3,6 +3,7 @@
true
+
@@ -49,4 +50,4 @@
-
\ No newline at end of file
+
diff --git a/Ryujinx.sln b/Ryujinx.sln
index b8304164d5..976bc82b4f 100644
--- a/Ryujinx.sln
+++ b/Ryujinx.sln
@@ -87,6 +87,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "src\Ryuj
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D796F12C-217B-4BBF-A131-B6DCB72C6282}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Input.SDL3", "src\Ryujinx.Input.SDL3\Ryujinx.Input.SDL3.csproj", "{3BF24278-547D-42C2-9D43-182B978F54DD}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -249,6 +253,10 @@ Global
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3BF24278-547D-42C2-9D43-182B978F54DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3BF24278-547D-42C2-9D43-182B978F54DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3BF24278-547D-42C2-9D43-182B978F54DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3BF24278-547D-42C2-9D43-182B978F54DD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -256,4 +264,7 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {110169B3-3328-4730-8AB0-BA05BEF75C1A}
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {3BF24278-547D-42C2-9D43-182B978F54DD} = {D796F12C-217B-4BBF-A131-B6DCB72C6282}
+ EndGlobalSection
EndGlobal
diff --git a/src/Ryujinx.Common/Configuration/Hid/Controller/Motion/JsonMotionConfigControllerConverter.cs b/src/Ryujinx.Common/Configuration/Hid/Controller/Motion/JsonMotionConfigControllerConverter.cs
index 40f067aea3..4f218c0d25 100644
--- a/src/Ryujinx.Common/Configuration/Hid/Controller/Motion/JsonMotionConfigControllerConverter.cs
+++ b/src/Ryujinx.Common/Configuration/Hid/Controller/Motion/JsonMotionConfigControllerConverter.cs
@@ -56,6 +56,7 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
return motionBackendType switch
{
MotionInputBackendType.GamepadDriver => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardMotionConfigController),
+ MotionInputBackendType.Handheld => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardMotionConfigController),
MotionInputBackendType.CemuHook => JsonSerializer.Deserialize(ref reader, _serializerContext.CemuHookMotionConfigController),
_ => throw new InvalidOperationException($"Unknown backend type {motionBackendType}"),
};
@@ -66,6 +67,7 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
switch (value.MotionBackend)
{
case MotionInputBackendType.GamepadDriver:
+ case MotionInputBackendType.Handheld:
JsonSerializer.Serialize(writer, value as StandardMotionConfigController, _serializerContext.StandardMotionConfigController);
break;
case MotionInputBackendType.CemuHook:
diff --git a/src/Ryujinx.Common/Configuration/Hid/Controller/Motion/MotionInputBackendType.cs b/src/Ryujinx.Common/Configuration/Hid/Controller/Motion/MotionInputBackendType.cs
index fd8391289c..fd09b25d83 100644
--- a/src/Ryujinx.Common/Configuration/Hid/Controller/Motion/MotionInputBackendType.cs
+++ b/src/Ryujinx.Common/Configuration/Hid/Controller/Motion/MotionInputBackendType.cs
@@ -9,5 +9,6 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
Invalid,
GamepadDriver,
CemuHook,
+ Handheld,
}
}
diff --git a/src/Ryujinx.Gtk3/Ryujinx.Gtk3.csproj b/src/Ryujinx.Gtk3/Ryujinx.Gtk3.csproj
index b4453f9d79..23f3317837 100644
--- a/src/Ryujinx.Gtk3/Ryujinx.Gtk3.csproj
+++ b/src/Ryujinx.Gtk3/Ryujinx.Gtk3.csproj
@@ -36,6 +36,7 @@
+
diff --git a/src/Ryujinx.Gtk3/UI/MainWindow.cs b/src/Ryujinx.Gtk3/UI/MainWindow.cs
index 66c0afae03..787121f5c4 100644
--- a/src/Ryujinx.Gtk3/UI/MainWindow.cs
+++ b/src/Ryujinx.Gtk3/UI/MainWindow.cs
@@ -26,6 +26,7 @@ using Ryujinx.Input.GTK3;
using Ryujinx.Input.HLE;
using Ryujinx.Input.SDL2;
using Ryujinx.Modules;
+using Ryujinx.SDL3;
using Ryujinx.UI.App.Common;
using Ryujinx.UI.Applet;
using Ryujinx.UI.Common;
@@ -339,7 +340,7 @@ namespace Ryujinx.UI
Task.Run(RefreshFirmwareLabel);
- InputManager = new InputManager(new GTK3KeyboardDriver(this), new SDL2GamepadDriver());
+ InputManager = new InputManager(new GTK3KeyboardDriver(this), new SDL2GamepadDriver(), new SDL3MotionDriver());
}
private void UpdateMultiplayerLanInterfaceId(object sender, ReactiveEventArgs args)
diff --git a/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs b/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs
index d0b8266f42..fa2231ce9c 100644
--- a/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs
+++ b/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs
@@ -47,6 +47,7 @@ namespace Ryujinx.UI.Windows
[GUI] Adjustment _gyroDeadzone;
[GUI] CheckButton _enableMotion;
[GUI] CheckButton _enableCemuHook;
+ [GUI] CheckButton _enableHandheld;
[GUI] CheckButton _mirrorInput;
[GUI] Entry _dsuServerHost;
[GUI] Entry _dsuServerPort;
@@ -185,6 +186,7 @@ namespace Ryujinx.UI.Windows
_rSl.Clicked += Button_Pressed;
_rSr.Clicked += Button_Pressed;
_enableCemuHook.Clicked += CemuHookCheckButtonPressed;
+ _enableHandheld.Clicked += HandheldCheckButtonPressed;
// Setup current values.
UpdateInputDeviceList();
@@ -202,6 +204,11 @@ namespace Ryujinx.UI.Windows
_mainWindow.RendererWidget?.NpadManager.BlockInputUpdates();
}
+ private void HandheldCheckButtonPressed(object sender, EventArgs e)
+ {
+ UpdateCemuHookSpecificFieldsVisibility();
+ }
+
private void CemuHookCheckButtonPressed(object sender, EventArgs e)
{
UpdateCemuHookSpecificFieldsVisibility();
@@ -291,8 +298,13 @@ namespace Ryujinx.UI.Windows
private void UpdateCemuHookSpecificFieldsVisibility()
{
+ if (_enableHandheld.Active)
+ {
+ _enableCemuHook.Active = false;
+ }
if (_enableCemuHook.Active)
{
+ _enableHandheld.Active = false;
_dsuServerHostBox.Show();
_dsuServerPortBox.Show();
_motionControllerSlot.Show();
@@ -429,6 +441,7 @@ namespace Ryujinx.UI.Windows
_mirrorInput.Active = false;
_enableMotion.Active = false;
_enableCemuHook.Active = false;
+ _enableHandheld.Active = false;
_slotNumber.Value = 0;
_altSlotNumber.Value = 0;
_sensitivity.Value = 100;
@@ -528,6 +541,7 @@ namespace Ryujinx.UI.Windows
_gyroDeadzone.Value = controllerConfig.Motion.GyroDeadzone;
_enableMotion.Active = controllerConfig.Motion.EnableMotion;
_enableCemuHook.Active = controllerConfig.Motion.MotionBackend == MotionInputBackendType.CemuHook;
+ _enableHandheld.Active = controllerConfig.Motion.MotionBackend == MotionInputBackendType.Handheld;
// If both stick ranges are 0 (usually indicative of an outdated profile load) then both sticks will be set to 1.0.
if (_controllerRangeLeft.Value <= 0.0 && _controllerRangeRight.Value <= 0.0)
@@ -688,7 +702,7 @@ namespace Ryujinx.UI.Windows
{
motionConfig = new StandardMotionConfigController
{
- MotionBackend = MotionInputBackendType.GamepadDriver,
+ MotionBackend = _enableHandheld.Active ? MotionInputBackendType.Handheld : MotionInputBackendType.GamepadDriver,
EnableMotion = _enableMotion.Active,
Sensitivity = (int)_sensitivity.Value,
GyroDeadzone = _gyroDeadzone.Value,
diff --git a/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.glade b/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.glade
index e433f5cc46..c148abe10b 100644
--- a/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.glade
+++ b/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.glade
@@ -1867,6 +1867,20 @@
1
+
+
+
+ False
+ True
+ 2
+
+