What APIs Does FluidVoice Use for Text Insertion? A Complete Technical Breakdown
FluidVoice uses a seven-layer fallback pipeline of macOS APIs for text insertion, ranging from fast CGEvent Unicode injection to reliable clipboard-based paste operations, as implemented in TypingService.swift.
FluidVoice is an open-source macOS voice dictation application that needs to inject transcribed text into any target application reliably. According to the altic-dev/FluidVoice source code, this requires a sophisticated multi-strategy approach that gracefully degrades when faster methods fail. The core insertion logic lives in Sources/Fluid/Services/TypingService.swift, where each API is attempted in priority order based on speed and compatibility.
The Seven-Layer Text Insertion Pipeline
FluidVoice's insertTextInstantly(_:preferredTargetPID:) method orchestrates a cascading fallback system. The pipeline first checks the user's chosen text insertion mode (.standard or .reliablePaste) before proceeding through these API layers:
CGEvent Unicode Insertion (Direct Typing)
The fastest path uses Core Graphics event injection to send Unicode characters directly to a target process identifier.
- Method:
insertTextBulkInstant - Mechanism: Creates
CGEventobjects with Unicode string payloads and posts them to a specific PID - Best for: Terminal applications, Electron apps, and processes with reliable PID targeting
// Direct CGEvent unicode insertion (bulk)
let success = typingService.insertTextBulkInstant("Hello, world!", targetPID: 12345)
This approach bypasses the macOS input system entirely, making it both fast and resistant to interference from input method editors.
Accessibility API Insertion
When CGEvent fails or no PID is available, FluidVoice falls back to the Accessibility framework to manipulate the focused UI element.
- Method:
insertTextViaAccessibility - Mechanism: Uses
AXUIElementSetAttributeValueto set theAXValueof the focused element, then positions the caret - Best for: Standard Cocoa applications with properly exposed accessibility trees
// Accessibility insertion
let success = typingService.insertTextViaAccessibility("Hello, world!")
This method requires the target application to implement accessibility support, but works where low-level event injection is blocked.
HID-Level CGEvent Insertion
For scenarios where no focused PID can be determined, FluidVoice uses HID-level event simulation that mimics a physical keyboard at the hardware abstraction layer.
- Method:
insertTextBulkHIDInstant - Mechanism: Creates
CGEventkeyboard events without PID targeting, relying on the system to route them - Best for: Global insertion when target identification fails
// HID-level CGEvent insertion (no PID)
let success = typingService.insertTextBulkHIDInstant("Hello, world!")
Clipboard-Based Insertion (Global Paste)
The most reliable fallback copies text to the system clipboard and simulates Command+V paste.
- Method:
tryReliablePasteInsertion→insertTextViaClipboard - Mechanism: Temporarily replaces clipboard contents, issues paste keystroke, then (optionally) restores original clipboard
- Best for: Applications that reject direct event injection but accept standard paste operations
// Clipboard-based insertion (global)
let success = typingService.insertTextViaClipboard("Hello, world!")
Clipboard-to-PID Insertion (Targeted Paste)
A refinement of the clipboard method that activates a specific target process before pasting.
- Method:
insertTextViaClipboardToPid - Mechanism: Activates target PID, performs clipboard paste, with optional foreground activation
- Best for: Applications like Ghostty that require explicit activation for paste to succeed
// Clipboard-to-PID insertion (targeted)
let success = typingService.insertTextViaClipboardToPid(
"Hello, world!", targetPID: 12345, activateTargetFirst: true)
Menu-Based Paste Insertion
When keyboard shortcuts fail, FluidVoice programmatically triggers the Edit → Paste menu command.
- Method:
insertTextViaMenuPaste - Mechanism: Uses Accessibility API to locate and click the Paste menu item
- Best for: Applications with non-standard keyboard handling or disabled shortcuts
// Menu-based paste insertion
let success = typingService.insertTextViaMenuPaste("Hello, world!")
Character-by-Character Typing
The final fallback types each character individually with small delays between keystrokes.
- Location: Loop starting at line 84 in
insertTextInstantly - Mechanism: HID-level events with
usleepdelays between each character - Best for: Hostile environments where all bulk methods fail
// Character-by-character fallback (automatic via pipeline)
typingService.insertTextInstantly("Hello, world!", preferredTargetPID: nil)
Key Source Files and Architecture
| File | Purpose |
|---|---|
Sources/Fluid/Services/TypingService.swift |
Central orchestration of all insertion APIs and the fallback pipeline |
Sources/Fluid/Services/ClipboardService.swift |
Clipboard state management for paste-based insertion paths |
Sources/Fluid/Services/TranscriptionProvider.swift |
Provides transcribed text consumed by TypingService |
Tests/FluidDictationIntegrationTests/TypingServiceTransientPasteboardTests.swift |
Unit tests verifying clipboard insertion correctness |
The pipeline includes comprehensive logging from line 350 onward in TypingService.swift, enabling debugging of which API succeeded or failed for any given insertion attempt.
Comparison of Text Insertion APIs
| API Layer | Speed | Reliability | Setup Required |
|---|---|---|---|
| CGEvent Unicode | Fastest | Moderate | Target PID |
| Accessibility | Fast | Moderate | AX permissions |
| HID CGEvent | Fast | Moderate | None |
| Global Clipboard | Moderate | High | None |
| Clipboard-to-PID | Moderate | High | Target PID |
| Menu Paste | Slow | High | AX permissions |
| Character-by-character | Slowest | Highest | None |
Summary
- FluidVoice's text insertion relies on
TypingService.swiftto coordinate seven distinct macOS APIs in a prioritized fallback chain. - CGEvent Unicode injection provides the fastest path when targeting a known PID, while clipboard-based paste operations offer the most reliable cross-application compatibility.
- The pipeline automatically escalates from high-speed, low-reliability methods to slower, more robust alternatives based on real-time success detection.
- Developers integrating similar functionality should study
insertTextInstantly(_:preferredTargetPID:)for patterns on graceful degradation and user-configurable insertion modes.
Frequently Asked Questions
Does FluidVoice require accessibility permissions for all text insertion methods?
No. Only the Accessibility API insertion and menu-based paste methods require Accessibility permissions. The CGEvent and HID-level methods function without additional permissions, though they may be blocked by certain application sandboxing configurations. The clipboard-based methods require no special permissions beyond standard pasteboard access.
How does FluidVoice handle clipboard restoration after paste insertion?
According to Sources/Fluid/Services/ClipboardService.swift, the implementation uses a transient pasteboard pattern. The original clipboard contents are preserved before insertion and restored after the paste operation completes (usually within milliseconds). This prevents dictation from corrupting the user's clipboard state, with unit tests in TypingServiceTransientPasteboardTests.swift verifying this behavior.
Why does FluidVoice need multiple text insertion APIs instead of just using paste?
Single-method approaches fail across macOS's diverse application ecosystem. Terminal applications often ignore paste operations in certain modes, Electron apps may block Accessibility API, games and full-screen apps frequently intercept all standard input, and sandboxed applications restrict cross-process event injection. The seven-layer pipeline ensures FluidVoice functions regardless of target application architecture or security posture.
Can I force FluidVoice to use a specific insertion API?
Yes. The insertTextInstantly method respects a text insertion mode parameter. Set .standard to attempt the full fast-to-slow pipeline starting with CGEvent, or .reliablePaste to skip directly to clipboard-based methods. Advanced users can also call individual methods like insertTextViaClipboard directly, though these are typically internal to the service.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →