Files
hrynco-kswitcher/README.md
T

28 KiB
Raw Blame History

KSwitcher

Native C++20 / Win32 rewrite of the Windows functionality of Typlo. Windows 10/11 x64. No .NET, Avalonia, WebView, Qt, external graphics engine, or separately installed C++ runtime. The original Typlo project and its data remain separate.

User guide / Wiki — setup, features, shortcuts, dictionaries, screenshots and troubleshooting in English and Українська. Each wiki page links to its translation.

Support KSwitcher development — buy the developer a coffee

Donate via Monobank · 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 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 and Windows shows a notification with a thumbnail. Click the notification to open the editor, including after the screenshot process has exited. If notifications are disabled or cannot be sent, the already-copied screenshot opens in the editor. 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. To annotate: N places sequential numbered red markers with a click, and A draws red arrows by dragging from the tail to the tip. 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. The compact toolbar uses Lucide 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. 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. A startup check also reports an available version, but never installs it automatically. Confirm the offered version to download and install 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.

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.
  • 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).
  • Windows OCR, entirely native and offline. Right-click an image in history and select Copy text from image. Requires a Windows OCR language installed for the user profile.
  • 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: 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 settings.json, preserving supported Windows layout IDs, hotkeys, snippets, exclusions and limits. Import is staged until Save. Existing Typlo files are never modified. 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'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:

.\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. 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; keep words sorted and unique. For a personal addition, rank 1 makes it eligible at every positive limit. 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 cancels pending work. 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 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 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

.\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:

.\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 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.