Implemented get_accValue(), put_accName(), and put_accValue(). Merged the contents of accessibilitynotes into accessibility.h. More TODOs.

This commit is contained in:
Pietro Gagliardi 2015-02-17 12:18:31 -05:00
parent 6264cf1fee
commit cc49202006
2 changed files with 91 additions and 14 deletions

View File

@ -1,5 +1,17 @@
// 24 december 2014 // 24 december 2014
// implement MSAA-conformant accessibility
// we need to use MSAA because UI Automation is too new for us
// unfortunately, MSAA's documentation is... very poor. very ambiguous, very inconsistent (just run through this file's commit history and watch the TODO progression to see)
// resources:
// http://msdn.microsoft.com/en-us/library/ms971338.aspx
// http://msdn.microsoft.com/en-us/library/windows/desktop/cc307844.aspx
// http://msdn.microsoft.com/en-us/library/windows/desktop/cc307847.aspx
// http://blogs.msdn.com/b/saraford/archive/2004/08/20/which-controls-support-which-msaa-properties-and-how-these-controls-implement-msaa-properties.aspx
// http://msdn.microsoft.com/en-us/library/ms971325
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd318017%28v=vs.85%29.aspx
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd373624%28v=vs.85%29.aspx
// notes: // notes:
// - TODO figure out what to do about header // - TODO figure out what to do about header
// - a row extends as far right as the right edge of the last cell in the row; anything to the right of that is treated as table space (just like with mouse selection) // - a row extends as far right as the right edge of the last cell in the row; anything to the right of that is treated as table space (just like with mouse selection)
@ -12,6 +24,9 @@
// TODOs: // TODOs:
// - make sure E_POINTER and RPC_E_DISCONNECTED are correct returns for IAccessible // - make sure E_POINTER and RPC_E_DISCONNECTED are correct returns for IAccessible
// - return last error on newTableAcc() in all accessible functions // - return last error on newTableAcc() in all accessible functions
// - figure out what should be names and what should be values
// - figure out what to do about that header row
// - http://acccheck.codeplex.com/
// uncomment this to debug table linked list management // uncomment this to debug table linked list management
//#define TABLE_DEBUG_LINKEDLIST //#define TABLE_DEBUG_LINKEDLIST
@ -320,13 +335,49 @@ static HRESULT STDMETHODCALLTYPE tableAccget_accName(IAccessible *this, VARIANT
return E_FAIL; return E_FAIL;
} }
// this differs quite much from what is described at https://msdn.microsoft.com/en-us/library/ms971325
static HRESULT STDMETHODCALLTYPE tableAccget_accValue(IAccessible *this, VARIANT varChild, BSTR *pszValue) static HRESULT STDMETHODCALLTYPE tableAccget_accValue(IAccessible *this, VARIANT varChild, BSTR *pszValue)
{ {
if (TA->t == NULL || TA->std == NULL) { HRESULT hr;
// TODO set values on error tableAccWhat what;
WCHAR *text;
if (pszValue == NULL)
return E_POINTER;
// TODO set pszValue to zero?
if (TA->t == NULL || TA->std == NULL)
return RPC_E_DISCONNECTED; return RPC_E_DISCONNECTED;
} what = TA->what;
hr = normalizeWhat(TA, varChild, &what);
if (hr != S_OK)
return hr;
switch (what.role) {
case ROLE_SYSTEM_TABLE:
// TODO really?
return IAccessible_get_accValue(TA->std, varChild, pszValue); return IAccessible_get_accValue(TA->std, varChild, pszValue);
case ROLE_SYSTEM_ROW:
// TODO
return DISP_E_MEMBERNOTFOUND;
case ROLE_SYSTEM_CELL:
switch (TA->t->columnTypes[what.column]) {
case tableColumnText:
text = getCellText(TA->t, what.row, what.column);
// TODO check for error
*pszValue = SysAllocString(text);
returnCellData(TA->t, what.row, what.column, text);
return S_OK;
case tableColumnImage:
// TODO
return DISP_E_MEMBERNOTFOUND;
case tableColumnCheckbox:
// TODO!!!!!!
return DISP_E_MEMBERNOTFOUND;
}
}
// TODO actually do this right
// TODO un-GetLastError() this
panic("impossible blah blah blah TODO write this");
return E_FAIL;
} }
static HRESULT STDMETHODCALLTYPE tableAccget_accDescription(IAccessible *this, VARIANT varChild, BSTR *pszDescription) static HRESULT STDMETHODCALLTYPE tableAccget_accDescription(IAccessible *this, VARIANT varChild, BSTR *pszDescription)
@ -891,22 +942,40 @@ static HRESULT STDMETHODCALLTYPE tableAccaccDoDefaultAction(IAccessible *this, V
return DISP_E_MEMBERNOTFOUND; return DISP_E_MEMBERNOTFOUND;
} }
// inconsistencies, inconsistencies
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd318491%28v=vs.85%29.aspx says to just return E_NOTIMPL and not even bother with an implementation; in fact it doesn't even *have* the documentation anymore
// http://blogs.msdn.com/b/saraford/archive/2004/08/20/which-controls-support-which-msaa-properties-and-how-these-controls-implement-msaa-properties.aspx says never to return E_NOTIMPL from an IAccessible method (but it also discounts RPC_E_DISCONNECTED (not explicitly), so I'm guessing this is a much older document)
// let's just do what our put_accValue() does and do full validation, then just return DISP_E_MEMBERNOTFOUND
// I really hope UI Automation isn't so ambiguous and inconsistent... too bad I'm still choosing to support Windows XP while its market share (compared to *every other OS ever*) is still as large as it is
static HRESULT STDMETHODCALLTYPE tableAccput_accName(IAccessible *this, VARIANT varChild, BSTR szName) static HRESULT STDMETHODCALLTYPE tableAccput_accName(IAccessible *this, VARIANT varChild, BSTR szName)
{ {
if (TA->t == NULL || TA->std == NULL) { HRESULT hr;
// TODO set values on error tableAccWhat what;
if (TA->t == NULL || TA->std == NULL)
return RPC_E_DISCONNECTED; return RPC_E_DISCONNECTED;
} what = TA->what;
return IAccessible_put_accName(TA->std, varChild, szName); hr = normalizeWhat(TA, varChild, &what);
if (hr != S_OK)
return hr;
// don't support setting values anyway; do return the above errors just to be safe
return DISP_E_MEMBERNOTFOUND;
} }
static HRESULT STDMETHODCALLTYPE tableAccput_accValue(IAccessible *this, VARIANT varChild, BSTR szValue) static HRESULT STDMETHODCALLTYPE tableAccput_accValue(IAccessible *this, VARIANT varChild, BSTR szValue)
{ {
if (TA->t == NULL || TA->std == NULL) { HRESULT hr;
// TODO set values on error tableAccWhat what;
if (TA->t == NULL || TA->std == NULL)
return RPC_E_DISCONNECTED; return RPC_E_DISCONNECTED;
} what = TA->what;
return IAccessible_put_accValue(TA->std, varChild, szValue); hr = normalizeWhat(TA, varChild, &what);
if (hr != S_OK)
return hr;
// don't support setting values anyway; do return the above errors just to be safe
// TODO defer ROW_SYSTEM_TABLE to the standard accessible object?
return DISP_E_MEMBERNOTFOUND;
} }
static const IAccessibleVtbl tableAccVtbl = { static const IAccessibleVtbl tableAccVtbl = {

View File

@ -1,6 +1,14 @@
// 8 december 2014 // 8 december 2014
// TODO move to api.h? definitely move somewhere // TODO move to api.h? definitely move somewhere
static WCHAR *getCellText(struct table *t, intptr_t row, intptr_t column)
{
return (WCHAR *) notify(t, tableNotificationGetCellData, row, column, 0);
}
static void returnCellData(struct table *t, intptr_t row, intptr_t column, void *what)
{
notify(t, tableNotificationFinishedWithCellData, row, column, (uintptr_t) what);
}
static int isCheckboxChecked(struct table *t, intptr_t row, intptr_t column) static int isCheckboxChecked(struct table *t, intptr_t row, intptr_t column)
{ {
return notify(t, tableNotificationGetCellData, row, column, 0) != 0; return notify(t, tableNotificationGetCellData, row, column, 0) != 0;
@ -25,10 +33,10 @@ static void drawTextCell(struct table *t, HDC dc, struct drawCellParams *p, RECT
panic("error setting Table cell text color"); panic("error setting Table cell text color");
if (SetBkMode(dc, TRANSPARENT) == 0) if (SetBkMode(dc, TRANSPARENT) == 0)
panic("error setting transparent text drawing mode for Table cell"); panic("error setting transparent text drawing mode for Table cell");
text = (WCHAR *) notify(t, tableNotificationGetCellData, p->row, p->column, 0); text = getCellText(t, p->row, p->column);
if (DrawTextExW(dc, text, -1, r, DT_END_ELLIPSIS | DT_LEFT | DT_NOPREFIX | DT_SINGLELINE, NULL) == 0) if (DrawTextExW(dc, text, -1, r, DT_END_ELLIPSIS | DT_LEFT | DT_NOPREFIX | DT_SINGLELINE, NULL) == 0)
panic("error drawing Table cell text"); panic("error drawing Table cell text");
notify(t, tableNotificationFinishedWithCellData, p->row, p->column, (uintptr_t) text); returnCellData(t, p->row, p->column, text);
} }
static void drawImageCell(struct table *t, HDC dc, struct drawCellParams *p, RECT *r) static void drawImageCell(struct table *t, HDC dc, struct drawCellParams *p, RECT *r)
@ -70,7 +78,7 @@ static void drawImageCell(struct table *t, HDC dc, struct drawCellParams *p, REC
if (DeleteDC(idc) == 0) if (DeleteDC(idc) == 0)
panic("error deleting Table compatible DC for image cell drawing"); panic("error deleting Table compatible DC for image cell drawing");
notify(t, tableNotificationFinishedWithCellData, p->row, p->column, (uintptr_t) bitmap); returnCellData(t, p->row, p->column, bitmap);
} }
static void drawCheckboxCell(struct table *t, HDC dc, struct drawCellParams *p, RECT *r) static void drawCheckboxCell(struct table *t, HDC dc, struct drawCellParams *p, RECT *r)