using System.Collections.Concurrent; namespace Terminal.Gui.Drivers; using InputRecord = WindowsConsole.InputRecord; /// /// Input processor for , deals in stream. /// internal class WindowsInputProcessor : InputProcessorImpl { private readonly bool [] _lastWasPressed = new bool [4]; /// public WindowsInputProcessor (ConcurrentQueue inputBuffer) : base (inputBuffer, new WindowsKeyConverter ()) { DriverName = "windows"; } /// public override void EnqueueMouseEvent (IApplication? app, MouseEventArgs mouseEvent) { InputQueue.Enqueue (new () { EventType = WindowsConsole.EventType.Mouse, MouseEvent = ToMouseEventRecord (mouseEvent) }); } /// protected override void Process (InputRecord inputEvent) { switch (inputEvent.EventType) { case WindowsConsole.EventType.Key: // TODO: v1 supported distinct key up/down events on Windows. // 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 DotNetDriver break; case WindowsConsole.EventType.Mouse: MouseEventArgs me = ToMouseEvent (inputEvent.MouseEvent); RaiseMouseEvent (me); break; } } /// /// Converts a Windows-specific mouse event to a . /// /// /// public MouseEventArgs ToMouseEvent (WindowsConsole.MouseEventRecord e) { var mouseFlags = MouseFlags.None; mouseFlags = UpdateMouseFlags ( mouseFlags, e.ButtonState, WindowsConsole.ButtonState.Button1Pressed, MouseFlags.Button1Pressed, MouseFlags.Button1Released, 0); mouseFlags = UpdateMouseFlags ( mouseFlags, e.ButtonState, WindowsConsole.ButtonState.Button2Pressed, MouseFlags.Button2Pressed, MouseFlags.Button2Released, 1); mouseFlags = UpdateMouseFlags ( mouseFlags, e.ButtonState, WindowsConsole.ButtonState.Button4Pressed, MouseFlags.Button4Pressed, MouseFlags.Button4Released, 3); // Deal with button 3 separately because it is considered same as 'rightmost button' if (e.ButtonState.HasFlag (WindowsConsole.ButtonState.Button3Pressed) || e.ButtonState.HasFlag (WindowsConsole.ButtonState.RightmostButtonPressed)) { mouseFlags |= MouseFlags.Button3Pressed; _lastWasPressed [2] = true; } else { if (_lastWasPressed [2]) { mouseFlags |= MouseFlags.Button3Released; _lastWasPressed [2] = false; } } if (e.EventFlags == WindowsConsole.EventFlags.MouseWheeled) { switch ((int)e.ButtonState) { case > 0: mouseFlags = MouseFlags.WheeledUp; break; case < 0: mouseFlags = MouseFlags.WheeledDown; break; } } if (e.EventFlags != WindowsConsole.EventFlags.NoEvent) { switch (e.EventFlags) { case WindowsConsole.EventFlags.MouseMoved: mouseFlags |= MouseFlags.ReportMousePosition; break; } } if (e.ControlKeyState != WindowsConsole.ControlKeyState.NoControlKeyPressed) { switch (e.ControlKeyState) { case WindowsConsole.ControlKeyState.RightAltPressed: case WindowsConsole.ControlKeyState.LeftAltPressed: mouseFlags |= MouseFlags.ButtonAlt; break; case WindowsConsole.ControlKeyState.RightControlPressed: case WindowsConsole.ControlKeyState.LeftControlPressed: mouseFlags |= MouseFlags.ButtonCtrl; break; case WindowsConsole.ControlKeyState.ShiftPressed: mouseFlags |= MouseFlags.ButtonShift; break; } } var result = new MouseEventArgs { Position = new (e.MousePosition.X, e.MousePosition.Y), Flags = mouseFlags }; return result; } private MouseFlags UpdateMouseFlags ( MouseFlags current, WindowsConsole.ButtonState newState, WindowsConsole.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; } /// /// Converts a to a Windows-specific . /// /// /// public WindowsConsole.MouseEventRecord ToMouseEventRecord (MouseEventArgs mouseEvent) { var buttonState = WindowsConsole.ButtonState.NoButtonPressed; var eventFlags = WindowsConsole.EventFlags.NoEvent; var controlKeyState = WindowsConsole.ControlKeyState.NoControlKeyPressed; // Convert button states if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed)) { buttonState |= WindowsConsole.ButtonState.Button1Pressed; } if (mouseEvent.Flags.HasFlag (MouseFlags.Button2Pressed)) { buttonState |= WindowsConsole.ButtonState.Button2Pressed; } if (mouseEvent.Flags.HasFlag (MouseFlags.Button3Pressed)) { buttonState |= WindowsConsole.ButtonState.Button3Pressed; } if (mouseEvent.Flags.HasFlag (MouseFlags.Button4Pressed)) { buttonState |= WindowsConsole.ButtonState.Button4Pressed; } // Convert mouse wheel events if (mouseEvent.Flags.HasFlag (MouseFlags.WheeledUp)) { eventFlags = WindowsConsole.EventFlags.MouseWheeled; buttonState = (WindowsConsole.ButtonState)0x00780000; // Positive value for wheel up } else if (mouseEvent.Flags.HasFlag (MouseFlags.WheeledDown)) { eventFlags = WindowsConsole.EventFlags.MouseWheeled; buttonState = (WindowsConsole.ButtonState)unchecked((int)0xFF880000); // Negative value for wheel down } // Convert movement flag if (mouseEvent.Flags.HasFlag (MouseFlags.ReportMousePosition)) { eventFlags |= WindowsConsole.EventFlags.MouseMoved; } // Convert modifier keys if (mouseEvent.Flags.HasFlag (MouseFlags.ButtonAlt)) { controlKeyState |= WindowsConsole.ControlKeyState.LeftAltPressed; } if (mouseEvent.Flags.HasFlag (MouseFlags.ButtonCtrl)) { controlKeyState |= WindowsConsole.ControlKeyState.LeftControlPressed; } if (mouseEvent.Flags.HasFlag (MouseFlags.ButtonShift)) { controlKeyState |= WindowsConsole.ControlKeyState.ShiftPressed; } return new WindowsConsole.MouseEventRecord { MousePosition = new WindowsConsole.Coord ((short)mouseEvent.Position.X, (short)mouseEvent.Position.Y), ButtonState = buttonState, ControlKeyState = controlKeyState, EventFlags = eventFlags }; } }