2
$\begingroup$

I have a modal operator that starts a timer when Right Mouse is pressed, and checks, when it's released, how long it's been held, and, if it's below a threshold, will open a context menu.

While the timer is running I also call view3d.walk navigation, the idea being to emulate Unreal Engine's navigation.

The issue that I'm running into is that I want to confirm the view3d.walk navigation before opening the context menu, but I can't seem to be able to do it via Python.

I'd like to call view3d.walk.confirm (or something) from within the cancel function of my modal operator, but I can't seem to be able to do it. I know I can set a key within the modal map in preferences, but I wanted it to be the same key that calls the cancel function (Right Mouse Release).

I put a comment in the cancel function with my imaginary solution.

import bpy


class UnrealRightClick(bpy.types.Operator):
    """Timer that decides whether to display a menu after Right Click"""
    bl_idname = "blui.unreal_right_click"
    bl_label = "Unreal Right Click"

    _timer = None
    _count = 0
    _threshold = 0.2

    def modal(self, context, event):
        if context.space_data.type == 'VIEW_3D':
            if context.mode == 'EDIT' or 'OBJECT':
                if event.type in {'RIGHTMOUSE'}:   
                    if event.value in {'RELEASE'}:
                        self.cancel(context)
                        return {'CANCELLED'}

                if event.type == 'TIMER':
                    self._count += 0.01
                return {'PASS_THROUGH'}

    def execute(self, context):
        bpy.ops.view3d.walk('INVOKE_DEFAULT')
        wm = context.window_manager
        self._timer = wm.event_timer_add(0.1, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        #bpy.ops.view3d.walk.confirm()
        wm = context.window_manager
        wm.event_timer_remove(self._timer)
        if self._count < self._threshold:
            if context.mode == 'OBJECT':
                bpy.ops.wm.call_menu(name="VIEW3D_MT_object_context_menu")


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


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


if __name__ == "__main__":
    register()

Thanks!

$\endgroup$

1 Answer 1

1
$\begingroup$

I found a hacky way around my issue using ctypes. It's not perfect, but it's something.

The magic line ended up being ctypes.windll.user32.mouse_event(self.MOUSE_RIGHTUP)

With the full code now reading:

import bpy, ctypes


class UnrealRightClick(bpy.types.Operator):
    """Timer that decides whether to display a menu after Right Click"""
    bl_idname = "blui.unreal_right_click"
    bl_label = "Unreal Right Click"

    _timer = None
    _count = 0
    _threshold = 0.2
    MOUSE_RIGHTUP = 0x0010

    def modal(self, context, event):
        if context.space_data.type == 'VIEW_3D':
            if context.mode == 'EDIT' or 'OBJECT':
                if event.type in {'RIGHTMOUSE'}:   
                    if event.value in {'RELEASE'}:
                        self.cancel(context)
                        return {'CANCELLED'}

                if event.type == 'TIMER':
                    self._count += 0.01
                return {'PASS_THROUGH'}

    def execute(self, context):
        bpy.ops.view3d.walk('INVOKE_DEFAULT')
        wm = context.window_manager
        self._timer = wm.event_timer_add(0.1, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        ctypes.windll.user32.mouse_event(self.MOUSE_RIGHTUP)
        wm = context.window_manager
        wm.event_timer_remove(self._timer)
        if self._count < self._threshold:
            if context.mode == 'OBJECT':
                bpy.ops.wm.call_menu(name="VIEW3D_MT_object_context_menu")
            # if context.mode == 'EDIT_MESH':
            #     if context.tool_settings.mesh_select_mode = (True, True, True)
            #         bpy.ops.wm.call_menu(name=”VIEW3D_MT_


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


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


if __name__ == "__main__":
    register()

Hope this helps someone else, I'll update it if I can figure out a better solution for the new problem of mouse focus!

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .