Skip to content

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)
     └───────────────┘
  1. 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).
  2. 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.
  3. 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.
  4. 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_system using the phrase event.
  • The on_pre_phrase function extracts the list of words from the recognized Phrase object and joins them into a single string.
  • It uses skip_phrase to 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_screens helper translates the user.subtitles_screens setting 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's SkiaCanvas paint styles:
  • It applies a subtle drop shadow using ImageFilter.drop_shadow to improve contrast.
  • It draws the base text in the color specified by user.subtitles_color.
  • It overlays a second text layer with Style.STROKE using the color from user.subtitles_color_outline to 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_rect scales down the font size iteratively until the text occupies less than 80% of the screen's width. The y position 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 asynchronous cron.after scheduler.

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 to 100).
  • 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.93 places the subtitles near the bottom of the screen).
  • Timeout Settings: Fine-grained settings (user.subtitles_timeout_per_char, user.subtitles_timeout_min, and user.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.