From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/uia_client.c | 2 +- dlls/uiautomationcore/uia_com_client.c | 87 ++++++++++++++++++++++++++ dlls/uiautomationcore/uia_private.h | 1 + 3 files changed, 89 insertions(+), 1 deletion(-)
diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index f7b602ab2ed..f57ffb4bc4c 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -2631,7 +2631,7 @@ static HRESULT uia_get_provider_from_hwnd(struct uia_node *node) return SendMessageW(client_thread.hwnd, WM_UIA_CLIENT_GET_NODE_PROV, (WPARAM)&args, (LPARAM)node); }
-static HRESULT create_uia_node_from_hwnd(HWND hwnd, HUIANODE *out_node, int node_flags) +HRESULT create_uia_node_from_hwnd(HWND hwnd, HUIANODE *out_node, int node_flags) { struct uia_node *node; HRESULT hr; diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 6d3d2216169..01272f89064 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -903,6 +903,7 @@ static HRESULT get_uia_cache_request_struct_from_iface(IUIAutomationCacheRequest */ static struct uia_com_event_handlers { + struct rb_tree handler_event_id_map; struct rb_tree handler_map;
LONG handler_count; @@ -917,6 +918,22 @@ static CRITICAL_SECTION_DEBUG com_event_handlers_cs_debug = }; static CRITICAL_SECTION com_event_handlers_cs = { &com_event_handlers_cs_debug, -1, 0, 0, 0, 0 };
+struct uia_event_handler_event_id_map_entry +{ + struct rb_entry entry; + int event_id; + + struct list handlers_list; +}; + +static int uia_com_event_handler_event_id_compare(const void *key, const struct rb_entry *entry) +{ + struct uia_event_handler_event_id_map_entry *event_entry = RB_ENTRY_VALUE(entry, struct uia_event_handler_event_id_map_entry, entry); + int event_id = *((int *)key); + + return (event_entry->event_id > event_id) - (event_entry->event_id < event_id); +} + struct uia_event_handler_identifier { IUnknown *handler_iface; SAFEARRAY *runtime_id; @@ -932,6 +949,9 @@ struct uia_event_handler_map_entry int event_id;
struct list handlers_list; + + struct uia_event_handler_event_id_map_entry *handler_event_id_map; + struct list handler_event_id_map_list_entry; };
static int uia_com_event_handler_id_compare(const void *key, const struct rb_entry *entry) @@ -1027,6 +1047,32 @@ HRESULT uia_com_win_event_callback(DWORD event_id, HWND hwnd, LONG obj_id, LONG break; }
+ case EVENT_OBJECT_FOCUS: + { + static const int uia_event_id = UIA_AutomationFocusChangedEventId; + struct rb_entry *rb_entry; + HRESULT hr; + + if (obj_id != OBJID_CLIENT) + break; + + EnterCriticalSection(&com_event_handlers_cs); + + if ((rb_entry = rb_get(&com_event_handlers.handler_event_id_map, &uia_event_id))) + { + HUIANODE node = NULL; + + 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"); + + UiaNodeRelease(node); + } + + LeaveCriticalSection(&com_event_handlers_cs); + break; + } + default: break; } @@ -1034,6 +1080,29 @@ HRESULT uia_com_win_event_callback(DWORD event_id, HWND hwnd, LONG obj_id, LONG return S_OK; }
+static HRESULT uia_event_handlers_add_handler_to_event_id_map(struct uia_event_handler_map_entry *event_map) +{ + struct uia_event_handler_event_id_map_entry *event_id_map; + struct rb_entry *rb_entry; + + if ((rb_entry = rb_get(&com_event_handlers.handler_event_id_map, &event_map->event_id))) + event_id_map = RB_ENTRY_VALUE(rb_entry, struct uia_event_handler_event_id_map_entry, entry); + else + { + if (!(event_id_map = calloc(1, sizeof(*event_id_map)))) + return E_OUTOFMEMORY; + + event_id_map->event_id = event_map->event_id; + list_init(&event_id_map->handlers_list); + rb_put(&com_event_handlers.handler_event_id_map, &event_map->event_id, &event_id_map->entry); + } + + list_add_tail(&event_id_map->handlers_list, &event_map->handler_event_id_map_list_entry); + event_map->handler_event_id_map = event_id_map; + + return S_OK; +} + static HRESULT uia_event_handlers_add_handler(IUnknown *handler_iface, SAFEARRAY *runtime_id, int event_id, struct uia_com_event *event) { @@ -1045,7 +1114,10 @@ static HRESULT uia_event_handlers_add_handler(IUnknown *handler_iface, SAFEARRAY EnterCriticalSection(&com_event_handlers_cs);
if (!com_event_handlers.handler_count) + { rb_init(&com_event_handlers.handler_map, uia_com_event_handler_id_compare); + rb_init(&com_event_handlers.handler_event_id_map, uia_com_event_handler_event_id_compare); + }
if ((rb_entry = rb_get(&com_event_handlers.handler_map, &event_ident))) event_map = RB_ENTRY_VALUE(rb_entry, struct uia_event_handler_map_entry, entry); @@ -1065,6 +1137,14 @@ static HRESULT uia_event_handlers_add_handler(IUnknown *handler_iface, SAFEARRAY }
event_map->event_id = event_id; + hr = uia_event_handlers_add_handler_to_event_id_map(event_map); + if (FAILED(hr)) + { + SafeArrayDestroy(event_map->runtime_id); + free(event_map); + goto exit; + } + event_map->handler_iface = handler_iface; IUnknown_AddRef(event_map->handler_iface);
@@ -1102,6 +1182,13 @@ static void uia_event_handler_map_entry_destroy(struct uia_event_handler_map_ent com_event_handlers.handler_count--; }
+ list_remove(&entry->handler_event_id_map_list_entry); + if (list_empty(&entry->handler_event_id_map->handlers_list)) + { + rb_remove(&com_event_handlers.handler_event_id_map, &entry->handler_event_id_map->entry); + free(entry->handler_event_id_map); + } + rb_remove(&com_event_handlers.handler_map, &entry->entry); IUnknown_Release(entry->handler_iface); SafeArrayDestroy(entry->runtime_id); diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 0a8f2d69dbd..0c4f1ee9dda 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -219,6 +219,7 @@ HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *out_node HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node, BOOL get_hwnd_providers, int node_flags) DECLSPEC_HIDDEN; HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode) DECLSPEC_HIDDEN; +HRESULT create_uia_node_from_hwnd(HWND hwnd, HUIANODE *out_node, int node_flags) DECLSPEC_HIDDEN; HRESULT uia_condition_check(HUIANODE node, struct UiaCondition *condition) DECLSPEC_HIDDEN; BOOL uia_condition_matched(HRESULT hr) DECLSPEC_HIDDEN;