Goldwave helped find more missing functionality.
This commit is contained in:
1 parent
df7879acb5
commit
67ebc28d15
9 files changed
+134
-8
No files matched your search
@@ -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
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in new issue
Block a user