public override void StartHook()
        {
            if (_started)
            {
                return;
            }

            _windowsKeyboardHookHandle = IntPtr.Zero;
            _keyboardHookProc          = LowLevelKeyboardProc; // we must keep alive proc, because GC is not aware about SetWindowsHookEx behaviour. If you remove this, the program will crash when the garbage collector reaps it.

            _user32LibraryHandle = IntPtr.Zero;

            _user32LibraryHandle = NativeApi.LoadLibrary("User32");
            if (_user32LibraryHandle == IntPtr.Zero)
            {
                var errorCode = Marshal.GetLastWin32Error();
                throw new Win32Exception(errorCode, $"Failed to load library 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
            }

            _windowsKeyboardHookHandle = NativeApi.SetWindowsHookEx(WH_KEYBOARD_LL, _keyboardHookProc, _user32LibraryHandle, 0);
            if (_windowsKeyboardHookHandle == IntPtr.Zero)
            {
                var errorCode = Marshal.GetLastWin32Error();
                throw new Win32Exception(errorCode, $"Failed to adjust keyboard hooks for '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
            }
        }
        public override void StopHook()
        {
            if (!_started)
            {
                return;
            }

            if (_windowsKeyboardHookHandle == IntPtr.Zero)
            {
                return;
            }
            if (!NativeApi.UnhookWindowsHookEx(_windowsKeyboardHookHandle))
            {
                var errorCode = Marshal.GetLastWin32Error();
                throw new Win32Exception(errorCode, $"Failed to remove keyboard hooks for '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
            }
            _windowsKeyboardHookHandle = IntPtr.Zero;

            // ReSharper disable once DelegateSubtraction
            _keyboardHookProc -= LowLevelKeyboardProc;
        }