Skip to content

Commit

Permalink
Input: Workaround some issues with some keys not being usable/bindabl…
Browse files Browse the repository at this point in the history
…e as shortcuts (e.g Print Screen)
  • Loading branch information
SourMesen committed Jul 10, 2024
1 parent 9f57622 commit 0996b95
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 8 deletions.
23 changes: 20 additions & 3 deletions UI/Windows/GetKeyWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@
using Mesen.Config;
using Mesen.Utilities;
using Mesen.Localization;
using Avalonia.Remote.Protocol.Input;
using DynamicData;
using Avalonia.Layout;
using System.Diagnostics;

namespace Mesen.Windows
{
Expand All @@ -27,6 +26,9 @@ public class GetKeyWindow : MesenWindow
private TextBlock lblCurrentKey;
private bool _allowKeyboardOnly;

private Stopwatch _stopWatch = Stopwatch.StartNew();
private Dictionary<Key, long> _keyPressedStamp = new();

public string HintLabel { get; }
public bool SingleKeyMode { get; set; } = false;

Expand Down Expand Up @@ -71,16 +73,31 @@ private void OnPreviewKeyDown(object? sender, KeyEventArgs e)
{
InputApi.SetKeyState((UInt16)e.Key, true);
DbgShortcutKey = new DbgShortKeys(e.KeyModifiers, e.Key);
_keyPressedStamp[e.Key] = _stopWatch.ElapsedTicks;
e.Handled = true;
}

private void OnPreviewKeyUp(object? sender, KeyEventArgs e)
{
e.Handled = true;

if(!_allowKeyboardOnly && (!_keyPressedStamp.TryGetValue(e.Key, out long stamp) || ((_stopWatch.ElapsedTicks - stamp) * 1000 / Stopwatch.Frequency) < 10)) {
//Key up received without key down, or key pressed for less than 10 ms, pretend the key was pressed for 50ms
//Some special keys can behave this way (e.g printscreen)
DbgShortcutKey = new DbgShortKeys(e.KeyModifiers, e.Key);
InputApi.SetKeyState((UInt16)e.Key, true);
UpdateKeyDisplay();
DispatcherTimer.RunOnce(() => InputApi.SetKeyState((UInt16)e.Key, false), TimeSpan.FromMilliseconds(50), DispatcherPriority.MaxValue);
_keyPressedStamp.Remove(e.Key);
return;
}

_keyPressedStamp.Remove(e.Key);

InputApi.SetKeyState((UInt16)e.Key, false);
if(_allowKeyboardOnly) {
this.Close();
}
e.Handled = true;
}

protected override void OnOpened(EventArgs e)
Expand Down
22 changes: 17 additions & 5 deletions UI/Windows/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using System.Collections.Generic;
using Mesen.Controls;
using Mesen.Localization;
using System.Diagnostics;

namespace Mesen.Windows
{
Expand Down Expand Up @@ -58,6 +59,9 @@ public class MainWindow : MesenWindow
private Dictionary<Key, IDisposable> _pendingKeyUpEvents = new();
private bool _isLinux = false;

private Stopwatch _stopWatch = Stopwatch.StartNew();
private Dictionary<Key, long> _keyPressedStamp = new();

static MainWindow()
{
WindowStateProperty.Changed.AddClassHandler<MainWindow>((x, e) => x.OnWindowStateChanged());
Expand Down Expand Up @@ -558,11 +562,6 @@ private bool ProcessTestModeShortcuts(Key key)
return false;
}

private static bool IsModifierKey(Key key)
{
return key == Key.LeftShift || key == Key.LeftCtrl || key == Key.LeftAlt || key == Key.RightShift || key == Key.RightCtrl || key == Key.RightAlt;
}

private void OnPreviewKeyDown(object? sender, KeyEventArgs e)
{
if(_testModeEnabled && e.KeyModifiers == KeyModifiers.Alt && ProcessTestModeShortcuts(e.Key)) {
Expand All @@ -575,6 +574,8 @@ private void OnPreviewKeyDown(object? sender, KeyEventArgs e)
}

if(e.Key != Key.None) {
_keyPressedStamp[e.Key] = _stopWatch.ElapsedTicks;

if(_isLinux && _pendingKeyUpEvents.TryGetValue(e.Key, out IDisposable? cancelTimer)) {
//Cancel any pending key up event
cancelTimer.Dispose();
Expand All @@ -598,6 +599,17 @@ private void OnPreviewKeyUp(object? sender, KeyEventArgs e)
}

if(e.Key != Key.None) {
if(!_keyPressedStamp.TryGetValue(e.Key, out long stamp) || ((_stopWatch.ElapsedTicks - stamp) * 1000 / Stopwatch.Frequency) < 10) {
//Key up received without key down, or key pressed for less than 10 ms, pretend the key was pressed for 50ms
//Some special keys can behave this way (e.g printscreen)
InputApi.SetKeyState((UInt16)e.Key, true);
DispatcherTimer.RunOnce(() => InputApi.SetKeyState((UInt16)e.Key, false), TimeSpan.FromMilliseconds(50), DispatcherPriority.MaxValue);
_keyPressedStamp.Remove(e.Key);
return;
}

_keyPressedStamp.Remove(e.Key);

if(_isLinux) {
//Process keyup events after 1ms on Linux to prevent key repeat from triggering key up/down repeatedly
IDisposable cancelTimer = DispatcherTimer.RunOnce(() => InputApi.SetKeyState((UInt16)e.Key, false), TimeSpan.FromMilliseconds(1), DispatcherPriority.MaxValue);
Expand Down

0 comments on commit 0996b95

Please sign in to comment.