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
@@ -163,6 +163,13 @@ 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
|
even when the labels were created after the fields. Application-owned MSAA
|
||||||
lists retain their own names, roles and item data.
|
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 and 32-bit menu/editor hooks remain outside
|
||||||
|
this support.
|
||||||
|
|
||||||
Control values and window titles retain literal ampersands. Button and static
|
Control values and window titles retain literal ampersands. Button and static
|
||||||
label captions decode keyboard mnemonics and escaped `&&`; static labels with
|
label captions decode keyboard mnemonics and escaped `&&`; static labels with
|
||||||
`SS_NOPREFIX` retain their literal text.
|
`SS_NOPREFIX` retain their literal text.
|
||||||
|
|||||||
@@ -7,6 +7,16 @@
|
|||||||
// not edits merely because their name contains EDIT somewhere.
|
// not edits merely because their name contains EDIT somewhere.
|
||||||
static inline BOOL wine_access_class_matches(const WCHAR *className, const WCHAR *nativeName) {
|
static inline BOOL wine_access_class_matches(const WCHAR *className, const WCHAR *nativeName) {
|
||||||
if (lstrcmpiW(className, nativeName) == 0) return TRUE;
|
if (lstrcmpiW(className, nativeName) == 0) return TRUE;
|
||||||
|
// Delphi VCL registers native subclasses under its own class names.
|
||||||
|
// Keep aliases explicit: an arbitrary T-prefixed custom control need not
|
||||||
|
// implement the corresponding Windows control messages.
|
||||||
|
if (lstrcmpiW(nativeName, L"SysListView32") == 0 &&
|
||||||
|
lstrcmpiW(className, L"TListView") == 0) return TRUE;
|
||||||
|
if (lstrcmpiW(nativeName, L"Button") == 0 &&
|
||||||
|
(lstrcmpiW(className, L"TButton") == 0 ||
|
||||||
|
lstrcmpiW(className, L"TBitBtn") == 0)) return TRUE;
|
||||||
|
if (lstrcmpiW(nativeName, L"Static") == 0 &&
|
||||||
|
lstrcmpiW(className, L"TStaticText") == 0) return TRUE;
|
||||||
if (lstrlenW(className) > 4 &&
|
if (lstrlenW(className) > 4 &&
|
||||||
CompareStringOrdinal(className, 4, L"ATL:", 4, TRUE) == CSTR_EQUAL &&
|
CompareStringOrdinal(className, 4, L"ATL:", 4, TRUE) == CSTR_EQUAL &&
|
||||||
lstrcmpiW(className + 4, nativeName) == 0) return TRUE;
|
lstrcmpiW(className + 4, nativeName) == 0) return TRUE;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Maintainer: Storm Dragon <storm_dragon@stormux.org>
|
# Maintainer: Storm Dragon <storm_dragon@stormux.org>
|
||||||
pkgname=wine-access-git
|
pkgname=wine-access-git
|
||||||
pkgver=r17.gcbce835
|
pkgver=r18.gdf7879a
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc='Wine accessibility helper with MSAA, NVDA Controller, and Tolk compatibility for Cthulhu'
|
pkgdesc='Wine accessibility helper with MSAA, NVDA Controller, and Tolk compatibility for Cthulhu'
|
||||||
arch=('x86_64')
|
arch=('x86_64')
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ ListViewRow read_list_view(HWND window) {
|
|||||||
DWORD_PTR state = 0;
|
DWORD_PTR state = 0;
|
||||||
if (query(window, LVM_GETITEMSTATE, row.index, LVIS_SELECTED, &state))
|
if (query(window, LVM_GETITEMSTATE, row.index, LVIS_SELECTED, &state))
|
||||||
row.selected = state & LVIS_SELECTED;
|
row.selected = state & LVIS_SELECTED;
|
||||||
|
row.checked = list_view_checked(window, row.index);
|
||||||
native_control::RemoteBuffer remote(window, bufferSize);
|
native_control::RemoteBuffer remote(window, bufferSize);
|
||||||
if (!remote) return row;
|
if (!remote) return row;
|
||||||
const bool wow64 = remote.is32Bit();
|
const bool wow64 = remote.is32Bit();
|
||||||
@@ -104,3 +105,15 @@ ListViewRow read_list_view(HWND window) {
|
|||||||
}
|
}
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int list_view_checked(HWND window, int index) {
|
||||||
|
DWORD_PTR style = 0, state = 0;
|
||||||
|
if (index < 0 ||
|
||||||
|
!query(window, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0, &style) ||
|
||||||
|
!(style & LVS_EX_CHECKBOXES) ||
|
||||||
|
!query(window, LVM_GETITEMSTATE, index, LVIS_STATEIMAGEMASK, &state))
|
||||||
|
return -1;
|
||||||
|
const DWORD_PTR image = (state & LVIS_STATEIMAGEMASK) >> 12;
|
||||||
|
// Other state images are application-defined; do not invent a check state.
|
||||||
|
return image == 1 ? 0 : image == 2 ? 1 : -1;
|
||||||
|
}
|
||||||
@@ -8,8 +8,10 @@ struct ListViewRow {
|
|||||||
int index = -1;
|
int index = -1;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
bool selected = false;
|
bool selected = false;
|
||||||
|
int checked = -1; // -1: no standard checkbox, 0: unchecked, 1: checked.
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_list_view(HWND window);
|
bool is_list_view(HWND window);
|
||||||
ListViewRow read_list_view(HWND window);
|
ListViewRow read_list_view(HWND window);
|
||||||
int list_view_index(HWND window, int *count);
|
int list_view_index(HWND window, int *count);
|
||||||
|
int list_view_checked(HWND window, int index);
|
||||||
@@ -38,6 +38,7 @@ HWND lastListControl = nullptr;
|
|||||||
int lastListIndex = -1;
|
int lastListIndex = -1;
|
||||||
int lastListCount = 0;
|
int lastListCount = 0;
|
||||||
bool lastListSelected = false;
|
bool lastListSelected = false;
|
||||||
|
int lastListChecked = -1;
|
||||||
HWND lastNativeControl = nullptr;
|
HWND lastNativeControl = nullptr;
|
||||||
NativeItemKey lastNativeItem;
|
NativeItemKey lastNativeItem;
|
||||||
|
|
||||||
@@ -332,10 +333,15 @@ ControlDescription describe_standard_control(HWND window) {
|
|||||||
if (!row.text.empty()) control.position = row.index + 1;
|
if (!row.text.empty()) control.position = row.index + 1;
|
||||||
control.count = row.count;
|
control.count = row.count;
|
||||||
if (row.selected) control.states = "selected";
|
if (row.selected) control.states = "selected";
|
||||||
|
if (row.checked >= 0) {
|
||||||
|
if (!control.states.empty()) control.states += ", ";
|
||||||
|
control.states += row.checked ? "checked" : "not checked";
|
||||||
|
}
|
||||||
lastListControl = window;
|
lastListControl = window;
|
||||||
lastListIndex = row.index;
|
lastListIndex = row.index;
|
||||||
lastListCount = row.count;
|
lastListCount = row.count;
|
||||||
lastListSelected = row.selected;
|
lastListSelected = row.selected;
|
||||||
|
lastListChecked = row.checked;
|
||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,6 +433,7 @@ void poll_control_focus(bool refresh = false) {
|
|||||||
lastListIndex = -1;
|
lastListIndex = -1;
|
||||||
lastListCount = 0;
|
lastListCount = 0;
|
||||||
lastListSelected = false;
|
lastListSelected = false;
|
||||||
|
lastListChecked = -1;
|
||||||
const auto key = native_item_key(info.hwndFocus);
|
const auto key = native_item_key(info.hwndFocus);
|
||||||
if (info.hwndFocus != lastNativeControl) {
|
if (info.hwndFocus != lastNativeControl) {
|
||||||
present_standard_focus(info.hwndFocus);
|
present_standard_focus(info.hwndFocus);
|
||||||
@@ -448,9 +455,11 @@ void poll_control_focus(bool refresh = false) {
|
|||||||
SendMessageTimeoutW(info.hwndFocus, LVM_GETITEMSTATE, index, LVIS_SELECTED,
|
SendMessageTimeoutW(info.hwndFocus, LVM_GETITEMSTATE, index, LVIS_SELECTED,
|
||||||
SMTO_ABORTIFHUNG, 100, &state);
|
SMTO_ABORTIFHUNG, 100, &state);
|
||||||
const bool selected = state & LVIS_SELECTED;
|
const bool selected = state & LVIS_SELECTED;
|
||||||
|
const int checked = list_view_checked(info.hwndFocus, index);
|
||||||
if (info.hwndFocus != lastListControl) {
|
if (info.hwndFocus != lastListControl) {
|
||||||
present_standard_focus(info.hwndFocus);
|
present_standard_focus(info.hwndFocus);
|
||||||
} else if (refresh || index != lastListIndex || count != lastListCount || selected != lastListSelected) {
|
} else if (refresh || index != lastListIndex || count != lastListCount ||
|
||||||
|
selected != lastListSelected || checked != lastListChecked) {
|
||||||
const auto control = describe_standard_control(info.hwndFocus);
|
const auto control = describe_standard_control(info.hwndFocus);
|
||||||
present_accessible_event(source_id(info.hwndFocus, "standard"), "selection",
|
present_accessible_event(source_id(info.hwndFocus, "standard"), "selection",
|
||||||
control, window_title(info.hwndFocus));
|
control, window_title(info.hwndFocus));
|
||||||
@@ -461,6 +470,7 @@ void poll_control_focus(bool refresh = false) {
|
|||||||
lastListIndex = -1;
|
lastListIndex = -1;
|
||||||
lastListCount = 0;
|
lastListCount = 0;
|
||||||
lastListSelected = false;
|
lastListSelected = false;
|
||||||
|
lastListChecked = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void present_menu_event(const WineAccessMenuEvent &event) {
|
void present_menu_event(const WineAccessMenuEvent &event) {
|
||||||
|
|||||||
@@ -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
|
native list, normal menus, editor navigation, switching to a native Linux
|
||||||
application, and reader shutdown. Verify speech and physical braille separately.
|
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
|
## Native tabs, trees and named clients
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
+37
-3
@@ -5,6 +5,9 @@
|
|||||||
#include <commctrl.h>
|
#include <commctrl.h>
|
||||||
|
|
||||||
static HWND list, button;
|
static HWND list, button;
|
||||||
|
#ifdef WINE_ACCESS_DELPHI_FIXTURE
|
||||||
|
static HWND okButton;
|
||||||
|
#endif
|
||||||
static int step;
|
static int step;
|
||||||
|
|
||||||
static LRESULT CALLBACK window_proc(HWND window, UINT message, WPARAM wp, LPARAM lp) {
|
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);
|
SendMessageW(list, WM_KEYDOWN, VK_DOWN, 1);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
|
#ifdef WINE_ACCESS_DELPHI_FIXTURE
|
||||||
|
SendMessageW(list, WM_KEYDOWN, VK_SPACE, 1);
|
||||||
|
#else
|
||||||
SendMessageW(list, WM_KEYDOWN, VK_UP, 1);
|
SendMessageW(list, WM_KEYDOWN, VK_UP, 1);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case 4: SetFocus(button); break;
|
case 4: SetFocus(button); break;
|
||||||
case 5: SetFocus(list); break;
|
case 5: SetFocus(list); break;
|
||||||
case 6: {
|
case 6: {
|
||||||
|
#ifdef WINE_ACCESS_DELPHI_FIXTURE
|
||||||
|
SendMessageW(list, WM_KEYDOWN, VK_SPACE, 1);
|
||||||
|
#else
|
||||||
LVITEMW item = {0};
|
LVITEMW item = {0};
|
||||||
item.pszText = L"Ready";
|
item.pszText = L"Ready";
|
||||||
SendMessageW(list, LVM_SETITEMTEXTW, 0, (LPARAM)&item);
|
SendMessageW(list, LVM_SETITEMTEXTW, 0, (LPARAM)&item);
|
||||||
NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, list, OBJID_CLIENT, CHILDID_SELF);
|
NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, list, OBJID_CLIENT, CHILDID_SELF);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 7: SendMessageW(list, LVM_DELETEALLITEMS, 0, 0); break;
|
case 7: SendMessageW(list, LVM_DELETEALLITEMS, 0, 0); break;
|
||||||
|
#ifdef WINE_ACCESS_DELPHI_FIXTURE
|
||||||
|
case 8: SetFocus(okButton); break;
|
||||||
|
#endif
|
||||||
default: DestroyWindow(window);
|
default: DestroyWindow(window);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -46,12 +60,32 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE previous, LPSTR args, int show)
|
|||||||
RegisterClassW(&cls);
|
RegisterClassW(&cls);
|
||||||
HWND window = CreateWindowW(cls.lpszClassName, L"Wine list fixture", WS_OVERLAPPEDWINDOW,
|
HWND window = CreateWindowW(cls.lpszClassName, L"Wine list fixture", WS_OVERLAPPEDWINDOW,
|
||||||
120, 120, 600, 300, NULL, NULL, instance, NULL);
|
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);
|
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);
|
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);
|
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};
|
LVCOLUMNW column = {0};
|
||||||
column.mask = LVCF_TEXT | LVCF_WIDTH;
|
column.mask = LVCF_TEXT | LVCF_WIDTH;
|
||||||
column.cx = 150;
|
column.cx = 150;
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ from gi.repository import Gio, GLib
|
|||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--build-dir", default="build")
|
parser.add_argument("--build-dir", default="build")
|
||||||
parser.add_argument("--session", action="store_true")
|
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("--notepadpp-exe", type=Path)
|
||||||
parser.add_argument("--32-bit", dest="is32Bit", action="store_true")
|
parser.add_argument("--32-bit", dest="is32Bit", action="store_true")
|
||||||
parser.add_argument("--late-helper", action="store_true")
|
parser.add_argument("--late-helper", action="store_true")
|
||||||
parser.add_argument("--restart-helper", action="store_true")
|
parser.add_argument("--restart-helper", action="store_true")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
if args.is32Bit and args.fixture not in ("list", "controls"):
|
if args.is32Bit and args.fixture not in ("list", "delphi", "controls"):
|
||||||
parser.error("32-bit checks currently require --fixture list or 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"):
|
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")
|
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()):
|
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"
|
fixture = Path(temporary) / "menu-fixture.exe"
|
||||||
compiler = "i686-w64-mingw32-gcc" if args.is32Bit else "x86_64-w64-mingw32-gcc"
|
compiler = "i686-w64-mingw32-gcc" if args.is32Bit else "x86_64-w64-mingw32-gcc"
|
||||||
sourceName = "edit" if args.fixture == "winforms" else args.fixture
|
sourceName = "edit" if args.fixture == "winforms" else args.fixture
|
||||||
|
if args.fixture == "delphi":
|
||||||
|
sourceName = "list"
|
||||||
subprocess.run([compiler, "-Wall", "-Wextra", "-mwindows",
|
subprocess.run([compiler, "-Wall", "-Wextra", "-mwindows",
|
||||||
*(["-DWINE_ACCESS_WINFORMS_FIXTURE"] if args.fixture == "winforms" else []),
|
*(["-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")),
|
"-o", str(fixture), str(Path(__file__).with_name(sourceName + "_fixture.c")),
|
||||||
"-luser32", "-lcomctl32", "-loleacc", "-lole32"], check=True)
|
"-luser32", "-lcomctl32", "-loleacc", "-lole32"], check=True)
|
||||||
helper = None
|
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"
|
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")
|
print("PASS: native/ATL tabs, tree selection/states/return, named button, combo and edit labels, empty controls")
|
||||||
sys.exit(0)
|
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":
|
if args.fixture == "list":
|
||||||
listEvents = [e for e in events if e[3] == "list"]
|
listEvents = [e for e in events if e[3] == "list"]
|
||||||
for event in listEvents:
|
for event in listEvents:
|
||||||
|
|||||||
Reference in new issue
Block a user