CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-keyboard

Hook and simulate keyboard events on Windows and Linux

Pending
Overview
Eval results
Files

hotkeys.mddocs/

Hotkeys

Registration and management of complex keyboard shortcuts, including multi-step hotkey sequences, global hotkey detection, and advanced hotkey remapping capabilities. The keyboard package provides comprehensive hotkey functionality that works system-wide regardless of application focus.

Capabilities

Hotkey Registration

Register callbacks to be executed when specific key combinations are pressed.

def add_hotkey(hotkey, callback, args=(), suppress=False, timeout=1, trigger_on_release=False):
    """
    Invokes a callback every time a hotkey is pressed. The hotkey must be in
    the format 'ctrl+shift+a, s'. This would trigger when the user holds ctrl,
    shift and "a" at once, releases, and then presses "s".
    
    Parameters:
    - hotkey: Hotkey string (e.g., 'ctrl+c', 'ctrl+shift+a, s')
    - callback: Function to call when hotkey is triggered
    - args: Optional arguments to pass to callback
    - suppress: If True, prevent hotkey from reaching other applications
    - timeout: Seconds allowed between steps in multi-step hotkeys
    - trigger_on_release: If True, trigger on key release instead of press
    
    Returns:
    Function to remove the hotkey
    
    Examples:
    - add_hotkey('ctrl+c', copy_function)
    - add_hotkey('f1', show_help)  
    - add_hotkey('ctrl+shift+s, ctrl+v', special_paste)
    """

def register_hotkey(hotkey, callback, args=(), suppress=False, timeout=1, trigger_on_release=False):
    """Alias for add_hotkey()."""

Hotkey Removal

Remove previously registered hotkeys by hotkey string or callback reference.

def remove_hotkey(hotkey_or_callback):
    """
    Removes a previously hooked hotkey. Must be called with the hotkey string
    used in add_hotkey() or the callback function.
    
    Parameters:
    - hotkey_or_callback: Hotkey string or callback function to remove
    """

def clear_hotkey(hotkey_or_callback):
    """Alias for remove_hotkey()."""

def unregister_hotkey(hotkey_or_callback):
    """Alias for remove_hotkey()."""

def unhook_all_hotkeys():
    """
    Removes all keyboard hotkeys in use, including abbreviations, word listeners,
    recorders and waits.
    """

def clear_all_hotkeys():
    """Alias for unhook_all_hotkeys()."""

def remove_all_hotkeys():
    """Alias for unhook_all_hotkeys()."""

def unregister_all_hotkeys():
    """Alias for unhook_all_hotkeys()."""

Hotkey Remapping

Remap hotkeys to other hotkey combinations with optional suppression.

def remap_hotkey(src, dst, suppress=True, trigger_on_release=False):
    """
    Whenever the hotkey src is pressed, suppress it and send dst instead.
    
    Parameters:
    - src: Source hotkey to remap
    - dst: Destination hotkey to send instead
    - suppress: If True, suppress the original hotkey
    - trigger_on_release: If True, trigger on key release
    
    Returns:
    Function to remove the remapping
    
    Example:
    remap_hotkey('alt+w', 'ctrl+up')  # Remap Alt+W to Ctrl+Up
    """

def unremap_hotkey(hotkey):
    """Alias for remove_hotkey()."""

Hotkey Utilities

Utility functions for working with hotkey strings and current key states.

def get_hotkey_name(names=None):
    """
    Returns a string representation of hotkey from the given key names, or
    the currently pressed keys if not given.
    
    Parameters:
    - names: List of key names (optional, uses currently pressed keys if None)
    
    Returns:
    str: Standardized hotkey string
    
    Example:
    get_hotkey_name(['ctrl', 'shift', 'a'])  # Returns 'ctrl+shift+a'
    """

def parse_hotkey_combinations(hotkey):
    """
    Parses a user-provided hotkey. Instead of each step being a list of the
    different scan codes for each key, each step is a list of all possible
    combinations of those scan codes.
    
    Parameters:
    - hotkey: Hotkey string to parse
    
    Returns:
    tuple: All possible scan code combinations for the hotkey
    """

