offapi/com/sun/star/accessibility/XAccessibleTextSelection.idl | 2 sw/source/core/access/accpara.cxx | 2 sw/source/core/access/accpara.hxx | 2 vcl/qt5/QtAccessibleWidget.cxx | 38 ++++++++-- vcl/unx/gtk3/a11y/atktext.cxx | 10 +- winaccessibility/source/UAccCOM/AccTextBase.cxx | 2 6 files changed, 44 insertions(+), 12 deletions(-)
New commits: commit d540577625ab140930f8467822aec70ede817ed5 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Thu Aug 14 11:42:47 2025 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Thu Aug 14 15:44:04 2025 +0200 tdf#167930 qt a11y: Implement QtAccessibleWidget::{add,remove}Selection Add initial implementation for these methods, but only supporting a single selection, similar to what the gtk3 implementation currently does. This makes the scenario described for gtk3 in Change-Id: Ieca9dff66eef366bf2a3845e5fdb53b3bfa70df9 Author: Michael Weghorn <m.wegh...@posteo.de> Date: Thu Aug 14 11:19:14 2025 +0200 tdf#167930 gtk3 a11y: Keep caret pos when removing selection also work when using the qt6 VCL plugin on Linux. Change-Id: I93694cb2b81ef95fc25c678eaae73fd0dc00a141 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189580 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins diff --git a/vcl/qt5/QtAccessibleWidget.cxx b/vcl/qt5/QtAccessibleWidget.cxx index 54cc047d5df6..911ea85776e7 100644 --- a/vcl/qt5/QtAccessibleWidget.cxx +++ b/vcl/qt5/QtAccessibleWidget.cxx @@ -993,9 +993,24 @@ QVariant QtAccessibleWidget::attributeValue(QAccessible::Attribute eAttribute) c #endif // QAccessibleTextInterface -void QtAccessibleWidget::addSelection(int /* startOffset */, int /* endOffset */) +void QtAccessibleWidget::addSelection(int startOffset, int endOffset) { - SAL_INFO("vcl.qt", "Unsupported QAccessibleTextInterface::addSelection"); + // only single selection supported currently + if (selectionCount() > 0) + return; + + Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); + if (!xText.is()) + return; + + const sal_Int32 nTextLength = xText->getCharacterCount(); + if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength) + { + SAL_WARN("vcl.qt", "QtAccessibleWidget::addSelection called with invalid offset."); + return; + } + + xText->setSelection(startOffset, endOffset); } // Text attributes are returned in format specified in IAccessible2 spec, since that @@ -1089,9 +1104,24 @@ int QtAccessibleWidget::offsetAtPoint(const QPoint& rPoint) const return xText->getIndexAtPoint(aPoint); } -void QtAccessibleWidget::removeSelection(int /* selectionIndex */) +void QtAccessibleWidget::removeSelection(int selectionIndex) { - SAL_INFO("vcl.qt", "Unsupported QAccessibleTextInterface::removeSelection"); + if (selectionIndex < 0 || selectionIndex >= selectionCount()) + { + SAL_WARN("vcl.qt", "QtAccessibleWidget::removeSelection called with invalid index"); + return; + } + + Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); + if (!xText.is()) + return; + + // only single selection supported at the moment (s.a. seleciontCount(); + // code below needs adjustment if that changes + assert(selectionIndex == 0); + + const sal_Int32 nCaretPos = xText->getCaretPosition(); + xText->setSelection(nCaretPos, nCaretPos); } void QtAccessibleWidget::scrollToSubstring(int startIndex, int endIndex) commit 315c94c91adc6a9e79a78b304e8d2b95e2f45b80 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Thu Aug 14 11:19:14 2025 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Thu Aug 14 15:43:58 2025 +0200 tdf#167930 gtk3 a11y: Keep caret pos when removing selection Don't always use an index of 0 for the start and end index of the new empty selection, but use the current caret position instead. This prevents the cursor from jumping to the beginning of a paragraph when removing a selection via the AT-SPI Text interface as decribed in tdf#167930: Example using Accerciser's IPython console with a sample Writer paragraph with text "abcdefghijk", with "efgh" initially selected. Previously (unexpected line marked with arrow): In [64]: text = acc.queryText() In [65]: text.caretOffset Out[65]: 8 In [66]: text.getNSelections() Out[66]: 1 In [67]: selection = text.getSelection(0) In [68]: selection[0] Out[68]: 4 In [69]: selection[1] Out[69]: 8 In [70]: text.removeSelection(0) Out[70]: True In [71]: text.caretOffset -> Out[71]: 0 In [72]: text.getNSelections() Out[72]: 0 With this commit in place, the caret offset remains unchanged: In [74]: text = acc.queryText() In [75]: text.caretOffset Out[75]: 8 In [76]: text.getNSelections() Out[76]: 1 In [77]: selection = text.getSelection(0) In [78]: selection[0] Out[78]: 4 In [79]: selection[1] Out[79]: 8 In [80]: text.removeSelection(0) Out[80]: True In [81]: text.caretOffset -> Out[81]: 8 In [82]: text.getNSelections() Out[82]: 0 There is also an XAccessibleTextSelection UNO interface that SwAccessibleParagraph implements that looks like it should be useful to implement the methods to add/remove/count selections, but it didn't work as expected in a quick test, so the implementation inside Writer would likely need to be fixed first if going that route. Change-Id: Ieca9dff66eef366bf2a3845e5fdb53b3bfa70df9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189579 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/vcl/unx/gtk3/a11y/atktext.cxx b/vcl/unx/gtk3/a11y/atktext.cxx index b140232055d3..54973d739e0c 100644 --- a/vcl/unx/gtk3/a11y/atktext.cxx +++ b/vcl/unx/gtk3/a11y/atktext.cxx @@ -793,10 +793,12 @@ text_wrapper_remove_selection (AtkText *text, g_return_val_if_fail( selection_num == 0, FALSE ); try { - css::uno::Reference<css::accessibility::XAccessibleText> pText - = getText( text ); - if( pText.is() ) - return pText->setSelection( 0, 0 ); // ? + css::uno::Reference<css::accessibility::XAccessibleText> xText = getText(text); + if (!xText.is()) + return false; + + const sal_Int32 nCaretPos = xText->getCaretPosition(); + return xText->setSelection(nCaretPos, nCaretPos); } catch(const uno::Exception&) { g_warning( "Exception in setSelection()" ); commit 3a2b113201fe2dede20286ad2cb3b45f266af976 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Thu Aug 14 10:00:40 2025 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Thu Aug 14 15:43:52 2025 +0200 [API CHANGE] a11y: Drop XAccessibleTextSelection::addSelection param Neither the corresponding AT-SPI "AddSelection" Text iface method [1] used on Linux nor the IAccessibleText::addSelection method [2] of the IAccessible2 API used on Windows has any such parameter to specify what selection index the newly added selection should have. The only implementation of the method in SwAccessibleParagraph::addSelection was also simply ignoring it. Therefore, drop that unnecessary and unused parameter altogether. [1] https://gitlab.gnome.org/GNOME/at-spi2-core/-/blob/93fc318e12b6bfc84aa160ce539a97b59189d8c3/xml/Text.xml#L108-112 [2] https://accessibility.linuxfoundation.org/a11yspecs/ia2/docs/html/interface_i_accessible_text.html#a646c0dff62feb76075e3890f059a86b6 Change-Id: I42fcea029139255b7b327c6e375e37ffb9039bc6 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189578 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins diff --git a/offapi/com/sun/star/accessibility/XAccessibleTextSelection.idl b/offapi/com/sun/star/accessibility/XAccessibleTextSelection.idl index 18f6ce999934..f9c84c054fa4 100644 --- a/offapi/com/sun/star/accessibility/XAccessibleTextSelection.idl +++ b/offapi/com/sun/star/accessibility/XAccessibleTextSelection.idl @@ -29,7 +29,7 @@ interface XAccessibleTextSelection : ::com::sun::star::uno::XInterface long getSeletedPositionEnd ([in] long nSelectedPortionIndex) raises (::com::sun::star::lang::IndexOutOfBoundsException); - long addSelection( [in] long selectionIndex, [in]long startOffset, [in] long endOffset) raises (::com::sun::star::lang::IndexOutOfBoundsException); + long addSelection([in] long startOffset, [in] long endOffset) raises (::com::sun::star::lang::IndexOutOfBoundsException); boolean removeSelection( [in] long selectionIndex ) raises (::com::sun::star::lang::IndexOutOfBoundsException); }; diff --git a/sw/source/core/access/accpara.cxx b/sw/source/core/access/accpara.cxx index b5f56036a88f..c54350dd3126 100644 --- a/sw/source/core/access/accpara.cxx +++ b/sw/source/core/access/accpara.cxx @@ -2880,7 +2880,7 @@ sal_Bool SAL_CALL SwAccessibleParagraph::removeSelection( sal_Int32 selectionInd return true; } -sal_Int32 SAL_CALL SwAccessibleParagraph::addSelection( sal_Int32, sal_Int32 startOffset, sal_Int32 endOffset) +sal_Int32 SAL_CALL SwAccessibleParagraph::addSelection(sal_Int32 startOffset, sal_Int32 endOffset) { SolarMutexGuard aGuard; diff --git a/sw/source/core/access/accpara.hxx b/sw/source/core/access/accpara.hxx index 035504fbc1e3..268f2d2f01cd 100644 --- a/sw/source/core/access/accpara.hxx +++ b/sw/source/core/access/accpara.hxx @@ -328,7 +328,7 @@ public: virtual sal_Int32 SAL_CALL getSeletedPositionStart( sal_Int32 nSelectedPortionIndex ) override; virtual sal_Int32 SAL_CALL getSeletedPositionEnd( sal_Int32 nSelectedPortionIndex ) override; virtual sal_Bool SAL_CALL removeSelection( sal_Int32 selectionIndex ) override; - virtual sal_Int32 SAL_CALL addSelection( sal_Int32 selectionIndex, sal_Int32 startOffset, sal_Int32 endOffset) override; + virtual sal_Int32 SAL_CALL addSelection(sal_Int32 startOffset, sal_Int32 endOffset) override; // XAccessibleExtendedAttributes virtual OUString SAL_CALL getExtendedAttributes() override; sal_Int32 GetRealHeadingLevel(); diff --git a/winaccessibility/source/UAccCOM/AccTextBase.cxx b/winaccessibility/source/UAccCOM/AccTextBase.cxx index 784e6cdd6430..0971b698c281 100644 --- a/winaccessibility/source/UAccCOM/AccTextBase.cxx +++ b/winaccessibility/source/UAccCOM/AccTextBase.cxx @@ -105,7 +105,7 @@ COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_addSelection(long startOffse if( pRExtension.is() ) { - pRExtension->addSelection(0, startOffset, endOffset); + pRExtension->addSelection(startOffset, endOffset); return S_OK; } else