XeFM’s key bindings system allows you to customize keyboard shortcuts for all actions in the application. The system supports:
The simplest form - just a single character:
'quit': ['Q']
'help': ['?']
'toggle_hidden': ['.']
Important behavior:
Examples:
'quit': ['Q'] # 'Q' and 'q' are equivalent (alphabet, case-insensitive)
'help': ['?'] # Matches only '?' (non-alphabet, case-sensitive)
'search': ['F'] # 'F' and 'f' are equivalent (alphabet, case-insensitive)
'search_dialog': ['Shift-F'] # Matches only Shift+F (explicit modifier)
For special keys, use the KeyCode name directly:
'move_up': ['UP']
'move_down': ['DOWN']
'page_up': ['PAGE_UP']
'page_down': ['PAGE_DOWN']
'confirm': ['ENTER']
'cancel': ['ESCAPE']
Available KeyCode names:
UP, DOWN, LEFT, RIGHT, HOME, END, PAGE_UP, PAGE_DOWNENTER, ESCAPE, TAB, BACKSPACE, DELETE, INSERT, SPACEF1 through F12KEY_A through KEY_ZKEY_0 through KEY_9KEY_MINUS, KEY_EQUAL, etc.KeyCode names are case-insensitive: 'ENTER', 'enter', and 'Enter' all work.
Add modifiers before the main key, separated by hyphens:
'page_up': ['PAGE_UP', 'Shift-UP']
'page_down': ['PAGE_DOWN', 'Shift-DOWN']
'jump_to_top': ['Command-UP']
'jump_to_bottom': ['Command-DOWN']
'delete_files': ['DELETE', 'Command-Backspace']
Available modifiers:
Shift - Shift keyControl or Ctrl - Control keyAlt or Option - Alt/Option keyCommand or Cmd - Command key (macOS)Modifier rules:
'Shift', 'SHIFT', and 'shift' all work'Command-Shift-X' equals 'Shift-Command-X''Command-Shift-X', 'Control-Alt-Delete'For actions without selection requirements, use a list of keys:
KEY_BINDINGS = {
'quit': ['Q'], # 'Q' and 'q' are equivalent (alphabet is case-insensitive)
'help': ['?'], # Matches only '?' (non-alphabet is case-sensitive)
'move_up': ['UP', 'k'], # 'k' and 'K' are equivalent
'move_down': ['DOWN', 'j'], # 'j' and 'J' are equivalent
}
For actions that require or prohibit file selection, use a dictionary:
KEY_BINDINGS = {
'delete_files': {
'keys': ['K', 'DELETE'],
'selection': 'required' # Only available when files are selected
},
'create_directory': {
'keys': ['M'],
'selection': 'none' # Only available when no files are selected
},
}
The plain list form is just shorthand for 'selection': 'any', so existing
list-style bindings keep working unchanged.
Selection requirements:
'required' - Action only available when files are selected'none' - Action only available when no files are selected'any' - Action always available (default)Default selection-aware actions. Out of the box these file operations use
'required' (they act on the selection, so they’re hidden when nothing is
selected): copy_files (C), move_files (M), delete_files (K / DELETE),
and create_archive (P). create_directory (M) uses 'none' so it shares
the M key with move_files without conflict — XeFM picks whichever action fits
the current selection state. You can add a 'selection' requirement to any other
action the same way.
Here’s a complete configuration example:
# ~/.xefm/config.py
class Config:
KEY_BINDINGS = {
# Basic navigation
'quit': ['q'], # Matches both 'q' and 'Q'
'help': ['?'], # Matches only '?'
'move_up': ['UP', 'k'], # 'k' matches both 'k' and 'K'
'move_down': ['DOWN', 'j'], # 'j' matches both 'j' and 'J'
'move_left': ['LEFT', 'h'], # 'h' matches both 'h' and 'H'
'move_right': ['RIGHT', 'l'], # 'l' matches both 'l' and 'L'
# Page navigation with modifiers
'page_up': ['PAGE_UP', 'Shift-UP'],
'page_down': ['PAGE_DOWN', 'Shift-DOWN'],
'jump_to_top': ['HOME', 'Command-UP'],
'jump_to_bottom': ['END', 'Command-DOWN'],
# File operations with selection requirements
'delete_files': {
'keys': ['K', 'DELETE'],
'selection': 'required'
},
'copy_files': {
'keys': ['C'], # 'C' and 'c' are equivalent
'selection': 'required'
},
'create_directory': {
'keys': ['M'], # 'M' and 'm' are equivalent
'selection': 'none'
},
# Use Shift modifier for uppercase-specific bindings
'search_dialog': ['Shift-F'], # Only matches Shift+F
}
If you have an existing configuration, here’s how to migrate:
KEY_BINDINGS = {
'quit': ['q', 'Q'], # Redundant uppercase
'copy_files': ['c', 'C'], # Redundant uppercase
'move_up': ['UP', 'k'],
'page_up': ['PPAGE'], # Old special key name
}
KEY_BINDINGS = {
'quit': ['Q'], # Single entry, 'Q' and 'q' are equivalent
'copy_files': ['C'], # Single entry, 'C' and 'c' are equivalent
'move_up': ['UP', 'k'], # 'k' and 'K' are equivalent
'page_up': ['PAGE_UP', 'Shift-UP'], # Use KeyCode name + modifier
}
Key changes:
PPAGE → PAGE_UPNPAGE → PAGE_DOWN'selection': 'required''selection': 'none'