3
$\begingroup$

I have a custom panel in which I have buttons that can use modifier keys, IE Clicking, Ctrl+Clicking, Alt+Clicking etc all do slightly different things and it works as expected. I want to hotkey the UI button but dont know how to differentiate if its called via the UI (and take modifiers into account) or via a hotkey (and not take the modifiers into account).

class dummyButton(bpy.types.Operator):
bl_idname = "view3d.fd_dummybutton"
bl_label = "Dummy Button"
bl_options = {'REGISTER', 'UNDO'}

modeEnum : bpy.props.EnumProperty(
    items = {
        ("1", "Stuff", ""),
        ("2", "Other stuff", ""),
        ("3", "Even more stuff", ""),
        ("4", "Final stuff", "")
    },
    name = "Mode",
    default = "1"
)

def invoke(self, context, event):
    
    if event.ctrl:
        self.modeEnum = "2"
    elif event.shift:
        self.modeEnum = "3"
    elif event.alt:
        self.modeEnum = "4"
    
    return self.execute(context)

def execute(self, context):
    
    if self.modeEnum == "1":
        print("Do stuff")
    elif self.modeEnum == "2":
        print("Do other stuff")
    else:
        print("Stuff")

    return {'FINISHED'}

I'd prefer to use an enum since then I can choose the function in the hotkey menuEnum dropdown to pick what the hotkey does I want to be able to use Ctrl+9 as a hotkey without it forcing the modeEnum to be set to "2"

Am I going about this in the wrong way?

$\endgroup$

2 Answers 2

3
$\begingroup$

You can catch the left-click event when the button is pressed to differentiate between UI and hotkey call, using event.type == 'LEFTMOUSE': https://docs.blender.org/api/current/bpy.types.Event.html#bpy.types.Event.type

import bpy

# https://blender.stackexchange.com/a/24002/
class OBJECT_OT_CustomOp(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"
    
    def invoke(self, context, event):
        #is_property_set
        ev = []
        if event.ctrl:
            ev.append("Ctrl")
        if event.shift:
            ev.append("Shift")
        if event.type == 'LEFTMOUSE':
            ev.append("Click")
        self.report({'INFO'}, "+".join(ev))
        return {'FINISHED'}

class OBJECT_PT_CustomPanel(bpy.types.Panel):
    bl_label = "Panel"
    bl_idname = "OBJECT_PT_custom_panel"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "Tools"
    bl_context = "objectmode"   

    def draw(self, context):
        layout = self.layout
        layout.operator(OBJECT_OT_CustomOp.bl_idname)
        layout.separator()

addon_keymaps = []

def register():
    bpy.utils.register_class(OBJECT_OT_CustomOp)
    bpy.utils.register_class(OBJECT_PT_CustomPanel)
    
    # https://blender.stackexchange.com/a/196518/
    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon
    if kc:
        km = wm.keyconfigs.addon.keymaps.new(name='3D View', space_type='VIEW_3D')
        kmi = km.keymap_items.new(OBJECT_OT_CustomOp.bl_idname, type='Q', value='PRESS', ctrl=True)
        addon_keymaps.append((km, kmi))


def unregister():
    bpy.utils.unregister_class(OBJECT_PT_CustomPanel)
    bpy.utils.unregister_class(OBJECT_OT_CustomOp)

    for km, kmi in addon_keymaps:
        km.keymap_items.remove(kmi)
    addon_keymaps.clear()


if __name__ == "__main__":
    register()

    # test call
    #bpy.ops.object.simple_operator()

Python: Ctrl+Click for buttons (capture invocation event)

Create keyboard shortcut for an operator using python?

$\endgroup$
1
  • 2
    $\begingroup$ This solution is both clean and simple, seems so obvious now in hindsight. Thanks for taking the time to help out! $\endgroup$
    – CybranM
    Jan 12, 2022 at 16:21
2
$\begingroup$

You can also add a (hidden) property, IE Bool or Enum to the operator (as you already do) which will be set when the button is pressed. https://docs.blender.org/api/current/bpy.types.KeyMapItem.html#bpy.types.KeyMapItem.properties

import bpy

# https://blender.stackexchange.com/a/24002/
class OBJECT_OT_CustomOp(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"
    bl_options = {'REGISTER', 'UNDO'}
    
    # https://blender.stackexchange.com/a/21108/
    hotkey_call: bpy.props.BoolProperty(options={'HIDDEN', 'SKIP_SAVE'})
    
    def invoke(self, context, event):
        ev = []
        if event.ctrl:
            ev.append("Ctrl")
        if event.shift:
            ev.append("Shift")
        if self.hotkey_call:
            ev = ["Hotkey Call"]
        self.report({'INFO'}, "+".join(ev))
        return {'FINISHED'}

class OBJECT_PT_CustomPanel(bpy.types.Panel):
    bl_label = "Panel"
    bl_idname = "OBJECT_PT_custom_panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"
    bl_category = "Tools"
    bl_context = "objectmode"   

    def draw(self, context):
        layout = self.layout
        layout.operator(OBJECT_OT_CustomOp.bl_idname)
        layout.separator()

addon_keymaps = []

def register():
    bpy.utils.register_class(OBJECT_OT_CustomOp)
    bpy.utils.register_class(OBJECT_PT_CustomPanel)
    
    # https://blender.stackexchange.com/a/196518/
    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon
    if kc:
        km = wm.keyconfigs.addon.keymaps.new(name='3D View', space_type='VIEW_3D')
        kmi = km.keymap_items.new(OBJECT_OT_CustomOp.bl_idname, type='Q', value='PRESS', ctrl=True)
        kmi.properties.hotkey_call = True
        addon_keymaps.append((km, kmi))


def unregister():
    bpy.utils.unregister_class(OBJECT_PT_CustomPanel)
    bpy.utils.unregister_class(OBJECT_OT_CustomOp)
    for km, kmi in addon_keymaps:
        km.keymap_items.remove(kmi)
    addon_keymaps.clear()


if __name__ == "__main__":
    register()

    # test call
    #bpy.ops.object.simple_operator()

Option flags for custom properties (bpy.props)

$\endgroup$
4
  • $\begingroup$ Using a hidden property partly worked, its hidden from the tools popup but still shows up in the hotkey editor which is a bit annoying $\endgroup$
    – CybranM
    Jan 12, 2022 at 16:20
  • 1
    $\begingroup$ Hey nice answer ! :) could you elaborate on what the property options {'HIDDEN', 'SKIP_SAVE'} do ? $\endgroup$
    – Gorgious
    Jan 13, 2022 at 9:45
  • 1
    $\begingroup$ @Gorgious this answer explains it well. $\endgroup$
    – CybranM
    Jan 13, 2022 at 9:48
  • $\begingroup$ @CybranM perfect, thank you. $\endgroup$
    – Gorgious
    Jan 13, 2022 at 9:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.