Post #5520: > @Pluglug !!! I ran this version of the cleaner and it **remove

📋 Metadata

🏷️ Tags

hotkeys configuration advanced unsolved

  • Hotkey Configuration
  • Stack Key Editor

💬 Content

@Pluglug !!! I ran this version of the cleaner and it removed 279 empty PME items.

Incredible score — a new world record. From now on please call yourself “Ghost-Buster”

I promised some key-map tips last time, but I’m no expert either, so take this as a working memo.
Corrections are welcome.


Why duplicate / ghost key-map items appear

They tend to show up whenever you run one of these three operators while Blender thinks at least one
edited shortcut exists
– technically, touching even a single KeyMapItem flips the
map-level flag km.is_user_modified = True (Not a per-item flag).

  • bpy.ops.preferences.keyconfig_export
  • bpy.ops.preferences.keyconfig_import
  • bpy.ops.preferences.keyconfig_preset_add

Glossary:
KeyMap(km): map such as “Window”, “3D View”;
KeyMapItem(kmi): kmi is a single shortcut inside a map.


Blender’s 4-layer key-map stack

LayerRolePersisted?
defaultFactory settings / reset target
activeCurrent preset, stored in userpref.blend:white_check_mark:
addonAdd-on shortcuts, rebuilt each session
userRuntime layer = active + addon.
Edits in the UI are saved as a diff and re-merged on startup.(diff only)

This layering is what lets us mix add-on keys, user tweaks and “clean reset”.


How the layer structure gets flattened

bl_keymap_utils/io.py performs an internal merge that destroys the four-layer separation.
Because editing even a single shortcut sets the map-level flagkm.is_user_modified = True, the exporter assumes “this whole KeyMap is custom” and copies every item it contains – untouched add-on shortcuts included. The result is a flat list of KeyMaps with no layer metadata.

Below are the step-by-step details:

  1. Operator passes wm.keyconfigs.active

  2. keyconfig_export_as_data() scans wm.keyconfigs.user.keymaps and collects every
    km where km.is_user_modified is True

  3. keyconfig_merge() stitches that collection back onto kc.active – the moment the
    layers are fused

# bl_operators/userpref.py
keyconfig_export_as_data(
    wm,
    wm.keyconfigs.active,   # (1) active is passed, no layer info
    filepath,
    all_keymaps=self.all,
)

# bl_keymap_utils/io.py
for km in wm.keyconfigs.user.keymaps:          # (2) take edited maps (user layer)
    if all_keymaps or km.is_user_modified:
        edited_kc.keymaps.append(km)

export_keymaps = keyconfig_merge(edited_kc, kc)  # (3) merge = layers fused

Source links for reference:
userpref.py L320
io.py L138-145
io.py L297-298

Import then loads the script and simply sets

keyconfigs.active = kc_new   # everything lands in the active layer

userpref.py L264
bpy.utils L873

Result : the add-on registers its shortcuts again in the addon layer → duplicates!!.

※ With all_keymaps=True even unmodified maps are exported, making things worse.


keyconfig_preset_add (Copy preset)

is just Export → Import → Activate in one click, so it inherits the same problem 100 %.

def add(self, _context, filepath):
    bpy.ops.preferences.keyconfig_export(filepath=filepath)  # flatten
    bpy.utils.keyconfig_set(filepath)                       # re-activate

presets.py L729

※ All code links are HEAD as of 2025-07-11.


Does that make the root cause clear?
In short, Blender’s current Export / Import / Preset-copy tools
destroy the layer structure and bake add-on keys into the active preset.
Until the core code learns to preserve layers, we can only treat
the official Import / Export buttons as a last resort
or, of course, wear the proud title of Ghost-Buster and keep cleaning…


❤️ 4 likes


🔗 View on Blender Artists