OCR-powered screen text search overlay for Windows — Ctrl+Alt+F to find any visible text on screen
C#
1
20 commits
updated Oct 4, 2026
Press Ctrl+Alt+F, search any text visible on screen with OCR, click to copy. Like Ctrl+F for the whole screen — and one click on 文A translates everything on screen, in place, in any app.
Press Ctrl+Alt+G on any selected text to send it to ChatGPT with one of your saved prompts — see Prompt Builder.
Ctrl+Alt+F | Open overlay (global hotkey) |
Ctrl+Alt+G | Prompt Builder: send the selected text to ChatGPT with a saved prompt (global hotkey, see Prompt Builder) |
| Type | Highlight matching text |
| Click match | Copy word to clipboard |
文A button | Translate the whole screen (click again to go back to search) |
Left-click (translate mode) | Close overlay, back to the app |
| Hover a translation | Show the text the OCR read |
Mouse wheel | Scroll the app underneath; overlay re-captures (and re-translates) when you stop |
Escape / Right-click | Close overlay |
↑ / ↓ | Search history |
Enter | Save current search to history |
| Drag search bar | Move it (position persisted) |
Right-click inside the search box itself still opens the native paste menu.
Windows.Media.Ocr, multi-language (pick from tray icon, choice persisted)文A covers every line of text with its translation, painted on the line's own background color. Works on any app: games, chat apps, software that was never localized. See Screen translation..* buttonCtrl+Alt+G, pick a saved prompt, send to ChatGPT (screenshot optional). See Prompt Builder.Built first for Japanese software; works for any language Windows OCR can read.
translateTarget in settings.json to any Google Translate code (en, es, de…).Translation uses the free, keyless Google Translate endpoint (translate.googleapis.com, the one behind the Chrome extension). It is unofficial and may be throttled. The text visible on screen is sent to Google when you click 文A — nothing leaves your machine while you only search.
Windows only reads the languages whose OCR pack is installed, usually just your system language. The tray menu OCR Languages lists them. Without the Japanese pack, Japanese text comes out as garbage (a Chinese pack turns kana into look-alike symbols) and so does the translation.
To add Japanese:
Or from an admin PowerShell:
Add-WindowsCapability -Online -Name "Language.Basic~~~ja-JP~0.0.1.0"
Add-WindowsCapability -Online -Name "Language.OCR~~~ja-JP~0.0.1.0"
On Windows 10, the "Optional features" page does not list OCR packs — use one of the two ways above.
Select text anywhere — a web page, a PDF, a chat, any app — press Ctrl+Alt+G, pick a prompt, send it to ChatGPT. Your prompts are saved, searchable and color-coded, so "fix this", "translate that", "explain this error" are one keystroke away.
Ctrl+C sent to the active app) and captures the screen under the cursor. Both stay in the clipboard: Win+V lists the screenshot right above the text.Fix this text:) reads naturally. Tick Attach screenshot to send the screen capture with it (hover the thumbnail to preview it, click it to toggle). The footer shows the total ChatGPT will receive, e.g. Total: 226 characters + screenshot.| Type in the search box | Filter prompts by name or content (accents and case ignored) |
↑ / ↓ | Pick a prompt (from the search box) |
Enter | Send (from the search box or the list) |
Ctrl+Enter | Send (from anywhere) |
Ctrl+1 … Ctrl+9 | Pick the n-th visible prompt (numbers shown in the list) |
Ctrl+N / Ctrl+D | New prompt / duplicate the selected one |
Alt+↑ / Alt+↓ | Move the selected prompt up / down |
Delete (in the list) | Delete, with Undo in the footer for a few seconds |
Ctrl+F | Search |
Ctrl+wheel in a text box | Text size |
| Double-click a prompt | Send with it |
Escape | Clear the search, then close |
Right-click a prompt for the same actions.
prompts.json.⚙ in the title bar:
Loc.cs.Ctrl+wheel).Hover the tray icon to see both hotkeys.
The window shows ~60 ms after the hotkey once something is selected (~300 ms more with nothing selected: the time given to the app to answer Ctrl+C).
Ctrl+C runs; its thumbnail, its PNG and its clipboard copy are all produced off the UI thread, after the window is up.AllowsTransparency), so resizing stays on the GPU. Everything is square, Windows 11 corners included.Ctrl+Alt+G preheats ChatGPT: a blank temporary chat loads in the background while you pick a prompt, so Send usually only has to type. The ChatGPT window's status strip shows how long the send took. If that window was open on a previous answer, the answer is replaced by the new blank chat.A WebView2 created on the first Ctrl+Alt+G, then hidden — never closed. It runs logged out, in a temporary chat (nothing is kept in any history), in a profile of its own (ScreenSearchOverlay.WebView2/); the cookie banner is refused automatically. Links in answers open in your browser.
Everything the app knows about chatgpt.com — selectors and injected scripts — lives in ChatGptPage.cs: when OpenAI changes its page, that is the file to fix. F12 in the ChatGPT window opens the DevTools. If sending fails, the status strip says at which step.
The text (and the screenshot, when ticked) is sent to OpenAI when you click Send. Nothing leaves your machine before.
Ctrl+C goes to whatever app is active. In a terminal with nothing selected, that interrupts the running command.
Download ScreenSearchOverlay.exe from the latest release. Self-contained, portable.
.\build.ps1 -Run # build + launch
.\build.ps1 # build to dist/
.\build.ps1 -Release # build + GitHub release
Version lives in package.json only — the .csproj and build.ps1 both read it from there.
To enable diagnostic logging at %TEMP%\ls-ocrlayout-scroll.log, add <DefineConstants>LS_DEBUG_LOG</DefineConstants> to the csproj. Off by default — [Conditional] strips the calls completely in release.
MainWindow is split into partial files by concern:
| File | Responsibility |
|---|---|
MainWindow.xaml.cs | ctor, lifecycle, fields, log |
MainWindow.Scroll.cs | scroll state machine + global hook handler |
MainWindow.Capture.cs | screen capture, WriteableBitmap swap, OCR pipeline + cache |
MainWindow.Search.cs | search box, regex, hamburger menu, highlights |
MainWindow.SearchBar.cs | drag, position, size, key nav, close handlers |
MainWindow.Translate.cs | translate mode: batch request, background sampling, font fitting, click-to-close |
MainWindow.NativeInterop.cs | Win32 P/Invoke + helpers (SetClickThrough, InjectMouseWheel, …) |
OcrLineBuilder.cs | OCR results → translation lines (engine arbitration, CJK joining, split-line repair) — no UI dependency |
Translator.cs | ITranslator, Google implementation (batching, cache), TranslationFilter |
LowLevelMouseHook.cs | WH_MOUSE_LL on a dedicated thread (per MSDN guidance — UI-thread hooks risk silent detachment past LowLevelHooksTimeout) |
App.xaml.cs | global hotkey, tray icon, settings/history persistence |
App.Prompt.cs | Prompt Builder: Ctrl+Alt+G, selection + screenshot capture, prompt/chat window lifetime, its settings |
PromptWindow.xaml(.cs) | prompt list and editor, keyboard navigation, delete/undo; built at idle, hidden on close and reused |
ChatWindow.xaml(.cs) | ChatGPT in a WebView2: preheated on every Ctrl+Alt+G, hidden on close, send status strip with timing |
ChatGptPage.cs | chatgpt.com selectors + injected scripts — no UI dependency |
PromptLibrary.cs | SavedPrompt, prompts.json, message composition — no UI dependency |
Loc.cs | UI languages and strings (Prompt Builder, ChatGPT window, tray), published as live resources |
SelectionGrabber.cs | simulated Ctrl+C (the hotkey's modifiers released on the app's side), clipboard access |
ScreenCapture.cs | screenshot pipeline off the UI thread: capture, thumbnails, PNG, full-resolution clipboard copy |
State machine Idle ↔ Scrolling. On the first wheel, the window goes WS_EX_TRANSPARENT (click-through Win32) and injects the wheel via SendInput so it lands on the app below. Subsequent wheels go natively to that app — Chromium-friendly because we never use synthetic WM_MOUSEWHEEL. A WH_MOUSE_LL hook on a dedicated thread keeps the debounce alive while we don't receive any events. After 400 ms of wheel silence: re-capture, refresh OCR, restore the overlay.
OcrLineBuilder keeps one reading per line position. Latin engines go first, and a CJK engine only takes over where its reading is mostly CJK — kana beat kanji-only readings, so the Japanese engine wins over the Chinese one. CJK characters are glued back together (the engines space every character), lines the OCR cut in two are re-joined, and two frequent Japanese-engine misreads are repaired (G。d。t → Godot, ヒ。ッ → ピッ).translate_a/t with repeated q parameters, which returns [translation, detectedLanguage] per item, in order. Index i in = index i out: each translation maps straight back to its screen rectangle, no markers needed. (translate_a/single detects one language for the whole payload and leaves the minority language untranslated on mixed screens.)settings.json — zen mode, highlight size, search bar size & position, translation target language, unchecked OCR languages, UI language, Prompt Builder window sizes, splitters and text size, last prompt, screenshot checkboxsearch-history.json — last 50 searchesprompts.json — saved prompts with their title color (indented, hand-editable; an unreadable file is set aside as prompts.json.bak, never overwritten)ScreenSearchOverlay.WebView2/ — the ChatGPT window's browser profile (created on the first send)All of them live next to the .exe.
Windows 10 build 19041+ or Windows 11. At least one OCR language pack (your system language is usually pre-installed). Translation needs an internet connection; translating from Japanese needs the Japanese OCR pack (see above). The Prompt Builder needs the Microsoft Edge WebView2 Runtime, preinstalled on Windows 11 and on up-to-date Windows 10.
C#
98.2%
PowerShell
1.8%
OCR-powered screen text search overlay for Windows — Ctrl+Alt+F to find any visible text on screen
C#
1
20 commits
updated Oct 4, 2026
Press Ctrl+Alt+F, search any text visible on screen with OCR, click to copy. Like Ctrl+F for the whole screen — and one click on 文A translates everything on screen, in place, in any app.
Press Ctrl+Alt+G on any selected text to send it to ChatGPT with one of your saved prompts — see Prompt Builder.
Ctrl+Alt+F | Open overlay (global hotkey) |
Ctrl+Alt+G | Prompt Builder: send the selected text to ChatGPT with a saved prompt (global hotkey, see Prompt Builder) |
| Type | Highlight matching text |
| Click match | Copy word to clipboard |
文A button | Translate the whole screen (click again to go back to search) |
Left-click (translate mode) | Close overlay, back to the app |
| Hover a translation | Show the text the OCR read |
Mouse wheel | Scroll the app underneath; overlay re-captures (and re-translates) when you stop |
Escape / Right-click | Close overlay |
↑ / ↓ | Search history |
Enter | Save current search to history |
| Drag search bar | Move it (position persisted) |
Right-click inside the search box itself still opens the native paste menu.
Windows.Media.Ocr, multi-language (pick from tray icon, choice persisted)文A covers every line of text with its translation, painted on the line's own background color. Works on any app: games, chat apps, software that was never localized. See Screen translation..* buttonCtrl+Alt+G, pick a saved prompt, send to ChatGPT (screenshot optional). See Prompt Builder.Built first for Japanese software; works for any language Windows OCR can read.
translateTarget in settings.json to any Google Translate code (en, es, de…).Translation uses the free, keyless Google Translate endpoint (translate.googleapis.com, the one behind the Chrome extension). It is unofficial and may be throttled. The text visible on screen is sent to Google when you click 文A — nothing leaves your machine while you only search.
Windows only reads the languages whose OCR pack is installed, usually just your system language. The tray menu OCR Languages lists them. Without the Japanese pack, Japanese text comes out as garbage (a Chinese pack turns kana into look-alike symbols) and so does the translation.
To add Japanese:
Or from an admin PowerShell:
Add-WindowsCapability -Online -Name "Language.Basic~~~ja-JP~0.0.1.0"
Add-WindowsCapability -Online -Name "Language.OCR~~~ja-JP~0.0.1.0"
On Windows 10, the "Optional features" page does not list OCR packs — use one of the two ways above.
Select text anywhere — a web page, a PDF, a chat, any app — press Ctrl+Alt+G, pick a prompt, send it to ChatGPT. Your prompts are saved, searchable and color-coded, so "fix this", "translate that", "explain this error" are one keystroke away.
Ctrl+C sent to the active app) and captures the screen under the cursor. Both stay in the clipboard: Win+V lists the screenshot right above the text.Fix this text:) reads naturally. Tick Attach screenshot to send the screen capture with it (hover the thumbnail to preview it, click it to toggle). The footer shows the total ChatGPT will receive, e.g. Total: 226 characters + screenshot.| Type in the search box | Filter prompts by name or content (accents and case ignored) |
↑ / ↓ | Pick a prompt (from the search box) |
Enter | Send (from the search box or the list) |
Ctrl+Enter | Send (from anywhere) |
Ctrl+1 … Ctrl+9 | Pick the n-th visible prompt (numbers shown in the list) |
Ctrl+N / Ctrl+D | New prompt / duplicate the selected one |
Alt+↑ / Alt+↓ | Move the selected prompt up / down |
Delete (in the list) | Delete, with Undo in the footer for a few seconds |
Ctrl+F | Search |
Ctrl+wheel in a text box | Text size |
| Double-click a prompt | Send with it |
Escape | Clear the search, then close |
Right-click a prompt for the same actions.
prompts.json.⚙ in the title bar:
Loc.cs.Ctrl+wheel).Hover the tray icon to see both hotkeys.
The window shows ~60 ms after the hotkey once something is selected (~300 ms more with nothing selected: the time given to the app to answer Ctrl+C).
Ctrl+C runs; its thumbnail, its PNG and its clipboard copy are all produced off the UI thread, after the window is up.AllowsTransparency), so resizing stays on the GPU. Everything is square, Windows 11 corners included.Ctrl+Alt+G preheats ChatGPT: a blank temporary chat loads in the background while you pick a prompt, so Send usually only has to type. The ChatGPT window's status strip shows how long the send took. If that window was open on a previous answer, the answer is replaced by the new blank chat.A WebView2 created on the first Ctrl+Alt+G, then hidden — never closed. It runs logged out, in a temporary chat (nothing is kept in any history), in a profile of its own (ScreenSearchOverlay.WebView2/); the cookie banner is refused automatically. Links in answers open in your browser.
Everything the app knows about chatgpt.com — selectors and injected scripts — lives in ChatGptPage.cs: when OpenAI changes its page, that is the file to fix. F12 in the ChatGPT window opens the DevTools. If sending fails, the status strip says at which step.
The text (and the screenshot, when ticked) is sent to OpenAI when you click Send. Nothing leaves your machine before.
Ctrl+C goes to whatever app is active. In a terminal with nothing selected, that interrupts the running command.
Download ScreenSearchOverlay.exe from the latest release. Self-contained, portable.
.\build.ps1 -Run # build + launch
.\build.ps1 # build to dist/
.\build.ps1 -Release # build + GitHub release
Version lives in package.json only — the .csproj and build.ps1 both read it from there.
To enable diagnostic logging at %TEMP%\ls-ocrlayout-scroll.log, add <DefineConstants>LS_DEBUG_LOG</DefineConstants> to the csproj. Off by default — [Conditional] strips the calls completely in release.
MainWindow is split into partial files by concern:
| File | Responsibility |
|---|---|
MainWindow.xaml.cs | ctor, lifecycle, fields, log |
MainWindow.Scroll.cs | scroll state machine + global hook handler |
MainWindow.Capture.cs | screen capture, WriteableBitmap swap, OCR pipeline + cache |
MainWindow.Search.cs | search box, regex, hamburger menu, highlights |
MainWindow.SearchBar.cs | drag, position, size, key nav, close handlers |
MainWindow.Translate.cs | translate mode: batch request, background sampling, font fitting, click-to-close |
MainWindow.NativeInterop.cs | Win32 P/Invoke + helpers (SetClickThrough, InjectMouseWheel, …) |
OcrLineBuilder.cs | OCR results → translation lines (engine arbitration, CJK joining, split-line repair) — no UI dependency |
Translator.cs | ITranslator, Google implementation (batching, cache), TranslationFilter |
LowLevelMouseHook.cs | WH_MOUSE_LL on a dedicated thread (per MSDN guidance — UI-thread hooks risk silent detachment past LowLevelHooksTimeout) |
App.xaml.cs | global hotkey, tray icon, settings/history persistence |
App.Prompt.cs | Prompt Builder: Ctrl+Alt+G, selection + screenshot capture, prompt/chat window lifetime, its settings |
PromptWindow.xaml(.cs) | prompt list and editor, keyboard navigation, delete/undo; built at idle, hidden on close and reused |
ChatWindow.xaml(.cs) | ChatGPT in a WebView2: preheated on every Ctrl+Alt+G, hidden on close, send status strip with timing |
ChatGptPage.cs | chatgpt.com selectors + injected scripts — no UI dependency |
PromptLibrary.cs | SavedPrompt, prompts.json, message composition — no UI dependency |
Loc.cs | UI languages and strings (Prompt Builder, ChatGPT window, tray), published as live resources |
SelectionGrabber.cs | simulated Ctrl+C (the hotkey's modifiers released on the app's side), clipboard access |
ScreenCapture.cs | screenshot pipeline off the UI thread: capture, thumbnails, PNG, full-resolution clipboard copy |
State machine Idle ↔ Scrolling. On the first wheel, the window goes WS_EX_TRANSPARENT (click-through Win32) and injects the wheel via SendInput so it lands on the app below. Subsequent wheels go natively to that app — Chromium-friendly because we never use synthetic WM_MOUSEWHEEL. A WH_MOUSE_LL hook on a dedicated thread keeps the debounce alive while we don't receive any events. After 400 ms of wheel silence: re-capture, refresh OCR, restore the overlay.
OcrLineBuilder keeps one reading per line position. Latin engines go first, and a CJK engine only takes over where its reading is mostly CJK — kana beat kanji-only readings, so the Japanese engine wins over the Chinese one. CJK characters are glued back together (the engines space every character), lines the OCR cut in two are re-joined, and two frequent Japanese-engine misreads are repaired (G。d。t → Godot, ヒ。ッ → ピッ).translate_a/t with repeated q parameters, which returns [translation, detectedLanguage] per item, in order. Index i in = index i out: each translation maps straight back to its screen rectangle, no markers needed. (translate_a/single detects one language for the whole payload and leaves the minority language untranslated on mixed screens.)settings.json — zen mode, highlight size, search bar size & position, translation target language, unchecked OCR languages, UI language, Prompt Builder window sizes, splitters and text size, last prompt, screenshot checkboxsearch-history.json — last 50 searchesprompts.json — saved prompts with their title color (indented, hand-editable; an unreadable file is set aside as prompts.json.bak, never overwritten)ScreenSearchOverlay.WebView2/ — the ChatGPT window's browser profile (created on the first send)All of them live next to the .exe.
Windows 10 build 19041+ or Windows 11. At least one OCR language pack (your system language is usually pre-installed). Translation needs an internet connection; translating from Japanese needs the Japanese OCR pack (see above). The Prompt Builder needs the Microsoft Edge WebView2 Runtime, preinstalled on Windows 11 and on up-to-date Windows 10.
C#
98.2%
PowerShell
1.8%