Commit f26d4709 authored by Connor McAdams's avatar Connor McAdams Committed by Alexandre Julliard

uiautomationcore: Potentially raise focus event on the currently focused…

uiautomationcore: Potentially raise focus event on the currently focused serverside provider in response to EVENT_OBJECT_FOCUS. Signed-off-by: 's avatarConnor McAdams <cmcadams@codeweavers.com>
parent 2be7de98
......@@ -14681,6 +14681,12 @@ static void set_com_event_data(struct node_provider_desc *exp_node_desc)
SET_EXPECT(uia_com_event_callback);
}
static void push_expected_com_event(struct node_provider_desc *exp_node_desc)
{
push_event_queue_event(&ComEventData.exp_events, exp_node_desc);
SET_EXPECT_MULTI(uia_com_event_callback, ComEventData.exp_events.exp_event_count);
}
#define test_com_event_data( sender ) \
test_com_event_data_( (sender), __FILE__, __LINE__)
static void test_com_event_data_(IUIAutomationElement *sender, const char *file, int line)
......@@ -15560,6 +15566,12 @@ static void set_multi_event_data(struct node_provider_desc *exp_node_desc)
SET_EXPECT(uia_event_callback);
}
static void push_expected_event(struct node_provider_desc *exp_node_desc)
{
push_event_queue_event(&MultiEventData.exp_events, exp_node_desc);
SET_EXPECT_MULTI(uia_event_callback, MultiEventData.exp_events.exp_event_count);
}
static void WINAPI multi_uia_event_callback(struct UiaEventArgs *args, SAFEARRAY *req_data, BSTR tree_struct)
{
struct node_provider_desc *exp_desc;
......@@ -15696,6 +15708,72 @@ static void test_uia_com_focus_change_event_handler_win_event_handling(IUIAutoma
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
set_provider_prop_override(&Provider, NULL, 0);
/*
* The first time EVENT_OBJECT_FOCUS is raised for an HWND with a
* serverside provider UIA will query for the currently focused provider
* and raise a focus change event for it, alongside advising the root
* provider of focus change events being listened for. All subsequent
* EVENT_OBJECT_FOCUS events on the same HWND only query the root
* provider.
*/
initialize_provider(&Provider_child2, ProviderOptions_ServerSideProvider, NULL, TRUE);
Provider_child2.parent = &Provider2.IRawElementProviderFragment_iface;
Provider_child2.frag_root = &Provider2.IRawElementProviderFragmentRoot_iface;
Provider2.focus_prov = &Provider_child2.IRawElementProviderFragment_iface;
set_provider_runtime_id(&Provider_child2, UiaAppendRuntimeId, 2);
initialize_provider_advise_events_ids(&Provider2);
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), NULL);
add_provider_desc(&exp_node_desc, L"Main", L"Provider_child2", TRUE);
set_multi_event_data(&exp_node_desc);
set_com_event_data(&exp_node_desc);
/* Second event. */
init_node_provider_desc(&exp_nested_node_desc, GetCurrentProcessId(), test_child_hwnd);
add_provider_desc(&exp_nested_node_desc, L"Main", L"Provider2", TRUE);
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), test_child_hwnd);
add_provider_desc(&exp_node_desc, L"Hwnd", L"Provider_hwnd3", TRUE);
add_provider_desc(&exp_node_desc, L"Nonclient", L"Provider_nc3", FALSE);
add_nested_provider_desc(&exp_node_desc, L"Main", NULL, FALSE, &exp_nested_node_desc);
push_expected_event(&exp_node_desc);
push_expected_com_event(&exp_node_desc);
set_uia_hwnd_expects(0, 2, 2, 3, 0); /* Win11 sends 3 WM_GETOBJECT messages, normally only 2. */
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 4); /* Win11 sends 4 WM_GETOBJECT messages, normally only 3. */
NotifyWinEvent(EVENT_OBJECT_FOCUS, test_child_hwnd, OBJID_CLIENT, CHILDID_SELF);
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, FALSE, 2, FALSE, 2, TRUE, 0, FALSE);
CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 3);
CHECK_CALLED_MULTI(uia_com_event_callback, 2);
CHECK_CALLED_MULTI(uia_event_callback, 2);
/*
* Second time EVENT_OBJECT_FOCUS is raised for this HWND, only the root
* provider will have an event raised.
*/
init_node_provider_desc(&exp_nested_node_desc, GetCurrentProcessId(), test_child_hwnd);
add_provider_desc(&exp_nested_node_desc, L"Main", L"Provider2", TRUE);
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), test_child_hwnd);
add_provider_desc(&exp_node_desc, L"Hwnd", L"Provider_hwnd3", TRUE);
add_provider_desc(&exp_node_desc, L"Nonclient", L"Provider_nc3", FALSE);
add_nested_provider_desc(&exp_node_desc, L"Main", NULL, FALSE, &exp_nested_node_desc);
set_multi_event_data(&exp_node_desc);
set_com_event_data(&exp_node_desc);
set_uia_hwnd_expects(0, 2, 2, 3, 0); /* Win11 sends 3 WM_GETOBJECT messages, normally only 2. */
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 4); /* Win11 sends 4 WM_GETOBJECT messages, normally only 3. */
NotifyWinEvent(EVENT_OBJECT_FOCUS, test_child_hwnd, OBJID_CLIENT, CHILDID_SELF);
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, FALSE, 2, FALSE, 2, TRUE, 0, FALSE);
CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 3);
CHECK_CALLED(uia_com_event_callback);
CHECK_CALLED(uia_event_callback);
set_uia_hwnd_expects(0, 1, 1, 0, 0);
hr = IUIAutomation_RemoveFocusChangedEventHandler(uia_iface,
&FocusChangedHandler.IUIAutomationFocusChangedEventHandler_iface);
......
......@@ -91,7 +91,7 @@ library UIA_wine_private
HRESULT get_prov_opts([out, retval]int *out_opts);
HRESULT has_parent([out, retval]BOOL *out_val);
HRESULT navigate([in]int nav_dir, [out, retval]VARIANT *ret_val);
HRESULT get_focus([out, retval]VARIANT *ret_val);
HRESULT get_focus([in]long flags, [out, retval]VARIANT *ret_val);
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);
......
......@@ -347,7 +347,7 @@ static HRESULT get_navigate_from_node_provider(IWineUiaNode *node, int idx, int
return hr;
}
static HRESULT get_focus_from_node_provider(IWineUiaNode *node, int idx, VARIANT *ret_val)
HRESULT get_focus_from_node_provider(IWineUiaNode *node, int idx, LONG flags, VARIANT *ret_val)
{
IWineUiaProvider *prov;
HRESULT hr;
......@@ -357,7 +357,7 @@ static HRESULT get_focus_from_node_provider(IWineUiaNode *node, int idx, VARIANT
if (FAILED(hr))
return hr;
hr = IWineUiaProvider_get_focus(prov, ret_val);
hr = IWineUiaProvider_get_focus(prov, flags, ret_val);
IWineUiaProvider_Release(prov);
return hr;
......@@ -1836,7 +1836,7 @@ static HRESULT WINAPI uia_provider_navigate(IWineUiaProvider *iface, int nav_dir
return S_OK;
}
static HRESULT WINAPI uia_provider_get_focus(IWineUiaProvider *iface, VARIANT *out_val)
static HRESULT WINAPI uia_provider_get_focus(IWineUiaProvider *iface, LONG flags, VARIANT *out_val)
{
struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
IRawElementProviderFragmentRoot *elroot;
......@@ -1844,7 +1844,10 @@ static HRESULT WINAPI uia_provider_get_focus(IWineUiaProvider *iface, VARIANT *o
IRawElementProviderSimple *elprov;
HRESULT hr;
TRACE("%p, %p\n", iface, out_val);
TRACE("%p, %#lx, %p\n", iface, flags, out_val);
if (flags & PROV_METHOD_FLAG_RETURN_NODE_LRES)
FIXME("PROV_METHOD_FLAG_RETURN_NODE_LRES ignored for normal providers.\n");
VariantInit(out_val);
hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragmentRoot, (void **)&elroot);
......@@ -2357,7 +2360,7 @@ static HRESULT WINAPI uia_nested_node_provider_get_prop_val(IWineUiaProvider *if
{
HUIANODE node;
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node);
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node, 0);
if (FAILED(hr))
return hr;
......@@ -2406,7 +2409,7 @@ static HRESULT WINAPI uia_nested_node_provider_navigate(IWineUiaProvider *iface,
if (FAILED(hr) || V_VT(&v) == VT_EMPTY)
return hr;
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node);
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node, 0);
if (FAILED(hr))
return hr;
......@@ -2416,21 +2419,27 @@ static HRESULT WINAPI uia_nested_node_provider_navigate(IWineUiaProvider *iface,
return S_OK;
}
static HRESULT WINAPI uia_nested_node_provider_get_focus(IWineUiaProvider *iface, VARIANT *out_val)
static HRESULT WINAPI uia_nested_node_provider_get_focus(IWineUiaProvider *iface, LONG flags, VARIANT *out_val)
{
struct uia_nested_node_provider *prov = impl_from_nested_node_IWineUiaProvider(iface);
HUIANODE node;
HRESULT hr;
VARIANT v;
TRACE("%p, %p\n", iface, out_val);
TRACE("%p, %#lx, %p\n", iface, flags, out_val);
VariantInit(out_val);
hr = get_focus_from_node_provider(prov->nested_node, 0, &v);
hr = get_focus_from_node_provider(prov->nested_node, 0, 0, &v);
if (FAILED(hr) || V_VT(&v) == VT_EMPTY)
return hr;
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node);
if (flags & PROV_METHOD_FLAG_RETURN_NODE_LRES)
{
*out_val = v;
return S_OK;
}
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node, 0);
if (FAILED(hr))
return hr;
......@@ -2488,7 +2497,7 @@ static HRESULT WINAPI uia_nested_node_provider_create_node_from_prov(IWineUiaPro
return S_OK;
}
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node);
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node, 0);
if (FAILED(hr))
return hr;
......@@ -2631,14 +2640,14 @@ static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESU
return S_OK;
}
HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode)
HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode, int node_flags)
{
struct uia_node *node;
HRESULT hr;
*huianode = NULL;
hr = create_uia_node(&node, 0);
hr = create_uia_node(&node, node_flags);
if (FAILED(hr))
{
uia_node_lresult_release(lr);
......@@ -2804,7 +2813,7 @@ static HRESULT get_focused_uia_node(HUIANODE in_node, HUIANODE *out_node)
(get_node_provider_type_at_idx(node, i) == PROV_TYPE_HWND)))
continue;
hr = get_focus_from_node_provider(&node->IWineUiaNode_iface, i, &v);
hr = get_focus_from_node_provider(&node->IWineUiaNode_iface, i, 0, &v);
if (FAILED(hr))
break;
......
......@@ -1013,7 +1013,7 @@ static HRESULT uia_com_focus_win_event_callback(struct uia_event *event, void *u
return hr;
}
static void uia_com_focus_handler_advise_node(struct uia_com_event *event, HUIANODE node, HWND hwnd)
static BOOL uia_com_focus_handler_advise_node(struct uia_com_event *event, HUIANODE node, HWND hwnd)
{
HRESULT hr;
......@@ -1021,12 +1021,15 @@ static void uia_com_focus_handler_advise_node(struct uia_com_event *event, HUIAN
if (FAILED(hr))
{
WARN("uia_event_advise_node failed with hr %#lx\n", hr);
return;
goto exit;
}
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);
exit:
return SUCCEEDED(hr);
}
static void uia_com_focus_win_event_handler(HUIANODE node, HWND hwnd, struct uia_event_handler_event_id_map_entry *event_id_map)
......@@ -1041,8 +1044,26 @@ static void uia_com_focus_win_event_handler(HUIANODE node, HWND hwnd, struct uia
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))
uia_com_focus_handler_advise_node(event, node, hwnd);
if (uia_hwnd_map_check_hwnd(&event->focus_hwnd_map, hwnd) ||
!uia_com_focus_handler_advise_node(event, node, hwnd))
continue;
hr = get_focus_from_node_provider((IWineUiaNode *)node, 0, PROV_METHOD_FLAG_RETURN_NODE_LRES, &v);
if (V_VT(&v) == VT_I4)
{
HUIANODE focus_node = NULL;
hr = uia_node_from_lresult(V_I4(&v), &focus_node, NODE_FLAG_IGNORE_CLIENTSIDE_HWND_PROVS);
if (SUCCEEDED(hr))
{
hr = uia_event_for_each(UIA_AutomationFocusChangedEventId, uia_com_focus_win_event_callback,
(void *)focus_node, TRUE);
if (FAILED(hr))
WARN("uia_event_for_each on focus_node failed with hr %#lx\n", hr);
}
UiaNodeRelease(focus_node);
}
VariantClear(&v);
}
}
......
......@@ -595,7 +595,7 @@ static HRESULT uia_raise_clientside_event(struct uia_queue_uia_event *event)
HRESULT hr;
node = nav_start_node = NULL;
hr = uia_node_from_lresult(event->u.clientside.node, &node);
hr = uia_node_from_lresult(event->u.clientside.node, &node, 0);
if (FAILED(hr))
{
WARN("Failed to create node from lresult, hr %#lx\n", hr);
......@@ -605,7 +605,7 @@ static HRESULT uia_raise_clientside_event(struct uia_queue_uia_event *event)
if (event->u.clientside.nav_start_node)
{
hr = uia_node_from_lresult(event->u.clientside.nav_start_node, &nav_start_node);
hr = uia_node_from_lresult(event->u.clientside.nav_start_node, &nav_start_node, 0);
if (FAILED(hr))
{
WARN("Failed to create nav_start_node from lresult, hr %#lx\n", hr);
......
......@@ -216,6 +216,7 @@ enum provider_method_flags {
/* uia_client.c */
int get_node_provider_type_at_idx(struct uia_node *node, int idx) DECLSPEC_HIDDEN;
HRESULT get_focus_from_node_provider(IWineUiaNode *node, int idx, LONG flags, VARIANT *ret_val) 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;
......@@ -224,7 +225,7 @@ 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;
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 uia_node_from_lresult(LRESULT lr, HUIANODE *huianode, int node_flags) DECLSPEC_HIDDEN;
void uia_node_lresult_release(LRESULT lr) 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;
......
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