mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-02-19 23:31:07 +00:00
Compare commits
7 Commits
Canary-1.3
...
224142b9c5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
224142b9c5 | ||
|
|
d1205dc95d | ||
|
|
6f95172bb6 | ||
|
|
8208d43d9e | ||
|
|
1260f93aaf | ||
|
|
1b3bf1473d | ||
|
|
081cdcab0c |
@@ -21,7 +21,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_CN": "启动 RenderDoc 帧捕获",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
@@ -46,7 +46,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_CN": "结束 RenderDoc 帧捕获",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
@@ -71,7 +71,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_CN": "丢弃 RenderDoc 帧捕获",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
@@ -96,7 +96,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_CN": "结束当前正在进行的 RenderDoc 帧捕获,并立即丢弃其结果。",
|
||||
"zh_TW": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2050,7 +2050,9 @@
|
||||
010003C00B868000,"Ninjin: Clash of Carrots",online-broken,playable,2024-07-10 05:12:26
|
||||
0100746010E4C000,"NinNinDays",,playable,2022-11-20 15:17:29
|
||||
0100C9A00ECE6000,"Nintendo 64™ – Nintendo Switch Online",gpu;vulkan,ingame,2024-04-23 20:21:07
|
||||
010057D00ECE4000,"Nintendo 64™ – Nintendo Switch Online",gpu;vulkan,ingame,2024-04-23 20:21:07
|
||||
0100e0601c632000,"Nintendo 64™ – Nintendo Switch Online: MATURE 17+",,ingame,2025-02-03 22:27:00
|
||||
010037A0170D2000,"NINTENDO 64™ – Nintendo Switch Online 18+",,ingame,2025-02-03 22:27:00
|
||||
0100D870045B6000,"Nintendo Entertainment System™ - Nintendo Switch Online",online,playable,2022-07-01 15:45:06
|
||||
0100C4B0034B2000,"Nintendo Labo Toy-Con 01 Variety Kit",gpu,ingame,2022-08-07 12:56:07
|
||||
01001E9003502000,"Nintendo Labo Toy-Con 03 Vehicle Kit",services;crash,menus,2022-08-03 17:20:11
|
||||
@@ -2638,6 +2640,7 @@
|
||||
0100B16009C10000,"SINNER: Sacrifice for Redemption",nvdec;UE4;vulkan-backend-bug,playable,2022-08-12 20:37:33
|
||||
0100E9201410E000,"Sir Lovelot",,playable,2021-04-05 16:21:46
|
||||
0100134011E32000,"Skate City",,playable,2022-11-04 11:37:39
|
||||
0100a8501b66e000,"Skateboard Drifting with Maxwell Cat: The Game Simulator",,playable,2026-02-17 19:05:00
|
||||
0100B2F008BD8000,"Skee-Ball",,playable,2020-11-16 04:44:07
|
||||
01001A900F862000,"Skelattack",,playable,2021-06-09 15:26:26
|
||||
01008E700F952000,"Skelittle: A Giant Party!",,playable,2021-06-09 19:08:34
|
||||
@@ -3307,6 +3310,7 @@
|
||||
0100AFA011068000,"Voxel Pirates",,playable,2022-09-28 22:55:02
|
||||
0100BFB00D1F4000,"Voxel Sword",,playable,2022-08-30 14:57:27
|
||||
01004E90028A2000,"Vroom in the night sky",Needs Update;vulkan-backend-bug,playable,2023-02-20 02:32:29
|
||||
0100BFC01D976000,"Virtual Boy – Nintendo Classics",services,nothing,2026-02-17 11:26:59
|
||||
0100C7C00AE6C000,"VSR: Void Space Racing",,playable,2021-01-27 14:08:59
|
||||
0100B130119D0000,"Waifu Uncovered",crash,ingame,2023-02-27 01:17:46
|
||||
0100E29010A4A000,"Wanba Warriors",,playable,2020-10-04 17:56:22
|
||||
|
||||
|
@@ -22,10 +22,11 @@ namespace Ryujinx.Common.Utilities
|
||||
}
|
||||
|
||||
// "dumpable" attribute of the calling process
|
||||
private const int PR_GET_DUMPABLE = 3;
|
||||
private const int PR_SET_DUMPABLE = 4;
|
||||
|
||||
[DllImport("libc", SetLastError = true)]
|
||||
private static extern int prctl(int option, int arg2);
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int prctl(int option, int arg2);
|
||||
|
||||
public static void SetCoreDumpable(bool dumpable)
|
||||
{
|
||||
@@ -36,5 +37,13 @@ namespace Ryujinx.Common.Utilities
|
||||
Debug.Assert(result == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Use the below line to display dumpable status in the console:
|
||||
// Console.WriteLine($"{OsUtils.IsCoreDumpable()}");
|
||||
public static bool IsCoreDumpable()
|
||||
{
|
||||
int result = prctl(PR_GET_DUMPABLE, 0);
|
||||
return result == 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,20 @@ using static SDL.SDL3;
|
||||
|
||||
namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
|
||||
|
||||
public unsafe class SDL3GamepadDriver : IGamepadDriver
|
||||
{
|
||||
private readonly Dictionary<SDL_JoystickID, string> _gamepadsInstanceIdsMapping;
|
||||
private readonly Dictionary<SDL_JoystickID, string> _gamepadsIds;
|
||||
/// <summary>
|
||||
/// Unlinked joy-cons
|
||||
/// </summary>
|
||||
private readonly Dictionary<SDL_JoystickID, string> _joyConsIds;
|
||||
/// <summary>
|
||||
/// Linked joy-cons, remove dual joy-con from <c>_gamepadsIds</c> when a linked joy-con is removed
|
||||
/// </summary>
|
||||
private readonly Dictionary<SDL_JoystickID,string> _linkedJoyConsIds;
|
||||
private readonly Lock _lock = new();
|
||||
|
||||
public ReadOnlySpan<string> GamepadsIds
|
||||
@@ -21,7 +31,11 @@ namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _gamepadsIds.Values.ToArray();
|
||||
List<string> temp = [];
|
||||
temp.AddRange(_gamepadsIds.Values);
|
||||
temp.AddRange(_joyConsIds.Values);
|
||||
temp.AddRange(_linkedJoyConsIds.Values);
|
||||
return temp.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +49,8 @@ namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
_gamepadsInstanceIdsMapping = new Dictionary<SDL_JoystickID, string>();
|
||||
_gamepadsIds = [];
|
||||
_joyConsIds = [];
|
||||
_linkedJoyConsIds = [];
|
||||
|
||||
SDL3Driver.Instance.Initialize();
|
||||
SDL3Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected;
|
||||
@@ -92,7 +108,7 @@ namespace Ryujinx.Input.SDL3
|
||||
int guidIndex = 0;
|
||||
id = guidIndex + "-" + guidString;
|
||||
|
||||
while (_gamepadsIds.ContainsValue(id))
|
||||
while (_gamepadsIds.ContainsValue(id) || _joyConsIds.ContainsValue(id) || _linkedJoyConsIds.ContainsValue(id))
|
||||
{
|
||||
id = (++guidIndex) + "-" + guidString;
|
||||
}
|
||||
@@ -104,16 +120,47 @@ namespace Ryujinx.Input.SDL3
|
||||
private void HandleJoyStickDisconnected(SDL_JoystickID joystickInstanceId)
|
||||
{
|
||||
bool joyConPairDisconnected = false;
|
||||
string fakeId = null;
|
||||
|
||||
if (!_gamepadsInstanceIdsMapping.Remove(joystickInstanceId, out string id))
|
||||
return;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_gamepadsIds.Remove(joystickInstanceId);
|
||||
if (!SDL3JoyConPair.IsCombinable(_gamepadsIds))
|
||||
if (!_linkedJoyConsIds.ContainsKey(joystickInstanceId))
|
||||
{
|
||||
_gamepadsIds.Remove(GetInstanceIdFromId(SDL3JoyConPair.Id));
|
||||
if (!_joyConsIds.Remove(joystickInstanceId))
|
||||
{
|
||||
_gamepadsIds.Remove(joystickInstanceId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string matchId in _gamepadsIds.Values)
|
||||
{
|
||||
if (matchId.Contains(id))
|
||||
{
|
||||
fakeId = matchId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string leftId = fakeId!.Split('_')[0];
|
||||
string rightId = fakeId!.Split('_')[1];
|
||||
|
||||
if (leftId == id)
|
||||
{
|
||||
_linkedJoyConsIds.Remove(GetInstanceIdFromId(rightId));
|
||||
_joyConsIds.Add(GetInstanceIdFromId(rightId), rightId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_linkedJoyConsIds.Remove(GetInstanceIdFromId(leftId));
|
||||
_joyConsIds.Add(GetInstanceIdFromId(leftId), leftId);
|
||||
}
|
||||
|
||||
_linkedJoyConsIds.Remove(joystickInstanceId);
|
||||
_gamepadsIds.Remove(GetInstanceIdFromId(fakeId));
|
||||
joyConPairDisconnected = true;
|
||||
}
|
||||
}
|
||||
@@ -121,13 +168,14 @@ namespace Ryujinx.Input.SDL3
|
||||
OnGamepadDisconnected?.Invoke(id);
|
||||
if (joyConPairDisconnected)
|
||||
{
|
||||
OnGamepadDisconnected?.Invoke(SDL3JoyConPair.Id);
|
||||
OnGamepadDisconnected?.Invoke(fakeId);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleJoyStickConnected(SDL_JoystickID joystickInstanceId)
|
||||
{
|
||||
bool joyConPairConnected = false;
|
||||
string fakeId = null;
|
||||
|
||||
if (SDL_IsGamepad(joystickInstanceId))
|
||||
{
|
||||
@@ -149,27 +197,40 @@ namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
|
||||
_gamepadsIds.Add(joystickInstanceId, id);
|
||||
|
||||
if (SDL3JoyConPair.IsCombinable(_gamepadsIds))
|
||||
if (!SDL3JoyCon.IsJoyCon(joystickInstanceId))
|
||||
{
|
||||
// TODO - It appears that you can only have one joy con pair connected at a time?
|
||||
// This was also the behavior before SDL3
|
||||
_gamepadsIds.Remove(GetInstanceIdFromId(SDL3JoyConPair.Id));
|
||||
uint fakeInstanceID = uint.MaxValue;
|
||||
while (!_gamepadsIds.TryAdd((SDL_JoystickID)fakeInstanceID, SDL3JoyConPair.Id))
|
||||
_gamepadsIds.Add(joystickInstanceId, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SDL3JoyConPair.IsCombinable(joystickInstanceId, _joyConsIds, out SDL_JoystickID match))
|
||||
{
|
||||
fakeInstanceID--;
|
||||
_joyConsIds.Remove(match, out string matchId);
|
||||
_linkedJoyConsIds.Add(joystickInstanceId, id);
|
||||
_linkedJoyConsIds.Add(match, matchId);
|
||||
|
||||
uint fakeInstanceId = uint.MaxValue;
|
||||
fakeId = SDL3JoyCon.IsLeftJoyCon(joystickInstanceId)
|
||||
? $"{id}_{matchId}"
|
||||
: $"{matchId}_{id}";
|
||||
while (!_gamepadsIds.TryAdd((SDL_JoystickID)fakeInstanceId, fakeId))
|
||||
{
|
||||
fakeInstanceId--;
|
||||
}
|
||||
_gamepadsInstanceIdsMapping.Add((SDL_JoystickID)fakeInstanceId, fakeId);
|
||||
joyConPairConnected = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_joyConsIds.Add(joystickInstanceId, id);
|
||||
}
|
||||
joyConPairConnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
OnGamepadConnected?.Invoke(id);
|
||||
if (joyConPairConnected)
|
||||
{
|
||||
OnGamepadConnected?.Invoke(SDL3JoyConPair.Id);
|
||||
OnGamepadConnected?.Invoke(fakeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,10 +254,22 @@ namespace Ryujinx.Input.SDL3
|
||||
{
|
||||
OnGamepadDisconnected?.Invoke(gamepad.Value);
|
||||
}
|
||||
|
||||
foreach (var gamepad in _joyConsIds)
|
||||
{
|
||||
OnGamepadDisconnected?.Invoke(gamepad.Value);
|
||||
}
|
||||
|
||||
foreach (var gamepad in _linkedJoyConsIds)
|
||||
{
|
||||
OnGamepadDisconnected?.Invoke(gamepad.Value);
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_gamepadsIds.Clear();
|
||||
_joyConsIds.Clear();
|
||||
_linkedJoyConsIds.Clear();
|
||||
}
|
||||
|
||||
SDL3Driver.Instance.Dispose();
|
||||
@@ -215,11 +288,27 @@ namespace Ryujinx.Input.SDL3
|
||||
|
||||
public IGamepad GetGamepad(string id)
|
||||
{
|
||||
if (id == SDL3JoyConPair.Id)
|
||||
// joy-con pair ids is the combined ids of its parts which are split using a '_'
|
||||
if (id.Contains('_'))
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return SDL3JoyConPair.GetGamepad(_gamepadsIds);
|
||||
string leftId = id.Split('_')[0];
|
||||
string rightId = id.Split('_')[1];
|
||||
|
||||
SDL_JoystickID leftInstanceId = GetInstanceIdFromId(leftId);
|
||||
SDL_JoystickID rightInstanceId = GetInstanceIdFromId(rightId);
|
||||
|
||||
SDL_Gamepad* leftGamepadHandle = SDL_OpenGamepad(leftInstanceId);
|
||||
SDL_Gamepad* rightGamepadHandle = SDL_OpenGamepad(rightInstanceId);
|
||||
|
||||
if (leftGamepadHandle == null || rightGamepadHandle == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SDL3JoyConPair(new SDL3JoyCon(leftGamepadHandle, leftId),
|
||||
new SDL3JoyCon(rightGamepadHandle, rightId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +321,7 @@ namespace Ryujinx.Input.SDL3
|
||||
return null;
|
||||
}
|
||||
|
||||
if (SDL_GetGamepadName(gamepadHandle).StartsWith(SDL3JoyCon.Prefix))
|
||||
if (SDL3JoyCon.IsJoyCon(instanceId))
|
||||
{
|
||||
return new SDL3JoyCon(gamepadHandle, id);
|
||||
}
|
||||
@@ -249,6 +338,22 @@ namespace Ryujinx.Input.SDL3
|
||||
yield return GetGamepad(gamepad.Value);
|
||||
}
|
||||
}
|
||||
|
||||
lock (_joyConsIds)
|
||||
{
|
||||
foreach (var gamepad in _joyConsIds)
|
||||
{
|
||||
yield return GetGamepad(gamepad.Value);
|
||||
}
|
||||
}
|
||||
|
||||
lock (_linkedJoyConsIds)
|
||||
{
|
||||
foreach (var gamepad in _linkedJoyConsIds)
|
||||
{
|
||||
yield return GetGamepad(gamepad.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,10 @@ namespace Ryujinx.Input.SDL3
|
||||
private readonly Dictionary<GamepadButtonInputId, SDL_GamepadButton> _leftButtonsDriverMapping = new()
|
||||
{
|
||||
{GamepadButtonInputId.LeftStick, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_STICK},
|
||||
{GamepadButtonInputId.DpadUp, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH},
|
||||
{GamepadButtonInputId.DpadDown, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH},
|
||||
{GamepadButtonInputId.DpadLeft, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST},
|
||||
{GamepadButtonInputId.DpadRight, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST},
|
||||
{GamepadButtonInputId.DpadUp, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST},
|
||||
{GamepadButtonInputId.DpadDown, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST},
|
||||
{GamepadButtonInputId.DpadLeft, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH},
|
||||
{GamepadButtonInputId.DpadRight, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH},
|
||||
{GamepadButtonInputId.Minus, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_START},
|
||||
{GamepadButtonInputId.LeftShoulder, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_PADDLE1},
|
||||
{GamepadButtonInputId.LeftTrigger, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_PADDLE2},
|
||||
@@ -37,10 +37,10 @@ namespace Ryujinx.Input.SDL3
|
||||
private readonly Dictionary<GamepadButtonInputId, SDL_GamepadButton> _rightButtonsDriverMapping = new()
|
||||
{
|
||||
{GamepadButtonInputId.RightStick, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_STICK},
|
||||
{GamepadButtonInputId.A, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST},
|
||||
{GamepadButtonInputId.B, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH},
|
||||
{GamepadButtonInputId.X, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH},
|
||||
{GamepadButtonInputId.Y, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST},
|
||||
{GamepadButtonInputId.A, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH},
|
||||
{GamepadButtonInputId.B, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST},
|
||||
{GamepadButtonInputId.X, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST},
|
||||
{GamepadButtonInputId.Y, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH},
|
||||
{GamepadButtonInputId.Plus, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_START},
|
||||
{GamepadButtonInputId.RightShoulder, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1},
|
||||
{GamepadButtonInputId.RightTrigger, SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2},
|
||||
@@ -398,5 +398,15 @@ namespace Ryujinx.Input.SDL3
|
||||
|
||||
return SDL_GetGamepadButton(_gamepadHandle, button);
|
||||
}
|
||||
|
||||
public static bool IsJoyCon(SDL_JoystickID gamepadsId)
|
||||
{
|
||||
return SDL_GetGamepadNameForID(gamepadsId) is LeftName or RightName;
|
||||
}
|
||||
|
||||
public static bool IsLeftJoyCon(SDL_JoystickID gamepadsId)
|
||||
{
|
||||
return SDL_GetGamepadNameForID(gamepadsId) is LeftName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Ryujinx.Input.SDL3
|
||||
public const string Id = "JoyConPair";
|
||||
string IGamepad.Id => Id;
|
||||
|
||||
public string Name => "* Nintendo Switch Joy-Con (L/R)";
|
||||
public string Name => "Nintendo Switch Dual Joy-Con (L/R)";
|
||||
public bool IsConnected => left is { IsConnected: true } && right is { IsConnected: true };
|
||||
|
||||
public void Dispose()
|
||||
@@ -96,44 +96,23 @@ namespace Ryujinx.Input.SDL3
|
||||
right.SetTriggerThreshold(triggerThreshold);
|
||||
}
|
||||
|
||||
public static bool IsCombinable(Dictionary<SDL_JoystickID, string> gamepadsIds)
|
||||
public static bool IsCombinable(SDL_JoystickID joyCon1, Dictionary<SDL_JoystickID, string> joyConIds, out SDL_JoystickID match)
|
||||
{
|
||||
(int leftIndex, int rightIndex) = DetectJoyConPair(gamepadsIds);
|
||||
return leftIndex >= 0 && rightIndex >= 0;
|
||||
}
|
||||
bool isLeft = SDL3JoyCon.IsLeftJoyCon(joyCon1);
|
||||
string matchName = isLeft ? SDL3JoyCon.RightName : SDL3JoyCon.LeftName;
|
||||
match = 0;
|
||||
|
||||
private static (int leftIndex, int rightIndex) DetectJoyConPair(Dictionary<SDL_JoystickID, string> gamepadsIds)
|
||||
{
|
||||
Dictionary<string, SDL_JoystickID> gamepadNames = gamepadsIds
|
||||
.Where(gamepadId => gamepadId.Value != Id && SDL_GetGamepadNameForID(gamepadId.Key) is SDL3JoyCon.LeftName or SDL3JoyCon.RightName)
|
||||
.Select(gamepad => (SDL_GetGamepadNameForID(gamepad.Key), gamepad.Key))
|
||||
.ToDictionary();
|
||||
SDL_JoystickID idx;
|
||||
int leftIndex = gamepadNames.TryGetValue(SDL3JoyCon.LeftName, out idx) ? (int)idx : -1;
|
||||
int rightIndex = gamepadNames.TryGetValue(SDL3JoyCon.RightName, out idx) ? (int)idx : -1;
|
||||
|
||||
return (leftIndex, rightIndex);
|
||||
}
|
||||
|
||||
public unsafe static IGamepad GetGamepad(Dictionary<SDL_JoystickID, string> gamepadsIds)
|
||||
{
|
||||
(int leftIndex, int rightIndex) = DetectJoyConPair(gamepadsIds);
|
||||
|
||||
if (leftIndex <= 0 || rightIndex <= 0)
|
||||
foreach (var joyConId in joyConIds.Keys)
|
||||
{
|
||||
return null;
|
||||
if (SDL_GetGamepadNameForID(joyConId) == matchName)
|
||||
{
|
||||
match = joyConId;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Gamepad* leftGamepadHandle = SDL_OpenGamepad((SDL_JoystickID)leftIndex);
|
||||
SDL_Gamepad* rightGamepadHandle = SDL_OpenGamepad((SDL_JoystickID)rightIndex);
|
||||
|
||||
if (leftGamepadHandle == null || rightGamepadHandle == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SDL3JoyConPair(new SDL3JoyCon(leftGamepadHandle, gamepadsIds[(SDL_JoystickID)leftIndex]),
|
||||
new SDL3JoyCon(rightGamepadHandle, gamepadsIds[(SDL_JoystickID)rightIndex]));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ using Ryujinx.Ava.UI.Windows;
|
||||
using Ryujinx.Ava.Utilities;
|
||||
using Ryujinx.Common.Helper;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||
@@ -410,6 +411,8 @@ namespace Ryujinx.Ava.Common
|
||||
|
||||
public static async Task ExtractAoc(IStorageProvider storageProvider, string updateFilePath, string updateName)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
Gommon.Optional<IStorageFolder> result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle]
|
||||
@@ -419,10 +422,17 @@ namespace Ryujinx.Ava.Common
|
||||
return;
|
||||
|
||||
ExtractAoc(result.Value.Path.LocalPath, updateFilePath, updateName);
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task ExtractSection(IStorageProvider storageProvider, NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
Gommon.Optional<IStorageFolder> result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle]
|
||||
@@ -432,6 +442,11 @@ namespace Ryujinx.Ava.Common
|
||||
return;
|
||||
|
||||
ExtractSection(result.Value.Path.LocalPath, ncaSectionType, titleFilePath, titleName, programIndex);
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath, CancellationToken token)
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace Ryujinx.Ava.Input
|
||||
AvaKey.OemComma,
|
||||
AvaKey.OemPeriod,
|
||||
AvaKey.OemQuestion,
|
||||
AvaKey.OemBackslash,
|
||||
AvaKey.OemPipe,
|
||||
|
||||
// NOTE: invalid
|
||||
AvaKey.None
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace Ryujinx.Ava
|
||||
public static bool PreviewerDetached { get; private set; }
|
||||
public static bool UseHardwareAcceleration { get; private set; }
|
||||
public static string BackendThreadingArg { get; private set; }
|
||||
public static bool CoreDumpArg { get; private set; }
|
||||
|
||||
private const uint MbIconwarning = 0x30;
|
||||
|
||||
@@ -81,6 +82,8 @@ namespace Ryujinx.Ava
|
||||
bool noGuiArg = ConsumeCommandLineArgument(ref args, "--no-gui") || ConsumeCommandLineArgument(ref args, "nogui");
|
||||
bool coreDumpArg = ConsumeCommandLineArgument(ref args, "--core-dumps");
|
||||
|
||||
CoreDumpArg = coreDumpArg;
|
||||
|
||||
// TODO: Ryujinx causes core dumps on Linux when it exits "uncleanly", eg. through an unhandled exception.
|
||||
// This is undesirable and causes very odd behavior during development (the process stops responding,
|
||||
// the .NET debugger freezes or suddenly detaches, /tmp/ gets filled etc.), unless explicitly requested by the user.
|
||||
|
||||
@@ -8,6 +8,7 @@ using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Common.Models;
|
||||
using Ryujinx.Ava.Systems.AppLibrary;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
@@ -128,6 +129,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
public async void Add()
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
IReadOnlyList<IStorageFile> result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle],
|
||||
@@ -158,6 +161,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
await ShowNewDlcAddedDialog(totalDlcAdded);
|
||||
}
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
private bool AddDownloadableContent(string path, out int numDlcAdded)
|
||||
|
||||
@@ -184,7 +184,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
_controller = 0;
|
||||
}
|
||||
|
||||
if (Controllers.Count > 0 && value < Controllers.Count && _controller > -1)
|
||||
if (Controllers.Count > 0 && _controller < Controllers.Count && _controller > -1)
|
||||
{
|
||||
ControllerType controller = Controllers[_controller].Type;
|
||||
|
||||
@@ -467,7 +467,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
IsModified = true;
|
||||
RevertChanges();
|
||||
FindPairedDeviceInConfigFile();
|
||||
|
||||
|
||||
_isChangeTrackingActive = true; // Enable configuration change tracking
|
||||
|
||||
}
|
||||
@@ -521,7 +521,17 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
|
||||
if (Config != null && Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType) != -1)
|
||||
{
|
||||
Controller = Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType);
|
||||
int controllerIndex = Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType);
|
||||
|
||||
// Avalonia bug: setting a newly instanced ComboBox to 0
|
||||
// causes the selected item to show up blank
|
||||
// Workaround: set the box to 1 and then 0
|
||||
if (controllerIndex == 0)
|
||||
{
|
||||
Controller = 1;
|
||||
}
|
||||
|
||||
Controller = controllerIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -576,7 +586,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
DeviceList.Clear();
|
||||
Devices.Add((DeviceType.None, Disabled, LocaleManager.Instance[LocaleKeys.ControllerSettingsDeviceDisabled]));
|
||||
|
||||
int controllerNumber = 0;
|
||||
|
||||
foreach (string id in _mainWindow.InputManager.KeyboardDriver.GamepadsIds)
|
||||
{
|
||||
using IGamepad gamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id);
|
||||
@@ -593,6 +603,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
|
||||
if (gamepad != null)
|
||||
{
|
||||
int controllerNumber = 0;
|
||||
string name = GetUniqueGamepadName(gamepad, ref controllerNumber);
|
||||
Devices.Add((DeviceType.Controller, id, name));
|
||||
}
|
||||
@@ -950,8 +961,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
LoadConfiguration(); // configuration preload is required if the paired gamepad was disconnected but was changed to another gamepad
|
||||
Device = Devices.ToList().FindIndex(d => d.Id == RevertDeviceId);
|
||||
|
||||
LoadDevice();
|
||||
_isLoaded = false;
|
||||
LoadConfiguration();
|
||||
LoadDevice();
|
||||
_isLoaded = true;
|
||||
|
||||
OnPropertyChanged();
|
||||
IsModified = false;
|
||||
|
||||
@@ -1266,6 +1266,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
private async Task LoadContentFromFolder(LocaleKeys localeMessageAddedKey, LocaleKeys localeMessageRemovedKey,
|
||||
LoadContentFromFolderDelegate onDirsSelected, LocaleKeys dirSelectDialogTitle)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
Optional<IReadOnlyList<IStorageFolder>> result =
|
||||
await StorageProvider.OpenMultiFolderPickerAsync(
|
||||
new FolderPickerOpenOptions { Title = LocaleManager.Instance[dirSelectDialogTitle] });
|
||||
@@ -1293,6 +1295,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
(int)Symbol.Checkmark);
|
||||
});
|
||||
}
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1355,6 +1362,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
public async Task InstallFirmwareFromFile()
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
Optional<IStorageFile> result = await StorageProvider.OpenSingleFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
FileTypeFilter = new List<FilePickerFileType>
|
||||
@@ -1384,20 +1393,34 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
await HandleFirmwareInstallation(result.Value.Path.LocalPath);
|
||||
}
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task InstallFirmwareFromFolder()
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
Optional<IStorageFolder> result = await StorageProvider.OpenSingleFolderPickerAsync();
|
||||
|
||||
if (result.HasValue)
|
||||
{
|
||||
await HandleFirmwareInstallation(result.Value.Path.LocalPath);
|
||||
}
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task InstallKeysFromFile()
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
Optional<IStorageFile> result = await StorageProvider.OpenSingleFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
FileTypeFilter = new List<FilePickerFileType>
|
||||
@@ -1415,16 +1438,28 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
await HandleKeysInstallation(result.Value.Path.LocalPath);
|
||||
}
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task InstallKeysFromFolder()
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
Optional<IStorageFolder> result = await StorageProvider.OpenSingleFolderPickerAsync();
|
||||
|
||||
if (result.HasValue)
|
||||
{
|
||||
await HandleKeysInstallation(result.Value.Path.LocalPath);
|
||||
}
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenRyujinxFolder()
|
||||
@@ -1528,6 +1563,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
public async Task OpenFile()
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
Optional<IStorageFile> result = await StorageProvider.OpenSingleFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.LoadApplicationFromFileDialogTitle],
|
||||
@@ -1599,6 +1636,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
LocaleManager.Instance[LocaleKeys.MenuBarFileOpenFromFileError]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task LoadDlcFromFolder()
|
||||
@@ -1621,6 +1663,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
public async Task OpenFolder()
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
Optional<IStorageFolder> result = await StorageProvider.OpenSingleFolderPickerAsync(
|
||||
new FolderPickerOpenOptions
|
||||
{
|
||||
@@ -1636,6 +1680,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
await LoadApplication(applicationData);
|
||||
}
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool InitializeUserConfig(ApplicationData application)
|
||||
@@ -1843,6 +1892,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
public async Task OpenBinFile()
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning)
|
||||
{
|
||||
Optional<IStorageFile> result = await StorageProvider.OpenSingleFilePickerAsync(
|
||||
@@ -1862,6 +1913,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
AppHost.Device.System.ScanAmiiboFromBin(result.Value.Path.LocalPath);
|
||||
}
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -288,6 +288,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
public async void Add()
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
IReadOnlyList<IStorageFolder> result = await _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.SelectModDialogTitle],
|
||||
@@ -298,6 +300,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
AddMod(new DirectoryInfo(folder.Path.LocalPath));
|
||||
}
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteAll()
|
||||
|
||||
@@ -7,6 +7,7 @@ using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Common.Models;
|
||||
using Ryujinx.Ava.Systems.AppLibrary;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -148,6 +149,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
public async Task Add()
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
IReadOnlyList<IStorageFile> result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
AllowMultiple = true,
|
||||
@@ -177,6 +180,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
await ShowNewUpdatesAddedDialog(totalUpdatesAdded);
|
||||
}
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void Save()
|
||||
|
||||
@@ -7,6 +7,7 @@ using Ryujinx.Ava.UI.Controls;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Ava.Utilities;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -27,6 +28,8 @@ namespace Ryujinx.Ava.UI.Views.Settings
|
||||
|
||||
private async Task AddDirButton(TextBox addDirBox, AvaloniaList<string> directories)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
string path = addDirBox.Text;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !directories.Contains(path))
|
||||
@@ -48,6 +51,11 @@ namespace Ryujinx.Ava.UI.Views.Settings
|
||||
ViewModel.GameListNeedsRefresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveGameDirButton_OnClick(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -8,6 +8,7 @@ using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Controls;
|
||||
using Ryujinx.Ava.UI.Models;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using SkiaSharp;
|
||||
using System.Collections.Generic;
|
||||
@@ -62,6 +63,8 @@ namespace Ryujinx.Ava.UI.Views.User
|
||||
|
||||
private async void Import_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(true);
|
||||
|
||||
IReadOnlyList<IStorageFile> result = await ((Window)this.GetVisualRoot()!).StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
AllowMultiple = false,
|
||||
@@ -81,6 +84,11 @@ namespace Ryujinx.Ava.UI.Views.User
|
||||
_profile.Image = ProcessProfileImage(File.ReadAllBytes(result[0].Path.LocalPath));
|
||||
_parent.GoBack();
|
||||
}
|
||||
|
||||
if (!Program.CoreDumpArg)
|
||||
{
|
||||
OsUtils.SetCoreDumpable(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void GoBack(object sender, RoutedEventArgs e)
|
||||
|
||||
Reference in New Issue
Block a user