1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Diagnostics ;
4
+ using System . Linq ;
5
+ using System . Net . Mime ;
6
+ using System . Runtime . InteropServices ;
7
+ using System . Text ;
8
+ using System . Windows ;
9
+ using System . Windows . Input ;
10
+ using System . Windows . Interop ;
11
+
12
+ namespace UnManaged {
13
+ public class GlobalHotKey : IDisposable {
14
+ private static Dictionary < int , GlobalHotKey > _dictHotKeyToCalBackProc ;
15
+
16
+ [ DllImport ( "user32.dll" ) ]
17
+ private static extern bool RegisterHotKey ( IntPtr hWnd , int id , UInt32 fsModifiers , UInt32 vlc ) ;
18
+
19
+ [ DllImport ( "user32.dll" ) ]
20
+ private static extern bool UnregisterHotKey ( IntPtr hWnd , int id ) ;
21
+
22
+ public const int WmHotKey = 0x0312 ;
23
+
24
+ private bool _disposed = false ;
25
+
26
+ public Key Key { get ; private set ; }
27
+ public KeyModifier KeyModifiers { get ; private set ; }
28
+ public Action < GlobalHotKey > Action { get ; set ; }
29
+ public int Id { get ; set ; }
30
+
31
+ // ******************************************************************
32
+ public GlobalHotKey ( Key k , KeyModifier keyModifiers , Action < GlobalHotKey > action , bool register = true ) {
33
+ Key = k ;
34
+ KeyModifiers = keyModifiers ;
35
+ Action = action ;
36
+ if ( register )
37
+ Register ( ) ;
38
+
39
+ }
40
+ private static object lock_obj = new object ( ) ;
41
+ public void UpdateHotKey ( Key k , KeyModifier keyModifiers , bool register = true ) {
42
+ Key = k ;
43
+ KeyModifiers = keyModifiers ;
44
+ if ( register )
45
+ Register ( ) ;
46
+ }
47
+
48
+ // ******************************************************************
49
+ public bool Register ( ) {
50
+ if ( Id != 0 )
51
+ Unregister ( ) ;
52
+ int virtualKeyCode = KeyInterop . VirtualKeyFromKey ( Key ) ;
53
+ Id = virtualKeyCode + ( ( int ) KeyModifiers * 0x10000 ) ;
54
+ bool result = RegisterHotKey ( IntPtr . Zero , Id , ( UInt32 ) KeyModifiers , ( UInt32 ) virtualKeyCode ) ;
55
+ lock ( lock_obj ) {
56
+ if ( _dictHotKeyToCalBackProc == null ) {
57
+ _dictHotKeyToCalBackProc = new Dictionary < int , GlobalHotKey > ( ) ;
58
+ ComponentDispatcher . ThreadFilterMessage += new ThreadMessageEventHandler ( ComponentDispatcherThreadFilterMessage ) ;
59
+ }
60
+ }
61
+
62
+ _dictHotKeyToCalBackProc . Add ( Id , this ) ;
63
+ if ( ! result )
64
+ throw new Exception ( "Unable to register hot key" ) ;
65
+ //Debug.Print(result.ToString() + ", " + Id + ", " + virtualKeyCode);
66
+ return result ;
67
+ }
68
+
69
+ // ******************************************************************
70
+ public void Unregister ( ) {
71
+ if ( Id == 0 )
72
+ return ;
73
+ UnregisterHotKey ( IntPtr . Zero , Id ) ;
74
+ _dictHotKeyToCalBackProc . Remove ( Id ) ;
75
+ Id = 0 ;
76
+ }
77
+
78
+ // ******************************************************************
79
+ private static void ComponentDispatcherThreadFilterMessage ( ref MSG msg , ref bool handled ) {
80
+ if ( ! handled ) {
81
+ if ( msg . message == WmHotKey ) {
82
+ GlobalHotKey hotKey ;
83
+
84
+ if ( _dictHotKeyToCalBackProc . TryGetValue ( ( int ) msg . wParam , out hotKey ) ) {
85
+ if ( hotKey . Action != null ) {
86
+ Application . Current . Dispatcher . BeginInvoke ( ( Action ) ( ( ) =>
87
+ hotKey . Action . Invoke ( hotKey )
88
+ ) ) ;
89
+ }
90
+ handled = true ;
91
+ }
92
+ }
93
+ }
94
+ }
95
+
96
+ // ******************************************************************
97
+ // Implement IDisposable.
98
+ // Do not make this method virtual.
99
+ // A derived class should not be able to override this method.
100
+ public void Dispose ( ) {
101
+ Dispose ( true ) ;
102
+ // This object will be cleaned up by the Dispose method.
103
+ // Therefore, you should call GC.SupressFinalize to
104
+ // take this object off the finalization queue
105
+ // and prevent finalization code for this object
106
+ // from executing a second time.
107
+ GC . SuppressFinalize ( this ) ;
108
+ }
109
+
110
+ // ******************************************************************
111
+ // Dispose(bool disposing) executes in two distinct scenarios.
112
+ // If disposing equals true, the method has been called directly
113
+ // or indirectly by a user's code. Managed and unmanaged resources
114
+ // can be _disposed.
115
+ // If disposing equals false, the method has been called by the
116
+ // runtime from inside the finalizer and you should not reference
117
+ // other objects. Only unmanaged resources can be _disposed.
118
+ protected virtual void Dispose ( bool disposing ) {
119
+ // Check to see if Dispose has already been called.
120
+ if ( ! this . _disposed ) {
121
+ // If disposing equals true, dispose all managed
122
+ // and unmanaged resources.
123
+ if ( disposing ) {
124
+ // Dispose managed resources.
125
+ Unregister ( ) ;
126
+ }
127
+
128
+ // Note disposing has been done.
129
+ _disposed = true ;
130
+ }
131
+ }
132
+ }
133
+
134
+ // ******************************************************************
135
+ [ Flags ]
136
+ public enum KeyModifier {
137
+ None = 0x0000 ,
138
+ Alt = 0x0001 ,
139
+ Ctrl = 0x0002 ,
140
+ NoRepeat = 0x4000 ,
141
+ Shift = 0x0004 ,
142
+ Win = 0x0008
143
+ }
144
+
145
+ // ******************************************************************
146
+ }
0 commit comments