// SPDX-License-Identifier: LGPL-2.1-or-later #pragma once #include #include #include #include #include #include #include struct ReviewFocus { std::string instance, window, focus, title, role; uint64_t revision = 0; bool protected_text = false; RECT bounds{}; }; struct ReviewRange { uint64_t start = 0, end = 0, utf16_start = 0, utf16_end = 0; std::string text; RECT bounds{}; }; struct ReviewNode { std::string id, parent, role, name; bool protected_text = false, visible = true, text_known = false, caret_known = false; uint64_t caret = 0, caret_utf16 = 0; RECT bounds{}; std::vector ranges; }; struct ReviewCapture { ReviewFocus source; std::string status = "unavailable"; std::vector nodes; }; // No native references are retained here. The event and capture STAs share // only lifetime tokens, protected by this mutex. class ReviewIdentityStore { public: ReviewIdentityStore(); ReviewFocus observe_foreground(); void destroyed(HWND, LONG object, LONG child); void reordered(HWND, LONG object); void retire(); std::string identity(HWND); private: struct State { std::mutex mutex; std::unordered_map identities; std::string instance, window, focus; uint64_t next = 0, revision = 0; }; // A detached stalled COM worker can retain this state safely until process // shutdown; it never borrows the event thread's stack or native references. std::shared_ptr state_; }; ReviewCapture capture_review_window(ReviewIdentityStore&, const ReviewFocus&, uint64_t deadline_tick);