#nullable enable using System.Collections.Concurrent; using static Terminal.Gui.WindowsConsole; namespace Terminal.Gui; using InputRecord = InputRecord; /// /// Input processor for , deals in stream. /// internal class WindowsInputProcessor : InputProcessor { private readonly bool [] _lastWasPressed = new bool[4]; /// public WindowsInputProcessor (ConcurrentQueue inputBuffer) : base (inputBuffer, new WindowsKeyConverter ()) { } /// protected override void Process (InputRecord inputEvent) { switch (inputEvent.EventType) { case EventType.Key: // TODO: For now ignore keyup because ANSI comes in as down+up which is confusing to try and parse/pair these things up if (!inputEvent.KeyEvent.bKeyDown) { return; } foreach (Tuple released in Parser.ProcessInput (Tuple.Create (inputEvent.KeyEvent.UnicodeChar, inputEvent))) { ProcessAfterParsing (released.Item2); } /* if (inputEvent.KeyEvent.wVirtualKeyCode == (VK)ConsoleKey.Packet) { // Used to pass Unicode characters as if they were keystrokes. // The VK_PACKET key is the low word of a 32-bit // Virtual Key value used for non-keyboard input methods. inputEvent.KeyEvent = FromVKPacketToKeyEventRecord (inputEvent.KeyEvent); } WindowsConsole.ConsoleKeyInfoEx keyInfo = ToConsoleKeyInfoEx (inputEvent.KeyEvent); //Debug.WriteLine ($"event: KBD: {GetKeyboardLayoutName()} {inputEvent.ToString ()} {keyInfo.ToString (keyInfo)}"); KeyCode map = MapKey (keyInfo); if (map == KeyCode.Null) { break; } */ // This follows convention in NetDriver break; case EventType.Mouse: MouseEventArgs me = ToDriverMouse (inputEvent.MouseEvent); OnMouseEvent (me); break; } } /// protected override void ProcessAfterParsing (InputRecord input) { var key = KeyConverter.ToKey (input); if (key != (Key)0) { OnKeyDown (key!); OnKeyUp (key!); } } public MouseEventArgs ToDriverMouse (MouseEventRecord e) { var mouseFlags = MouseFlags.ReportMousePosition; mouseFlags = UpdateMouseFlags (mouseFlags, e.ButtonState, ButtonState.Button1Pressed, MouseFlags.Button1Pressed, MouseFlags.Button1Released, 0); mouseFlags = UpdateMouseFlags (mouseFlags, e.ButtonState, ButtonState.Button2Pressed, MouseFlags.Button2Pressed, MouseFlags.Button2Released, 1); mouseFlags = UpdateMouseFlags (mouseFlags, e.ButtonState, ButtonState.Button4Pressed, MouseFlags.Button4Pressed, MouseFlags.Button4Released, 3); // Deal with button 3 separately because it is considered same as 'rightmost button' if (e.ButtonState.HasFlag (ButtonState.Button3Pressed) || e.ButtonState.HasFlag (ButtonState.RightmostButtonPressed)) { mouseFlags |= MouseFlags.Button3Pressed; _lastWasPressed [2] = true; } else { if (_lastWasPressed [2]) { mouseFlags |= MouseFlags.Button3Released; _lastWasPressed [2] = false; } } if (e.EventFlags == EventFlags.MouseWheeled) { switch ((int)e.ButtonState) { case > 0: mouseFlags = MouseFlags.WheeledUp; break; case < 0: mouseFlags = MouseFlags.WheeledDown; break; } } var result = new MouseEventArgs { Position = new (e.MousePosition.X, e.MousePosition.Y), Flags = mouseFlags }; // TODO: Return keys too return result; } private MouseFlags UpdateMouseFlags ( MouseFlags current, ButtonState newState, ButtonState pressedState, MouseFlags pressedFlag, MouseFlags releasedFlag, int buttonIndex ) { if (newState.HasFlag (pressedState)) { current |= pressedFlag; _lastWasPressed [buttonIndex] = true; } else { if (_lastWasPressed [buttonIndex]) { current |= releasedFlag; _lastWasPressed [buttonIndex] = false; } } return current; } }