Synchronous AccessibleObjectFromEvent and IAccessible property queries on the helper's WinEvent thread could block native typing and focus feedback while an application-owned accessibility provider stopped responding. Move those calls into MsaaEventReader, a single COM worker that owns its native references and exchanges copied requests and results with the event thread. Bound both queues to 32 entries, invalidate queued work on focus or foreground changes, and discard results older than 500 ms. Validate the window, process, thread, generation, and foreground relationship before presenting a result. Read protected state before querying accessible values. Reject unrelated background presentation events before invoking providers or invalidating foreground work. Preserve accessible events from visible popups owned by the foreground window. Keep existing native menu, editor, combo, list, and item-control paths, and use native focus fallback when an MSAA focus request expires or fails. Poll completed results from the existing event timer. On shutdown, retire pending work and wait at most 100 ms for the worker; a blocked COM call keeps only its own state until it completes or the helper process exits. Never spawn additional workers behind an unresponsive provider. Validation: CMake configure/build and git diff --check passed. On a private dummy Xorg display, all four CTest checks passed, as did six event-stall runs (default, --32-bit, --getter, --background, --popup, --reader orca) and the existing menu, edit, controls, and list fixtures in both 64-bit and 32-bit modes. See the accompanying regression-test commit for commands. Private recording-service fixtures do not establish audible speech, physical braille, or acceptance of every live MUSHclient workflow. A provider that never returns occupies the single MSAA worker until helper exit.
40 lines
1.1 KiB
C++
40 lines
1.1 KiB
C++
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
#pragma once
|
|
#include <windows.h>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
// Native focus owners can keep keyboard focus while their visible popup
|
|
// reports accessible item focus. Unrelated windows are never event sources.
|
|
bool msaa_event_in_foreground(HWND window);
|
|
|
|
struct MsaaEvent {
|
|
HWND window = nullptr;
|
|
DWORD event = 0, process = 0, thread = 0;
|
|
LONG object = 0, child = 0;
|
|
uint64_t generation = 0, deadline = 0;
|
|
};
|
|
struct MsaaResult {
|
|
MsaaEvent source;
|
|
bool available = false, native_client = false, password = false;
|
|
std::string name, role, value, states, description;
|
|
LONG count = 0;
|
|
};
|
|
|
|
// One COM worker owns native references. The event thread exchanges only
|
|
// copied requests/results, and never waits for a provider to finish.
|
|
class MsaaEventReader {
|
|
public:
|
|
~MsaaEventReader();
|
|
bool start();
|
|
void invalidate(uint64_t generation);
|
|
void submit(const MsaaEvent &event);
|
|
bool take(MsaaResult &result);
|
|
void stop();
|
|
private:
|
|
struct State;
|
|
std::shared_ptr<State> state_;
|
|
HANDLE worker_ = nullptr;
|
|
};
|