mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-06-28 00:16:23 +02:00
Extended hotkeys to player1-8 + h, localized the overlay
This commit is contained in:
parent
ef0dac5533
commit
3ec079855d
16 changed files with 338 additions and 79 deletions
|
@ -24373,12 +24373,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ID": "SettingsTabHotkeysCycleInputDevicePlayer1",
|
"ID": "SettingsTabHotkeysCycleInputDevicePlayerX",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
"ar_SA": "",
|
"ar_SA": "",
|
||||||
"de_DE": "",
|
"de_DE": "",
|
||||||
"el_GR": "",
|
"el_GR": "",
|
||||||
"en_US": "Cycle Input Device Player 1:",
|
"en_US": "Cycle Input Device {0}:",
|
||||||
"es_ES": "",
|
"es_ES": "",
|
||||||
"fr_FR": "",
|
"fr_FR": "",
|
||||||
"he_IL": "",
|
"he_IL": "",
|
||||||
|
@ -24398,12 +24398,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ID": "SettingsTabHotkeysCycleInputDevicePlayer2",
|
"ID": "ControllerOverlayTitle",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
"ar_SA": "",
|
"ar_SA": "",
|
||||||
"de_DE": "",
|
"de_DE": "",
|
||||||
"el_GR": "",
|
"el_GR": "",
|
||||||
"en_US": "Cycle Input Device Player 2:",
|
"en_US": "Controller Bindings",
|
||||||
"es_ES": "",
|
"es_ES": "",
|
||||||
"fr_FR": "",
|
"fr_FR": "",
|
||||||
"he_IL": "",
|
"he_IL": "",
|
||||||
|
@ -24423,12 +24423,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ID": "SettingsTabHotkeysCycleInputDevicePlayer3",
|
"ID": "ControllerOverlayNoController",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
"ar_SA": "",
|
"ar_SA": "",
|
||||||
"de_DE": "",
|
"de_DE": "",
|
||||||
"el_GR": "",
|
"el_GR": "",
|
||||||
"en_US": "Cycle Input Device Player 3:",
|
"en_US": "No controller assigned",
|
||||||
"es_ES": "",
|
"es_ES": "",
|
||||||
"fr_FR": "",
|
"fr_FR": "",
|
||||||
"he_IL": "",
|
"he_IL": "",
|
||||||
|
@ -24448,12 +24448,62 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ID": "SettingsTabHotkeysCycleInputDevicePlayer4",
|
"ID": "ControllerOverlayKeyboard",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
"ar_SA": "",
|
"ar_SA": "",
|
||||||
"de_DE": "",
|
"de_DE": "",
|
||||||
"el_GR": "",
|
"el_GR": "",
|
||||||
"en_US": "Cycle Input Device Player 4:",
|
"en_US": "Keyboard",
|
||||||
|
"es_ES": "",
|
||||||
|
"fr_FR": "",
|
||||||
|
"he_IL": "",
|
||||||
|
"it_IT": "",
|
||||||
|
"ja_JP": "",
|
||||||
|
"ko_KR": "",
|
||||||
|
"no_NO": "",
|
||||||
|
"pl_PL": "",
|
||||||
|
"pt_BR": "",
|
||||||
|
"ru_RU": "",
|
||||||
|
"sv_SE": "",
|
||||||
|
"th_TH": "",
|
||||||
|
"tr_TR": "",
|
||||||
|
"uk_UA": "",
|
||||||
|
"zh_CN": "",
|
||||||
|
"zh_TW": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "ControllerOverlayController",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "",
|
||||||
|
"de_DE": "",
|
||||||
|
"el_GR": "",
|
||||||
|
"en_US": "Controller",
|
||||||
|
"es_ES": "",
|
||||||
|
"fr_FR": "",
|
||||||
|
"he_IL": "",
|
||||||
|
"it_IT": "",
|
||||||
|
"ja_JP": "",
|
||||||
|
"ko_KR": "",
|
||||||
|
"no_NO": "",
|
||||||
|
"pl_PL": "",
|
||||||
|
"pt_BR": "",
|
||||||
|
"ru_RU": "",
|
||||||
|
"sv_SE": "",
|
||||||
|
"th_TH": "",
|
||||||
|
"tr_TR": "",
|
||||||
|
"uk_UA": "",
|
||||||
|
"zh_CN": "",
|
||||||
|
"zh_TW": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "ControllerOverlayUnknown",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "",
|
||||||
|
"de_DE": "",
|
||||||
|
"el_GR": "",
|
||||||
|
"en_US": "Unknown",
|
||||||
"es_ES": "",
|
"es_ES": "",
|
||||||
"fr_FR": "",
|
"fr_FR": "",
|
||||||
"he_IL": "",
|
"he_IL": "",
|
||||||
|
|
|
@ -19,5 +19,10 @@ namespace Ryujinx.Common.Configuration.Hid
|
||||||
public Key CycleInputDevicePlayer2 { get; set; }
|
public Key CycleInputDevicePlayer2 { get; set; }
|
||||||
public Key CycleInputDevicePlayer3 { get; set; }
|
public Key CycleInputDevicePlayer3 { get; set; }
|
||||||
public Key CycleInputDevicePlayer4 { get; set; }
|
public Key CycleInputDevicePlayer4 { get; set; }
|
||||||
|
public Key CycleInputDevicePlayer5 { get; set; }
|
||||||
|
public Key CycleInputDevicePlayer6 { get; set; }
|
||||||
|
public Key CycleInputDevicePlayer7 { get; set; }
|
||||||
|
public Key CycleInputDevicePlayer8 { get; set; }
|
||||||
|
public Key CycleInputDeviceHandheld { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,18 @@ using OriginalInputBackendType = Ryujinx.Common.Configuration.Hid.InputBackendTy
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Overlay
|
namespace Ryujinx.Graphics.Gpu.Overlay
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Localization strings for the controller overlay
|
||||||
|
/// </summary>
|
||||||
|
public class ControllerOverlayLocalization
|
||||||
|
{
|
||||||
|
public string TitleText { get; set; } = "Controller Bindings";
|
||||||
|
public string NoControllerText { get; set; } = "No controller assigned";
|
||||||
|
public string KeyboardText { get; set; } = "Keyboard";
|
||||||
|
public string ControllerText { get; set; } = "Controller";
|
||||||
|
public string UnknownText { get; set; } = "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controller overlay that shows controller bindings matching the original AXAML design
|
/// Controller overlay that shows controller bindings matching the original AXAML design
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -23,9 +35,11 @@ namespace Ryujinx.Graphics.Gpu.Overlay
|
||||||
private const float PlayerTextSize = 22;
|
private const float PlayerTextSize = 22;
|
||||||
|
|
||||||
private float _lifespan = 0f;
|
private float _lifespan = 0f;
|
||||||
|
private ControllerOverlayLocalization _localization;
|
||||||
|
|
||||||
public ControllerOverlay() : base("ControllerOverlay")
|
public ControllerOverlay(ControllerOverlayLocalization localization) : base("ControllerOverlay")
|
||||||
{
|
{
|
||||||
|
_localization = localization;
|
||||||
CreateBaseElements();
|
CreateBaseElements();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,8 +56,8 @@ namespace Ryujinx.Graphics.Gpu.Overlay
|
||||||
};
|
};
|
||||||
AddElement(background);
|
AddElement(background);
|
||||||
|
|
||||||
// Title text
|
// Title text (will be updated with localized text)
|
||||||
var titleText = new TextElement(Padding + 30, Padding, "Controller Bindings", TitleTextSize, SKColors.White)
|
var titleText = new TextElement(Padding + 30, Padding, _localization.TitleText, TitleTextSize, SKColors.White)
|
||||||
{
|
{
|
||||||
Name = "TitleText",
|
Name = "TitleText",
|
||||||
FontStyle = SKFontStyle.Bold
|
FontStyle = SKFontStyle.Bold
|
||||||
|
@ -52,21 +66,27 @@ namespace Ryujinx.Graphics.Gpu.Overlay
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Show controller bindings matching the original AXAML implementation
|
/// Show controller bindings with localized strings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ShowControllerBindings(List<OriginalInputConfig> inputConfigs, int durationSeconds = 3)
|
public void ShowControllerBindings(List<OriginalInputConfig> inputConfigs, int durationSeconds = 3)
|
||||||
{
|
{
|
||||||
|
// Update title text
|
||||||
|
var titleElement = FindElement<TextElement>("TitleText");
|
||||||
|
if (titleElement != null)
|
||||||
|
{
|
||||||
|
titleElement.Text = _localization.TitleText;
|
||||||
|
}
|
||||||
|
|
||||||
// Reset lifespan and opacity
|
// Reset lifespan and opacity
|
||||||
_lifespan = durationSeconds;
|
_lifespan = durationSeconds;
|
||||||
|
|
||||||
// Clear existing player bindings
|
// Clear existing player bindings
|
||||||
ClearPlayerBindings();
|
ClearPlayerBindings();
|
||||||
|
|
||||||
// Debug: Log input data
|
// Group controllers by player index (support all players + handheld)
|
||||||
// Group controllers by player index
|
|
||||||
var playerBindings = new Dictionary<OriginalPlayerIndex, List<OriginalInputConfig>>();
|
var playerBindings = new Dictionary<OriginalPlayerIndex, List<OriginalInputConfig>>();
|
||||||
|
|
||||||
foreach (var config in inputConfigs.Where(c => c.PlayerIndex <= OriginalPlayerIndex.Player4))
|
foreach (var config in inputConfigs.Where(c => c.PlayerIndex <= OriginalPlayerIndex.Handheld))
|
||||||
{
|
{
|
||||||
if (!playerBindings.ContainsKey(config.PlayerIndex))
|
if (!playerBindings.ContainsKey(config.PlayerIndex))
|
||||||
{
|
{
|
||||||
|
@ -77,10 +97,17 @@ namespace Ryujinx.Graphics.Gpu.Overlay
|
||||||
|
|
||||||
float currentY = Padding + 40; // After title
|
float currentY = Padding + 40; // After title
|
||||||
|
|
||||||
// Add player bindings to UI
|
// Add player bindings to UI (support 8 players + handheld)
|
||||||
for (int i = 0; i < 4; i++)
|
var playerIndices = new[]
|
||||||
|
{
|
||||||
|
OriginalPlayerIndex.Player1, OriginalPlayerIndex.Player2, OriginalPlayerIndex.Player3, OriginalPlayerIndex.Player4,
|
||||||
|
OriginalPlayerIndex.Player5, OriginalPlayerIndex.Player6, OriginalPlayerIndex.Player7, OriginalPlayerIndex.Player8,
|
||||||
|
OriginalPlayerIndex.Handheld
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < playerIndices.Length; i++)
|
||||||
{
|
{
|
||||||
var playerIndex = (OriginalPlayerIndex)i;
|
var playerIndex = playerIndices[i];
|
||||||
float rowY = currentY + (i * (PlayerRowHeight + PlayerSpacing));
|
float rowY = currentY + (i * (PlayerRowHeight + PlayerSpacing));
|
||||||
|
|
||||||
// Player number with colored background (circular badge)
|
// Player number with colored background (circular badge)
|
||||||
|
@ -93,13 +120,14 @@ namespace Ryujinx.Graphics.Gpu.Overlay
|
||||||
AddElement(playerBadge);
|
AddElement(playerBadge);
|
||||||
|
|
||||||
// Player number text
|
// Player number text
|
||||||
var playerLabel = new TextElement(Padding + 12, rowY + 2, $"P{i + 1}", PlayerTextSize, SKColors.White)
|
string playerLabel = playerIndex == OriginalPlayerIndex.Handheld ? "H" : $"P{(int)playerIndex + 1}";
|
||||||
|
var playerLabelElement = new TextElement(Padding + 12, rowY + 2, playerLabel, PlayerTextSize, SKColors.White)
|
||||||
{
|
{
|
||||||
Name = $"PlayerLabel_{i}",
|
Name = $"PlayerLabel_{i}",
|
||||||
FontStyle = SKFontStyle.Bold,
|
FontStyle = SKFontStyle.Bold,
|
||||||
TextAlign = SKTextAlign.Center
|
TextAlign = SKTextAlign.Center
|
||||||
};
|
};
|
||||||
AddElement(playerLabel);
|
AddElement(playerLabelElement);
|
||||||
|
|
||||||
// Controller info
|
// Controller info
|
||||||
if (playerBindings.ContainsKey(playerIndex))
|
if (playerBindings.ContainsKey(playerIndex))
|
||||||
|
@ -107,37 +135,32 @@ namespace Ryujinx.Graphics.Gpu.Overlay
|
||||||
var controllers = playerBindings[playerIndex];
|
var controllers = playerBindings[playerIndex];
|
||||||
var controllerNames = controllers.Select(c => GetControllerDisplayName(c)).ToList();
|
var controllerNames = controllers.Select(c => GetControllerDisplayName(c)).ToList();
|
||||||
|
|
||||||
var controllerText = new TextElement(Padding + 56, rowY + 2, string.Join(", ", controllerNames), PlayerTextSize, new SKColor(144, 238, 144)) // LightGreen
|
var controllerTextElement = new TextElement(Padding + 56, rowY + 2, string.Join(", ", controllerNames), PlayerTextSize, new SKColor(144, 238, 144)) // LightGreen
|
||||||
{
|
{
|
||||||
Name = $"ControllerText_{i}",
|
Name = $"ControllerText_{i}",
|
||||||
FontStyle = SKFontStyle.Bold
|
FontStyle = SKFontStyle.Bold
|
||||||
};
|
};
|
||||||
AddElement(controllerText);
|
AddElement(controllerTextElement);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var noControllerText = new TextElement(Padding + 56, rowY + 2, "No controller assigned", PlayerTextSize, new SKColor(128, 128, 128)) // Gray
|
var noControllerTextElement = new TextElement(Padding + 56, rowY + 2, _localization.NoControllerText, PlayerTextSize, new SKColor(128, 128, 128)) // Gray
|
||||||
{
|
{
|
||||||
Name = $"NoControllerText_{i}",
|
Name = $"NoControllerText_{i}",
|
||||||
FontStyle = SKFontStyle.Italic
|
FontStyle = SKFontStyle.Italic
|
||||||
};
|
};
|
||||||
AddElement(noControllerText);
|
AddElement(noControllerTextElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate total height and update background
|
// Calculate total height and update background
|
||||||
float totalHeight = Padding + 40 + (4 * (PlayerRowHeight + PlayerSpacing)) + Padding + 40; // Extra space for duration text
|
float totalHeight = Padding + 40 + (playerIndices.Length * (PlayerRowHeight + PlayerSpacing)) + Padding + 20;
|
||||||
var background = FindElement<RectangleElement>("Background");
|
var background = FindElement<RectangleElement>("Background");
|
||||||
if (background != null)
|
if (background != null)
|
||||||
{
|
{
|
||||||
background.Height = totalHeight;
|
background.Height = totalHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duration text at bottom
|
|
||||||
string durationText = durationSeconds == 1
|
|
||||||
? "This overlay will disappear in 1 second"
|
|
||||||
: $"This overlay will disappear in {durationSeconds} seconds";
|
|
||||||
|
|
||||||
// Show the overlay (position will be set by Window class with actual dimensions)
|
// Show the overlay (position will be set by Window class with actual dimensions)
|
||||||
IsVisible = true;
|
IsVisible = true;
|
||||||
}
|
}
|
||||||
|
@ -150,19 +173,24 @@ namespace Ryujinx.Graphics.Gpu.Overlay
|
||||||
1 => new SKColor(54, 162, 235), // Blue for Player 2
|
1 => new SKColor(54, 162, 235), // Blue for Player 2
|
||||||
2 => new SKColor(255, 206, 84), // Yellow for Player 3
|
2 => new SKColor(255, 206, 84), // Yellow for Player 3
|
||||||
3 => new SKColor(75, 192, 192), // Green for Player 4
|
3 => new SKColor(75, 192, 192), // Green for Player 4
|
||||||
|
4 => new SKColor(153, 102, 255), // Purple for Player 5
|
||||||
|
5 => new SKColor(255, 159, 64), // Orange for Player 6
|
||||||
|
6 => new SKColor(199, 199, 199), // Light Gray for Player 7
|
||||||
|
7 => new SKColor(83, 102, 255), // Indigo for Player 8
|
||||||
|
8 => new SKColor(255, 99, 132), // Pink for Handheld
|
||||||
_ => new SKColor(128, 128, 128) // Gray fallback
|
_ => new SKColor(128, 128, 128) // Gray fallback
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetControllerDisplayName(OriginalInputConfig config)
|
private string GetControllerDisplayName(OriginalInputConfig config)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(config.Name))
|
if (string.IsNullOrEmpty(config.Name))
|
||||||
{
|
{
|
||||||
return config.Backend switch
|
return config.Backend switch
|
||||||
{
|
{
|
||||||
OriginalInputBackendType.WindowKeyboard => "Keyboard",
|
OriginalInputBackendType.WindowKeyboard => _localization.KeyboardText,
|
||||||
OriginalInputBackendType.GamepadSDL2 => "Controller",
|
OriginalInputBackendType.GamepadSDL2 => _localization.ControllerText,
|
||||||
_ => "Unknown"
|
_ => _localization.UnknownText
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,9 @@ namespace Ryujinx.Graphics.Gpu.Overlay
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ImageElement : OverlayElement
|
public class ImageElement : OverlayElement
|
||||||
{
|
{
|
||||||
private SKBitmap? _bitmap;
|
private SKBitmap _bitmap;
|
||||||
private byte[]? _imageData;
|
private byte[] _imageData;
|
||||||
private string? _imagePath;
|
private string _imagePath;
|
||||||
|
|
||||||
public SKFilterQuality FilterQuality { get; set; } = SKFilterQuality.Medium;
|
public SKFilterQuality FilterQuality { get; set; } = SKFilterQuality.Medium;
|
||||||
public bool MaintainAspectRatio { get; set; } = true;
|
public bool MaintainAspectRatio { get; set; } = true;
|
||||||
|
|
|
@ -107,9 +107,6 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
_overlayManager = new OverlayManager();
|
_overlayManager = new OverlayManager();
|
||||||
|
|
||||||
_frameQueue = new ConcurrentQueue<PresentationTexture>();
|
_frameQueue = new ConcurrentQueue<PresentationTexture>();
|
||||||
|
|
||||||
// Initialize controller overlay
|
|
||||||
InitializeControllerOverlay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -258,12 +255,11 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize controller overlay
|
/// Add overlay to the overlay manager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeControllerOverlay()
|
public void AddOverlay(Overlay.Overlay overlay)
|
||||||
{
|
{
|
||||||
var controllerOverlay = new ControllerOverlay();
|
_overlayManager.AddOverlay(overlay);
|
||||||
_overlayManager.AddOverlay(controllerOverlay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -363,17 +359,6 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Show controller overlay with the provided input configurations
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inputConfigs">List of input configurations to display</param>
|
|
||||||
/// <param name="durationSeconds">Duration to show the overlay in seconds</param>
|
|
||||||
public void ShowControllerBindings(List<Common.Configuration.Hid.InputConfig> inputConfigs, int durationSeconds = 3)
|
|
||||||
{
|
|
||||||
var controllerOverlay = _overlayManager.FindOverlay("ControllerOverlay") as ControllerOverlay;
|
|
||||||
controllerOverlay?.ShowControllerBindings(inputConfigs, durationSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the overlay manager for external access
|
/// Get the overlay manager for external access
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -19,5 +19,10 @@ namespace Ryujinx.Ava.Common
|
||||||
CycleInputDevicePlayer2,
|
CycleInputDevicePlayer2,
|
||||||
CycleInputDevicePlayer3,
|
CycleInputDevicePlayer3,
|
||||||
CycleInputDevicePlayer4,
|
CycleInputDevicePlayer4,
|
||||||
|
CycleInputDevicePlayer5,
|
||||||
|
CycleInputDevicePlayer6,
|
||||||
|
CycleInputDevicePlayer7,
|
||||||
|
CycleInputDevicePlayer8,
|
||||||
|
CycleInputDeviceHandheld,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Avalonia.Data.Converters;
|
||||||
using Avalonia.Markup.Xaml.MarkupExtensions;
|
using Avalonia.Markup.Xaml.MarkupExtensions;
|
||||||
using Projektanker.Icons.Avalonia;
|
using Projektanker.Icons.Avalonia;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
@ -18,11 +19,19 @@ namespace Ryujinx.Ava.Common.Markup
|
||||||
|
|
||||||
internal class LocaleExtension(LocaleKeys key) : BasicMarkupExtension<string>
|
internal class LocaleExtension(LocaleKeys key) : BasicMarkupExtension<string>
|
||||||
{
|
{
|
||||||
|
public IValueConverter Converter { get; set; }
|
||||||
|
|
||||||
public override string Name => "Translation";
|
public override string Name => "Translation";
|
||||||
protected override string Value => LocaleManager.Instance[key];
|
protected override string Value => LocaleManager.Instance[key];
|
||||||
|
|
||||||
protected override void ConfigureBindingExtension(CompiledBindingExtension bindingExtension)
|
protected override void ConfigureBindingExtension(CompiledBindingExtension bindingExtension)
|
||||||
=> bindingExtension.Source = LocaleManager.Instance;
|
{
|
||||||
|
bindingExtension.Source = LocaleManager.Instance;
|
||||||
|
if (Converter != null)
|
||||||
|
{
|
||||||
|
bindingExtension.Converter = Converter;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class WindowTitleExtension(LocaleKeys key, bool includeVersion) : BasicMarkupExtension<string>
|
internal class WindowTitleExtension(LocaleKeys key, bool includeVersion) : BasicMarkupExtension<string>
|
||||||
|
|
|
@ -33,6 +33,7 @@ using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.GAL.Multithreading;
|
using Ryujinx.Graphics.GAL.Multithreading;
|
||||||
using Ryujinx.Graphics.Gpu;
|
using Ryujinx.Graphics.Gpu;
|
||||||
|
using Ryujinx.Graphics.Gpu.Overlay;
|
||||||
using Ryujinx.Graphics.OpenGL;
|
using Ryujinx.Graphics.OpenGL;
|
||||||
using Ryujinx.Graphics.Vulkan;
|
using Ryujinx.Graphics.Vulkan;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
|
@ -129,6 +130,7 @@ namespace Ryujinx.Ava.Systems
|
||||||
private readonly bool _isFirmwareTitle;
|
private readonly bool _isFirmwareTitle;
|
||||||
|
|
||||||
private readonly Lock _lockObject = new();
|
private readonly Lock _lockObject = new();
|
||||||
|
private ControllerOverlay _controllerOverlay;
|
||||||
|
|
||||||
public event EventHandler AppExit;
|
public event EventHandler AppExit;
|
||||||
public event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
|
public event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
|
||||||
|
@ -932,6 +934,18 @@ namespace Ryujinx.Ava.Systems
|
||||||
_viewModel.UiHandler
|
_viewModel.UiHandler
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Initialize controller overlay with localization
|
||||||
|
var localization = new ControllerOverlayLocalization
|
||||||
|
{
|
||||||
|
TitleText = LocaleManager.Instance[LocaleKeys.ControllerOverlayTitle],
|
||||||
|
NoControllerText = LocaleManager.Instance[LocaleKeys.ControllerOverlayNoController],
|
||||||
|
KeyboardText = LocaleManager.Instance[LocaleKeys.ControllerOverlayKeyboard],
|
||||||
|
ControllerText = LocaleManager.Instance[LocaleKeys.ControllerOverlayController],
|
||||||
|
UnknownText = LocaleManager.Instance[LocaleKeys.ControllerOverlayUnknown]
|
||||||
|
};
|
||||||
|
_controllerOverlay = new ControllerOverlay(localization);
|
||||||
|
Device.Gpu.Window.AddOverlay(_controllerOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IHardwareDeviceDriver InitializeAudio()
|
private static IHardwareDeviceDriver InitializeAudio()
|
||||||
|
@ -1350,6 +1364,21 @@ namespace Ryujinx.Ava.Systems
|
||||||
case KeyboardHotkeyState.CycleInputDevicePlayer4:
|
case KeyboardHotkeyState.CycleInputDevicePlayer4:
|
||||||
CycleInputDevice(HLE.HOS.Services.Hid.PlayerIndex.Player4);
|
CycleInputDevice(HLE.HOS.Services.Hid.PlayerIndex.Player4);
|
||||||
break;
|
break;
|
||||||
|
case KeyboardHotkeyState.CycleInputDevicePlayer5:
|
||||||
|
CycleInputDevice(HLE.HOS.Services.Hid.PlayerIndex.Player5);
|
||||||
|
break;
|
||||||
|
case KeyboardHotkeyState.CycleInputDevicePlayer6:
|
||||||
|
CycleInputDevice(HLE.HOS.Services.Hid.PlayerIndex.Player6);
|
||||||
|
break;
|
||||||
|
case KeyboardHotkeyState.CycleInputDevicePlayer7:
|
||||||
|
CycleInputDevice(HLE.HOS.Services.Hid.PlayerIndex.Player7);
|
||||||
|
break;
|
||||||
|
case KeyboardHotkeyState.CycleInputDevicePlayer8:
|
||||||
|
CycleInputDevice(HLE.HOS.Services.Hid.PlayerIndex.Player8);
|
||||||
|
break;
|
||||||
|
case KeyboardHotkeyState.CycleInputDeviceHandheld:
|
||||||
|
CycleInputDevice(HLE.HOS.Services.Hid.PlayerIndex.Handheld);
|
||||||
|
break;
|
||||||
case KeyboardHotkeyState.None:
|
case KeyboardHotkeyState.None:
|
||||||
(_keyboardInterface as AvaloniaKeyboard).Clear();
|
(_keyboardInterface as AvaloniaKeyboard).Clear();
|
||||||
break;
|
break;
|
||||||
|
@ -1458,7 +1487,7 @@ namespace Ryujinx.Ava.Systems
|
||||||
NpadManager.ReloadConfiguration(currentConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse);
|
NpadManager.ReloadConfiguration(currentConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse);
|
||||||
|
|
||||||
// Show controller overlay
|
// Show controller overlay
|
||||||
ShowControllerOverlay(currentConfig);
|
ShowControllerOverlay(currentConfig, ConfigurationState.Instance.ControllerOverlayInputCycleDuration.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputConfig CreateDefaultInputConfig((DeviceType Type, string Id, string Name) device, PlayerIndex playerIndex)
|
private InputConfig CreateDefaultInputConfig((DeviceType Type, string Id, string Name) device, PlayerIndex playerIndex)
|
||||||
|
@ -1476,21 +1505,17 @@ namespace Ryujinx.Ava.Systems
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ShowControllerOverlay(List<InputConfig> inputConfigs, int duration)
|
||||||
|
|
||||||
private void ShowControllerOverlay(List<InputConfig> inputConfigs)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Show overlay through the GPU context window directly
|
if (_controllerOverlay != null)
|
||||||
if (Device?.Gpu?.Window != null)
|
|
||||||
{
|
{
|
||||||
int duration = ConfigurationState.Instance.ControllerOverlayInputCycleDuration.Value;
|
_controllerOverlay.ShowControllerBindings(inputConfigs, duration);
|
||||||
Device.Gpu.Window.ShowControllerBindings(inputConfigs, duration);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, "AppHost: Cannot show overlay - Device.Gpu.Window is null");
|
Logger.Warning?.Print(LogClass.Application, "AppHost: Cannot show overlay - ControllerOverlay is null");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -1567,6 +1592,26 @@ namespace Ryujinx.Ava.Systems
|
||||||
{
|
{
|
||||||
state = KeyboardHotkeyState.CycleInputDevicePlayer4;
|
state = KeyboardHotkeyState.CycleInputDevicePlayer4;
|
||||||
}
|
}
|
||||||
|
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CycleInputDevicePlayer5))
|
||||||
|
{
|
||||||
|
state = KeyboardHotkeyState.CycleInputDevicePlayer5;
|
||||||
|
}
|
||||||
|
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CycleInputDevicePlayer6))
|
||||||
|
{
|
||||||
|
state = KeyboardHotkeyState.CycleInputDevicePlayer6;
|
||||||
|
}
|
||||||
|
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CycleInputDevicePlayer7))
|
||||||
|
{
|
||||||
|
state = KeyboardHotkeyState.CycleInputDevicePlayer7;
|
||||||
|
}
|
||||||
|
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CycleInputDevicePlayer8))
|
||||||
|
{
|
||||||
|
state = KeyboardHotkeyState.CycleInputDevicePlayer8;
|
||||||
|
}
|
||||||
|
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CycleInputDeviceHandheld))
|
||||||
|
{
|
||||||
|
state = KeyboardHotkeyState.CycleInputDeviceHandheld;
|
||||||
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace Ryujinx.Ava.Systems.Configuration
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current version of the file format
|
/// The current version of the file format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int CurrentVersion = 71;
|
public const int CurrentVersion = 72;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version of the configuration file format
|
/// Version of the configuration file format
|
||||||
|
|
|
@ -486,6 +486,34 @@ namespace Ryujinx.Ava.Systems.Configuration
|
||||||
{
|
{
|
||||||
cff.ControllerOverlayGameStartDuration = 3;
|
cff.ControllerOverlayGameStartDuration = 3;
|
||||||
cff.ControllerOverlayInputCycleDuration = 2;
|
cff.ControllerOverlayInputCycleDuration = 2;
|
||||||
|
}),
|
||||||
|
(72, static cff =>
|
||||||
|
{
|
||||||
|
cff.Hotkeys = new KeyboardHotkeys
|
||||||
|
{
|
||||||
|
ToggleVSyncMode = cff.Hotkeys.ToggleVSyncMode,
|
||||||
|
Screenshot = cff.Hotkeys.Screenshot,
|
||||||
|
ShowUI = cff.Hotkeys.ShowUI,
|
||||||
|
Pause = cff.Hotkeys.Pause,
|
||||||
|
ToggleMute = cff.Hotkeys.ToggleMute,
|
||||||
|
ResScaleUp = cff.Hotkeys.ResScaleUp,
|
||||||
|
ResScaleDown = cff.Hotkeys.ResScaleDown,
|
||||||
|
VolumeUp = cff.Hotkeys.VolumeUp,
|
||||||
|
VolumeDown = cff.Hotkeys.VolumeDown,
|
||||||
|
CustomVSyncIntervalIncrement = cff.Hotkeys.CustomVSyncIntervalIncrement,
|
||||||
|
CustomVSyncIntervalDecrement = cff.Hotkeys.CustomVSyncIntervalDecrement,
|
||||||
|
TurboMode = cff.Hotkeys.TurboMode,
|
||||||
|
TurboModeWhileHeld = cff.Hotkeys.TurboModeWhileHeld,
|
||||||
|
CycleInputDevicePlayer1 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer2 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer3 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer4 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer5 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer6 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer7 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer8 = Key.Unbound,
|
||||||
|
CycleInputDeviceHandheld = Key.Unbound
|
||||||
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,7 +273,16 @@ namespace Ryujinx.Ava.Systems.Configuration
|
||||||
CustomVSyncIntervalIncrement = Key.Unbound,
|
CustomVSyncIntervalIncrement = Key.Unbound,
|
||||||
CustomVSyncIntervalDecrement = Key.Unbound,
|
CustomVSyncIntervalDecrement = Key.Unbound,
|
||||||
TurboMode = Key.Unbound,
|
TurboMode = Key.Unbound,
|
||||||
TurboModeWhileHeld = false
|
TurboModeWhileHeld = false,
|
||||||
|
CycleInputDevicePlayer1 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer2 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer3 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer4 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer5 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer6 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer7 = Key.Unbound,
|
||||||
|
CycleInputDevicePlayer8 = Key.Unbound,
|
||||||
|
CycleInputDeviceHandheld = Key.Unbound
|
||||||
};
|
};
|
||||||
Hid.RainbowSpeed.Value = 1f;
|
Hid.RainbowSpeed.Value = 1f;
|
||||||
Hid.InputConfig.Value =
|
Hid.InputConfig.Value =
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
using Avalonia.Data.Converters;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Helpers
|
||||||
|
{
|
||||||
|
internal class PlayerHotkeyLabelConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public static readonly PlayerHotkeyLabelConverter Instance = new();
|
||||||
|
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value is string playerName && !string.IsNullOrEmpty(playerName))
|
||||||
|
{
|
||||||
|
string baseText = LocaleManager.Instance[LocaleKeys.SettingsTabHotkeysCycleInputDevicePlayerX];
|
||||||
|
return string.Format(baseText, playerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,6 +40,16 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||||
|
|
||||||
[ObservableProperty] private Key _cycleInputDevicePlayer4;
|
[ObservableProperty] private Key _cycleInputDevicePlayer4;
|
||||||
|
|
||||||
|
[ObservableProperty] private Key _cycleInputDevicePlayer5;
|
||||||
|
|
||||||
|
[ObservableProperty] private Key _cycleInputDevicePlayer6;
|
||||||
|
|
||||||
|
[ObservableProperty] private Key _cycleInputDevicePlayer7;
|
||||||
|
|
||||||
|
[ObservableProperty] private Key _cycleInputDevicePlayer8;
|
||||||
|
|
||||||
|
[ObservableProperty] private Key _cycleInputDeviceHandheld;
|
||||||
|
|
||||||
public HotkeyConfig(KeyboardHotkeys config)
|
public HotkeyConfig(KeyboardHotkeys config)
|
||||||
{
|
{
|
||||||
if (config == null)
|
if (config == null)
|
||||||
|
@ -62,6 +72,11 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||||
CycleInputDevicePlayer2 = config.CycleInputDevicePlayer2;
|
CycleInputDevicePlayer2 = config.CycleInputDevicePlayer2;
|
||||||
CycleInputDevicePlayer3 = config.CycleInputDevicePlayer3;
|
CycleInputDevicePlayer3 = config.CycleInputDevicePlayer3;
|
||||||
CycleInputDevicePlayer4 = config.CycleInputDevicePlayer4;
|
CycleInputDevicePlayer4 = config.CycleInputDevicePlayer4;
|
||||||
|
CycleInputDevicePlayer5 = config.CycleInputDevicePlayer5;
|
||||||
|
CycleInputDevicePlayer6 = config.CycleInputDevicePlayer6;
|
||||||
|
CycleInputDevicePlayer7 = config.CycleInputDevicePlayer7;
|
||||||
|
CycleInputDevicePlayer8 = config.CycleInputDevicePlayer8;
|
||||||
|
CycleInputDeviceHandheld = config.CycleInputDeviceHandheld;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyboardHotkeys GetConfig() =>
|
public KeyboardHotkeys GetConfig() =>
|
||||||
|
@ -83,7 +98,12 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||||
CycleInputDevicePlayer1 = CycleInputDevicePlayer1,
|
CycleInputDevicePlayer1 = CycleInputDevicePlayer1,
|
||||||
CycleInputDevicePlayer2 = CycleInputDevicePlayer2,
|
CycleInputDevicePlayer2 = CycleInputDevicePlayer2,
|
||||||
CycleInputDevicePlayer3 = CycleInputDevicePlayer3,
|
CycleInputDevicePlayer3 = CycleInputDevicePlayer3,
|
||||||
CycleInputDevicePlayer4 = CycleInputDevicePlayer4
|
CycleInputDevicePlayer4 = CycleInputDevicePlayer4,
|
||||||
|
CycleInputDevicePlayer5 = CycleInputDevicePlayer5,
|
||||||
|
CycleInputDevicePlayer6 = CycleInputDevicePlayer6,
|
||||||
|
CycleInputDevicePlayer7 = CycleInputDevicePlayer7,
|
||||||
|
CycleInputDevicePlayer8 = CycleInputDevicePlayer8,
|
||||||
|
CycleInputDeviceHandheld = CycleInputDeviceHandheld
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1600,9 +1600,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
// Code where conditions will be executed after loading user configuration
|
// Code where conditions will be executed after loading user configuration
|
||||||
if (ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString() != backendThreadingInit)
|
if (ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString() != backendThreadingInit)
|
||||||
{
|
{
|
||||||
Rebooter.RebootAppWithGame(application.Path,
|
Rebooter.RebootAppWithGame(application.Path,
|
||||||
[
|
[
|
||||||
"--bt",
|
"--bt",
|
||||||
ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString()
|
ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -1710,10 +1710,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
// Always show overlay - if no configs, it will show test data
|
// Always show overlay - if no configs, it will show test data
|
||||||
int duration = ConfigurationState.Instance.ControllerOverlayGameStartDuration.Value;
|
int duration = ConfigurationState.Instance.ControllerOverlayGameStartDuration.Value;
|
||||||
// Show overlay through the GPU context window directly
|
// Show overlay through the GPU context window directly
|
||||||
if (AppHost?.Device?.Gpu?.Window != null)
|
AppHost.ShowControllerOverlay(inputConfigs, duration);
|
||||||
{
|
|
||||||
AppHost.Device.Gpu.Window.ShowControllerBindings(inputConfigs, duration);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -121,29 +121,59 @@
|
||||||
<CheckBox IsChecked="{Binding KeyboardHotkey.TurboModeWhileHeld}" />
|
<CheckBox IsChecked="{Binding KeyboardHotkey.TurboModeWhileHeld}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock Text="{ext:Locale SettingsTabHotkeysCycleInputDevicePlayer1}" Classes="settingHeader" />
|
<TextBlock Text="{ext:Locale ControllerSettingsPlayer1, Converter={x:Static helpers:PlayerHotkeyLabelConverter.Instance}}" Classes="settingHeader" />
|
||||||
<ToggleButton Name="CycleInputDevicePlayer1">
|
<ToggleButton Name="CycleInputDevicePlayer1">
|
||||||
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer1, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer1, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock Text="{ext:Locale SettingsTabHotkeysCycleInputDevicePlayer2}" Classes="settingHeader" />
|
<TextBlock Text="{ext:Locale ControllerSettingsPlayer2, Converter={x:Static helpers:PlayerHotkeyLabelConverter.Instance}}" Classes="settingHeader" />
|
||||||
<ToggleButton Name="CycleInputDevicePlayer2">
|
<ToggleButton Name="CycleInputDevicePlayer2">
|
||||||
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer2, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer2, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock Text="{ext:Locale SettingsTabHotkeysCycleInputDevicePlayer3}" Classes="settingHeader" />
|
<TextBlock Text="{ext:Locale ControllerSettingsPlayer3, Converter={x:Static helpers:PlayerHotkeyLabelConverter.Instance}}" Classes="settingHeader" />
|
||||||
<ToggleButton Name="CycleInputDevicePlayer3">
|
<ToggleButton Name="CycleInputDevicePlayer3">
|
||||||
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer3, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer3, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock Text="{ext:Locale SettingsTabHotkeysCycleInputDevicePlayer4}" Classes="settingHeader" />
|
<TextBlock Text="{ext:Locale ControllerSettingsPlayer4, Converter={x:Static helpers:PlayerHotkeyLabelConverter.Instance}}" Classes="settingHeader" />
|
||||||
<ToggleButton Name="CycleInputDevicePlayer4">
|
<ToggleButton Name="CycleInputDevicePlayer4">
|
||||||
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer4, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer4, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="{ext:Locale ControllerSettingsPlayer5, Converter={x:Static helpers:PlayerHotkeyLabelConverter.Instance}}" Classes="settingHeader" />
|
||||||
|
<ToggleButton Name="CycleInputDevicePlayer5">
|
||||||
|
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer5, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="{ext:Locale ControllerSettingsPlayer6, Converter={x:Static helpers:PlayerHotkeyLabelConverter.Instance}}" Classes="settingHeader" />
|
||||||
|
<ToggleButton Name="CycleInputDevicePlayer6">
|
||||||
|
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer6, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="{ext:Locale ControllerSettingsPlayer7, Converter={x:Static helpers:PlayerHotkeyLabelConverter.Instance}}" Classes="settingHeader" />
|
||||||
|
<ToggleButton Name="CycleInputDevicePlayer7">
|
||||||
|
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer7, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="{ext:Locale ControllerSettingsPlayer8, Converter={x:Static helpers:PlayerHotkeyLabelConverter.Instance}}" Classes="settingHeader" />
|
||||||
|
<ToggleButton Name="CycleInputDevicePlayer8">
|
||||||
|
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDevicePlayer8, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="{ext:Locale ControllerSettingsHandheld, Converter={x:Static helpers:PlayerHotkeyLabelConverter.Instance}}" Classes="settingHeader" />
|
||||||
|
<ToggleButton Name="CycleInputDeviceHandheld">
|
||||||
|
<TextBlock Text="{Binding KeyboardHotkey.CycleInputDeviceHandheld, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
|
@ -86,7 +86,12 @@ namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
{ "CycleInputDevicePlayer1", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer1 = Key.Unbound },
|
{ "CycleInputDevicePlayer1", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer1 = Key.Unbound },
|
||||||
{ "CycleInputDevicePlayer2", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer2 = Key.Unbound },
|
{ "CycleInputDevicePlayer2", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer2 = Key.Unbound },
|
||||||
{ "CycleInputDevicePlayer3", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer3 = Key.Unbound },
|
{ "CycleInputDevicePlayer3", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer3 = Key.Unbound },
|
||||||
{ "CycleInputDevicePlayer4", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer4 = Key.Unbound }
|
{ "CycleInputDevicePlayer4", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer4 = Key.Unbound },
|
||||||
|
{ "CycleInputDevicePlayer5", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer5 = Key.Unbound },
|
||||||
|
{ "CycleInputDevicePlayer6", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer6 = Key.Unbound },
|
||||||
|
{ "CycleInputDevicePlayer7", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer7 = Key.Unbound },
|
||||||
|
{ "CycleInputDevicePlayer8", () => viewModel.KeyboardHotkey.CycleInputDevicePlayer8 = Key.Unbound },
|
||||||
|
{ "CycleInputDeviceHandheld", () => viewModel.KeyboardHotkey.CycleInputDeviceHandheld = Key.Unbound }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (buttonActions.TryGetValue(_currentAssigner.ToggledButton.Name, out Action action))
|
if (buttonActions.TryGetValue(_currentAssigner.ToggledButton.Name, out Action action))
|
||||||
|
@ -178,6 +183,21 @@ namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
case "CycleInputDevicePlayer4":
|
case "CycleInputDevicePlayer4":
|
||||||
ViewModel.KeyboardHotkey.CycleInputDevicePlayer4 = buttonValue.AsHidType<Key>();
|
ViewModel.KeyboardHotkey.CycleInputDevicePlayer4 = buttonValue.AsHidType<Key>();
|
||||||
break;
|
break;
|
||||||
|
case "CycleInputDevicePlayer5":
|
||||||
|
ViewModel.KeyboardHotkey.CycleInputDevicePlayer5 = buttonValue.AsHidType<Key>();
|
||||||
|
break;
|
||||||
|
case "CycleInputDevicePlayer6":
|
||||||
|
ViewModel.KeyboardHotkey.CycleInputDevicePlayer6 = buttonValue.AsHidType<Key>();
|
||||||
|
break;
|
||||||
|
case "CycleInputDevicePlayer7":
|
||||||
|
ViewModel.KeyboardHotkey.CycleInputDevicePlayer7 = buttonValue.AsHidType<Key>();
|
||||||
|
break;
|
||||||
|
case "CycleInputDevicePlayer8":
|
||||||
|
ViewModel.KeyboardHotkey.CycleInputDevicePlayer8 = buttonValue.AsHidType<Key>();
|
||||||
|
break;
|
||||||
|
case "CycleInputDeviceHandheld":
|
||||||
|
ViewModel.KeyboardHotkey.CycleInputDeviceHandheld = buttonValue.AsHidType<Key>();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue