Flip config keybinding format to field → key and clear conflicting rofi defaults

This commit is contained in:
Navid Sassan 2026-02-17 22:08:00 +01:00
parent 8df2281f60
commit fab921066a
3 changed files with 32 additions and 15 deletions

View File

@ -54,15 +54,7 @@ Default keybindings:
| Ctrl+Enter | Copy **username** |
| Escape | Cancel |
Keybindings are configurable via `$XDG_CONFIG_HOME/bw-menu/config.yaml` (defaults to `~/.config/bw-menu/config.yaml`):
```yaml
keybindings:
Return: password
Control+Return: username
```
Each entry maps a rofi key name to the vault field it copies. The first entry is bound to rofi's accept key, additional entries become custom keybindings.
Keybindings are configurable — see [Configuration](#configuration) for details.
### fzf
@ -90,6 +82,22 @@ The selected field is copied to the clipboard using `wl-copy` (Wayland) or `xcli
Selections are saved to `$XDG_CACHE_HOME/bw-menu/history.json` (defaults to `~/.cache/bw-menu/history.json`), up to 10 entries. The most recent selection is at index 0.
## Configuration
Config file location: `$XDG_CONFIG_HOME/bw-menu/config.yaml` (defaults to `~/.config/bw-menu/config.yaml`).
```yaml
keybindings:
password: Return
username: Control+Return
totp: Control+Shift+Return
```
Each entry maps a vault field to a [rofi key name](https://davatorium.github.io/rofi/current/rofi-keys.5/). Available fields: `password`, `username`, `totp`.
The **first** entry is bound to rofi's accept key (`kb-accept-entry`). Additional entries become custom keybindings (`kb-custom-1`, `kb-custom-2`, …).
## Sway keybindings
Example keybindings for `~/.config/sway/config`:

View File

@ -6,7 +6,7 @@ from pathlib import Path
import yaml
DEFAULT_KEYBINDINGS = {"Return": "password", "Control+Return": "username"}
DEFAULT_KEYBINDINGS = {"password": "Return", "username": "Control+Return"}
VALID_FIELDS = {"password", "username", "totp"}
@ -43,7 +43,7 @@ def load() -> Config:
)
return Config()
keybindings = {str(k): str(v) for k, v in kb.items()}
invalid = {v for v in keybindings.values() if v not in VALID_FIELDS}
invalid = {k for k in keybindings if k not in VALID_FIELDS}
if invalid:
raise ValueError(
f"Invalid keybinding field(s): {', '.join(sorted(invalid))}. Valid fields: {', '.join(sorted(VALID_FIELDS))}"

View File

@ -34,7 +34,7 @@ class RofiSelector:
self.__print_entries(keybindings)
return None
fields = list(keybindings.values())
fields = list(keybindings.keys())
# kb-accept-entry → first field
if rofi_retv == 1:
@ -77,7 +77,7 @@ class RofiSelector:
def __launch(self, keybindings: dict[str, str]):
script = str(Path(sys.argv[0]).resolve())
keys = list(keybindings.keys())
keys = list(keybindings.values())
# Clean up any stale result from a previous run
_result_path().unlink(missing_ok=True)
@ -91,7 +91,16 @@ class RofiSelector:
"-kb-accept-entry",
keys[0],
]
cmd.extend(["-kb-accept-custom", ""])
cmd.extend(
[
"-kb-accept-custom",
"",
"-kb-accept-alt",
"",
"-kb-accept-custom-alt",
"",
]
)
for i, key in enumerate(keys[1:], start=1):
cmd.extend([f"-kb-custom-{i}", key])
@ -105,7 +114,7 @@ class RofiSelector:
print("\0use-hot-keys\x1ftrue")
hints = []
for key, field in keybindings.items():
for field, key in keybindings.items():
label = key.replace("+", " + ")
hints.append(f"{label}: {field}")
print(f"\0message\x1f{' | '.join(hints)}")