Issue with Mouse Wheel Message and Coordinates

There is a long standing issue where it can happen that the mouse coordinates reported for mouse wheel events are totally off. This results in problems like Listboxes that cannot be scrolled using the mouse wheel, which is really irritating.

I just got back to that issue and tried to shed some light on what is happening and report here so this can be solved in JUCE.

I reproduced this issue on multiple Windows machines with at least two different hosts, being Ableton Live and Bitwig Studio. It seems to happen if the host is in High DPI mode and is also running the plugins in High DPI mode. It is also the case that on those machines the systems DPI scaling is set to 125%.

To make sure this is not specific to our plugin, I created a small test plugin of which I will attach the source.

TestHiDPI.zip (5.5 KB)

Here is a screenshot from the Standalone version which has the expected behavior. That is, I left-clicked at three different spots within the plugin window and marked the positions in blue. At the very same positions I also turned the mouse wheel and marked the reported positions in red. This is how it correctly looks like:

Now I did the exact same thing using the VST3 version from within Bitwig Studio.

Two very strange effects can be observed here. For one thing the mouse wheel coordinates for spot 0 and spot 1 are completely different from the coordinates for the mouse clicks. For another thing the mouse wheel coordinates for spot 2 are correct. So this is not a simple scaling issue.

In JUCE the mouse coordinates for mouse wheel messages are retrieved using GetMessagePos() which I suspected to be a problem at first. The documentation by Microsoft states that it returns the screen coordinates from the last message pulled off the queue using GetMessage(). But as a plugin we do not really know if the messages was really just collected using GetMessage() or if the host buffered them in between and is now just sending them off to the plugin. But using the mouse coordinates that are provided by the mouse wheel message itself does not actually change anything - they are wrong too. This can also be double-checked using Spy++ (note: only the 64 bit version can show messages from 64 bit apps, but the 32 bit default version does not tell you that). Digging deeper into GetMessagePos() and where it might get its coordinates set was not possible as it quickly calls into the kernel which cannot easily be debugged.

Not much can be found regarding this problem in general. The only report of a similar issue in another software seems to be here, where a “terminal window” application cannot be used with mouse wheel scrolling in some cases.

Taking into account the findings from the “terminal window” developers as well as a brief statement I received from Ableton regarding my finding a few years back this might be an issue of Windows itself for which we would need a work-around.

I propose solving this in JUCE by either using GetCursorPos() at the time the message is received, or by storing and using the last known mouse coordinate from the last mouse move message.

2 Likes

Having the same issue in Ableton on Windows when I have “Auto-scale Plug-in Window” disabled. Problem is, if I have that enabled then all my fonts and all my pixel-art graphics are completely blurry. Seems like there’s some scaling issue with the mouse wheel. I’d use the method you suggested, however the wheel coordinates affect my sliders’ movements as well :sob:

I’ve debugged this a bit, and it looks to me like this probably is a scaling issue.

When a plugin window is DPI-aware, the system will generally pass it mouse events with physical coordinates. JUCE will then convert these physical coordinates into the coordinate space of the plugin window as necessary.

I think that Live/Bitwig don’t necessarily use dpi-aware windows to host plugins, which means that mouse events sent to those windows will use scaled (logical) coordinates, instead of physical coordinates. This is problematic because JUCE uses a hook to intercept mouse wheel events before they are sent to the host - but because these events may be destined for a dpi-unaware window, they may not use the physical coordinates that JUCE expects.

I made the following change to the mouseWheelHookCallback in juce_WindowsHooks_windows.cpp. With this change in place, the demo app you provided appears to behave as expected in Live 11.3 and Bitwig 5.1.

if (auto* comp = Desktop::getInstance().findComponentAt ({ hs.pt.x, hs.pt.y }))
{
    if (auto* target = static_cast<HWND> (comp->getWindowHandle()))
    {
        const ScopedThreadDPIAwarenessSetter scope { target };
        return PostMessage (target, WM_MOUSEWHEEL,
                            hs.mouseData & 0xffff0000, MAKELPARAM (hs.pt.x, hs.pt.y));
    }
}

Could you test this change and let us know if you encounter any new issues? Thanks!

Thanks for reporting this issue. The proposed fix has been merged to develop, as it seemed effective when I tested it locally.

Please try out this update and let us know if you still encounter issues. Thanks!

Thank you for the fix. We just updated to the latest JUCE version to test this and it seems to work fine.