Keystrokes / Keyboard Input in Cubase 7 64bit

I think it was Live 8. The version of Windows shouldn't make any difference.

It's also not working in Live 8.4.2 (latest, 32-bit) on Win7 64-bit here: plugin loads and processing works fine, but typing doesn't.

I've put my build here (VST2 32-bit):

http://dropbox.samplesumo.com/public/JuceDemoPlugin_build20140313.zip

(in Reaper and Bidule it is working)

Ā 

Okay, I can confirm that on Windows 8 using Cubase 7.0.7 x64 that the host is eating most of the keystrokesā€¦ Itā€™s hard to debug, but Iā€™m going to try and create a FileLogger to see whatā€™s going on in juce_win32_Windowing.cpp

Keystrokes which Cubase doesnā€™t use like q & w are fine, but e is forwarded to the host.

Rail

Hi Jules,

So I was able to replicate the issue in Windows running Cubase 7.x x64

You can get an inkling of the issue using a VST3 build of the demo plugin using the VST3PluginTestHost 64bit app in the VST3 SDKā€¦ try entering a period (full stop) or the spacebar.

Cheers,

Rail

Ah, you are right. I was completely thrown off by the nested structure of the forum and wasn't looking backward for replies. Thank you and thank you also for your help on the issue.

Okay, I tried adding some logging:

    static LRESULT CALLBACK windowProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
    {
        if (HWNDComponentPeer* const peer = getOwnerOfWindow (h))
        {
		Logger::writeToLog (Time::getCurrentTime().toString (false, true) + " CALLBACK windowProc: " + String (message));
		
			jassert (isValidPeer (peer));
            return peer->peerWindowProc (h, message, wParam, lParam);
        }

		Logger::writeToLog (Time::getCurrentTime().toString (false, true) + " CALLBACK windowProc...  send to: DefWindowProcW: " + String (message));

        return DefWindowProcW (h, message, wParam, lParam);
    }

and the pertinent log includes the following when I type QWERTY in the demoā€¦

6:22:44pm CALLBACK windowProc: 256 - WM_KEYDOWN: 81, 1048577
6:22:44pm CALLBACK windowProc: 258 - WM_CHAR: 113, 1048577 - ComponentPeer::handleKeyPress - 81 - keyPressed: Q
6:22:44pm CALLBACK windowProc: 132 (WM_NCHITTEST)
6:22:44pm CALLBACK windowProc: 15 (WM_PAINT)
6:22:44pm CALLBACK windowProc: 257 (WM_KEYUP)

6:22:44pm CALLBACK windowProc: 256 - WM_KEYDOWN: 87, 1114113
6:22:44pm CALLBACK windowProc: 258 - WM_CHAR: 119, 1114113 - ComponentPeer::handleKeyPress - 87 - keyPressed: W
6:22:44pm CALLBACK windowProc: 132 (WM_NCHITTEST)
6:22:44pm CALLBACK windowProc: 15 (WM_PAINT)
6:22:44pm CALLBACK windowProc: 257 (WM_KEYUP)

6:22:45pm CALLBACK windowProc: 132
6:22:45pm CALLBACK windowProc: 15
6:22:45pm CALLBACK windowProc: 257
6:22:45pm CALLBACK windowProc: 132
6:22:45pm CALLBACK windowProc: 15
6:22:45pm CALLBACK windowProc: 257
6:22:45pm CALLBACK windowProc: 132
6:22:45pm CALLBACK windowProc: 15
6:22:46pm CALLBACK windowProc: 257
6:22:46pm CALLBACK windowProc: 132
6:22:46pm CALLBACK windowProc: 15
6:22:46pm CALLBACK windowProc: 132
6:22:46pm CALLBACK windowProc: 15
6:22:47pm CALLBACK windowProc: 132
6:22:47pm CALLBACK windowProc: 15

6:22:47pm CALLBACK windowProc: 256 - WM_KEYDOWN: 89, 1376257
6:22:47pm CALLBACK windowProc: 258 - WM_CHAR: 121, 1376257 - ComponentPeer::handleKeyPress - 89 - keyPressed: Y

The E, R & T donā€™t make it to peerWindowProc()'s WM_KEYDOWN or WM_CHAR

Rail

ThanksĀ for confirming this Rail!

Yes, in Cubase I think only 5 or 6 characters come through from the (a-z, 0-9) keys.Ā  In Live 9.1.1, nothing at all.Ā 
Also no space, backspace nor delete either.

Ā 

Ok, I've wasted most of today struggling with this and am completely sick of it now and moving onto other things. This isn't the first time I've looked at the problem, and never found a good solution.

What it all comes down to is this: the host is being an asshole.

The plugin code is completely legit - the windowing code is doing all the right things, but the host has got a win32 hook in place which is consuming the key events before they get anywhere near the plugin's window, regardless of whether the plugin window has focus.

I've been using the Steinberg VST test host to debug, and it blocks all the spacebar events from reaching the plugin. Presumably a similar system is used in Cubase, catching other keys as well, presumably it stops any that are used as app shortcuts.

