From 8a407d79b78934e8f8ab2da1c87a2388b267d5dc Mon Sep 17 00:00:00 2001 From: Zaafar Ahmed Date: Sun, 13 Jan 2019 16:10:41 -0500 Subject: [PATCH] Added Code to enable keyboard mouse on the overlay added code to show/hide the overlay added code to resize the overlay --- ClickableTransparentOverlay.sln | 6 + .../ClickableTransparentOverlay.csproj | 193 ++++++- ClickableTransparentOverlay/HookController.cs | 204 ++++++++ .../ImGuiController.cs | 490 ++++++++++++++++++ ClickableTransparentOverlay/Overlay.cs | 152 ++++++ ClickableTransparentOverlay/WinApi.cs | 51 ++ ClickableTransparentOverlay/app.config | 4 + .../{deps => }/cimgui.dll | Bin ClickableTransparentOverlay/packages.config | 60 +++ DriverProgram/App.config | 22 + DriverProgram/DriverProgram.csproj | 95 ++++ DriverProgram/Program.cs | 42 ++ DriverProgram/Properties/AssemblyInfo.cs | 36 ++ DriverProgram/packages.config | 7 + README.md | 2 + 15 files changed, 1362 insertions(+), 2 deletions(-) create mode 100644 ClickableTransparentOverlay/HookController.cs create mode 100644 ClickableTransparentOverlay/ImGuiController.cs create mode 100644 ClickableTransparentOverlay/Overlay.cs create mode 100644 ClickableTransparentOverlay/WinApi.cs rename ClickableTransparentOverlay/{deps => }/cimgui.dll (100%) create mode 100644 DriverProgram/App.config create mode 100644 DriverProgram/DriverProgram.csproj create mode 100644 DriverProgram/Program.cs create mode 100644 DriverProgram/Properties/AssemblyInfo.cs create mode 100644 DriverProgram/packages.config diff --git a/ClickableTransparentOverlay.sln b/ClickableTransparentOverlay.sln index c0b6511..1a56a0c 100644 --- a/ClickableTransparentOverlay.sln +++ b/ClickableTransparentOverlay.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 15.0.28307.168 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClickableTransparentOverlay", "ClickableTransparentOverlay\ClickableTransparentOverlay.csproj", "{F5CF8972-D0DA-4FC0-8796-E7C60101C8EA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DriverProgram", "DriverProgram\DriverProgram.csproj", "{370E1945-EF74-4618-A2DE-B5796AC3093E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -15,6 +17,10 @@ Global {F5CF8972-D0DA-4FC0-8796-E7C60101C8EA}.Debug|x64.Build.0 = Debug|x64 {F5CF8972-D0DA-4FC0-8796-E7C60101C8EA}.Release|x64.ActiveCfg = Release|x64 {F5CF8972-D0DA-4FC0-8796-E7C60101C8EA}.Release|x64.Build.0 = Release|x64 + {370E1945-EF74-4618-A2DE-B5796AC3093E}.Debug|x64.ActiveCfg = Debug|x64 + {370E1945-EF74-4618-A2DE-B5796AC3093E}.Debug|x64.Build.0 = Debug|x64 + {370E1945-EF74-4618-A2DE-B5796AC3093E}.Release|x64.ActiveCfg = Release|x64 + {370E1945-EF74-4618-A2DE-B5796AC3093E}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ClickableTransparentOverlay/ClickableTransparentOverlay.csproj b/ClickableTransparentOverlay/ClickableTransparentOverlay.csproj index 5258ce8..ef2ab7a 100644 --- a/ClickableTransparentOverlay/ClickableTransparentOverlay.csproj +++ b/ClickableTransparentOverlay/ClickableTransparentOverlay.csproj @@ -12,6 +12,8 @@ v4.7.2 512 true + + true @@ -39,6 +41,8 @@ x64 prompt MinimumRecommendedRules.ruleset + true + false bin\x64\Release\ @@ -48,6 +52,7 @@ x64 prompt MinimumRecommendedRules.ruleset + true @@ -56,27 +61,204 @@ ..\packages\ImGui.NET.1.66.0\lib\netstandard2.0\ImGui.NET.dll + + ..\packages\Microsoft.DotNet.PlatformAbstractions.2.0.3\lib\net45\Microsoft.DotNet.PlatformAbstractions.dll + + + ..\packages\Microsoft.Extensions.DependencyModel.2.0.3\lib\net451\Microsoft.Extensions.DependencyModel.dll + + + ..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll + True + True + + + ..\packages\NativeLibraryLoader.1.0.10\lib\netstandard2.0\NativeLibraryLoader.dll + + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\packages\SharpDX.4.0.1\lib\net45\SharpDX.dll + + + ..\packages\SharpDX.D3DCompiler.4.0.1\lib\net45\SharpDX.D3DCompiler.dll + + + ..\packages\SharpDX.Direct3D11.4.0.1\lib\net45\SharpDX.Direct3D11.dll + + + ..\packages\SharpDX.DXGI.4.0.1\lib\net45\SharpDX.DXGI.dll + + + ..\packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll + True + True + ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll + + + ..\packages\System.Console.4.3.0\lib\net46\System.Console.dll + True + True + + + ..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll + + + ..\packages\System.Diagnostics.Tracing.4.3.0\lib\net462\System.Diagnostics.Tracing.dll + True + True + + + + ..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll + True + True + + + ..\packages\System.IO.4.3.0\lib\net462\System.IO.dll + True + True + + + ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll + True + True + + + + ..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll + True + True + + + ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll + True + True + + + ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll + True + True + + + ..\packages\System.Linq.4.3.0\lib\net463\System.Linq.dll + True + True + + + ..\packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll + True + True + + + ..\packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll + True + True + + + ..\packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll + True + True + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + ..\packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll + True + True + + + ..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll + True + True + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + ..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll + True + True + + + ..\packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll + True + True + + + ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True + True + + + ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll + True + True + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + True + True + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + True + True + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll + True + True + + + ..\packages\System.Text.RegularExpressions.4.3.0\lib\net463\System.Text.RegularExpressions.dll + True + True + + - + + ..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll + True + True + + + ..\packages\Veldrid.4.5.0\lib\netstandard2.0\Veldrid.dll + + + ..\packages\Veldrid.MetalBindings.4.5.0\lib\netstandard2.0\Veldrid.MetalBindings.dll + + + ..\packages\Veldrid.OpenGLBindings.4.5.0\lib\netstandard2.0\Veldrid.OpenGLBindings.dll + + + ..\packages\Veldrid.SDL2.4.5.0\lib\netstandard2.0\Veldrid.SDL2.dll + + + ..\packages\Veldrid.StartupUtilities.4.5.0\lib\netstandard2.0\Veldrid.StartupUtilities.dll + + + ..\packages\Vk.1.0.21\lib\netstandard1.4\vk.dll + + + + + @@ -91,9 +273,16 @@ - + PreserveNewest + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/ClickableTransparentOverlay/HookController.cs b/ClickableTransparentOverlay/HookController.cs new file mode 100644 index 0000000..bb54d7c --- /dev/null +++ b/ClickableTransparentOverlay/HookController.cs @@ -0,0 +1,204 @@ +namespace ClickableTransparentOverlay +{ + using Gma.System.MouseKeyHook; + using ImGuiNET; + using System.Numerics; + using System.Windows.Forms; + + public class HookController + { + private IKeyboardMouseEvents _hook; + private bool Enable; + private int WindowX; + private int WindowY; + + public HookController(int x, int y) + { + WindowX = x; + WindowY = y; + Enable = true; + _hook = Hook.GlobalEvents(); + } + + public void EnableHooks() + { + _hook.KeyDown += _hook_KeyDown; + _hook.KeyUp += _hook_KeyUp; + _hook.KeyPress += _hook_KeyPress; + + _hook.MouseDownExt += _hook_MouseDownExt; + _hook.MouseMove += _hook_MouseMove; + _hook.MouseUpExt += _hook_MouseUpExt; + + _hook.MouseWheelExt += _hook_MouseWheelExt; + } + + public void UpdateWindowPosition(int x, int y) + { + WindowX = x; + WindowY = y; + } + + public void PauseHooks() + { + Enable = false; + } + + public void ResumeHooks() + { + Enable = true; + } + + private void _hook_MouseWheelExt(object sender, MouseEventExtArgs e) + { + if (!Enable) + { + return; + } + + ImGuiIOPtr io = ImGui.GetIO(); + if (io.WantCaptureMouse) + { + io.MouseWheel = e.Delta / SystemInformation.MouseWheelScrollDelta; + e.Handled = true; + } + } + + private void _hook_MouseUpExt(object sender, MouseEventExtArgs e) + { + if (!Enable) + { + return; + } + + ImGuiIOPtr io = ImGui.GetIO(); + + switch (e.Button) + { + case MouseButtons.Left: + io.MouseDown[0] = false; + break; + case MouseButtons.None: + // TODO: Find out what does this None mean + break; + case MouseButtons.Right: + io.MouseDown[1] = false; + break; + case MouseButtons.Middle: + io.MouseDown[2] = false; + break; + case MouseButtons.XButton1: + io.MouseDown[3] = false; + break; + case MouseButtons.XButton2: + io.MouseDown[4] = false; + break; + default: + // Make a Logger for the whole Overlay + break; + } + + if (io.WantCaptureMouse) + { + e.Handled = true; + } + } + + private void _hook_MouseMove(object sender, MouseEventArgs e) + { + if (!Enable) + { + return; + } + + ImGuiIOPtr io = ImGui.GetIO(); + io.MousePos = new Vector2(e.X - WindowX, e.Y - WindowY); + // TODO: Show ImGUI Cursor/Hide ImGui Cursor + // ImGui.GetIO().MouseDrawCursor = true; + // Window32 API ShowCursor(false) + } + + private void _hook_MouseDownExt(object sender, MouseEventExtArgs e) + { + if (!Enable) + { + return; + } + + ImGuiIOPtr io = ImGui.GetIO(); + if (io.WantCaptureMouse) + { + switch (e.Button) + { + case MouseButtons.Left: + io.MouseDown[0] = true; + e.Handled = true; + break; + case MouseButtons.Right: + io.MouseDown[1] = true; + e.Handled = true; + break; + case MouseButtons.Middle: + io.MouseDown[2] = true; + e.Handled = true; + break; + case MouseButtons.XButton1: + io.MouseDown[3] = true; + e.Handled = true; + break; + case MouseButtons.XButton2: + io.MouseDown[4] = true; + e.Handled = true; + break; + case MouseButtons.None: + // TODO: Find out what does this None mean + break; + default: + // TODO: Make a Logger for the whole Overlay + break; + } + } + } + + private void _hook_KeyPress(object sender, KeyPressEventArgs e) + { + if (!Enable) + { + return; + } + // TODO: + } + + private void _hook_KeyUp(object sender, KeyEventArgs e) + { + if (!Enable) + { + return; + } + // TODO: + } + + private void _hook_KeyDown(object sender, KeyEventArgs e) + { + if (!Enable) + { + return; + } + // TODO: + } + + public void Dispose() + { + _hook.KeyDown -= _hook_KeyDown; + _hook.KeyUp -= _hook_KeyUp; + _hook.KeyPress -= _hook_KeyPress; + + _hook.MouseDownExt -= _hook_MouseDownExt; + _hook.MouseMove -= _hook_MouseMove; + _hook.MouseUpExt -= _hook_MouseUpExt; + + _hook.MouseWheelExt -= _hook_MouseWheelExt; + _hook.Dispose(); + } + } +} diff --git a/ClickableTransparentOverlay/ImGuiController.cs b/ClickableTransparentOverlay/ImGuiController.cs new file mode 100644 index 0000000..2bbc090 --- /dev/null +++ b/ClickableTransparentOverlay/ImGuiController.cs @@ -0,0 +1,490 @@ +namespace ClickableTransparentOverlay +{ + using System; + using System.Collections.Generic; + using System.Numerics; + using System.Reflection; + using System.IO; + using Veldrid; + using System.Runtime.CompilerServices; + using ImGuiNET; + + /// + /// A modified version of ImGui.NET.SampleProgram's ImGuiController. + /// Manages input for ImGui and handles rendering ImGui's DrawLists with Veldrid. + /// + public class ImGuiController : IDisposable + { + private GraphicsDevice _gd; + private bool _frameBegun; + + // Veldrid objects + private DeviceBuffer _vertexBuffer; + private DeviceBuffer _indexBuffer; + private DeviceBuffer _projMatrixBuffer; + private Texture _fontTexture; + private TextureView _fontTextureView; + private Shader _vertexShader; + private Shader _fragmentShader; + private ResourceLayout _layout; + private ResourceLayout _textureLayout; + private Pipeline _pipeline; + private ResourceSet _mainResourceSet; + private ResourceSet _fontTextureResourceSet; + + private IntPtr _fontAtlasID = (IntPtr)1; + + private int _windowWidth; + private int _windowHeight; + private Vector2 _scaleFactor = Vector2.One; + + // Image trackers + private readonly Dictionary _setsByView + = new Dictionary(); + private readonly Dictionary _autoViewsByTexture + = new Dictionary(); + private readonly Dictionary _viewsById = new Dictionary(); + private readonly List _ownedResources = new List(); + private int _lastAssignedID = 100; + + /// + /// Constructs a new ImGuiController. + /// + public ImGuiController(GraphicsDevice gd, OutputDescription outputDescription, int width, int height, int fps) + { + _gd = gd; + _windowWidth = width; + _windowHeight = height; + + IntPtr context = ImGui.CreateContext(); + ImGui.SetCurrentContext(context); + + ImGui.GetIO().Fonts.AddFontDefault(); + + CreateDeviceResources(gd, outputDescription); + SetKeyMappings(); + + SetPerFrameImGuiData(1f / fps); + + ImGui.NewFrame(); + _frameBegun = true; + } + + public void WindowResized(int width, int height) + { + _windowWidth = width; + _windowHeight = height; + } + + public void DestroyDeviceObjects() + { + Dispose(); + } + + public void CreateDeviceResources(GraphicsDevice gd, OutputDescription outputDescription) + { + _gd = gd; + ResourceFactory factory = gd.ResourceFactory; + _vertexBuffer = factory.CreateBuffer(new BufferDescription(10000, BufferUsage.VertexBuffer | BufferUsage.Dynamic)); + _vertexBuffer.Name = "ImGui.NET Vertex Buffer"; + _indexBuffer = factory.CreateBuffer(new BufferDescription(2000, BufferUsage.IndexBuffer | BufferUsage.Dynamic)); + _indexBuffer.Name = "ImGui.NET Index Buffer"; + RecreateFontDeviceTexture(gd); + + _projMatrixBuffer = factory.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer | BufferUsage.Dynamic)); + _projMatrixBuffer.Name = "ImGui.NET Projection Buffer"; + + byte[] vertexShaderBytes = LoadEmbeddedShaderCode(gd.ResourceFactory, "imgui-vertex", ShaderStages.Vertex); + byte[] fragmentShaderBytes = LoadEmbeddedShaderCode(gd.ResourceFactory, "imgui-frag", ShaderStages.Fragment); + _vertexShader = factory.CreateShader(new ShaderDescription(ShaderStages.Vertex, vertexShaderBytes, "VS")); + _fragmentShader = factory.CreateShader(new ShaderDescription(ShaderStages.Fragment, fragmentShaderBytes, "FS")); + + VertexLayoutDescription[] vertexLayouts = new VertexLayoutDescription[] + { + new VertexLayoutDescription( + new VertexElementDescription("in_position", VertexElementSemantic.Position, VertexElementFormat.Float2), + new VertexElementDescription("in_texCoord", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float2), + new VertexElementDescription("in_color", VertexElementSemantic.Color, VertexElementFormat.Byte4_Norm)) + }; + + _layout = factory.CreateResourceLayout(new ResourceLayoutDescription( + new ResourceLayoutElementDescription("ProjectionMatrixBuffer", ResourceKind.UniformBuffer, ShaderStages.Vertex), + new ResourceLayoutElementDescription("MainSampler", ResourceKind.Sampler, ShaderStages.Fragment))); + _textureLayout = factory.CreateResourceLayout(new ResourceLayoutDescription( + new ResourceLayoutElementDescription("MainTexture", ResourceKind.TextureReadOnly, ShaderStages.Fragment))); + + GraphicsPipelineDescription pd = new GraphicsPipelineDescription( + BlendStateDescription.SingleAlphaBlend, + new DepthStencilStateDescription(false, false, ComparisonKind.Always), + new RasterizerStateDescription(FaceCullMode.None, PolygonFillMode.Solid, FrontFace.Clockwise, false, true), + PrimitiveTopology.TriangleList, + new ShaderSetDescription(vertexLayouts, new[] { _vertexShader, _fragmentShader }), + new ResourceLayout[] { _layout, _textureLayout }, + outputDescription); + _pipeline = factory.CreateGraphicsPipeline(ref pd); + + _mainResourceSet = factory.CreateResourceSet(new ResourceSetDescription(_layout, + _projMatrixBuffer, + gd.PointSampler)); + + _fontTextureResourceSet = factory.CreateResourceSet(new ResourceSetDescription(_textureLayout, _fontTextureView)); + } + + /// + /// Gets or creates a handle for a texture to be drawn with ImGui. + /// Pass the returned handle to Image() or ImageButton(). + /// + public IntPtr GetOrCreateImGuiBinding(ResourceFactory factory, TextureView textureView) + { + if (!_setsByView.TryGetValue(textureView, out ResourceSetInfo rsi)) + { + ResourceSet resourceSet = factory.CreateResourceSet(new ResourceSetDescription(_textureLayout, textureView)); + rsi = new ResourceSetInfo(GetNextImGuiBindingID(), resourceSet); + + _setsByView.Add(textureView, rsi); + _viewsById.Add(rsi.ImGuiBinding, rsi); + _ownedResources.Add(resourceSet); + } + + return rsi.ImGuiBinding; + } + + private IntPtr GetNextImGuiBindingID() + { + int newID = _lastAssignedID++; + return (IntPtr)newID; + } + + /// + /// Gets or creates a handle for a texture to be drawn with ImGui. + /// Pass the returned handle to Image() or ImageButton(). + /// + public IntPtr GetOrCreateImGuiBinding(ResourceFactory factory, Texture texture) + { + if (!_autoViewsByTexture.TryGetValue(texture, out TextureView textureView)) + { + textureView = factory.CreateTextureView(texture); + _autoViewsByTexture.Add(texture, textureView); + _ownedResources.Add(textureView); + } + + return GetOrCreateImGuiBinding(factory, textureView); + } + + /// + /// Retrieves the shader texture binding for the given helper handle. + /// + public ResourceSet GetImageResourceSet(IntPtr imGuiBinding) + { + if (!_viewsById.TryGetValue(imGuiBinding, out ResourceSetInfo tvi)) + { + throw new InvalidOperationException("No registered ImGui binding with id " + imGuiBinding.ToString()); + } + + return tvi.ResourceSet; + } + + public void ClearCachedImageResources() + { + foreach (IDisposable resource in _ownedResources) + { + resource.Dispose(); + } + + _ownedResources.Clear(); + _setsByView.Clear(); + _viewsById.Clear(); + _autoViewsByTexture.Clear(); + _lastAssignedID = 100; + } + + private byte[] LoadEmbeddedShaderCode(ResourceFactory factory, string name, ShaderStages stage) + { + switch (factory.BackendType) + { + case GraphicsBackend.Direct3D11: + { + string resourceName = name + ".hlsl.bytes"; + return GetEmbeddedResourceBytes(resourceName); + } + case GraphicsBackend.OpenGL: + { + string resourceName = name + ".glsl"; + return GetEmbeddedResourceBytes(resourceName); + } + case GraphicsBackend.Vulkan: + { + string resourceName = name + ".spv"; + return GetEmbeddedResourceBytes(resourceName); + } + case GraphicsBackend.Metal: + { + string resourceName = name + ".metallib"; + return GetEmbeddedResourceBytes(resourceName); + } + default: + throw new NotImplementedException(); + } + } + + private byte[] GetEmbeddedResourceBytes(string resourceName) + { + Assembly assembly = typeof(ImGuiController).Assembly; + using (Stream s = assembly.GetManifestResourceStream(resourceName)) + { + byte[] ret = new byte[s.Length]; + s.Read(ret, 0, (int)s.Length); + return ret; + } + } + + /// + /// Recreates the device texture used to render text. + /// + public unsafe void RecreateFontDeviceTexture(GraphicsDevice gd) + { + ImGuiIOPtr io = ImGui.GetIO(); + // Build + byte* pixels; + int width, height, bytesPerPixel; + io.Fonts.GetTexDataAsRGBA32(out pixels, out width, out height, out bytesPerPixel); + // Store our identifier + io.Fonts.SetTexID(_fontAtlasID); + + _fontTexture = gd.ResourceFactory.CreateTexture(TextureDescription.Texture2D( + (uint)width, + (uint)height, + 1, + 1, + PixelFormat.R8_G8_B8_A8_UNorm, + TextureUsage.Sampled)); + _fontTexture.Name = "ImGui.NET Font Texture"; + gd.UpdateTexture( + _fontTexture, + (IntPtr)pixels, + (uint)(bytesPerPixel * width * height), + 0, + 0, + 0, + (uint)width, + (uint)height, + 1, + 0, + 0); + _fontTextureView = gd.ResourceFactory.CreateTextureView(_fontTexture); + + io.Fonts.ClearTexData(); + } + + /// + /// Renders the ImGui draw list data. + /// This method requires a because it may create new DeviceBuffers if the size of vertex + /// or index data has increased beyond the capacity of the existing buffers. + /// A is needed to submit drawing and resource update commands. + /// + public void Render(GraphicsDevice gd, CommandList cl) + { + if (_frameBegun) + { + _frameBegun = false; + ImGui.Render(); + RenderImDrawData(ImGui.GetDrawData(), gd, cl); + } + } + + /// + /// Initilizes a new frame + /// + public void InitlizeFrame(float deltaSeconds) + { + if (_frameBegun) + { + ImGui.Render(); + } + + SetPerFrameImGuiData(deltaSeconds); + + _frameBegun = true; + ImGui.NewFrame(); + } + + /// + /// Sets per-frame data based on the associated window. + /// This is called by Update(float). + /// + private void SetPerFrameImGuiData(float deltaSeconds) + { + ImGuiIOPtr io = ImGui.GetIO(); + io.DisplaySize = new Vector2( + _windowWidth / _scaleFactor.X, + _windowHeight / _scaleFactor.Y); + io.DisplayFramebufferScale = _scaleFactor; + io.DeltaTime = deltaSeconds; // DeltaTime is in seconds. + } + + private static void SetKeyMappings() + { + ImGuiIOPtr io = ImGui.GetIO(); + io.KeyMap[(int)ImGuiKey.Tab] = (int)Key.Tab; + io.KeyMap[(int)ImGuiKey.LeftArrow] = (int)Key.Left; + io.KeyMap[(int)ImGuiKey.RightArrow] = (int)Key.Right; + io.KeyMap[(int)ImGuiKey.UpArrow] = (int)Key.Up; + io.KeyMap[(int)ImGuiKey.DownArrow] = (int)Key.Down; + io.KeyMap[(int)ImGuiKey.PageUp] = (int)Key.PageUp; + io.KeyMap[(int)ImGuiKey.PageDown] = (int)Key.PageDown; + io.KeyMap[(int)ImGuiKey.Home] = (int)Key.Home; + io.KeyMap[(int)ImGuiKey.End] = (int)Key.End; + io.KeyMap[(int)ImGuiKey.Delete] = (int)Key.Delete; + io.KeyMap[(int)ImGuiKey.Backspace] = (int)Key.BackSpace; + io.KeyMap[(int)ImGuiKey.Enter] = (int)Key.Enter; + io.KeyMap[(int)ImGuiKey.Escape] = (int)Key.Escape; + io.KeyMap[(int)ImGuiKey.A] = (int)Key.A; + io.KeyMap[(int)ImGuiKey.C] = (int)Key.C; + io.KeyMap[(int)ImGuiKey.V] = (int)Key.V; + io.KeyMap[(int)ImGuiKey.X] = (int)Key.X; + io.KeyMap[(int)ImGuiKey.Y] = (int)Key.Y; + io.KeyMap[(int)ImGuiKey.Z] = (int)Key.Z; + } + + private void RenderImDrawData(ImDrawDataPtr draw_data, GraphicsDevice gd, CommandList cl) + { + uint vertexOffsetInVertices = 0; + uint indexOffsetInElements = 0; + + if (draw_data.CmdListsCount == 0) + { + return; + } + + uint totalVBSize = (uint)(draw_data.TotalVtxCount * Unsafe.SizeOf()); + if (totalVBSize > _vertexBuffer.SizeInBytes) + { + gd.DisposeWhenIdle(_vertexBuffer); + _vertexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription((uint)(totalVBSize * 1.5f), BufferUsage.VertexBuffer | BufferUsage.Dynamic)); + } + + uint totalIBSize = (uint)(draw_data.TotalIdxCount * sizeof(ushort)); + if (totalIBSize > _indexBuffer.SizeInBytes) + { + gd.DisposeWhenIdle(_indexBuffer); + _indexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription((uint)(totalIBSize * 1.5f), BufferUsage.IndexBuffer | BufferUsage.Dynamic)); + } + + for (int i = 0; i < draw_data.CmdListsCount; i++) + { + ImDrawListPtr cmd_list = draw_data.CmdListsRange[i]; + + cl.UpdateBuffer( + _vertexBuffer, + vertexOffsetInVertices * (uint)Unsafe.SizeOf(), + cmd_list.VtxBuffer.Data, + (uint)(cmd_list.VtxBuffer.Size * Unsafe.SizeOf())); + + cl.UpdateBuffer( + _indexBuffer, + indexOffsetInElements * sizeof(ushort), + cmd_list.IdxBuffer.Data, + (uint)(cmd_list.IdxBuffer.Size * sizeof(ushort))); + + vertexOffsetInVertices += (uint)cmd_list.VtxBuffer.Size; + indexOffsetInElements += (uint)cmd_list.IdxBuffer.Size; + } + + // Setup orthographic projection matrix into our constant buffer + ImGuiIOPtr io = ImGui.GetIO(); + Matrix4x4 mvp = Matrix4x4.CreateOrthographicOffCenter( + 0f, + io.DisplaySize.X, + io.DisplaySize.Y, + 0.0f, + -1.0f, + 1.0f); + + _gd.UpdateBuffer(_projMatrixBuffer, 0, ref mvp); + + cl.SetVertexBuffer(0, _vertexBuffer); + cl.SetIndexBuffer(_indexBuffer, IndexFormat.UInt16); + cl.SetPipeline(_pipeline); + cl.SetGraphicsResourceSet(0, _mainResourceSet); + + draw_data.ScaleClipRects(io.DisplayFramebufferScale); + + // Render command lists + int vtx_offset = 0; + int idx_offset = 0; + for (int n = 0; n < draw_data.CmdListsCount; n++) + { + ImDrawListPtr cmd_list = draw_data.CmdListsRange[n]; + for (int cmd_i = 0; cmd_i < cmd_list.CmdBuffer.Size; cmd_i++) + { + ImDrawCmdPtr pcmd = cmd_list.CmdBuffer[cmd_i]; + if (pcmd.UserCallback != IntPtr.Zero) + { + throw new NotImplementedException(); + } + else + { + if (pcmd.TextureId != IntPtr.Zero) + { + if (pcmd.TextureId == _fontAtlasID) + { + cl.SetGraphicsResourceSet(1, _fontTextureResourceSet); + } + else + { + cl.SetGraphicsResourceSet(1, GetImageResourceSet(pcmd.TextureId)); + } + } + + cl.SetScissorRect( + 0, + (uint)pcmd.ClipRect.X, + (uint)pcmd.ClipRect.Y, + (uint)(pcmd.ClipRect.Z - pcmd.ClipRect.X), + (uint)(pcmd.ClipRect.W - pcmd.ClipRect.Y)); + + cl.DrawIndexed(pcmd.ElemCount, 1, (uint)idx_offset, vtx_offset, 0); + } + + idx_offset += (int)pcmd.ElemCount; + } + vtx_offset += cmd_list.VtxBuffer.Size; + } + } + + /// + /// Frees all graphics resources used by the renderer. + /// + public void Dispose() + { + _vertexBuffer.Dispose(); + _indexBuffer.Dispose(); + _projMatrixBuffer.Dispose(); + _fontTexture.Dispose(); + _fontTextureView.Dispose(); + _vertexShader.Dispose(); + _fragmentShader.Dispose(); + _layout.Dispose(); + _textureLayout.Dispose(); + _pipeline.Dispose(); + _mainResourceSet.Dispose(); + + foreach (IDisposable resource in _ownedResources) + { + resource.Dispose(); + } + } + + private struct ResourceSetInfo + { + public readonly IntPtr ImGuiBinding; + public readonly ResourceSet ResourceSet; + + public ResourceSetInfo(IntPtr imGuiBinding, ResourceSet resourceSet) + { + ImGuiBinding = imGuiBinding; + ResourceSet = resourceSet; + } + } + } +} diff --git a/ClickableTransparentOverlay/Overlay.cs b/ClickableTransparentOverlay/Overlay.cs new file mode 100644 index 0000000..59a83e7 --- /dev/null +++ b/ClickableTransparentOverlay/Overlay.cs @@ -0,0 +1,152 @@ +namespace ClickableTransparentOverlay +{ + using System; + using System.Numerics; + using System.Threading; + using System.Windows.Forms; + using Veldrid; + using Veldrid.Sdl2; + using Veldrid.StartupUtilities; + + public class Overlay + { + private static Sdl2Window _window; + private static GraphicsDevice _gd; + private static CommandList _cl; + private static ImGuiController _im_controller; + private static HookController _hook_controller; + private static Thread _ui_thread; + public event EventHandler SubmitUI; + + // UI State + private static Vector4 _clearColor; + private static Vector2 _future_pos; + private static Vector2 _future_size; + private static int _fps; + private static bool _is_visible; + private static bool _require_resize; + private static bool _start_resizing; + private static object _resize_thread_lock; + + public Overlay(int x, int y, int width, int height, int fps) + { + _clearColor = new Vector4(0.00f, 0.00f, 0.00f, 0.00f); + _fps = fps; + _is_visible = true; + // Stuff related to (thread safe) resizing of SDL2Window + _require_resize = false; + _start_resizing = false; + _resize_thread_lock = new object(); + _future_size = Vector2.Zero; + _future_pos = Vector2.Zero; + + _window = new Sdl2Window("Overlay", x, x, width, height, SDL_WindowFlags.Borderless | SDL_WindowFlags.AlwaysOnTop | SDL_WindowFlags.Resizable | SDL_WindowFlags.SkipTaskbar, true); + _gd = VeldridStartup.CreateGraphicsDevice(_window, new GraphicsDeviceOptions(true, null, true), GraphicsBackend.Direct3D11); + WinApi.EnableTransparent(_window.Handle); + _window.Resized += () => + { + _gd.MainSwapchain.Resize((uint)_window.Width, (uint)_window.Height); + _im_controller.WindowResized(_window.Width, _window.Height); + lock (_resize_thread_lock) + { + _require_resize = false; + _start_resizing = false; + } + }; + + _cl = _gd.ResourceFactory.CreateCommandList(); + _im_controller = new ImGuiController(_gd, _gd.MainSwapchain.Framebuffer.OutputDescription, _window.Width, _window.Height, _fps); + _ui_thread = new Thread(WhileLoop); + _hook_controller = new HookController(_window.X, _window.Y); + } + + public void Run() + { + _ui_thread.Start(); + _hook_controller.EnableHooks(); + WinApi.HideConsoleWindow(); + Application.Run(new ApplicationContext()); + } + + public void Dispose() + { + _is_visible = false; + _window.Close(); + _ui_thread.Join(); + _gd.WaitForIdle(); + _im_controller.Dispose(); + _cl.Dispose(); + _gd.Dispose(); + _hook_controller.Dispose(); + WinApi.ShowConsoleWindow(); + Console.WriteLine("All Overlay resources are cleared."); + } + + public void ResizeWindow(int x, int y, int width, int height) + { + // TODO: Add lock here to pause the ImGUI thread before resizing + // TODO: Test mouse/imgui UI in a non-full screen overlay + _future_pos.X = x; + _future_pos.Y = y; + _future_size.X = width; + _future_size.Y = height; + // TODO: move it to _window.Moved + _hook_controller.UpdateWindowPosition(x, y); + _require_resize = true; + } + + public void ShowWindow() + { + // TODO: Test this feature for ImGui Display and Hooks + _hook_controller.ResumeHooks(); + _is_visible = true; + } + + public void HideWindow() + { + //TODO: Test this feature for ImGui Display and Hooks + _hook_controller.PauseHooks(); + _is_visible = false; + } + + private void WhileLoop() + { + while (_window.Exists) + { + lock (_resize_thread_lock) + { + if (_require_resize) + { + if (!_start_resizing) + { + Sdl2Native.SDL_SetWindowPosition(_window.SdlWindowHandle, (int)_future_pos.X, (int)_future_pos.Y); + Sdl2Native.SDL_SetWindowSize(_window.SdlWindowHandle, (int)_future_size.X, (int)_future_size.Y); + _start_resizing = true; + } + continue; + } + } + + if (!_window.Exists) + { + break; + } + + _im_controller.InitlizeFrame(1f / _fps); + + if (_is_visible) + { + SubmitUI?.Invoke(this, new EventArgs()); + } + + _cl.Begin(); + _cl.SetFramebuffer(_gd.MainSwapchain.Framebuffer); + _cl.ClearColorTarget(0, new RgbaFloat(_clearColor.X, _clearColor.Y, _clearColor.Z, _clearColor.W)); + _im_controller.Render(_gd, _cl); + _cl.End(); + _gd.SubmitCommands(_cl); + _gd.SwapBuffers(_gd.MainSwapchain); + } + } + } +} diff --git a/ClickableTransparentOverlay/WinApi.cs b/ClickableTransparentOverlay/WinApi.cs new file mode 100644 index 0000000..198f1c1 --- /dev/null +++ b/ClickableTransparentOverlay/WinApi.cs @@ -0,0 +1,51 @@ +namespace ClickableTransparentOverlay +{ + using System; + using System.Runtime.InteropServices; + + public static class WinApi + { + private const int GWL_EXSTYLE = -20; + private const int WS_EX_LAYERED = 0x80000; + private const int WS_EX_TRANSPARENT = 0x20; + private const int LWA_ALPHA = 0x02; + private const int LWA_COLORKEY = 0x01; + + private const int SW_HIDE = 0x00; + private const int SW_SHOW = 0x05; + + public static void EnableTransparent(IntPtr handle) + { + int windowLong = GetWindowLong(handle, GWL_EXSTYLE) | WS_EX_LAYERED | WS_EX_TRANSPARENT; + SetWindowLong(handle, GWL_EXSTYLE, new IntPtr(windowLong)); + SetLayeredWindowAttributes(handle, 0, 255, LWA_ALPHA | LWA_COLORKEY); + } + + public static void HideConsoleWindow() + { + var handle = GetConsoleWindow(); + ShowWindow(handle, SW_HIDE); + } + + public static void ShowConsoleWindow() + { + var handle = GetConsoleWindow(); + ShowWindow(handle, SW_SHOW); + } + + [DllImport("user32.dll", SetLastError = true)] + private static extern int GetWindowLong(IntPtr hWnd, int nIndex); + + [DllImport("user32.dll", SetLastError = true)] + private static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong); + + [DllImport("user32.dll", SetLastError = true)] + private static extern bool SetLayeredWindowAttributes(IntPtr hWnd, uint crKey, byte bAlpha, uint dwFlags); + + [DllImport("kernel32.dll")] + static extern IntPtr GetConsoleWindow(); + + [DllImport("user32.dll")] + static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + } +} diff --git a/ClickableTransparentOverlay/app.config b/ClickableTransparentOverlay/app.config index 8e3c0a1..a1b0aab 100644 --- a/ClickableTransparentOverlay/app.config +++ b/ClickableTransparentOverlay/app.config @@ -10,6 +10,10 @@ + + + + \ No newline at end of file diff --git a/ClickableTransparentOverlay/deps/cimgui.dll b/ClickableTransparentOverlay/cimgui.dll similarity index 100% rename from ClickableTransparentOverlay/deps/cimgui.dll rename to ClickableTransparentOverlay/cimgui.dll diff --git a/ClickableTransparentOverlay/packages.config b/ClickableTransparentOverlay/packages.config index 63832ef..c0042df 100644 --- a/ClickableTransparentOverlay/packages.config +++ b/ClickableTransparentOverlay/packages.config @@ -1,8 +1,68 @@  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DriverProgram/App.config b/DriverProgram/App.config new file mode 100644 index 0000000..37a645e --- /dev/null +++ b/DriverProgram/App.config @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DriverProgram/DriverProgram.csproj b/DriverProgram/DriverProgram.csproj new file mode 100644 index 0000000..93ccb88 --- /dev/null +++ b/DriverProgram/DriverProgram.csproj @@ -0,0 +1,95 @@ + + + + + Debug + AnyCPU + {370E1945-EF74-4618-A2DE-B5796AC3093E} + Exe + DriverProgram + DriverProgram + v4.7.2 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + true + + + + ..\packages\ImGui.NET.1.66.0\lib\netstandard2.0\ImGui.NET.dll + + + + ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll + + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + + + + + + + + + + + + + + + + + {f5cf8972-d0da-4fc0-8796-e7c60101c8ea} + ClickableTransparentOverlay + + + + \ No newline at end of file diff --git a/DriverProgram/Program.cs b/DriverProgram/Program.cs new file mode 100644 index 0000000..37d98b6 --- /dev/null +++ b/DriverProgram/Program.cs @@ -0,0 +1,42 @@ +namespace DriverProgram +{ + using ClickableTransparentOverlay; + using ImGuiNET; + using System.Threading; + + class Program + { + private static Overlay demo; + private static int Width; + private static int Height; + private static int Fps; + static void Main(string[] args) + { + Width = int.Parse(System.IO.File.ReadAllText("config/width.txt")); + Height = int.Parse(System.IO.File.ReadAllText("config/height.txt")); + Fps = int.Parse(System.IO.File.ReadAllText("config/fps.txt")); + var EndDemo = new Thread(DistroyDemo); + EndDemo.Start(); + StartDemo(); + } + + public static void StartDemo() + { + demo = new Overlay(0, 0, Width, Height, Fps); + demo.SubmitUI += (object sender, System.EventArgs e) => ImGui.ShowDemoWindow(); + demo.Run(); + } + + public static void DistroyDemo() + { + Thread.Sleep(10000); + demo.ResizeWindow(100, 100, 1024, 1024); + Thread.Sleep(10000); + demo.HideWindow(); + Thread.Sleep(10000); + demo.ShowWindow(); + Thread.Sleep(10000); + demo.Dispose(); + } + } +} diff --git a/DriverProgram/Properties/AssemblyInfo.cs b/DriverProgram/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c1cd08a --- /dev/null +++ b/DriverProgram/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DriverProgram")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DriverProgram")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("370e1945-ef74-4618-a2de-b5796ac3093e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DriverProgram/packages.config b/DriverProgram/packages.config new file mode 100644 index 0000000..c8a4541 --- /dev/null +++ b/DriverProgram/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 95a7dd2..8876602 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,5 @@ A library for creating clickable transparent overlay using Win32 API and ImGui.N * ImGui.NET * Veldrid * MouseKeyHook +* .NET Core 2.0 +* .NET Framework 4.7.2 \ No newline at end of file