Using Component::mouseWheelMove() in VST plugins


#1

I just added ::mouseWheelMove() to my knobs in my VST but it only seems to work if:

  1. MainComponent calls setWantsKeyboardFocus(true)
  2. user clicked into my Plugin window after clicking somewhere else into the host

I’ve got no problem with point 1) but I got a problem with point 2) because Cubase plugins behave differently: You don’t need to click into them for them to receive mouseWheel messages. Also, from a user-perspective point of view, I don’t see what keyboard focus has to do with mouse wheel messages: The Component under the mouse should just receive the mousewheel messages wether it’s focused (or one of its parents) or not.

How can I force the mouse wheel messages to still reach my components, even if my VST has not been clicked before? I don’t want to start using dodgy ways like grabbing the keyboard focus via a timer.

For this plugin I’m using JUCE146, and it’s on Windows. Sorry for the question if anything changed in 151.


#2

Yeah, I agree, but Windows is quite bone-headed about the wheel, just sending wheel events to the focused window. Certainly it’s always driven me mad in XP (probably still the case in Win7?) that when you click on the left-hand treeview of an explorer window and then go over to the file list and try to use the wheel, it’s the treeview that scrolls… doh!


#3

Ah, after searching a bit around in the VSTGUI source, I just found out that Steinberg actually adds a hook for the mousewheel messages!
Check out bool InitWindowClass() in vstgui.cpp, it’s where it gets installed.

Something tells me, I’ll hack JUCE’s VstWrapper a bit again today…

BTW, you could add this hook code to any JUCE app, too. Wouldn’t hurt.


#4

I’ve nearly completed the code, and I attach it so you can have a look at it:

Global:

[code]HHOOK MouseHook = 0L;

struct MSLLHOOKSTRUCT
{
POINT pt;
DWORD mouseData;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
};

LRESULT CALLBACK MouseProc (int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx (MouseHook, nCode, wParam, lParam);

if (wParam == 0x020a) // WM_MOUSEWHEEL
{
	MSLLHOOKSTRUCT *hs = (MSLLHOOKSTRUCT*) lParam; 

	// get window under cursor 
	HWND hwnd = WindowFromPoint(hs->pt);

	if (hwnd!=0)
	{			
		HINSTANCE inst1 = (HINSTANCE)PlatformUtilities::getCurrentModuleInstanceHandle();
		HINSTANCE inst2 = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);
		if(inst1 == inst2)
		{
			return PostMessage(hwnd,  0x020a, hs->mouseData &0xffff0000, // low-word is undefined 
									(hs->pt.x&0xffff) | (hs->pt.y<<16)); 
		}
	}
}
return CallNextHookEx (MouseHook, nCode, wParam, lParam);

}
#endif[/code]

In EditorCompWrapper constructor, add to end:

[code]#if JUCE_WIN32
addMouseListener (this, true);

	MouseHook = SetWindowsHookEx(14, MouseProc, (HINSTANCE)PlatformUtilities::getCurrentModuleInstanceHandle() , 0);

#endif[/code]

In EditorCompWrapper destructor, add to begin:

#if JUCE_WIN32 if (MouseHook) { UnhookWindowsHookEx (MouseHook); MouseHook = 0L; } #endif

You see that in MouseProc the variable ‘hwnd’ will contain the window handle of the window that is under the mouse. The thing is, that I have to check if this window belongs to the plugin (the DLL) or not. I do this via the line HINSTANCE inst2 = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE); but for some reason I always get 0 as return value. Any ideas how to solve this problem? If I comment the line if(inst1 == inst2) then it all works as long as I don’t start turning the mousewheel on some window that hasn’t been created by the plugin (DLL).


#5

I fixed the problem by adding the following line in JUCEVSTWrapper::dispatcher() :

just behind the line:

So, to conclude, on Windows all mouse wheel messages are now routed to your JUCE-made VST’s components, wether it has focus or not. You don’t need to call setWantsKeyboardFocus(true) nor do you need to set JucePlugin_EditorRequiresKeyboardFocus to 1 in the JucePluginCharacteristics.h header file.


#6