Usage Examples

Basic Hotkey Registration

import keyboard

def on_ctrl_c():
    print('Ctrl+C was pressed!')

def on_f1():
    print('F1 Help key pressed!')

def on_custom_hotkey():
    print('Custom hotkey Ctrl+Shift+H pressed!')

# Register hotkeys
keyboard.add_hotkey('ctrl+c', on_ctrl_c)
keyboard.add_hotkey('f1', on_f1)  
keyboard.add_hotkey('ctrl+shift+h', on_custom_hotkey)

print('Hotkeys registered. Press ESC to exit.')
keyboard.wait('esc')

# Clean up
keyboard.unhook_all_hotkeys()

Hotkeys with Arguments

import keyboard

def show_message(msg, count=1):
    for i in range(count):
        print(f'{msg} ({i+1})')

# Hotkey with arguments
keyboard.add_hotkey('f2', show_message, args=('Hello from F2!', 3))
keyboard.add_hotkey('f3', show_message, args=('Quick message',))

keyboard.wait('esc')
keyboard.unhook_all_hotkeys()

Multi-Step Hotkeys

import keyboard

def konami_code():
    print('Konami code activated!')

def quick_save():
    print('Quick save sequence activated!')

# Multi-step hotkey sequences
keyboard.add_hotkey('up, up, down, down, left, right, left, right, b, a', konami_code)
keyboard.add_hotkey('ctrl+s, ctrl+s', quick_save, timeout=2)  # Double Ctrl+S within 2 seconds

keyboard.wait('esc')
keyboard.unhook_all_hotkeys()

Hotkey Suppression

import keyboard

def custom_alt_f4():
    print('Alt+F4 intercepted! Custom close behavior.')
    # Could implement custom confirmation dialog here
    return False  # Suppress the original Alt+F4

# Suppress Alt+F4 and replace with custom behavior
keyboard.add_hotkey('alt+f4', custom_alt_f4, suppress=True)

print('Alt+F4 is now intercepted. Press ESC to exit.')
keyboard.wait('esc')
keyboard.unhook_all_hotkeys()

Dynamic Hotkey Management

import keyboard

hotkey_callbacks = {}

def register_dynamic_hotkey(hotkey_str, message):
    def callback():
        print(f'Dynamic hotkey: {message}')
    
    remove_func = keyboard.add_hotkey(hotkey_str, callback)
    hotkey_callbacks[hotkey_str] = remove_func
    print(f'Registered: {hotkey_str}')

def unregister_dynamic_hotkey(hotkey_str):
    if hotkey_str in hotkey_callbacks:
        hotkey_callbacks[hotkey_str]()  # Call remove function
        del hotkey_callbacks[hotkey_str]
        print(f'Unregistered: {hotkey_str}')

# Register some dynamic hotkeys
register_dynamic_hotkey('f5', 'Refresh action')
register_dynamic_hotkey('f6', 'Toggle action')
register_dynamic_hotkey('ctrl+1', 'Workspace 1')

print('Dynamic hotkeys registered. Press F9 to remove F5, F10 to exit.')

def remove_f5():
    unregister_dynamic_hotkey('f5')

keyboard.add_hotkey('f9', remove_f5)
keyboard.wait('f10')

# Clean up all remaining hotkeys
for remove_func in hotkey_callbacks.values():
    remove_func()

Hotkey Remapping

import keyboard

# Remap Windows key combinations for different workflow
remove_remap1 = keyboard.remap_hotkey('win+l', 'ctrl+alt+l')  # Custom lock
remove_remap2 = keyboard.remap_hotkey('win+d', 'alt+tab')     # Show desktop -> Alt+Tab

# Remap for left-handed users
remove_remap3 = keyboard.remap_hotkey('ctrl+c', 'ctrl+insert')  # Alternative copy
remove_remap4 = keyboard.remap_hotkey('ctrl+v', 'shift+insert') # Alternative paste

print('Hotkey remapping active. Press ESC to exit.')
keyboard.wait('esc')

# Remove all remappings
remove_remap1()
remove_remap2() 
remove_remap3()
remove_remap4()

