6
6
using System . Runtime . InteropServices . ComTypes ;
7
7
using System . Threading . Tasks ;
8
8
using System . Windows . Forms ;
9
+ using System . Windows . Input ;
9
10
using Microsoft . Vbe . Interop ;
10
11
using NLog ;
11
12
using Rubberduck . Common ;
17
18
using Rubberduck . UI . Command . MenuItems ;
18
19
using Infralution . Localization . Wpf ;
19
20
using Rubberduck . Common . Dispatch ;
21
+ using Rubberduck . Common . Hotkeys ;
22
+ using Rubberduck . UI . Command ;
23
+ using Hotkey = Rubberduck . Common . Hotkeys . Hotkey ;
20
24
21
25
namespace Rubberduck
22
26
{
@@ -31,6 +35,7 @@ public class App : IDisposable
31
35
private readonly RubberduckCommandBar _stateBar ;
32
36
private readonly IIndenter _indenter ;
33
37
private readonly IRubberduckHooks _hooks ;
38
+ private readonly IEnumerable < ICommand > _appCommands ;
34
39
35
40
private readonly Logger _logger ;
36
41
@@ -40,15 +45,21 @@ public class App : IDisposable
40
45
private readonly int _projectsEventsCookie ;
41
46
42
47
private readonly IDictionary < VBComponents , Tuple < IConnectionPoint , int > > _componentsEventsConnectionPoints =
43
- new Dictionary < VBComponents , Tuple < IConnectionPoint , int > > ( ) ;
48
+ new Dictionary < VBComponents , Tuple < IConnectionPoint , int > > ( ) ;
49
+
50
+ private IReadOnlyDictionary < string , RubberduckHotkey > _hotkeyNameMap ;
51
+
52
+ private IReadOnlyDictionary < RubberduckHotkey , ICommand > _hotkeyActions ;
53
+ private IReadOnlyDictionary < string , ICommand > _secondKeyActions ;
44
54
45
55
public App ( VBE vbe , IMessageBox messageBox ,
46
56
IRubberduckParser parser ,
47
57
IGeneralConfigService configService ,
48
58
IAppMenu appMenus ,
49
59
RubberduckCommandBar stateBar ,
50
- IIndenter indenter /*
51
- IRubberduckHooks hooks*/ )
60
+ IIndenter indenter ,
61
+ IRubberduckHooks hooks ,
62
+ IEnumerable < ICommand > appCommands )
52
63
{
53
64
_vbe = vbe ;
54
65
_messageBox = messageBox ;
@@ -58,10 +69,11 @@ IIndenter indenter/*
58
69
_appMenus = appMenus ;
59
70
_stateBar = stateBar ;
60
71
_indenter = indenter ;
61
- //_hooks = hooks;
72
+ _hooks = hooks ;
73
+ _appCommands = appCommands ;
62
74
_logger = LogManager . GetCurrentClassLogger ( ) ;
63
75
64
- // _hooks.MessageReceived += hooks_MessageReceived;
76
+ _hooks . MessageReceived += hooks_MessageReceived ;
65
77
_configService . LanguageChanged += ConfigServiceLanguageChanged ;
66
78
_parser . State . StateChanged += Parser_StateChanged ;
67
79
_stateBar . Refresh += _stateBar_Refresh ;
@@ -81,6 +93,18 @@ IIndenter indenter/*
81
93
UiDispatcher . Initialize ( ) ;
82
94
}
83
95
96
+ public void Startup ( )
97
+ {
98
+ CleanReloadConfig ( ) ;
99
+
100
+ _appMenus . Initialize ( ) ;
101
+ _appMenus . Localize ( ) ;
102
+
103
+ //_hooks.AddHook(new LowLevelKeyboardHook(_vbe));
104
+ HookHotkeys ( ) ;
105
+ _hooks . Attach ( ) ;
106
+ }
107
+
84
108
async void sink_ProjectRemoved ( object sender , DispatcherEventArgs < VBProject > e )
85
109
{
86
110
Debug . WriteLine ( string . Format ( "Project '{0}' was removed." , e . Item . Name ) ) ;
@@ -220,56 +244,68 @@ async void sink_ProjectActivated(object sender, DispatcherEventArgs<VBProject> e
220
244
private bool _isAwaitingTwoStepKey ;
221
245
private bool _skipKeyUp ;
222
246
223
- private async void hooks_MessageReceived ( object sender , HookEventArgs e )
247
+ private void hooks_MessageReceived ( object sender , HookEventArgs e )
224
248
{
225
249
if ( sender is LowLevelKeyboardHook )
226
250
{
227
- if ( _skipKeyUp )
228
- {
229
- _skipKeyUp = false ;
230
- return ;
231
- }
232
-
233
- if ( _isAwaitingTwoStepKey )
234
- {
235
- // todo: use _firstStepHotKey and e.Key to run 2-step hotkey action
236
- if ( _firstStepHotKey == Keys . I && e . Key == Keys . M )
237
- {
238
- _indenter . IndentCurrentModule ( ) ;
239
- }
240
-
241
- AwaitNextKey ( ) ;
242
- return ;
243
- }
244
-
245
- var component = _vbe . ActiveCodePane . CodeModule . Parent ;
246
- _parser . ParseComponent ( component ) ;
247
-
248
- AwaitNextKey ( ) ;
251
+ HandleLowLevelKeyhook ( e ) ;
249
252
return ;
250
253
}
251
-
252
- var hotKey = sender as IHotKey ;
253
- if ( hotKey == null )
254
+
255
+ var hotKey = sender as IHotkey ;
256
+ if ( hotKey != null )
257
+ {
258
+ HandleHotkey ( hotKey ) ;
259
+ }
260
+ else
254
261
{
255
262
AwaitNextKey ( ) ;
256
- return ;
257
263
}
264
+ }
258
265
259
- if ( hotKey . IsTwoStepHotKey )
266
+ private void HandleHotkey ( IHotkey hotkey )
267
+ {
268
+ if ( hotkey . IsTwoStepHotkey )
260
269
{
261
- _firstStepHotKey = hotKey . HotKeyInfo . Keys ;
262
- AwaitNextKey ( true , hotKey . HotKeyInfo ) ;
270
+ _firstStepHotKey = hotkey . HotkeyInfo . Keys ;
271
+ AwaitNextKey ( true , hotkey . HotkeyInfo ) ;
263
272
}
264
273
else
265
274
{
266
- // todo: use e.Key to run 1-step hotkey action
267
275
_firstStepHotKey = Keys . None ;
276
+ _hotkeyActions [ _hotkeyNameMap [ hotkey . Key ] ] . Execute ( null ) ;
277
+ AwaitNextKey ( ) ;
278
+ }
279
+ }
280
+
281
+ private void HandleLowLevelKeyhook ( HookEventArgs e )
282
+ {
283
+ if ( _skipKeyUp )
284
+ {
285
+ _skipKeyUp = false ;
286
+ return ;
287
+ }
288
+
289
+ if ( _isAwaitingTwoStepKey )
290
+ {
291
+ // todo: use _firstStepHotKey and e.Key to run 2-step hotkey action
292
+ if ( _firstStepHotKey == Keys . I && e . Key == Keys . M )
293
+ {
294
+ _indenter . IndentCurrentModule ( ) ;
295
+ }
296
+
268
297
AwaitNextKey ( ) ;
298
+ return ;
269
299
}
300
+
301
+ var component = _vbe . ActiveCodePane . CodeModule . Parent ;
302
+ _parser . ParseComponent ( component ) ;
303
+
304
+ AwaitNextKey ( ) ;
305
+ return ;
270
306
}
271
307
272
- private void AwaitNextKey ( bool eatNextKey = false , HotKeyInfo info = default ( HotKeyInfo ) )
308
+ private void AwaitNextKey ( bool eatNextKey = false , HotkeyInfo info = default ( HotkeyInfo ) )
273
309
{
274
310
_isAwaitingTwoStepKey = eatNextKey ;
275
311
foreach ( var hook in _hooks . Hooks . OfType < ILowLevelKeyboardHook > ( ) )
@@ -299,22 +335,42 @@ private void Parser_StateChanged(object sender, EventArgs e)
299
335
_appMenus . EvaluateCanExecute ( _parser . State ) ;
300
336
}
301
337
302
- public void Startup ( )
338
+ private void HookHotkeys ( )
303
339
{
304
- CleanReloadConfig ( ) ;
305
-
306
- _appMenus . Initialize ( ) ;
307
- _appMenus . Localize ( ) ;
308
-
309
- //_hooks.AddHook(new LowLevelKeyboardHook(_vbe));
310
- //_hooks.AddHook(new HotKey((IntPtr)_vbe.MainWindow.HWnd, "%^R", Keys.R));
311
- //_hooks.AddHook(new HotKey((IntPtr)_vbe.MainWindow.HWnd, "%^I", Keys.I));
312
- //_hooks.Attach();
340
+ var settings = _config . UserSettings . GeneralSettings . HotkeySettings ;
341
+ foreach ( var hotkey in settings . Where ( hotkey => hotkey . IsEnabled ) )
342
+ {
343
+ _hooks . AddHook ( new Hotkey ( ( IntPtr ) _vbe . MainWindow . HWnd , hotkey . ToString ( ) ) ) ;
344
+ }
313
345
}
314
346
315
347
private void CleanReloadConfig ( )
316
348
{
317
349
LoadConfig ( ) ;
350
+ var hotkeys = _config . UserSettings . GeneralSettings . HotkeySettings
351
+ . Where ( hotkey => hotkey . IsEnabled ) . ToList ( ) ;
352
+
353
+ _hotkeyNameMap = hotkeys
354
+ . ToDictionary (
355
+ hotkey => hotkey . ToString ( ) ,
356
+ hotkey => ( RubberduckHotkey ) Enum . Parse ( typeof ( RubberduckHotkey ) , hotkey . Name ) ) ;
357
+
358
+ _hotkeyActions = ( from hotkey in hotkeys
359
+ let value = ( RubberduckHotkey ) Enum . Parse ( typeof ( RubberduckHotkey ) , hotkey . Name )
360
+ where string . IsNullOrEmpty ( hotkey . Key2 )
361
+ select new
362
+ {
363
+ Hotkey = value ,
364
+ Command = _appCommands . OfType < IHotkeyCommand > ( )
365
+ . SingleOrDefault ( command => command . Hotkey == ( RubberduckHotkey ) Enum . Parse ( typeof ( RubberduckHotkey ) , hotkey . Name ) )
366
+ } )
367
+ . ToDictionary ( kvp => kvp . Hotkey , kvp => ( ICommand ) kvp . Command ) ;
368
+
369
+ _secondKeyActions = hotkeys
370
+ . Where ( hotkey => ! string . IsNullOrEmpty ( hotkey . Key2 ) )
371
+ . ToDictionary (
372
+ hotkey => hotkey . Key2 ,
373
+ hotkey => hotkey . Command ) ;
318
374
}
319
375
320
376
private void ConfigServiceLanguageChanged ( object sender , EventArgs e )
@@ -354,8 +410,8 @@ public void Dispose()
354
410
item . Value . Item1 . Unadvise ( item . Value . Item2 ) ;
355
411
}
356
412
357
- // _hooks.MessageReceived -= hooks_MessageReceived;
358
- // _hooks.Dispose();
413
+ _hooks . MessageReceived -= hooks_MessageReceived ;
414
+ _hooks . Dispose ( ) ;
359
415
}
360
416
}
361
417
}
0 commit comments