Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
rewrite windows console to use full event data from console api
Browse files Browse the repository at this point in the history
tomlm committed Jan 2, 2025
1 parent 7c1fc1e commit 1e61653
Showing 2 changed files with 107 additions and 69 deletions.
6 changes: 4 additions & 2 deletions src/Consolonia.GuiCS/WindowsDriver.cs
Original file line number Diff line number Diff line change
@@ -31,12 +31,14 @@ public CONSOLE_INPUT_MODE ConsoleMode
{
get
{
GetConsoleMode(InputHandle, out CONSOLE_INPUT_MODE v);
if (!GetConsoleMode(InputHandle, out CONSOLE_INPUT_MODE v))
throw GetLastError().GetException();
return v;
}
set
{
SetConsoleMode(InputHandle, value);
if (!SetConsoleMode(InputHandle, value))
throw GetLastError().GetException();
}
}

170 changes: 103 additions & 67 deletions src/Consolonia.PlatformSupport/WindowsConsole.cs
Original file line number Diff line number Diff line change
@@ -23,38 +23,54 @@ namespace Consolonia.PlatformSupport
public class Win32Console : InputLessDefaultNetConsole
{
private static readonly FlagTranslator<CONTROL_KEY_STATE, RawInputModifiers>
ModifiersFlagTranslator = new(
KeyModifiersTranslator = new(
[
(CONTROL_KEY_STATE.NONE, RawInputModifiers.None),
(CONTROL_KEY_STATE.SHIFT_PRESSED, RawInputModifiers.Shift),
(CONTROL_KEY_STATE.LEFT_ALT_PRESSED, RawInputModifiers.Alt),
(CONTROL_KEY_STATE.RIGHT_ALT_PRESSED, RawInputModifiers.Alt),
(CONTROL_KEY_STATE.LEFT_CTRL_PRESSED, RawInputModifiers.Control),
(CONTROL_KEY_STATE.RIGHT_CTRL_PRESSED, RawInputModifiers.Control)
(CONTROL_KEY_STATE.RIGHT_CTRL_PRESSED, RawInputModifiers.Control),
]);

private static readonly FlagTranslator<MOUSE_BUTTON_STATE, RawInputModifiers>
MouseModifiersTranslator = new(
[
(MOUSE_BUTTON_STATE.NONE, RawInputModifiers.None),
(MOUSE_BUTTON_STATE.FROM_LEFT_1ST_BUTTON_PRESSED, RawInputModifiers.LeftMouseButton),
(MOUSE_BUTTON_STATE.RIGHTMOST_BUTTON_PRESSED, RawInputModifiers.RightMouseButton),
(MOUSE_BUTTON_STATE.FROM_LEFT_2ND_BUTTON_PRESSED, RawInputModifiers.MiddleMouseButton),
(MOUSE_BUTTON_STATE.FROM_LEFT_3RD_BUTTON_PRESSED, RawInputModifiers.XButton1MouseButton),
(MOUSE_BUTTON_STATE.FROM_LEFT_4TH_BUTTON_PRESSED, RawInputModifiers.XButton2MouseButton)
]);


private static readonly FlagTranslator<MOUSE_BUTTON_STATE, RawPointerEventType>
MouseButtonFlagTranslator = new(
MouseButtonDownEventTypeTranslator = new(
[
(MOUSE_BUTTON_STATE.FROM_LEFT_1ST_BUTTON_PRESSED, RawPointerEventType.LeftButtonDown),
(MOUSE_BUTTON_STATE.RIGHTMOST_BUTTON_PRESSED, RawPointerEventType.RightButtonDown),
(MOUSE_BUTTON_STATE.FROM_LEFT_2ND_BUTTON_PRESSED, RawPointerEventType.MiddleButtonDown),
(MOUSE_BUTTON_STATE.FROM_LEFT_3RD_BUTTON_PRESSED, RawPointerEventType.XButton1Down),
(MOUSE_BUTTON_STATE.FROM_LEFT_4TH_BUTTON_PRESSED, RawPointerEventType.XButton2Down)
(MOUSE_BUTTON_STATE.FROM_LEFT_4TH_BUTTON_PRESSED, RawPointerEventType.XButton2Down),
(MOUSE_BUTTON_STATE.NONE, RawPointerEventType.LeaveWindow) // ugh. that's default
]);

private static readonly FlagTranslator<MOUSE_BUTTON_STATE, RawInputModifiers>
MouseModifiersFlagTranslator = new(
private static readonly FlagTranslator<MOUSE_BUTTON_STATE, RawPointerEventType>
MouseButtonUpEventTypeTranslator = new(
[
(MOUSE_BUTTON_STATE.FROM_LEFT_1ST_BUTTON_PRESSED, RawInputModifiers.LeftMouseButton),
(MOUSE_BUTTON_STATE.RIGHTMOST_BUTTON_PRESSED, RawInputModifiers.RightMouseButton),
(MOUSE_BUTTON_STATE.FROM_LEFT_2ND_BUTTON_PRESSED, RawInputModifiers.MiddleMouseButton),
(MOUSE_BUTTON_STATE.FROM_LEFT_3RD_BUTTON_PRESSED, RawInputModifiers.XButton1MouseButton),
(MOUSE_BUTTON_STATE.FROM_LEFT_4TH_BUTTON_PRESSED, RawInputModifiers.XButton2MouseButton)
(MOUSE_BUTTON_STATE.FROM_LEFT_1ST_BUTTON_PRESSED, RawPointerEventType.LeftButtonUp),
(MOUSE_BUTTON_STATE.RIGHTMOST_BUTTON_PRESSED, RawPointerEventType.RightButtonUp),
(MOUSE_BUTTON_STATE.FROM_LEFT_2ND_BUTTON_PRESSED, RawPointerEventType.MiddleButtonUp),
(MOUSE_BUTTON_STATE.FROM_LEFT_3RD_BUTTON_PRESSED, RawPointerEventType.XButton1Up),
(MOUSE_BUTTON_STATE.FROM_LEFT_4TH_BUTTON_PRESSED, RawPointerEventType.XButton2Up),
(MOUSE_BUTTON_STATE.NONE, RawPointerEventType.LeaveWindow) // ugh. that's default
]);


private readonly WindowsConsole _windowsConsole;

private MOUSE_BUTTON_STATE _mouseButtonsState;
private MOUSE_BUTTON_STATE _mouseButtonsState = MOUSE_BUTTON_STATE.NONE;

public Win32Console()
{
@@ -116,10 +132,8 @@ private void StartEventLoop()
HandleKeyInput(inputRecord.Event.KeyEvent);
break;
case EVENT_TYPE.MOUSE_EVENT:

var mouseEvent = inputRecord.Event.MouseEvent;

if (HandleMouseInput(mouseEvent)) return; //todo: implement
HandleMouseInput(mouseEvent);
break;
}
}
@@ -128,87 +142,109 @@ private void StartEventLoop()

private bool HandleMouseInput(MOUSE_EVENT_RECORD mouseEvent)
{

Check warning on line 144 in src/Consolonia.PlatformSupport/WindowsConsole.cs

GitHub Actions / build

"[UnusedMethodReturnValue.Local] Method 'HandleMouseInput' return value is never used" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.PlatformSupport/WindowsConsole.cs(144,17)
var point = new Point(mouseEvent.dwMousePosition.X,
mouseEvent.dwMousePosition.Y);
var modifiers = ModifiersFlagTranslator.Translate(mouseEvent.dwControlKeyState);
var modifiers2 = MouseModifiersFlagTranslator.Translate(mouseEvent.dwButtonState);
RawInputModifiers inputModifiers = modifiers | modifiers;
RawPointerEventType eventType = default;
var point = new Point(mouseEvent.dwMousePosition.X, mouseEvent.dwMousePosition.Y);
RawInputModifiers inputModifiers =
KeyModifiersTranslator.Translate(mouseEvent.dwControlKeyState) |
MouseModifiersTranslator.Translate(mouseEvent.dwButtonState);

RawPointerEventType eventType = RawPointerEventType.Move;
Vector? wheelDelta = null;
short repeat = 1;

switch (mouseEvent.dwEventFlags)
{
case MOUSE_EVENT_FLAG.DOUBLE_CLICK:
repeat = 2; //todo: now supporting only leftbutton
eventType = RawPointerEventType.LeftButtonDown;
var downButtonEvent = MouseButtonDownEventTypeTranslator.Translate(mouseEvent.dwButtonState);
if (downButtonEvent != RawPointerEventType.LeaveWindow)
{
var upButtonEvent = MouseButtonUpEventTypeTranslator.Translate(mouseEvent.dwButtonState);
for (int i = 0; i < 2; i++)
{
RaiseMouseEvent(downButtonEvent,
point,
wheelDelta,
inputModifiers);

RaiseMouseEvent(upButtonEvent,

Check warning on line 167 in src/Consolonia.PlatformSupport/WindowsConsole.cs

GitHub Actions / build

"[ExpressionIsAlwaysNull] Expression is always null" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.PlatformSupport/WindowsConsole.cs(167,33)
point,
wheelDelta,
inputModifiers);
}
}

Check warning on line 172 in src/Consolonia.PlatformSupport/WindowsConsole.cs

GitHub Actions / build

"[ExpressionIsAlwaysNull] Expression is always null" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.PlatformSupport/WindowsConsole.cs(172,33)
break;
case default(MOUSE_EVENT_FLAG):
MOUSE_BUTTON_STATE xor = _mouseButtonsState ^ mouseEvent.dwButtonState;
foreach (RawPointerEventType pointerEventType in (xor &
mouseEvent.dwButtonState).GetFlags()
.Select(MouseButtonFlagTranslator.Translate))
//todo: вернуть mouse gesture на элементы
RaiseMouseEvent(pointerEventType,
point,
null,
inputModifiers);

//todo: refactor: code clone
foreach (RawPointerEventType pointerEventType in (xor &
_mouseButtonsState).GetFlags()
.Select(MouseButtonFlagTranslator.Translate))

case MOUSE_EVENT_FLAG.NONE:
foreach (var flag in Enum.GetValues<MOUSE_BUTTON_STATE>())
{
RawPointerEventType rawPointerEventType = pointerEventType + 1;
RaiseMouseEvent(rawPointerEventType,
point,
null,
inputModifiers);
if (!_mouseButtonsState.HasFlag(flag) && mouseEvent.dwButtonState.HasFlag(flag))
{
// If we went from flag off to flag on
var buttonEventType = MouseButtonDownEventTypeTranslator.Translate(flag);
if (buttonEventType != default)
{
RaiseMouseEvent(buttonEventType,
point,
null,
inputModifiers);
}
}

else if (_mouseButtonsState.HasFlag(flag) && !mouseEvent.dwButtonState.HasFlag(flag))
{
// If we went from flag On to flag off
var buttonEventType = MouseButtonUpEventTypeTranslator.Translate(flag);
if (buttonEventType != default)
{
RaiseMouseEvent(buttonEventType,
point,
null,
inputModifiers);
}
}
else
{
RaiseMouseEvent(eventType,
point,
null,
inputModifiers);
}
}

_mouseButtonsState = mouseEvent.dwButtonState;
repeat = 0;
break;

case MOUSE_EVENT_FLAG.MOUSE_WHEELED:
double velocity = mouseEvent.dwButtonState < 0 ? -1 : 1;
wheelDelta = new Vector(0, velocity);
eventType = RawPointerEventType.Wheel;
RaiseMouseEvent(RawPointerEventType.Wheel,
point,
wheelDelta,
inputModifiers);
break;
case MOUSE_EVENT_FLAG.MOUSE_HWHEELED:
return true;
break;
case MOUSE_EVENT_FLAG.MOUSE_MOVED:
eventType = RawPointerEventType.Move;
RaiseMouseEvent(RawPointerEventType.Move,

Check warning on line 225 in src/Consolonia.PlatformSupport/WindowsConsole.cs

GitHub Actions / build

"[ExpressionIsAlwaysNull] Expression is always null" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.PlatformSupport/WindowsConsole.cs(225,25)
point,
wheelDelta,
inputModifiers);
_mouseButtonsState = mouseEvent.dwButtonState;
break;
case MOUSE_EVENT_FLAG.MOUSE_MOVED | MOUSE_EVENT_FLAG.DOUBLE_CLICK:
RaiseMouseEvent(RawPointerEventType.LeftButtonDown, point, null, inputModifiers);
RaiseMouseEvent(RawPointerEventType.Move, point, null, inputModifiers);
return false;
//RaiseMouseEvent(RawPointerEventType.LeftButtonUp, point, null, inputModifiers);
break;
default:
throw new InvalidOperationException(mouseEvent.dwEventFlags.ToString());
}

for (short i = 0; i < repeat; i++)
{
RaiseMouseEvent(eventType,
point,
wheelDelta,
inputModifiers);

if (eventType <= RawPointerEventType.XButton2Down)
RaiseMouseEvent(eventType + 1,
point,
wheelDelta,
inputModifiers);
}

return false;
_mouseButtonsState = mouseEvent.dwButtonState;
return true;
}

private void HandleKeyInput(KEY_EVENT_RECORD keyEvent)
{
char character = keyEvent.uChar;
RawInputModifiers modifiers =
ModifiersFlagTranslator.Translate(keyEvent.dwControlKeyState);
KeyModifiersTranslator.Translate(keyEvent.dwControlKeyState);
Key key = DefaultNetConsole.ConvertToKey((ConsoleKey)keyEvent.wVirtualKeyCode);
if (key == Key.LeftAlt || key == Key.RightAlt)
modifiers |= RawInputModifiers.Alt;

0 comments on commit 1e61653

Please sign in to comment.