mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2026-01-01 00:46:39 +01:00
Add WindowsDriverKeyPairer
This commit is contained in:
@@ -20,6 +20,7 @@ using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Terminal.Gui.ConsoleDrivers;
|
||||
using static Terminal.Gui.ConsoleDrivers.ConsoleKeyMapping;
|
||||
using static Terminal.Gui.SpinnerStyle;
|
||||
|
||||
@@ -1462,7 +1463,7 @@ internal class WindowsDriver : ConsoleDriver
|
||||
/// How long after Esc has been pressed before we give up on getting an Ansi escape sequence
|
||||
/// </summary>
|
||||
private TimeSpan _escTimeout = TimeSpan.FromMilliseconds (50);
|
||||
public AnsiResponseParser<WindowsConsole.InputRecord> Parser { get; set; } = new ();
|
||||
public AnsiResponseParser<WindowsConsole.InputRecord []> Parser { get; set; } = new ();
|
||||
|
||||
internal void ProcessInput (WindowsConsole.InputRecord inputEvent)
|
||||
{
|
||||
@@ -1553,6 +1554,7 @@ internal class WindowsDriver : ConsoleDriver
|
||||
}
|
||||
}
|
||||
|
||||
private WindowsDriverKeyPairer pairer = new WindowsDriverKeyPairer ();
|
||||
private IEnumerable<WindowsConsole.InputRecord> Parse (WindowsConsole.InputRecord inputEvent)
|
||||
{
|
||||
if (inputEvent.EventType != WindowsConsole.EventType.Key)
|
||||
@@ -1561,26 +1563,36 @@ internal class WindowsDriver : ConsoleDriver
|
||||
yield break;
|
||||
}
|
||||
|
||||
// TODO: For now ignore key up events completely
|
||||
if (!inputEvent.KeyEvent.bKeyDown)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
// TODO: Esc on its own is a problem - need a minute delay i.e. if you get Esc but nothing after release it.
|
||||
|
||||
// TODO: keydown/keyup badness
|
||||
var pair = pairer.ProcessInput (inputEvent).ToArray ();
|
||||
|
||||
foreach (var i in ShouldRelease ())
|
||||
{
|
||||
yield return i;
|
||||
}
|
||||
|
||||
foreach (Tuple<char, WindowsConsole.InputRecord> output in
|
||||
Parser.ProcessInput (Tuple.Create(inputEvent.KeyEvent.UnicodeChar,inputEvent)))
|
||||
foreach (var p in pair)
|
||||
{
|
||||
yield return output.Item2;
|
||||
// may be down/up
|
||||
if (p.Length == 2)
|
||||
{
|
||||
var c = p [0].KeyEvent.UnicodeChar;
|
||||
foreach (Tuple<char, WindowsConsole.InputRecord []> output in
|
||||
Parser.ProcessInput (Tuple.Create(c,p)))
|
||||
{
|
||||
foreach (var r in output.Item2)
|
||||
{
|
||||
yield return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// environment doesn't support down/up
|
||||
|
||||
// TODO: what we do in this situation?
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public IEnumerable<WindowsConsole.InputRecord> ShouldRelease ()
|
||||
@@ -1589,11 +1601,10 @@ internal class WindowsDriver : ConsoleDriver
|
||||
if (Parser.State == ParserState.ExpectingBracket &&
|
||||
DateTime.Now - Parser.StateChangedAt > _escTimeout)
|
||||
{
|
||||
foreach (Tuple<char, WindowsConsole.InputRecord> output in Parser.Release ())
|
||||
{
|
||||
yield return output.Item2;
|
||||
}
|
||||
return Parser.Release ().SelectMany (o => o.Item2);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
#if HACK_CHECK_WINCHANGED
|
||||
|
||||
74
Terminal.Gui/ConsoleDrivers/WindowsDriverKeyPairer.cs
Normal file
74
Terminal.Gui/ConsoleDrivers/WindowsDriverKeyPairer.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using static Terminal.Gui.WindowsConsole;
|
||||
|
||||
namespace Terminal.Gui.ConsoleDrivers;
|
||||
class WindowsDriverKeyPairer
|
||||
{
|
||||
private InputRecord? _heldDownEvent = null; // To hold the "down" event
|
||||
|
||||
// Process a single input record at a time
|
||||
public IEnumerable<InputRecord []> ProcessInput (InputRecord record)
|
||||
{
|
||||
// If it's a "down" event, store it as a held event
|
||||
if (IsKeyDown (record))
|
||||
{
|
||||
return HandleKeyDown (record);
|
||||
}
|
||||
// If it's an "up" event, try to match it with the held "down" event
|
||||
else if (IsKeyUp (record))
|
||||
{
|
||||
return HandleKeyUp (record);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it's not a key event, just pass it through
|
||||
return new [] { new [] { record } };
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<InputRecord []> HandleKeyDown (InputRecord record)
|
||||
{
|
||||
// If we already have a held "down" event, release it (unmatched)
|
||||
if (_heldDownEvent != null)
|
||||
{
|
||||
// Release the previous "down" event since there's a new "down"
|
||||
var previousDown = _heldDownEvent.Value;
|
||||
_heldDownEvent = record; // Hold the new "down" event
|
||||
return new [] { new [] { previousDown } };
|
||||
}
|
||||
|
||||
// Hold the new "down" event
|
||||
_heldDownEvent = record;
|
||||
return Enumerable.Empty<InputRecord []> ();
|
||||
}
|
||||
|
||||
private IEnumerable<InputRecord []> HandleKeyUp (InputRecord record)
|
||||
{
|
||||
// If we have a held "down" event that matches this "up" event, release both
|
||||
if (_heldDownEvent != null && IsMatchingKey (record, _heldDownEvent.Value))
|
||||
{
|
||||
var downEvent = _heldDownEvent.Value;
|
||||
_heldDownEvent = null; // Clear the held event
|
||||
return new [] { new [] { downEvent, record } };
|
||||
}
|
||||
else
|
||||
{
|
||||
// No match, release the "up" event by itself
|
||||
return new [] { new [] { record } };
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsKeyDown (InputRecord record)
|
||||
{
|
||||
return record.KeyEvent.bKeyDown;
|
||||
}
|
||||
|
||||
private bool IsKeyUp (InputRecord record)
|
||||
{
|
||||
return !record.KeyEvent.bKeyDown;
|
||||
}
|
||||
|
||||
private bool IsMatchingKey (InputRecord upEvent, InputRecord downEvent)
|
||||
{
|
||||
return upEvent.KeyEvent.UnicodeChar == downEvent.KeyEvent.UnicodeChar;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user