mirror of
git://source.winehq.org/git/wine.git
synced 2024-08-31 23:23:39 +00:00
uiautomationcore: Implement NavigateDirection_{Previous/Next}Sibling for MSAA providers.
Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
parent
66b6786e8d
commit
163e9c5b45
|
@ -1112,13 +1112,13 @@ static void test_uia_prov_from_acc_navigation(void)
|
|||
elfrag2 = (void *)0xdeadbeef;
|
||||
hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_NextSibling, &elfrag2);
|
||||
ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!elfrag2, "elfrag2 != NULL\n");
|
||||
|
||||
elfrag2 = (void *)0xdeadbeef;
|
||||
hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_PreviousSibling, &elfrag2);
|
||||
ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!elfrag2, "elfrag2 != NULL\n");
|
||||
|
||||
/*
|
||||
|
@ -1149,18 +1149,16 @@ static void test_uia_prov_from_acc_navigation(void)
|
|||
SET_EXPECT(Accessible_get_accChild);
|
||||
SET_EXPECT(Accessible_get_accState);
|
||||
hr = IRawElementProviderFragment_Navigate(elfrag2, NavigateDirection_NextSibling, &elfrag3);
|
||||
todo_wine ok(Accessible.ref == 5, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
todo_wine ok(!!elfrag3, "elfrag2 == NULL\n");
|
||||
todo_wine CHECK_CALLED(Accessible_get_accChildCount);
|
||||
todo_wine CHECK_CALLED(Accessible_get_accChild);
|
||||
todo_wine CHECK_CALLED(Accessible_get_accState);
|
||||
if (elfrag3)
|
||||
{
|
||||
check_fragment_acc(elfrag3, &Accessible.IAccessible_iface, 3);
|
||||
IRawElementProviderFragment_Release(elfrag3);
|
||||
ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
}
|
||||
ok(Accessible.ref == 5, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!elfrag3, "elfrag2 == NULL\n");
|
||||
CHECK_CALLED(Accessible_get_accChildCount);
|
||||
CHECK_CALLED(Accessible_get_accChild);
|
||||
CHECK_CALLED(Accessible_get_accState);
|
||||
check_fragment_acc(elfrag3, &Accessible.IAccessible_iface, 3);
|
||||
|
||||
IRawElementProviderFragment_Release(elfrag3);
|
||||
ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
IRawElementProviderFragment_Release(elfrag2);
|
||||
ok(Accessible_child.ref == 1, "Unexpected refcnt %ld\n", Accessible_child.ref);
|
||||
ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
|
@ -1206,19 +1204,16 @@ static void test_uia_prov_from_acc_navigation(void)
|
|||
SET_EXPECT(Accessible_get_accChild);
|
||||
SET_EXPECT(Accessible_get_accState);
|
||||
hr = IRawElementProviderFragment_Navigate(elfrag2, NavigateDirection_PreviousSibling, &elfrag3);
|
||||
todo_wine ok(Accessible.ref == 5, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
todo_wine ok(!!elfrag3, "elfrag2 == NULL\n");
|
||||
todo_wine CHECK_CALLED(Accessible_get_accChildCount);
|
||||
todo_wine CHECK_CALLED(Accessible_get_accChild);
|
||||
todo_wine CHECK_CALLED(Accessible_get_accState);
|
||||
if (elfrag3)
|
||||
{
|
||||
check_fragment_acc(elfrag3, &Accessible.IAccessible_iface, 3);
|
||||
IRawElementProviderFragment_Release(elfrag3);
|
||||
ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
}
|
||||
ok(Accessible.ref == 5, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!elfrag3, "elfrag2 == NULL\n");
|
||||
CHECK_CALLED(Accessible_get_accChildCount);
|
||||
CHECK_CALLED(Accessible_get_accChild);
|
||||
CHECK_CALLED(Accessible_get_accState);
|
||||
check_fragment_acc(elfrag3, &Accessible.IAccessible_iface, 3);
|
||||
|
||||
IRawElementProviderFragment_Release(elfrag3);
|
||||
ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
IRawElementProviderFragment_Release(elfrag2);
|
||||
ok(Accessible_child2.ref == 1, "Unexpected refcnt %ld\n", Accessible_child2.ref);
|
||||
ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
|
@ -1338,21 +1333,21 @@ static void test_uia_prov_from_acc_navigation(void)
|
|||
SET_EXPECT(Accessible_child2_accLocation);
|
||||
SET_EXPECT(Accessible_child2_get_accName);
|
||||
hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_NextSibling, &elfrag2);
|
||||
todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!elfrag2, "elfrag2 != NULL\n");
|
||||
todo_wine CHECK_CALLED_MULTI(Accessible_get_accChildCount, 5);
|
||||
todo_wine CHECK_CALLED_MULTI(Accessible_get_accChild, 4);
|
||||
todo_wine CHECK_CALLED(Accessible_child_get_accParent);
|
||||
todo_wine CHECK_CALLED(Accessible_child_get_accRole);
|
||||
todo_wine CHECK_CALLED(Accessible_child_get_accState);
|
||||
todo_wine CHECK_CALLED(Accessible_child_get_accChildCount);
|
||||
todo_wine CHECK_CALLED(Accessible_child_accLocation);
|
||||
todo_wine CHECK_CALLED(Accessible_child_get_accName);
|
||||
todo_wine CHECK_CALLED(Accessible_child2_get_accRole);
|
||||
todo_wine CHECK_CALLED(Accessible_child2_get_accState);
|
||||
todo_wine CHECK_CALLED(Accessible_child2_get_accChildCount);
|
||||
todo_wine CHECK_CALLED(Accessible_child2_accLocation);
|
||||
todo_wine CHECK_CALLED(Accessible_child2_get_accName);
|
||||
CHECK_CALLED_MULTI(Accessible_get_accChildCount, 5);
|
||||
CHECK_CALLED_MULTI(Accessible_get_accChild, 4);
|
||||
CHECK_CALLED(Accessible_child_get_accParent);
|
||||
CHECK_CALLED(Accessible_child_get_accRole);
|
||||
CHECK_CALLED(Accessible_child_get_accState);
|
||||
CHECK_CALLED(Accessible_child_get_accChildCount);
|
||||
CHECK_CALLED(Accessible_child_accLocation);
|
||||
CHECK_CALLED(Accessible_child_get_accName);
|
||||
CHECK_CALLED(Accessible_child2_get_accRole);
|
||||
CHECK_CALLED(Accessible_child2_get_accState);
|
||||
CHECK_CALLED(Accessible_child2_get_accChildCount);
|
||||
CHECK_CALLED(Accessible_child2_accLocation);
|
||||
CHECK_CALLED(Accessible_child2_get_accName);
|
||||
|
||||
/* Now they have a role mismatch, we can determine our position. */
|
||||
set_accessible_props(&Accessible_child2, ROLE_SYSTEM_DOCUMENT, STATE_SYSTEM_FOCUSABLE, 1,
|
||||
|
@ -1369,27 +1364,27 @@ static void test_uia_prov_from_acc_navigation(void)
|
|||
* Even though we didn't get a new fragment, now that we know our
|
||||
* position, a reference is added to the parent IAccessible.
|
||||
*/
|
||||
todo_wine ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!elfrag2, "elfrag2 != NULL\n");
|
||||
todo_wine CHECK_CALLED_MULTI(Accessible_get_accChildCount, 6);
|
||||
todo_wine CHECK_CALLED_MULTI(Accessible_get_accChild, 5);
|
||||
todo_wine CHECK_CALLED(Accessible_get_accState);
|
||||
todo_wine CHECK_CALLED(Accessible_child_get_accParent);
|
||||
todo_wine CHECK_CALLED(Accessible_child_get_accRole);
|
||||
todo_wine CHECK_CALLED(Accessible_child2_get_accRole);
|
||||
CHECK_CALLED_MULTI(Accessible_get_accChildCount, 6);
|
||||
CHECK_CALLED_MULTI(Accessible_get_accChild, 5);
|
||||
CHECK_CALLED(Accessible_get_accState);
|
||||
CHECK_CALLED(Accessible_child_get_accParent);
|
||||
CHECK_CALLED(Accessible_child_get_accRole);
|
||||
CHECK_CALLED(Accessible_child2_get_accRole);
|
||||
|
||||
/* Now that we know our position, no extra nav work. */
|
||||
SET_EXPECT(Accessible_get_accChildCount);
|
||||
SET_EXPECT(Accessible_get_accChild);
|
||||
SET_EXPECT(Accessible_get_accState);
|
||||
hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_NextSibling, &elfrag2);
|
||||
todo_wine ok(Accessible.ref == 4, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
todo_wine ok(!!elfrag2, "elfrag2 == NULL\n");
|
||||
todo_wine CHECK_CALLED(Accessible_get_accChildCount);
|
||||
todo_wine CHECK_CALLED(Accessible_get_accChild);
|
||||
todo_wine CHECK_CALLED(Accessible_get_accState);
|
||||
ok(Accessible.ref == 4, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!elfrag2, "elfrag2 == NULL\n");
|
||||
CHECK_CALLED(Accessible_get_accChildCount);
|
||||
CHECK_CALLED(Accessible_get_accChild);
|
||||
CHECK_CALLED(Accessible_get_accState);
|
||||
if (elfrag2)
|
||||
{
|
||||
check_fragment_acc(elfrag2, &Accessible.IAccessible_iface, 3);
|
||||
|
@ -1449,23 +1444,20 @@ static void test_uia_prov_from_acc_navigation(void)
|
|||
SET_EXPECT(Accessible_child_accNavigate);
|
||||
SET_EXPECT(Accessible_child_get_accParent);
|
||||
hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_NextSibling, &elfrag2);
|
||||
todo_wine ok(Accessible_child.ref == 2, "Unexpected refcnt %ld\n", Accessible_child.ref);
|
||||
todo_wine ok(Accessible.ref == 4, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
todo_wine ok(!!elfrag2, "elfrag2 == NULL\n");
|
||||
todo_wine CHECK_CALLED(Accessible_get_accChildCount);
|
||||
todo_wine CHECK_CALLED(Accessible_get_accChild);
|
||||
todo_wine CHECK_CALLED(Accessible_child_get_accState);
|
||||
todo_wine CHECK_CALLED(Accessible_child_accNavigate);
|
||||
todo_wine CHECK_CALLED(Accessible_child_get_accParent);
|
||||
if (elfrag2)
|
||||
{
|
||||
check_fragment_acc(elfrag2, &Accessible_child.IAccessible_iface, CHILDID_SELF);
|
||||
IRawElementProviderFragment_Release(elfrag2);
|
||||
ok(Accessible_child.ref == 1, "Unexpected refcnt %ld\n", Accessible_child.ref);
|
||||
ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
}
|
||||
ok(Accessible_child.ref == 2, "Unexpected refcnt %ld\n", Accessible_child.ref);
|
||||
ok(Accessible.ref == 4, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!elfrag2, "elfrag2 == NULL\n");
|
||||
CHECK_CALLED(Accessible_get_accChildCount);
|
||||
CHECK_CALLED(Accessible_get_accChild);
|
||||
CHECK_CALLED(Accessible_child_get_accState);
|
||||
CHECK_CALLED(Accessible_child_accNavigate);
|
||||
CHECK_CALLED(Accessible_child_get_accParent);
|
||||
check_fragment_acc(elfrag2, &Accessible_child.IAccessible_iface, CHILDID_SELF);
|
||||
|
||||
IRawElementProviderFragment_Release(elfrag2);
|
||||
ok(Accessible_child.ref == 1, "Unexpected refcnt %ld\n", Accessible_child.ref);
|
||||
ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
IRawElementProviderFragment_Release(elfrag);
|
||||
IRawElementProviderSimple_Release(elprov);
|
||||
ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||
|
|
|
@ -223,7 +223,7 @@ static HRESULT msaa_acc_get_parent(IAccessible *acc, IAccessible **parent)
|
|||
#define DIR_FORWARD 0
|
||||
#define DIR_REVERSE 1
|
||||
static HRESULT msaa_acc_get_next_child(IAccessible *acc, LONG start_pos, LONG direction,
|
||||
IAccessible **child, LONG *child_id, LONG *child_pos)
|
||||
IAccessible **child, LONG *child_id, LONG *child_pos, BOOL check_visible)
|
||||
{
|
||||
LONG child_count, cur_pos;
|
||||
IDispatch *disp;
|
||||
|
@ -246,7 +246,7 @@ static HRESULT msaa_acc_get_next_child(IAccessible *acc, LONG start_pos, LONG di
|
|||
|
||||
if (hr == S_FALSE)
|
||||
{
|
||||
if (!msaa_check_acc_state(acc, cid, STATE_SYSTEM_INVISIBLE))
|
||||
if (!check_visible || !msaa_check_acc_state(acc, cid, STATE_SYSTEM_INVISIBLE))
|
||||
{
|
||||
*child = acc;
|
||||
*child_id = *child_pos = cur_pos;
|
||||
|
@ -264,7 +264,7 @@ static HRESULT msaa_acc_get_next_child(IAccessible *acc, LONG start_pos, LONG di
|
|||
break;
|
||||
|
||||
variant_init_i4(&cid, CHILDID_SELF);
|
||||
if (!msaa_check_acc_state(acc_child, cid, STATE_SYSTEM_INVISIBLE))
|
||||
if (!check_visible || !msaa_check_acc_state(acc_child, cid, STATE_SYSTEM_INVISIBLE))
|
||||
{
|
||||
*child = acc_child;
|
||||
*child_id = CHILDID_SELF;
|
||||
|
@ -287,6 +287,86 @@ static HRESULT msaa_acc_get_next_child(IAccessible *acc, LONG start_pos, LONG di
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT msaa_acc_get_child_pos(IAccessible *acc, IAccessible **out_parent,
|
||||
LONG *out_child_pos)
|
||||
{
|
||||
LONG child_count, child_id, child_pos, match_pos;
|
||||
IAccessible *child, *parent, *match, **children;
|
||||
HRESULT hr;
|
||||
int i;
|
||||
|
||||
*out_parent = NULL;
|
||||
*out_child_pos = 0;
|
||||
hr = msaa_acc_get_parent(acc, &parent);
|
||||
if (FAILED(hr) || !parent)
|
||||
return hr;
|
||||
|
||||
hr = IAccessible_get_accChildCount(parent, &child_count);
|
||||
if (FAILED(hr) || !child_count)
|
||||
{
|
||||
IAccessible_Release(parent);
|
||||
return hr;
|
||||
}
|
||||
|
||||
children = heap_alloc_zero(sizeof(*children) * child_count);
|
||||
if (!children)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
match = NULL;
|
||||
for (i = 0; i < child_count; i++)
|
||||
{
|
||||
hr = msaa_acc_get_next_child(parent, i + 1, DIR_FORWARD, &child, &child_id, &child_pos, FALSE);
|
||||
if (FAILED(hr) || !child)
|
||||
goto exit;
|
||||
|
||||
if (child != parent)
|
||||
children[i] = child;
|
||||
else
|
||||
IAccessible_Release(child);
|
||||
}
|
||||
|
||||
for (i = 0; i < child_count; i++)
|
||||
{
|
||||
if (!children[i])
|
||||
continue;
|
||||
|
||||
if (msaa_acc_compare(acc, children[i]))
|
||||
{
|
||||
if (!match)
|
||||
{
|
||||
match = children[i];
|
||||
match_pos = i + 1;
|
||||
}
|
||||
/* Can't have more than one IAccessible match. */
|
||||
else
|
||||
{
|
||||
match = NULL;
|
||||
match_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (match)
|
||||
{
|
||||
*out_parent = parent;
|
||||
*out_child_pos = match_pos;
|
||||
}
|
||||
else
|
||||
IAccessible_Release(parent);
|
||||
|
||||
for (i = 0; i < child_count; i++)
|
||||
{
|
||||
if (children[i])
|
||||
IAccessible_Release(children[i]);
|
||||
}
|
||||
|
||||
heap_free(children);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static LONG msaa_role_to_uia_control_type(LONG role)
|
||||
{
|
||||
switch (role)
|
||||
|
@ -649,10 +729,10 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
|
|||
|
||||
if (direction == NavigateDirection_FirstChild)
|
||||
hr = msaa_acc_get_next_child(msaa_prov->acc, 1, DIR_FORWARD, &acc, &child_id,
|
||||
&child_pos);
|
||||
&child_pos, TRUE);
|
||||
else
|
||||
hr = msaa_acc_get_next_child(msaa_prov->acc, child_count, DIR_REVERSE, &acc, &child_id,
|
||||
&child_pos);
|
||||
&child_pos, TRUE);
|
||||
|
||||
if (FAILED(hr) || !acc)
|
||||
break;
|
||||
|
@ -676,8 +756,53 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
|
|||
|
||||
case NavigateDirection_NextSibling:
|
||||
case NavigateDirection_PreviousSibling:
|
||||
FIXME("Unimplemented NavigateDirection %d\n", direction);
|
||||
return E_NOTIMPL;
|
||||
if (msaa_check_root_acc(msaa_prov))
|
||||
break;
|
||||
|
||||
if (!msaa_prov->parent)
|
||||
{
|
||||
if (V_I4(&msaa_prov->cid) != CHILDID_SELF)
|
||||
{
|
||||
msaa_prov->parent = msaa_prov->acc;
|
||||
IAccessible_AddRef(msaa_prov->acc);
|
||||
msaa_prov->child_pos = V_I4(&msaa_prov->cid);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = msaa_acc_get_child_pos(msaa_prov->acc, &acc, &child_pos);
|
||||
if (FAILED(hr) || !acc)
|
||||
break;
|
||||
msaa_prov->parent = acc;
|
||||
msaa_prov->child_pos = child_pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (direction == NavigateDirection_NextSibling)
|
||||
hr = msaa_acc_get_next_child(msaa_prov->parent, msaa_prov->child_pos + 1, DIR_FORWARD,
|
||||
&acc, &child_id, &child_pos, TRUE);
|
||||
else
|
||||
hr = msaa_acc_get_next_child(msaa_prov->parent, msaa_prov->child_pos - 1, DIR_REVERSE,
|
||||
&acc, &child_id, &child_pos, TRUE);
|
||||
|
||||
if (FAILED(hr) || !acc)
|
||||
break;
|
||||
|
||||
hr = UiaProviderFromIAccessible(acc, child_id, 0, &elprov);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
struct msaa_provider *prov = impl_from_msaa_provider(elprov);
|
||||
|
||||
*ret_val = &prov->IRawElementProviderFragment_iface;
|
||||
prov->parent = msaa_prov->parent;
|
||||
IAccessible_AddRef(msaa_prov->parent);
|
||||
if (acc != msaa_prov->acc)
|
||||
prov->child_pos = child_pos;
|
||||
else
|
||||
prov->child_pos = child_id;
|
||||
}
|
||||
IAccessible_Release(acc);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
FIXME("Invalid NavigateDirection %d\n", direction);
|
||||
|
|
Loading…
Reference in a new issue