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

uiautomationcore: Implement UIA_ControlTypePropertyId for MSAA providers.

parent e3349cef
......@@ -58,6 +58,7 @@ static HRESULT (WINAPI *pUiaProviderFromIAccessible)(IAccessible *, long, DWORD,
DEFINE_EXPECT(winproc_GETOBJECT_CLIENT);
DEFINE_EXPECT(Accessible_accNavigate);
DEFINE_EXPECT(Accessible_get_accParent);
DEFINE_EXPECT(Accessible_get_accRole);
DEFINE_EXPECT(Accessible_child_accNavigate);
DEFINE_EXPECT(Accessible_child_get_accParent);
......@@ -80,6 +81,7 @@ static struct Accessible
IAccessible *parent;
HWND acc_hwnd;
HWND ow_hwnd;
INT role;
} Accessible, Accessible_child;
static inline struct Accessible* impl_from_Accessible(IAccessible *iface)
......@@ -197,7 +199,18 @@ static HRESULT WINAPI Accessible_get_accDescription(IAccessible *iface, VARIANT
static HRESULT WINAPI Accessible_get_accRole(IAccessible *iface, VARIANT child_id,
VARIANT *out_role)
{
ok(0, "unexpected call\n");
struct Accessible *This = impl_from_Accessible(iface);
ok(This == &Accessible, "unexpected call\n");
CHECK_EXPECT(Accessible_get_accRole);
if (This->role)
{
V_VT(out_role) = VT_I4;
V_I4(out_role) = This->role;
return S_OK;
}
return E_NOTIMPL;
}
......@@ -395,7 +408,8 @@ static struct Accessible Accessible =
{ &OleWindowVtbl },
1,
NULL,
0, 0
0, 0,
0,
};
static struct Accessible Accessible_child =
{
......@@ -403,7 +417,8 @@ static struct Accessible Accessible_child =
{ &OleWindowVtbl },
1,
&Accessible.IAccessible_iface,
0, 0
0, 0,
0,
};
static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
......@@ -662,6 +677,153 @@ static void test_uia_reserved_value_ifaces(void)
CoUninitialize();
}
struct msaa_role_uia_type {
INT acc_role;
INT uia_control_type;
};
static const struct msaa_role_uia_type msaa_role_uia_types[] = {
{ ROLE_SYSTEM_TITLEBAR, UIA_TitleBarControlTypeId },
{ ROLE_SYSTEM_MENUBAR, UIA_MenuBarControlTypeId },
{ ROLE_SYSTEM_SCROLLBAR, UIA_ScrollBarControlTypeId },
{ ROLE_SYSTEM_GRIP, UIA_ThumbControlTypeId },
{ ROLE_SYSTEM_WINDOW, UIA_WindowControlTypeId },
{ ROLE_SYSTEM_MENUPOPUP, UIA_MenuControlTypeId },
{ ROLE_SYSTEM_MENUITEM, UIA_MenuItemControlTypeId },
{ ROLE_SYSTEM_TOOLTIP, UIA_ToolTipControlTypeId },
{ ROLE_SYSTEM_APPLICATION, UIA_WindowControlTypeId },
{ ROLE_SYSTEM_DOCUMENT, UIA_DocumentControlTypeId },
{ ROLE_SYSTEM_PANE, UIA_PaneControlTypeId },
{ ROLE_SYSTEM_GROUPING, UIA_GroupControlTypeId },
{ ROLE_SYSTEM_SEPARATOR, UIA_SeparatorControlTypeId },
{ ROLE_SYSTEM_TOOLBAR, UIA_ToolBarControlTypeId },
{ ROLE_SYSTEM_STATUSBAR, UIA_StatusBarControlTypeId },
{ ROLE_SYSTEM_TABLE, UIA_TableControlTypeId },
{ ROLE_SYSTEM_COLUMNHEADER, UIA_HeaderControlTypeId },
{ ROLE_SYSTEM_ROWHEADER, UIA_HeaderControlTypeId },
{ ROLE_SYSTEM_CELL, UIA_DataItemControlTypeId },
{ ROLE_SYSTEM_LINK, UIA_HyperlinkControlTypeId },
{ ROLE_SYSTEM_LIST, UIA_ListControlTypeId },
{ ROLE_SYSTEM_LISTITEM, UIA_ListItemControlTypeId },
{ ROLE_SYSTEM_OUTLINE, UIA_TreeControlTypeId },
{ ROLE_SYSTEM_OUTLINEITEM, UIA_TreeItemControlTypeId },
{ ROLE_SYSTEM_PAGETAB, UIA_TabItemControlTypeId },
{ ROLE_SYSTEM_INDICATOR, UIA_ThumbControlTypeId },
{ ROLE_SYSTEM_GRAPHIC, UIA_ImageControlTypeId },
{ ROLE_SYSTEM_STATICTEXT, UIA_TextControlTypeId },
{ ROLE_SYSTEM_TEXT, UIA_EditControlTypeId },
{ ROLE_SYSTEM_PUSHBUTTON, UIA_ButtonControlTypeId },
{ ROLE_SYSTEM_CHECKBUTTON, UIA_CheckBoxControlTypeId },
{ ROLE_SYSTEM_RADIOBUTTON, UIA_RadioButtonControlTypeId },
{ ROLE_SYSTEM_COMBOBOX, UIA_ComboBoxControlTypeId },
{ ROLE_SYSTEM_PROGRESSBAR, UIA_ProgressBarControlTypeId },
{ ROLE_SYSTEM_SLIDER, UIA_SliderControlTypeId },
{ ROLE_SYSTEM_SPINBUTTON, UIA_SpinnerControlTypeId },
{ ROLE_SYSTEM_BUTTONDROPDOWN, UIA_SplitButtonControlTypeId },
{ ROLE_SYSTEM_BUTTONMENU, UIA_MenuItemControlTypeId },
{ ROLE_SYSTEM_BUTTONDROPDOWNGRID, UIA_ButtonControlTypeId },
{ ROLE_SYSTEM_PAGETABLIST, UIA_TabControlTypeId },
{ ROLE_SYSTEM_SPLITBUTTON, UIA_SplitButtonControlTypeId },
/* These accessible roles have no equivalent in UI Automation. */
{ ROLE_SYSTEM_SOUND, 0 },
{ ROLE_SYSTEM_CURSOR, 0 },
{ ROLE_SYSTEM_CARET, 0 },
{ ROLE_SYSTEM_ALERT, 0 },
{ ROLE_SYSTEM_CLIENT, 0 },
{ ROLE_SYSTEM_CHART, 0 },
{ ROLE_SYSTEM_DIALOG, 0 },
{ ROLE_SYSTEM_BORDER, 0 },
{ ROLE_SYSTEM_COLUMN, 0 },
{ ROLE_SYSTEM_ROW, 0 },
{ ROLE_SYSTEM_HELPBALLOON, 0 },
{ ROLE_SYSTEM_CHARACTER, 0 },
{ ROLE_SYSTEM_PROPERTYPAGE, 0 },
{ ROLE_SYSTEM_DROPLIST, 0 },
{ ROLE_SYSTEM_DIAL, 0 },
{ ROLE_SYSTEM_HOTKEYFIELD, 0 },
{ ROLE_SYSTEM_DIAGRAM, 0 },
{ ROLE_SYSTEM_ANIMATION, 0 },
{ ROLE_SYSTEM_EQUATION, 0 },
{ ROLE_SYSTEM_WHITESPACE, 0 },
{ ROLE_SYSTEM_IPADDRESS, 0 },
{ ROLE_SYSTEM_OUTLINEBUTTON, 0 },
};
static void test_uia_prov_from_acc_properties(void)
{
IRawElementProviderSimple *elprov;
HRESULT hr;
VARIANT v;
int i;
/* MSAA role to UIA control type test. */
for (i = 0; i < ARRAY_SIZE(msaa_role_uia_types); i++)
{
const struct msaa_role_uia_type *role = &msaa_role_uia_types[i];
/*
* Roles get cached once a valid one is mapped, so create a new
* element for each role.
*/
hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
Accessible.role = role->acc_role;
SET_EXPECT(Accessible_get_accRole);
VariantClear(&v);
hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_ControlTypePropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
if (role->uia_control_type)
ok(check_variant_i4(&v, role->uia_control_type), "MSAA role %d: V_I4(&v) = %ld\n", role->acc_role, V_I4(&v));
else
ok(V_VT(&v) == VT_EMPTY, "MSAA role %d: V_VT(&v) = %d\n", role->acc_role, V_VT(&v));
CHECK_CALLED(Accessible_get_accRole);
if (!role->uia_control_type)
SET_EXPECT(Accessible_get_accRole);
VariantClear(&v);
hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_ControlTypePropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
if (role->uia_control_type)
ok(check_variant_i4(&v, role->uia_control_type), "MSAA role %d: V_I4(&v) = %ld\n", role->acc_role, V_I4(&v));
else
ok(V_VT(&v) == VT_EMPTY, "MSAA role %d: V_VT(&v) = %d\n", role->acc_role, V_VT(&v));
if (!role->uia_control_type)
CHECK_CALLED(Accessible_get_accRole);
IRawElementProviderSimple_Release(elprov);
ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
}
/* ROLE_SYSTEM_CLOCK has no mapping in Windows < 10 1809. */
hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
Accessible.role = ROLE_SYSTEM_CLOCK;
SET_EXPECT(Accessible_get_accRole);
VariantClear(&v);
hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_ControlTypePropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(check_variant_i4(&v, UIA_ButtonControlTypeId) || broken(V_VT(&v) == VT_EMPTY), /* Windows < 10 1809 */
"MSAA role %d: V_I4(&v) = %ld\n", Accessible.role, V_I4(&v));
CHECK_CALLED(Accessible_get_accRole);
if (V_VT(&v) == VT_EMPTY)
SET_EXPECT(Accessible_get_accRole);
VariantClear(&v);
hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_ControlTypePropertyId, &v);
ok(check_variant_i4(&v, UIA_ButtonControlTypeId) || broken(V_VT(&v) == VT_EMPTY), /* Windows < 10 1809 */
"MSAA role %d: V_I4(&v) = %ld\n", Accessible.role, V_I4(&v));
if (V_VT(&v) == VT_EMPTY)
CHECK_CALLED(Accessible_get_accRole);
Accessible.role = 0;
IRawElementProviderSimple_Release(elprov);
ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
}
static void test_UiaProviderFromIAccessible(void)
{
IRawElementProviderSimple *elprov;
......@@ -781,6 +943,8 @@ static void test_UiaProviderFromIAccessible(void)
IRawElementProviderSimple_Release(elprov);
ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
test_uia_prov_from_acc_properties();
DestroyWindow(hwnd);
UnregisterClassA("pUiaProviderFromIAccessible class", NULL);
Accessible.acc_hwnd = NULL;
......
......@@ -32,6 +32,85 @@ static void variant_init_i4(VARIANT *v, int val)
V_I4(v) = val;
}
static LONG msaa_role_to_uia_control_type(LONG role)
{
switch (role)
{
case ROLE_SYSTEM_TITLEBAR: return UIA_TitleBarControlTypeId;
case ROLE_SYSTEM_MENUBAR: return UIA_MenuBarControlTypeId;
case ROLE_SYSTEM_SCROLLBAR: return UIA_ScrollBarControlTypeId;
case ROLE_SYSTEM_INDICATOR:
case ROLE_SYSTEM_GRIP: return UIA_ThumbControlTypeId;
case ROLE_SYSTEM_APPLICATION:
case ROLE_SYSTEM_WINDOW: return UIA_WindowControlTypeId;
case ROLE_SYSTEM_MENUPOPUP: return UIA_MenuControlTypeId;
case ROLE_SYSTEM_TOOLTIP: return UIA_ToolTipControlTypeId;
case ROLE_SYSTEM_DOCUMENT: return UIA_DocumentControlTypeId;
case ROLE_SYSTEM_PANE: return UIA_PaneControlTypeId;
case ROLE_SYSTEM_GROUPING: return UIA_GroupControlTypeId;
case ROLE_SYSTEM_SEPARATOR: return UIA_SeparatorControlTypeId;
case ROLE_SYSTEM_TOOLBAR: return UIA_ToolBarControlTypeId;
case ROLE_SYSTEM_STATUSBAR: return UIA_StatusBarControlTypeId;
case ROLE_SYSTEM_TABLE: return UIA_TableControlTypeId;
case ROLE_SYSTEM_COLUMNHEADER:
case ROLE_SYSTEM_ROWHEADER: return UIA_HeaderControlTypeId;
case ROLE_SYSTEM_CELL: return UIA_DataItemControlTypeId;
case ROLE_SYSTEM_LINK: return UIA_HyperlinkControlTypeId;
case ROLE_SYSTEM_LIST: return UIA_ListControlTypeId;
case ROLE_SYSTEM_LISTITEM: return UIA_ListItemControlTypeId;
case ROLE_SYSTEM_OUTLINE: return UIA_TreeControlTypeId;
case ROLE_SYSTEM_OUTLINEITEM: return UIA_TreeItemControlTypeId;
case ROLE_SYSTEM_PAGETAB: return UIA_TabItemControlTypeId;
case ROLE_SYSTEM_GRAPHIC: return UIA_ImageControlTypeId;
case ROLE_SYSTEM_STATICTEXT: return UIA_TextControlTypeId;
case ROLE_SYSTEM_TEXT: return UIA_EditControlTypeId;
case ROLE_SYSTEM_CLOCK:
case ROLE_SYSTEM_BUTTONDROPDOWNGRID:
case ROLE_SYSTEM_PUSHBUTTON: return UIA_ButtonControlTypeId;
case ROLE_SYSTEM_CHECKBUTTON: return UIA_CheckBoxControlTypeId;
case ROLE_SYSTEM_RADIOBUTTON: return UIA_RadioButtonControlTypeId;
case ROLE_SYSTEM_COMBOBOX: return UIA_ComboBoxControlTypeId;
case ROLE_SYSTEM_PROGRESSBAR: return UIA_ProgressBarControlTypeId;
case ROLE_SYSTEM_SLIDER: return UIA_SliderControlTypeId;
case ROLE_SYSTEM_SPINBUTTON: return UIA_SpinnerControlTypeId;
case ROLE_SYSTEM_BUTTONMENU:
case ROLE_SYSTEM_MENUITEM: return UIA_MenuItemControlTypeId;
case ROLE_SYSTEM_PAGETABLIST: return UIA_TabControlTypeId;
case ROLE_SYSTEM_BUTTONDROPDOWN:
case ROLE_SYSTEM_SPLITBUTTON: return UIA_SplitButtonControlTypeId;
case ROLE_SYSTEM_SOUND:
case ROLE_SYSTEM_CURSOR:
case ROLE_SYSTEM_CARET:
case ROLE_SYSTEM_ALERT:
case ROLE_SYSTEM_CLIENT:
case ROLE_SYSTEM_CHART:
case ROLE_SYSTEM_DIALOG:
case ROLE_SYSTEM_BORDER:
case ROLE_SYSTEM_COLUMN:
case ROLE_SYSTEM_ROW:
case ROLE_SYSTEM_HELPBALLOON:
case ROLE_SYSTEM_CHARACTER:
case ROLE_SYSTEM_PROPERTYPAGE:
case ROLE_SYSTEM_DROPLIST:
case ROLE_SYSTEM_DIAL:
case ROLE_SYSTEM_HOTKEYFIELD:
case ROLE_SYSTEM_DIAGRAM:
case ROLE_SYSTEM_ANIMATION:
case ROLE_SYSTEM_EQUATION:
case ROLE_SYSTEM_WHITESPACE:
case ROLE_SYSTEM_IPADDRESS:
case ROLE_SYSTEM_OUTLINEBUTTON:
WARN("No UIA control type mapping for MSAA role %ld\n", role);
break;
default:
FIXME("UIA control type mapping unimplemented for MSAA role %ld\n", role);
break;
}
return 0;
}
/*
* UiaProviderFromIAccessible IRawElementProviderSimple interface.
*/
......@@ -42,6 +121,7 @@ struct msaa_provider {
IAccessible *acc;
VARIANT cid;
HWND hwnd;
LONG control_type;
};
static inline struct msaa_provider *impl_from_msaa_provider(IRawElementProviderSimple *iface)
......@@ -106,9 +186,14 @@ HRESULT WINAPI msaa_provider_GetPatternProvider(IRawElementProviderSimple *iface
HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface,
PROPERTYID prop_id, VARIANT *ret_val)
{
struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
HRESULT hr;
VARIANT v;
TRACE("%p, %d, %p\n", iface, prop_id, ret_val);
VariantInit(ret_val);
VariantInit(&v);
switch (prop_id)
{
case UIA_ProviderDescriptionPropertyId:
......@@ -116,6 +201,19 @@ HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface,
V_BSTR(ret_val) = SysAllocString(L"Wine: MSAA Proxy");
break;
case UIA_ControlTypePropertyId:
if (!msaa_prov->control_type)
{
hr = IAccessible_get_accRole(msaa_prov->acc, msaa_prov->cid, &v);
if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
msaa_prov->control_type = msaa_role_to_uia_control_type(V_I4(&v));
}
if (msaa_prov->control_type)
variant_init_i4(ret_val, msaa_prov->control_type);
break;
default:
FIXME("Unimplemented propertyId %d\n", prop_id);
break;
......@@ -192,7 +290,7 @@ HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD
if (!hwnd)
return E_FAIL;
msaa_prov = heap_alloc(sizeof(*msaa_prov));
msaa_prov = heap_alloc_zero(sizeof(*msaa_prov));
if (!msaa_prov)
return E_OUTOFMEMORY;
......
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