451 lines
34 KiB
Markdown
451 lines
34 KiB
Markdown
# KSwitcher
|
||
|
||
Native C++20 / Win32 rewrite of the Windows functionality of [Typlo](https://github.com/bitcodepro/Typlo). Windows 10/11 x64.
|
||
No .NET, Avalonia, WebView, Qt, external graphics engine, or separately installed C++ runtime.
|
||
The original [Typlo](https://github.com/bitcodepro/Typlo) project and its data remain separate.
|
||
|
||
**[User guide / Wiki](https://gitea.hrynco.com/hrynco/hrynco-kswitcher/wiki)** — setup, features, shortcuts, dictionaries, screenshots and troubleshooting in **English** and **[Українська](https://gitea.hrynco.com/hrynco/hrynco-kswitcher/wiki/Home-uk)**. Each wiki page links to its translation.
|
||
|
||
[](https://send.monobank.ua/jar/88h2TddKfS)
|
||
|
||
[Donate via Monobank](https://send.monobank.ua/jar/88h2TddKfS) · Thank you for supporting KSwitcher.
|
||
|
||
## Run
|
||
|
||
Run `build/KSwitcher.exe`, or extract `dist/KSwitcher-win-x64.zip` and run the executable.
|
||
The build also refreshes the release copy in `build/release/`. Exit KSwitcher before rebuilding.
|
||
The application lives in the notification area. Right-click its icon for Settings, Snippets and history.
|
||
Double-click the tray icon to open Settings, the bold default menu item.
|
||
Settings and the snippet editor run on demand in **KSwitcher.Config.exe**, beside the main executable.
|
||
Repeated launches activate the existing configurator; closing its last window exits that process.
|
||
Saving applies changes immediately through the resident KSwitcher process. The configurator does not
|
||
load clipboard history, dictionaries or global input hooks. Clipboard history and the log viewer remain
|
||
in the resident app. Screen capture and all screenshot editors run on demand in
|
||
**KSwitcher.Screenshot.exe**. The capture hotkey starts it; subsequent captures reuse the same
|
||
process. Closing the last editor (or cancelling the only selection) exits that process. It does not
|
||
load resident settings, dictionaries, clipboard history or keyboard hooks. Editor windows have
|
||
stable numbered titles within that process. Keep all three executables together when copying or
|
||
updating the application. Close screenshot editors before installing an update.
|
||
If settings change in the tray while the configurator is open, a conflicting Save is rejected; reopen
|
||
the configurator to load the latest settings.
|
||
Updates from v0.3.x–v0.4.1 first install the compatible **v0.4.2 bridge** through
|
||
Update in the tray menu. Select Update again to install the full current release;
|
||
manual extraction is not required. Future full releases use stable `release-vX.Y.Z`
|
||
tags, which the bridge and newer clients recognize. Older clients ignore those tags
|
||
and continue to find the bridge instead of skipping it. Versions v0.2.3 and earlier
|
||
still require the previously documented initial configurator migration.
|
||
|
||
Modern ZIPs contain `release-files.json` (schema, version, file paths, sizes and SHA-256
|
||
hashes). The updater validates that every packaged file is declared, all hashes match,
|
||
and paths stay within the installation directory. `data/` is protected; existing
|
||
dictionaries are preserved. Adding a new program file no longer needs a new updater.
|
||
In Settings, enable **Start with Windows** and **Start with Windows as administrator**
|
||
to use a per-user Task Scheduler logon task with highest privileges. Enabling or changing
|
||
the elevated task requests UAC approval if the app is not already elevated. No password is stored;
|
||
the task runs in the signed-in user's interactive session, including on battery power.
|
||
Disabling the administrator option restores ordinary per-user startup; disabling startup stops
|
||
future automatic launches. Saving unrelated settings does not recreate startup entries.
|
||
`KSwitcher.exe --settings` opens Settings, including when the app is already running.
|
||
Exit [Typlo](https://github.com/bitcodepro/Typlo) when using overlapping shortcuts to avoid competing keyboard hooks.
|
||
|
||
### Change a shortcut
|
||
|
||
1. Open **Settings** and click a shortcut field.
|
||
2. Press the desired combination. The field records the actual keys; no typing of names is needed.
|
||
3. Click **Save**. Duplicate shortcuts within KSwitcher and protected Windows combinations are reported.
|
||
|
||
This also works for each layout's **Direct layout shortcut**. Backspace or Delete without modifiers
|
||
clears a shortcut. Tab moves to the next field. The recorded shortcut is suppressed while the field
|
||
has focus, so recording the conversion shortcut does not perform a conversion.
|
||
All configured shortcuts use the existing keyboard hook and can replace ordinary Windows/app
|
||
shortcuts, including **Win+V** and **Win+Shift+S**, while KSwitcher is running. Only exact configured
|
||
combinations are intercepted. Unassigned shortcuts and simulated copy/paste pass through.
|
||
Choose another shortcut or exit KSwitcher to restore the original action. Windows protects
|
||
Ctrl+Alt+Delete and Win+L; these cannot be assigned.
|
||
|
||
Keyboard and mouse input forwarded by Microsoft Mouse Without Borders follows the same input
|
||
path as a local keyboard/mouse, including shortcuts, recent-word conversion and snippets.
|
||
KSwitcher marks its own generated input so copy/paste, selection, modifier releases and shell-mask
|
||
keys cannot trigger recursive commands or overwrite the recorded typing run. Other injected input
|
||
is accepted, including key-up events and VK-only keyboard events. Unicode packets do not provide
|
||
physical key positions and therefore reset recent-word tracking; selection conversion still works.
|
||
|
||
### Screen capture and annotations
|
||
|
||
Press **Win+Shift+S**, choose **Capture screen region…** in the tray menu, or run
|
||
`KSwitcher.exe --capture`. Drag a rectangle on the dimmed, frozen desktop; the selected area stays
|
||
at normal brightness. Escape cancels. Selection and annotation frames are buffered to avoid flicker.
|
||
The selected area is copied immediately, the fullscreen selection is hidden, and a Windows notification
|
||
is sent. Click the notification to open the editor. Enable **Open editor after screen capture** in settings
|
||
to open it automatically; this option is off by default. An immediate notification error still opens the editor.
|
||
Existing saved preferences are preserved. Windows Do Not Disturb can send notifications directly to the
|
||
notification center without showing a banner.
|
||
The preference applies to each new capture, including while other editors are open.
|
||
KSwitcher also sends a notification with a thumbnail. Notification identity and activation are registered
|
||
at resident startup and refreshed before sending; registration/submission errors are written to the log.
|
||
Click the notification to reopen the original screenshot, including after the screenshot process has exited.
|
||
Originals in the local notification cache are DPAPI-encrypted. Thumbnail PNGs live in a separate
|
||
per-user cache under ProgramData, readable only by that user and SYSTEM, so the Windows notification
|
||
broker can load them even when the profile directory is inaccessible to it.
|
||
Notifications expire after 24 hours. Cache cleanup runs on capture/open; each cache is bounded to
|
||
40 files and 256 MiB. Expired or evicted notifications cannot reopen their screenshot.
|
||
In the editor, **Ctrl+C** or **Enter** copies the current result without closing the window.
|
||
The editor starts with **Pencil / Freehand (F)** for drawing. Choose **Pointer (V)** to select objects, move them, and edit geometry, thickness and
|
||
other properties using handles and controls. Clicking empty space clears selection; dragging empty
|
||
space adds nothing. Choose a drawing tool to create objects, then return to **V** to edit them.
|
||
The cursor identifies the active tool: pointer, text caret, pencil, or a crosshair with the drawing
|
||
tool symbol. Move/resize/thickness/rotation handles override it with their action cursor. Custom
|
||
cursors scale with display DPI and use a contrasting outline for light and dark images.
|
||
To annotate: **N** places sequential numbered red markers with a click, and **A** draws
|
||
red arrows by dragging from the tail to the tip. With **Pointer (V)**, click an existing marker or arrow to select it;
|
||
drag its body to move it. Drag the square handle on a number's right edge to change its diameter
|
||
(the text scales with it), or either endpoint handle of an arrow to change its length and direction.
|
||
Select an arrow and drag the extra handle beside its midpoint perpendicular to the line to change
|
||
its thickness from 1 to 30 pixels. The arrowhead scales with the line. Minus/plus keys also work.
|
||
Alternatively, scroll the mouse wheel over an arrow to change its thickness, or over a number to
|
||
change its diameter. Wheel up increases the size; wheel down decreases it. These edits support Undo
|
||
and update linked arrows. **Ctrl+D** clones the selected object with a small offset. A cloned number
|
||
gets the smallest available positive number, just like a newly placed number: gaps left by deletion
|
||
are filled first, without renumbering existing objects. A cloned arrow keeps its style but starts without endpoint links.
|
||
Arrow and line endpoints can attach to numbered markers, rectangles, circles, ellipses, text blocks,
|
||
and other arrows or strokes. In Arrow or Straight line mode, hold **Ctrl** and drag from one object
|
||
to another to draw over them and automatically attach both endpoints. Without Ctrl, existing objects
|
||
can still be selected and edited as before. With Pointer, drag an existing endpoint onto a target to attach it. Attached endpoints follow movement and resizing; text attachments
|
||
also follow rotation. Arrow-to-arrow attachments retain their relative position along the target line.
|
||
Clicking a connector or adding/editing its caption preserves its links. Moving the whole connector
|
||
intentionally detaches its endpoints; moving one endpoint detaches only that end. Deleting a target
|
||
leaves connected endpoints at their last position. Self-links and circular dependency chains are rejected.
|
||
The compact toolbar uses [Lucide](https://lucide.dev) icons with hover tooltips showing each action
|
||
and its keyboard shortcut.
|
||
Drop either arrow endpoint onto a number to link it to the circle's edge. Linked endpoints follow
|
||
the number when it moves or changes diameter. Drag an endpoint away to unlink it; moving the whole
|
||
arrow unlinks both ends. In Arrow mode, hold **Ctrl** while dragging to start a new arrow directly
|
||
from a number. Deleting a number leaves its arrows in place and removes their links; Undo restores them.
|
||
**Delete** removes the selected object. **Ctrl+Z** (Undo) reverses additions, moves, resizes and deletions
|
||
(up to 100 actions). **Ctrl+Y** or **Ctrl+Shift+Z** (Redo) restores undone edits; a new edit clears the
|
||
redo history. Undo and Redo buttons are disabled when unavailable. Enabled toolbar buttons use a
|
||
hand cursor. Selection handles are visible only in the editor, never in the copied image.
|
||
The **palette** changes the selected object's color: arrow, numbered marker, or highlight.
|
||
It also sets the color for newly drawn objects of every type. With nothing selected, only the
|
||
color for new objects changes. Number text switches between dark and white for readability.
|
||
**Highlight (H)** paints a translucent freehand marker stroke. Dark text remains readable beneath
|
||
the highlight. Drag a selected stroke
|
||
to move it, scroll over it to change width (4–100 pixels), or use Delete / Ctrl+D / Undo / Redo.
|
||
Hold Ctrl while drawing to paint a new stroke over an existing object. Highlights render beneath
|
||
arrows and numbered markers. The palette's color indicator reflects the selected object, or the
|
||
color for new objects when nothing is selected.
|
||
The editor status bar shows contextual tool, selection, rotation and text-editing hints.
|
||
Hover a toolbar button to see its action and shortcut; the title stays **KSwitcher — Screenshot**.
|
||
**Text (T)** adds text directly on the image. Enter inserts a line break; Ctrl+Enter or a click
|
||
outside commits the edit, and Escape cancels it. Double-click text or press F2 to edit it again.
|
||
The **Aa** icon opens the standard font dialog for family, size (6–200 pt), bold and italic.
|
||
The mouse wheel over text adjusts its font size. Text supports color, dragging, Ctrl+D,
|
||
Delete and Undo/Redo. Arrow keys move the selected object by one source-image pixel;
|
||
selecting an arrow caption moves only that caption. Repositioning a caption preserves its
|
||
automatic angle; only dragging the rotation handle switches to a fixed angle.
|
||
New standalone text starts horizontally, even after editing an angled arrow caption. Font styling
|
||
is reused; rotation belongs to each individual object.
|
||
Text has a rotation handle above its selection. Drag to rotate; hold Shift to snap to 15-degree steps.
|
||
Double-click an arrow, press F2, or use the label icon to add/edit its caption. Captions follow
|
||
the arrow when moved or resized; drag the caption to adjust its offset. By default, the caption
|
||
angle follows the line (or middle curve segment) and stays upright. Rotating its handle manually
|
||
fixes its angle; Shift snaps to 15-degree steps. Undo restores automatic mode. The Aa icon changes
|
||
the selected caption font, and the mouse wheel over it changes its size. Captions and rotation
|
||
are included in clipboard export, cloning and Undo/Redo.
|
||
**Straight line (L)** creates a line without arrowheads. **Rectangle (R)**, **Circle (O)** and
|
||
**Ellipse (E)** create transparent shapes with colored outlines. Drag the two corner handles to
|
||
resize; circles keep equal width and height. Move shapes by their outlines, adjust thickness with
|
||
the mouse wheel or side handle, recolor, clone with Ctrl+D, and undo/redo as with other objects.
|
||
Hold Ctrl to start drawing over an existing object. Line style applies to outlines; Ends is disabled
|
||
for shapes.
|
||
**Freehand line (F)** draws an opaque curve by following the mouse. The curve is one object:
|
||
move it, change its color or thickness, clone it, or drag its endpoints. Hold Ctrl to start a new
|
||
stroke over an existing object. The **Line style** selector supports Solid, Dotted, Dashed and
|
||
Dash-dot; **Ends** supports an arrow at the end, start, both ends, or no arrows. These settings
|
||
apply to selected straight/freehand lines and set defaults for subsequent lines. Both are disabled
|
||
for numbered markers and highlights unless a line drawing tool is active. Undo/Redo includes style changes.
|
||
The window close button asks for confirmation before discarding an uncopied screenshot.
|
||
**Escape** cancels region selection or inline text edits; it does not close the editor. Copy keeps the editor open and publishes the image
|
||
at its original pixel size, ready to paste. The preview fits the window without changing export size.
|
||
The shortcut is configurable in Settings under **Screen capture**.
|
||
Each capture opens an independent editor available through Alt+Tab; use the shortcut again to take another screenshot while
|
||
keeping earlier editors and their annotations open.
|
||
Captures use ordinary clipboard history settings and limits. Protected video and secure desktops cannot be captured.
|
||
|
||
### Updates
|
||
|
||
Select **Update** in the tray menu to check the stable Releases of
|
||
[this repository](https://gitea.hrynco.com/hrynco/hrynco-kswitcher/releases).
|
||
A background check runs shortly after startup and every 6 hours while KSwitcher is running.
|
||
It reports each available version once per session and never installs automatically.
|
||
Update availability uses the same Windows toast notification channel as screenshot notifications.
|
||
Click the notification or **Review update** to check the latest release and confirm installation;
|
||
**Later** dismisses it. Windows Do Not Disturb may send it directly to Notification Center.
|
||
Failed notification submissions are logged and retried after five minutes instead of being marked
|
||
as delivered. Check results and successful submissions are recorded in the log when logging is enabled.
|
||
Network failures stay in diagnostics; the next scheduled check retries. You can also check manually at any time.
|
||
Confirm the offered version to download and install it. A progress window shows
|
||
download percentage and received/total size, package verification,
|
||
installation and restart. After the new process confirms startup, that window shows the installed
|
||
version and a Done button; it does not send a separate completion notification. If installation
|
||
fails after KSwitcher closes, the same window shows recovery and the error. Background checks
|
||
remain silent unless a new version is available. This progress UI is supplied by the updater in
|
||
the currently installed build, so it becomes available for subsequent updates after installing it.
|
||
|
||
The updater uses the existing
|
||
`KSwitcher-win-x64.zip` and `SHA256SUMS.txt` assets, checks the checksum, package contents, x64
|
||
executable identity and version, then closes and restarts KSwitcher. Downloads and staging happen
|
||
before the application exits. If replacement or startup fails, it restores the previous files;
|
||
if recovery itself fails, it reports the retained backup directory.
|
||
|
||
Saved settings and clipboard history in `data/` or the local-app-data fallback are preserved.
|
||
Existing dictionary files are preserved too; missing dictionary files are installed. Save settings
|
||
edits before updating. The installation directory must be writable at KSwitcher's current privilege
|
||
level. A blocked network request, incomplete release or checksum mismatch leaves the running version
|
||
intact and is reported when Update is selected. Startup network failures remain non-interactive.
|
||
The helper uses Windows' built-in Windows PowerShell 5.1; no additional runtime is installed.
|
||
|
||
Settings and the other utility windows use the destination monitor's DPI for their initial frame,
|
||
controls and fonts. Settings has a fixed form size, without manual resizing or maximization; other
|
||
utility windows remain resizable. Windows stay within a remaining monitor's work area after display
|
||
changes and provide scrollbars when their content does not fit. Tab navigation scrolls the focused
|
||
field into view; Shift+wheel scrolls horizontally.
|
||
Clipboard history also updates its preview row heights when DPI changes, keeping text,
|
||
thumbnails and source labels aligned with the scaled fonts and spacing.
|
||
|
||
## Implemented
|
||
|
||
- Installed Windows keyboard layouts, configurable cycle/order and direct shortcuts; IMEs are switch-only.
|
||
- Selection conversion and verified recent input (physical scan codes, 2-second typing-run boundary).
|
||
- Same-process clipboard ownership plus verified WebView2 descendants, including the Teams fix.
|
||
- Teams recent-word conversion uses a single word-selection command and validates the copied range.
|
||
If the editor's word boundary differs from the recorded typing, it falls back to paced character
|
||
selection: Teams can coalesce a burst of Shift+Left events into just one character.
|
||
- Clipboard snapshot/restoration with concurrent-copy, foreground and input-version checks.
|
||
- Case cycling, Russian/Ukrainian transliteration, verified undo and repeated conversion.
|
||
- Text snippets across layouts, multiline insertion and a verified `{cursor}` position;
|
||
`{{cursor}}` inserts the literal marker. Snippets are stored as plaintext settings, as in [Typlo](https://github.com/bitcodepro/Typlo).
|
||
- Clipboard history for text, HTML/RTF, file lists, DIB and PNG images; plain-text paste;
|
||
full-text search, pinning, deletion, full text viewing and image previews.
|
||
- Image thumbnails and text/file icons appear directly in the history list. Only visible rows
|
||
load thumbnails; the 32-entry thumbnail cache is bounded to about 3.3 MiB and released on close.
|
||
- Text rows render RTF and basic clipboard HTML emphasis (bold, italic, underline, strike-through),
|
||
paragraphs, line breaks and list bullets using native Windows RichEdit. Previews are bounded to
|
||
4096 characters / 64 KiB RTF, with at most 32 cached text previews; original paste formats are unchanged.
|
||
HTML is parsed as text, without a browser, scripts or external resources. Complex web layouts and
|
||
stylesheet rules are not reproduced; preview text uses the list's colors for readability.
|
||
- Consecutive screenshot copies are compared by image content, ignoring changing OLE transport
|
||
metadata (including Snipping Tool's repeated clipboard publication).
|
||
- New images are recognized automatically in a separate background worker using native, offline
|
||
Windows OCR. Recognized text is saved in a per-user DPAPI-encrypted sidecar and included in search,
|
||
without changing the image or clipboard. Completed results (including empty text) are reused;
|
||
pending work resumes after restart. Older images without OCR are processed once in the background,
|
||
starting with the newest entries.
|
||
Right-click an image and select **Copy text from image** to copy the saved text or explicitly
|
||
retry recognition. Requires a Windows OCR language installed for the user profile; automatic
|
||
failures are logged quietly. OCR sidecars count toward the history size limit and are removed
|
||
with their images.
|
||
- Optional Tesseract 5 support is available in **Settings → OCR options…**. Windows OCR remains
|
||
the default and has no Tesseract dependency. Install the 64-bit Tesseract 5 Windows package
|
||
separately, then enable it and choose language codes such as `ukr+eng+rus`. Leave the executable
|
||
path blank to detect a standard installation, or select `tesseract.exe`; its neighboring
|
||
`libtesseract-5.dll`, dependencies and `tessdata` language files are required. **Check installation**
|
||
validates the selected models. **Download Tesseract…** opens the Windows installer page in your
|
||
browser. No packages or models are downloaded automatically.
|
||
Tesseract processes screenshots locally in memory with a 30-second recognition deadline.
|
||
Changing engine, executable path or languages refreshes cached image text in the background.
|
||
- History exclusion flags and excluded processes, pause/resume, count/size limits.
|
||
- Per-user Windows DPAPI encryption for both history payloads and the preview index.
|
||
- Autostart, keep-screen-awake, idle-only F15 activity signal, settings import/export.
|
||
- Single instance and `--history`, `--convert`, `--case`, `--transliterate`, `--settings`,
|
||
`--snippets`, `--exit` commands. `--convert` cycles layouts.
|
||
|
||
Default text shortcuts match [Typlo](https://github.com/bitcodepro/Typlo): Ctrl+Alt+Shift+Space (cycle), C (case), T (transliteration),
|
||
Z (undo), and 1/2/3 (first layouts). Clipboard history defaults to **Win+V** for new settings;
|
||
existing saved shortcuts are preserved. While KSwitcher runs, this binding opens its history instead of Windows clipboard history.
|
||
|
||
History controls: Enter to paste, Shift+Enter for plain text, Ctrl+1…9 for quick paste,
|
||
Ctrl+P to pin/unpin, Delete to delete, Ctrl+O for the full item, Escape to hide.
|
||
Pressing the history shortcut a second time pastes the second-most-recent item.
|
||
|
||
## Data and migration
|
||
|
||
Data is in `data/` beside the executable, falling back to `%LOCALAPPDATA%/KSwitcher` when
|
||
the executable's directory is not writable. Each clipboard payload is an encrypted disk file;
|
||
only bounded previews/metadata stay in memory. Image data is loaded on demand and released when
|
||
the history popup is hidden. Settings **Write log** (`writeLog`, enabled by default) controls all
|
||
log writes. Disabling it also clears diagnostic context from memory; existing log files remain.
|
||
Successful operations stay in a memory buffer of at most 40 diagnostic events for 30 seconds.
|
||
Only failures flush this context to `kswitcher.log`; flushed
|
||
context is discarded. Ordinary application errors are also logged when logging is enabled.
|
||
Incident context contains tracked physical input, the expected word, copied text, conversion result,
|
||
and layout IDs, correlated by request ID even when verification fails. Text fields use quoted,
|
||
escaped UTF-16 (`\uXXXX` for non-ASCII and control characters) for exact reproduction, with
|
||
original length and a truncation flag; each field is limited to 512 UTF-16 code units.
|
||
Manual conversion attempts in `kswitcher.log` have request IDs and explicit outcomes, including
|
||
busy, empty copy, verification mismatch, unchanged conversion, and cancelled paste. Requests
|
||
record the process, window, input version, and repeated attempts within ten seconds without new
|
||
input. Successful repeated commands do not flush the log; intentional layout cycling is normal.
|
||
An unchanged result containing no letters, or a direct command
|
||
to the detected current layout, is treated as expected. `paste-sent-unverified` means Windows
|
||
accepted the paste shortcut; it does not prove that the editor applied the replacement.
|
||
The previous 256 KiB log is retained as `kswitcher.log.1` when the current log rotates.
|
||
Open **View log…** from Settings or the tray menu to read logs inside KSwitcher.
|
||
Choose the current or previous log and press **Refresh** to reload. The ListView shows Time,
|
||
Attempt, Event, and Details columns. Select rows and use **Copy selected** or Ctrl+C to copy
|
||
tab-separated entries; Ctrl+A selects all rows. Viewing saved logs also works when logging is disabled.
|
||
**Clear log** clears only the selected current or previous file and refreshes the table.
|
||
Clearing the current log also discards buffered diagnostic context; new problems can still be logged.
|
||
|
||
Settings **Import** accepts a [Typlo](https://github.com/bitcodepro/Typlo) `settings.json`, preserving supported Windows layout IDs,
|
||
hotkeys, snippets, exclusions and limits. Import is staged until Save. Existing [Typlo](https://github.com/bitcodepro/Typlo) files are
|
||
never modified. [Typlo](https://github.com/bitcodepro/Typlo)'s encrypted SQLite history is **not migrated** to the new DPAPI file format.
|
||
DPAPI data belongs to the Windows account/machine; copying the portable folder is not a cross-account backup.
|
||
|
||
## Differences still to port
|
||
|
||
This is a working native implementation, not a claim of complete UI/release parity:
|
||
|
||
- UI currently uses English and the native Windows control appearance. [Typlo](https://github.com/bitcodepro/Typlo)'s ten-language UI and
|
||
explicit light/dark theme selector are not yet ported.
|
||
- No import of old encrypted clipboard history. Export/import applies to settings.
|
||
- The clipboard popup uses per-monitor DPI scaling and scrolls when space is limited; PNG/DIB previews use Windows WIC/GDI.
|
||
|
||
The Windows focus/injection rules still apply: an unelevated process cannot edit an elevated app.
|
||
Conversion is cancelled rather than pasting into a different window or replacing unverified recent text.
|
||
|
||
## Build
|
||
|
||
The easiest reproducible local route uses the pinned portable w64devkit toolchain:
|
||
|
||
```powershell
|
||
.\setup-toolchain.ps1
|
||
.\build.ps1 -Test
|
||
.\package.ps1
|
||
```
|
||
|
||
`setup-toolchain.ps1` downloads the compiler from its upstream GitHub release and verifies SHA-256.
|
||
`.tools/`, build objects, test executables and compiler headers are development-only. **Do not distribute
|
||
the entire source/build folder.** The package contains just the application and notices/documentation.
|
||
The vendored JSON header is nlohmann/json 3.12.0 (MIT); it is compiled into the executable.
|
||
|
||
Alternatively open this directory as a CMake project in Visual Studio with the C++ desktop workload
|
||
and Windows SDK installed, or use CMake with a Windows GCC toolchain. CMake/MSVC is provided but the
|
||
verified local build uses GCC/w64devkit.
|
||
|
||
## Automatic layout correction (experimental)
|
||
|
||
Enable **Automatically correct layout (experimental)** in Settings, then use **Auto-correction
|
||
options…** to select dictionary languages and edit excluded applications or words to never correct.
|
||
The feature is off by default. English and Ukrainian are selected initially; Russian is optional.
|
||
Target layouts must also be enabled in the layout cycle.
|
||
|
||
**Characters before a word** and **Characters after a word** configure punctuation to preserve around
|
||
the corrected word. Enter characters directly, without spaces or separators; a comma or semicolon
|
||
is itself a character. Defaults include parentheses, square/curly brackets, quotation marks and common
|
||
trailing punctuation, including colon and semicolon. Empty fields disable stripping on that side.
|
||
Up to three leading and six trailing characters (including the final space) are supported. Recognition
|
||
still requires a verified complete word; punctuation inside a word is not stripped. Correction runs
|
||
after Space, not immediately after a punctuation key. Save Settings to apply changes.
|
||
|
||
**Frequency rank limit** defaults to **0 (entire dictionary)**. A positive value allows corrections
|
||
only to words with a rank at or below that number (for example, 10000). All dictionary words still
|
||
protect already valid input, and ambiguous alternatives remain unchanged regardless of this limit.
|
||
**My dictionary** provides separate English, Ukrainian and Russian fields for correct words missing
|
||
from the bundled dictionaries. Enter words separated by commas or new lines, then click OK and Save
|
||
in Settings. Case and duplicates are normalized automatically; no file editing or ranks are needed.
|
||
These entries are stored in settings and survive dictionary updates. They protect correct input and
|
||
are eligible as correction targets at any frequency limit. The language and target layout must still
|
||
be enabled. **Never correct these words** is a separate exception list and takes precedence.
|
||
**Open dictionary folder** opens the files beside the running executable. After editing, click OK
|
||
in the options window and Save in Settings to validate and reload the dictionaries without restarting.
|
||
Use UTF-8, one lowercase word followed by a Tab and a positive rank per line. Entries can be appended;
|
||
loading sorts them and merges duplicates using the lowest rank. Back up your edited
|
||
files before replacing dictionaries with a new distribution.
|
||
|
||
After Space and a 250 ms typing pause, KSwitcher checks the last physically typed word against local
|
||
dictionaries. For example, `ghbdsn ` can become `привіт `. Continuing to type before selection cancels
|
||
pending work. During the replacement itself, key presses and releases are queued and replayed after
|
||
clipboard restoration and layout switching, preserving typing order, modifiers and Backspace.
|
||
If the active window changes, queued typing is not sent to another window and a warning is shown.
|
||
It only corrects unknown words when exactly one alternative is a dictionary word.
|
||
**Minimum word length** defaults to 3 and can be set from 1 to 32 letters. Surrounding punctuation
|
||
does not count toward this minimum; the maximum word length is 32 letters.
|
||
Known words, ambiguous alternatives, ALL CAPS, mixed-case identifiers, numbers, URLs and email
|
||
addresses are left unchanged. Short trailing punctuation is retained when the editor selects it
|
||
together with the word. Actual selected text is verified before replacement. Layout switching follows
|
||
the existing switch-layout setting. The configured Undo shortcut restores the original and suppresses
|
||
that word for the rest of the session (until restart).
|
||
|
||
Password fields and inaccessible controls are skipped using Windows UI Automation. Editors, terminals
|
||
and password managers are excluded by default; process names can be edited in the options window.
|
||
Controls that do not expose an editable/document element or cannot select a complete word may not
|
||
support automatic correction. Dictionary recognition is heuristic, not an understanding of the sentence;
|
||
subtitle vocabulary is incomplete, and uncommon names or jargon can need personal exceptions.
|
||
|
||
No network service or language model is used. The three dictionary files occupy about 2.6 MB on disk;
|
||
the English/Ukrainian lookup data uses less than 3 MiB of RAM and is loaded on first automatic check.
|
||
Keep `dictionaries/` beside the executable when copying the app. These word lists derive from
|
||
[FrequencyWords](https://github.com/hermitdave/FrequencyWords) and are separately licensed under
|
||
CC BY-SA 4.0; attribution, pinned source revision and license are in `dictionaries/`.
|
||
|
||
## Latest compiled release
|
||
|
||
The [Release folder](Release/README.md) contains the latest portable Windows x64 ZIP and SHA-256 checksum.
|
||
Run `./package.ps1 -PublishRelease` after building and testing to refresh the tracked release archive.
|
||
|
||
## Verification
|
||
|
||
```powershell
|
||
.\build.ps1 -Test # Pure/native regression checks; does not touch the user's clipboard
|
||
.\build.ps1 -Ocr # Render a synthetic image, decode it with WIC and recognize it with Windows OCR
|
||
.\build.ps1 -Integration # Interactive, isolated test editor; avoid input for about 10 seconds
|
||
.\tests\configuration.ps1 # Separate-process settings tests; close KSwitcher first
|
||
```
|
||
|
||
`-Test` also checks remote/own input separation, hidden Settings layout and scrolling, and updater
|
||
package validation, file preservation and rollback in temporary fixture directories. It does not
|
||
replace a running installation. Optional read-only network checks:
|
||
|
||
```powershell
|
||
.\build\KSwitcherInputTests.exe --update-check
|
||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\tests\update.ps1 -Network
|
||
```
|
||
|
||
These validate the live release metadata/download/checksum in a temporary directory. They do not
|
||
prove hardware interoperability between two laptops or a physical monitor-disconnection sequence.
|
||
|
||
The interactive test requires installed English-US and Russian layouts. It opens its own editor,
|
||
tests real copy/paste, undo, repeat conversion, recent-input verification and snippet cursor placement,
|
||
then restores the clipboard. Test data is stored in its own temporary directory. It never sends messages
|
||
to Teams or other user applications. Do not run it while typing elsewhere.
|
||
|
||
`KSwitcher.exe --smoke-test` starts a normal tray instance and exits after ten seconds for idle-memory checks.
|
||
It still uses the normal instance lock; close a running KSwitcher first if measuring a fresh process.
|
||
|
||
## Structure
|
||
|
||
- `core.*`: conversion, transliteration, snippets, shortcut parsing/formatting, recent-input model.
|
||
- `platform.*`: Win32 layouts, clipboard, input, ownership, DPAPI and file primitives.
|
||
- `storage.*`: settings and encrypted, disk-backed history.
|
||
- `app.*`: message loop, hooks, background work and guarded text transactions.
|
||
- `config_main.cpp`, `configuration.*`: single-instance configurator and validated settings IPC.
|
||
- `ui.cpp`: native windows and shortcut recording.
|
||
- `ocr.*`: Windows WIC and OCR via the native Windows Runtime ABI.
|
||
- `tests/`: regression checks, real editor integration and OCR fixture.
|
||
|
||
Application code is MIT licensed; preserves the original [Typlo](https://github.com/bitcodepro/Typlo) attribution in `LICENSE`.
|
||
Dictionary data has its own CC BY-SA 4.0 license as described above.
|
||
|
||
The screenshot process lifecycle can be checked interactively with `tests/screenshot_process.ps1`
|
||
against a staged build. It briefly opens real selection/editor windows without changing the clipboard.
|
||
|
||
### Release channel rule
|
||
|
||
Keep `v0.4.2` as the last legacy `vX.Y.Z` release. Publish full packages as
|
||
`release-vX.Y.Z` (stable, not prerelease), including `release-files.json`,
|
||
`KSwitcher-win-x64.zip` and `SHA256SUMS.txt`. Never publish a manifest package under a
|
||
legacy version tag: clients that have not installed the bridge would select it.
|
||
Keep the compatibility bridge in the first 100 releases returned by Gitea while
|
||
supporting old clients; their immutable update code only reads that page.
|