mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
First implementation of mouse events on windows
This commit is contained in:
@@ -1590,14 +1590,12 @@ namespace Terminal.Gui {
|
||||
if (Top != null)
|
||||
return;
|
||||
|
||||
if (!UseSystemConsole) {
|
||||
var p = Environment.OSVersion.Platform;
|
||||
if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows)
|
||||
UseSystemConsole = true;
|
||||
}
|
||||
//UseSystemConsole = true;
|
||||
var p = Environment.OSVersion.Platform;
|
||||
|
||||
if (UseSystemConsole)
|
||||
Driver = new NetDriver ();
|
||||
else if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows)
|
||||
Driver = new WindowsDriver();
|
||||
else
|
||||
Driver = new CursesDriver ();
|
||||
Driver.Init (TerminalResized);
|
||||
|
||||
@@ -238,7 +238,7 @@ namespace Terminal.Gui {
|
||||
currentAttribute = c.value;
|
||||
}
|
||||
|
||||
Key MapKey (ConsoleKeyInfo keyInfo)
|
||||
public Key MapKey (ConsoleKeyInfo keyInfo)
|
||||
{
|
||||
switch (keyInfo.Key) {
|
||||
case ConsoleKey.Escape:
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Mono.Terminal;
|
||||
|
||||
namespace Terminal.Gui {
|
||||
|
||||
@@ -8,9 +10,6 @@ namespace Terminal.Gui {
|
||||
public const int STD_INPUT_HANDLE = -10;
|
||||
public const int STD_ERROR_HANDLE = -12;
|
||||
|
||||
[DllImport ("kernel32.dll", SetLastError = true)]
|
||||
static extern IntPtr GetStdHandle (int nStdHandle);
|
||||
|
||||
IntPtr inputHandle, outputHandle;
|
||||
|
||||
public WindowsConsole ()
|
||||
@@ -19,6 +18,15 @@ namespace Terminal.Gui {
|
||||
outputHandle = GetStdHandle (STD_OUTPUT_HANDLE);
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ConsoleModes : uint
|
||||
{
|
||||
EnableMouseInput = 16,
|
||||
EnableQuickEditMode = 64,
|
||||
EnableExtendedFlags = 128,
|
||||
}
|
||||
|
||||
|
||||
[StructLayout (LayoutKind.Explicit, CharSet = CharSet.Unicode)]
|
||||
public struct KeyEventRecord {
|
||||
[FieldOffset (0), MarshalAs (UnmanagedType.Bool)]
|
||||
@@ -160,6 +168,57 @@ namespace Terminal.Gui {
|
||||
}
|
||||
};
|
||||
|
||||
public void PollEvents(Action<InputRecord> inputEventHandler)
|
||||
{
|
||||
if (OriginalConsoleMode != 0)
|
||||
return;
|
||||
|
||||
OriginalConsoleMode = ConsoleMode;
|
||||
|
||||
ConsoleMode |= (uint)ConsoleModes.EnableMouseInput;
|
||||
ConsoleMode &= ~(uint)ConsoleModes.EnableQuickEditMode;
|
||||
ConsoleMode |= (uint)ConsoleModes.EnableExtendedFlags;
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
uint numberEventsRead = 0;
|
||||
uint length = 1;
|
||||
InputRecord[] records = new InputRecord[length];
|
||||
|
||||
while (
|
||||
ContinueListeningForConsoleEvents &&
|
||||
ReadConsoleInput(inputHandle, records, length, out numberEventsRead) &&
|
||||
numberEventsRead > 0
|
||||
)
|
||||
{
|
||||
inputEventHandler(records[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
{
|
||||
ContinueListeningForConsoleEvents = false;
|
||||
ConsoleMode = OriginalConsoleMode;
|
||||
OriginalConsoleMode = 0;
|
||||
}
|
||||
|
||||
private bool ContinueListeningForConsoleEvents = true;
|
||||
|
||||
private uint OriginalConsoleMode = 0;
|
||||
|
||||
public uint ConsoleMode {
|
||||
get {
|
||||
uint v;
|
||||
GetConsoleMode (inputHandle, out v);
|
||||
return v;
|
||||
}
|
||||
|
||||
set {
|
||||
SetConsoleMode (inputHandle, value);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport ("kernel32.dll", EntryPoint = "ReadConsoleInputW", CharSet = CharSet.Unicode)]
|
||||
public static extern bool ReadConsoleInput (
|
||||
IntPtr hConsoleInput,
|
||||
@@ -173,21 +232,93 @@ namespace Terminal.Gui {
|
||||
[DllImport ("kernel32.dll")]
|
||||
static extern bool SetConsoleMode (IntPtr hConsoleHandle, uint dwMode);
|
||||
|
||||
public uint ConsoleMode {
|
||||
get {
|
||||
uint v;
|
||||
GetConsoleMode (inputHandle, out v);
|
||||
return v;
|
||||
}
|
||||
[DllImport ("kernel32.dll", SetLastError = true)]
|
||||
static extern IntPtr GetStdHandle (int nStdHandle);
|
||||
|
||||
}
|
||||
|
||||
internal class WindowsDriver : NetDriver {
|
||||
|
||||
WindowsConsole WinConsole;
|
||||
|
||||
set {
|
||||
SetConsoleMode (inputHandle, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
public class WindowsDriver {
|
||||
public WindowsDriver ()
|
||||
{
|
||||
WinConsole = new WindowsConsole();
|
||||
}
|
||||
|
||||
private MouseEvent ToDriverMouse(WindowsConsole.MouseEventRecord mouseEvent)
|
||||
{
|
||||
MouseFlags mouseFlag = MouseFlags.AllEvents;
|
||||
|
||||
if (mouseEvent.EventFlags == 0)
|
||||
{
|
||||
switch (mouseEvent.ButtonState)
|
||||
{
|
||||
case WindowsConsole.ButtonState.Button1Pressed:
|
||||
mouseFlag = MouseFlags.Button1Clicked;
|
||||
break;
|
||||
|
||||
case WindowsConsole.ButtonState.Button2Pressed:
|
||||
mouseFlag = MouseFlags.Button2Clicked;
|
||||
break;
|
||||
|
||||
case WindowsConsole.ButtonState.Button3Pressed:
|
||||
mouseFlag = MouseFlags.Button3Clicked;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved)
|
||||
{
|
||||
mouseFlag = MouseFlags.ReportMousePosition;
|
||||
}
|
||||
|
||||
|
||||
return new MouseEvent () {
|
||||
X = mouseEvent.MousePosition.X,
|
||||
Y = mouseEvent.MousePosition.Y,
|
||||
Flags = mouseFlag
|
||||
};
|
||||
}
|
||||
|
||||
private ConsoleKeyInfo ToConsoleKeyInfo(WindowsConsole.KeyEventRecord keyEvent)
|
||||
{
|
||||
var state = keyEvent.dwControlKeyState;
|
||||
|
||||
bool shift = (state & WindowsConsole.ControlKeyState.ShiftPressed) != 0;
|
||||
bool alt = (state & (WindowsConsole.ControlKeyState.LeftAltPressed | WindowsConsole.ControlKeyState.RightAltPressed)) != 0;
|
||||
bool control = (state & (WindowsConsole.ControlKeyState.LeftControlPressed | WindowsConsole.ControlKeyState.RightControlPressed)) != 0;
|
||||
|
||||
return new ConsoleKeyInfo(keyEvent.UnicodeChar, (ConsoleKey)keyEvent.wVirtualKeyCode, shift, alt, control);
|
||||
}
|
||||
|
||||
public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<MouseEvent> mouseHandler)
|
||||
{
|
||||
WinConsole.PollEvents (inputEvent =>
|
||||
{
|
||||
switch(inputEvent.EventType)
|
||||
{
|
||||
case WindowsConsole.EventType.Key:
|
||||
if (inputEvent.KeyEvent.bKeyDown == false)
|
||||
return;
|
||||
var map = MapKey (ToConsoleKeyInfo (inputEvent.KeyEvent));
|
||||
if (map == (Key) 0xffffffff)
|
||||
return;
|
||||
keyHandler (new KeyEvent (map));
|
||||
break;
|
||||
|
||||
case WindowsConsole.EventType.Mouse:
|
||||
mouseHandler (ToDriverMouse (inputEvent.MouseEvent));
|
||||
break;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override void End()
|
||||
{
|
||||
WinConsole.Cleanup();
|
||||
base.End();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,10 +128,13 @@ namespace Mono.Terminal {
|
||||
read (wakeupPipes [0], ignore, (IntPtr)1);
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
Thread readThread = new Thread (WindowsKeyReader);
|
||||
readThread.Start ();
|
||||
}
|
||||
// Using this results in buggy behavior when we are hooking into ReadConsoleInput api ourselves
|
||||
// Because if left in both custom code and this one tries to read from the consoleInput
|
||||
// else {
|
||||
// Thread readThread = new Thread (WindowsKeyReader);
|
||||
// readThread.Start ();
|
||||
// }
|
||||
}
|
||||
|
||||
void Wakeup ()
|
||||
|
||||
Reference in New Issue
Block a user