mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-06-05 03:49:17 +00:00
Add UI keyboard trace logs for key state and rebinding
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
|
||||||
namespace Ryujinx.Input.Assigner
|
namespace Ryujinx.Input.Assigner
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -24,7 +26,21 @@ namespace Ryujinx.Input.Assigner
|
|||||||
{
|
{
|
||||||
_keyboardState = _keyboard.GetKeyboardStateSnapshot();
|
_keyboardState = _keyboard.GetKeyboardStateSnapshot();
|
||||||
|
|
||||||
_pressedButton ??= GetPressedButtonFromState() ?? GetPressedButtonFromBufferedPress();
|
if (_pressedButton is not null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Button? buttonFromState = GetPressedButtonFromState();
|
||||||
|
Button? buttonFromBufferedPress = buttonFromState is null ? GetPressedButtonFromBufferedPress() : null;
|
||||||
|
|
||||||
|
_pressedButton = buttonFromState ?? buttonFromBufferedPress;
|
||||||
|
|
||||||
|
if (_pressedButton is not null)
|
||||||
|
{
|
||||||
|
string source = buttonFromState is not null ? "state" : "buffered-press";
|
||||||
|
Logger.Debug?.Print(LogClass.UI, $"Keyboard assigner registered key={_pressedButton.Value.AsHidType<Key>()}, source={source}, cancelPressed={ShouldCancel()}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsAnyButtonPressed()
|
public bool IsAnyButtonPressed()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Input;
|
using Ryujinx.Input;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -12,6 +13,13 @@ namespace Ryujinx.Ava.Input
|
|||||||
{
|
{
|
||||||
internal class AvaloniaKeyboardDriver : IKeyboardModeDriver
|
internal class AvaloniaKeyboardDriver : IKeyboardModeDriver
|
||||||
{
|
{
|
||||||
|
private enum PhysicalKeySource
|
||||||
|
{
|
||||||
|
Direct,
|
||||||
|
ObservedFallback,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
private static readonly string[] _keyboardIdentifers = ["0"];
|
private static readonly string[] _keyboardIdentifers = ["0"];
|
||||||
private readonly Control _control;
|
private readonly Control _control;
|
||||||
private readonly HashSet<Key> _semanticPressedKeys;
|
private readonly HashSet<Key> _semanticPressedKeys;
|
||||||
@@ -193,9 +201,11 @@ namespace Ryujinx.Ava.Input
|
|||||||
{
|
{
|
||||||
Key semanticKey = AvaloniaKeyboardMappingHelper.ToInputKey(args.Key);
|
Key semanticKey = AvaloniaKeyboardMappingHelper.ToInputKey(args.Key);
|
||||||
Key resolvedSemanticKey = AvaloniaKeyboardMappingHelper.ToInputKey(args.PhysicalKey, args.Key);
|
Key resolvedSemanticKey = AvaloniaKeyboardMappingHelper.ToInputKey(args.PhysicalKey, args.Key);
|
||||||
ConfigPhysicalKey physicalKey = GetPhysicalInputKey(args, semanticKey);
|
ConfigPhysicalKey physicalKey = GetPhysicalInputKey(args, semanticKey, out PhysicalKeySource physicalKeySource);
|
||||||
bool semanticWasPressed = _semanticPressedKeys.Contains(resolvedSemanticKey);
|
bool semanticWasPressed = _semanticPressedKeys.Contains(resolvedSemanticKey);
|
||||||
bool physicalWasPressed = _physicalPressedKeys.Contains(physicalKey);
|
bool physicalWasPressed = _physicalPressedKeys.Contains(physicalKey);
|
||||||
|
bool bufferedSemanticPress = false;
|
||||||
|
bool bufferedPhysicalPress = false;
|
||||||
|
|
||||||
UpdateKeyState(_semanticPressedKeys, resolvedSemanticKey, isPressed);
|
UpdateKeyState(_semanticPressedKeys, resolvedSemanticKey, isPressed);
|
||||||
UpdateKeyState(_physicalPressedKeys, physicalKey, isPressed);
|
UpdateKeyState(_physicalPressedKeys, physicalKey, isPressed);
|
||||||
@@ -207,11 +217,13 @@ namespace Ryujinx.Ava.Input
|
|||||||
if (!semanticWasPressed && resolvedSemanticKey is not Key.Unknown and not Key.Unbound)
|
if (!semanticWasPressed && resolvedSemanticKey is not Key.Unknown and not Key.Unbound)
|
||||||
{
|
{
|
||||||
_semanticPressedKeyQueue.Enqueue(resolvedSemanticKey);
|
_semanticPressedKeyQueue.Enqueue(resolvedSemanticKey);
|
||||||
|
bufferedSemanticPress = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!physicalWasPressed && physicalKey is not ConfigPhysicalKey.Unknown and not ConfigPhysicalKey.Unbound)
|
if (!physicalWasPressed && physicalKey is not ConfigPhysicalKey.Unknown and not ConfigPhysicalKey.Unbound)
|
||||||
{
|
{
|
||||||
_physicalPressedKeyQueue.Enqueue((Key)(int)physicalKey);
|
_physicalPressedKeyQueue.Enqueue((Key)(int)physicalKey);
|
||||||
|
bufferedPhysicalPress = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,26 +234,38 @@ namespace Ryujinx.Ava.Input
|
|||||||
{
|
{
|
||||||
_observedPhysicalKeysBySemanticKey[semanticKey] = physicalKey;
|
_observedPhysicalKeysBySemanticKey[semanticKey] = physicalKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Trace?.Print(
|
||||||
|
LogClass.UI,
|
||||||
|
$"Keyboard {(isPressed ? "down" : "up")}: avaloniaKey={args.Key}, avaloniaPhysical={args.PhysicalKey}, keySymbol={FormatKeySymbol(args.KeySymbol)}, modifiers={args.KeyModifiers}, semantic={semanticKey}, resolvedSemantic={resolvedSemanticKey}, physical={physicalKey}, physicalSource={physicalKeySource}, bufferedSemantic={bufferedSemanticPress}, bufferedPhysical={bufferedPhysicalPress}, semanticPressed={_semanticPressedKeys.Count}, physicalPressed={_physicalPressedKeys.Count}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConfigPhysicalKey GetPhysicalInputKey(KeyEventArgs args, Key semanticKey)
|
private ConfigPhysicalKey GetPhysicalInputKey(KeyEventArgs args, Key semanticKey, out PhysicalKeySource source)
|
||||||
{
|
{
|
||||||
Key key = AvaloniaKeyboardMappingHelper.ToInputKey(args.PhysicalKey);
|
Key key = AvaloniaKeyboardMappingHelper.ToInputKey(args.PhysicalKey);
|
||||||
|
|
||||||
if (key is >= Key.Unknown and < Key.Count)
|
if (key is >= Key.Unknown and < Key.Count)
|
||||||
{
|
{
|
||||||
|
source = PhysicalKeySource.Direct;
|
||||||
return (ConfigPhysicalKey)(int)key;
|
return (ConfigPhysicalKey)(int)key;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (semanticKey is not Key.Unknown and not Key.Unbound &&
|
if (semanticKey is not Key.Unknown and not Key.Unbound &&
|
||||||
_observedPhysicalKeysBySemanticKey.TryGetValue(semanticKey, out ConfigPhysicalKey observedPhysicalKey))
|
_observedPhysicalKeysBySemanticKey.TryGetValue(semanticKey, out ConfigPhysicalKey observedPhysicalKey))
|
||||||
{
|
{
|
||||||
|
source = PhysicalKeySource.ObservedFallback;
|
||||||
return observedPhysicalKey;
|
return observedPhysicalKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
source = PhysicalKeySource.Unknown;
|
||||||
return ConfigPhysicalKey.Unknown;
|
return ConfigPhysicalKey.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string FormatKeySymbol(string keySymbol)
|
||||||
|
{
|
||||||
|
return string.IsNullOrEmpty(keySymbol) ? "<none>" : keySymbol;
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user