3
$\begingroup$

I’m encountering an issue while developing a modal operator in Blender where the Middlemouse release event is never received. The operator detects the press event correctly but never gets the release event when I release the middle mouse button.

Here are the details:

Blender version: [4.2.1]

OS: [Windows 10]

Context: Running a modal operator in the 3D View

Expected behavior: The modal operator should receive both the Press and Release events for the Middlemouse.

Actual behavior: The modal operator receives the Press event but never the Release event for the middle mouse button

Below is code snippet of modal which only prints Press event

import bpy

class ModalMiddleMouseMoveOperator(bpy.types.Operator):
    bl_idname = "wm.middle_mouse_move_modal"
    bl_label = "Middle Mouse Move Modal Operator"

    middle_held = False

    def modal(self, context, event):
        if event.type == 'ESC':
            self.report({'INFO'}, "Cancelled")
            return {'CANCELLED'}

        # Track middle mouse press/release
        if event.type == 'MIDDLEMOUSE':
            if event.value == 'PRESS':
                self.middle_held = True
                print("Middle mouse pressed")
            elif event.value == 'RELEASE':
                self.middle_held = False
                print("Middle mouse released")

        # Track mouse move only if middle mouse is held
        if event.type == 'MOUSEMOVE' and self.middle_held:
            print(f"Mouse moved while middle held: {event.mouse_region_x}, {event.mouse_region_y}")

        return {'PASS_THROUGH'}

    def invoke(self, context, event):
        context.window_manager.modal_handler_add(self)
        print("Modal started. Press ESC to stop.")
        return {'RUNNING_MODAL'}


def register():
    bpy.utils.register_class(ModalMiddleMouseMoveOperator)

def unregister():
    bpy.utils.unregister_class(ModalMiddleMouseMoveOperator)

if __name__ == "__main__":
    register()
    bpy.ops.wm.middle_mouse_move_modal('INVOKE_DEFAULT')

```
$\endgroup$
9
  • 2
    $\begingroup$ I don't know why, but it seems to be detected by returning {'RUNNING_MODAL'}. $\endgroup$ Commented Aug 21 at 11:47
  • $\begingroup$ Yea, I think when you use PASS_THROUG MMB just triggers other stuff that it is assigned to and that's why it will not work this way. $\endgroup$ Commented Aug 21 at 15:13
  • $\begingroup$ I think that's it. @tetii, maybe that should be put into a proper answer? $\endgroup$ Commented Aug 21 at 15:15
  • $\begingroup$ Because it works if you disable MMB hotkey assigned to view3d.rotate $\endgroup$ Commented Aug 21 at 15:18
  • $\begingroup$ @tetii It might be the case that returning {"PASS_THROUGH"} passes of handling of functionality back to the Blender kernel and sort of makes the modal "forget" the PRESS value and that is what is required for a RELEASE event to register. Like maybe RELEASE is only a value that is registered correctly if it is immediately preceded by an uninterrupted PRESS in the modal handling operation. Just spitballing, but that seems like it may be it. $\endgroup$ Commented Aug 21 at 17:59

1 Answer 1

1
$\begingroup$

When you run the script for your question, something interesting happens. The moment you release the MMB, a 'MOUSEMOVE' event is queued instead of 'MIDDLEMOUSE'. Because your script returns {'PASS_THROUGH'}, I suspected that other processes were interfering, so I changed it to return {'RUNNING_MODAL'} on the 'MIDDLEMOUSE' event. As a result, I was able to prevent this strange phenomenon.

class ModalMiddleMouseMoveOperator(bpy.types.Operator):
    bl_idname = "wm.middle_mouse_move_modal"
    bl_label = "Middle Mouse Move Modal Operator"

    middle_held = False

    def modal(self, context, event):
        if event.type == 'ESC':
            self.report({'INFO'}, "Cancelled")
            return {'CANCELLED'}

        # Track middle mouse press/release
        if event.type == 'MIDDLEMOUSE':
            if event.value == 'PRESS':
                self.middle_held = True
                print("Middle mouse pressed")
                return {'RUNNING_MODAL'}
            elif event.value == 'RELEASE':
                self.middle_held = False
                print("Middle mouse released")
                return {'RUNNING_MODAL'}

        # Track mouse move only if middle mouse is held
        if event.type == 'MOUSEMOVE' and self.middle_held:
            print(f"Mouse moved while middle held: {event.mouse_region_x}, {event.mouse_region_y}")

        return {'PASS_THROUGH'}

    def invoke(self, context, event):
        context.window_manager.modal_handler_add(self)
        print("Modal started. Press ESC to stop.")
        return {'RUNNING_MODAL'}

I think the comments on your question almost go a long way in explaining the reason for this strange behavior.

$\endgroup$
5
  • $\begingroup$ We tried it. Release event is working but viewport rotation is not working $\endgroup$ Commented Sep 3 at 10:57
  • $\begingroup$ Our requirement is that the viewport should rotate while holding the middle mouse button, and the release event of the middle mouse button should also be detected when it's released. Currently, we're only able to achieve one of these behaviors at a time. However, with your current solution, the middle mouse release is being detected, but viewport rotation is no longer working. $\endgroup$ Commented Sep 4 at 8:04
  • $\begingroup$ Since it returns RUNNING_MODAL, bpy.ops.view3d.rotate will not work. In your original code, can you guess whether the MOUSEMOVE event can be considered as a release detection? $\endgroup$ Commented Sep 4 at 12:23
  • $\begingroup$ I am not sure what you are trying to say but mouse move cannot be considered as release detection. We simply want to detect whether middle mouse button pressed/released, and viewport rotation should work on mouse move and middle mouse button press. $\endgroup$ Commented Sep 4 at 12:52
  • $\begingroup$ See my answer: The moment you release the MMB, a 'MOUSEMOVE' event is queued instead of 'MIDDLEMOUSE'. $\endgroup$ Commented Sep 5 at 12:49

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.