From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 4 +-- dlls/uiautomationcore/uia_com_client.c | 40 +++++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index d5f8bb492a4..4523e09693f 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -15420,12 +15420,12 @@ static void test_uia_com_event_handler_event_advisement(IUIAutomation *uia_iface set_uia_hwnd_expects(0, 1, 1, 2, 0); /* Only Win11 sends WM_GETOBJECT 2 times. */
NotifyWinEvent(EVENT_OBJECT_FOCUS, test_child_hwnd, OBJID_CLIENT, CHILDID_SELF); - todo_wine ok(msg_wait_for_all_events(method_event, 1, 2000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n"); + ok(msg_wait_for_all_events(method_event, 1, 2000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n"); if (wait_for_clientside_callbacks(2000)) trace("Kept getting callbacks up until timeout\n");
check_uia_hwnd_expects_at_most(0, 1, 1, 2, 0); CHECK_CALLED_AT_MOST(child_winproc_GETOBJECT_UiaRoot, 3); - test_provider_event_advise_added(&Provider2, UIA_AutomationFocusChangedEventId, TRUE); + test_provider_event_advise_added(&Provider2, UIA_AutomationFocusChangedEventId, FALSE); test_provider_event_advise_added(&Provider_hwnd3, 0, FALSE); test_provider_event_advise_added(&Provider_nc3, 0, FALSE);
diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 01272f89064..b6e06d21935 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -974,10 +974,37 @@ struct uia_com_event { HUIAEVENT event; BOOL from_cui8;
+ struct rb_tree focus_hwnd_map; struct list event_handler_map_list_entry; struct uia_event_handler_map_entry *handler_map; };
+static void uia_com_focus_win_event_handler(HUIANODE node, HWND hwnd, struct uia_event_handler_event_id_map_entry *event_id_map) +{ + struct uia_event_handler_map_entry *entry; + HRESULT hr; + + LIST_FOR_EACH_ENTRY(entry, &event_id_map->handlers_list, struct uia_event_handler_map_entry, handler_event_id_map_list_entry) + { + struct uia_com_event *event; + + LIST_FOR_EACH_ENTRY(event, &entry->handlers_list, struct uia_com_event, event_handler_map_list_entry) + { + if (uia_hwnd_map_check_hwnd(&event->focus_hwnd_map, hwnd)) + continue; + + /* Advise provider that we're listening for focus events. */ + hr = uia_event_advise_node((struct uia_event *)event->event, node); + if (FAILED(hr)) + WARN("uia_event_advise_node failed with hr %#lx\n", hr); + + hr = uia_hwnd_map_add_hwnd(&event->focus_hwnd_map, hwnd); + if (FAILED(hr)) + WARN("Failed to add hwnd for focus winevent, hr %#lx\n", hr); + } + } +} + HRESULT uia_com_win_event_callback(DWORD event_id, HWND hwnd, LONG obj_id, LONG child_id, DWORD thread_id, DWORD event_time) { LONG handler_count; @@ -1060,11 +1087,13 @@ HRESULT uia_com_win_event_callback(DWORD event_id, HWND hwnd, LONG obj_id, LONG
if ((rb_entry = rb_get(&com_event_handlers.handler_event_id_map, &uia_event_id))) { + struct uia_event_handler_event_id_map_entry *event_id_map; HUIANODE node = NULL;
+ event_id_map = RB_ENTRY_VALUE(rb_entry, struct uia_event_handler_event_id_map_entry, entry); hr = create_uia_node_from_hwnd(hwnd, &node, NODE_FLAG_IGNORE_CLIENTSIDE_HWND_PROVS); if (SUCCEEDED(hr)) - FIXME("EVENT_OBJECT_FOCUS event advisement currently unimplemented\n"); + uia_com_focus_win_event_handler(node, hwnd, event_id_map);
UiaNodeRelease(node); } @@ -1155,6 +1184,13 @@ static HRESULT uia_event_handlers_add_handler(IUnknown *handler_iface, SAFEARRAY list_add_tail(&event_map->handlers_list, &event->event_handler_map_list_entry); event->handler_map = event_map; com_event_handlers.handler_count++; + if (event_id == UIA_AutomationFocusChangedEventId) + { + GUITHREADINFO info = { sizeof(info) }; + + if (GetGUIThreadInfo(0, &info) && info.hwndFocus) + uia_hwnd_map_add_hwnd(&event->focus_hwnd_map, info.hwndFocus); + }
exit: LeaveCriticalSection(&com_event_handlers_cs); @@ -1165,6 +1201,7 @@ exit: static void uia_event_handler_destroy(struct uia_com_event *event) { list_remove(&event->event_handler_map_list_entry); + uia_hwnd_map_destroy(&event->focus_hwnd_map); if (event->event) UiaRemoveEvent(event->event); if (event->git_cookie) @@ -3459,6 +3496,7 @@ static HRESULT uia_add_com_event_handler(IUIAutomation6 *iface, EVENTID event_id
com_event->from_cui8 = element->from_cui8; list_init(&com_event->event_handler_map_list_entry); + uia_hwnd_map_init(&com_event->focus_hwnd_map);
hr = IUnknown_QueryInterface(handler_unk, handler_riid, (void **)&handler_iface); if (FAILED(hr))