I've looked at the Steinberg VSTGUI code to see how their own text editor class works, and can assure you that there is nothing in there which is missing from my code. It's all done the same way. I can only assume that Cubase has some sort of hard-coded hack to see whether the focused window is some kind of special text control HWND, and if so, they allow the events to go through.

There's really only one possible hack that could be used here, and that's for the plugin to add its own windows hook to intercept the events before the host manages to get them. Unfortunately although I did manage to intercept the events, and to stop them getting sent to the host, I couldn't find a way to dig out the character info needed from the ancient win32 structures involved. At that point I gave up.

I've done a bit of refactoring in the process, and now have a place in which extra keyboard hooking could be done. If anyone fancies themselves an expert on win32 hooking and wants to have a go, please let me know how you get on. I'll revisit this at some point.

If you check out my log, the plugin still gets the WM_KEYUP messagesā€¦ so perhaps thereā€™s room for some kind of kludgeā€¦ but it still wouldnā€™t stop the host from getting the same keys. (Edit: But you posted that you have a solution for that).

Iā€™ll have a look at how the other framework I have handles this today and see if it has the same behaviour.

Cheers,

Rail

Yes, the plugin gets the key-ups, but when they arrive, the host will already have responded to the key-down - so even if we can get the space bar working in the text editor, it'll also be triggering play/stop commands at the same time.

Rightā€¦ But I just edited my postā€¦ Since you mentioned you have a hook which stops them getting to the hostā€¦ Would that work while using KeyUp? Or would it stop the host getting them completely, even when the textEditor doesnā€™t have focus?

Best,

Rail

The hook does the job well - it can block the events only when the keys are actually used by the plugin and allow unused ones through. But I couldn't find a way to get the same level of info that you get from a real event. There are other types of more general hook that can be used to selectively filter out messages, and it's possible that that could be used to get the original event data, but I didn't have time to investigate it.

Hi Jules,

Trying to check out your hookā€¦ but the tip appears to be missing passKeyUpDownToPeer()

Thanks,

Rail

Thanks Jules for looking into this (again)! And sorry to hear this poisoned your mood right before the weekend...

Would it make sense to try and get one of Steinberg's / Ableton's developers involved here to explain what they really do inside Cubase / Live that might conflict with the Juce code (one of the advantages of being open source)? Maybe with Juce being an important plugin development framework, they would be willing to have a look?

Ā 

1 Like

It's definitely not something only the built-in Cubase plugins are able to get functioning. ALL my plugins that I use minus the two built on the JUCE framework having functioning text inputs. FabFilter (the leader hands down in the GUI department overall), IK Multimedia, Waves, Sonimus, 2C Audio,Ā  iZotope, Overloud, Voxengo and on and on and on all have functioning text input in Cubase.

It just occurred to me that I have some plugins from Sonimus and Cerberus that use the iPlug framework and which have functioning text inputs. Would it be possible to look at the iPlug code to see how they are going about it?

iPlug (WDL) uses native EDIT windows with their own window procedure (ParamEditProc) for CreateTextEntry() ā€¦ JUCE isnā€™t using native windows for the textEditorā€¦ but I do think Jules is on the right track with the hook code heā€™s added to the latest buildā€¦ I think he just needs to have a static boolean variable to indicate when a textEditor is accepting input so the callback knows when to redirect the incoming keystrokes. The new keyboardHookCallback() is getting all the keystrokes typed in Cubaseā€¦ the trick now is how to direct them to the JUCE HWNDComponentPeer::windowProc() vs. forwarding them on to the host.

Something like:

	if (bTextEntryActive)
		{
		if (HIWORD (lParam) & 0xC000)
			HWNDComponentPeer::windowProc (hwnd, WM_KEYUP, wParam, lParam);
		else
			HWNDComponentPeer::windowProc (hwnd, WM_KEYDOWN, wParam, lParam);
		}

Rail

Greg, with all due respect, telling us which plugins do/don't work is not helpful at this stage. And nobody mentioned built-in Cubase plugins anyway, so you've misunderstood something there.

Thanks for raising the whole issue in the first place, but the only useful contributions now would be technical tips about how the win32 message-hook system could be used to work around the issue.

Thanks. It's not something that should be specific to text editors though - the thing to do is to check the bool that's returned from ComponentPeer::handleKeyPress, which indicates whether or not the key was wanted by the juce editor. The HWNDComponentPeer::doKeyUp and doKeyDown also return a bool to indicate that. If it's false, the event should be allowed to propagate to other handlers.

That makes senseā€¦ If you could let me know how you were thinking of communicating between the callback and the ComponentPeer::handleKeyPress() I can mess around with itā€¦ Iā€™m sure it wonā€™t be exactly what youā€™d doā€¦ but it may give you sufficient input to know what works or doesnā€™t.

The passKeyUpDownToPeer() method is missing in the repos.

Cheers,

Rail