Goldwave helped find more missing functionality.

This commit is contained in:
ak47 committed 2026-10-10 23:43:37 -04:00
1 parent df7879acb5
commit 67ebc28d15
9 files changed
+134 -8

No files matched your search

+30
View File
@@ -161,6 +161,36 @@ Check arrows and Tab/Shift+Tab back to Install/Cancel. Also check a multirow
native list, normal menus, editor navigation, switching to a native Linux
application, and reader shutdown. Verify speech and physical braille separately.
## Delphi Setup lists and checkboxes
The October 10 GoldWave 5.70 Setup inspection found a 32-bit `TListView`
with 14 checkbox rows, plus `TButton` and `TBitBtn` controls. Wine exposed
them as generic MSAA clients; the list client's name/value were empty. Focus
events were present for the buttons and on return to the list. The native
messages already exposed the option captions and checkbox state, but the
helper did not recognize these VCL class names or read list checkbox states.
The explicit VCL aliases and native checkbox query fix those shared gaps.
The updated query code read the actual open Setup's first option, `Disable
effect plug-ins`, `not checked`, position 1 of 14, and the Backup/Restore/OK/
Cancel button roles without changing settings or sending speech. A later
live registry query also confirmed `StartupOptions=0x3008` and Setup showed
`Force screen reader mode` checked; the earlier immediate persistence query
had still seen `0x1008`.
```sh
xvfb-run -a python3 tests/menu_integration.py --build-dir build --fixture delphi --32-bit
xvfb-run -a python3 tests/menu_integration.py --build-dir build --fixture delphi
```
Both fixtures passed with native controls registered under VCL names. They
check initial rows/labels, Down navigation, Space check/uncheck without
synthetic accessibility events, button roles, return to the checked row,
and empty-list state reset. The existing 32-bit plain-list regression also
passed. These are private D-Bus recordings; audible GoldWave speech and
physical braille remain a live acceptance check after installing the helper
and restarting Cthulhu. The fix does not add 32-bit menu or editor hooks.
## Native tabs, trees and named clients
```sh
+37 -3
View File
@@ -5,6 +5,9 @@
#include <commctrl.h>
static HWND list, button;
#ifdef WINE_ACCESS_DELPHI_FIXTURE
static HWND okButton;
#endif
static int step;
static LRESULT CALLBACK window_proc(HWND window, UINT message, WPARAM wp, LPARAM lp) {
@@ -15,18 +18,29 @@ static LRESULT CALLBACK window_proc(HWND window, UINT message, WPARAM wp, LPARAM
SendMessageW(list, WM_KEYDOWN, VK_DOWN, 1);
break;
case 3:
#ifdef WINE_ACCESS_DELPHI_FIXTURE
SendMessageW(list, WM_KEYDOWN, VK_SPACE, 1);
#else
SendMessageW(list, WM_KEYDOWN, VK_UP, 1);
#endif
break;
case 4: SetFocus(button); break;
case 5: SetFocus(list); break;
case 6: {
#ifdef WINE_ACCESS_DELPHI_FIXTURE
SendMessageW(list, WM_KEYDOWN, VK_SPACE, 1);
#else
LVITEMW item = {0};
item.pszText = L"Ready";
SendMessageW(list, LVM_SETITEMTEXTW, 0, (LPARAM)&item);
NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, list, OBJID_CLIENT, CHILDID_SELF);
#endif
break;
}
case 7: SendMessageW(list, LVM_DELETEALLITEMS, 0, 0); break;
#ifdef WINE_ACCESS_DELPHI_FIXTURE
case 8: SetFocus(okButton); break;
#endif
default: DestroyWindow(window);
}
return 0;
@@ -46,12 +60,32 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE previous, LPSTR args, int show)
RegisterClassW(&cls);
HWND window = CreateWindowW(cls.lpszClassName, L"Wine list fixture", WS_OVERLAPPEDWINDOW,
120, 120, 600, 300, NULL, NULL, instance, NULL);
button = CreateWindowW(L"Button", L"Return to control", WS_CHILD | WS_VISIBLE | WS_TABSTOP,
#ifdef WINE_ACCESS_DELPHI_FIXTURE
const WCHAR *nativeNames[] = {WC_LISTVIEWW, L"Button", L"Button", L"Static"};
const WCHAR *delphiNames[] = {L"TListView", L"TBitBtn", L"TButton", L"TStaticText"};
for (int i = 0; i < 4; ++i) {
WNDCLASSEXW subclass = {0};
subclass.cbSize = sizeof(subclass);
if (!GetClassInfoExW(NULL, nativeNames[i], &subclass)) return 1;
subclass.hInstance = instance;
subclass.lpszClassName = delphiNames[i];
if (!RegisterClassExW(&subclass)) return 2;
}
const WCHAR *buttonClass = L"TBitBtn", *listClass = L"TListView", *labelClass = L"TStaticText";
okButton = CreateWindowW(L"TButton", L"&OK", WS_CHILD | WS_VISIBLE | WS_TABSTOP,
240, 240, 120, 30, window, NULL, instance, NULL);
#else
const WCHAR *buttonClass = L"Button", *listClass = WC_LISTVIEWW, *labelClass = L"Static";
#endif
button = CreateWindowW(buttonClass, L"Return to control", WS_CHILD | WS_VISIBLE | WS_TABSTOP,
10, 240, 200, 30, window, NULL, instance, NULL);
CreateWindowW(L"Static", L"Required components", WS_CHILD | WS_VISIBLE,
CreateWindowW(labelClass, L"Required components", WS_CHILD | WS_VISIBLE,
10, 10, 550, 30, window, NULL, instance, NULL);
list = CreateWindowW(WC_LISTVIEWW, L"List1", WS_CHILD | WS_VISIBLE | WS_TABSTOP | LVS_REPORT,
list = CreateWindowW(listClass, L"List1", WS_CHILD | WS_VISIBLE | WS_TABSTOP | LVS_REPORT,
10, 50, 550, 180, window, NULL, instance, NULL);
#ifdef WINE_ACCESS_DELPHI_FIXTURE
SendMessageW(list, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
#endif
LVCOLUMNW column = {0};
column.mask = LVCF_TEXT | LVCF_WIDTH;
column.cx = 150;
+23 -3
View File
@@ -17,14 +17,14 @@ from gi.repository import Gio, GLib
parser = argparse.ArgumentParser()
parser.add_argument("--build-dir", default="build")
parser.add_argument("--session", action="store_true")
parser.add_argument("--fixture", choices=("menu", "edit", "notepad", "list", "winforms", "controls", "scintilla"), default="menu")
parser.add_argument("--fixture", choices=("menu", "edit", "notepad", "list", "delphi", "winforms", "controls", "scintilla"), default="menu")
parser.add_argument("--notepadpp-exe", type=Path)
parser.add_argument("--32-bit", dest="is32Bit", action="store_true")
parser.add_argument("--late-helper", action="store_true")
parser.add_argument("--restart-helper", action="store_true")
args = parser.parse_args()
if args.is32Bit and args.fixture not in ("list", "controls"):
parser.error("32-bit checks currently require --fixture list or controls")
if args.is32Bit and args.fixture not in ("list", "delphi", "controls"):
parser.error("32-bit checks currently require --fixture list, delphi or controls")
if (args.late_helper or args.restart_helper) and args.fixture not in ("edit", "winforms", "scintilla"):
parser.error("helper lifecycle checks require --fixture edit, winforms or scintilla")
if args.fixture == "scintilla" and (not args.notepadpp_exe or not args.notepadpp_exe.is_file()):
@@ -82,8 +82,11 @@ with tempfile.TemporaryDirectory(prefix="wine-access-menus-") as temporary:
fixture = Path(temporary) / "menu-fixture.exe"
compiler = "i686-w64-mingw32-gcc" if args.is32Bit else "x86_64-w64-mingw32-gcc"
sourceName = "edit" if args.fixture == "winforms" else args.fixture
if args.fixture == "delphi":
sourceName = "list"
subprocess.run([compiler, "-Wall", "-Wextra", "-mwindows",
*(["-DWINE_ACCESS_WINFORMS_FIXTURE"] if args.fixture == "winforms" else []),
*(["-DWINE_ACCESS_DELPHI_FIXTURE"] if args.fixture == "delphi" else []),
"-o", str(fixture), str(Path(__file__).with_name(sourceName + "_fixture.c")),
"-luser32", "-lcomctl32", "-loleacc", "-lole32"], check=True)
helper = None
@@ -160,6 +163,23 @@ with tempfile.TemporaryDirectory(prefix="wine-access-menus-") as temporary:
assert not any(e[2] == "Tree1" for e in events), "generic tree name leaked"
print("PASS: native/ATL tabs, tree selection/states/return, named button, combo and edit labels, empty controls")
sys.exit(0)
if args.fixture == "delphi":
for event in events:
print(event[1:9])
assert any(e[1] == "focus" and e[2] == "Required components" and
e[3] == "list" and e[4] == "Pending, Runtime & tools β" and
e[5] == "not checked" and e[7:9] == (1, 2) for e in events), "Delphi initial row/label/state missing"
rows = [e for e in events if e[3] == "list" and e[4] == "Installed, Second component"]
assert any(e[1] == "selection" and e[5] == "selected, not checked" for e in rows), "Delphi Down missing"
assert any(e[1] == "selection" and e[5] == "selected, checked" for e in rows), "Space checkbox change missing"
assert any(e[1] == "focus" and e[5] == "selected, checked" for e in rows), "Delphi return lost checkbox"
assert sum(e[1] == "selection" and e[5] == "selected, not checked" for e in rows) >= 2, "Space uncheck missing"
for caption in ("Return to control", "OK"):
assert any(e[1] == "focus" and e[2] == caption and e[3] == "button" for e in events), f"Delphi button missing: {caption}"
assert any(e[3] == "list" and e[4] == "" and e[5] == "" and e[7:9] == (0, 0) for e in events), "empty Delphi list retained state"
assert not any(e[2] == "List1" for e in events), "Delphi generic client leaked"
print("PASS: Delphi list labels, rows, keyboard navigation, checkbox toggles, return, buttons and empty state")
sys.exit(0)
if args.fixture == "list":
listEvents = [e for e in events if e[3] == "list"]
for event in listEvents: