diff --git a/Src/ContainerModule.cs b/Src/ContainerModule.cs index 9a92724..de6289a 100644 --- a/Src/ContainerModule.cs +++ b/Src/ContainerModule.cs @@ -1,5 +1,4 @@ using Autofac; -using NClicker.Hooks; using NClicker.Repositories; using NClicker.Services; using NClicker.Storage; @@ -20,10 +19,10 @@ protected override void Load(ContainerBuilder builder) builder.Register(c => new MouseControllerService(new System.Random())) .As().SingleInstance(); - builder.Register(c => new GlobalKeyboardHook()).SingleInstance(); + builder.Register(c => new GlobalKeyboardService()).SingleInstance(); builder.Register(c => new KeyboardService( - c.Resolve())).As().SingleInstance(); + c.Resolve())).As().SingleInstance(); builder.Register(c => new MainViewModel(c.Resolve(), c.Resolve())).SingleInstance(); diff --git a/Src/Helpers/Win32KernelApi.cs b/Src/Helpers/Win32KernelApi.cs new file mode 100644 index 0000000..4a03932 --- /dev/null +++ b/Src/Helpers/Win32KernelApi.cs @@ -0,0 +1,49 @@ +using NClicker.Services; +using System; +using System.Runtime.InteropServices; + +namespace NClicker.Helpers +{ + public class Win32KernelApi + { + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + public static extern IntPtr LoadLibrary(string lpFileName); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + public static extern bool FreeLibrary(IntPtr hModule); + + /// + /// The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. + /// You would install a hook procedure to monitor the system for certain types of events. These events are + /// associated either with a specific thread or with all threads in the same desktop as the calling thread. + /// + /// hook type + /// hook procedure + /// handle to application instance + /// thread identifier + /// If the function succeeds, the return value is the handle to the hook procedure. + [DllImport("USER32", SetLastError = true)] + public static extern IntPtr SetWindowsHookEx(int idHook, GlobalKeyboardService.HookProc hookProc, IntPtr hMod, int dwThreadId); + /// + /// The UnhookWindowsHookEx function removes a hook procedure installed in a hook chain by the SetWindowsHookEx function. + /// + /// handle to hook procedure + /// If the function succeeds, the return value is true. + [DllImport("USER32", SetLastError = true)] + public static extern bool UnhookWindowsHookEx(IntPtr hHook); + + /// + /// The CallNextHookEx function passes the hook information to the next hook procedure in the current hook chain. + /// A hook procedure can call this function either before or after processing the hook information. + /// + /// handle to current hook + /// hook code passed to hook procedure + /// value passed to hook procedure + /// value passed to hook procedure + /// If the function succeeds, the return value is true. + [DllImport("USER32", SetLastError = true)] + public static extern IntPtr CallNextHookEx(IntPtr hHook, int code, IntPtr wParam, IntPtr lParam); + + + } +} diff --git a/Src/Hooks/GlobalKeyboardHookEventArgs.cs b/Src/Hooks/GlobalKeyboardHookEventArgs.cs deleted file mode 100644 index c98f5fa..0000000 --- a/Src/Hooks/GlobalKeyboardHookEventArgs.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.ComponentModel; - -namespace NClicker.Hooks -{ - public class GlobalKeyboardHookEventArgs : HandledEventArgs - { - public GlobalKeyboardHook.KeyboardState KeyboardState { get; } - public GlobalKeyboardHook.LowLevelKeyboardInputEvent KeyboardData { get; } - - public GlobalKeyboardHookEventArgs( - GlobalKeyboardHook.LowLevelKeyboardInputEvent keyboardData, - GlobalKeyboardHook.KeyboardState keyboardState) - { - KeyboardData = keyboardData; - KeyboardState = keyboardState; - } - } -} \ No newline at end of file diff --git a/Src/Models/GlobalKeyboardHookEventArgs.cs b/Src/Models/GlobalKeyboardHookEventArgs.cs new file mode 100644 index 0000000..adcceb0 --- /dev/null +++ b/Src/Models/GlobalKeyboardHookEventArgs.cs @@ -0,0 +1,18 @@ +using NClicker.Services; +using System.ComponentModel; + +namespace NClicker.Models +{ + public class GlobalKeyboardHookEventArgs : HandledEventArgs + { + public GlobalKeyboardService.KeyboardState KeyboardState { get; } + public GlobalKeyboardService.LowLevelKeyboardInputEvent KeyboardData { get; } + + public GlobalKeyboardHookEventArgs(GlobalKeyboardService.LowLevelKeyboardInputEvent keyboardData, + GlobalKeyboardService.KeyboardState keyboardState) + { + KeyboardData = keyboardData; + KeyboardState = keyboardState; + } + } +} \ No newline at end of file diff --git a/Src/NClicker.csproj b/Src/NClicker.csproj index 459cb00..2404ae9 100644 --- a/Src/NClicker.csproj +++ b/Src/NClicker.csproj @@ -14,6 +14,7 @@ https://github.com/Buryyy/NClicker nclicker.png NClicker.App + true diff --git a/Src/Hooks/GlobalKeyboardHook.cs b/Src/Services/GlobalKeyboardService.cs similarity index 62% rename from Src/Hooks/GlobalKeyboardHook.cs rename to Src/Services/GlobalKeyboardService.cs index ab3cde7..17059cf 100644 --- a/Src/Hooks/GlobalKeyboardHook.cs +++ b/Src/Services/GlobalKeyboardService.cs @@ -1,22 +1,28 @@ -using System; +using NClicker.Helpers; +using NClicker.Models; +using System; using System.ComponentModel; using System.Diagnostics; using System.Runtime.InteropServices; -namespace NClicker.Hooks +namespace NClicker.Services { - public sealed class GlobalKeyboardHook : IDisposable + public sealed class GlobalKeyboardService : IDisposable { public event EventHandler KeyboardPressed; + private IntPtr _windowsHookHandle; + private IntPtr _user32LibraryHandle; + private HookProc _hookProc; + + public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam); - public GlobalKeyboardHook() + public GlobalKeyboardService() { _windowsHookHandle = IntPtr.Zero; _user32LibraryHandle = IntPtr.Zero; - _hookProc = - LowLevelKeyboardProc; // we must keep alive _hookProc, because GC is not aware about SetWindowsHookEx behaviour. + _hookProc = LowLevelKeyboardProc; // we must keep alive _hookProc, because GC is not aware about SetWindowsHookEx behaviour. - _user32LibraryHandle = LoadLibrary("User32"); + _user32LibraryHandle = Win32KernelApi.LoadLibrary("User32"); if (_user32LibraryHandle == IntPtr.Zero) { int errorCode = Marshal.GetLastWin32Error(); @@ -24,7 +30,7 @@ public GlobalKeyboardHook() $"Failed to load library 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}."); } - _windowsHookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, _hookProc, _user32LibraryHandle, 0); + _windowsHookHandle = Win32KernelApi.SetWindowsHookEx(WH_KEYBOARD_LL, _hookProc, _user32LibraryHandle, 0); if (_windowsHookHandle == IntPtr.Zero) { int errorCode = Marshal.GetLastWin32Error(); @@ -40,7 +46,7 @@ private void Dispose(bool disposing) // because we can unhook only in the same thread, not in garbage collector thread if (_windowsHookHandle != IntPtr.Zero) { - if (!UnhookWindowsHookEx(_windowsHookHandle)) + if (!Win32KernelApi.UnhookWindowsHookEx(_windowsHookHandle)) { int errorCode = Marshal.GetLastWin32Error(); throw new Win32Exception(errorCode, @@ -56,7 +62,7 @@ private void Dispose(bool disposing) if (_user32LibraryHandle != IntPtr.Zero) { - if (!FreeLibrary(_user32LibraryHandle)) // reduces reference to library by 1. + if (!Win32KernelApi.FreeLibrary(_user32LibraryHandle)) // reduces reference to library by 1. { int errorCode = Marshal.GetLastWin32Error(); throw new Win32Exception(errorCode, @@ -67,61 +73,6 @@ private void Dispose(bool disposing) } } - ~GlobalKeyboardHook() - { - Dispose(false); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private IntPtr _windowsHookHandle; - private IntPtr _user32LibraryHandle; - private HookProc _hookProc; - - private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] - private static extern IntPtr LoadLibrary(string lpFileName); - - [DllImport("kernel32.dll", CharSet = CharSet.Auto)] - private static extern bool FreeLibrary(IntPtr hModule); - - /// - /// The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. - /// You would install a hook procedure to monitor the system for certain types of events. These events are - /// associated either with a specific thread or with all threads in the same desktop as the calling thread. - /// - /// hook type - /// hook procedure - /// handle to application instance - /// thread identifier - /// If the function succeeds, the return value is the handle to the hook procedure. - [DllImport("USER32", SetLastError = true)] - private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId); - - /// - /// The UnhookWindowsHookEx function removes a hook procedure installed in a hook chain by the SetWindowsHookEx function. - /// - /// handle to hook procedure - /// If the function succeeds, the return value is true. - [DllImport("USER32", SetLastError = true)] - private static extern bool UnhookWindowsHookEx(IntPtr hHook); - - /// - /// The CallNextHookEx function passes the hook information to the next hook procedure in the current hook chain. - /// A hook procedure can call this function either before or after processing the hook information. - /// - /// handle to current hook - /// hook code passed to hook procedure - /// value passed to hook procedure - /// value passed to hook procedure - /// If the function succeeds, the return value is true. - [DllImport("USER32", SetLastError = true)] - private static extern IntPtr CallNextHookEx(IntPtr hHook, int code, IntPtr wParam, IntPtr lParam); [StructLayout(LayoutKind.Sequential)] public struct LowLevelKeyboardInputEvent @@ -172,7 +123,7 @@ public enum KeyboardState //const int VkControl = 0x11; private const int KfAltdown = 0x2000; - public const int LlkhfAltdown = (KfAltdown >> 8); + public const int LlkhfAltdown = KfAltdown >> 8; public IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam) { @@ -191,7 +142,19 @@ public IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam) fEatKeyStroke = eventArguments.Handled; } - return fEatKeyStroke ? (IntPtr)1 : CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam); + return fEatKeyStroke ? (IntPtr)1 : Win32KernelApi.CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam); + + } + + ~GlobalKeyboardService() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); } } } \ No newline at end of file diff --git a/Src/Services/IMouseControllerService.cs b/Src/Services/IMouseControllerService.cs index 0a85dff..afe836d 100644 --- a/Src/Services/IMouseControllerService.cs +++ b/Src/Services/IMouseControllerService.cs @@ -2,7 +2,7 @@ { public interface IMouseControllerService { - void LoopClick(int seconds, int milliseconds, int randomSeconds, int randomMilliseconds); + void OnLoopClick(int seconds, int milliseconds, int randomSeconds, int randomMilliseconds); void Stop(); } diff --git a/Src/Services/KeyboardService.cs b/Src/Services/KeyboardService.cs index 032481b..f122185 100644 --- a/Src/Services/KeyboardService.cs +++ b/Src/Services/KeyboardService.cs @@ -1,5 +1,5 @@ using Autofac; -using NClicker.Hooks; +using NClicker.Models; using NClicker.ViewModels; namespace NClicker.Services @@ -9,13 +9,13 @@ public class KeyboardService : IKeyboardService private const int VirtualKeyF1 = 0x70; private const int VirtualKeyF2 = 0x71; - private readonly GlobalKeyboardHook _globalKeyboardHook; + private readonly GlobalKeyboardService _globalKeyboardService; private bool _blockKeys; - public KeyboardService(GlobalKeyboardHook globalKeyboardHook) + public KeyboardService(GlobalKeyboardService globalKeyboardService) { - _globalKeyboardHook = globalKeyboardHook; - _globalKeyboardHook.KeyboardPressed += OnKeyPressed; + _globalKeyboardService = globalKeyboardService; + _globalKeyboardService.KeyboardPressed += OnKeyPressed; } private void OnKeyPressed(object sender, GlobalKeyboardHookEventArgs @event) diff --git a/Src/Services/MouseControllerService.cs b/Src/Services/MouseControllerService.cs index 19a64df..7f0eed0 100644 --- a/Src/Services/MouseControllerService.cs +++ b/Src/Services/MouseControllerService.cs @@ -1,7 +1,6 @@ using NClicker.Helpers; using NClicker.Models; using System; -using System.Runtime.InteropServices; using System.Threading.Tasks; namespace NClicker.Services @@ -14,16 +13,10 @@ public class MouseControllerService : IMouseControllerService public MouseControllerService(Random random) { - _random = new Random(); + _random = Random.Shared; } - - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetCursorPos(out Position lpPoint); - - public void LoopClick(int seconds, int milliseconds, int randomSeconds, int randomMilliseconds) + public void OnLoopClick(int seconds, int milliseconds, int randomSeconds, int randomMilliseconds) { if (IsRunning) return; Task.Run(async () => diff --git a/Src/ViewModels/MainViewModel.cs b/Src/ViewModels/MainViewModel.cs index 8764ad1..0ffa68a 100644 --- a/Src/ViewModels/MainViewModel.cs +++ b/Src/ViewModels/MainViewModel.cs @@ -68,7 +68,7 @@ public MainViewModel(IPresetService presetService, } App.Context.Resolve() - .LoopClick(_seconds, _milliseconds, _randomSeconds, _randomMilliseconds); + .OnLoopClick(_seconds, _milliseconds, _randomSeconds, _randomMilliseconds); } catch (Exception exception) {