Compare commits

...

11 Commits

Author SHA1 Message Date
IvonWei a4b2feef79 Merge branch 'GreemDev:master' into master 2024-12-23 22:13:47 +08:00
IvonWei ad7d9d1ce0 Update NpadController.cs
add ?
2024-12-23 18:55:49 +08:00
IvonWei 86f9544910 Update NpadController.cs
back to Debug
2024-12-23 18:54:11 +08:00
madwind e9ecbd44fc Add a virtual controller to merge Joy-Cons. 2024-12-23 17:57:55 +08:00
asfasagag a270dc721c UI: Option to resize window to 1440p, 2160p (#432)
Minor but useful quality of life addition
2024-12-22 22:49:40 -06:00
Evan Husted 23b0b22400 UI: Ensure last played date & time are always on 2 separate lines, for consistency. 2024-12-22 16:08:12 -06:00
Evan Husted 3dfbf55611 Merge remote-tracking branch 'origin/master' 2024-12-22 16:01:19 -06:00
Evan Husted cb355f504d UI: Rearrange help menu item & merge wiki page link buttons into a "category" button. 2024-12-22 16:01:09 -06:00
Marco Carvalho b5483d8fe0 Prefer generic overload when type is known (#430) 2024-12-22 13:23:35 -06:00
Evan Husted 8259f790d7 misc: Cleanup locale validator 2024-12-22 13:19:10 -06:00
Evan Husted 1ea345faa7 UI: Move Match PC Time to next to the time selector & change label & tooltip to clarify behavior further. 2024-12-22 12:53:48 -06:00
19 changed files with 404 additions and 66 deletions
@@ -14,20 +14,20 @@ namespace Ryujinx.BuildValidationTasks
{ {
string path = System.Reflection.Assembly.GetExecutingAssembly().Location; string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
if (path.Split(new string[] { "src" }, StringSplitOptions.None).Length == 1 ) if (path.Split(["src"], StringSplitOptions.None).Length == 1)
{ {
//i assume that we are in a build directory in the solution dir //i assume that we are in a build directory in the solution dir
path = new FileInfo(path).Directory.Parent.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName; path = new FileInfo(path).Directory!.Parent!.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName;
} }
else else
{ {
path = path.Split(new string[] { "src" }, StringSplitOptions.None)[0]; path = path.Split(["src"], StringSplitOptions.None)[0];
path = new FileInfo(path).Directory.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName; path = new FileInfo(path).Directory!.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName;
} }
string data; string data;
using (StreamReader sr = new StreamReader(path)) using (StreamReader sr = new(path))
{ {
data = sr.ReadToEnd(); data = sr.ReadToEnd();
} }
@@ -38,13 +38,10 @@ namespace Ryujinx.BuildValidationTasks
{ {
LocalesEntry locale = json.Locales[i]; LocalesEntry locale = json.Locales[i];
foreach (string language in json.Languages) foreach (string langCode in json.Languages.Where(it => !locale.Translations.ContainsKey(it)))
{ {
if (!locale.Translations.ContainsKey(language)) locale.Translations.Add(langCode, string.Empty);
{ Log.LogMessage(MessageImportance.High, $"Added '{langCode}' to Locale '{locale.ID}'");
locale.Translations.Add(language, "");
Log.LogMessage(MessageImportance.High, $"Added {{{language}}} to Locale {{{locale.ID}}}");
}
} }
locale.Translations = locale.Translations.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value); locale.Translations = locale.Translations.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value);
@@ -53,7 +50,7 @@ namespace Ryujinx.BuildValidationTasks
string jsonString = JsonConvert.SerializeObject(json, Formatting.Indented); string jsonString = JsonConvert.SerializeObject(json, Formatting.Indented);
using (StreamWriter sw = new StreamWriter(path)) using (StreamWriter sw = new(path))
{ {
sw.Write(jsonString); sw.Write(jsonString);
} }
@@ -62,7 +62,7 @@ namespace Ryujinx.Graphics.Vulkan
_api = api; _api = api;
_physicalDevice = physicalDevice; _physicalDevice = physicalDevice;
int totalFormats = Enum.GetNames(typeof(Format)).Length; int totalFormats = Enum.GetNames<Format>().Length;
_bufferTable = new FormatFeatureFlags[totalFormats]; _bufferTable = new FormatFeatureFlags[totalFormats];
_optimalTable = new FormatFeatureFlags[totalFormats]; _optimalTable = new FormatFeatureFlags[totalFormats];
+1 -1
View File
@@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Vulkan
static FormatTable() static FormatTable()
{ {
_table = new VkFormat[Enum.GetNames(typeof(Format)).Length]; _table = new VkFormat[Enum.GetNames<Format>().Length];
_reverseMap = new Dictionary<VkFormat, Format>(); _reverseMap = new Dictionary<VkFormat, Format>();
#pragma warning disable IDE0055 // Disable formatting #pragma warning disable IDE0055 // Disable formatting
@@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
{ {
_pipeline = pipeline; _pipeline = pipeline;
int count = Enum.GetNames(typeof(CounterType)).Length; int count = Enum.GetNames<CounterType>().Length;
_counterQueues = new CounterQueue[count]; _counterQueues = new CounterQueue[count];
+6 -6
View File
@@ -23,18 +23,18 @@ namespace Ryujinx.HLE.HOS.Services
public IpcService(ServerBase server = null) public IpcService(ServerBase server = null)
{ {
CmifCommands = typeof(IpcService).Assembly.GetTypes() CmifCommands = GetType().Assembly.GetTypes()
.Where(type => type == GetType()) .Where(type => type == GetType())
.SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public)) .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public))
.SelectMany(methodInfo => methodInfo.GetCustomAttributes(typeof(CommandCmifAttribute)) .SelectMany(methodInfo => methodInfo.GetCustomAttributes<CommandCmifAttribute>()
.Select(command => (((CommandCmifAttribute)command).Id, methodInfo))) .Select(command => (command.Id, methodInfo)))
.ToDictionary(command => command.Id, command => command.methodInfo); .ToDictionary(command => command.Id, command => command.methodInfo);
TipcCommands = typeof(IpcService).Assembly.GetTypes() TipcCommands = GetType().Assembly.GetTypes()
.Where(type => type == GetType()) .Where(type => type == GetType())
.SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public)) .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public))
.SelectMany(methodInfo => methodInfo.GetCustomAttributes(typeof(CommandTipcAttribute)) .SelectMany(methodInfo => methodInfo.GetCustomAttributes<CommandTipcAttribute>()
.Select(command => (((CommandTipcAttribute)command).Id, methodInfo))) .Select(command => (command.Id, methodInfo)))
.ToDictionary(command => command.Id, command => command.methodInfo); .ToDictionary(command => command.Id, command => command.methodInfo);
Server = server; Server = server;
@@ -444,7 +444,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
private ResultCode ScanInternal(IVirtualMemoryManager memory, ushort channel, ScanFilter scanFilter, ulong bufferPosition, ulong bufferSize, out ulong counter) private ResultCode ScanInternal(IVirtualMemoryManager memory, ushort channel, ScanFilter scanFilter, ulong bufferPosition, ulong bufferSize, out ulong counter)
{ {
ulong networkInfoSize = (ulong)Marshal.SizeOf(typeof(NetworkInfo)); ulong networkInfoSize = (ulong)Marshal.SizeOf<NetworkInfo>();
ulong maxGames = bufferSize / networkInfoSize; ulong maxGames = bufferSize / networkInfoSize;
MemoryHelper.FillWithZeros(memory, bufferPosition, (int)bufferSize); MemoryHelper.FillWithZeros(memory, bufferPosition, (int)bufferSize);
@@ -94,7 +94,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
{ {
if (_services.TryGetValue(name, out Type type)) if (_services.TryGetValue(name, out Type type))
{ {
ServiceAttribute serviceAttribute = (ServiceAttribute)type.GetCustomAttributes(typeof(ServiceAttribute)).First(service => ((ServiceAttribute)service).Name == name); ServiceAttribute serviceAttribute = type.GetCustomAttributes<ServiceAttribute>().First(service => service.Name == name);
IpcService service = GetServiceInstance(type, context, serviceAttribute.Parameter); IpcService service = GetServiceInstance(type, context, serviceAttribute.Parameter);
@@ -34,14 +34,14 @@ namespace Ryujinx.Horizon.Kernel.Generators
private const string TypeResult = NamespaceHorizonCommon + "." + TypeResultName; private const string TypeResult = NamespaceHorizonCommon + "." + TypeResultName;
private const string TypeExecutionContext = "IExecutionContext"; private const string TypeExecutionContext = "IExecutionContext";
private static readonly string[] _expectedResults = new string[] private static readonly string[] _expectedResults =
{ [
$"{TypeResultName}.Success", $"{TypeResultName}.Success",
$"{TypeKernelResultName}.TimedOut", $"{TypeKernelResultName}.TimedOut",
$"{TypeKernelResultName}.Cancelled", $"{TypeKernelResultName}.Cancelled",
$"{TypeKernelResultName}.PortRemoteClosed", $"{TypeKernelResultName}.PortRemoteClosed",
$"{TypeKernelResultName}.InvalidState", $"{TypeKernelResultName}.InvalidState",
}; ];
private readonly struct OutParameter private readonly struct OutParameter
{ {
+17 -3
View File
@@ -1,6 +1,7 @@
using Ryujinx.SDL2.Common; using Ryujinx.SDL2.Common;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using static SDL2.SDL; using static SDL2.SDL;
@@ -11,7 +12,7 @@ namespace Ryujinx.Input.SDL2
private readonly Dictionary<int, string> _gamepadsInstanceIdsMapping; private readonly Dictionary<int, string> _gamepadsInstanceIdsMapping;
private readonly List<string> _gamepadsIds; private readonly List<string> _gamepadsIds;
private readonly Lock _lock = new(); private readonly Lock _lock = new();
private readonly SDL2JoyConPair joyConPair;
public ReadOnlySpan<string> GamepadsIds public ReadOnlySpan<string> GamepadsIds
{ {
get get
@@ -36,7 +37,7 @@ namespace Ryujinx.Input.SDL2
SDL2Driver.Instance.Initialize(); SDL2Driver.Instance.Initialize();
SDL2Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected; SDL2Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected;
SDL2Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected; SDL2Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected;
joyConPair = new SDL2JoyConPair();
// Add already connected gamepads // Add already connected gamepads
int numJoysticks = SDL_NumJoysticks(); int numJoysticks = SDL_NumJoysticks();
@@ -89,6 +90,10 @@ namespace Ryujinx.Input.SDL2
lock (_lock) lock (_lock)
{ {
_gamepadsIds.Remove(id); _gamepadsIds.Remove(id);
if (joyConPair.GetJoyConPair(_gamepadsIds) == null)
{
_gamepadsIds.Remove(joyConPair.Id);
}
} }
OnGamepadDisconnected?.Invoke(id); OnGamepadDisconnected?.Invoke(id);
@@ -120,8 +125,12 @@ namespace Ryujinx.Input.SDL2
_gamepadsIds.Insert(joystickDeviceId, id); _gamepadsIds.Insert(joystickDeviceId, id);
else else
_gamepadsIds.Add(id); _gamepadsIds.Add(id);
if (joyConPair.GetJoyConPair(_gamepadsIds) != null)
{
_gamepadsIds.Remove(joyConPair.Id);
_gamepadsIds.Add(joyConPair.Id);
}
} }
OnGamepadConnected?.Invoke(id); OnGamepadConnected?.Invoke(id);
} }
} }
@@ -157,6 +166,11 @@ namespace Ryujinx.Input.SDL2
public IGamepad GetGamepad(string id) public IGamepad GetGamepad(string id)
{ {
if (id == joyConPair.Id)
{
return joyConPair.GetJoyConPair(_gamepadsIds);
}
int joystickIndex = GetJoystickIndexByGamepadId(id); int joystickIndex = GetJoystickIndexByGamepadId(id);
if (joystickIndex == -1) if (joystickIndex == -1)
+229
View File
@@ -0,0 +1,229 @@
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using static SDL2.SDL;
namespace Ryujinx.Input.SDL2
{
internal class SDL2JoyConPair : IGamepad
{
private IGamepad _left;
private IGamepad _right;
private StandardControllerInputConfig _configuration;
private readonly StickInputId[] _stickUserMapping = new StickInputId[(int)StickInputId.Count]
{
StickInputId.Unbound,
StickInputId.Left,
StickInputId.Right,
};
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From)
{
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not GamepadButtonInputId.Unbound;
}
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
public SDL2JoyConPair()
{
_buttonsUserMapping = new List<ButtonMappingEntry>(20);
}
private readonly object _userMappingLock = new();
public GamepadFeaturesFlag Features => (_left?.Features ?? GamepadFeaturesFlag.None) | (_right?.Features ?? GamepadFeaturesFlag.None);
public string Id => "JoyConPair";
public string Name => "Nintendo Switch Joy-Con (L/R)";
private static readonly string leftName = "Nintendo Switch Joy-Con (L)";
private static readonly string rightName = "Nintendo Switch Joy-Con (R)";
public bool IsConnected => (_left != null && _left.IsConnected) && (_right != null && _right.IsConnected);
public void Dispose()
{
_left?.Dispose();
_right?.Dispose();
}
public GamepadStateSnapshot GetMappedStateSnapshot()
{
GamepadStateSnapshot rawState = GetStateSnapshot();
GamepadStateSnapshot result = default;
lock (_userMappingLock)
{
if (_buttonsUserMapping.Count == 0)
return rawState;
// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
{
if (!entry.IsValid)
continue;
// Do not touch state of button already pressed
if (!result.IsPressed(entry.To))
{
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
}
}
(float leftStickX, float leftStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Left]);
(float rightStickX, float rightStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Right]);
result.SetStick(StickInputId.Left, leftStickX, leftStickY);
result.SetStick(StickInputId.Right, rightStickX, rightStickY);
}
return result;
}
public Vector3 GetMotionData(MotionInputId inputId)
{
return inputId switch
{
MotionInputId.SecondAccelerometer => _right.GetMotionData(MotionInputId.Accelerometer),
MotionInputId.SecondGyroscope => _right.GetMotionData(MotionInputId.Gyroscope),
_ => _left.GetMotionData(inputId)
};
}
public GamepadStateSnapshot GetStateSnapshot()
{
return IGamepad.GetStateSnapshot(this);
}
public (float, float) GetStick(StickInputId inputId)
{
if (inputId == StickInputId.Left)
{
(float x, float y) = _left.GetStick(StickInputId.Left);
return (y, -x);
}
else if (inputId == StickInputId.Right)
{
(float x, float y) = _right.GetStick(StickInputId.Left);
return (-y, x);
}
return (0, 0);
}
public bool IsPressed(GamepadButtonInputId inputId)
{
return inputId switch
{
GamepadButtonInputId.LeftStick => _left.IsPressed(GamepadButtonInputId.LeftStick),
GamepadButtonInputId.DpadUp => _left.IsPressed(GamepadButtonInputId.Y),
GamepadButtonInputId.DpadDown => _left.IsPressed(GamepadButtonInputId.A),
GamepadButtonInputId.DpadLeft => _left.IsPressed(GamepadButtonInputId.B),
GamepadButtonInputId.DpadRight => _left.IsPressed(GamepadButtonInputId.X),
GamepadButtonInputId.Minus => _left.IsPressed(GamepadButtonInputId.Start),
GamepadButtonInputId.LeftShoulder => _left.IsPressed(GamepadButtonInputId.Paddle2),
GamepadButtonInputId.LeftTrigger => _left.IsPressed(GamepadButtonInputId.Paddle4),
GamepadButtonInputId.SingleRightTrigger0 => _left.IsPressed(GamepadButtonInputId.LeftShoulder),
GamepadButtonInputId.SingleLeftTrigger0 => _left.IsPressed(GamepadButtonInputId.RightShoulder),
GamepadButtonInputId.RightStick => _right.IsPressed(GamepadButtonInputId.LeftStick),
GamepadButtonInputId.A => _right.IsPressed(GamepadButtonInputId.B),
GamepadButtonInputId.B => _right.IsPressed(GamepadButtonInputId.Y),
GamepadButtonInputId.X => _right.IsPressed(GamepadButtonInputId.A),
GamepadButtonInputId.Y => _right.IsPressed(GamepadButtonInputId.X),
GamepadButtonInputId.Plus => _right.IsPressed(GamepadButtonInputId.Start),
GamepadButtonInputId.RightShoulder => _right.IsPressed(GamepadButtonInputId.Paddle1),
GamepadButtonInputId.RightTrigger => _right.IsPressed(GamepadButtonInputId.Paddle3),
GamepadButtonInputId.SingleRightTrigger1 => _right.IsPressed(GamepadButtonInputId.LeftShoulder),
GamepadButtonInputId.SingleLeftTrigger1 => _right.IsPressed(GamepadButtonInputId.RightShoulder),
_ => false
};
}
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
{
if (lowFrequency != 0)
{
_right.Rumble(lowFrequency, lowFrequency, durationMs);
}
if (highFrequency != 0)
{
_left.Rumble(highFrequency, highFrequency, durationMs);
}
if (lowFrequency == 0 && highFrequency == 0)
{
_left.Rumble(lowFrequency, highFrequency, durationMs);
_right.Rumble(lowFrequency, highFrequency, durationMs);
}
}
public void SetConfiguration(InputConfig configuration)
{
lock (_userMappingLock)
{
_configuration = (StandardControllerInputConfig)configuration;
_left.SetConfiguration(configuration);
_right.SetConfiguration(configuration);
_buttonsUserMapping.Clear();
// First update sticks
_stickUserMapping[(int)StickInputId.Left] = (StickInputId)_configuration.LeftJoyconStick.Joystick;
_stickUserMapping[(int)StickInputId.Right] = (StickInputId)_configuration.RightJoyconStick.Joystick;
// Then left joycon
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (GamepadButtonInputId)_configuration.LeftJoyconStick.StickButton));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (GamepadButtonInputId)_configuration.LeftJoycon.DpadUp));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (GamepadButtonInputId)_configuration.LeftJoycon.DpadDown));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft, (GamepadButtonInputId)_configuration.LeftJoycon.DpadLeft));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight, (GamepadButtonInputId)_configuration.LeftJoycon.DpadRight));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonMinus));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonL));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonZl));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonSr));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonSl));
// Finally right joycon
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (GamepadButtonInputId)_configuration.RightJoyconStick.StickButton));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (GamepadButtonInputId)_configuration.RightJoycon.ButtonA));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (GamepadButtonInputId)_configuration.RightJoycon.ButtonB));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X, (GamepadButtonInputId)_configuration.RightJoycon.ButtonX));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y, (GamepadButtonInputId)_configuration.RightJoycon.ButtonY));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus, (GamepadButtonInputId)_configuration.RightJoycon.ButtonPlus));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder, (GamepadButtonInputId)_configuration.RightJoycon.ButtonR));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (GamepadButtonInputId)_configuration.RightJoycon.ButtonZr));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (GamepadButtonInputId)_configuration.RightJoycon.ButtonSr));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (GamepadButtonInputId)_configuration.RightJoycon.ButtonSl));
SetTriggerThreshold(_configuration.TriggerThreshold);
}
}
public void SetTriggerThreshold(float triggerThreshold)
{
_left.SetTriggerThreshold(triggerThreshold);
_right.SetTriggerThreshold(triggerThreshold);
}
public SDL2JoyConPair GetJoyConPair(List<string> _gamepadsIds)
{
this.Dispose();
var gamepadNames = _gamepadsIds.Where(gamepadId => gamepadId != Id).Select((gamepadId, index) => SDL_GameControllerNameForIndex(index)).ToList();
int leftIndex = gamepadNames.IndexOf(leftName);
int rightIndex = gamepadNames.IndexOf(rightName);
if (leftIndex != -1 && rightIndex != -1)
{
nint leftGamepadHandle = SDL_GameControllerOpen(leftIndex);
nint rightGamepadHandle = SDL_GameControllerOpen(rightIndex);
_left = new SDL2Gamepad(leftGamepadHandle, _gamepadsIds[leftIndex]);
_right = new SDL2Gamepad(rightGamepadHandle, _gamepadsIds[leftIndex]);
return this;
}
return null;
}
}
}
+16 -1
View File
@@ -266,6 +266,7 @@ namespace Ryujinx.Input.HLE
if (motionConfig.MotionBackend != MotionInputBackendType.CemuHook) if (motionConfig.MotionBackend != MotionInputBackendType.CemuHook)
{ {
_leftMotionInput = new MotionInput(); _leftMotionInput = new MotionInput();
_rightMotionInput = new MotionInput();
} }
else else
{ {
@@ -298,7 +299,20 @@ namespace Ryujinx.Input.HLE
if (controllerConfig.ControllerType == ConfigControllerType.JoyconPair) if (controllerConfig.ControllerType == ConfigControllerType.JoyconPair)
{ {
_rightMotionInput = _leftMotionInput; if (gamepad.Id== "JoyConPair")
{
Vector3 rightAccelerometer = gamepad.GetMotionData(MotionInputId.SecondAccelerometer);
Vector3 rightGyroscope = gamepad.GetMotionData(MotionInputId.SecondGyroscope);
rightAccelerometer = new Vector3(rightAccelerometer.X, -rightAccelerometer.Z, rightAccelerometer.Y);
rightGyroscope = new Vector3(rightGyroscope.X, -rightGyroscope.Z, rightGyroscope.Y);
_rightMotionInput.Update(rightAccelerometer, rightGyroscope, (ulong)PerformanceCounter.ElapsedNanoseconds / 1000, controllerConfig.Motion.Sensitivity, (float)controllerConfig.Motion.GyroDeadzone);
}
else
{
_rightMotionInput = _leftMotionInput;
}
} }
} }
} }
@@ -333,6 +347,7 @@ namespace Ryujinx.Input.HLE
// Reset states // Reset states
State = default; State = default;
_leftMotionInput = null; _leftMotionInput = null;
_rightMotionInput = null;
} }
} }
+12
View File
@@ -21,5 +21,17 @@ namespace Ryujinx.Input
/// </summary> /// </summary>
/// <remarks>Values are in degrees</remarks> /// <remarks>Values are in degrees</remarks>
Gyroscope, Gyroscope,
/// <summary>
/// Second accelerometer.
/// </summary>
/// <remarks>Values are in m/s^2</remarks>
SecondAccelerometer,
/// <summary>
/// Second gyroscope.
/// </summary>
/// <remarks>Values are in degrees</remarks>
SecondGyroscope
} }
} }
+1 -1
View File
@@ -38,7 +38,7 @@ namespace Ryujinx.UI.App.Common
public string TimePlayedString => ValueFormatUtils.FormatTimeSpan(TimePlayed); public string TimePlayedString => ValueFormatUtils.FormatTimeSpan(TimePlayed);
public string LastPlayedString => ValueFormatUtils.FormatDateTime(LastPlayed) ?? LocalizedNever(); public string LastPlayedString => ValueFormatUtils.FormatDateTime(LastPlayed)?.Replace(" ", "\n") ?? LocalizedNever();
public string FileSizeString => ValueFormatUtils.FormatFileSize(FileSize); public string FileSizeString => ValueFormatUtils.FormatFileSize(FileSize);
+74 -2
View File
@@ -1077,6 +1077,54 @@
"zh_TW": "" "zh_TW": ""
} }
}, },
{
"ID": "MenuBarViewWindow1440",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "1440p",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{
"ID": "MenuBarViewWindow2160",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "2160p",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{ {
"ID": "MenuBarHelp", "ID": "MenuBarHelp",
"Translations": { "Translations": {
@@ -1125,6 +1173,30 @@
"zh_TW": "檢查更新" "zh_TW": "檢查更新"
} }
}, },
{
"ID": "MenuBarHelpFaqAndGuides",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "FAQ & Guides",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{ {
"ID": "MenuBarHelpFaq", "ID": "MenuBarHelpFaq",
"Translations": { "Translations": {
@@ -3771,7 +3843,7 @@
"ar_SA": "", "ar_SA": "",
"de_DE": "", "de_DE": "",
"el_GR": "", "el_GR": "",
"en_US": "Match PC Time", "en_US": "Resync to PC Date & Time",
"es_ES": "", "es_ES": "",
"fr_FR": "", "fr_FR": "",
"he_IL": "", "he_IL": "",
@@ -14571,7 +14643,7 @@
"ar_SA": "", "ar_SA": "",
"de_DE": "", "de_DE": "",
"el_GR": "", "el_GR": "",
"en_US": "Change System Time to match your PC's date & time.", "en_US": "Resync System Time to match your PC's current date & time.\n\nThis is not an active setting, it can still fall out of sync; in which case just click this button again.",
"es_ES": "", "es_ES": "",
"fr_FR": "", "fr_FR": "",
"he_IL": "", "he_IL": "",
@@ -97,7 +97,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{ {
if (IsModified) if (IsModified)
{ {
_playerIdChoose = value; _playerIdChoose = value;
return; return;
} }
@@ -105,7 +105,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
IsModified = false; IsModified = false;
_playerId = value; _playerId = value;
if (!Enum.IsDefined(typeof(PlayerIndex), _playerId)) if (!Enum.IsDefined<PlayerIndex>(_playerId))
{ {
_playerId = PlayerIndex.Player1; _playerId = PlayerIndex.Player1;
+27 -24
View File
@@ -287,9 +287,16 @@
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarViewWindow}"> <MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarViewWindow}">
<MenuItem Header="{ext:Locale MenuBarViewWindow720}" Tag="1280 720" Click="ChangeWindowSize_Click" /> <MenuItem Header="{ext:Locale MenuBarViewWindow720}" Tag="1280 720" Click="ChangeWindowSize_Click" />
<MenuItem Header="{ext:Locale MenuBarViewWindow1080}" Tag="1920 1080" Click="ChangeWindowSize_Click" /> <MenuItem Header="{ext:Locale MenuBarViewWindow1080}" Tag="1920 1080" Click="ChangeWindowSize_Click" />
<MenuItem Header="{ext:Locale MenuBarViewWindow1440}" Tag="2560 1440" Click="ChangeWindowSize_Click" />
<MenuItem Header="{ext:Locale MenuBarViewWindow2160}" Tag="3840 2160" Click="ChangeWindowSize_Click" />
</MenuItem> </MenuItem>
</MenuItem> </MenuItem>
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarHelp}"> <MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarHelp}">
<MenuItem
Click="OpenAboutWindow"
Header="{ext:Locale MenuBarHelpAbout}"
Icon="{ext:Icon fa-solid fa-circle-info}"
ToolTip.Tip="{ext:Locale OpenAboutTooltip}" />
<MenuItem <MenuItem
Name="UpdateMenuItem" Name="UpdateMenuItem"
IsEnabled="{Binding CanUpdate}" IsEnabled="{Binding CanUpdate}"
@@ -298,30 +305,26 @@
Icon="{ext:Icon mdi-update}" Icon="{ext:Icon mdi-update}"
ToolTip.Tip="{ext:Locale CheckUpdatesTooltip}" /> ToolTip.Tip="{ext:Locale CheckUpdatesTooltip}" />
<Separator /> <Separator />
<MenuItem <MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarHelpFaqAndGuides}" Icon="{ext:Icon fa-solid fa-question}" >
Click="MenuItem_OnClick" <MenuItem
Header="{ext:Locale MenuBarHelpFaq}" Click="MenuItem_OnClick"
Icon="{ext:Icon fa-github}" Header="{ext:Locale MenuBarHelpFaq}"
Tag="https://github.com/GreemDev/Ryujinx/wiki/FAQ-and-Troubleshooting" Icon="{ext:Icon fa-github}"
ToolTip.Tip="{ext:Locale MenuBarHelpFaqTooltip}" /> Tag="https://github.com/GreemDev/Ryujinx/wiki/FAQ-and-Troubleshooting"
<MenuItem ToolTip.Tip="{ext:Locale MenuBarHelpFaqTooltip}" />
Click="MenuItem_OnClick" <MenuItem
Header="{ext:Locale MenuBarHelpSetup}" Click="MenuItem_OnClick"
Icon="{ext:Icon fa-github}" Header="{ext:Locale MenuBarHelpSetup}"
Tag="https://github.com/GreemDev/Ryujinx/wiki/Ryujinx-Setup-&amp;-Configuration-Guide" Icon="{ext:Icon fa-github}"
ToolTip.Tip="{ext:Locale MenuBarHelpSetupTooltip}" /> Tag="https://github.com/GreemDev/Ryujinx/wiki/Ryujinx-Setup-&amp;-Configuration-Guide"
<MenuItem ToolTip.Tip="{ext:Locale MenuBarHelpSetupTooltip}" />
Click="MenuItem_OnClick" <MenuItem
Header="{ext:Locale MenuBarHelpMultiplayer}" Click="MenuItem_OnClick"
Icon="{ext:Icon fa-github}" Header="{ext:Locale MenuBarHelpMultiplayer}"
Tag="https://github.com/GreemDev/Ryujinx/wiki/Multiplayer%E2%80%90(LDN%E2%80%90Local%E2%80%90Wireless)%E2%80%90Guide" Icon="{ext:Icon fa-github}"
ToolTip.Tip="{ext:Locale MenuBarHelpMultiplayerTooltip}" /> Tag="https://github.com/GreemDev/Ryujinx/wiki/Multiplayer%E2%80%90(LDN%E2%80%90Local%E2%80%90Wireless)%E2%80%90Guide"
<Separator /> ToolTip.Tip="{ext:Locale MenuBarHelpMultiplayerTooltip}" />
<MenuItem </MenuItem>
Click="OpenAboutWindow"
Header="{ext:Locale MenuBarHelpAbout}"
Icon="{ext:Icon fa-solid fa-circle-info}"
ToolTip.Tip="{ext:Locale OpenAboutTooltip}" />
</MenuItem> </MenuItem>
</Menu> </Menu>
</DockPanel> </DockPanel>
@@ -52,7 +52,7 @@ namespace Ryujinx.Ava.UI.Views.Main
private void AspectRatioStatus_OnClick(object sender, RoutedEventArgs e) private void AspectRatioStatus_OnClick(object sender, RoutedEventArgs e)
{ {
AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value; AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value;
ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1; ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames<AspectRatio>().Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1;
} }
private void Refresh_OnClick(object sender, RoutedEventArgs e) => Window.LoadApplications(); private void Refresh_OnClick(object sender, RoutedEventArgs e) => Window.LoadApplications();
@@ -181,15 +181,11 @@
SelectedTime="{Binding CurrentTime}" SelectedTime="{Binding CurrentTime}"
Width="350" Width="350"
ToolTip.Tip="{ext:Locale TimeTooltip}" /> ToolTip.Tip="{ext:Locale TimeTooltip}" />
</StackPanel>
<StackPanel
Margin="350,0,0,10"
Orientation="Horizontal">
<Button <Button
Margin="10, 0, 0, 0"
VerticalAlignment="Center" VerticalAlignment="Center"
Click="MatchSystemTime_OnClick" Click="MatchSystemTime_OnClick"
Background="{DynamicResource SystemAccentColor}" Background="{DynamicResource SystemAccentColor}"
Width="150"
ToolTip.Tip="{ext:Locale MatchTimeTooltip}"> ToolTip.Tip="{ext:Locale MatchTimeTooltip}">
<TextBlock Text="{ext:Locale SettingsTabSystemSystemTimeMatch}" /> <TextBlock Text="{ext:Locale SettingsTabSystemSystemTimeMatch}" />
</Button> </Button>
@@ -1,7 +1,7 @@
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using System;
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone; using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
namespace Ryujinx.Ava.UI.Views.Settings namespace Ryujinx.Ava.UI.Views.Settings