Added Support for queueing the Keyboard/Mouse events

before sending them to the ImGui

This featured can be turned on/off per event basis.
Currently, it is turned off for the Key Up/Down
and turned on for Key press, mouse Up/Down/Move
master
Zaafar Ahmed 6 years ago
parent 0d3f689f40
commit 0a4fc113f6
  1. 3
      ClickableTransparentOverlay/ClickableTransparentOverlay.csproj
  2. 348
      ClickableTransparentOverlay/HookController.cs
  3. 1
      ClickableTransparentOverlay/Overlay.cs

@ -86,6 +86,7 @@
<Reference Include="SixLabors.ImageSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="SixLabors.ImageSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\SixLabors.ImageSharp.1.0.0-beta0006\lib\net472\SixLabors.ImageSharp.dll</HintPath> <HintPath>..\packages\SixLabors.ImageSharp.1.0.0-beta0006\lib\net472\SixLabors.ImageSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> <Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll</HintPath> <HintPath>..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
</Reference> </Reference>
@ -149,4 +150,4 @@
<PostBuildEvent> <PostBuildEvent>
</PostBuildEvent> </PostBuildEvent>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

@ -4,17 +4,24 @@
namespace ClickableTransparentOverlay namespace ClickableTransparentOverlay
{ {
using System;
using System.Collections.Generic;
using System.Numerics; using System.Numerics;
using System.Windows.Forms; using System.Windows.Forms;
using Gma.System.MouseKeyHook; using Gma.System.MouseKeyHook;
using ImGuiNET; using ImGuiNET;
/// <summary> /// <summary>
/// This class Hooks the Global Window Mouse/Keyboard events /// This class Hooks the Global Window Keyboard/Mouse events
/// and pass them into ImGui Overlay. /// and pass them into the ImGui Overlay.
///
/// NOTE: This class might miss/skip a Keyboard/Mouse event
/// if ImGui render function takes a lot of time. Report on GitHub
/// if that happens.
/// </summary> /// </summary>
public class HookController public class HookController
{ {
private readonly Stack<HookControllerMessage> messages;
private IKeyboardMouseEvents myHook; private IKeyboardMouseEvents myHook;
private bool enable; private bool enable;
private int windowX; private int windowX;
@ -31,12 +38,23 @@ namespace ClickableTransparentOverlay
/// </param> /// </param>
public HookController(int x, int y) public HookController(int x, int y)
{ {
this.messages = new Stack<HookControllerMessage>();
this.windowX = x; this.windowX = x;
this.windowY = y; this.windowY = y;
this.enable = true; this.enable = true;
this.myHook = Hook.GlobalEvents(); this.myHook = Hook.GlobalEvents();
} }
private enum HookControllerMessageType
{
MouseUpDown,
MouseMove,
MouseWheel,
KeyUp,
KeyDown,
KeyPress,
}
/// <summary> /// <summary>
/// Enable this class functionality ( only call it once ). /// Enable this class functionality ( only call it once ).
/// </summary> /// </summary>
@ -101,144 +119,215 @@ namespace ClickableTransparentOverlay
this.myHook.Dispose(); this.myHook.Dispose();
} }
private void MouseButtonFunction(MouseEventExtArgs e, bool isDownEvent) /// <summary>
/// Tells the HookController if the ImGui is ready to accept keyboard/mouse messages.
/// </summary>
public void PopMessages()
{ {
ImGuiIOPtr io = ImGui.GetIO(); int counter = 0;
switch (e.Button) int maxCounter = 10;
while (counter < maxCounter && this.messages.Count > 0)
{ {
case MouseButtons.Left: var message = this.messages.Pop();
io.MouseDown[0] = isDownEvent; switch (message.Type)
break; {
case MouseButtons.Right: case HookControllerMessageType.MouseUpDown:
io.MouseDown[1] = isDownEvent; this.ProcessMouseUpDown((MouseEventExtArgs)message.E, message.MiscArg, true);
break; break;
case MouseButtons.Middle: case HookControllerMessageType.MouseMove:
io.MouseDown[2] = isDownEvent; this.ProcessMouseMove((MouseEventArgs)message.E, true);
break; break;
case MouseButtons.XButton1: case HookControllerMessageType.MouseWheel:
io.MouseDown[3] = isDownEvent; this.ProcessMouseWheel((MouseEventExtArgs)message.E, true);
break; break;
case MouseButtons.XButton2: case HookControllerMessageType.KeyUp:
io.MouseDown[4] = isDownEvent; this.ProcessKeyUp((KeyEventArgs)message.E, true);
break; break;
case MouseButtons.None: case HookControllerMessageType.KeyDown:
// TODO: Find out what does this None mean this.ProcessKeyDown((KeyEventArgs)message.E, true);
break; break;
default: case HookControllerMessageType.KeyPress:
// TODO: Make a Logger for the whole Overlay this.ProcessKeyPress((KeyPressEventArgs)message.E, true);
break; break;
} default:
break;
}
if (io.WantCaptureMouse) counter++;
{
e.Handled = true;
} }
} }
private void HookMouseUpExt(object sender, MouseEventExtArgs e) private void PushMessage(HookControllerMessageType type, EventArgs e, bool miscArg = false)
{ {
if (this.enable) var message = new HookControllerMessage()
{ {
this.MouseButtonFunction(e, false); Type = type,
} E = e,
MiscArg = miscArg,
};
this.messages.Push(message);
} }
private void HookMouseDownExt(object sender, MouseEventExtArgs e) private void ProcessMouseUpDown(MouseEventExtArgs e, bool isDownEvent, bool shouldSendToImGui)
{ {
if (this.enable) ImGuiIOPtr io = ImGui.GetIO();
if (shouldSendToImGui)
{ {
this.MouseButtonFunction(e, true); switch (e.Button)
{
case MouseButtons.Left:
io.MouseDown[0] = isDownEvent;
break;
case MouseButtons.Right:
io.MouseDown[1] = isDownEvent;
break;
case MouseButtons.Middle:
io.MouseDown[2] = isDownEvent;
break;
case MouseButtons.XButton1:
io.MouseDown[3] = isDownEvent;
break;
case MouseButtons.XButton2:
io.MouseDown[4] = isDownEvent;
break;
case MouseButtons.None:
// TODO: Find out what does this None mean
break;
default:
// TODO: Make a Logger for the whole Overlay
break;
}
} }
} else
private void HookMouseMove(object sender, MouseEventArgs e)
{
if (!this.enable)
{ {
return; this.PushMessage(HookControllerMessageType.MouseUpDown, e, isDownEvent);
} }
ImGuiIOPtr io = ImGui.GetIO(); if (io.WantCaptureMouse)
io.MousePos = new Vector2(e.X - this.windowX, e.Y - this.windowY); {
e.Handled = true;
// TODO: Show ImGUI Cursor/Hide ImGui Cursor }
// ImGui.GetIO().MouseDrawCursor = true;
// Window32 API ShowCursor(false)
} }
private void HookMouseWheelExt(object sender, MouseEventExtArgs e) private void ProcessMouseMove(MouseEventArgs e, bool shouldSendToImGui)
{ {
if (!this.enable) if (shouldSendToImGui)
{ {
return; ImGuiIOPtr io = ImGui.GetIO();
io.MousePos = new Vector2(e.X - this.windowX, e.Y - this.windowY);
// TODO: Show ImGUI Cursor/Hide ImGui Cursor
// ImGui.GetIO().MouseDrawCursor = true;
// Window32 API ShowCursor(false)
}
else
{
this.PushMessage(HookControllerMessageType.MouseMove, e);
} }
}
private void ProcessMouseWheel(MouseEventExtArgs e, bool shouldSendToImGui)
{
ImGuiIOPtr io = ImGui.GetIO(); ImGuiIOPtr io = ImGui.GetIO();
if (io.WantCaptureMouse) if (io.WantCaptureMouse)
{ {
io.MouseWheel = e.Delta / SystemInformation.MouseWheelScrollDelta; if (shouldSendToImGui)
{
io.MouseWheel = e.Delta / SystemInformation.MouseWheelScrollDelta;
}
else
{
this.PushMessage(HookControllerMessageType.MouseWheel, e);
}
e.Handled = true; e.Handled = true;
} }
} }
private void HookKeyUp(object sender, KeyEventArgs e) private void ProcessKeyUp(KeyEventArgs e, bool shouldSendToImGui)
{ {
var io = ImGui.GetIO(); if (shouldSendToImGui)
io.KeysDown[e.KeyValue] = false; {
var io = ImGui.GetIO();
io.KeysDown[e.KeyValue] = false;
switch (e.KeyCode) switch (e.KeyCode)
{
case Keys.LWin:
case Keys.RWin:
io.KeySuper = false;
break;
case Keys.LControlKey:
case Keys.RControlKey:
io.KeyCtrl = false;
break;
case Keys.LMenu:
case Keys.RMenu:
io.KeyAlt = false;
break;
case Keys.LShiftKey:
case Keys.RShiftKey:
io.KeyShift = false;
break;
default:
break;
}
}
else
{ {
case Keys.LWin: this.PushMessage(HookControllerMessageType.KeyUp, e);
case Keys.RWin:
io.KeySuper = false;
break;
case Keys.LControlKey:
case Keys.RControlKey:
io.KeyCtrl = false;
break;
case Keys.LMenu:
case Keys.RMenu:
io.KeyAlt = false;
break;
case Keys.LShiftKey:
case Keys.RShiftKey:
io.KeyShift = false;
break;
default:
break;
} }
} }
private void HookKeyDown(object sender, KeyEventArgs e) private void ProcessKeyDown(KeyEventArgs e, bool shouldSendToImGui)
{ {
if (!this.enable)
{
return;
}
var io = ImGui.GetIO(); var io = ImGui.GetIO();
if (io.WantCaptureKeyboard) if (io.WantCaptureKeyboard)
{ {
io.KeysDown[e.KeyValue] = true; if (shouldSendToImGui)
{
io.KeysDown[e.KeyValue] = true;
}
else
{
this.PushMessage(HookControllerMessageType.KeyDown, e);
}
switch (e.KeyCode) switch (e.KeyCode)
{ {
case Keys.LWin: case Keys.LWin:
case Keys.RWin: case Keys.RWin:
io.KeySuper = true; if (shouldSendToImGui)
{
io.KeySuper = true;
}
break; break;
case Keys.LControlKey: case Keys.LControlKey:
case Keys.RControlKey: case Keys.RControlKey:
io.KeyCtrl = true; if (shouldSendToImGui)
{
io.KeyCtrl = true;
}
e.Handled = true; e.Handled = true;
break; break;
case Keys.LMenu: // LAlt is LMenu case Keys.LMenu: // LAlt is LMenu
case Keys.RMenu: // RAlt is RMenu case Keys.RMenu: // RAlt is RMenu
io.KeyAlt = true; if (shouldSendToImGui)
{
io.KeyAlt = true;
}
break; break;
case Keys.LShiftKey: case Keys.LShiftKey:
case Keys.RShiftKey: case Keys.RShiftKey:
io.KeyShift = true; if (shouldSendToImGui)
{
io.KeyShift = true;
}
break; break;
default: default:
// Ignoring ALT key so we can do ALT+TAB or ALT+F4 etc. // Ignoring ALT key so we can do ALT+TAB or ALT+F4 etc.
@ -257,13 +346,8 @@ namespace ClickableTransparentOverlay
} }
} }
private void HookKeyPress(object sender, KeyPressEventArgs e) private void ProcessKeyPress(KeyPressEventArgs e, bool shouldSendToImGui)
{ {
if (!this.enable)
{
return;
}
var io = ImGui.GetIO(); var io = ImGui.GetIO();
// Ignoring Win/Super key so we can do Win+D or other stuff // Ignoring Win/Super key so we can do Win+D or other stuff
@ -276,9 +360,87 @@ namespace ClickableTransparentOverlay
if (io.WantTextInput || io.WantCaptureKeyboard) if (io.WantTextInput || io.WantCaptureKeyboard)
{ {
io.AddInputCharacter(e.KeyChar); if (shouldSendToImGui)
{
io.AddInputCharacter(e.KeyChar);
}
else
{
this.PushMessage(HookControllerMessageType.KeyPress, e);
}
e.Handled = true; e.Handled = true;
} }
} }
private void HookMouseUpExt(object sender, MouseEventExtArgs e)
{
if (this.enable)
{
this.ProcessMouseUpDown(e, false, false);
}
}
private void HookMouseDownExt(object sender, MouseEventExtArgs e)
{
if (this.enable)
{
this.ProcessMouseUpDown(e, true, false);
}
}
private void HookMouseMove(object sender, MouseEventArgs e)
{
if (!this.enable)
{
return;
}
this.ProcessMouseMove(e, false);
}
private void HookMouseWheelExt(object sender, MouseEventExtArgs e)
{
if (!this.enable)
{
return;
}
this.ProcessMouseWheel(e, false);
}
private void HookKeyUp(object sender, KeyEventArgs e)
{
this.ProcessKeyUp(e, true);
}
private void HookKeyDown(object sender, KeyEventArgs e)
{
if (!this.enable)
{
return;
}
this.ProcessKeyDown(e, true);
}
private void HookKeyPress(object sender, KeyPressEventArgs e)
{
if (!this.enable)
{
return;
}
this.ProcessKeyPress(e, false);
}
private struct HookControllerMessage
{
public HookControllerMessageType Type { get; set; }
public EventArgs E { get; set; }
public bool MiscArg { get; set; }
}
} }
} }

@ -245,6 +245,7 @@ namespace ClickableTransparentOverlay
continue; continue;
} }
hookController.PopMessages();
if (!window.Exists) if (!window.Exists)
{ {
break; break;

Loading…
Cancel
Save