Keyboard handling in plugins


#1

I’ve just checked in a fix/bodge for the mac that might be of interest to some of you.

Basically, I’ve used a cunning trick, so that your GUI can get key focus, but when a keypress happens that isn’t consumed by your components, it activates one of the host’s windows and re-posts the key event, giving the host a chance to use them. It’s not a perfect fix, but seems to work fairly well!


#2

Hi,

With the master tip, it seems that PT8 respond to key with both EditorRequiresKeyboardFocus set to 1 or 0. (While previously with PT I remember having to set this to 0.)

Though on Digital Performer all keys event are still catched by the plugin whatever EditorRequiresKeyboardFocus is set on.
(Note : the filter demo AU from apple also block all keys when upfront.)
This is quite annoying as one can’t even use apple+W to close the GUI, or spacebar to stop playing sound…

Might be related or not, but in xcode with DP attached, I get a lot of message like these :
2009-09-22 13:07:27.996 Digital Performer[5064:a0f] *** __NSAutoreleaseNoPool(): Object 0x15600c60 of class JuceUIViewClass_1_50_JuceDemoAU autoreleased with no pool in place - just leaking
2009-09-22 13:07:27.997 Digital Performer[5064:a0f] *** __NSAutoreleaseNoPool(): Object 0x247ffa0 of class NSCFNumber autoreleased with no pool in place - just leaking
2009-09-22 13:07:27.998 Digital Performer[5064:a0f] *** __NSAutoreleaseNoPool(): Object 0x3a81880 of class NSCFArray autoreleased with no pool in place - just leaking
2009-09-22 13:07:27.999 Digital Performer[5064:a0f] *** __NSAutoreleaseNoPool(): Object 0x3a99e90 of class NSMutableParagraphStyle autoreleased with no pool in place - just leaking
2009-09-22 13:07:28.000 Digital Performer[5064:a0f] *** __NSAutoreleaseNoPool(): Object 0x156013e0 of class NSCFDictionary autoreleased with no pool in place - just leaking

and so on for about 30 items like this.

Thanks,

Salvator


#3

Hmm, are you sure you rebuilt properly? If that flag is set to 0 the code should behave exactly as it used to. (I actually saw the same thing happen myself while I was testing, but a clean rebuild sorted it out)

Damned DP carbon-based junk… grumble… If it’s leaking the JuceUIViewClass then it must be calling uiViewForAudioUnit without having set up an auto-release pool. That’d be pretty slack anywhere, but Apple’s docs actually stipulate that the object returned by that method is supposed to be autoreleased! Most likely the other leaks are just objects that are used by the leaked view object.


#4

Hi,

I suppose that there are some bugs which I described here http://www.rawmaterialsoftware.com/juceforum/viewtopic.php?t=4491 related to these changes. However the problems I noticed may be caused by something completely different - that’s why I created new thread.

Cheers,
Przemek


#5

Great! This bug is a major blocker for us. Post houses in particular cannot have anything that interferes with workflow, and this most definitely does.

However, we’ve given it a try, and while keyboard events are now passed back to Pro Tools, the plug-in no longer receives them. So, it is impossible to edit values with the keyboard. Not a complete solution yet, I’m afraid.


#6

Ah… I see you have switched to git and that this fix is not in svn. Will report again once we have the plug-in compiling. Currently trying to resolve missing symbols. ApplicationServices.framework is needed for the font stuff, but causes compile errors when it is included (uint32 not defined).


#7

It is fixed! Thank you so much for fixing this. We were literally hours away from switching to a different UI toolkit.

We are still getting crashes when the plug-in binary is loaded/unloaded. I’ve included the relevant parts of the crash log:

Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x000000001d4b7001
Crashed Thread: 7

Thread 7 Crashed:
0 ??? 0x1d4b7001 0 + 491483137
1 libSystem.B.dylib 0x940ba155 _pthread_start + 321
2 libSystem.B.dylib 0x940ba012 thread_start + 34

Thread 7 crashed with X86 Thread State (32-bit):
eax: 0x00000000 ebx: 0x1d4b6fe6 ecx: 0xb0395eac edx: 0x940893a6
edi: 0x00000000 esi: 0xb0396000 ebp: 0xb0395f78 esp: 0xb0395f50
ss: 0x0000001f efl: 0x00010286 eip: 0x1d4b7001 cs: 0x00000017
ds: 0x0000001f es: 0x0000001f fs: 0x0000001f gs: 0x00000037
cr2: 0x1d4b7001

