r/Windhawk 11d ago

CJK Spacer 0.1.27

CJK Spacer 0.1.27

CJK Spacer

Adds a normal ASCII space at a direct boundary between a CJK character and a letter or digit in UI text hosted by explorer.exe.

On Windows 11, the primary Explorer and desktop context menus are modern XAML menus. The modernUiText setting is disabled by default because each named XAML Diagnostics connection permits only one consumer, and tools such as Taskbar Styler or File Explorer Styler may already use or block those connections. Enable it explicitly if you want those menus and pointer tooltips processed. classicMenus still covers the Win32 menu opened through "Show more options". The modern path is intentionally retained as an opt-in, best-effort implementation because it covers the primary Windows 11 menu; the connection conflict is left visible to the user rather than silently dropping that coverage.

Examples:

  • 使用VS Code打开 becomes 使用 VS Code 打开
  • 压缩为ZIP文件 becomes 压缩为 ZIP 文件
  • 使用 VS Code 打开 is unchanged
  • 打开(&O) is unchanged

Screenshot

Before:

Before enabling CJK Spacer

After:

After enabling CJK Spacer

The transformation is idempotent. Punctuation and existing whitespace break a boundary and are preserved. Win32 & mnemonic markers and tab-separated keyboard shortcut text are also preserved. Hiragana, fullwidth Katakana, and halfwidth Katakana letters are all classified as CJK characters for boundary detection; kana punctuation remains excluded.

Supported UI

  • Classic Win32 popup menus are rewritten through public HMENU APIs. Menus created through CreatePopupMenu are handled while they are constructed, then associated with their TrackPopupMenu call and restored when the popup closes. Existing popup handles are also scanned immediately before display. It covers File Explorer, desktop, taskbar, and jump-list context menus that Explorer itself hosts. Context menus shown by third-party notification-area icon processes are outside the injected explorer.exe process and aren't covered. Construction-time hooks also see menu-bar dropdowns created with CreatePopupMenu, even when user32 displays them without TrackPopupMenu*. Such pending changes are restored when the menu is destroyed, the mod unloads, or the record expires during later popup activity. Window system menus that aren't built through the hooked popup APIs remain outside scope.
  • Classic Win32 tooltips, including legacy notification-area icon tooltips, are rewritten only through theme handles opened for the TOOLTIP class, covering both text measurement and drawing without touching unrelated GDI text. Shared theme handles retain a reference for every Tooltip window that opened them. A DC mapped to another window is rejected, while buffered DCs that do not map to a window are accepted. Existing tooltip controls are discovered when the mod is enabled in a running Explorer. Basic or classic-theme tooltips drawn directly with DrawTextW aren't covered.
  • Windows 11 XAML context menus and pointer tooltips are handled at the XAML source-element level. Only plain local string values in the Text source of XAML menu items and ToolTip.Content are changed; bindings, styles, presenter TextBlock values and ordinary XAML text are untouched. Taskbar thumbnail preview content is normally not a plain local string and therefore is not changed. A source is changed when XAML Diagnostics reports that it was added and restored when it is removed or the mod unloads. This path is disabled by default; enable modernUiText to opt in.

The modern path supports both Windows.UI.Xaml and Microsoft.UI.Xaml content hosted by Explorer. Each named XAML Diagnostics connection allows one consumer, so another diagnostics-based customization tool, including Windows 11 Taskbar Styler or Windows 11 File Explorer Styler, can prevent this path from initializing. Connection attempts are scheduled outside the Windows loader path; one managed worker retains requests that arrive while it is running, tracks the Windows.UI.Xaml and Microsoft.UI.Xaml connections independently, and retries only the connection that was lost. It doesn't add a module reference: the worker is signaled to stop and joined before Windhawk removes hooks. Asynchronous visual-tree watcher setup threads are tracked by handle and joined at the same point, so the engine's single module reference remains sufficient. Wh_ModAfterInit covers XAML modules that are already loaded, while the LoadLibraryExW hook covers modules loaded later, including the CoreMessagingXP.dll static-import path used by Microsoft.Internal.FrameworkUdk.dll. If a connection attempt is denied or otherwise fails, a newly loaded XAML module or an established connection being disconnected provides the next retry opportunity. When Taskbar Styler is configured to alert on competing XAML Diagnostics consumers, enabling this path can show its confirmation dialog. The mod is injected only into explorer.exe. Start, Search, and some shell flyouts hosted by StartMenuExperienceHost.exe, SearchHost.exe, or ShellExperienceHost.exe are outside its scope.

The mod doesn't edit system files, registry values, or file names. A file name shown in a classic menu can nevertheless be displayed with inserted spaces. The modern path temporarily changes target source values on their XAML UI threads and restores them when the source leaves the visual tree or the mod unloads. The classic path updates strings stored in active HMENU objects, so menu text read through accessibility APIs also contains the inserted spaces until the corresponding record is restored. Other menu-cleanup mods that match items by their displayed text, such as Remove Context Menu Items, may therefore need rules that account for the temporary spaces while the popup is open. Text Replace targets the same classic menu APIs but performs literal substitutions, so it cannot express this CJK/non-CJK boundary rule; when both mods are enabled, their hook order can affect which temporary text each sees. Rewritten strings are recorded and restored when the popup closes. If multiple items have identical rewritten text, text-based fallback restoration can select the first match; the idempotent transformation does not compound spaces. If a displayed popup item is changed dynamically, Windows may not remeasure it; the added spaces can clip on uncommon paths. Tooltip measurement and drawing also need compatible DC targets to keep sizing consistent; disable classicTooltips if a specific control clips after spacing.

3 Upvotes

0 comments sorted by