Compare commits

...

10 Commits

26 changed files with 400 additions and 220 deletions
+1
View File
@@ -3,6 +3,7 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageVersion Include="Alimer.Bindings.SDL" Version="3.7.1" />
<PackageVersion Include="Avalonia" Version="11.0.13" /> <PackageVersion Include="Avalonia" Version="11.0.13" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.13" /> <PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.13" />
<PackageVersion Include="Avalonia.Desktop" Version="11.0.13" /> <PackageVersion Include="Avalonia.Desktop" Version="11.0.13" />
+6
View File
@@ -75,6 +75,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "src\Ryuj
EndProject 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}" 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 EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Input.SDL3", "src\Ryujinx.Input.SDL3\Ryujinx.Input.SDL3.csproj", "{3BF24278-547D-42C2-9D43-182B978F54DD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.Metal", "src\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj", "{C08931FA-1191-417A-864F-3882D93E683B}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.Metal", "src\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj", "{C08931FA-1191-417A-864F-3882D93E683B}"
@@ -259,6 +261,10 @@ Global
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.Build.0 = Debug|Any CPU {81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.ActiveCfg = Release|Any CPU {81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.Build.0 = Release|Any CPU {81EA598C-DBA1-40B0-8DA4-4796B78F2037}.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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -56,6 +56,7 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
return motionBackendType switch return motionBackendType switch
{ {
MotionInputBackendType.GamepadDriver => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardMotionConfigController), MotionInputBackendType.GamepadDriver => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardMotionConfigController),
MotionInputBackendType.Handheld => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardMotionConfigController),
MotionInputBackendType.CemuHook => JsonSerializer.Deserialize(ref reader, _serializerContext.CemuHookMotionConfigController), MotionInputBackendType.CemuHook => JsonSerializer.Deserialize(ref reader, _serializerContext.CemuHookMotionConfigController),
_ => throw new InvalidOperationException($"Unknown backend type {motionBackendType}"), _ => throw new InvalidOperationException($"Unknown backend type {motionBackendType}"),
}; };
@@ -66,6 +67,7 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
switch (value.MotionBackend) switch (value.MotionBackend)
{ {
case MotionInputBackendType.GamepadDriver: case MotionInputBackendType.GamepadDriver:
case MotionInputBackendType.Handheld:
JsonSerializer.Serialize(writer, value as StandardMotionConfigController, _serializerContext.StandardMotionConfigController); JsonSerializer.Serialize(writer, value as StandardMotionConfigController, _serializerContext.StandardMotionConfigController);
break; break;
case MotionInputBackendType.CemuHook: case MotionInputBackendType.CemuHook:
@@ -9,5 +9,6 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
Invalid, Invalid,
GamepadDriver, GamepadDriver,
CemuHook, CemuHook,
Handheld,
} }
} }
+10 -6
View File
@@ -10,14 +10,18 @@ namespace Ryujinx.Common.Helper
public static bool IsMacOS => OperatingSystem.IsMacOS(); public static bool IsMacOS => OperatingSystem.IsMacOS();
public static bool IsWindows => OperatingSystem.IsWindows(); public static bool IsWindows => OperatingSystem.IsWindows();
public static bool IsLinux => OperatingSystem.IsLinux(); public static bool IsLinux => OperatingSystem.IsLinux();
public static bool IsArm => RuntimeInformation.OSArchitecture is Architecture.Arm64;
public static bool IsX64 => RuntimeInformation.OSArchitecture is Architecture.X64;
public static bool IsIntelMac => IsMacOS && RuntimeInformation.OSArchitecture is Architecture.X64; public static bool IsIntelMac => IsMacOS && IsX64;
public static bool IsArmMac => IsMacOS && RuntimeInformation.OSArchitecture is Architecture.Arm64; public static bool IsArmMac => IsMacOS && IsArm;
public static bool IsX64Windows => IsWindows && (RuntimeInformation.OSArchitecture is Architecture.X64); public static bool IsX64Windows => IsWindows && IsX64;
public static bool IsArmWindows => IsWindows && (RuntimeInformation.OSArchitecture is Architecture.Arm64); public static bool IsArmWindows => IsWindows && IsArm;
public static bool IsX64Linux => IsLinux && (RuntimeInformation.OSArchitecture is Architecture.X64); public static bool IsX64Linux => IsLinux && IsX64;
public static bool IsArmLinux => IsLinux && (RuntimeInformation.OSArchitecture is Architecture.Arm64); public static bool IsArmLinux => IsLinux && IsArmMac;
} }
} }
@@ -83,11 +83,11 @@ namespace Ryujinx.Graphics.Gpu.Synchronization
// TODO: Remove this when GPU channel scheduling will be implemented. // TODO: Remove this when GPU channel scheduling will be implemented.
if (timeout == Timeout.InfiniteTimeSpan) if (timeout == Timeout.InfiniteTimeSpan)
{ {
timeout = TimeSpan.FromSeconds(1); timeout = TimeSpan.FromMilliseconds(500);
} }
using ManualResetEvent waitEvent = new(false); using ManualResetEvent waitEvent = new(false);
SyncpointWaiterHandle info = _syncpoints[id].RegisterCallback(threshold, (x) => waitEvent.Set()); SyncpointWaiterHandle info = _syncpoints[id].RegisterCallback(threshold, _ => waitEvent.Set());
if (info == null) if (info == null)
{ {
@@ -96,7 +96,7 @@ namespace Ryujinx.Graphics.Gpu.Synchronization
bool signaled = waitEvent.WaitOne(timeout); bool signaled = waitEvent.WaitOne(timeout);
if (!signaled && info != null) if (!signaled)
{ {
Logger.Error?.Print(LogClass.Gpu, $"Wait on syncpoint {id} for threshold {threshold} took more than {timeout.TotalMilliseconds}ms, resuming execution..."); Logger.Error?.Print(LogClass.Gpu, $"Wait on syncpoint {id} for threshold {threshold} took more than {timeout.TotalMilliseconds}ms, resuming execution...");
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ryujinx.Input\Ryujinx.Input.csproj" />
<PackageReference Include="Alimer.Bindings.SDL" />
</ItemGroup>
</Project>
@@ -0,0 +1,44 @@
using Ryujinx.Input;
using SDL3;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using static SDL3.SDL3;
namespace Ryujinx.Input.SDL3;
public unsafe class SDL3MotionDriver : IHandheld, IDisposable
{
private Dictionary<SDL_SensorType, SDL_Sensor> sensors;
public SDL3MotionDriver()
{
SDL_Init(SDL_InitFlags.Sensor);
sensors = SDL_GetSensors().ToArray().ToDictionary(SDL_GetSensorTypeForID, SDL_OpenSensor);
}
public void Dispose()
{
foreach (var sensor in sensors.Values)
{
SDL_CloseSensor(sensor);
}
}
public Vector3 GetMotionData(MotionInputId gyroscope)
{
var data = stackalloc float[3];
switch (gyroscope)
{
case MotionInputId.Gyroscope:
SDL_GetSensorData(sensors[SDL_SensorType.Gyro], data, 3);
return new Vector3(data[0], data[1], data[2]) * (180 / MathF.PI);
case MotionInputId.Accelerometer:
SDL_GetSensorData(sensors[SDL_SensorType.Accel], data, 3);
return new Vector3(data[0], data[1], data[2]) / SDL_STANDARD_GRAVITY;
default:
return Vector3.Zero;
}
}
}
+4 -2
View File
@@ -2,12 +2,13 @@ using System;
namespace Ryujinx.Input.HLE namespace Ryujinx.Input.HLE
{ {
public class InputManager(IGamepadDriver keyboardDriver, IGamepadDriver gamepadDriver) public class InputManager(IGamepadDriver keyboardDriver, IGamepadDriver gamepadDriver, IHandheld handheld)
: IDisposable : IDisposable
{ {
public IGamepadDriver KeyboardDriver { get; } = keyboardDriver; public IGamepadDriver KeyboardDriver { get; } = keyboardDriver;
public IGamepadDriver GamepadDriver { get; } = gamepadDriver; public IGamepadDriver GamepadDriver { get; } = gamepadDriver;
public IGamepadDriver MouseDriver { get; private set; } public IGamepadDriver MouseDriver { get; private set; }
public IHandheld Handheld { get; } = handheld;
public void SetMouseDriver(IGamepadDriver mouseDriver) public void SetMouseDriver(IGamepadDriver mouseDriver)
{ {
@@ -18,7 +19,7 @@ namespace Ryujinx.Input.HLE
public NpadManager CreateNpadManager() public NpadManager CreateNpadManager()
{ {
return new NpadManager(KeyboardDriver, GamepadDriver, MouseDriver); return new NpadManager(KeyboardDriver, GamepadDriver, MouseDriver, Handheld);
} }
public TouchScreenManager CreateTouchScreenManager() public TouchScreenManager CreateTouchScreenManager()
@@ -38,6 +39,7 @@ namespace Ryujinx.Input.HLE
KeyboardDriver?.Dispose(); KeyboardDriver?.Dispose();
GamepadDriver?.Dispose(); GamepadDriver?.Dispose();
MouseDriver?.Dispose(); MouseDriver?.Dispose();
Handheld?.Dispose();
} }
} }
+15 -1
View File
@@ -218,12 +218,14 @@ namespace Ryujinx.Input.HLE
public string Id { get; private set; } public string Id { get; private set; }
private readonly CemuHookClient _cemuHookClient; private readonly CemuHookClient _cemuHookClient;
private readonly IHandheld _handheld;
public NpadController(CemuHookClient cemuHookClient) public NpadController(CemuHookClient cemuHookClient, IHandheld handheld)
{ {
State = default; State = default;
Id = null; Id = null;
_cemuHookClient = cemuHookClient; _cemuHookClient = cemuHookClient;
_handheld = handheld;
} }
public bool UpdateDriverConfiguration(IGamepadDriver gamepadDriver, InputConfig config) public bool UpdateDriverConfiguration(IGamepadDriver gamepadDriver, InputConfig config)
@@ -287,6 +289,18 @@ namespace Ryujinx.Input.HLE
if (_config is StandardControllerInputConfig controllerConfig && controllerConfig.Motion.EnableMotion) if (_config is StandardControllerInputConfig controllerConfig && controllerConfig.Motion.EnableMotion)
{ {
if (controllerConfig.Motion.MotionBackend == MotionInputBackendType.Handheld)
{
Vector3 accelerometer = _handheld.GetMotionData(MotionInputId.Accelerometer);
Vector3 gyroscope = _handheld.GetMotionData(MotionInputId.Gyroscope);
accelerometer = new Vector3(accelerometer.X, -accelerometer.Z, accelerometer.Y);
gyroscope = new Vector3(gyroscope.X, -gyroscope.Z, gyroscope.Y);
_leftMotionInput.Update(accelerometer, gyroscope, (ulong)PerformanceCounter.ElapsedNanoseconds / 1000, controllerConfig.Motion.Sensitivity, (float)controllerConfig.Motion.GyroDeadzone);
_rightMotionInput = _leftMotionInput;
}
if (controllerConfig.Motion.MotionBackend == MotionInputBackendType.GamepadDriver) if (controllerConfig.Motion.MotionBackend == MotionInputBackendType.GamepadDriver)
{ {
if (gamepad.Features.HasFlag(GamepadFeaturesFlag.Motion)) if (gamepad.Features.HasFlag(GamepadFeaturesFlag.Motion))
+4 -2
View File
@@ -31,6 +31,7 @@ namespace Ryujinx.Input.HLE
private readonly IGamepadDriver _keyboardDriver; private readonly IGamepadDriver _keyboardDriver;
private readonly IGamepadDriver _gamepadDriver; private readonly IGamepadDriver _gamepadDriver;
private readonly IGamepadDriver _mouseDriver; private readonly IGamepadDriver _mouseDriver;
private readonly IHandheld _handheld;
private bool _isDisposed; private bool _isDisposed;
private List<InputConfig> _inputConfig; private List<InputConfig> _inputConfig;
@@ -38,7 +39,7 @@ namespace Ryujinx.Input.HLE
private bool _enableMouse; private bool _enableMouse;
private Switch _device; private Switch _device;
public NpadManager(IGamepadDriver keyboardDriver, IGamepadDriver gamepadDriver, IGamepadDriver mouseDriver) public NpadManager(IGamepadDriver keyboardDriver, IGamepadDriver gamepadDriver, IGamepadDriver mouseDriver, IHandheld handheld)
{ {
_controllers = new NpadController[MaxControllers]; _controllers = new NpadController[MaxControllers];
_cemuHookClient = new CemuHookClient(this); _cemuHookClient = new CemuHookClient(this);
@@ -47,6 +48,7 @@ namespace Ryujinx.Input.HLE
_gamepadDriver = gamepadDriver; _gamepadDriver = gamepadDriver;
_mouseDriver = mouseDriver; _mouseDriver = mouseDriver;
_inputConfig = []; _inputConfig = [];
_handheld = handheld;
_gamepadDriver.OnGamepadConnected += HandleOnGamepadConnected; _gamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
_gamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected; _gamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
@@ -139,7 +141,7 @@ namespace Ryujinx.Input.HLE
} }
else else
{ {
controller = new(_cemuHookClient); controller = new(_cemuHookClient, _handheld);
} }
bool isValid = DriverConfigurationUpdate(ref controller, inputConfigEntry); bool isValid = DriverConfigurationUpdate(ref controller, inputConfigEntry);
+10
View File
@@ -0,0 +1,10 @@
using System;
using System.Numerics;
namespace Ryujinx.Input
{
public interface IHandheld : IDisposable
{
Vector3 GetMotionData(MotionInputId gyroscope);
}
}
+197 -172
View File
@@ -7522,6 +7522,31 @@
"zh_TW": "使用與 CemuHook 相容的體感" "zh_TW": "使用與 CemuHook 相容的體感"
} }
}, },
{
"ID": "ControllerSettingsMotionUseHandheldCompatibleMotion",
"Translations": {
"ar_SA": "استخدام الحركة المتوافقة مع Hendheld",
"de_DE": "Hendheld kompatible Bewegungssteuerung",
"el_GR": "Κίνηση συμβατή με Hendheld",
"en_US": "Use Hendheld compatible motion",
"es_ES": "Usar movimiento compatible con Hendheld",
"fr_FR": "Utiliser un capteur de mouvements Hendheld",
"he_IL": "השתמש בתנועת Hendheld תואמת ",
"it_IT": "Usa sensore compatibile con Hendheld",
"ja_JP": "Hendheld 互換モーションを使用",
"ko_KR": "Hendheld 호환 모션 사용",
"no_NO": "Bruk Hendheld kompatibel bevegelse",
"pl_PL": "Użyj ruchu zgodnego z Hendheld",
"pt_BR": "Usar sensor compatível com Hendheld",
"ru_RU": "Включить совместимость с Hendheld",
"sv_SE": "Använd Hendheld-kompatibel rörelse",
"th_TH": "ใช้การเคลื่อนไหวที่เข้ากันได้กับ Hendheld",
"tr_TR": "Hendheld uyumlu hareket kullan",
"uk_UA": "Використовувати рух, сумісний з Hendheld",
"zh_CN": "使用 Hendheld 兼容的体感协议",
"zh_TW": "使用與 Hendheld 相容的體感"
}
},
{ {
"ID": "ControllerSettingsMotionControllerSlot", "ID": "ControllerSettingsMotionControllerSlot",
"Translations": { "Translations": {
@@ -11475,126 +11500,126 @@
{ {
"ID": "DialogConfirmationTitle", "ID": "DialogConfirmationTitle",
"Translations": { "Translations": {
"ar_SA": "ريوجينكس - تأكيد", "ar_SA": "{0} - تأكيد",
"de_DE": "Ryujinx - Bestätigung", "de_DE": "{0} - Bestätigung",
"el_GR": "Ryujinx - Επιβεβαίωση", "el_GR": "{0} - Επιβεβαίωση",
"en_US": "Ryujinx - Confirmation", "en_US": "{0} - Confirmation",
"es_ES": "Ryujinx - Confirmación", "es_ES": "{0} - Confirmación",
"fr_FR": "", "fr_FR": "",
"he_IL": "ריוג'ינקס - אישור", "he_IL": "{0} - אישור",
"it_IT": "Ryujinx - Conferma", "it_IT": "{0} - Conferma",
"ja_JP": "Ryujinx - 確認", "ja_JP": "{0} - 確認",
"ko_KR": "Ryujinx - 확인", "ko_KR": "{0} - 확인",
"no_NO": "Ryujinx - Bekreftelse", "no_NO": "{0} - Bekreftelse",
"pl_PL": "Ryujinx - Potwierdzenie", "pl_PL": "{0} - Potwierdzenie",
"pt_BR": "Ryujinx - Confirmação", "pt_BR": "{0} - Confirmação",
"ru_RU": "Ryujinx - Подтверждение", "ru_RU": "{0} - Подтверждение",
"sv_SE": "Ryujinx - Bekräftelse", "sv_SE": "{0} - Bekräftelse",
"th_TH": "Ryujinx - ยืนยัน", "th_TH": "{0} - ยืนยัน",
"tr_TR": "Ryujinx - Onay", "tr_TR": "{0} - Onay",
"uk_UA": "Ryujinx - Підтвердження", "uk_UA": "{0} - Підтвердження",
"zh_CN": "Ryujinx - 确认", "zh_CN": "{0} - 确认",
"zh_TW": "Ryujinx - 確認" "zh_TW": "{0} - 確認"
} }
}, },
{ {
"ID": "DialogUpdaterTitle", "ID": "DialogUpdaterTitle",
"Translations": { "Translations": {
"ar_SA": "ريوجينكس - المحدث", "ar_SA": "{0} - المحدث",
"de_DE": "", "de_DE": "",
"el_GR": "Ryujinx - Ενημερωτής", "el_GR": "{0} - Ενημερωτής",
"en_US": "Ryujinx - Updater", "en_US": "{0} - Updater",
"es_ES": "Ryujinx - Actualizador", "es_ES": "{0} - Actualizador",
"fr_FR": "Ryujinx - Mise à Jour", "fr_FR": "{0} - Mise à Jour",
"he_IL": "ריוג'ינקס - מעדכן", "he_IL": "{0} - מעדכן",
"it_IT": "Ryujinx - Aggiornamento", "it_IT": "{0} - Aggiornamento",
"ja_JP": "Ryujinx - アップデータ", "ja_JP": "{0} - アップデータ",
"ko_KR": "Ryujinx - 업데이터", "ko_KR": "{0} - 업데이터",
"no_NO": "Ryujinx Oppdaterer", "no_NO": "{0} Oppdaterer",
"pl_PL": "Ryujinx - Asystent aktualizacji", "pl_PL": "{0} - Asystent aktualizacji",
"pt_BR": "Ryujinx - Atualizador", "pt_BR": "{0} - Atualizador",
"ru_RU": "Ryujinx - Обновление", "ru_RU": "{0} - Обновление",
"sv_SE": "Ryujinx - Uppdatering", "sv_SE": "{0} - Uppdatering",
"th_TH": "Ryujinx - อัพเดต", "th_TH": "{0} - อัพเดต",
"tr_TR": "Ryujinx - Güncelleyici", "tr_TR": "{0} - Güncelleyici",
"uk_UA": "Ryujinx - Програма оновлення", "uk_UA": "{0} - Програма оновлення",
"zh_CN": "Ryujinx - 更新", "zh_CN": "{0} - 更新",
"zh_TW": "Ryujinx - 更新程式" "zh_TW": "{0} - 更新程式"
} }
}, },
{ {
"ID": "DialogErrorTitle", "ID": "DialogErrorTitle",
"Translations": { "Translations": {
"ar_SA": "ريوجينكس - خطأ", "ar_SA": "{0} - خطأ",
"de_DE": "Ryujinx - Fehler", "de_DE": "{0} - Fehler",
"el_GR": "Ryujinx - Σφάλμα", "el_GR": "{0} - Σφάλμα",
"en_US": "Ryujinx - Error", "en_US": "{0} - Error",
"es_ES": "", "es_ES": "",
"fr_FR": "Ryujinx - Erreur", "fr_FR": "{0} - Erreur",
"he_IL": "ריוג'ינקס - שגיאה", "he_IL": "{0} - שגיאה",
"it_IT": "Ryujinx - Errore", "it_IT": "{0} - Errore",
"ja_JP": "Ryujinx - エラー", "ja_JP": "{0} - エラー",
"ko_KR": "Ryujinx - 오류", "ko_KR": "{0} - 오류",
"no_NO": "Ryujinx - Feil", "no_NO": "{0} - Feil",
"pl_PL": "Ryujinx - Błąd", "pl_PL": "{0} - Błąd",
"pt_BR": "Ryujinx - Erro", "pt_BR": "{0} - Erro",
"ru_RU": "Ryujinx - Ошибка", "ru_RU": "{0} - Ошибка",
"sv_SE": "Ryujinx - Fel", "sv_SE": "{0} - Fel",
"th_TH": "Ryujinx - ผิดพลาด", "th_TH": "{0} - ผิดพลาด",
"tr_TR": "Ryujinx - Hata", "tr_TR": "{0} - Hata",
"uk_UA": "Ryujinx - Помилка", "uk_UA": "{0} - Помилка",
"zh_CN": "Ryujinx - 错误", "zh_CN": "{0} - 错误",
"zh_TW": "Ryujinx - 錯誤" "zh_TW": "{0} - 錯誤"
} }
}, },
{ {
"ID": "DialogWarningTitle", "ID": "DialogWarningTitle",
"Translations": { "Translations": {
"ar_SA": "ريوجينكس - تحذير", "ar_SA": "{0} - تحذير",
"de_DE": "Ryujinx - Warnung", "de_DE": "{0} - Warnung",
"el_GR": "Ryujinx - Προειδοποίηση", "el_GR": "{0} - Προειδοποίηση",
"en_US": "Ryujinx - Warning", "en_US": "{0} - Warning",
"es_ES": "Ryujinx - Advertencia", "es_ES": "{0} - Advertencia",
"fr_FR": "Ryujinx - Avertissement", "fr_FR": "{0} - Avertissement",
"he_IL": "ריוג'ינקס - אזהרה", "he_IL": "{0} - אזהרה",
"it_IT": "Ryujinx - Avviso", "it_IT": "{0} - Avviso",
"ja_JP": "Ryujinx - 警告", "ja_JP": "{0} - 警告",
"ko_KR": "Ryujinx - 경고", "ko_KR": "{0} - 경고",
"no_NO": "Ryujinx - Advarsel", "no_NO": "{0} - Advarsel",
"pl_PL": "Ryujinx - Ostrzeżenie", "pl_PL": "{0} - Ostrzeżenie",
"pt_BR": "Ryujinx - Alerta", "pt_BR": "{0} - Alerta",
"ru_RU": "Ryujinx - Предупреждение", "ru_RU": "{0} - Предупреждение",
"sv_SE": "Ryujinx - Varning", "sv_SE": "{0} - Varning",
"th_TH": "Ryujinx - คำเตือน", "th_TH": "{0} - คำเตือน",
"tr_TR": "Ryujinx - Uyarı", "tr_TR": "{0} - Uyarı",
"uk_UA": "Ryujinx - Попередження", "uk_UA": "{0} - Попередження",
"zh_CN": "Ryujinx - 警告", "zh_CN": "{0} - 警告",
"zh_TW": "Ryujinx - 警告" "zh_TW": "{0} - 警告"
} }
}, },
{ {
"ID": "DialogExitTitle", "ID": "DialogExitTitle",
"Translations": { "Translations": {
"ar_SA": "ريوجينكس - الخروج", "ar_SA": "{0} - الخروج",
"de_DE": "Ryujinx - Beenden", "de_DE": "{0} - Beenden",
"el_GR": "Ryujinx - Έξοδος", "el_GR": "{0} - Έξοδος",
"en_US": "Ryujinx - Exit", "en_US": "{0} - Exit",
"es_ES": "Ryujinx - Salir", "es_ES": "{0} - Salir",
"fr_FR": "Ryujinx - Quitter", "fr_FR": "{0} - Quitter",
"he_IL": "ריוג'ינקס - יציאה", "he_IL": "{0} - יציאה",
"it_IT": "Ryujinx - Esci", "it_IT": "{0} - Esci",
"ja_JP": "Ryujinx - 終了", "ja_JP": "{0} - 終了",
"ko_KR": "Ryujinx - 종료", "ko_KR": "{0} - 종료",
"no_NO": "Ryujinx - Avslutt", "no_NO": "{0} - Avslutt",
"pl_PL": "Ryujinx - Wyjdź", "pl_PL": "{0} - Wyjdź",
"pt_BR": "Ryujinx - Sair", "pt_BR": "{0} - Sair",
"ru_RU": "Ryujinx - Выход", "ru_RU": "{0} - Выход",
"sv_SE": "Ryujinx - Avslut", "sv_SE": "{0} - Avslut",
"th_TH": "Ryujinx - ออก", "th_TH": "{0} - ออก",
"tr_TR": "Ryujinx - Çıkış", "tr_TR": "{0} - Çıkış",
"uk_UA": "Ryujinx - Вихід", "uk_UA": "{0} - Вихід",
"zh_CN": "Ryujinx - 退出", "zh_CN": "{0} - 退出",
"zh_TW": "Ryujinx - 結束" "zh_TW": "{0} - 結束"
} }
}, },
{ {
@@ -17025,26 +17050,26 @@
{ {
"ID": "DialogStopEmulationTitle", "ID": "DialogStopEmulationTitle",
"Translations": { "Translations": {
"ar_SA": "ريوجينكس - إيقاف المحاكاة", "ar_SA": "{0} - إيقاف المحاكاة",
"de_DE": "Ryujinx - Beende Emulation", "de_DE": "{0} - Beende Emulation",
"el_GR": "Ryujinx - Διακοπή εξομοίωσης", "el_GR": "{0} - Διακοπή εξομοίωσης",
"en_US": "Ryujinx - Stop Emulation", "en_US": "{0} - Stop Emulation",
"es_ES": "Ryujinx - Detener emulación", "es_ES": "{0} - Detener emulación",
"fr_FR": "Ryujinx - Arrêt de l'émulation", "fr_FR": "{0} - Arrêt de l'émulation",
"he_IL": "ריוג'ינקס - עצור אמולציה", "he_IL": "{0} - עצור אמולציה",
"it_IT": "Ryujinx - Ferma emulazione", "it_IT": "{0} - Ferma emulazione",
"ja_JP": "Ryujinx - エミュレーションを中止", "ja_JP": "{0} - エミュレーションを中止",
"ko_KR": "Ryujinx - 에뮬레이션 중지", "ko_KR": "{0} - 에뮬레이션 중지",
"no_NO": "Ryujinx - Stopp emulasjon", "no_NO": "{0} - Stopp emulasjon",
"pl_PL": "Ryujinx - Zatrzymaj Emulację", "pl_PL": "{0} - Zatrzymaj Emulację",
"pt_BR": "Ryujinx - Parar emulação", "pt_BR": "{0} - Parar emulação",
"ru_RU": "Ryujinx - Остановка эмуляции", "ru_RU": "{0} - Остановка эмуляции",
"sv_SE": "Ryujinx - Stoppa emulering", "sv_SE": "{0} - Stoppa emulering",
"th_TH": "Ryujinx - หยุดการจำลอง", "th_TH": "{0} - หยุดการจำลอง",
"tr_TR": "Ryujinx - Emülasyonu Durdur", "tr_TR": "{0} - Emülasyonu Durdur",
"uk_UA": "Ryujinx - Зупинити емуляцію", "uk_UA": "{0} - Зупинити емуляцію",
"zh_CN": "Ryujinx - 停止模拟", "zh_CN": "{0} - 停止模拟",
"zh_TW": "Ryujinx - 停止模擬" "zh_TW": "{0} - 停止模擬"
} }
}, },
{ {
@@ -17950,51 +17975,51 @@
{ {
"ID": "RyujinxInfo", "ID": "RyujinxInfo",
"Translations": { "Translations": {
"ar_SA": "ريوجينكس - معلومات", "ar_SA": "{0} - معلومات",
"de_DE": "", "de_DE": "",
"el_GR": "Ryujinx - Πληροφορίες", "el_GR": "{0} - Πληροφορίες",
"en_US": "Ryujinx - Info", "en_US": "{0} - Info",
"es_ES": "", "es_ES": "",
"fr_FR": "", "fr_FR": "",
"he_IL": "ריוג'ינקס - מידע", "he_IL": "{0} - מידע",
"it_IT": "Ryujinx - Informazioni", "it_IT": "{0} - Informazioni",
"ja_JP": "Ryujinx - 情報", "ja_JP": "{0} - 情報",
"ko_KR": "Ryujinx - 정보", "ko_KR": "{0} - 정보",
"no_NO": "Ryujinx - Informasjon", "no_NO": "{0} - Informasjon",
"pl_PL": "", "pl_PL": "",
"pt_BR": "Ryujinx - Informação", "pt_BR": "{0} - Informação",
"ru_RU": "Ryujinx - Информация", "ru_RU": "{0} - Информация",
"sv_SE": "", "sv_SE": "",
"th_TH": "Ryujinx ข้อมูล", "th_TH": "{0} ข้อมูล",
"tr_TR": "Ryujinx - Bilgi", "tr_TR": "{0} - Bilgi",
"uk_UA": "Ryujin x - Інформація", "uk_UA": "{0} - Інформація",
"zh_CN": "Ryujinx - 信息", "zh_CN": "{0} - 信息",
"zh_TW": "Ryujinx - 資訊" "zh_TW": "{0} - 資訊"
} }
}, },
{ {
"ID": "RyujinxConfirm", "ID": "RyujinxConfirm",
"Translations": { "Translations": {
"ar_SA": "ريوجينكس - تأكيد", "ar_SA": "{0} - تأكيد",
"de_DE": "Ryujinx - Bestätigung", "de_DE": "{0} - Bestätigung",
"el_GR": "Ryujinx - Επιβεβαίωση", "el_GR": "{0} - Επιβεβαίωση",
"en_US": "Ryujinx - Confirmation", "en_US": "{0} - Confirmation",
"es_ES": "Ryujinx - Confirmación", "es_ES": "{0} - Confirmación",
"fr_FR": "", "fr_FR": "",
"he_IL": "ריוג'ינקס - אישור", "he_IL": "{0} - אישור",
"it_IT": "Ryujinx - Conferma", "it_IT": "{0} - Conferma",
"ja_JP": "Ryujinx - 確認", "ja_JP": "{0} - 確認",
"ko_KR": "Ryujinx - 확인", "ko_KR": "{0} - 확인",
"no_NO": "Ryujinx - Bekreftelse", "no_NO": "{0} - Bekreftelse",
"pl_PL": "Ryujinx - Potwierdzenie", "pl_PL": "{0} - Potwierdzenie",
"pt_BR": "Ryujinx - Confirmação", "pt_BR": "{0} - Confirmação",
"ru_RU": "Ryujinx - Подтверждение", "ru_RU": "{0} - Подтверждение",
"sv_SE": "Ryujinx - Bekräfta", "sv_SE": "{0} - Bekräfta",
"th_TH": "Ryujinx - ยืนยัน", "th_TH": "{0} - ยืนยัน",
"tr_TR": "Ryujinx - Doğrulama", "tr_TR": "{0} - Doğrulama",
"uk_UA": "Ryujinx - Підтвердження", "uk_UA": "{0} - Підтвердження",
"zh_CN": "Ryujinx - 确认", "zh_CN": "{0} - 确认",
"zh_TW": "Ryujinx - 確認" "zh_TW": "{0} - 確認"
} }
}, },
{ {
@@ -18800,26 +18825,26 @@
{ {
"ID": "RyujinxUpdater", "ID": "RyujinxUpdater",
"Translations": { "Translations": {
"ar_SA": "محدث ريوجينكس", "ar_SA": "محدث {0}",
"de_DE": "Ryujinx - Updater", "de_DE": "",
"el_GR": "Ryujinx Ενημερωτής", "el_GR": "{0} Ενημερωτής",
"en_US": "Ryujinx Updater", "en_US": "{0} Updater",
"es_ES": "Actualizador de Ryujinx", "es_ES": "Actualizador de {0}",
"fr_FR": "Mise à jour de Ryujinx", "fr_FR": "Mise à jour de {0}",
"he_IL": "מעדכן ריוג'ינקס", "he_IL": "מעדכן {0}",
"it_IT": "Aggiornamento di Ryujinx", "it_IT": "Aggiornamento di {0}",
"ja_JP": "Ryujinx アップデータ", "ja_JP": "{0} アップデータ",
"ko_KR": "Ryujinx 업데이터", "ko_KR": "{0} 업데이터",
"no_NO": "Ryujinx Oppgradering", "no_NO": "{0} Oppgradering",
"pl_PL": "Aktualizator Ryujinx", "pl_PL": "Aktualizator {0}",
"pt_BR": "Atualizador do Ryujinx", "pt_BR": "Atualizador do {0}",
"ru_RU": "Ryujinx - Обновление", "ru_RU": "{0} Обновление",
"sv_SE": "Uppdaterare för Ryujinx", "sv_SE": "Uppdaterare för {0}",
"th_TH": "ตัวอัปเดต Ryujinx", "th_TH": "ตัวอัปเดต {0}",
"tr_TR": "Ryujinx Güncelleyicisi", "tr_TR": "{0} Güncelleyicisi",
"uk_UA": "Програма оновлення Ryujinx", "uk_UA": "Програма оновлення {0}",
"zh_CN": "Ryujinx 更新", "zh_CN": "{0} 更新",
"zh_TW": "Ryujinx 更新程式" "zh_TW": "{0} 更新程式"
} }
}, },
{ {
@@ -23198,4 +23223,4 @@
} }
} }
] ]
} }
+1 -5
View File
@@ -337,7 +337,7 @@ namespace Ryujinx.Ava.Common
if (publicDataNca is null) if (publicDataNca is null)
{ {
Logger.Error?.Print(LogClass.Application, "Extraction failure. The NCA was not present in the selected file"); Logger.Error?.Print(LogClass.Application, "Extraction failure. The PublicData NCA was not present in the selected file");
Dispatcher.UIThread.InvokeAsync(async () => Dispatcher.UIThread.InvokeAsync(async () =>
{ {
@@ -349,10 +349,6 @@ namespace Ryujinx.Ava.Common
return; return;
} }
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid
: IntegrityCheckLevel.None;
int index = Nca.GetSectionIndexFromType(NcaSectionType.Data, publicDataNca.Header.ContentType); int index = Nca.GetSectionIndexFromType(NcaSectionType.Data, publicDataNca.Header.ContentType);
try try
+16 -1
View File
@@ -44,6 +44,16 @@ namespace Ryujinx.Ava.Common.Locale
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
} }
SetDynamicValues(LocaleKeys.DialogConfirmationTitle, RyujinxApp.FullAppName);
SetDynamicValues(LocaleKeys.DialogUpdaterTitle, RyujinxApp.FullAppName);
SetDynamicValues(LocaleKeys.DialogErrorTitle, RyujinxApp.FullAppName);
SetDynamicValues(LocaleKeys.DialogWarningTitle, RyujinxApp.FullAppName);
SetDynamicValues(LocaleKeys.DialogExitTitle, RyujinxApp.FullAppName);
SetDynamicValues(LocaleKeys.DialogStopEmulationTitle, RyujinxApp.FullAppName);
SetDynamicValues(LocaleKeys.RyujinxInfo, RyujinxApp.FullAppName);
SetDynamicValues(LocaleKeys.RyujinxConfirm, RyujinxApp.FullAppName);
SetDynamicValues(LocaleKeys.RyujinxUpdater, RyujinxApp.FullAppName);
} }
public string this[LocaleKeys key] public string this[LocaleKeys key]
@@ -88,11 +98,16 @@ namespace Ryujinx.Ava.Common.Locale
public static string FormatDynamicValue(LocaleKeys key, params object[] values) public static string FormatDynamicValue(LocaleKeys key, params object[] values)
=> Instance.UpdateAndGetDynamicValue(key, values); => Instance.UpdateAndGetDynamicValue(key, values);
public string UpdateAndGetDynamicValue(LocaleKeys key, params object[] values) public void SetDynamicValues(LocaleKeys key, params object[] values)
{ {
_dynamicValues[key] = values; _dynamicValues[key] = values;
OnPropertyChanged("Translation"); OnPropertyChanged("Translation");
}
public string UpdateAndGetDynamicValue(LocaleKeys key, params object[] values)
{
SetDynamicValues(key, values);
return this[key]; return this[key];
} }
+2 -1
View File
@@ -23,6 +23,7 @@ using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.Input; using Ryujinx.Input;
using Ryujinx.Input.HLE; using Ryujinx.Input.HLE;
using Ryujinx.Input.SDL2; using Ryujinx.Input.SDL2;
using Ryujinx.Input.SDL3;
using Ryujinx.SDL2.Common; using Ryujinx.SDL2.Common;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -182,7 +183,7 @@ namespace Ryujinx.Headless
_accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient, option.UserProfile); _accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient, option.UserProfile);
_userChannelPersistence = new UserChannelPersistence(); _userChannelPersistence = new UserChannelPersistence();
_inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver()); _inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver(), new SDL3MotionDriver());
GraphicsConfig.EnableShaderCache = !option.DisableShaderCache; GraphicsConfig.EnableShaderCache = !option.DisableShaderCache;
+1
View File
@@ -76,6 +76,7 @@
<ProjectReference Include="..\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj" />
<ProjectReference Include="..\Ryujinx.Input\Ryujinx.Input.csproj" /> <ProjectReference Include="..\Ryujinx.Input\Ryujinx.Input.csproj" />
<ProjectReference Include="..\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj" /> <ProjectReference Include="..\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj" />
<ProjectReference Include="..\Ryujinx.Input.SDL3\Ryujinx.Input.SDL3.csproj" />
<ProjectReference Include="..\Ryujinx.Audio.Backends.OpenAL\Ryujinx.Audio.Backends.OpenAL.csproj" /> <ProjectReference Include="..\Ryujinx.Audio.Backends.OpenAL\Ryujinx.Audio.Backends.OpenAL.csproj" />
<ProjectReference Include="..\Ryujinx.Audio.Backends.SoundIo\Ryujinx.Audio.Backends.SoundIo.csproj" /> <ProjectReference Include="..\Ryujinx.Audio.Backends.SoundIo\Ryujinx.Audio.Backends.SoundIo.csproj" />
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" /> <ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
+4 -4
View File
@@ -22,12 +22,12 @@ namespace Ryujinx.Ava
{ {
public class RyujinxApp : Application public class RyujinxApp : Application
{ {
internal static string FormatTitle(LocaleKeys? windowTitleKey = null) internal static string FormatTitle(LocaleKeys? windowTitleKey = null, bool includeVersion = true)
=> windowTitleKey is null => windowTitleKey is null
? $"{FullAppName} {Program.Version}" ? $"{FullAppName}{(includeVersion ? $" {Program.Version}" : string.Empty)}"
: $"{FullAppName} {Program.Version} - {LocaleManager.Instance[windowTitleKey.Value]}"; : $"{FullAppName}{(includeVersion ? $" {Program.Version}" : string.Empty)} - {LocaleManager.Instance[windowTitleKey.Value]}";
public static readonly string FullAppName = ReleaseInformation.IsCanaryBuild ? "Ryujinx Canary" : "Ryujinx"; public static readonly string FullAppName = string.Intern(ReleaseInformation.IsCanaryBuild ? "Ryujinx Canary" : "Ryujinx");
public static MainWindow MainWindow => Current! public static MainWindow MainWindow => Current!
.ApplicationLifetime.Cast<IClassicDesktopStyleApplicationLifetime>() .ApplicationLifetime.Cast<IClassicDesktopStyleApplicationLifetime>()
@@ -159,6 +159,7 @@ namespace Ryujinx.Ava.UI.Helpers
Symbol = (Symbol)symbol, Symbol = (Symbol)symbol,
Margin = new Thickness(10), Margin = new Thickness(10),
FontSize = 40, FontSize = 40,
FlowDirection = FlowDirection.LeftToRight,
VerticalAlignment = VerticalAlignment.Center, VerticalAlignment = VerticalAlignment.Center,
}; };
@@ -10,6 +10,7 @@ namespace Ryujinx.Ava.UI.Models.Input
public partial class GamepadInputConfig : BaseModel public partial class GamepadInputConfig : BaseModel
{ {
public bool EnableCemuHookMotion { get; set; } public bool EnableCemuHookMotion { get; set; }
public bool EnableHandheldMotion { get; set; }
public string DsuServerHost { get; set; } public string DsuServerHost { get; set; }
public int DsuServerPort { get; set; } public int DsuServerPort { get; set; }
public int Slot { get; set; } public int Slot { get; set; }
@@ -162,7 +163,7 @@ namespace Ryujinx.Ava.UI.Models.Input
EnableMotion = controllerInput.Motion.EnableMotion; EnableMotion = controllerInput.Motion.EnableMotion;
GyroDeadzone = controllerInput.Motion.GyroDeadzone; GyroDeadzone = controllerInput.Motion.GyroDeadzone;
Sensitivity = controllerInput.Motion.Sensitivity; Sensitivity = controllerInput.Motion.Sensitivity;
EnableHandheldMotion = controllerInput.Motion.MotionBackend == MotionInputBackendType.Handheld;
if (controllerInput.Motion is CemuHookMotionConfigController cemuHook) if (controllerInput.Motion is CemuHookMotionConfigController cemuHook)
{ {
EnableCemuHookMotion = true; EnableCemuHookMotion = true;
@@ -285,7 +286,7 @@ namespace Ryujinx.Ava.UI.Models.Input
config.Motion = new StandardMotionConfigController config.Motion = new StandardMotionConfigController
{ {
EnableMotion = EnableMotion, EnableMotion = EnableMotion,
MotionBackend = MotionInputBackendType.GamepadDriver, MotionBackend = EnableHandheldMotion ? MotionInputBackendType.Handheld : MotionInputBackendType.GamepadDriver,
GyroDeadzone = GyroDeadzone, GyroDeadzone = GyroDeadzone,
Sensitivity = Sensitivity, Sensitivity = Sensitivity,
}; };
@@ -1,3 +1,4 @@
using Ryujinx.Common.Helper;
using SharpMetal.QuartzCore; using SharpMetal.QuartzCore;
using System; using System;
@@ -7,14 +8,12 @@ namespace Ryujinx.Ava.UI.Renderer
{ {
public CAMetalLayer CreateSurface() public CAMetalLayer CreateSurface()
{ {
if (OperatingSystem.IsMacOS()) if (OperatingSystem.IsMacOS() && RunningPlatform.IsArm)
{ {
return new CAMetalLayer(MetalLayer); return new CAMetalLayer(MetalLayer);
} }
else
{ throw new NotSupportedException($"Cannot create a {nameof(CAMetalLayer)} without being on ARM Mac.");
throw new NotSupportedException();
}
} }
} }
} }
+13 -13
View File
@@ -43,19 +43,19 @@ namespace Ryujinx.Ava.UI.Renderer
public RendererHost(string titleId) public RendererHost(string titleId)
{ {
switch (TitleIDs.SelectGraphicsBackend(titleId, ConfigurationState.Instance.Graphics.GraphicsBackend)) Focusable = true;
{ FlowDirection = FlowDirection.LeftToRight;
case GraphicsBackend.OpenGl:
EmbeddedWindow = new EmbeddedWindowOpenGL(); EmbeddedWindow =
break; #pragma warning disable CS8509
case GraphicsBackend.Metal: TitleIDs.SelectGraphicsBackend(titleId, ConfigurationState.Instance.Graphics.GraphicsBackend) switch
EmbeddedWindow = new EmbeddedWindowMetal(); #pragma warning restore CS8509
break; {
case GraphicsBackend.Vulkan: GraphicsBackend.OpenGl => new EmbeddedWindowOpenGL(),
EmbeddedWindow = new EmbeddedWindowVulkan(); GraphicsBackend.Metal => new EmbeddedWindowMetal(),
break; GraphicsBackend.Vulkan => new EmbeddedWindowVulkan(),
} };
string backendText = EmbeddedWindow switch string backendText = EmbeddedWindow switch
{ {
EmbeddedWindowVulkan => "Vulkan", EmbeddedWindowVulkan => "Vulkan",
@@ -18,6 +18,34 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
[ObservableProperty] private double _gyroDeadzone; [ObservableProperty] private double _gyroDeadzone;
[ObservableProperty] private bool _enableCemuHookMotion; private bool _enableCemuHookMotion;
public bool EnableCemuHookMotion
{
get => _enableCemuHookMotion;
set
{
if (value)
{
EnableHandheldMotion = false;
}
_enableCemuHookMotion = value;
OnPropertyChanged();
}
}
private bool _enableHandheldMotion;
public bool EnableHandheldMotion
{
get => _enableHandheldMotion;
set
{
if (value)
{
EnableCemuHookMotion = false;
}
_enableHandheldMotion = value;
OnPropertyChanged();
}
}
} }
} }
@@ -61,6 +61,17 @@
Margin="5, 0" Margin="5, 0"
Text="{Binding GyroDeadzone, StringFormat=\{0:0.00\}}" /> Text="{Binding GyroDeadzone, StringFormat=\{0:0.00\}}" />
</StackPanel> </StackPanel>
<Separator
Height="1"
Margin="0,5" />
<CheckBox
Margin="5"
IsChecked="{Binding EnableHandheldMotion}">
<TextBlock
Margin="0,3,0,0"
VerticalAlignment="Center"
Text="{ext:Locale ControllerSettingsMotionUseHandheldCompatibleMotion}" />
</CheckBox>
<Separator <Separator
Height="1" Height="1"
Margin="0,5" /> Margin="0,5" />
@@ -30,6 +30,7 @@ namespace Ryujinx.Ava.UI.Views.Input
Sensitivity = config.Sensitivity, Sensitivity = config.Sensitivity,
GyroDeadzone = config.GyroDeadzone, GyroDeadzone = config.GyroDeadzone,
EnableCemuHookMotion = config.EnableCemuHookMotion, EnableCemuHookMotion = config.EnableCemuHookMotion,
EnableHandheldMotion = config.EnableHandheldMotion,
}; };
InitializeComponent(); InitializeComponent();
@@ -58,6 +59,7 @@ namespace Ryujinx.Ava.UI.Views.Input
config.DsuServerHost = content._viewModel.DsuServerHost; config.DsuServerHost = content._viewModel.DsuServerHost;
config.DsuServerPort = content._viewModel.DsuServerPort; config.DsuServerPort = content._viewModel.DsuServerPort;
config.EnableCemuHookMotion = content._viewModel.EnableCemuHookMotion; config.EnableCemuHookMotion = content._viewModel.EnableCemuHookMotion;
config.EnableHandheldMotion = content._viewModel.EnableHandheldMotion;
config.MirrorInput = content._viewModel.MirrorInput; config.MirrorInput = content._viewModel.MirrorInput;
}; };
+3 -2
View File
@@ -29,6 +29,7 @@ using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.Input.HLE; using Ryujinx.Input.HLE;
using Ryujinx.Input.SDL2; using Ryujinx.Input.SDL2;
using Ryujinx.Input.SDL3;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -107,7 +108,7 @@ namespace Ryujinx.Ava.UI.Windows
if (Program.PreviewerDetached) if (Program.PreviewerDetached)
{ {
InputManager = new InputManager(new AvaloniaKeyboardDriver(this), new SDL2GamepadDriver()); InputManager = new InputManager(new AvaloniaKeyboardDriver(this), new SDL2GamepadDriver(), new SDL3MotionDriver());
_ = this.GetObservable(IsActiveProperty).Subscribe(it => ViewModel.IsActive = it); _ = this.GetObservable(IsActiveProperty).Subscribe(it => ViewModel.IsActive = it);
this.ScalingChanged += OnScalingChanged; this.ScalingChanged += OnScalingChanged;
@@ -302,7 +303,7 @@ namespace Ryujinx.Ava.UI.Windows
LinuxHelper.RecommendedVmMaxMapCount); LinuxHelper.RecommendedVmMaxMapCount);
UserResult response = await ContentDialogHelper.ShowTextDialog( UserResult response = await ContentDialogHelper.ShowTextDialog(
$"Ryujinx - {LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountDialogTitle]}", RyujinxApp.FormatTitle(LocaleKeys.LinuxVmMaxMapCountDialogTitle, false),
LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountDialogTextPrimary], LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountDialogTextPrimary],
LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountDialogTextSecondary], LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountDialogTextSecondary],
LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountDialogButtonUntilRestart], LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountDialogButtonUntilRestart],