From 9aad6748e048e544889e6612c8ffdf1a603da128 Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Sat, 10 Oct 2026 01:02:34 -0400 Subject: [PATCH] Coupple regressions fixed. --- README.md | 3 ++ .../ArchLinux/wine-access-git/PKGBUILD | 2 +- edit_hook.c | 4 ++- menu_bridge.h | 1 + tests/README.md | 10 ++++++- tests/menu_integration.py | 11 ++++++-- tests/notepad_fixture.c | 28 +++++++++++++++++++ 7 files changed, 54 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3bbde1a..581f3fa 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,9 @@ contents are excluded, and read-only edits do not report unsuccessful deletions. Undo refreshes the text snapshot used by subsequent navigation. It can attach to an already-focused editor and resume after the helper restarts. +Backspace reports only the removed text, such as `t`. Delete and Cut retain +their deletion feedback, such as `t deleted`. + Editor actions use `PresentAccessibleEvent` with event type `text`; actual focus uses `focus`. Cthulhu-Go must include the corresponding editor-event support so rapid actions and repeated characters bypass focus coalescing. UTF-16 selection diff --git a/distro-packages/ArchLinux/wine-access-git/PKGBUILD b/distro-packages/ArchLinux/wine-access-git/PKGBUILD index be64a04..eb7e100 100644 --- a/distro-packages/ArchLinux/wine-access-git/PKGBUILD +++ b/distro-packages/ArchLinux/wine-access-git/PKGBUILD @@ -1,6 +1,6 @@ # Maintainer: Storm Dragon pkgname=wine-access-git -pkgver=r8.gc5657ee +pkgver=r9.g39b7488 pkgrel=1 pkgdesc='Wine accessibility helper with MSAA, NVDA Controller, and Tolk compatibility for Cthulhu' arch=('x86_64') diff --git a/edit_hook.c b/edit_hook.c index cea0be6..318e4f9 100644 --- a/edit_hook.c +++ b/edit_hook.c @@ -175,7 +175,9 @@ static LRESULT CALLBACK edit_proc(HWND window, UINT message, WPARAM wp, LPARAM l (message == WM_CHAR && wp == VK_BACK) || (message == WM_KEYDOWN && wp == VK_DELETE))) { lstrcpynW(text, removed, 1024); - kind = WINE_ACCESS_TEXT_DELETED; report = TRUE; + kind = message == WM_CHAR && wp == VK_BACK + ? WINE_ACCESS_TEXT_BACKSPACED : WINE_ACCESS_TEXT_DELETED; + report = TRUE; } if (report) notify_text(window, kind, text, start, end); state->busy = FALSE; diff --git a/menu_bridge.h b/menu_bridge.h index 3da75d9..bf903d1 100644 --- a/menu_bridge.h +++ b/menu_bridge.h @@ -16,6 +16,7 @@ #define WINE_ACCESS_TEXT_DELETED 4 #define WINE_ACCESS_TEXT_READ 5 #define WINE_ACCESS_TEXT_PASSWORD 6 +#define WINE_ACCESS_TEXT_BACKSPACED 7 typedef struct WineAccessTextEvent { ULONGLONG owner; diff --git a/tests/README.md b/tests/README.md index f31b7c0..573d599 100644 --- a/tests/README.md +++ b/tests/README.md @@ -91,7 +91,7 @@ Close existing Notepad windows after saving any work so the updated hook can loa 5. Press Home, Shift+Right twice, then Shift+Left twice. Expect `s selected`, `e selected`, `e unselected`, `s unselected`. Focus stays in the edit area. Delete should say `s deleted`. Right followed by Backspace should say - `e deleted`; the second line is now `cond line`. + `e`; the second line is now `cond line`. 6. Press Alt to enter the menus and Escape to return (Escape again if needed). Expect menu labels while navigating and `edit, cond line` on return, not the start of the document. Arrows must continue to reach Notepad. @@ -104,3 +104,11 @@ not establish a routable editor buffer. Report the step, exact speech and braille, focused control, and any key that behaved differently. For unexpected results inspect `~/devel/cthulhu-go.log`; debug `Wine editor feedback` records include source IDs, native UTF-16 selection ranges, action kinds and output text. + +The Notepad fixture also opens the unsaved-document dialog and presses Tab, +Tab, Shift+Tab and Escape. It records the actual Yes/No/Cancel focus and state +sequence. Wine sends a focus-loss state event for the previous button before +the new focus event; the Go presenter must suppress that unchanged state +presentation. For live acceptance, change the document, close Notepad and +verify each Tab announces only the newly focused button, including reverse +navigation. Escape must return to the editor without discarding the document. diff --git a/tests/menu_integration.py b/tests/menu_integration.py index cf248ae..5c08509 100644 --- a/tests/menu_integration.py +++ b/tests/menu_integration.py @@ -105,6 +105,10 @@ with tempfile.TemporaryDirectory(prefix="wine-access-menus-") as temporary: elif event[1] == "text": assert event[0] == focused, f"text sent without establishing focus: {event!r}" if args.fixture == "notepad": + dialogEvents = [e for e in events if e[2] in ("Yes", "No", "Cancel")] + for event in dialogEvents: + print("Save dialog:", event[:7]) + assert [e[2] for e in dialogEvents if e[1] == "focus"] == ["Yes", "No", "Cancel", "No"], "save dialog focus order changed" text_events = [e for e in events if e[0].endswith(":text")] spoken = [e[2] for e in text_events] for expected in ("e", "l", "beta", "Notepad second line", "N selected", @@ -120,7 +124,7 @@ with tempfile.TemporaryDirectory(prefix="wine-access-menus-") as temporary: print(event[2:7]) spoken = [e[2] for e in text_events] for expected in ("l", "beta", "second line", "s selected", "e selected", - "e unselected", "s unselected", "s deleted", "e deleted", + "e unselected", "s unselected", "s deleted", "e", "alpha selected", "alpha deleted", "😀"): assert expected in spoken, f"missing editor feedback: {expected!r}" assert any(e[3] == "edit" and e[4] == "alpha beta" for e in text_events), "initial line missing" @@ -131,7 +135,10 @@ with tempfile.TemporaryDirectory(prefix="wine-access-menus-") as temporary: assert "hello deleted" not in spoken, "replacement misreported as deletion" assert sum(e[1] == "text" and e[2] == "l" for e in text_events) == 3, "rapid repeated letters lost" assert any(e[3] == "edit" and e[4] == "menu return line" for e in text_events), "menu return lost caret line" - assert spoken.count("new line deleted") == 2, "CRLF deletion feedback missing" + assert any(e[1] == "text" and e[2] == "e" and "kind=7" in e[5] for e in text_events), "Backspace did not report only the removed character" + assert "e deleted" not in spoken, "Backspace retained the deletion suffix" + assert sum(e[2] == "new line" and "kind=7" in e[5] for e in text_events) == 1, "CRLF Backspace feedback missing" + assert sum(e[2] == "new line deleted" and "kind=4" in e[5] for e in text_events) == 1, "CRLF Delete feedback missing" assert any(e[4] == "x" * 1022 for e in text_events), "truncated surrogate discarded line" assert "d" in spoken and "undo restored" in spoken, "Undo left stale text snapshot" print("PASS: editor focus, characters, words, lines, selection, deletion, Unicode, passwords, and read-only controls") diff --git a/tests/notepad_fixture.c b/tests/notepad_fixture.c index 7961780..d74ce0f 100644 --- a/tests/notepad_fixture.c +++ b/tests/notepad_fixture.c @@ -4,6 +4,20 @@ static DWORD notepad_pid; static HWND notepad; +static HWND saveDialog; + +static BOOL CALLBACK find_save_dialog(HWND window, LPARAM unused) { + (void)unused; + DWORD pid; + GetWindowThreadProcessId(window, &pid); + if (pid == notepad_pid && IsWindowVisible(window) && + GetDlgItem(window, IDYES) && GetDlgItem(window, IDNO) && + GetDlgItem(window, IDCANCEL)) { + saveDialog = window; + return FALSE; + } + return TRUE; +} static BOOL CALLBACK find_notepad(HWND window, LPARAM unused) { (void)unused; @@ -65,6 +79,20 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE previous, LPSTR args, int show) WCHAR text[80] = {0}; SendMessageW(edit, WM_GETTEXT, 80, (LPARAM)text); if (!lstrcmpW(text, L"hello beta\r\notepad second line")) result = 0; + PostMessageW(notepad, WM_CLOSE, 0, 0); + for (int i = 0; i < 100 && !saveDialog; ++i) { + EnumWindows(find_save_dialog, 0); + Sleep(50); + } + if (!saveDialog) result = 2; + else { + SetForegroundWindow(saveDialog); + Sleep(400); + key(VK_TAB, FALSE, FALSE); // Yes -> No + key(VK_TAB, FALSE, FALSE); // No -> Cancel + key(VK_TAB, FALSE, TRUE); // Cancel -> No + key(VK_ESCAPE, FALSE, FALSE); + } // Suppress the save prompt only in this test-owned, unsaved document. SendMessageW(edit, EM_SETMODIFY, FALSE, 0); PostMessageW(notepad, WM_CLOSE, 0, 0);