Commit 2be7de98 authored by Connor McAdams's avatar Connor McAdams Committed by Alexandre Julliard

uiautomationcore: Potentially raise focus event for serverside providers in…

uiautomationcore: Potentially raise focus event for serverside providers in response to EVENT_OBJECT_FOCUS. Signed-off-by: 's avatarConnor McAdams <cmcadams@codeweavers.com>
parent 5a987d48
......@@ -15659,11 +15659,11 @@ static void test_uia_com_focus_change_event_handler_win_event_handling(IUIAutoma
set_uia_hwnd_expects(0, 2, 2, 4, 0); /* Win11 sends 4 WM_GETOBJECT messages, normally only 3. */
NotifyWinEvent(EVENT_OBJECT_FOCUS, test_hwnd, OBJID_CLIENT, CHILDID_SELF);
todo_wine ok(msg_wait_for_all_events(event_handles, 2, 5000) != WAIT_TIMEOUT, "Wait for event_handle(s) timed out.\n");
ok(msg_wait_for_all_events(event_handles, 2, 5000) != WAIT_TIMEOUT, "Wait for event_handle(s) timed out.\n");
if (wait_for_clientside_callbacks(2000)) trace("Kept getting callbacks up until timeout\n");
check_uia_hwnd_expects_at_least(0, FALSE, 2, TRUE, 2, TRUE, 3, TRUE, 0, FALSE);
todo_wine CHECK_CALLED(uia_com_event_callback);
todo_wine CHECK_CALLED(uia_event_callback);
check_uia_hwnd_expects_at_least(0, FALSE, 2, FALSE, 2, FALSE, 3, FALSE, 0, FALSE);
CHECK_CALLED(uia_com_event_callback);
CHECK_CALLED(uia_event_callback);
/*
* Child ID is ignored when translating EVENT_OBJECT_FOCUS events into
......@@ -15674,11 +15674,11 @@ static void test_uia_com_focus_change_event_handler_win_event_handling(IUIAutoma
set_uia_hwnd_expects(0, 2, 2, 4, 0); /* Win11 sends 4 WM_GETOBJECT messages, normally only 3. */
NotifyWinEvent(EVENT_OBJECT_FOCUS, test_hwnd, OBJID_CLIENT, -1);
todo_wine ok(msg_wait_for_all_events(event_handles, 2, 5000) != WAIT_TIMEOUT, "Wait for event_handle(s) timed out.\n");
ok(msg_wait_for_all_events(event_handles, 2, 5000) != WAIT_TIMEOUT, "Wait for event_handle(s) timed out.\n");
if (wait_for_clientside_callbacks(2000)) trace("Kept getting callbacks up until timeout\n");
check_uia_hwnd_expects_at_least(0, FALSE, 2, TRUE, 2, TRUE, 3, TRUE, 0, FALSE);
todo_wine CHECK_CALLED(uia_com_event_callback);
todo_wine CHECK_CALLED(uia_event_callback);
check_uia_hwnd_expects_at_least(0, FALSE, 2, FALSE, 2, FALSE, 3, FALSE, 0, FALSE);
CHECK_CALLED(uia_com_event_callback);
CHECK_CALLED(uia_event_callback);
/*
* UIA queries the serverside provider for UIA_HasKeyboardFocusPropertyId.
......
......@@ -95,6 +95,7 @@ library UIA_wine_private
HRESULT attach_event([in]LONG_PTR huiaevent);
HRESULT respond_to_win_event([in]DWORD win_event, [in]ULONG hwnd, [in]LONG obj_id, [in]LONG child_id,
[in]IProxyProviderWinEventSink *sink);
HRESULT create_node_from_prov([in]long flags, [out, retval]VARIANT *ret_val);
}
[
......
......@@ -394,6 +394,22 @@ HRESULT respond_to_win_event_on_node_provider(IWineUiaNode *node, int idx, DWORD
return hr;
}
HRESULT create_node_from_node_provider(IWineUiaNode *node, int idx, LONG flags, VARIANT *ret_val)
{
IWineUiaProvider *prov;
HRESULT hr;
VariantInit(ret_val);
hr = IWineUiaNode_get_provider(node, idx, &prov);
if (FAILED(hr))
return hr;
hr = IWineUiaProvider_create_node_from_prov(prov, flags, ret_val);
IWineUiaProvider_Release(prov);
return hr;
}
/*
* IWineUiaNode interface.
*/
......@@ -1972,6 +1988,26 @@ static HRESULT WINAPI uia_provider_respond_to_win_event(IWineUiaProvider *iface,
return hr;
}
static HRESULT WINAPI uia_provider_create_node_from_prov(IWineUiaProvider *iface, LONG flags, VARIANT *ret_val)
{
struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
IRawElementProviderSimple *elprov;
HRESULT hr;
TRACE("%p, %#lx, %p\n", iface, flags, ret_val);
if (flags & PROV_METHOD_FLAG_RETURN_NODE_LRES)
FIXME("PROV_METHOD_FLAG_RETURN_NODE_LRES ignored for normal providers.\n");
VariantInit(ret_val);
hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderSimple, (void **)&elprov);
if (FAILED(hr))
return hr;
/* get_variant_for_elprov_node will release our provider upon failure. */
return get_variant_for_elprov_node(elprov, prov->return_nested_node, prov->refuse_hwnd_node_providers, ret_val);
}
static const IWineUiaProviderVtbl uia_provider_vtbl = {
uia_provider_QueryInterface,
uia_provider_AddRef,
......@@ -1983,6 +2019,7 @@ static const IWineUiaProviderVtbl uia_provider_vtbl = {
uia_provider_get_focus,
uia_provider_attach_event,
uia_provider_respond_to_win_event,
uia_provider_create_node_from_prov,
};
static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov,
......@@ -2431,6 +2468,36 @@ static HRESULT WINAPI uia_nested_node_provider_respond_to_win_event(IWineUiaProv
return E_FAIL;
}
static HRESULT WINAPI uia_nested_node_provider_create_node_from_prov(IWineUiaProvider *iface, LONG flags, VARIANT *ret_val)
{
struct uia_nested_node_provider *prov = impl_from_nested_node_IWineUiaProvider(iface);
HUIANODE node;
HRESULT hr;
VARIANT v;
TRACE("%p, %#lx, %p\n", iface, flags, ret_val);
VariantInit(ret_val);
hr = create_node_from_node_provider(prov->nested_node, 0, 0, &v);
if (FAILED(hr) || V_VT(&v) == VT_EMPTY)
return hr;
if (flags & PROV_METHOD_FLAG_RETURN_NODE_LRES)
{
*ret_val = v;
return S_OK;
}
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node);
if (FAILED(hr))
return hr;
get_variant_for_node(node, ret_val);
VariantClear(&v);
return S_OK;
}
static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = {
uia_nested_node_provider_QueryInterface,
uia_nested_node_provider_AddRef,
......@@ -2442,6 +2509,7 @@ static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = {
uia_nested_node_provider_get_focus,
uia_nested_node_provider_attach_event,
uia_nested_node_provider_respond_to_win_event,
uia_nested_node_provider_create_node_from_prov,
};
static BOOL is_nested_node_provider(IWineUiaProvider *iface)
......
......@@ -979,6 +979,40 @@ struct uia_com_event {
struct uia_event_handler_map_entry *handler_map;
};
static HRESULT uia_com_focus_win_event_callback(struct uia_event *event, void *user_data)
{
struct uia_node *node = impl_from_IWineUiaNode((IWineUiaNode *)user_data);
VARIANT v, v2;
HRESULT hr;
/* Only match desktop events. */
if (!event->desktop_subtree_event)
return S_OK;
VariantInit(&v);
VariantInit(&v2);
hr = create_node_from_node_provider(&node->IWineUiaNode_iface, 0, PROV_METHOD_FLAG_RETURN_NODE_LRES, &v);
if (FAILED(hr))
{
WARN("Failed to create new node lres with hr %#lx\n", hr);
return hr;
}
if (V_VT(&v) == VT_I4)
{
hr = IWineUiaEvent_raise_event(&event->IWineUiaEvent_iface, v, v2);
if (FAILED(hr))
{
WARN("raise_event failed with hr %#lx\n", hr);
uia_node_lresult_release(V_I4(&v));
}
}
VariantClear(&v);
return hr;
}
static void uia_com_focus_handler_advise_node(struct uia_com_event *event, HUIANODE node, HWND hwnd)
{
HRESULT hr;
......@@ -998,6 +1032,8 @@ static void uia_com_focus_handler_advise_node(struct uia_com_event *event, HUIAN
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;
VARIANT v;
LIST_FOR_EACH_ENTRY(entry, &event_id_map->handlers_list, struct uia_event_handler_map_entry, handler_event_id_map_list_entry)
{
......@@ -1009,6 +1045,17 @@ static void uia_com_focus_win_event_handler(HUIANODE node, HWND hwnd, struct uia
uia_com_focus_handler_advise_node(event, node, hwnd);
}
}
VariantInit(&v);
hr = UiaGetPropertyValue(node, UIA_HasKeyboardFocusPropertyId, &v);
if (SUCCEEDED(hr) && (V_VT(&v) == VT_BOOL && V_BOOL(&v) == VARIANT_TRUE))
{
hr = uia_event_for_each(UIA_AutomationFocusChangedEventId, uia_com_focus_win_event_callback, (void *)node, TRUE);
if (FAILED(hr))
WARN("uia_event_for_each failed with hr %#lx\n", hr);
}
VariantClear(&v);
}
HRESULT uia_com_win_event_callback(DWORD event_id, HWND hwnd, LONG obj_id, LONG child_id, DWORD thread_id, DWORD event_time)
......
......@@ -252,8 +252,7 @@ static void uia_event_map_entry_release(struct uia_event_map_entry *entry)
}
}
typedef HRESULT UiaWineEventForEachCallback(struct uia_event *, void *);
static HRESULT uia_event_for_each(int event_id, UiaWineEventForEachCallback *callback, void *user_data,
HRESULT uia_event_for_each(int event_id, UiaWineEventForEachCallback *callback, void *user_data,
BOOL clientside_only)
{
struct uia_event_map_entry *event_entry;
......
......@@ -158,6 +158,7 @@ struct uia_event
};
typedef HRESULT UiaWineEventCallback(struct uia_event *, struct uia_event_args *, SAFEARRAY *, BSTR);
typedef HRESULT UiaWineEventForEachCallback(struct uia_event *, void *);
static inline void variant_init_bool(VARIANT *v, BOOL val)
{
......@@ -209,10 +210,15 @@ static inline BOOL uia_array_reserve(void **elements, SIZE_T *capacity, SIZE_T c
return TRUE;
}
enum provider_method_flags {
PROV_METHOD_FLAG_RETURN_NODE_LRES = 0x0001,
};
/* uia_client.c */
int get_node_provider_type_at_idx(struct uia_node *node, int idx) DECLSPEC_HIDDEN;
HRESULT respond_to_win_event_on_node_provider(IWineUiaNode *node, int idx, DWORD win_event, HWND hwnd, LONG obj_id,
LONG child_id, IProxyProviderWinEventSink *sink) DECLSPEC_HIDDEN;
HRESULT create_node_from_node_provider(IWineUiaNode *node, int idx, LONG flags, VARIANT *ret_val) DECLSPEC_HIDDEN;
HRESULT attach_event_to_uia_node(HUIANODE node, struct uia_event *event) DECLSPEC_HIDDEN;
HRESULT clone_uia_node(HUIANODE in_node, HUIANODE *out_node) DECLSPEC_HIDDEN;
HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *out_node) DECLSPEC_HIDDEN;
......@@ -231,6 +237,8 @@ HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) DECLSPEC_HIDDEN;
/* uia_event.c */
HRESULT uia_event_add_win_event_hwnd(struct uia_event *event, HWND hwnd) DECLSPEC_HIDDEN;
HRESULT uia_event_for_each(int event_id, UiaWineEventForEachCallback *callback, void *user_data,
BOOL clientside_only) DECLSPEC_HIDDEN;
BOOL uia_clientside_event_start_event_thread(struct uia_event *event) DECLSPEC_HIDDEN;
HRESULT create_serverside_uia_event(struct uia_event **out_event, LONG process_id, LONG event_cookie) DECLSPEC_HIDDEN;
HRESULT uia_event_add_provider_event_adviser(IRawElementProviderAdviseEvents *advise_events,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment