Skip to content

Commit 81b1601

Browse files
committed
GlobalKeyboardListener: Clean up a bit, a make disposable
(imported from Perforce changelist 4195)
1 parent 547c769 commit 81b1601

File tree

1 file changed

+17
-22
lines changed

1 file changed

+17
-22
lines changed

Src/GlobalKeyboardListener.cs

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
namespace RT.Util
88
{
99
/// <summary>Manages a global low-level keyboard hook.</summary>
10-
public sealed class GlobalKeyboardListener
10+
public sealed class GlobalKeyboardListener : IDisposable
1111
{
1212
/// <summary>The collections of keys to watch for. This is ignored if <see cref="HookAllKeys" /> is set to true.</summary>
1313
public List<Keys> HookedKeys { get { return _hookedKeys; } }
@@ -24,45 +24,41 @@ public sealed class GlobalKeyboardListener
2424
/// <summary>Current state of each modifier key.</summary>
2525
private bool _ctrl, _alt, _shift, _win;
2626

27-
#region Events
2827
/// <summary>Occurs when one of the hooked keys is pressed.</summary>
2928
public event GlobalKeyEventHandler KeyDown;
3029
/// <summary>Occurs when one of the hooked keys is released.</summary>
3130
public event GlobalKeyEventHandler KeyUp;
32-
#endregion
3331

34-
#region Constructors and Destructors
32+
/// <summary>Keeps the managed delegate referenced so that the garbage collector doesn’t collect it.</summary>
33+
private WinAPI.KeyboardHookProc _hook;
34+
3535
/// <summary>
3636
/// Initializes a new instance of the <see cref="GlobalKeyboardListener" /> class and installs the keyboard hook.</summary>
3737
public GlobalKeyboardListener()
3838
{
39-
hook();
39+
IntPtr hInstance = WinAPI.LoadLibrary("User32");
40+
_hook = hookProc; // don’t remove this or the garbage collector will collect it while the global hook still tries to access it
41+
_hHook = WinAPI.SetWindowsHookEx(WinAPI.WH_KEYBOARD_LL, _hook, IntPtr.Zero, 0);
4042
}
4143

44+
private bool _disposed = false;
45+
4246
/// <summary>
4347
/// Releases unmanaged resources and performs other cleanup operations before the <see
4448
/// cref="GlobalKeyboardListener" /> is reclaimed by garbage collection and uninstalls the keyboard hook.</summary>
4549
~GlobalKeyboardListener()
4650
{
47-
unhook();
48-
}
49-
#endregion
50-
51-
private WinAPI.KeyboardHookProc _hook;
52-
53-
#region Public Methods
54-
/// <summary>Installs the global hook</summary>
55-
private void hook()
56-
{
57-
IntPtr hInstance = WinAPI.LoadLibrary("User32");
58-
_hook = new WinAPI.KeyboardHookProc(hookProc);
59-
_hHook = WinAPI.SetWindowsHookEx(WinAPI.WH_KEYBOARD_LL, _hook, hInstance, 0);
51+
Dispose();
6052
}
6153

62-
/// <summary>Uninstalls the global hook</summary>
63-
private void unhook()
54+
/// <summary>Unregisters the hook and disposes the object.</summary>
55+
public void Dispose()
6456
{
65-
WinAPI.UnhookWindowsHookEx(_hHook);
57+
if (!_disposed)
58+
{
59+
_disposed = true;
60+
WinAPI.UnhookWindowsHookEx(_hHook);
61+
}
6662
}
6763

6864
/// <summary>
@@ -139,7 +135,6 @@ private int hookProc(int code, int wParam, ref WinAPI.KeyboardHookStruct lParam)
139135
}
140136
return WinAPI.CallNextHookEx(_hHook, code, wParam, ref lParam);
141137
}
142-
#endregion
143138
}
144139

145140
/// <summary>Encapsulates the current state of modifier keys.</summary>

0 commit comments

Comments
 (0)