Context-Sensitive Hotkeys

import keyboard

class HotkeyManager:
    def __init__(self):
        self.mode = 'normal'
        self.hotkeys = {}
        self.setup_mode_hotkeys()
    
    def setup_mode_hotkeys(self):
        # Mode switching
        self.hotkeys['f12'] = keyboard.add_hotkey('f12', self.toggle_mode)
        
        # Context-sensitive hotkeys
        self.hotkeys['1'] = keyboard.add_hotkey('1', self.handle_1_key)
        self.hotkeys['2'] = keyboard.add_hotkey('2', self.handle_2_key)
    
    def toggle_mode(self):
        self.mode = 'editing' if self.mode == 'normal' else 'normal'
        print(f'Switched to {self.mode} mode')
    
    def handle_1_key(self):
        if self.mode == 'normal':
            print('Normal mode: Action 1')
        else:
            print('Editing mode: Edit action 1')
    
    def handle_2_key(self):
        if self.mode == 'normal':
            print('Normal mode: Action 2')
        else:
            print('Editing mode: Edit action 2')
    
    def cleanup(self):
        for remove_func in self.hotkeys.values():
            remove_func()

# Usage
manager = HotkeyManager()
print('Context-sensitive hotkeys active. F12 to toggle mode, ESC to exit.')
keyboard.wait('esc')
manager.cleanup()

Advanced Hotkey Features

Timeout Control

import keyboard

def slow_sequence():
    print('Slow sequence completed!')

def fast_sequence():
    print('Fast sequence completed!')

# Different timeout values for different sequences
keyboard.add_hotkey('ctrl+a, ctrl+b', slow_sequence, timeout=5)    # 5 seconds allowed
keyboard.add_hotkey('ctrl+x, ctrl+y', fast_sequence, timeout=0.5)  # 0.5 seconds allowed

keyboard.wait('esc')
keyboard.unhook_all_hotkeys()

Release-Triggered Hotkeys

import keyboard

def on_key_release():
    print('Hotkey triggered on release!')

def on_key_press():
    print('Hotkey triggered on press!')

# Compare press vs release triggering
keyboard.add_hotkey('f7', on_key_press, trigger_on_release=False)
keyboard.add_hotkey('f8', on_key_release, trigger_on_release=True)

keyboard.wait('esc')
keyboard.unhook_all_hotkeys()

Hotkey String Format

Single Key Hotkeys

  • 'f1' - Function keys
  • 'a' - Letter keys
  • 'space' - Named keys
  • 'enter' - Special keys

Modifier Combinations

  • 'ctrl+c' - Single modifier
  • 'ctrl+shift+a' - Multiple modifiers
  • 'alt+f4' - Case insensitive

Multi-Step Sequences

  • 'ctrl+k, ctrl+c' - Visual Studio style
  • 'ctrl+x, ctrl+c' - Emacs style
  • 'g, g' - Vim style (double key)

Special Key Names

  • 'plus' for '+' symbol
  • 'comma' for ',' symbol
  • 'space' for spacebar
  • 'left ctrl' / 'right ctrl' for sided modifiers

Error Handling

Hotkey registration may fail due to:

  • Invalid hotkey format strings
  • Platform limitations (Linux requires root for global hotkeys)
  • Conflicting hotkey registrations
  • System security restrictions

The package will raise ValueError for invalid hotkey strings and may silently fail to register hotkeys in restricted environments.

Performance Considerations

  • Hotkeys with many modifiers are more expensive to detect
  • Multi-step hotkeys require state tracking and timeout management
  • Suppressed hotkeys add processing overhead
  • Large numbers of registered hotkeys can impact system responsiveness

For optimal performance:

  • Use specific hotkeys rather than broad key hooks when possible
  • Remove unused hotkeys promptly
  • Avoid overlapping hotkey patterns that could cause conflicts

Install with Tessl CLI

npx tessl i tessl/pypi-keyboard

docs

hotkeys.md

index.md

interactive-input.md

key-simulation.md

keyboard-events.md

recording-playback.md

text-processing.md

tile.json