@@ -18,23 +18,53 @@ public class HotKeyManager : IDisposable
18
18
/// </summary>
19
19
public HotKeyManager ( )
20
20
{
21
- // messageLoopThreadHwnd:
22
21
// Create a TaskCompletionSource to receive the window handle.
23
22
var tcsHwnd = new TaskCompletionSource < IntPtr > ( ) ;
24
23
24
+ _messageLoopThread = new Thread ( new ThreadStart ( HotKeyThreadEntry ) )
25
+ {
26
+ Name = "GlobalHotKeyManager Message Loop"
27
+ } ;
28
+ _messageLoopThread . Start ( ) ;
29
+ _hWnd = tcsHwnd . Task . Result ;
30
+ return ;
31
+
25
32
// Thread entry method.
26
- void ThreadEntry ( )
33
+ void HotKeyThreadEntry ( )
27
34
{
35
+ // Dictionary to keep track of registrations.
36
+ var registrations = new Dictionary < int , HotKey > ( ) ;
37
+
28
38
// Retrieve the module handle.
29
39
var hInstance = NativeFunctions . GetModuleHandle ( null ) ;
30
40
31
- // Dictionary to keep track of registrations.
32
- var registrations = new Dictionary < int , HotKey > ( ) ;
41
+ // Create the window class from the window procedure.
42
+ var wndProcDelegate = new WndProc ( MessageHandler ) ;
43
+
44
+ // Convert the WndProc delegate into a structure.
45
+ var wndClassEx = WNDCLASSEX . FromWndProc ( wndProcDelegate ) ;
46
+
47
+ // Register the window class.
48
+ var registeredClass = NativeFunctions . RegisterClassEx ( ref wndClassEx ) ;
49
+
50
+ // create the window.
51
+ var localHWnd = NativeFunctions . CreateWindowEx ( 0 , ( uint ) registeredClass , null , WindowStyle . WS_OVERLAPPED , 0 , 0 , 640 , 480 , IntPtr . Zero , IntPtr . Zero , IntPtr . Zero , IntPtr . Zero ) ;
52
+
53
+ // Signal that the window has been created.
54
+ tcsHwnd . SetResult ( localHWnd ) ;
55
+
56
+ // enter message loop.
57
+ MessageLoop ( localHWnd ) ;
58
+
59
+ // cleanup the resources after wards.
60
+ Cleanup ( localHWnd ) ;
61
+
62
+ return ;
33
63
34
64
// nextId: find the next free id from 0x0000 to 0xBFFF.
35
65
int ? NextId ( )
36
66
{
37
- for ( int i = 0x0000 ; i <= 0xBFFF ; i ++ )
67
+ for ( var i = 0x0000 ; i <= 0xBFFF ; i ++ )
38
68
{
39
69
if ( ! registrations . ContainsKey ( i ) )
40
70
{
@@ -44,8 +74,8 @@ void ThreadEntry()
44
74
return null ;
45
75
}
46
76
47
- // register : wrapper for calling RegisterHotKey and updating registrations.
48
- bool register ( IntPtr hWnd , VirtualKeyCode key , Modifiers modifiers , int id )
77
+ // RegisterKey : wrapper for calling RegisterHotKey and updating registrations.
78
+ bool RegisterKey ( IntPtr hWnd , VirtualKeyCode key , Modifiers modifiers , int id )
49
79
{
50
80
if ( NativeFunctions . RegisterHotKey ( hWnd , id , modifiers , key ) )
51
81
{
@@ -58,8 +88,8 @@ bool register(IntPtr hWnd, VirtualKeyCode key, Modifiers modifiers, int id)
58
88
}
59
89
}
60
90
61
- // unregister : wrapper for calling UnregisterHotKey and updating registrations.
62
- bool unregister ( IntPtr hWnd , int id )
91
+ // UnregisterKey : wrapper for calling UnregisterHotKey and updating registrations.
92
+ bool UnregisterKey ( IntPtr hWnd , int id )
63
93
{
64
94
var registration = registrations . GetValueOrDefault ( id ) ;
65
95
if ( registration != null )
@@ -76,49 +106,42 @@ bool unregister(IntPtr hWnd, int id)
76
106
// messageHandler: processes window messages.
77
107
IntPtr MessageHandler ( IntPtr hWnd , uint uMsg , IntPtr wParam , IntPtr lParam )
78
108
{
79
- if ( uMsg == RegisterHotKeyMsg )
109
+ switch ( uMsg )
80
110
{
81
- // Extract key and modifiers.
82
- var key = ( VirtualKeyCode ) wParam . ToInt32 ( ) ;
83
- var modifiers = ( Modifiers ) lParam . ToInt32 ( ) ;
84
- var id = NextId ( ) ;
85
- if ( id . HasValue )
86
- {
87
- return register ( hWnd , key , modifiers , id . Value ) ? new IntPtr ( id . Value ) : new IntPtr ( - 1 ) ;
88
- }
89
- else
90
- {
91
- return IntPtr . Zero ;
92
- }
93
- }
94
- else if ( uMsg == UnregisterHotKeyMsg )
95
- {
96
- var id = wParam . ToInt32 ( ) ;
97
- return unregister ( hWnd , id ) ? new IntPtr ( id ) : new IntPtr ( - 1 ) ;
98
- }
99
- else if ( uMsg == HotKeyMsg )
100
- {
101
- var registration = registrations . GetValueOrDefault ( wParam . ToInt32 ( ) ) ;
102
- if ( registration != null )
103
- {
104
- _hotkey . OnNext ( registration ) ;
105
- }
106
- return new IntPtr ( 1 ) ;
107
- }
108
- else
109
- {
110
- return NativeFunctions . DefWindowProc ( hWnd , uMsg , wParam , lParam ) ;
111
+ case RegisterHotKeyMsg :
112
+ {
113
+ // Extract key and modifiers.
114
+ var key = ( VirtualKeyCode ) wParam . ToInt32 ( ) ;
115
+ var modifiers = ( Modifiers ) lParam . ToInt32 ( ) ;
116
+ var id = NextId ( ) ;
117
+ if ( id . HasValue )
118
+ {
119
+ return RegisterKey ( hWnd , key , modifiers , id . Value ) ? new IntPtr ( id . Value ) : new IntPtr ( - 1 ) ;
120
+ }
121
+ else
122
+ {
123
+ return IntPtr . Zero ;
124
+ }
125
+ }
126
+ case UnregisterHotKeyMsg :
127
+ {
128
+ var id = wParam . ToInt32 ( ) ;
129
+ return UnregisterKey ( hWnd , id ) ? new IntPtr ( id ) : new IntPtr ( - 1 ) ;
130
+ }
131
+ case HotKeyMsg :
132
+ {
133
+ var registration = registrations . GetValueOrDefault ( wParam . ToInt32 ( ) ) ;
134
+ if ( registration != null )
135
+ {
136
+ _hotkey . OnNext ( registration ) ;
137
+ }
138
+ return new IntPtr ( 1 ) ;
139
+ }
140
+ default :
141
+ return NativeFunctions . DefWindowProc ( hWnd , uMsg , wParam , lParam ) ;
111
142
}
112
143
}
113
144
114
- // Create the window class from the window procedure.
115
- var wndProcDelegate = new WndProc ( MessageHandler ) ;
116
- // Convert the WndProc delegate into a WNDCLASSEX structure.
117
- var wndClassEx = WNDCLASSEX . FromWndProc ( wndProcDelegate ) ;
118
-
119
- // Register the window class.
120
- var registeredClass = NativeFunctions . RegisterClassEx ( ref wndClassEx ) ;
121
-
122
145
// messageLoop: processes messages until quit.
123
146
void MessageLoop ( IntPtr hWnd )
124
147
{
@@ -136,32 +159,13 @@ void Cleanup(IntPtr hWnd)
136
159
{
137
160
foreach ( var key in registrations . Keys . ToArray ( ) )
138
161
{
139
- unregister ( hWnd , key ) ;
162
+ UnregisterKey ( hWnd , key ) ;
140
163
}
141
164
142
165
NativeFunctions . DestroyWindow ( hWnd ) ;
143
166
NativeFunctions . UnregisterClass ( wndClassEx . lpszClassName , hInstance ) ;
144
167
}
145
-
146
- // create the window.
147
- var localHWnd = NativeFunctions . CreateWindowEx ( 0 , ( uint ) registeredClass , null , WindowStyle . WS_OVERLAPPED , 0 , 0 , 640 , 480 , IntPtr . Zero , IntPtr . Zero , IntPtr . Zero , IntPtr . Zero ) ;
148
-
149
- // Signal that the window has been created.
150
- tcsHwnd . SetResult ( localHWnd ) ;
151
-
152
- // enter message loop.
153
- MessageLoop ( localHWnd ) ;
154
-
155
- // cleanup the resources afterwards.
156
- Cleanup ( localHWnd ) ;
157
168
}
158
-
159
- _messageLoopThread = new Thread ( new ThreadStart ( ThreadEntry ) )
160
- {
161
- Name = "GlobalHotKeyManager Message Loop"
162
- } ;
163
- _messageLoopThread . Start ( ) ;
164
- _hWnd = tcsHwnd . Task . Result ;
165
169
}
166
170
167
171
/// <summary>
@@ -173,13 +177,12 @@ void Cleanup(IntPtr hWnd)
173
177
public IRegistration Register ( VirtualKeyCode key , Modifiers modifiers )
174
178
{
175
179
// Retrieve the window handle.
176
- var hWnd = _hWnd ;
177
180
178
181
// tell the message loop to register the _hotkey.
179
- var result = NativeFunctions . SendMessage ( hWnd , RegisterHotKeyMsg , new IntPtr ( ( int ) key ) , new IntPtr ( ( int ) modifiers ) ) ;
182
+ var result = NativeFunctions . SendMessage ( _hWnd , RegisterHotKeyMsg , new IntPtr ( ( int ) key ) , new IntPtr ( ( int ) modifiers ) ) ;
180
183
181
184
// return a disposable that instructs the message loop to unregister the _hotkey on disposal.
182
- return new Registration ( hWnd , result ) ;
185
+ return new Registration ( _hWnd , result ) ;
183
186
}
184
187
185
188
/// <summary>
0 commit comments