subtitles
This directory contains a custom subtitle system for Talon. It intercept spoken phrases and renders them dynamically as styled subtitles on the screen. It is designed as a highly configurable alternative to Talon's default subtitle rendering, offering deep control over colors, text styling (including outlines and drop shadows), screen positioning, multiple monitor layouts, and display duration.
How the Subtitle System Works
The subtitle plugin operates through a coordinated sequence of interception, layout computation, and canvas rendering.
[Speech Input]
│
▼
┌───────────────┐
│ on_phrase.py │ <-- Intercepts recognized phrases (skips if asleep)
└───────┬───────┘
│ (passes text)
▼
┌───────────────┐
│ subtitles.py │ <-- Computes screen placement, scales text size,
└───────┬───────┘ and draws using SkiaCanvas API with shadow/outline
│
▼
┌───────────────┐
│ Talon Canvas │ <-- Displays subtitle temporarily on target screen(s)
└───────────────┘
- Phrase Interception: The system registers a callback with Talon's speech engine. When speech is recognized, the system formats the phrase and filters out commands that should not generate subtitles (such as speech received while Talon is asleep).
- Layout and Dimension Calculations: The system checks settings to determine which screen(s) should display the subtitle. It then dynamically calculates the necessary size of the subtitle so it fits comfortably within the bounds of the targeted screen.
- Canvas Drawing: Using Talon's native canvas API, the system uses Skia to draw the text with custom styling, incorporating an outline and a drop shadow for maximum legibility on various backgrounds.
- Display Timeout: The canvas is displayed for a configurable duration that scales proportionally to the length of the spoken phrase, before automatically closing.
Component Breakdown
Speech Listener and Filter
The script on_phrase.py hooks directly into Talon's speech pipeline.
- It registers a listener on
speech_systemusing thephraseevent. - The
on_pre_phrasefunction extracts the list of words from the recognizedPhraseobject and joins them into a single string. - It uses
skip_phraseto ignore empty phrases and handles sleep state logic. If the microphone is asleep and the parsed phrase is a sleep-only activation pattern (like___ltphrase_gt__), it suppresses the subtitle to prevent visual clutter. - Successfully validated phrases are forwarded to the renderer by calling
show_subtitle.
Subtitle Rendering and Canvas Lifecycle
The core rendering engine is implemented in subtitles.py. This file registers all custom user.subtitles_* configurations with Talon's settings database and implements the display logic.
- Target Screen Determination: The
get_screenshelper translates theuser.subtitles_screenssetting into actual screen contexts. Subtitles can be routed to the"main"screen,"all"active screens, the screen containing the mouse"cursor", or the screen containing the active"focus"window. - Canvas Styling & Skia Draw: In
on_draw, the engine utilizes Talon'sSkiaCanvaspaint styles: - It applies a subtle drop shadow using
ImageFilter.drop_shadowto improve contrast. - It draws the base text in the color specified by
user.subtitles_color. - It overlays a second text layer with
Style.STROKEusing the color fromuser.subtitles_color_outlineto create a clean border around the text. - Scaling and Bounds Guarding: Text size is automatically adjusted. If a phrase is long,
set_text_size_and_get_rectscales down the font size iteratively until the text occupies less than 80% of the screen's width. Theyposition is clamped using screen boundaries to ensure the text is never pushed off-screen. - Timeout Management: Subtitle display duration is calculated dynamically based on character count (
user.subtitles_timeout_per_char), clamped securely between configured minimum and maximum limits. Timed dismissal is handled via Talon's asynchronouscron.afterscheduler.
User Settings and Defaults
Configuration defaults and definitions are stored in subtitles.talon. Users can override these defaults in their custom user settings:
user.subtitles_show: A boolean switch to toggle custom subtitles on or off.user.subtitles_screens: Configures screen behavior (options:"all","main","cursor", or"focus").user.subtitles_size: The maximum font size in pixels (defaults to100).user.subtitles_color/user.subtitles_color_outline: Hexadecimal color codes defining text fill and outline colors.user.subtitles_y: The vertical alignment factor relative to screen height (e.g.,0.93places the subtitles near the bottom of the screen).- Timeout Settings: Fine-grained settings (
user.subtitles_timeout_per_char,user.subtitles_timeout_min, anduser.subtitles_timeout_max) to calibrate how long a subtitle remains visible depending on the size of the phrase spoken.
Detailed instructions on how to toggle the feature and avoid duplicate native overlays can be found in the README.md.