Removing a specific default hotkey / shortcut via a script?

So I’m using one of those standard keymap PY templates to add my own custom hotkeys, where the standard chain for adding a new key looks something like this:

wm = bpy.context.window_manager
kc = wm.keyconfigs.addon
km = kc.keymaps.new('Screen Editing', space_type='EMPTY', region_type='WINDOW', modal=False)
kmi = km.keymap_items.new("screen.area_options", 'LEFTMOUSE', 'PRESS')

Now, pretend that instead of adding a hotkey that way, I wanted to remove one of Blender’s default hotkey assignments for a given op. (Don’t worry about reassigning a hotkey to the op.) I’ve been Googling how to do this, but I’m not sure I have the exact chain right. Let’s pretend I want to remove Blender’s default/existing hotkey for the same op as above (Screen Editing -> screen.area_options). How would I do that?

I’ve gotten as far as figuring out that maybe this is the remove command:
bpy.context.window_manager.keyconfigs.default.keymaps['Screen Editing'].keymap_items[???].remove(???)

But I’m not sure how to fill in the questions marks. And there might also be an "active’ property that you can disable instead?
bpy.context.window_manager.keyconfigs.default.keymaps['Screen Editing'].keymap_items[???].active = False

The default keymap often isn’t accessible during addon registration, so you probably need to add a timer.

Note: This example only checks for kmi entries that matches the kmi.idname, so if you used something like wm.call_pie_menu it would disable every entry, unless you added a conditional based off from the kmi operator property.

def disable_default_kmi(km=None, idname=None, retries=10):
    wm = bpy.context.window_manager

    if not (km and idname) or retries < 1:
        return

    # the default keyconfig
    kc = wm.keyconfigs['blender']
    for kmi in kc.keymaps[km].keymap_items:
        if kmi.idname == idname:
            kmi.active = False
            print("Disabled", kmi.name)
            return

    print("Retrying..")
    # add some delay
    bpy.app.timers.register(
        lambda: disable_default_kmi(km, idname, retries - 1),
        first_interval=0.1)

Then during register() you can run something like this.

def register():
    ...
    disable_default_kmi('Screen Editing', 'screen.area_options')
1 Like

Thanks for taking the time. If I did want to add a conditional to check for a property name, would it be an additional nested if statement that looked something like this?

if kmi.properties.name == propName:

(where the propName var would be an argument passed in the function call at the end of the script?)

Also, for your code, would I need to import anything extra at the start? math or anything? Or “from .default_keymap import default_keymap” to get the Blender default?

If it’s a keymap for a custom operator with your own defined properties, they can be accessed like dict keys:

if 'some_prop' in kmi.properties:
    ...

But this doesn’t always work with internal operators. Instead you can check by hasattr(), which works for both custom and internal ones.

if hasattr(kmi.properties, 'some_prop'):
    ...

For checking by keybindings, you can do this.

if kmi.type == 'RIGHTMOUSE' and kmi.value == 'PRESS':
    ...

And if you want to check for modifier keys.

if not kmi.alt and not kmi.ctrl and not kmi.shift:
    ...

You don’t need to import anything other than bpy.

1 Like