Circle-to-Search for Windows — offline screen OCR and visual search in one hotkey.
OrbitOCR lives in your system tray. Press Ctrl + Shift + S (configurable), your desktop freezes across every monitor, and you can click or drag over any text to copy or search it, or draw a freehand circle around any image to search it with Google Lens. Text recognition runs entirely on the built-in Windows OCR engine — no cloud, no telemetry, no Tesseract, no Python.
- Key Features
- Getting Started
- Usage Guide
- Configuration & Shortcuts
- Architecture & Tech Stack
- Contributing
- License
- Acknowledgments
- 100% offline OCR — powered by the native Windows 10/11
Windows.Media.Ocrengine. Zero cloud APIs, zero telemetry, zero external runtimes. The explicit Search Google / Search with Lens actions are the only features that send data off-device, and only when you click them. - Circle-to-Search interaction — inspired by Google Pixel.
- Auto screen scan: on trigger, the whole virtual desktop is OCR'd in one background pass (typically ~150–250 ms) and every detected word becomes interactive.
- Direct text interaction: hovering a word shows a soft glow and switches to an
IBeamcursor; click a word or drag across a phrase to select it in reading order. - Region selection: drag a rectangle around any object, photo, or UI region to enter image mode, or hold
Alt(orShift) for a freehand lasso with a glowing cyan trail. Both show a live dimensions badge and draggable corner handles to refine the selection. - Dimming mask cut-out keeps your active selection at 100% brightness while the rest of the screen dims.
- Context-aware floating action pill
- Text mode: Copy Text (with a synthesized chime and tray toast) and Search Google.
- Image mode: Search with Lens (uploads the crop straight into Google Lens via the browser — no clipboard paste), Copy Image, Save Image (PNG/JPEG), plus Copy Text when text is detected inside the circle.
- Multi-monitor virtual desktop capture — captures all displays, including negative virtual-screen coordinates, and is PerMonitorV2 DPI-aware to prevent blur and coordinate drift.
- Global hotkey, no polling — registered through the Win32
RegisterHotKeyAPI and a hidden message pump. Defaults toCtrl + Shift + S; fully remappable from Settings (at least one modifier or anF1–F12key is required to avoid accidental triggers). - Background-first lifecycle — single-instance mutex, tray balloon on launch, and aggressive working-set trimming after every snip (idle footprint ~30 MB).
- OCR with small-text boost — crops up to 1500 × 1500 px are rescaled 2× with high-quality bicubic interpolation before recognition, significantly improving accuracy on small UI fonts.
- Language-aware — defaults to your Windows user-profile OCR languages, with a configurable picker over every installed recognizer language pack.
- Fluent dark UI — custom WPF design system (accent
#60CDFF), DWM immersive dark title bar, and automation names/live regions for screen readers.
| Requirement | Details |
|---|---|
| OS | Windows 10 version 2004 (build 19041) or later, or Windows 11 — x64 |
| Runtime (end users) | None. Use the self-contained build; no .NET installation required |
| Runtime (developers) | .NET 8.0 SDK or newer |
| OCR language pack | Installed via Settings → Time & Language → Language & region for any language you want to recognize (English ships with Windows) |
| Optional | Visual Studio 2022 17.8+ (workload .NET desktop development) or VS Code + C# Dev Kit |
No installer and no admin rights required — OrbitOCR is a portable single executable (asInvoker manifest).
- Download OrbitOCR.exe (Windows 10 2004+ / Windows 11, x64) from the Releases page.
- Put it in any folder (e.g.
%LOCALAPPDATA%\Programs\OrbitOCR) and run it. Since the binary is unsigned, Windows SmartScreen may show a warning on first launch — choose More info → Run anyway. - On first start the Settings window opens. Press Test or the global hotkey to try a snip.
- Optional: enable Start with Windows in Settings to add OrbitOCR to your sign-in.
- It now lives in the notification tray. Right-click the tray icon for
Trigger snip,Settings…,About OrbitOCR, andExit.
Or install with the Windows Package Manager:
winget install torpidno.OrbitOCRThe winget manifest is submitted to
microsoft/winget-pkgsand resolves once that pull request is merged — until then, use the direct download above.
git clone https://github.com/torpidno/OrbitOCR.git
cd OrbitOCR
# Restore, compile, run (opens the Settings window)
dotnet build
dotnet run
# Or start straight to the tray, skipping the Settings window
dotnet run -- --minimizedThe app targets net8.0-windows10.0.19041.0 with WPF enabled, so build and run commands must be executed on Windows.
dotnet test tests/OrbitOCR.Tests.csproj13 automated tests (MSTest) cover bitmap cropping and clamping, settings defaults and hotkey formatting, OCR language discovery, virtual-screen bounds, end-to-end OCR on clear and small dark-mode text, the Lens upload payload contract, PNG encoding, and XAML/resource smoke tests for every view.
The OCR end-to-end tests require a desktop session with at least one installed Windows OCR language pack.
Creates a self-contained, compressed, single-file OrbitOCR.exe with the .NET runtime bundled:
dotnet publish -c Release -r win-x64 --self-contained true `
-p:PublishSingleFile=true `
-p:IncludeNativeLibrariesForSelfExtract=true `
-p:EnableCompressionInSingleFile=true `
-o ./publishOutput: ./publish/OrbitOCR.exe — copy it to any folder, USB drive, or startup directory (publish/ is git-ignored).
- Trigger — press your global hotkey (default
Ctrl + Shift + S), left-click the tray icon, or pickTrigger snipfrom the tray menu. - Wait for the scan — the desktop freezes, dims, and the top pill reports how many words were detected.
- Interact:
- Click any underlined word, or drag across several, to select text. A pill appears with Copy Text and Search Google.
- Dragging anywhere that isn't text draws a rectangular selection. Hold
Alt(orShift) while dragging for a freehand lasso instead. Release to capture that region as an image; drag the corner handles to adjust it.
- Act on the pill (copy, search, save), or press
Escto dismiss everything.
| Goal | Steps |
|---|---|
| Copy text from a video, PDF, or app that blocks selection | Hotkey → click/drag the words → Copy Text (or Ctrl + C) |
| Look up an error message | Hotkey → drag the message → Search Google |
| Identify a product, landmark, or plant | Hotkey → drag or circle it → Search with Lens |
| Save a region as an image | Hotkey → drag around the region → Save Image → choose PNG/JPEG |
| Reuse a screenshot in a chat | Hotkey → drag around the region → Copy Image → paste anywhere |
| Grab text without clicking the pill | Enable Auto-copy recognized text in Settings — the selection is copied the moment you release the mouse |
Text mode (words detected under the cursor):
| Action | Description |
|---|---|
| Click a word | Selects the single word |
| Drag across words | Selects the phrase in reading order, preserving spaces |
Copy Text / Ctrl + C |
Clipboard + chime + tray toast, then closes the overlay |
| Search Google | Opens https://www.google.com/search?q=… in the default browser |
| Esc | Cancels the snip immediately |
Image mode (drag or circle a non-text region):
| Action | Description |
|---|---|
| Search with Lens | Encodes the crop and hands it to Google Lens through your default browser via a self-submitting temp page (deleted after 2 minutes; stale files swept on startup). Falls back to clipboard + lens.google.com if the hand-off fails |
| Copy Image | Puts the cropped bitmap on the clipboard |
| Save Image | Save-as dialog; defaults to OrbitOCR_yyyyMMdd_HHmmss.png, PNG or JPEG |
| Copy Text | Appears only when text was detected inside the region; runs OCR on the crop with the 2× upscale boost |
| Corner handles | Resize the lasso bounding box before acting |
| Item | Description |
|---|---|
| Trigger snip | Same as the global hotkey (the configured shortcut is shown as its gesture) |
| Settings… | Shortcut recorder, behavior toggles, and OCR language |
| About OrbitOCR | Version and credits |
| Exit | Fully unregisters the hotkey and removes the tray icon |
Left-clicking or double-clicking the tray icon also triggers a snip.
| Shortcut | Context | Action |
|---|---|---|
Ctrl + Shift + S |
Global (default, configurable) | Trigger a snip |
Ctrl + C |
Overlay, text selected | Copy the selected text and close the overlay |
Alt (or Shift) + drag |
Overlay, non-text area | Freehand lasso instead of the default rectangular selection |
Esc |
Overlay / shortcut recorder | Cancel the snip / stop recording |
F1–F12 |
Global | Function keys are valid hotkeys without any modifier |
Hotkey validation: a combination must include at least one of Ctrl, Shift, Alt, Win, or be a function key (F1–F12). Assignments that would swallow ordinary typing are rejected when saving. If Windows itself refuses a combination (another app already owns it), OrbitOCR keeps the previously working shortcut active and shows a warning instead of leaving you without one.
| Setting | Default | Description |
|---|---|---|
| Global shortcut | Ctrl + Shift + S |
Click Record, press the combination, then Save. Test fires a snip immediately |
| Auto-copy recognized text | Off | Copies the selection to the clipboard as soon as the mouse is released over text |
| Sound feedback | On | Plays the Windows notification sound when text or an image is copied |
| Start with Windows | Off | Adds "OrbitOCR.exe" --minimized to HKCU\Software\Microsoft\Windows\CurrentVersion\Run, so sign-in boots straight to the tray |
| OCR language | Default (Windows user profile) | Any installed Windows.Media.Ocr recognizer language; falls back to the user profile, then to the first available language |
Settings persist as JSON at %APPDATA%\OrbitOCR\settings.json. The file is created on first save; a corrupt file silently falls back to defaults.
| Key | Type | Default | Description |
|---|---|---|---|
HotkeyCtrl |
bool | true |
Include Ctrl in the global hotkey |
HotkeyShift |
bool | true |
Include Shift |
HotkeyAlt |
bool | false |
Include Alt |
HotkeyWin |
bool | false |
Include Win |
HotkeyKey |
string | "S" |
Key name (Key enum name or a single character) |
AutoCopyOnSnip |
bool | false |
Copy text automatically when a text selection ends |
PlaySounds |
bool | true |
Play the copy chime |
StartWithWindows |
bool | false |
Register/unregister the HKCU\...\Run entry (launches with --minimized) |
PreferredOcrLanguage |
string? | null |
BCP-47 tag (e.g. "de-DE"); null follows Windows user-profile languages |
| Flag | Effect |
|---|---|
--minimized / /minimized |
Start in the tray without opening the Settings window |
OrbitOCR is a single-process WPF tray application. Services are composed by hand in App.OnStartup and communicate through events (HotkeyTriggered, TriggerSnipRequested, SettingsChanged, …), so the UI never talks to Win32 directly and the hotkey, tray, and settings subsystems stay testable and disposable.
| Layer | Technology |
|---|---|
| Runtime | .NET 8 (net8.0-windows10.0.19041.0), C# 12, nullable reference types, implicit usings |
| UI | WPF (XAML + code-behind, no MVVM framework), custom Fluent dark design system in UI/Theme.xaml, DWM immersive dark title bar |
| OCR | Windows WinRT Windows.Media.Ocr.OcrEngine via Microsoft.Windows.SDK.NET projection |
| Capture | GDI+ CopyFromScreen across SM_*VIRTUALSCREEN metrics, System.Drawing.Common 8.0.8, high-quality bicubic 2× upscale for crops |
| Interop | Win32 RegisterHotKey/WM_HOTKEY, Shell_NotifyIcon, SetProcessWorkingSetSize, SetWindowPos, PerMonitorV2 DPI |
| Persistence | System.Text.Json → %APPDATA%\OrbitOCR\settings.json; HKCU\...\Run for startup |
| Lens hand-off | Generated temp HTML that multipart-POSTs the PNG to Google Lens' own upload endpoint, opened in the default browser (temp file lifetime 2 min, stale sweep on startup) |
| Tests | MSTest 3.1.1, Microsoft.NET.Test.Sdk 17.8.0, coverlet.collector 6.0.0 |
OrbitOCR/
├── .github/workflows/build.yml # CI: restore, build, and test on windows-latest
├── docs/ # Landing page (GitHub Pages source) + README screenshot
│ ├── index.html # Static landing page (search + AI discoverable)
│ ├── llms.txt # Fact sheet for AI assistants and crawlers
│ ├── preview.png # README/landing screenshot
│ ├── sitemap.xml · robots.txt # Search indexing
│ └── favicon.ico
├── LICENSE # MIT License
├── app.manifest # PerMonitorV2 DPI awareness, Win10/11 compatibility, asInvoker
├── OrbitOCR.csproj # net8.0-windows target, version 1.0.0, single-file publish spec
├── App.xaml / App.xaml.cs # Composition root: tray lifecycle, single-instance mutex, memory trimming
├── Models/
│ ├── AppSettings.cs # Hotkey, selection mode, sound/startup flags, OCR language
│ └── OcrExtractedResult.cs # OCR result text + word bounding boxes
├── Services/
│ ├── HotkeyService.cs # RegisterHotKey + hidden HwndSource message pump (MOD_NOREPEAT)
│ ├── ScreenCaptureService.cs # Virtual-desktop capture, DIP-aware conversion, clamped cropping
│ ├── OcrService.cs # OcrEngine wrapper: language selection, 2× upscale, word boxes
│ ├── LensSearchService.cs # Self-submitting Lens payload page, temp lifecycle, cleanup
│ ├── TrayIconService.cs # Shell_NotifyIcon, balloons, Fluent dark context menu
│ ├── SoundService.cs # Windows notification sound on copy
│ └── SettingsService.cs # settings.json load/save + startup registry
├── UI/
│ ├── Theme.xaml # Fluent dark design tokens, control templates, switches
│ ├── ActionMenu.xaml (.cs) # Floating pill with contextual text/image actions
│ ├── OverlayWindow.xaml (.cs) # TopMost frozen-desktop canvas, lasso, mask cutout, word layer
│ └── SettingsWindow.xaml (.cs) # Hotkey recorder, toggles, OCR language selector
├── Assets/
│ ├── app.ico # Application (exe) icon
│ └── tray.ico # Tray icon, multi-resolution (16/32/48/64 px)
└── tests/
├── OrbitOCR.Tests.csproj # MSTest project
├── UnitTest1.cs # Unit + integration tests (cropping, settings, OCR, Lens payload)
└── UiSmokeTests.cs # Parses/lays out every view to catch XAML resource errors
- No polling anywhere. The global hotkey arrives as a
WM_HOTKEYmessage on a hidden window, and the tray icon asWM_TRAYICONcallbacks. - Capture → scan are decoupled. The full-screen OCR runs asynchronously after the overlay is shown, so the UI stays responsive while words stream in.
- Memory discipline. On overlay close, bitmaps and visual canvases are explicitly disposed/cleared, then a full GC plus
SetProcessWorkingSetSize(-1, -1)trims the working set for an ultra-light tray footprint. - Coordinates are kept in DIP space. Physical pixel word boxes are scaled to canvas coordinates, and crops are scaled back on capture — keeping selection accurate under DPI scaling and multi-monitor setups.
Contributions are welcome — bug reports, fixes, and features alike.
Open an issue and include:
- Windows version/build and monitor layout (single or multi-monitor, DPI scale);
- steps to reproduce and what you expected;
- the OCR language selected and, if relevant, your
%APPDATA%\OrbitOCR\settings.json; - screenshots or a screen recording when the overlay misbehaves.
Check for existing issues first, and keep one issue per problem.
- Fork the repository and create a topic branch (
fix/lasso-resize,feat/tray-theme). - Make your change; keep diffs focused and match the existing style (file-scoped namespaces, nullable enabled, services single-purpose).
- Build and run the full test suite — CI (
.github/workflows/build.yml) runs the same restore/build/test flow on Windows for every push and pull request tomain. - Open a PR describing what changed and why; link any related issue. This project follows a conventional commit style (
feat:,fix:,docs:,test:).
git clone https://github.com/torpidno/OrbitOCR.git
cd OrbitOCR
dotnet build # compile
dotnet run # launch on the development desktop
dotnet test tests/OrbitOCR.Tests.csproj- Windows 10 2004+ / Windows 11 with the .NET 8 SDK is required; WPF projects cannot be built on Linux/macOS.
- Visual Studio 2022 (workload .NET desktop development) or VS Code with the C# Dev Kit both work out of the box — no solution file is needed.
- The UI smoke tests and OCR integration tests need an interactive desktop session; run them locally, not in a headless agent.
- New dependencies should be justified — the app project deliberately ships with a single NuGet dependency (
System.Drawing.Common).
OrbitOCR is released under the MIT License — free for personal and commercial use, with attribution. See LICENSE for the full text.
- Google Pixel's "Circle to Search" — the interaction model that inspired this project.
- Microsoft Windows OCR (
Windows.Media.Ocr) — the on-device recognition engine that makes offline text extraction possible. - Google Lens — the visual search destination for circled regions.
- Microsoft Fluent Design — the dark design language and accent palette used across the overlay and settings.
- MSTest, Microsoft.NET.Test.Sdk, and coverlet — the testing stack.
- Everyone who reports bugs, suggests features, and sends pull requests.
