@@ -2459,6 +2459,85 @@ void postMidiResets(int command) {
2459
2459
}
2460
2460
}
2461
2461
2462
+ // The virtual MIDI keyboard dialog HWND.
2463
+ HWND vkbHwnd = nullptr ;
2464
+ // This is called from translateAccel. This is necessary because REAPER
2465
+ // registers its own accelerator hook for the virtual MIDI keyboard when the
2466
+ // keyboard first opens and we need to be ahead of that hook in order to be
2467
+ // called. This might happen right at startup if the virtual keyboard is
2468
+ // configured to open then. REAPER never unregisters its hook once registered.
2469
+ int vkbTranslateAccel (MSG* msg, accelerator_register_t * accelReg) {
2470
+ if (!vkbHwnd) {
2471
+ // The window probably isn't open.
2472
+ return 0 ; // Normal handling.
2473
+ }
2474
+ if (!IsWindow (vkbHwnd)) {
2475
+ vkbHwnd = nullptr ;
2476
+ return 0 ;
2477
+ }
2478
+ if (msg->message != WM_KEYDOWN ||
2479
+ (msg->hwnd != vkbHwnd && GetParent (msg->hwnd ) != vkbHwnd)) {
2480
+ // This key isn't for us.
2481
+ return 0 ;
2482
+ }
2483
+ if (isClassName (msg->hwnd , " Edit" ) || isClassName (msg->hwnd , " ComboBox" )) {
2484
+ // Don't trap arrow keys in these controls.
2485
+ return 0 ;
2486
+ }
2487
+ if (isShortcutHelpEnabled) {
2488
+ switch (msg->wParam ) {
2489
+ case VK_RIGHT:
2490
+ outputMessage (translate (" Octave up" ));
2491
+ return 1 ; // Eat the key.
2492
+ case VK_LEFT:
2493
+ outputMessage (translate (" Octave down" ));
2494
+ return 1 ;
2495
+ case VK_UP:
2496
+ outputMessage (translate (" Increase MIDI channel" ));
2497
+ return 1 ;
2498
+ case VK_DOWN:
2499
+ outputMessage (translate (" Decrease MIDI channel" ));
2500
+ return 1 ;
2501
+ default :
2502
+ break ;
2503
+ }
2504
+ return 0 ;
2505
+ }
2506
+ switch (msg->wParam ) {
2507
+ case VK_RIGHT:
2508
+ case VK_LEFT:
2509
+ // We need to wait until this executes before we can report the new value.
2510
+ CallLater ([] {
2511
+ constexpr long WCID_CENTER_NOTE = 1239 ;
2512
+ char note[10 ];
2513
+ if (GetDlgItemText (vkbHwnd, WCID_CENTER_NOTE, note, sizeof (note)) != 0 ) {
2514
+ outputMessage (note);
2515
+ }
2516
+ }, 0 );
2517
+ return 0 ;
2518
+ case VK_UP:
2519
+ case VK_DOWN:
2520
+ CallLater ([] {
2521
+ constexpr long WCID_CHANNEL = 1377 ;
2522
+ char channel[10 ];
2523
+ if (GetDlgItemText (vkbHwnd, WCID_CHANNEL, channel, sizeof (channel)) != 0 ) {
2524
+ outputMessage (channel);
2525
+ }
2526
+ }, 0 );
2527
+ return 0 ;
2528
+ default :
2529
+ break ;
2530
+ }
2531
+ return 0 ;
2532
+ }
2533
+
2534
+ void postVirtualMidiKeyboard (int command) {
2535
+ if (GetToggleCommandState (command)) {
2536
+ // The window has just been shown. Store its HWND for vkbTranslateAccel.
2537
+ vkbHwnd = GetForegroundWindow ();
2538
+ }
2539
+ }
2540
+
2462
2541
void postMExplorerChangeVolume (int cmd, HWND hwnd) {
2463
2542
HWND w = GetDlgItem (hwnd, 997 );
2464
2543
if (!w) {// support Reaper versions before 6.65
@@ -2710,9 +2789,10 @@ PostCommand POST_COMMANDS[] = {
2710
2789
{24866 , postMomentarilySetOverrideToAltN}, // Main action section: Momentarily set override to alt-14
2711
2790
{24867 , postMomentarilySetOverrideToAltN}, // Main action section: Momentarily set override to alt-15
2712
2791
{24868 , postMomentarilySetOverrideToAltN}, // Main action section: Momentarily set override to alt-16
2713
- {41175 , postMidiResets}, // Reset all MIDI devices
2714
- {42348 , postMidiResets}, // Reset all MIDI control surface devices
2715
- {40345 , postMidiResets}, // Send all-notes-off and all-sounds-off to all MIDI outputs/plug-ins
2792
+ {41175 , postMidiResets}, // Reset all MIDI devices
2793
+ {42348 , postMidiResets}, // Reset all MIDI control surface devices
2794
+ {40345 , postMidiResets}, // Send all-notes-off and all-sounds-off to all MIDI outputs/plug-ins
2795
+ {40377 , postVirtualMidiKeyboard}, // View: Show virtual MIDI keyboard
2716
2796
{0 },
2717
2797
};
2718
2798
MidiPostCommand MIDI_POST_COMMANDS[] = {
@@ -5213,89 +5293,6 @@ void cmdJumpToTime(Command* command) {
5213
5293
}, 50 );
5214
5294
}
5215
5295
5216
- void cmdVirtualMidiKeyboard (Command* command) {
5217
- static accelerator_register_t accelReg = {0 };
5218
- if (GetToggleCommandState (command->gaccel .accel .cmd )) {
5219
- // The virtual keyboard is showing. Run the command to hide it.
5220
- Main_OnCommand (command->gaccel .accel .cmd , 0 );
5221
- return ;
5222
- }
5223
- const bool isRegistered = !!accelReg.translateAccel ;
5224
- accelReg.translateAccel = [](MSG* msg, accelerator_register_t * accelReg) -> int {
5225
- HWND dialog = (HWND)accelReg->user ;
5226
- if (dialog && !IsWindow (dialog)) {
5227
- // The dialog is dead. Ideally, we would unregister. However, if we do,
5228
- // subsequent registrations of our hook never intercept key presses in the
5229
- // virtual keyboard. So, we just have to leave this registered.
5230
- accelReg->user = nullptr ;
5231
- return 0 ; // Normal handling.
5232
- }
5233
- if (msg->message != WM_KEYDOWN ||
5234
- (msg->hwnd != dialog && GetParent (msg->hwnd ) != dialog)) {
5235
- // This key isn't for us.
5236
- return 0 ;
5237
- }
5238
- if (isClassName (msg->hwnd , " Edit" ) || isClassName (msg->hwnd , " ComboBox" )) {
5239
- // Don't trap arrow keys in these controls.
5240
- return 0 ;
5241
- }
5242
- if (isShortcutHelpEnabled) {
5243
- switch (msg->wParam ) {
5244
- case VK_RIGHT:
5245
- outputMessage (translate (" Octave up" ));
5246
- return 1 ; // Eat the key.
5247
- case VK_LEFT:
5248
- outputMessage (translate (" Octave down" ));
5249
- return 1 ;
5250
- case VK_UP:
5251
- outputMessage (translate (" Increase MIDI channel" ));
5252
- return 1 ;
5253
- case VK_DOWN:
5254
- outputMessage (translate (" Decrease MIDI channel" ));
5255
- return 1 ;
5256
- default :
5257
- break ;
5258
- }
5259
- return 0 ;
5260
- }
5261
- switch (msg->wParam ) {
5262
- case VK_RIGHT:
5263
- case VK_LEFT:
5264
- // We need to wait until this executes before we can report the new value.
5265
- CallLater ([dialog] {
5266
- constexpr long WCID_CENTER_NOTE = 1239 ;
5267
- char note[10 ];
5268
- if (GetDlgItemText (dialog, WCID_CENTER_NOTE, note, sizeof (note)) != 0 ) {
5269
- outputMessage (note);
5270
- }
5271
- }, 0 );
5272
- return 0 ;
5273
- case VK_UP:
5274
- case VK_DOWN:
5275
- CallLater ([dialog] {
5276
- constexpr long WCID_CHANNEL = 1377 ;
5277
- char channel[10 ];
5278
- if (GetDlgItemText (dialog, WCID_CHANNEL, channel, sizeof (channel)) != 0 ) {
5279
- outputMessage (channel);
5280
- }
5281
- }, 0 );
5282
- return 0 ;
5283
- default :
5284
- break ;
5285
- }
5286
- return 0 ;
5287
- };
5288
- accelReg.isLocal = true ;
5289
- accelReg.user = nullptr ;
5290
- if (!isRegistered) {
5291
- // We must register the hook before the window appears or it won't work.
5292
- plugin_register (" accelerator" , &accelReg);
5293
- }
5294
- // Show the window.
5295
- Main_OnCommand (command->gaccel .accel .cmd , 0 );
5296
- accelReg.user = GetForegroundWindow (); // The dialog.
5297
- }
5298
-
5299
5296
#define DEFACCEL {0 , 0 , 0 }
5300
5297
5301
5298
Command COMMANDS[] = {
@@ -5399,7 +5396,6 @@ Command COMMANDS[] = {
5399
5396
{MAIN_SECTION, {{0 , 0 , 42207 }, nullptr }, nullptr , cmdAddAutoItems}, // Envelope: Convert all project automation to automation items
5400
5397
{MAIN_SECTION, {{0 , 0 , 42089 }, nullptr }, nullptr , cmdGlueAutoItems}, // Envelope: Glue automation items
5401
5398
{MAIN_SECTION, {{0 , 0 , 40069 }, nullptr }, nullptr , cmdJumpToTime}, // View: Jump (go) to time window
5402
- {MAIN_SECTION, {{0 , 0 , 40377 }, nullptr }, nullptr , cmdVirtualMidiKeyboard}, // View: Show virtual MIDI keyboard
5403
5399
{MIDI_EDITOR_SECTION, {{0 , 0 , 40036 }, nullptr }, nullptr , cmdMidiMoveCursor}, // View: Go to start of file
5404
5400
{MIDI_EVENT_LIST_SECTION, {{0 , 0 , 40036 }, nullptr }, nullptr , cmdMidiMoveCursor}, // View: Go to start of file
5405
5401
{MIDI_EDITOR_SECTION, {{0 , 0 , 40037 }, nullptr }, nullptr , cmdMidiMoveCursor}, // View: Go to end of file
@@ -5968,6 +5964,12 @@ HWINEVENTHOOK winEventHook = nullptr;
5968
5964
5969
5965
#endif // _WIN32
5970
5966
5967
+ // This accelerator hook is registered at startup and remains registered until
5968
+ // REAPER exits.
5969
+ int translateAccel (MSG* msg, accelerator_register_t * accelReg) {
5970
+ return vkbTranslateAccel (msg, accelReg);
5971
+ }
5972
+
5971
5973
extern " C" {
5972
5974
5973
5975
REAPER_PLUGIN_DLL_EXPORT int REAPER_PLUGIN_ENTRYPOINT (REAPER_PLUGIN_HINSTANCE hInstance, reaper_plugin_info_t * rec) {
@@ -6021,6 +6023,12 @@ REAPER_PLUGIN_DLL_EXPORT int REAPER_PLUGIN_ENTRYPOINT(REAPER_PLUGIN_HINSTANCE hI
6021
6023
#ifdef _WIN32
6022
6024
keyboardHook = SetWindowsHookEx (WH_KEYBOARD, keyboardHookProc, nullptr , guiThread);
6023
6025
#endif
6026
+
6027
+ static accelerator_register_t accelReg;
6028
+ accelReg.translateAccel = translateAccel;
6029
+ accelReg.isLocal = true ;
6030
+ accelReg.user = nullptr ;
6031
+ plugin_register (" accelerator" , &accelReg);
6024
6032
return 1 ;
6025
6033
6026
6034
} else {
0 commit comments