diff options
author | Michael Weghorn <[email protected]> | 2025-06-14 22:57:59 +0200 |
---|---|---|
committer | Michael Weghorn <[email protected]> | 2025-06-16 16:41:00 +0200 |
commit | 9756f62a63f58098513343714b4c0367c0a62dde (patch) | |
tree | 4629c951f46b959e73a6fe4e7a1e33fe535ec630 | |
parent | 4556caaa594e0e51984cc051df9fa0e2bdd9c0c6 (diff) |
QLineEdit a11y: Report displayText on a11y layer
Instead of reporting no/empty text on the a11y layer when
using a QLineEdit::EchoMode that doesn't display the actual
text as is (e.g. in case of a password field), use
QLineEdit::displayText, which already prevents exposing the
actual text unless it's also displayed on screen.
Previously, the character count and caret/cursor position was
still reported for the actual text, but an empty string was reported
for the text itself, which was inconsistent. (A cursor position of
3 within an allegedly empty text doesn't make sense, and empty text
cannot have a character count of 5.)
With this commit in place, entering "hello" in the QLineEdit from the
sample app from QTBUG-109599 now results in replacement/mask
characters as shown on screen being reported for the text on the a11y
layer as well as long as QLineEdit::Password is used.
Demo using Accerciser's IPython console on Linux, with the
QLineEdit's accessible object selected in Accerciser's treeview
of the sample app's a11y hierarchy.
Without this commit in place:
In [11]: text = acc.queryText()
In [12]: text.characterCount
Out[12]: 5
In [13]: text.getText(0, -1)
Out[13]: ''
With this commit in place:
In [16]: text = acc.queryText()
In [17]: text.characterCount
Out[17]: 5
In [18]: text.getText(0, -1)
Out[18]: '●●●●●'
The Orca screen reader now announces "circle" as expected
when moving the cursor between the individual characters.
This also fixes the assert/crash seen with Narrator as mentioned
in QTBUG-109599, due to the above-mentioned mismatch between
reported character count and actual text length.
(QWindowsUiaTextRangeProvider::ExpandToEnclosingUnit relies on
the reported character count, then accesses the character by
index, but the actual string was empty.)
The QAccessibleLineEdit::text(QAccessible::Value) case
previously had manual handling to report mask characters.
Use the displayText there, too.
Adjust tst_QAccessibility::lineEditTest accordingly and
extend it to test the QAccessibleTextInterface in addition.
Since mask characters for passwords in QLineEdit::displayText
are platform-dependent, don't compare the text reported via
a11y interfaces to a hard-coded string, but instead check it
matches the displayText, but differs from the (plain) text.
Fixes: QTBUG-109599
Pick-to: 6.10 6.9
Change-Id: Ifebb4502b71e11d431b708eea613cb2a10e3f237
Reviewed-by: Volker Hilsheimer <[email protected]>
-rw-r--r-- | src/widgets/accessible/simplewidgets.cpp | 24 | ||||
-rw-r--r-- | tests/auto/other/qaccessibility/tst_qaccessibility.cpp | 16 |
2 files changed, 17 insertions, 23 deletions
diff --git a/src/widgets/accessible/simplewidgets.cpp b/src/widgets/accessible/simplewidgets.cpp index a15c51bc09f..f256f2cb37c 100644 --- a/src/widgets/accessible/simplewidgets.cpp +++ b/src/widgets/accessible/simplewidgets.cpp @@ -669,10 +669,7 @@ QString QAccessibleLineEdit::text(QAccessible::Text t) const QString str; switch (t) { case QAccessible::Value: - if (lineEdit()->echoMode() == QLineEdit::Normal) - str = lineEdit()->text(); - else if (lineEdit()->echoMode() != QLineEdit::NoEcho) - str = QString(lineEdit()->text().size(), QChar::fromLatin1('*')); + str = lineEdit()->displayText(); break; default: break; @@ -786,19 +783,12 @@ QString QAccessibleLineEdit::text(int startOffset, int endOffset) const if (startOffset > endOffset) return QString(); - if (lineEdit()->echoMode() != QLineEdit::Normal) - return QString(); - - return lineEdit()->text().mid(startOffset, endOffset - startOffset); + return lineEdit()->displayText().mid(startOffset, endOffset - startOffset); } QString QAccessibleLineEdit::textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const { - if (lineEdit()->echoMode() != QLineEdit::Normal) { - *startOffset = *endOffset = -1; - return QString(); - } if (offset == -2) offset = cursorPosition(); return QAccessibleTextInterface::textBeforeOffset(offset, boundaryType, startOffset, endOffset); @@ -807,10 +797,6 @@ QString QAccessibleLineEdit::textBeforeOffset(int offset, QAccessible::TextBound QString QAccessibleLineEdit::textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const { - if (lineEdit()->echoMode() != QLineEdit::Normal) { - *startOffset = *endOffset = -1; - return QString(); - } if (offset == -2) offset = cursorPosition(); return QAccessibleTextInterface::textAfterOffset(offset, boundaryType, startOffset, endOffset); @@ -819,10 +805,6 @@ QString QAccessibleLineEdit::textAfterOffset(int offset, QAccessible::TextBounda QString QAccessibleLineEdit::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const { - if (lineEdit()->echoMode() != QLineEdit::Normal) { - *startOffset = *endOffset = -1; - return QString(); - } if (offset == -2) offset = cursorPosition(); return QAccessibleTextInterface::textAtOffset(offset, boundaryType, startOffset, endOffset); @@ -851,7 +833,7 @@ void QAccessibleLineEdit::setSelection(int selectionIndex, int startOffset, int int QAccessibleLineEdit::characterCount() const { - return lineEdit()->text().size(); + return lineEdit()->displayText().size(); } void QAccessibleLineEdit::scrollToSubstring(int startIndex, int endIndex) diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp index a316e81aa57..011852c28e4 100644 --- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp @@ -2138,6 +2138,8 @@ void tst_QAccessibility::lineEditTest() auto le = std::make_unique<QLineEdit>(); QAccessibleInterface *iface(QAccessible::queryAccessibleInterface(le.get())); QVERIFY(iface); + QAccessibleTextInterface *textIface = iface->textInterface(); + QVERIFY(textIface); le->show(); QApplication::processEvents(); @@ -2169,13 +2171,23 @@ void tst_QAccessibility::lineEditTest() QCOMPARE(iface->text(QAccessible::Value), QString()); le->setEchoMode(QLineEdit::Password); QVERIFY(iface->state().passwordEdit); - QCOMPARE(iface->text(QAccessible::Value), QString(secret.size(), QLatin1Char('*'))); + QVERIFY(iface->text(QAccessible::Value) != le->text()); + QCOMPARE(iface->text(QAccessible::Value), le->displayText()); + QCOMPARE(textIface->characterCount(), secret.size()); + QVERIFY(textIface->text(0, textIface->characterCount()) != le->text()); + QCOMPARE(textIface->text(0, textIface->characterCount()), le->displayText()); le->setEchoMode(QLineEdit::PasswordEchoOnEdit); QVERIFY(iface->state().passwordEdit); - QCOMPARE(iface->text(QAccessible::Value), QString(secret.size(), QLatin1Char('*'))); + QVERIFY(iface->text(QAccessible::Value) != le->text()); + QCOMPARE(iface->text(QAccessible::Value), le->displayText()); + QCOMPARE(textIface->characterCount(), secret.size()); + QVERIFY(textIface->text(0, textIface->characterCount()) != le->text()); + QCOMPARE(textIface->text(0, textIface->characterCount()), le->displayText()); le->setEchoMode(QLineEdit::Normal); QVERIFY(!(iface->state().passwordEdit)); QCOMPARE(iface->text(QAccessible::Value), secret); + QCOMPARE(textIface->characterCount(), secret.size()); + QCOMPARE(textIface->text(0, textIface->characterCount()), secret); le->setParent(toplevel); toplevel->show(); |