519 lines
28 KiB
Markdown
519 lines
28 KiB
Markdown
# Wine Access
|
|
|
|
`wine-access` is a standalone Wine-hosted accessibility helper for screen
|
|
readers that implement its Wine D-Bus protocol. An Orca endpoint is
|
|
available for future Orca-side integration; stock Orca does not implement
|
|
the required Wine methods.
|
|
|
|
It provides these capabilities:
|
|
|
|
- an MSAA/WinEvent reader for standard Wine controls;
|
|
- NVDA Controller 1, 2, and 3 plus Tolk compatibility for applications using
|
|
`nvdaControllerClient32.dll`, `nvdaControllerClient64.dll`, or `Tolk.dll`;
|
|
- a UIA notification bridge for applications whose announcements Wine discards,
|
|
including Prism's UIA speech backend.
|
|
|
|
The compatibility window is hidden and non-activating. It is expected to be
|
|
invisible; the important endpoint is the local Wine RPC server registered by
|
|
the helper. The helper forwards speech, braille, cancellation, and standard
|
|
control events to the selected reader on the session D-Bus. The default is
|
|
`org.stormux.Cthulhu1.Service`.
|
|
|
|
Wine currently returns success from `UiaRaiseNotificationEvent` without
|
|
delivering its text. The native application hooks redirect direct imports of
|
|
that function to the reader. This works with both 32-bit and 64-bit applications;
|
|
it requires no application files or per-game DLL overrides. Notifications from
|
|
background processes are ignored. Important notifications interrupt speech,
|
|
and an empty important notification cancels speech. Each notification is
|
|
bounded to 4095 UTF-16 code units without splitting surrogate pairs.
|
|
|
|
The bridge covers direct named imports, rather than calls obtained dynamically
|
|
with `GetProcAddress`. It leaves implementations that reject a missing provider
|
|
untouched. The hook DLL remains mapped until the application exits so redirected
|
|
imports remain valid across reader restarts. Close and reopen applications after
|
|
updating Wine Access to load the new hooks. `--no-dialog-reader` disables these
|
|
hooks along with standard control reading.
|
|
|
|
The executable is named `wine-access.exe`. Its launcher, Winelib sidecar,
|
|
and native hooks share a reader-independent installation directory.
|
|
|
|
## Requirements
|
|
|
|
Building requires an x86_64 Linux host with:
|
|
|
|
- CMake 3.20 or newer;
|
|
- Make and native GCC/G++ (the script uses CMake's default Makefile generator);
|
|
- `pkg-config` and the GLib/GIO development files;
|
|
- XCB development files for Wine-associated X11 window geometry;
|
|
- Wine development tools: `winegcc`, `wineg++`, and `widl`;
|
|
- `x86_64-w64-mingw32-gcc` and `i686-w64-mingw32-gcc` to build native menu hooks
|
|
(`mingw-w64-gcc` on Arch Linux).
|
|
|
|
The D-Bus helper is a 64-bit Winelib executable. A small 32-bit Windows
|
|
companion supplies menu and standard Edit hooks for 32-bit applications, without requiring
|
|
32-bit Linux GLib/GIO development files.
|
|
|
|
## Build
|
|
|
|
On Arch Linux, the [PKGBUILD](distro-packages/ArchLinux/wine-access-git/README.md)
|
|
provides package-managed installation and upgrades. Choose one installation
|
|
method to avoid a local copy taking precedence over the system package.
|
|
|
|
The convenience script builds in `./build`. Running it as a user installs to
|
|
`$HOME/.local/libexec/wine-access`; running it as root installs system wide to
|
|
`/usr/libexec/wine-access`:
|
|
|
|
```sh
|
|
./build.sh
|
|
sudo ./build.sh
|
|
```
|
|
|
|
Before building, the script checks required tools and GIO development files.
|
|
If any are missing, it lists them with Arch Linux package names and an install
|
|
command, then exits without building. Other distributions need equivalent
|
|
development packages. Removal does not require these dependencies.
|
|
|
|
Use `./build.sh -r` to remove the local installation, or
|
|
`sudo ./build.sh -r` to remove the system installation. If a user has no local
|
|
installation but a system installation exists, the script requests the latter
|
|
command without running sudo itself. Removal deletes only the five helper
|
|
files and leaves other directory contents untouched.
|
|
|
|
Alternative build and install locations may be supplied as positional
|
|
arguments. The second argument is the installation prefix, not the final
|
|
helper directory:
|
|
|
|
```sh
|
|
./build.sh /tmp/wine-access-build "$HOME/.local"
|
|
./build.sh -r /tmp/wine-access-build "$HOME/.local"
|
|
```
|
|
|
|
That installs the helper and its Winelib sidecar as:
|
|
|
|
```text
|
|
$prefix/libexec/wine-access/wine-access.exe
|
|
$prefix/libexec/wine-access/wine-access.exe.so
|
|
$prefix/libexec/wine-access/wine-access-menu.dll
|
|
$prefix/libexec/wine-access/wine-access-menu32.dll
|
|
$prefix/libexec/wine-access/wine-access-menu-host32.exe
|
|
```
|
|
|
|
For Cthulhu, either set `CTHULHU_WINE_ACCESS_HELPER` to the installed
|
|
executable or install it under one of these prefixes:
|
|
|
|
```text
|
|
$HOME/.local/libexec/wine-access/wine-access.exe
|
|
/usr/local/libexec/wine-access/wine-access.exe
|
|
/usr/libexec/wine-access/wine-access.exe
|
|
```
|
|
|
|
Cthulhu checks the environment override first, then the user installation,
|
|
`/usr/local`, `/usr`, and finally `PATH`. Its existing Cthulhu-specific user
|
|
and system paths remain supported; avoid leaving stale user copies installed.
|
|
|
|
The helper is started automatically when Cthulhu detects an active Wine
|
|
loader for the same user and prefix. It requires the selected reader service
|
|
to be running; it exits if that service is unavailable.
|
|
|
|
## Version and diagnostics
|
|
|
|
Edit the single line in [`VERSION`](VERSION) to set the release date, using
|
|
`YYYY.MM.DD`. Every build embeds that version, the source checkout's Git
|
|
revision and a modified-build flag. Incremental builds refresh the identity
|
|
after commits or source changes. The flag includes untracked files that Git
|
|
does not ignore; a source archive without `.git` reports revision `unavailable`.
|
|
It identifies the helper sidecar being executed, rather than a separate
|
|
installed version file or the installed package database.
|
|
|
|
Query an installed executable directly, for example:
|
|
|
|
```sh
|
|
/usr/libexec/wine-access/wine-access.exe --version
|
|
```
|
|
|
|
This exits before reader discovery or singleton acquisition, so it works
|
|
without a reader and while another helper is running. Wine itself still needs
|
|
to initialize normally. To identify an already running helper, use its startup
|
|
record; replacing files on disk does not update the running process.
|
|
|
|
Ordinary startup writes `wine-access: identity` and `wine-access: ready` JSON
|
|
records to stderr. Identity is emitted even when later startup fails. The ready
|
|
record means initialization reached the message loop; inspect its individual
|
|
booleans for unavailable components. Hook handles and `host32_started` report
|
|
installation/launch success, not attachment to a particular application or
|
|
confirmation that the companion installed its hooks. Failures retain concise
|
|
`wine-access:` diagnostics without accessible event text or password values.
|
|
Reader replies that merely filter duplicate/unwanted events are not errors.
|
|
|
|
Updated Cthulhu versions capture these records in their normal log, including
|
|
worker/hook startup failures, reader-call failures, recovery and queue overflow.
|
|
Executable, loader and prefix paths appear only in Cthulhu's debug log. For a
|
|
bug report, include the helper identity and initialization records, relevant
|
|
diagnostics and the exact navigation steps. Review debug output for private
|
|
text before sharing. No reader-specific logging service is required by the
|
|
helper; other readers can consume the same stderr records.
|
|
|
|
## Reader selection and Orca integration
|
|
|
|
The default invocation and `--reader cthulhu` use the existing Cthulhu endpoint.
|
|
An Orca-side integration can launch the helper in the application's Wine prefix:
|
|
|
|
```sh
|
|
WINEPREFIX=/path/to/prefix /path/to/wine-access.exe --reader orca
|
|
```
|
|
|
|
| Reader | Session bus name and interface | Object path |
|
|
| --- | --- | --- |
|
|
| Cthulhu (default) | `org.stormux.Cthulhu1.Service` | `/org/stormux/Cthulhu1/Service` |
|
|
| Orca | `org.gnome.Orca1.Service` | `/org/gnome/Orca1/Service` |
|
|
|
|
An Orca user extension can expose the Wine methods on its own object and
|
|
interface, without adding them to Orca's core service. Override either field
|
|
with `--reader-path` and `--reader-interface`; omitted fields retain the
|
|
selected reader's defaults. For an extension class named `WineAccess`:
|
|
|
|
```sh
|
|
WINEPREFIX=/path/to/prefix /path/to/wine-access.exe --reader orca \
|
|
--reader-path /org/gnome/Orca1/Service/WineAccess \
|
|
--reader-interface org.gnome.Orca1.WineAccess
|
|
```
|
|
|
|
Both overrides accept validated D-Bus values and apply regardless of their
|
|
position relative to `--reader`. The bus name stays that of the selected
|
|
reader; overrides do not grant review access to another connection.
|
|
|
|
Before starting its hooks or controller server, the helper introspects the
|
|
selected object and interface and checks the required method signatures for
|
|
the enabled capabilities. A missing extension or incompatible interface
|
|
causes startup to fail with a diagnostic. Controller support requires
|
|
`SpeakText`, `CancelSpeech`, `BrailleMessage` and `SpeakSsml`; control reading
|
|
requires `PresentAccessibleEvent`, plus `SpeakText` and `CancelSpeech` for UIA
|
|
notifications even with `--no-controller`. Review methods remain optional. The
|
|
interface must be published before launching the helper. This check runs at
|
|
startup; later request failures still follow the ordinary error handling.
|
|
|
|
Selection applies to controller requests, accessibility events, review
|
|
registration and review-capture authorization. Only one helper runs per Wine
|
|
desktop/prefix, so stop the existing helper before changing readers. There is
|
|
no automatic switching between services. Unknown or missing reader values
|
|
are rejected. Orca must arrange helper startup and shutdown itself.
|
|
|
|
The Orca endpoint follows the versioned service in Orca's `dbus_service.py`.
|
|
It uses the same Wine methods and signatures as Cthulhu, on the selected
|
|
service interface:
|
|
|
|
| Method | Input signature | Output signature |
|
|
| --- | --- | --- |
|
|
| `SpeakText` | `sb` (text, interrupt) | `b` |
|
|
| `CancelSpeech` | empty | `b` |
|
|
| `BrailleMessage` | `s` (text) | `b` |
|
|
| `SpeakSsml` | `ss` (source, SSML) | `i` (Windows status code) |
|
|
| `PresentAccessibleEvent` | `sssssssiis` | `b` |
|
|
| `RegisterWineReviewProvider` (optional) | `ou` (provider path, version) | `b` |
|
|
| `PresentWineReviewFocus` (optional) | `ssstssb(iiii)` | `b` |
|
|
|
|
Boolean replies indicate whether the reader accepted the request. The helper
|
|
queues plain controller speech with `interrupt=false`; Tolk requests
|
|
interruption separately through `CancelSpeech`. An unsupported `SpeakSsml`
|
|
implementation should return `ERROR_CALL_NOT_IMPLEMENTED` (120).
|
|
`PresentAccessibleEvent` arguments are source ID, event type, name, role,
|
|
value, states, description, position, count and window title, in that order.
|
|
The reader handles focus tracking, event filtering and presentation; preserve
|
|
repeated editor actions and exclude password values as described below.
|
|
|
|
Orca's existing `SpeakMessage` and `DisplayMessage` methods have different
|
|
names/signatures. Wine Access does not translate to those methods. An Orca
|
|
contributor must implement the Wine methods above for the capabilities they
|
|
want to enable. `--no-controller` and `--no-dialog-reader` can disable either
|
|
capability while bringing up the integration.
|
|
|
|
Review retains the shared `/org/stormux/Cthulhu1/WineReview` object path and
|
|
`org.stormux.Cthulhu1.WineReview` interface for both readers. Use the helper's
|
|
unique D-Bus sender from `RegisterWineReviewProvider` as the destination for
|
|
`CaptureWindow`. Only the current same-user owner of the selected reader
|
|
service may capture; owning the other reader name grants no access. See
|
|
[the flat-review contract](#independent-wine-flat-review) for focus arguments,
|
|
capture replies and limits. Missing review methods leave ordinary control and
|
|
controller forwarding available.
|
|
|
|
When a game closes inside a Wine virtual desktop, the desktop can regain X11
|
|
focus while Wine has no foreground application. The helper restores native
|
|
focus when exactly one visible, enabled application remains. Both X11 keyboard
|
|
focus and the window manager's active window must identify that same virtual
|
|
desktop. Existing application focus, Linux windows, minimized/disabled windows,
|
|
and ambiguous choices between multiple applications are left alone.
|
|
|
|
## Protocol and behavior
|
|
|
|
`nvdaController.idl` contains the compatible local RPC interfaces. The helper
|
|
registers the legacy `NvdaCtlr` endpoint and the session/desktop-specific
|
|
endpoint used by newer clients. It intentionally preserves the standard
|
|
controller behavior for plain speech and cancellation while returning the
|
|
documented unsupported status for SSML speaking-state callbacks that Cthulhu
|
|
cannot currently implement accurately.
|
|
|
|
The standard-control reader is deliberately limited to native Wine controls.
|
|
Custom-drawn, DirectX, and game-specific accessibility APIs remain the
|
|
responsibility of the application or its accessibility middleware.
|
|
|
|
Battle.net's `Blizzard Bootstrapper` wizard has a separate, guarded UI Automation
|
|
reader. Its language page exposes no MSAA child controls. The helper reads the
|
|
focused language selector and its current language, and the Continue button,
|
|
without activating controls or changing focus. The provider marks the selected
|
|
language as focused even while Continue owns Tab focus, so language choices
|
|
are presented as the selector's value rather than independent focus events.
|
|
Arrow changes are polled and unchanged results are suppressed. This support
|
|
also reads the second page's startup checkbox through its native Toggle
|
|
provider. Wine rejects the client toggle-state property query, so the native
|
|
input hook borrows the focused provider on the application's UI thread and
|
|
copies its checked/unchecked/mixed state. Only the foreground bootstrapper's
|
|
direct `UiaReturnRawElementProvider` import is observed; the original call and
|
|
result are preserved, no control is toggled, and provider references are not
|
|
retained. State changes use the existing reader's `state` event.
|
|
|
|
After installing updated hooks, close and reopen the wizard as well as
|
|
restarting the reader. The hook stays mapped for the application's lifetime.
|
|
Later installer pages beyond these exposed controls and the Battle.net
|
|
launcher remain unverified.
|
|
|
|
The UIA queries use a separate COM worker, limited to the foreground bootstrapper
|
|
class, 64 sibling controls and a 500 ms result deadline. Wine's implemented
|
|
extended property queries and an explicitly constructed tree walker avoid
|
|
unimplemented convenience APIs. Protected field values and values whose
|
|
protection is unknown are never queried. A blocked provider can stop this
|
|
wizard's feedback until it returns, but does not block native menus, editing,
|
|
MSAA events or helper shutdown. This is control feedback, not UIA flat review.
|
|
|
|
Native menu reading uses accompanying 64-bit and 32-bit Windows hook DLLs. They
|
|
observe
|
|
`WM_MENUSELECT` inside Wine applications and sends menu labels, displayed
|
|
shortcuts, submenu roles, and checked/unavailable states to the helper. The
|
|
helper queues these messages before forwarding them over D-Bus, suppresses
|
|
repeated selections, and restores standard-control focus reporting when menus
|
|
close. The hooks apply to the helper's Wine desktop and prefix and are removed
|
|
on normal shutdown. The 32-bit host attaches to the foreground 32-bit UI thread
|
|
so Wine's global hook chain cannot interfere with 64-bit menus. It exits when the helper dies or its bridge
|
|
window closes. Menu and editor hooks are disabled by `--no-dialog-reader`. The
|
|
32-bit companion attaches both hooks to the same foreground UI thread.
|
|
|
|
Focused combo boxes are checked every 100 ms to recover value changes that
|
|
Wine does not report through WinEvents. The combo's internal list events use
|
|
the same source identity as the focused combo, so the reader can accept the
|
|
new value without a Tab/Shift+Tab round trip.
|
|
|
|
Both hook DLLs subclass standard `Edit` controls, including Wine Notepad's
|
|
document area, MUSHclient's command field and read-only output notepad, and
|
|
`WindowsForms10.EDIT.app.*` controls. Windows Forms fields
|
|
use visible sibling labels immediately to their left, even when the labels
|
|
were created after the fields. Protected fields report their label and
|
|
password role without forwarding their contents.
|
|
It reports accepted typed characters, the current line on focus and menu return,
|
|
characters and words on horizontal navigation, lines on vertical/page/document-boundary
|
|
navigation, changed selections, and Backspace/Delete/Cut feedback. Password
|
|
contents are excluded, and read-only edits do not report unsuccessful deletions.
|
|
Command-history recalls in MUSHclient report the recalled command, or `blank`
|
|
when returning to empty input. The input hook observes Up/Down before the
|
|
application consumes them, so recalls also work when the caret position stays
|
|
the same. Unrelated programmatic text changes remain silent.
|
|
Undo refreshes the text snapshot used by subsequent navigation. It can attach to
|
|
an already-focused editor and resume after the helper restarts.
|
|
|
|
The 64-bit DLL also subclasses `Scintilla` controls, including Notepad++'s document
|
|
area. Up/Down and page navigation report the current document line;
|
|
Left/Right report characters, and Ctrl+Left/Right report words. Focus and menu
|
|
return read the caret's line. Ordinary selections, Backspace/Delete/Ctrl+X,
|
|
Unicode characters, undo and read-only documents are supported. Text is read
|
|
inside the application through Scintilla's native API, using its encoding and
|
|
byte positions; no full document snapshot is required. Rectangular/multiple
|
|
selection feedback and Ctrl+Backspace/Delete feedback are not implemented.
|
|
|
|
Backspace reports only the removed text, such as `t`. Delete and Cut retain
|
|
their deletion feedback, such as `t deleted`.
|
|
|
|
Standard Edit typing sends each accepted character as an ordered editor action,
|
|
including repeated letters, spaces, tabs, line breaks and Unicode surrogate
|
|
pairs. Typing over selected text also reports the inserted character. Password
|
|
fields, background controls and rejected input remain silent. Paste and
|
|
programmatic text changes do not generate character echo. The reader presents
|
|
these through the same feedback path as caret navigation and Backspace.
|
|
Character case is preserved. Cthulhu uses its configured uppercase voice
|
|
and pitch for capital-letter feedback, then the normal character voice for
|
|
lowercase letters. This requires the matching reader update; the helper does
|
|
not set speech pitch itself.
|
|
|
|
Editor actions use `PresentAccessibleEvent` with event type `text`; actual focus
|
|
uses `focus`. Cthulhu must include the corresponding editor-event support so
|
|
rapid actions and repeated characters bypass focus coalescing. Selection
|
|
offsets and the action kind (8 for typed insertion) travel in the otherwise
|
|
non-spoken `states` field for debug diagnostics. Standard edits use UTF-16 offsets; Scintilla marks its
|
|
encoded byte offsets with `offset_unit=byte`. Older readers that only accept
|
|
focus/value/selection events still receive focus and menus, but need updating
|
|
for editor actions.
|
|
|
|
MSAA `name` and `state` events report changes to controls. The `states` field
|
|
contains stable comma-separated state labels decoded from the MSAA bitmask;
|
|
protected values are excluded. Readers should filter name/state changes to
|
|
their focused source and distinguish these labels from editor diagnostics.
|
|
|
|
Application-owned MSAA queries run on one separate COM worker, with bounded
|
|
pending requests and copied results. A stalled provider cannot block the
|
|
helper's menu/editor event thread or normal shutdown. Focus/foreground changes
|
|
retire previous results; event results expire after 500 ms. If focus queries
|
|
do not finish, native control feedback uses the existing bounded fallback.
|
|
Unrelated background events are rejected before querying providers; visible
|
|
popups owned by the foreground window retain their accessible event path.
|
|
A provider that never completes still occupies the one MSAA worker until
|
|
helper exit; native menus, editing, focus fallback and controller requests
|
|
remain available. No extra workers accumulate behind blocked providers.
|
|
|
|
Reader acknowledgments also run on a separate worker. Menu, editor and control
|
|
events enter a bounded FIFO so a delayed D-Bus reply cannot block reception of
|
|
the hooks' `WM_COPYDATA` messages. The event thread's success means queued;
|
|
controller RPC requests still return the reader's actual status. At most 128
|
|
events wait behind the active call. Each reply has a 500 ms timeout, and normal
|
|
shutdown cancels the call. Failed exchanges and queue overflow produce concise
|
|
stderr diagnostics without event text. After a failed exchange, editor actions
|
|
re-establish their focus dependency; timed-out text actions are never replayed.
|
|
An unavailable reader can still cause feedback loss or queue overflow.
|
|
|
|
|
|
Standard `SysListView32` controls now report the current row's text columns,
|
|
selection and position, including 32-bit installers driven by the 64-bit
|
|
helper. Wine can expose these controls only as a generic client named `List1`,
|
|
so the helper queries the native control with target-architecture structures.
|
|
When a populated list has no focused or selected row, focus reads its first
|
|
row without changing selection. A bounded focus poll reports row navigation
|
|
when Wine omits selection events. Up to eight columns and 1023 UTF-16 units
|
|
per column are read. These queries do not add column navigation or routable
|
|
object review.
|
|
|
|
Standard `ListBox` controls report the selected item's text and position when
|
|
Up/Down changes the selection, including AudioQuake's map chooser. The same
|
|
foreground poll detects changes when Wine omits selection events, with one
|
|
source identity for focus and selection. Background lists remain silent.
|
|
|
|
Native tab controls report their focused caption and position; tree controls
|
|
report the selected node and its expansion state. A bounded focus poll follows
|
|
navigation when Wine omits selection events. These queries work with 32-bit
|
|
and 64-bit controls, including standard controls registered with `ATL:` names.
|
|
Named generic MSAA clients no longer hide known native button/combo-box roles
|
|
and values. Edit and combo-box labels can be visible siblings to the left,
|
|
even when the labels were created after the fields. Application-owned MSAA
|
|
lists retain their own names, roles and item data.
|
|
|
|
Delphi VCL `TListView`, `TButton`, `TBitBtn`, and `TStaticText` subclasses
|
|
use these same native queries. List views with standard checkboxes report
|
|
checked/not-checked states and observe Space-key toggles even without a
|
|
selection event. This covers GoldWave 5.70's Setup list and standard buttons;
|
|
arbitrary custom Delphi controls remain outside this support.
|
|
|
|
Control values and window titles retain literal ampersands. Button and static
|
|
label captions decode keyboard mnemonics and escaped `&&`; static labels with
|
|
`SS_NOPREFIX` retain their literal text.
|
|
|
|
These hooks provide editing feedback. Independent review-cursor commands use
|
|
the optional flat-review protocol described below; Say All and native braille
|
|
routing remain unsupported. Word echo and typing echo in Scintilla
|
|
remain outside this helper's current support. RichEdit and 32-bit Scintilla hooks
|
|
are not covered. Reports are limited to 1023 UTF-16 units; documents over one million
|
|
units retain typing and line feedback without full selection/deletion snapshots.
|
|
Scintilla reads at most 4096 encoded bytes per report, then limits output to
|
|
1023 UTF-16 units without splitting surrogate pairs. Wrapped Scintilla lines
|
|
report the underlying document line.
|
|
|
|
Keep all five installed files together. Native menus and standard Edit controls
|
|
are supported in 32-bit and 64-bit applications; custom menus that do not send
|
|
`WM_MENUSELECT` are not covered.
|
|
|
|
## Menu integration check
|
|
|
|
After building, run this in a graphical session with Python's PyGObject
|
|
available (`python-gobject` on Arch Linux):
|
|
|
|
```sh
|
|
python3 tests/menu_integration.py --build-dir build
|
|
python3 tests/menu_integration.py --build-dir build --fixture edit
|
|
python3 tests/menu_integration.py --build-dir build --fixture edit --32-bit
|
|
python3 tests/menu_integration.py --build-dir build --fixture notepad
|
|
```
|
|
|
|
The test opens a short-lived native menu window in a temporary Wine prefix,
|
|
uses a private D-Bus recording service, and checks keyboard menu navigation,
|
|
context menus, shortcuts, item states, and duplicate suppression. It does not
|
|
send speech or braille to the running reader. Live listening with Cthulhu is a
|
|
separate acceptance check.
|
|
|
|
See [the test guide](tests/README.md) for helper lifecycle checks and the live
|
|
Notepad speech/braille procedure. After updating the DLL, close and reopen the
|
|
Wine application: existing control subclasses keep their DLL loaded until the
|
|
application exits.
|
|
|
|
## License
|
|
|
|
The helper source is available under the terms of LGPL-2.1-or-later. See
|
|
`LICENSE`.
|
|
|
|
## Independent Wine flat review
|
|
|
|
With the matching Go reader, existing keypad review commands read visible
|
|
standard Edit text, button/static captions, native ListBox/ListView items, and
|
|
usable MSAA captions/values in both 32-bit and 64-bit applications. Each
|
|
command captures fresh text while preserving application focus, caret,
|
|
selection, scrolling and clipboard. Password and hidden contents are excluded
|
|
before text retrieval. Caption mnemonics are decoded; literal item ampersands
|
|
are preserved. Review text uses the reader's normal speech and braille queues.
|
|
|
|
Custom painted game output still needs an accessible output provider, such as
|
|
MUSHclient's output plugin. RichEdit/Scintilla capture, semantic object review,
|
|
Say All, typing echo and native braille routing remain outside this protocol.
|
|
|
|
Protocol version 1 adds `RegisterWineReviewProvider(ou) -> b` and
|
|
`PresentWineReviewFocus(ssstssb(iiii)) -> b` to the reader service. The helper
|
|
exports `/org/stormux/Cthulhu1/WineReview`, interface
|
|
`org.stormux.Cthulhu1.WineReview`, with `CaptureWindow(sst) -> a{sv}`. Only the
|
|
current same-user owner of the selected reader service can capture. Replies contain exactly
|
|
`version:u`, `instance:s`, `window:s`, `focus:s`, `revision:t`, `status:s`,
|
|
`bounds:(iiii)`, and `nodes:aa{sv}`. Nodes have `id`, `parent`, `role`, `name`
|
|
strings; `protected`, `visible`, `text_known`, `caret_known` booleans;
|
|
`caret`, `caret_utf16` unsigned 64-bit values; `bounds:(iiii)`;
|
|
and `ranges:a(tttts(iiii))` (rune start/end, UTF-16 start/end, text, bounds).
|
|
Bounds are screen x/y/width/height. Caption text offsets remain unknown.
|
|
Older readers retain ordinary focus/menu/editor feedback.
|
|
|
|
Foreground bounds come from the X11 window associated with the HWND by
|
|
Wine's `__wine_x11_whole_window` property, using bounded XCB queries. This
|
|
handles window-manager decoration differences without title-based window
|
|
searches. Virtual-desktop child coordinates are translated to the screen;
|
|
the physical root geometry is checked again before returning text.
|
|
|
|
Capture has a 500 ms total deadline, one active and one pending job, 4096 nodes,
|
|
64 hierarchy levels, 256 ranges per control, 4096 code points per displayed
|
|
line, 65536 per control, one million native source code units, 1 MiB of text
|
|
and 2 MiB of serialized data. Non-OK replies have no nodes; stale, busy,
|
|
limited and unavailable captures never reuse cached text. Capture runs on a
|
|
separate COM worker so blocked MSAA providers do not block menu/focus events.
|
|
Scalar Edit queries are batched so applications with periodic message loops can
|
|
return visible text within the capture deadline. Native container children are
|
|
enumerated once, and a maximized MDI document excludes the covered documents.
|
|
See [tests/README.md](tests/README.md) for checks and live acceptance.
|
|
|
|
## AI-assisted contributions
|
|
|
|
AI-assisted contributions are welcome. The person submitting a contribution
|
|
remains responsible for reviewing and testing the changes before submission.
|
|
Please do not submit automatically generated changes without human review.
|
|
|
|
Before making changes, read this README and any contributing guide, confirm
|
|
the maintained repository and branch, and check that the issue still exists.
|
|
Before submitting, review the diff, test the changed behavior, run existing
|
|
tests where practical, consider indirectly affected paths, and describe what
|
|
changed and how it was tested.
|
|
|
|
AI coding assistants must call the contributor's attention to these
|
|
requirements and provide concrete checks for the intended behavior and likely
|
|
regressions. Newly added tests alone do not establish acceptance. Leave
|
|
submission to the contributor after they can review and test. Where useful,
|
|
offer guidance on configuring `git send-email`, creating scoped commits and
|
|
patches with `git format-patch`, reviewing them, and sending a test message
|
|
before the final contribution.
|