Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSView does not receive mouseUp: event when mouse button is released outside of view

I have a custom NSView subclass with (for example) the following methods:

override func mouseDown(with event: NSEvent) { Swift.print("mouseDown") }
override func mouseDragged(with event: NSEvent) { Swift.print("mouseDragged") }
override func mouseUp(with event: NSEvent) { Swift.print("mouseUp") }

As long as the mouse (button) is pressed, dragged and released all inside the view, this works fine. However, when the mouse is depressed inside the view, moved outside the view, and only then released, I never receive the mouseUp event.

P.S.: Calling the super implementations does not help.

like image 770
MrMage Avatar asked Nov 22 '16 14:11

MrMage


People also ask

Which raises an event when the mouse button is released?

The MouseClick event is raised. The MouseUp event is raised. If the user moves the pointer out of the toggle control while the mouse button is down (such as moving the mouse off the Button control while it is pressed), the toggle control will paint in the raised state and only the MouseUp event occurs.

Which mouse event is fired when the right mouse button is pressed and released?

contextmenu. Triggers when the right mouse button is pressed. There are other ways to open a context menu, e.g. using a special keyboard key, it triggers in that case also, so it's not exactly the mouse event.

What is MouseUp event?

The mouseup event is fired at an Element when a button on a pointing device (such as a mouse or trackpad) is released while the pointer is located inside it. mouseup events are the counterpoint to mousedown events.

How do I use Mousedown event?

To cause a MouseDown event for a form section to occur, press the mouse button in a blank area of the form section. The following apply to MouseDown events: If a mouse button is pressed while the pointer is over a form or control, that object receives all mouse events up to and including the last MouseUp event.


1 Answers

The Handling Mouse Dragging Operations section of Apple's mouse events documentation provided a solution: Apparently, we do receive the mouseUp event when tracking events with a mouse-tracking loop.

Here's a variant of the sample code from the documentation, adapted for Swift 3:

override func mouseDown(with event: NSEvent) {
    var keepOn = true

    mouseDownImpl(with: event)

    // We need to use a mouse-tracking loop as otherwise mouseUp events are not delivered when the mouse button is
    // released outside the view.
    while true {
        guard let nextEvent = self.window?.nextEvent(matching: [.leftMouseUp, .leftMouseDragged]) else { continue }
        let mouseLocation = self.convert(nextEvent.locationInWindow, from: nil)
        let isInside = self.bounds.contains(mouseLocation)

        switch nextEvent.type {
        case .leftMouseDragged:
            if isInside {
                mouseDraggedImpl(with: nextEvent)
            }

        case .leftMouseUp:
            mouseUpImpl(with: nextEvent)
            return

        default: break
        }
    }
}

func mouseDownImpl(with event: NSEvent) { Swift.print("mouseDown") }
func mouseDraggedImpl(with event: NSEvent) { Swift.print("mouseDragged") }
func mouseUpImpl(with event: NSEvent) { Swift.print("mouseUp") }
like image 147
MrMage Avatar answered Oct 04 '22 17:10

MrMage