@ -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,9 +119,61 @@ 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 ( )
{
int counter = 0 ;
int maxCounter = 1 0 ;
while ( counter < maxCounter & & this . messages . Count > 0 )
{
var message = this . messages . Pop ( ) ;
switch ( message . Type )
{
case HookControllerMessageType . MouseUpDown :
this . ProcessMouseUpDown ( ( MouseEventExtArgs ) message . E , message . MiscArg , true ) ;
break ;
case HookControllerMessageType . MouseMove :
this . ProcessMouseMove ( ( MouseEventArgs ) message . E , true ) ;
break ;
case HookControllerMessageType . MouseWheel :
this . ProcessMouseWheel ( ( MouseEventExtArgs ) message . E , true ) ;
break ;
case HookControllerMessageType . KeyUp :
this . ProcessKeyUp ( ( KeyEventArgs ) message . E , true ) ;
break ;
case HookControllerMessageType . KeyDown :
this . ProcessKeyDown ( ( KeyEventArgs ) message . E , true ) ;
break ;
case HookControllerMessageType . KeyPress :
this . ProcessKeyPress ( ( KeyPressEventArgs ) message . E , true ) ;
break ;
default :
break ;
}
counter + + ;
}
}
private void PushMessage ( HookControllerMessageType type , EventArgs e , bool miscArg = false )
{
var message = new HookControllerMessage ( )
{
Type = type ,
E = e ,
MiscArg = miscArg ,
} ;
this . messages . Push ( message ) ;
}
private void ProcessMouseUpDown ( MouseEventExtArgs e , bool isDownEvent , bool shouldSendToImGui )
{
{
ImGuiIOPtr io = ImGui . GetIO ( ) ;
ImGuiIOPtr io = ImGui . GetIO ( ) ;
if ( shouldSendToImGui )
{
switch ( e . Button )
switch ( e . Button )
{
{
case MouseButtons . Left :
case MouseButtons . Left :
@ -128,36 +198,22 @@ namespace ClickableTransparentOverlay
// TODO: Make a Logger for the whole Overlay
// TODO: Make a Logger for the whole Overlay
break ;
break ;
}
}
if ( io . WantCaptureMouse )
{
e . Handled = true ;
}
}
}
else
private void HookMouseUpExt ( object sender , MouseEventExtArgs e )
{
{
if ( this . enable )
this . PushMessage ( HookControllerMessageType . MouseUpDown , e , isDownEvent ) ;
{
this . MouseButtonFunction ( e , false ) ;
}
}
}
private void HookMouseDownExt ( object sender , MouseEventExtArgs e )
if ( io . WantCaptureMouse )
{
if ( this . enable )
{
{
this . MouseButtonFunction ( e , true ) ;
e . Handled = true ;
}
}
}
}
private void HookMouseMove ( object sender , MouseEventArgs e )
private void ProcessMouseMove ( MouseEventArgs e , bool shouldSendToImGui )
{
{
if ( ! this . enable )
if ( shouldSendToImGui )
{
{
return ;
}
ImGuiIOPtr io = ImGui . GetIO ( ) ;
ImGuiIOPtr io = ImGui . GetIO ( ) ;
io . MousePos = new Vector2 ( e . X - this . windowX , e . Y - this . windowY ) ;
io . MousePos = new Vector2 ( e . X - this . windowX , e . Y - this . windowY ) ;
@ -165,23 +221,33 @@ namespace ClickableTransparentOverlay
// ImGui.GetIO().MouseDrawCursor = true;
// ImGui.GetIO().MouseDrawCursor = true;
// Window32 API ShowCursor(false)
// Window32 API ShowCursor(false)
}
}
else
private void HookMouseWheelExt ( object sender , MouseEventExtArgs e )
{
{
if ( ! this . enable )
this . PushMessage ( HookControllerMessageType . MouseMove , e ) ;
{
}
return ;
}
}
private void ProcessMouseWheel ( MouseEventExtArgs e , bool shouldSendToImGui )
{
ImGuiIOPtr io = ImGui . GetIO ( ) ;
ImGuiIOPtr io = ImGui . GetIO ( ) ;
if ( io . WantCaptureMouse )
if ( io . WantCaptureMouse )
{
if ( shouldSendToImGui )
{
{
io . MouseWheel = e . Delta / SystemInformation . MouseWheelScrollDelta ;
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 )
{
if ( shouldSendToImGui )
{
{
var io = ImGui . GetIO ( ) ;
var io = ImGui . GetIO ( ) ;
io . KeysDown [ e . KeyValue ] = false ;
io . KeysDown [ e . KeyValue ] = false ;
@ -208,37 +274,60 @@ namespace ClickableTransparentOverlay
break ;
break ;
}
}
}
}
else
private void HookKeyDown ( object sender , KeyEventArgs e )
{
{
if ( ! this . enable )
this . PushMessage ( HookControllerMessageType . KeyUp , e ) ;
{
}
return ;
}
}
private void ProcessKeyDown ( KeyEventArgs e , bool shouldSendToImGui )
{
var io = ImGui . GetIO ( ) ;
var io = ImGui . GetIO ( ) ;
if ( io . WantCaptureKeyboard )
if ( io . WantCaptureKeyboard )
{
if ( shouldSendToImGui )
{
{
io . KeysDown [ e . KeyValue ] = true ;
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 :
if ( shouldSendToImGui )
{
io . KeySuper = true ;
io . KeySuper = true ;
}
break ;
break ;
case Keys . LControlKey :
case Keys . LControlKey :
case Keys . RControlKey :
case Keys . RControlKey :
if ( shouldSendToImGui )
{
io . KeyCtrl = true ;
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
if ( shouldSendToImGui )
{
io . KeyAlt = true ;
io . KeyAlt = true ;
}
break ;
break ;
case Keys . LShiftKey :
case Keys . LShiftKey :
case Keys . RShiftKey :
case Keys . RShiftKey :
if ( shouldSendToImGui )
{
io . KeyShift = true ;
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
@ -275,10 +359,88 @@ namespace ClickableTransparentOverlay
}
}
if ( io . WantTextInput | | io . WantCaptureKeyboard )
if ( io . WantTextInput | | io . WantCaptureKeyboard )
{
if ( shouldSendToImGui )
{
{
io . AddInputCharacter ( e . KeyChar ) ;
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 ; }
}
}
}
}
}