Jules, is this going to get fixed within the next week? We absolutely must have a plug-in that works as it should without crashing one week from now. We need to know ASAP so that we can switch toolkits if we need to.

Thanks.


#8

Debugger my friend, Debugger.
The crashlog you are providing don’t have any useful information in it FWIW.


#9

Whenever someone shows me how to reproduce a serious bug, I’ll always drop anything else I’m doing to fix it.

But as otristan said, the crash log you posted is completely useless - I couldn’t even begin to help with this unless you can show me something more meaty. Get friendly with your debugger!


#10

I’m afraid that is all the information I have. The crash does not happen when Pro Tools is run in the debugger.


#11

Ok, well that’s when you start pumping out logging messages!

And let me know when you’ve got more information than “something crashes somewhere”!


#12

Try with the demo plugin.
It might be in your code.
When it crashes in release and not in debug, it’s usually non initialized data/pointer.


#13

It does seem likely that it’s in your code, or the forum would be overflowing with people moaning about the same thing.

I’d suggest stubbing out all your own code, leaving a dummy plugin that just loads and does nothing. Then gradually replace bits of your code until it breaks…


#14

look at JUCE_FORCE_DEBUG option in juce configuration and check your JUCE_DEBUG/JUCE_RELEASE defines in the project. I had problems with that.


#15

I have interface freezes with the implementation of this solution in the AU wrapper.

The problem happpens in Live 6 or Live 7, but it works ok in Live 8 and Logic 8.

I have a plug-in that wants keyboard focus (in order to enter text into TextEditors), but the plug-in editor component does not handle keyPressed events.

If I load the plug in, then click on the main component giving it the focus, and then press a key (the spacebar, for example), the plug-in interface freezes and the following method in juce_AU_wrapper.cpp gets called repeatedly:

        bool keyPressed (const KeyPress& kp)
        {
            if (! kp.getModifiers().isCommandDown())
            {
                // If we have an unused keypress, move the key-focus to a host window
                // and re-inject the event..
                [[hostWindow parentWindow] makeKeyWindow];
                [NSApp postEvent: [NSApp currentEvent] atStart: YES];
            }

            return false;
        }

I think that the re-injected event causes another call to this method, which re-injects the event and so on in an endless loop.
Returning true instead of false at the end of the function does not break the cycle, but commenting out the if and its body does.

As I’ve said, the problem exists for Live 6 and 7, but not for Live 8 or Logic 8, so I think this may be related to hosts that use Carbon… but I’m not expert there, so I leave to you further considerations…


#16

Oh, for f*ck’s sake… Keeping all the hosts happy feels like mole-bashing…

I’ve no time to test this right now, but my initial suggestion would be:

[code] if (! kp.getModifiers().isCommandDown())
{
// If we have an unused keypress, move the key-focus to a host window
// and re-inject the event…
static NSTimeInterval lastEventTime = 0; // check we’re not recursively sending the same event

            if (lastEventTime != [[NSApp currentEvent] timestamp])
            {
                lastEventTime = [[NSApp currentEvent] timestamp];
                [[hostWindow parentWindow] makeKeyWindow];
                [NSApp postEvent: [NSApp currentEvent] atStart: YES];
            }
        }

[/code]

which should work as long as the event dispatching code doesn’t update the event’s timestamp.


#17

Will try this immediately.

For what is worth, I still am a sustainer of the need to determine at run time what host is the plug-in running into.
I’ve already done some guessing based on the name of the executable currently being run, as explained here: http://www.rawmaterialsoftware.com/viewtopic.php?f=2&t=3999&start=0


#18

Your patch seem to work: I get no endless loops now. I only suspect that Live is getting the keystroke twice this way, because Live 6 and 7 seem to correctly pass to the host those keystrokes that the plugin ignores, thus it correctly gets the original keystroke and the reinjected one (which under those hosts wouldn’t be needed, then, but I think it’s a fair price to pay)


#19

Yes, I agree it’d be good to know what DAW it is - ideally as a big enum containing all the common ones, and some code that automatically figures it out from the exe name.


#20

I have some code for that. Should I post it?