Modifier keys in plugin builds bug

i just updated to the latest develop build and now modifier keys are acting weird in plugin builds suddenly.

i tested 3 different methods of getting it to work. (all of these work in standalone)

  1. accessing mods.isShiftDown() from the mouse event object in mouseDrag. this only works when shift was down at the beginning of a drag, but it doesn’t update its state within a drag.

  2. statically getting the modifier from a timer callback to then check for mods.isShiftDown(). This continuously yields false in a plugin build, even if shift is down.

  3. overriding component’s modifierKeysChanged-method. This function doesn’t even seem to be called at all. It neither yielded false nor true, regardless of wether the component was just clicked, dragged or not and shift’s actual state.

about my system: windows 10. tested in cubase artist 9.5.3

ok so now i found out that having shift down corresponds to the modifier tag 17 while not having it down corresponds to 16. this is the same in standalone and plugin builds. but it’s just not being set to the right numbers in the plugin build. so i traced back the mouseDrag-function call of juce::Component and it leads through a lot of functions. i’m not very good at this lowlevel stuff so i’d appreciate some help, but I found that this method in particular seemed a little suspicious:

void doMouseMove (Point<float> position, bool isMouseDownEvent)
    {
        ModifierKeys modsToSend (ModifierKeys::currentModifiers);

        // this will be handled by WM_TOUCH
        if (isTouchEvent() || areOtherTouchSourcesActive())
            return;

        if (! isMouseOver)
        {
            isMouseOver = true;

            // This avoids a rare stuck-button problem when focus is lost unexpectedly, but must
            // not be called as part of a move, in case it's actually a mouse-drag from another
            // app which ends up here when we get focus before the mouse is released..
            if (isMouseDownEvent && getNativeRealtimeModifiers != nullptr)
                getNativeRealtimeModifiers();

            updateKeyModifiers();

           #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client
            if (modProvider != nullptr)
                ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withFlags (modProvider->getWin32Modifiers());
           #endif

            TRACKMOUSEEVENT tme;
            tme.cbSize = sizeof (tme);
            tme.dwFlags = TME_LEAVE;
            tme.hwndTrack = hwnd;
            tme.dwHoverTime = 0;

            if (! TrackMouseEvent (&tme))
                jassertfalse;

            Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate();
        }
        else if (! isDragging)
        {
            if (! contains (position.roundToInt(), false))
                return;
        }

        static uint32 lastMouseTime = 0;
        static auto minTimeBetweenMouses = getMinTimeBetweenMouseMoves();
        auto now = Time::getMillisecondCounter();

        if (! Desktop::getInstance().getMainMouseSource().isDragging())
            modsToSend = modsToSend.withoutMouseButtons();

        if (now >= lastMouseTime + minTimeBetweenMouses)
        {
            lastMouseTime = now;
            doMouseEvent (position, MouseInputSource::invalidPressure,
                          MouseInputSource::invalidOrientation, modsToSend);
        }

i found out that it’s being called for a lot of different types of mouse events. if i set a breakpoint in it i can’t even touch the GUI without it triggering. So apparently drags are only part of its functionality. it is also the exact method in the callstack where the modifier tags (modsToSend) are created. i expected this method to have some macros in it like “do this if it’s a standalone build and do that if it’s a plugin build” or so, but there doesn’t seem to be anything like that. the updateKeyModifiers() method seems to get the current state of the modifiers into ModifierKeys::currentModifiers.

static void updateKeyModifiers() noexcept
    {
        int keyMods = 0;
        if (isKeyDown (VK_SHIFT))   keyMods |= ModifierKeys::shiftModifier;
        if (isKeyDown (VK_CONTROL)) keyMods |= ModifierKeys::ctrlModifier;
        if (isKeyDown (VK_MENU))    keyMods |= ModifierKeys::altModifier;

        // workaround: Windows maps AltGr to left-Ctrl + right-Alt.
        if (isKeyDown (VK_RMENU) && !isKeyDown (VK_RCONTROL))
        {
            keyMods = (keyMods & ~ModifierKeys::ctrlModifier) | ModifierKeys::altModifier;
        }

        ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withOnlyMouseButtons().withFlags (keyMods);
    }

instantly after that method there is a macro that checks for something with plugins, but this macro also seems to be true if the standalone solution is selected currently so i guess that’s not it?:

#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client
            if (modProvider != nullptr)
                ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withFlags (modProvider->getWin32Modifiers());
           #endif

some time later there’s another piece of code that can change the modifiers. but idk if Desktop::getInstance() does something differently in standalone or plugin. but it shouldn’t be the thing that gets triggered either because it asks for “if NOT dragging” while this bug happens regardless of drag-states.

if (! Desktop::getInstance().getMainMouseSource().isDragging())
            modsToSend = modsToSend.withoutMouseButtons();

so again: i still don’t see where exactly this function is supposed to act differently depending on the build-type, but maybe someone who is better at this kinda stuff could help me out a little here. it’s very well worth it because it would enable features like sensitive drag-changes within a drag on a slider/parameter. i thought i had figured it out before because it works perfectly in standalone but apparently there’s something bad going on that is still beyond my control

It would be very helpful if you could test this in some different hosts. JUCE’s AudioPluginHost and REAPER would provide some more data points.

If the behaviour is consistent across multiple hosts then tracking down the commit that triggered the change in behaviour will help us narrow down where things are going wrong.

1 Like

thank you for helping me with this! :slight_smile: ok so…

i just tested this with the AudioPluginHost(6.1.4) and it works perfectly fine, just like in the standalone build.

also works with reaper v6.28.

it doesn’t work in studio one artist 5.1.1.61815. same issue as in cubase artist 9.5.3.

it also doesn’t work with fl studio 20.7.3.

those are all the daws that i currently have for testing. tell me if i can do anything else to help

Unfortunately hosts can do things like steal key presses to use for their own ends, so this might be very difficult to track down.

If you can tell us which JUCE commit changed the behaviour this would help a lot.

ok i’ll try to find that out. it definitely has to be solvable, because a lot of plugins react to mod-key changes within drags