From 6460c1a481a8d4d2e3020670a44bcb9ab8ad689d Mon Sep 17 00:00:00 2001 From: blacku Date: Sat, 8 Aug 2026 04:23:24 +0200 Subject: [PATCH] fix(keymap): make modifier layers discoverable (#249) --- keymap/README.md | 2 + keymap/panel.luau | 75 +++++++++++++++++++++++++++++++++++-- keymap/plugin.toml | 2 +- keymap/translations/en.json | 2 + 4 files changed, 77 insertions(+), 4 deletions(-) diff --git a/keymap/README.md b/keymap/README.md index 6861cec..4058541 100644 --- a/keymap/README.md +++ b/keymap/README.md @@ -102,6 +102,8 @@ In keyboard view, enable an exact Super, Ctrl, Shift, and Alt layer. Occupied keys open the shortcuts assigned to that combination; unoccupied keys can be sent directly to the creator. Change the physical layout from the keyboard size selector while editing shortcuts, or set its default in plugin settings. +When a key is occupied in another modifier layer, select it and use the layer +buttons in the details card to jump directly to the matching combination. In list view, type into the search box to filter the complete category tree. Sequential shortcuts such as workspaces 1 through 9 can optionally be folded diff --git a/keymap/panel.luau b/keymap/panel.luau index 78b9594..28989a1 100644 --- a/keymap/panel.luau +++ b/keymap/panel.luau @@ -286,6 +286,33 @@ local function activeModifierSignature() return table.concat(ordered, "+") end +local function modifierSignatureLabel(signature) + if signature == "" then return tr("panel.keyboard.no_modifiers") end + local labels = {} + for modifier in tostring(signature):gmatch("[^+]+") do + labels[#labels + 1] = modifier == "CTRL" and "Ctrl" + or (modifier == "SUPER" and "Super" or (modifier == "SHIFT" and "Shift" or ( + modifier == "ALT" and "Alt" or modifier + ))) + end + return table.concat(labels, " + ") +end + +local function modifierSignatureSelectable(signature) + for modifier in tostring(signature):gmatch("[^+]+") do + if activeModifiers[modifier] == nil then return false end + end + return true +end + +local function selectModifierSignature(signature) + local selected = {} + for modifier in tostring(signature):gmatch("[^+]+") do selected[modifier] = true end + for _, modifier in ipairs(MODIFIER_ORDER) do + activeModifiers[modifier] = selected[modifier] == true + end +end + local function expandedKeys(value) local canonical = canonicalKey(value) local first, last = canonical:match("^(%d)%-(%d)$") @@ -341,6 +368,19 @@ local function keyCallback(id, code) return callback end +local layerCallbackCache = {} +local function layerCallback(signature) + local callback = layerCallbackCache[signature] + if callback == nil then + callback = function() + selectModifierSignature(signature) + render() + end + layerCallbackCache[signature] = callback + end + return callback +end + local function contains(haystack, needle) return string.find(normalized(haystack), needle, 1, true) ~= nil end @@ -1059,6 +1099,17 @@ local function selectedKeyDetails(index) local signature = activeModifierSignature() local entries = asArray(index.exact[signature .. "|" .. selectedKeyboardKey]) + local otherSignatures = {} + local seenSignatures = {} + for _, entry in ipairs(asArray(index.any[selectedKeyboardKey])) do + local entrySignature = modifierSignature(entry.bind.modifiers) + if entrySignature ~= signature and not seenSignatures[entrySignature] then + seenSignatures[entrySignature] = true + otherSignatures[#otherSignatures + 1] = entrySignature + end + end + table.sort(otherSignatures) + local usedOnAnotherLayer = #entries == 0 and #otherSignatures > 0 local chordParts = {} for _, modifier in ipairs(MODIFIER_ORDER) do if activeModifiers[modifier] then @@ -1073,8 +1124,11 @@ local function selectedKeyDetails(index) ui.row({ gap = 8, align = "center" }, { ui.label({ text = chord, color = "on_surface", fontSize = 13, fontWeight = "bold", flexGrow = 1 }), ui.label({ - text = #entries > 0 and tr("panel.keyboard.occupied") or tr("panel.keyboard.free"), - color = #entries > 0 and asString(cfg("category_color"), "primary") or "on_surface_variant", + text = #entries > 0 and tr("panel.keyboard.occupied") or ( + usedOnAnotherLayer and tr("panel.keyboard.other_layer") or tr("panel.keyboard.free") + ), + color = (#entries > 0 or usedOnAnotherLayer) + and asString(cfg("category_color"), "primary") or "on_surface_variant", fontSize = 11, fontWeight = "bold", }), @@ -1082,11 +1136,26 @@ local function selectedKeyDetails(index) } if #entries == 0 then children[#children + 1] = ui.label({ - text = tr("panel.keyboard.free_hint"), + text = tr(usedOnAnotherLayer and "panel.keyboard.other_layer_hint" or "panel.keyboard.free_hint"), color = "on_surface_variant", fontSize = 11, maxLines = 2, }) + if usedOnAnotherLayer then + local layerButtons = { + ui.label({ text = tr("panel.keyboard.available_layers"), color = "on_surface_variant", fontSize = 10 }), + } + for _, otherSignature in ipairs(otherSignatures) do + layerButtons[#layerButtons + 1] = ui.button({ + text = modifierSignatureLabel(otherSignature), + variant = "outline", + controlSize = "sm", + enabled = modifierSignatureSelectable(otherSignature), + onClick = layerCallback(otherSignature), + }) + end + children[#children + 1] = ui.row({ gap = 6, align = "center" }, layerButtons) + end else for entryIndex, entry in ipairs(entries) do if entryIndex > 5 then diff --git a/keymap/plugin.toml b/keymap/plugin.toml index 97dd27d..f83d161 100644 --- a/keymap/plugin.toml +++ b/keymap/plugin.toml @@ -1,6 +1,6 @@ id = "blackbartblues/keymap" name = "Keymap" -version = "1.3.5" +version = "1.3.6" plugin_api = 9 author = "blackbartblues" license = "MIT" diff --git a/keymap/translations/en.json b/keymap/translations/en.json index 197b008..055b855 100644 --- a/keymap/translations/en.json +++ b/keymap/translations/en.json @@ -289,6 +289,7 @@ "unknown": "The service returned an unknown error." }, "keyboard": { + "available_layers": "Used with", "clear_modifiers": "Clear modifiers", "free": "Free", "free_hint": "This combination is not used in the currently selected layer.", @@ -307,6 +308,7 @@ "no_modifiers": "No modifiers", "occupied": "Occupied", "other_layer": "Used on another layer", + "other_layer_hint": "This key is assigned with different modifiers. Choose a layer below to view its shortcuts.", "outside": "{count} shortcuts outside the keyboard view", "select_hint": "Select modifiers, then click a key to inspect that combination.", "summary": "{layer}: {count} occupied keys",