selection-capture
selection-capture is a Rust library for selected-text capture with retry, cancellation,
and strategy fallbacks.
For AI agents, use the machine-oriented guide: AGENTS.md
Raw URL: https://raw.githubusercontent.com/maemreyo/selection-capture/main/AGENTS.md
It is designed as a replacement foundation for earlier get-selected-text style usage,
with explicit capture status and trace metadata for app-level UX decisions.
Features
- โ Synchronous API - Simple, blocking calls that are easy to integrate
- โ
Optional Async API - Feature-gated
capture_async(...)for Tokio-based applications - โ
Optional Rich Content API - Feature-gated
capture_rich(...)/try_capture_rich(...)with clipboard HTML/RTF enrichment - ๐งช Experimental Monitoring Scaffold - Backend-agnostic monitoring API surface for future selection change streams
- ๐ Retry Logic - Automatic retry with configurable budgets and delays
- โก Multiple Strategies - Falls back through different capture methods automatically
- ๐ฏ App-Specific Profiles - Customize behavior per application
- ๐ Detailed Tracing - Full visibility into what happened during capture attempts
- โ Cancellation Support - Cooperative cancellation via
CancelSignaltrait - ๐งน Automatic Cleanup - Clipboard cleanup after capture
Platform Support
- macOS: Fully implemented (
MacOSPlatform) - Windows:
windows-betaincludes real clipboard reads, foreground active-app lookup, and initial UIA + legacy IAccessible focused-element capture paths - Linux:
linux-alphaincludes shell-backed clipboard/primary-selection reads, active-app lookup, and AT-SPI focused-descendant capture - Other platforms: Portable API via
CapturePlatformtrait, implementations welcome!
Experimental monitoring support is scaffolded with a generic MonitorPlatform trait plus
CaptureMonitor<P>, and CaptureMetrics for aggregating capture-outcome success/latency
statistics from trace data. Polling monitor backends are available for macOS
(MacOSSelectionMonitor), Windows (WindowsSelectionMonitor, windows-beta), and Linux
(LinuxSelectionMonitor, linux-alpha) with per-backend de-duplication. Poll helpers now
include cancellation-aware loops and an optional coalescing mode for bursty event streams.
Installation
Add this to your Cargo.toml:
[]
= "0.1"
Or use the latest from Git:
[]
= { = "https://github.com/maemreyo/selection-capture" }
Enable the Windows beta scaffold explicitly:
[]
= { = "0.1", = ["windows-beta"] }
Enable the optional async wrapper explicitly:
[]
= { = "0.1", = ["async"] }
Enable rich-content capture explicitly:
[]
= { = "0.1", = ["rich-content"] }
Quick Start (macOS)
use ;
// Implement required traits for your use case
;
;
Core API
Main Function
capture(...)โCaptureOutcome- The primary capture functiontry_capture(...)โResult<CaptureOutcome, WouldBlock>- Non-blocking single-pass variantcapture_async(...).awaitโCaptureOutcome- Optional Tokio-backed wrapper behind theasyncfeaturecapture_rich(...)โCaptureRichOutcome- Optional rich-content capture behindrich-contenttry_capture_rich(...)โResult<CaptureRichOutcome, WouldBlock>- Non-blocking rich variant behindrich-content
Configuration
CaptureOptions- Configure timeouts, trace collection, and strategy overridesCapturePlatform- Trait for platform-specific implementationsMonitorPlatform- Experimental trait for platform-specific selection-change monitoringCancelSignal- Trait for cooperative cancellationAppAdapter- Trait for app-specific customizationsAppProfileStore- Trait for persisting app profiles
Experimental Monitoring
use ;
;
let monitor = new;
assert_eq!;
let processed = monitor.run_with_limit;
assert_eq!;
;
let mac_monitor = new;
let _native_pref = new_with_options;
let _ = _native_pref.enqueue_native_selection_event;
let _ = _native_pref.ingest_native_observer_payload;
let cancel = StopImmediately;
let _processed = mac_monitor.poll_until_cancelled;
let guard = MonitorSpamGuard ;
let _guarded = mac_monitor.poll_until_cancelled_guarded;
let _native_stats = _native_pref.native_observer_stats;
let _stats = mac_monitor.poll_until_cancelled_guarded_with_stats;
let mut metrics = default;
// metrics.record_outcome(&capture_outcome);
Current limitations:
- Native callback integration is fully wired on macOS; Windows/Linux expose native-event-preferred queue-and-pump scaffolds with polling fallback
- macOS
NativeObserverPreferreduses AXObserver callback ingress with a native-event queue and safe polling fallback - No async stream integration exists yet
Nonefrom backend is treated as "no more events" byrun(...)APIs- For anti-spam behavior, prefer
poll_until_cancelled_guarded(...)withMonitorSpamGuard
Return Types
CaptureOutcome::{Success, Failure}- Result of capture attemptCaptureRichOutcome::{Success, Failure}- Rich result with plain fallback semanticsCaptureStatus- Detailed status codes for deterministic UX mappingFailureKind- Categorization of failure modesCaptureTrace- Complete trace of all attempts madeCaptureSuccess.focused_window_frame- Focused window bounds (Option<CGRect>) for monitor-aware consumers
Rich Content Capture (rich-content feature)
capture_rich(...) preserves backward compatibility by keeping the plain capture engine as baseline,
then optionally attaching clipboard rich payloads.
- Rich payload sources (current):
- macOS direct AX RTF (
AXRTFForRange) when capture method is accessibility-based - Windows direct UIA text wrapped to minimal RTF when capture method is accessibility-based (
windows-beta) - Linux direct AT-SPI text wrapped to minimal RTF when capture method is accessibility-based (
linux-alpha) - Clipboard HTML/RTF fallback
- macOS direct AX RTF (
- Guardrail: rich payload is accepted only when clipboard plain text matches captured plain text
- Fallback: if guard fails (or payload unavailable/oversized), result degrades to plain content
CaptureRichOptions::allow_direct_accessibility_rich controls the direct AX path and defaults to
true.
CaptureRichOptions::conversion = Some(RichConversion::Markdown) enables markdown normalization and
populates RichPayload.markdown (powered by quick_html2md and rtf-to-html).
Example with Custom Options
use ;
use Duration;
let options = CaptureOptions ;
Permission Notes (macOS)
Depending on the target application and capture strategy, users may need to grant:
-
Accessibility Permission
System Settings โ Privacy & Security โ Accessibility -
Automation Permission
Required for AppleScript fallback in some application combinations
The library will gracefully degrade through available strategies based on permissions.
Architecture
โโโโโโโโโโโโโโโโโโโ
โ capture() โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โโโโโโผโโโโโ
โ Strategy โ
โ Manager โ
โโโโโโฌโโโโโ
โ
โโโโโโผโโโโโโโโโโโโโโโโโโ
โ 1. Accessibility API โ โ Primary method
โโโโโโโโโโโโโโโโโโโโโโโโค
โ 2. AppleScript โ โ Fallback 1
โโโโโโโโโโโโโโโโโโโโโโโโค
โ 3. Clipboard Monitor โ โ Fallback 2
โโโโโโโโโโโโโโโโโโโโโโโโ
Each strategy is attempted in order, with automatic retry and detailed tracing.
Contributing
Contributions are welcome! Please see our Contributing Guide for details on:
- Reporting bugs
- Suggesting features
- Submitting pull requests
- Code style and testing
Development Setup
# Clone the repository
# Build
# Run tests
# Run the Windows beta smoke path on any host
# Run the async wrapper tests
# Check formatting
# Run linter
Documentation
Related Projects
This library was extracted from the zmr-koe project, which provides a complete text capture solution.
License
MIT License - See LICENSE file for details.
Acknowledgments
Thanks to all contributors and the Rust community for making this possible!
Built with โค๏ธ by zamery and contributors