Would it be possible to add this code to JUCE’s VST wrapper code (maybe add some #define USE_MOUSEWHEEL_HOOK or something like that on top op the vst wrapper code so one can always not use it if one prefers) ?


#7

Thanks - I’m doing some plugin stuff today so will have a go. There are actually some more cunning tricks I can probably use to find out if the window is a juce one - I’ll see what I can figure out…


#8

Ok, I’ve just checked in a version of this + your other request about mouse-moves + a couple of other plugin fixes. I’d appreciate you giving my changes a good bashing!


#9

that’s great, thanks! i’ll let you know ASAP.


#10

I just checked your freshly commited code, and it works. Thanks, nice one, it’s all much more pro now you can use the mouse wheel to change values.


#11

Thanks!


#12

Is it possible that the VST wrapper won’t build with VS2005 since this change - or is there a way to work around these compiler errors I get with today’s tip.

1>------ Build started: Project: JuceDemoPlugin, Configuration: Release Win32 ------
1>Compiling...
1>juce_VST_Wrapper.cpp
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(213) : error C2065: 'WM_MOUSEWHEEL' : undeclared identifier
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(215) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(215) : error C2143: syntax error : missing ';' before '&'
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(215) : error C2065: 'hs' : undeclared identifier
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(215) : error C2059: syntax error : ')'
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(217) : error C2228: left of '.pt' must have class/struct/union
1>        type is ''unknown-type''
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(217) : error C2228: left of '.x' must have class/struct/union
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(218) : error C2228: left of '.pt' must have class/struct/union
1>        type is ''unknown-type''
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(218) : error C2228: left of '.y' must have class/struct/union
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(221) : error C2228: left of '.mouseData' must have class/struct/union
1>        type is ''unknown-type''
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(221) : error C2228: left of '.pt' must have class/struct/union
1>        type is ''unknown-type''
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(221) : error C2228: left of '.x' must have class/struct/union
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(221) : error C2228: left of '.pt' must have class/struct/union
1>        type is ''unknown-type''
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(221) : error C2228: left of '.y' must have class/struct/union
1>..\..\..\wrapper\vst\juce_VST_Wrapper.cpp(230) : error C2065: 'WH_MOUSE_LL' : undeclared identifier

the same code compiles fine with vs2008.


#13

Bloody hell, weren’t mouse-wheels invented in 2005!? Ok, I’ll replace those with constants so that VS2005 can handle it. To save me digging out my old machine with VS2005, could you do me a favour and try this:

[code] LRESULT CALLBACK mouseWheelHookCallback (int nCode, WPARAM wParam, LPARAM lParam)
{
#ifndef WM_MOUSEWHEEL
#define WH_MOUSE_LL 14
#define WM_MOUSEWHEEL 0x20a

     struct MSLLHOOKSTRUCT 
     {
        POINT pt;
        DWORD mouseData;
        DWORD flags;
        DWORD time;
        ULONG_PTR dwExtraInfo;
     };
    #endif[/code]

#14

thanks, that seems to do the trick (at least it compiles, haven’t checked if it actually works)


#15

Just stumbled upon this issue again with the current tip.

I had to insert a slightly varied version of the additional defines at the beginning of the VST wrapper’s mouseWheelHookCallback() function:

#ifndef WM_MOUSEWHEEL
#define WH_MOUSE_LL 14
#define WM_MOUSEWHEEL 0x20a

        struct MOUSEHOOKSTRUCTEX
        {
            POINT pt;
            DWORD mouseData;
            DWORD flags;
            DWORD time;
            ULONG_PTR dwExtraInfo;
        };
#endif

Am I right in assuming that I just had to rename the struct?


#16

No! It’s a completely different structure!

Instead of doing that, try this at the top of the file:

#ifdef _WIN32 #define _WIN32_WINNT 0x0500 #include <windows.h>


#17

Thanks, that works fine. I felt like I was doing something I shouldn’t do - good thing that I asked.


#18

Thanks - I’ll update that flag in my next check-in.


#19

Is there an issue with this functionality in Windows 7 64-bit?

I am probably speaking in terrible terminology, but there just seems to be some incompatibility on Mac vs. Windows and was wondering if JUCE supported scroll wheel functionality across all Windows DAW’s even if each DAW may be using different dialog libraries?