Skip to content

Commit

Permalink
Keyboard input is now processed in separate threads to prevent slowin…
Browse files Browse the repository at this point in the history
…g down keyboard input
  • Loading branch information
kfirprods committed Dec 29, 2018
1 parent c528fda commit efef9ff
Showing 1 changed file with 47 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,22 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;

namespace NonInvasiveKeyboardHookLibrary
{
internal struct KeyboardParams
{
public IntPtr wParam;
public int vkCode;

public KeyboardParams(IntPtr wParam, int vkCode)
{
this.wParam = wParam;
this.vkCode = vkCode;
}
}

/// <summary>
/// A hotkey manager that uses a low-level global keyboard hook, but eventually only fires events for
/// pre-registered hotkeys, i.e. not invading a user's privacy.
Expand All @@ -28,7 +41,7 @@ public KeyboardHookManager()
this._registeredCallbacks = new Dictionary<KeybindStruct, Action>();
this._downModifierKeys = new HashSet<ModifierKeys>();
}
#endregion
#endregion

#region Public API
/// <summary>
Expand All @@ -43,7 +56,7 @@ public void Start()
}

/// <summary>
/// Pauses the low-level keyboard hook without unregistering the existing hotkeys
/// Pauses the low-level keyboard hook (without unregistering the existing hotkeys)
/// </summary>
public void Stop()
{
Expand Down Expand Up @@ -170,7 +183,6 @@ private void HandleKeyPress(int virtualKeyCode)

#region Low level keyboard hook
// Source: https://blogs.msdn.microsoft.com/toub/2006/05/03/low-level-keyboard-hook-in-c/

private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
Expand All @@ -186,34 +198,49 @@ private static IntPtr SetHook(LowLevelKeyboardProc proc)
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
userLibrary, 0);
}

public IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
var vkCode = Marshal.ReadInt32(lParam);
var modifierKey = ModifierKeysUtilities.GetModifierKeyFromCode(vkCode);

if (wParam == (IntPtr) WM_KEYDOWN || wParam == (IntPtr) WM_SYSKEYDOWN)
// To prevent slowing keyboard input down, we use handle keyboard inputs in a separate thread
ThreadPool.QueueUserWorkItem(this.HandleSingleKeyboardInput, new KeyboardParams(wParam, vkCode));
}

return CallNextHookEx(_hookId, nCode, wParam, lParam);
}

/// <summary>
/// Handles a keyboard event based on the KeyboardParams it receives
/// </summary>
/// <param name="keyboardParamsObj">KeyboardParams struct (object type to comply with QueueUserWorkItem)</param>
private void HandleSingleKeyboardInput(object keyboardParamsObj)
{
var keyboardParams = (KeyboardParams)keyboardParamsObj;
var wParam = keyboardParams.wParam;
var vkCode = keyboardParams.vkCode;

var modifierKey = ModifierKeysUtilities.GetModifierKeyFromCode(vkCode);

if (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN)
{
if (modifierKey != null)
{
if (modifierKey != null)
{
this._downModifierKeys.Add(modifierKey.Value);
}
this._downModifierKeys.Add(modifierKey.Value);
}
}

if (wParam == (IntPtr) WM_KEYUP || wParam == (IntPtr) WM_SYSKEYUP)
if (wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP)
{
if (modifierKey != null)
{
if (modifierKey != null)
{
this._downModifierKeys.Remove(modifierKey.Value);
}

this.HandleKeyPress(vkCode);
this._downModifierKeys.Remove(modifierKey.Value);
}
}

return CallNextHookEx(_hookId, nCode, wParam, lParam);
this.HandleKeyPress(vkCode);
}
}

private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
Expand Down

0 comments on commit efef9ff

Please sign in to comment.