Bug 6/30: Mouse Up Not Always Detected

Posted on Sep 29, 2020

Bug 6 is PixiEditor/PixiEditor/Pen up is not detected when pen up occurs outside the application.

Again this bug was in the PixiEditor project. I found and reported it almost immediately after starting to work on the previous bug. I guess it was something they must have known about, but no one wanted to touch.

PixiEditor

What was happening here was that if you started to draw on the canvas and then released the mouse outside of the application, then started to draw again inside the application it would draw a line between the place that you exited the canvas and the place you began to draw again.

The problem is that a WPF application is completely oblivious to mouse events raised outside of the application itself and so will not raise a mouse up event if even if the mouse down started in the application. Most of the time this behaviour is fine, and perhaps desirable, but in situations like this, where they were specifically looking for a mouse up event and not receiving one, it causes problems.

The only way to fix it is to implement a global mouse hook that listens to all mouse events raised by the operating system. This requires platform invocations and as such is not portable. But since WPF isn’t portable anyway that’s of little consequence. Obviously this isn’t the kind of code you want to try to work out yourself, so I cribbed it from Stack Overflow How to capture MouseUp event outside the WPF window?. There are a few implementations floating around, but the one I’ve linked was the best of them and did exactly what I needed.

I dropped it in and rewired the source of the mouse up event to the global hook and it worked perfectly. I was happy.

However I was a bit worried that it might be rejected or queried heavily because it’s a heavy duty solution, despite being the only one that wouldn’t require the existing drawing mechanism to be redesigned. It’s hard to see any other approach that would have maintained the undo stack in the same way. Put it this way, it’s the kind of code that I would want to think hard about before allowing into my own codebase because it uses native methods. I would have wanted to convince myself that there was no other way of getting that event.

The PR can be found here.

Update

Boom! The PR got accepted first time and the maintainer seemed very happy with it. Considering that I found the bug and that this was a fairly esoteric fix I’m particularly pleased with this one.

Five down, 25 to go 😄