public void StopStopwatch()
        {
            stopwatch.Stop();

            var e = new KeyboardInput
            {
                Key       = Keys.None,
                KeyStatus = KeyStatus.Down,
                Millis    = stopwatch.ElapsedMilliseconds
            };

            KeyboardStatusChanged?.Invoke(this, e);
        }
        /// <summary>
        /// A callback function which will be called every time a keyboard activity detected.
        /// </summary>
        /// <param name="nCode">
        /// [in] Specifies whether the hook procedure must process the message.
        /// If nCode is HC_ACTION, the hook procedure must process the message.
        /// If nCode is less than zero, the hook procedure must pass the message to the
        /// CallNextHookEx function without further processing and must return the
        /// value returned by CallNextHookEx.
        /// </param>
        /// <param name="wParam">
        /// [in] Specifies whether the message was sent by the current thread.
        /// If the message was sent by the current thread, it is nonzero; otherwise, it is zero.
        /// </param>
        /// <param name="lParam">
        /// [in] Pointer to a CWPSTRUCT structure that contains details about the message.
        /// </param>
        /// <returns>
        /// If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.
        /// If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx
        /// and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC
        /// hooks will not receive hook notifications and may behave incorrectly as a result. If the hook
        /// procedure does not call CallNextHookEx, the return value should be zero.
        /// </returns>
        private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            //Indicates if any of underlaing events set e.Handled flag
            bool handled = false;

            //If was Ok and someone listens to events
            if ((nCode >= 0) && KeyboardStatusChanged != null)
            {
                //Read structure KeyboardHookStruct at lParam
                var myKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));

                var keyData = (Keys)myKeyboardHookStruct.vkCode;
                var e       = new KeyboardInput
                {
                    Key    = keyData,
                    Millis = stopwatch.ElapsedMilliseconds
                };

                // Raise KeyDown
                if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
                {
                    e.KeyStatus = KeyStatus.Down;
                }

                // Raise KeyUp
                if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)
                {
                    e.KeyStatus = KeyStatus.Up;
                }

                stopwatch.Restart();
                KeyboardStatusChanged?.Invoke(this, e);

                handled = handled || e.Handled;
            }

            //If event handled in application do not handoff to other listeners
            if (handled)
            {
                return(1);
            }

            return(CallNextHookEx(hKeyboardHook, nCode, wParam, lParam));
        }
 private void OnKeyboardStatusChanged(KeyboardStatusChangeEventArgs e)
 {
     // Trigger the event
     KeyboardStatusChanged?.Invoke(e);
 }