Post #5520: > @Pluglug !!! I ran this version of the cleaner and it **remove
📋 Metadata
- Author: Pluglug
- Date: 2025-07-10 17:12:04
- Type:
discussion - Quality Score: 9/10
- Reply to: post_05519
- Replies (2): post_05521, post_05527
🏷️ Tags
hotkeys configuration advanced unsolved
⚙️ Related PME Features
- 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_exportbpy.ops.preferences.keyconfig_importbpy.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
| Layer | Role | Persisted? |
|---|---|---|
| default | Factory settings / reset target | – |
| active | Current preset, stored in userpref.blend | ![]() |
| addon | Add-on shortcuts, rebuilt each session | – |
| user | Runtime 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:
-
Operator passes
wm.keyconfigs.active -
keyconfig_export_as_data()scanswm.keyconfigs.user.keymapsand collects every
kmwherekm.is_user_modifiedisTrue -
keyconfig_merge()stitches that collection back ontokc.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
※ 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
