winaccessibility/source/UAccCOM/AccTextBase.cxx | 16 ++++- winaccessibility/source/UAccCOM/MAccessible.cxx | 76 ++++++++++-------------- 2 files changed, 48 insertions(+), 44 deletions(-)
New commits: commit d1d07992a89ba503f1d457a8f79926063f4d3f9c Author: Michael Weghorn <[email protected]> AuthorDate: Tue Aug 8 19:43:09 2023 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Wed Aug 9 06:14:52 2023 +0200 tdf#156679 wina11y: Convert screen to local coords as needed When `AccTextBase::get_offsetAtPoint` gets called with screen coordinates, convert them to local coordinates within the text object first, because that is what `XAccessibleText::getIndexAtPoint` expects. Not doing so resulted in NVDA failing to create a TextInfo object in the mouse event handler [1] when hovering over a Calc cell containing text, because the method would always return an offset of -1. With this change in place, NVDA now announces the text when hovering over the text and mouse tracking is enabled in NVDA (which is the case by default). Other than with Microsoft Excel, the text is only announced when the mouse is actually over the text, not over free space in the cell, which might be because Excel uses UIA and the UIA equivalent, `ITextProvider::RangeFromPoint` [2] shall also return the index of the closest character when the point itself is not over the actual bounds of any character. [1] https://github.com/nvaccess/nvda/blob/a198c9b5f27e47ff2830f77c833eec584078dfd8/source/NVDAObjects/__init__.py#L1209 [2] https://learn.microsoft.com/en-us/windows/win32/api/uiautomationcore/nf-uiautomationcore-itextprovider-rangefrompoint Change-Id: I1e4ab2dd3dace5fea1de2eef67a91fe3c31218a9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155492 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/winaccessibility/source/UAccCOM/AccTextBase.cxx b/winaccessibility/source/UAccCOM/AccTextBase.cxx index 183ec3467655..b70b13c0a980 100644 --- a/winaccessibility/source/UAccCOM/AccTextBase.cxx +++ b/winaccessibility/source/UAccCOM/AccTextBase.cxx @@ -417,7 +417,7 @@ COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_nSelections(long * nSelectio * @param offset Variant to accept offset. * @return Result. */ -COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_offsetAtPoint(long x, long y, IA2CoordinateType, long * offset) +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_offsetAtPoint(long x, long y, IA2CoordinateType coordType, long * offset) { SolarMutexGuard g; @@ -432,6 +432,20 @@ COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_offsetAtPoint(long x, long y css::awt::Point point; point.X = x; point.Y = y; + + if (coordType == IA2_COORDTYPE_SCREEN_RELATIVE) + { + // convert from screen to local coordinates + Reference<XAccessibleContext> xContext = pUNOInterface->getAccessibleContext(); + Reference<XAccessibleComponent> xComponent(xContext, UNO_QUERY); + if (!xComponent.is()) + return S_FALSE; + + css::awt::Point aObjectPos = xComponent->getLocationOnScreen(); + point.X -= aObjectPos.X; + point.Y -= aObjectPos.Y; + } + *offset = GetXInterface()->getIndexAtPoint(point); return S_OK; commit 39302875c27d4cf4246bb7520ed90abcf0af777a Author: Michael Weghorn <[email protected]> AuthorDate: Tue Aug 8 18:27:16 2023 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Wed Aug 9 06:14:44 2023 +0200 tdf#156679 wina11y: Implement accHitTest via UNO equivalent Instead of manually iterating over the children and checking whether the given position is in the location that they're in in `CMAccessible::accHitTest`, use `XAccessibleComponent::XAccessibleComponent`, which provides exactly the functionality that's needed. (This is similar to what the Qt-based VCL plugins on Linux do, s. `QtAccessibleWidget::childAt`.) This also drops the need to limit this to objects that have at most a certain amount of children for performance reasons (previously 256) and thus makes this work e.g. also to identify a Calc cell that the mouse pointer is currently over while previously the document was returned, as could be seen also in NVDA's Python console: 1) start NVDA 2) hover over a Calc cell 3) press NVDA+Ctrl+Z to capture snapshot variables 4) check what NVDA identifies as the mouse object via the Python Console: Before: >>> mouse <NVDAObjects.IAccessible.IAccessible object at 0x00FB9910> >>> mouse.name 'Untitled 1 - LibreOfficeDev Spreadsheets' >>> mouse.role <Role.DOCUMENT: 52> With this change in place: >>> mouse <NVDAObjects.Dynamic_SymphonyIATableCellEditableTextWithAutoSelectDetectionIAccessible object at 0x0774DD10> >>> mouse.name >>> mouse.role <Role.TABLECELL: 29> The cell's text still isn't announced by NVDA even with mouse tracking enabled, but that's another issue. Change-Id: Ib821020cef6303ab786c4c3fc3ccd917398214f1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155491 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/winaccessibility/source/UAccCOM/MAccessible.cxx b/winaccessibility/source/UAccCOM/MAccessible.cxx index 7ca1a8eca836..1a5ec8c4efc1 100644 --- a/winaccessibility/source/UAccCOM/MAccessible.cxx +++ b/winaccessibility/source/UAccCOM/MAccessible.cxx @@ -974,48 +974,38 @@ COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::accHitTest(long xLeft, long yTop if (!pvarChild) return E_INVALIDARG; - try { - long x, y, w, h; - VARIANT varSelf; - VariantInit(&varSelf); - varSelf.vt = VT_I4; - varSelf.lVal = CHILDID_SELF; - accLocation(&x,&y,&w,&h,varSelf); - if( (x < xLeft && (x + w) >xLeft) && (y < yTop && (y + h) >yTop) ) - { - sal_Int64 i, nCount; - pvarChild->vt = VT_EMPTY; - Reference< XAccessibleContext > pRContext = GetContextByXAcc(m_xAccessible.get()); - nCount = pRContext->getAccessibleChildCount(); - if(nCount > 256) - return E_FAIL; - IMAccessible* child = nullptr; - for( i = 0; i<nCount; i++) - { + try + { + pvarChild->vt = VT_EMPTY; - child = GetChildInterface(i + 1); - if(child && child->accHitTest(xLeft,yTop,pvarChild) == S_OK) - break; - } + Reference<XAccessibleContext> xContext = GetContextByXAcc(m_xAccessible.get()); + Reference<XAccessibleComponent> xComponent(xContext, UNO_QUERY); + if (!xComponent.is()) + return S_FALSE; - if(pvarChild->vt == VT_DISPATCH) - return S_OK; + // convert from screen to object-local coordinates + css::awt::Point aTopLeft = xComponent->getLocationOnScreen(); + css::awt::Point aPoint(xLeft - aTopLeft.X, yTop - aTopLeft.Y); - if( i < nCount) - { - pvarChild->vt = VT_DISPATCH; - pvarChild->pdispVal = child; - child->AddRef(); - } - else - { - pvarChild->vt = VT_I4; - pvarChild->lVal = CHILDID_SELF; - } - return S_OK; + Reference<XAccessible> xAccAtPoint = xComponent->getAccessibleAtPoint(aPoint); + if (!xAccAtPoint.is()) + return S_FALSE; + + IAccessible* pRet = nullptr; + bool bHaveIAccessible = get_IAccessibleFromXAccessible(xAccAtPoint.get(), &pRet); + if (!bHaveIAccessible) + { + g_pAccObjectManager->InsertAccObj(xAccAtPoint.get(), m_xAccessible.get(), m_hwnd); + bHaveIAccessible = get_IAccessibleFromXAccessible(xAccAtPoint.get(), &pRet); } - return S_FALSE; + if (!bHaveIAccessible) + return S_FALSE; + pvarChild->vt = VT_DISPATCH; + pvarChild->pdispVal = pRet; + pRet->AddRef(); + + return S_OK; } catch(...) { return E_FAIL; } } commit 0044ec90b3182a25740b53fb8679d83f0dc8f369 Author: Michael Weghorn <[email protected]> AuthorDate: Tue Aug 8 13:12:49 2023 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Wed Aug 9 06:14:38 2023 +0200 wina11y: Move these 2 checks out of try/catch Change-Id: I4ae7527d9b5047d46aab44a1ab6fa42a99c43a14 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155490 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/winaccessibility/source/UAccCOM/MAccessible.cxx b/winaccessibility/source/UAccCOM/MAccessible.cxx index 091acfeb780c..7ca1a8eca836 100644 --- a/winaccessibility/source/UAccCOM/MAccessible.cxx +++ b/winaccessibility/source/UAccCOM/MAccessible.cxx @@ -968,13 +968,13 @@ COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::accHitTest(long xLeft, long yTop { SolarMutexGuard g; + if (m_isDestroy) + return S_FALSE; + + if (!pvarChild) + return E_INVALIDARG; + try { - if (m_isDestroy) return S_FALSE; - // #CHECK# - if(pvarChild == nullptr) - { - return E_INVALIDARG; - } long x, y, w, h; VARIANT varSelf; VariantInit(&varSelf);
