Keycast is a cross-platform keystroke and mouse click visualizer built in Python.
Project description
keycast
A cross-platform keystroke and mouse click visualizer built in Python.
Features
- Cross-platform support: Works on macOS, Linux, and Windows
- Keyboard visualization: Shows keystrokes in real-time with customizable formatting
- Mouse click visualization: Displays mouse clicks with optional position information
- Transparent overlay: Semi-transparent window that stays on top (when Tkinter is available)
- Configurable display: Customize colors, fonts, position, and behavior
- Key mapping: Customizable key name mappings for better display
- Fade effects: Events fade out after a configurable duration
- Graceful error handling: Handles permission issues and missing dependencies gracefully
Installation
uvx keycast
Usage
Basic Usage
Simply run the application:
uv run keycast
The application will start and display a transparent overlay window that shows your keystrokes and mouse clicks in real-time.
Stopping the Application
Press Ctrl+C in the terminal to stop the application gracefully.
Platform-Specific Permissions
macOS
On macOS, you'll need to grant accessibility permissions to your terminal or IDE:
- Go to System Preferences > Security & Privacy > Privacy > Accessibility
- Add your terminal application (Terminal.app, iTerm2, etc.) or IDE to the list.
- Make sure the checkbox is checked.
Configuration
keycast uses a JSON configuration file with Pydantic-based settings validation. You do not need to manually create this file—the application will automatically create it if it doesn't exist.
- All platforms:
~/.keycast/config.json
Configuration Options
Display Settings
{
"display": {
"width": 400,
"height": 100,
"x_position": "center",
"y_position": 50,
"background_color": "black",
"text_color": "white",
"font_family": "Arial",
"font_size": 16,
"font_weight": "bold",
"alpha": 0.8,
"always_on_top": true,
"draggable": false,
"fade_duration_ms": 2000,
"max_events": 5
}
}
Keyboard Settings
{
"keyboard": {
"show_modifier_keys": true,
"show_function_keys": true,
"show_special_keys": true,
"key_mappings": {
"ctrl_l": "Control Left",
"space": "Space Bar",
"enter": "Enter"
}
}
}
Mouse Settings
{
"mouse": {
"show_mouse_clicks": true,
"show_mouse_position": false,
"button_names": {
"Button.left": "Left Click",
"Button.right": "Right Click"
}
}
}
Logging Settings
{
"logging": {
"level": "INFO",
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
"file_path": "/Users/you/.keycast/main.log",
"max_file_size_mb": 10,
"backup_count": 5
}
}
file_pathdefaults to~/.keycast/main.log(shown above as an absolute path;~is not expanded in the config). Set it tonullto log to the console only. When a file is used, it rotates atmax_file_size_mb, keepingbackup_countrotated copies.
General Settings
{
"debug": false,
"start_minimized": false,
"auto_start": true
}
These are top-level flags (not sections).
debug— whentrue, keycast surfaces verbose diagnostics regardless oflogging.level; a quick switch for troubleshooting without editing the logging block. Defaults tofalse.
auto_start— whentrue(default), the input listeners start on launch. Set it tofalseas a master switch to start with the overlay visible but capturing nothing, regardless ofkeyboard.enabled/mouse.enabled.
start_minimized— whentrue, the overlay starts hidden and appears the first time a key or click is captured. Requiresauto_startto betrue(otherwise nothing is captured and the overlay would never appear, so the combination is rejected). If no input source is actually live at startup — both listeners disabled, or they fail to start (e.g. missing OS input permissions) — keycast keeps the overlay visible rather than hiding a window it could never restore. Defaults tofalse.
Enabling/disabling each listener is controlled per-component via
keyboard.enabledandmouse.enabled(see the Keyboard/Mouse settings above).
Development
Running Tests
# Run all tests
uv run python -m pytest tests/
# Run specific test file
uv run python -m pytest tests/test_display.py
# Run with verbose output
uv run python -m pytest tests/ -v
Project Structure
keycast/
├── src/keycast/
│ ├── __init__.py # Package initialization
│ ├── __main__.py # `python -m keycast` entry point
│ ├── application.py # Keycast orchestrator (lifecycle + wiring)
│ ├── cli.py # Typer CLI entry point (`keycast` command)
│ ├── main.py # main(): constructs and runs Keycast
│ ├── listeners.py # Input event listeners + TextSink protocol
│ ├── display.py # Tkinter display window
│ ├── settings.py # Pydantic settings configuration
│ └── logging_setup.py # Logging configuration
├── tests/ # One test module per source module
├── docs/ # Comprehensive documentation
│ ├── README.md # Documentation index
│ ├── ARCHITECTURE.md # Architecture documentation
│ ├── API.md # API documentation
│ ├── DESIGN_DECISIONS.md # Design decisions
│ └── PROJECT_OVERVIEW.md # Project overview
├── pyproject.toml # Project configuration
└── README.md # This file
Documentation
Comprehensive documentation is available in the docs/ directory:
- Documentation Index - Overview of all documentation
- Project Overview - Complete project overview
- Architecture Documentation - Technical architecture details
- API Documentation - Complete API reference
- Design Decisions - Design rationale and trade-offs
Adding New Features
- Create a new branch for your feature
- Implement the feature with tests
- Update documentation if needed
- Submit a pull request
Troubleshooting
Common Issues
"Permission denied" or "This process is not trusted" errors on macOS
This is the most common issue on macOS. You need to grant accessibility permissions:
- Go to System Preferences (or System Settings on newer macOS versions)
- Navigate to Security & Privacy > Privacy > Accessibility
- Click the lock icon to make changes (enter your password)
- Add your terminal application (Terminal.app, iTerm2, etc.) or IDE to the list
- Make sure the checkbox is checked next to your application
- Restart keycast
If you're still having issues, try:
- Restart your terminal/IDE after granting permissions
- Make sure you're running keycast from the same terminal/IDE that you granted permissions to
- On some systems, you may need to restart your computer after granting permissions
Window doesn't appear
- Check if the application is running in the background
- Set
logging.levelto"DEBUG"(and optionallylogging.file_path) in the config to see detailed messages; logs default to~/.keycast/main.log - Ensure your display settings are correct
Keys not showing
- Check that
keyboard.enabled: truein your config - Verify the key filtering settings (
show_modifier_keys,show_function_keys, etc.)
Mouse clicks not showing
- Check that
mouse.enabled: truein your config - Verify that
show_mouse_clicks: truein the mouse settings
Testing Permissions
The "This process is not trusted!" messages you see are warnings from pynput, but they don't necessarily mean the permissions aren't working. The actual input monitoring should still function properly.
If you want to verify that permissions are working, try running keycast and see if it captures your keystrokes and mouse clicks. If it's not working, follow the accessibility permission steps above.
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file keycast-0.1.0.tar.gz.
File metadata
- Download URL: keycast-0.1.0.tar.gz
- Upload date:
- Size: 133.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d03ed74dcb35821abcb306218897ca396b2458c19b01e4374fc9cf0312b80035
|
|
| MD5 |
5d62aad469099c1596cbbe74a093df34
|
|
| BLAKE2b-256 |
18077ae07911e273c69af3b141055ee8bdbac4612462ced97a547ca2968f72a0
|
File details
Details for the file keycast-0.1.0-py3-none-any.whl.
File metadata
- Download URL: keycast-0.1.0-py3-none-any.whl
- Upload date:
- Size: 35.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dcc21bd172209462e1ffc444473789ba994e22ff90ec30ec591d68256c809477
|
|
| MD5 |
89a7a61ea387c8a3369d74a8c8d161e8
|
|
| BLAKE2b-256 |
25e9946553c4f2c8c02c3249681c5fc25bbda3b83a08f02d0870127ac4640f6e
|