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

it was working using wm.keyconfigs.user
but I couldn’t change a key and add new ones at the same time

addon_keymaps = []

def disable_default_kmi(retries=10):
    wm = bpy.context.window_manager

    # the default keyconfig
    kc = wm.keyconfigs.user

    for kmi in kc.keymaps['3D View'].keymap_items:
        if kmi.idname == 'wm.call_menu_pie':
            if hasattr(kmi.properties, 'name'):
                if kmi.properties.name == 'VIEW3D_MT_snap_pie':
                    kmi.active = False
                    print("Disabled", kmi.name)
                    return
    print("Retrying..")
    # add some delay
    bpy.app.timers.register(
        lambda: disable_default_kmi(retries - 1),
        first_interval=0.1)

def register():
    for cls in classes:
        bpy.utils.register_class(cls)
        
    bpy.types.Scene.extra_snap = PointerProperty(type=ExtraSnapMenuProperties)   
    disable_default_kmi()

    wm = bpy.context.window_manager  

    if wm.keyconfigs.addon:
        km = wm.keyconfigs.addon.keymaps.new(name = '3D View', space_type = 'VIEW_3D') 
        kmi = km.keymap_items.new('wm.call_panel', 'S', 'CLICK', shift=True, head=True)
        kmi.properties.name = "SNAP_PT_MENU"
        addon_keymaps.append((km, kmi))   

        km = wm.keyconfigs.addon.keymaps.new(name = '3D View', space_type = 'VIEW_3D') 
        kmi = km.keymap_items.new('wm.call_menu_pie', 'S', 'CLICK_DRAG', shift=True, head=True)
        kmi.properties.name = "VIEW3D_MT_snap_pie"
        addon_keymaps.append((km, kmi))   

I opened a topic there How to modify a key and register another key at the same time in an addon?
can you provide an example where you disable(modify) a default key and register a new one at the same time, when registering an addon? I tried with a timer, but I couldn’t figure it out. and I’m confused about what map to use. I use user map “kc = wm.keyconfigs.user” but I don’t know if it is working on any configuration? I mean if you don’t create your own settings? I’m quite lost with this key part…