Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First stab at making Mudlet's text window readable by screenreaders #5985

Conversation

bauermann
Copy link

@bauermann bauermann commented Feb 23, 2022

Hello! This is what I have so far regarding fixing issue #3342. It’s not done yet because there’s a significant issue I’m still trying to figure out how to fix (ideas welcome):

When new text arrives in the TTextEdit, the screen reader doesn’t announce it even though the widget is sending the ‘TextInsertEvent’ with the new text. The only time it works is when Caret Mode is enabled (press F7 to activate it), so what I believe is going on is that the screen reader only pays attention to the emitted ‘TextInsertEvent’ when the TTextEdit is focused.

Therefore I’m trying to figure out a way to tell the screen reader that changes in TTextEdit should be announced even when it’s not focused. Orca’s documentation mentions something called “live regions” which seems to be what I need, but so far I have the impression that it’s a concept applied only to web content. I hope I’m wrong though.

Using Orca’s “Speak entire document” command (KP_PLUS or + Semicolon) works though, and so does speaking when moving the cursor in Caret Mode which means that the widget’s contents are being exposed correctly to the screen reader. It’s just that there’s something more I need to do in order to make the screen reader know that it needs to announce new text as it arrives.

Nobody asked to implement Caret Mode but I did anyway, inspired by the feature of the same name in Firefox. It seems useful to me, please let me know what you think.

I dropped the commit where I was removing the HTML markup from the tooltips in TConsole’s buttons. The screen reader still speaks them so it’s a bit annoying, but now there’s only <p>…</p> markup whereas before it was <html><head/><body><p>…</p></body></html>, so a lot better now.

Also, since Qt does expect HTML markup in the tooltip then it should strip the
markup before passing the tooltip contents along to the screen reader. So it’s a
problem to be fixed somewhere else in the technology stack.

I’m testing with GNOME on Linux, with the Orca screen reader.

I’d appreciate more testing, as well as feedback on the code and design.

I don’t expect this PR to be merged. It’s mostly so that the CI can generate snapshot builds.

@bauermann bauermann requested review from a team as code owners February 23, 2022 19:47
@add-deployment-links
Copy link

add-deployment-links bot commented Feb 23, 2022

Hey there! Thanks for helping Mudlet improve. 🌟

Test versions

You can directly test the changes here:

No need to install anything - just unzip and run.
Let us know if it works well, and if it doesn't, please give details.

@mudlet-machine-account mudlet-machine-account added this to the 4.16.0 milestone Feb 23, 2022
@github-actions
Copy link
Contributor

github-actions bot commented Feb 23, 2022

Fails
🚫 Source file src/TAccessibleTextEdit.cpp includes a TODO with no Mudlet issue link. New TODO items in source files must have an accompanying github issue
🚫

PR title must start with fix, improve, add or infra for release notes purposes.

Generated by 🚫 dangerJS against e673121

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

src/TAccessibleTextEdit.cpp Show resolved Hide resolved
src/TAccessibleTextEdit.cpp Show resolved Hide resolved
src/TAccessibleTextEdit.cpp Show resolved Hide resolved
src/TTextEdit.cpp Show resolved Hide resolved
src/TTextEdit.cpp Show resolved Hide resolved
src/mudlet.cpp Outdated Show resolved Hide resolved
@vadi2
Copy link
Member

vadi2 commented Feb 23, 2022

Nice! Thanks for this. Will review it in detail in the coming days. In the meantime I posted it on our Discord's accessibility channel for people to start testing.

@bauermann
Copy link
Author

bauermann commented Feb 23, 2022 via email

Copy link
Member

@SlySven SlySven left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an initial review...!

src/TAccessibleTextEdit.h Outdated Show resolved Hide resolved
src/TAccessibleTextEdit.h Show resolved Hide resolved
src/CMakeLists.txt Outdated Show resolved Hide resolved
src/TConsole.cpp Outdated Show resolved Hide resolved
src/TConsole.cpp Outdated Show resolved Hide resolved
src/TTextEdit.cpp Outdated Show resolved Hide resolved
@@ -602,7 +640,8 @@ int TTextEdit::drawGraphemeBackground(QPainter& painter, QVector<QColor>& fgColo
}
textRects.append(textRect);
QColor bgColor;
if (Q_UNLIKELY(static_cast<bool>(attributes & TChar::Reverse) != charStyle.isSelected())) {
bool caretIsHere = mudlet::self()->isCaretModeEnabled() && mCaretLine == line && mCaretColumn == column;
if (Q_UNLIKELY(static_cast<bool>(attributes & TChar::Reverse) != (charStyle.isSelected() != caretIsHere))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure of this - originally it was to EXCLUSIVE-OR the reverse text mode with the reverse effect that selecting text does (so when combined the state is the same as if neither was applied) - what does the "CaratMod" mode do to how the text is/should be shown?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to implement the caret mode’s cursor. It is displayed as a reversed-color character cell, similar to old terminals.

The change above reverses the color when the character cell has normal color, and uses normal color when it has reversed-color.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So logically you have to handle all three conditions at the same time and apply the reverse effect when an odd number of them are true. Maybe the logic you have chosen will work, I'll have to think about it a bit more.

src/TTextEdit.cpp Outdated Show resolved Hide resolved
src/main.cpp Show resolved Hide resolved
@@ -2976,6 +2977,12 @@ void mudlet::slot_multi_view(const bool state)
}
}

void mudlet::slot_caret_mode(bool state)
{
// FIXME: Support multiple hosts.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you will need to handle multiple host instances - and using // FIXME: is not making this PR "dangerous" (upsetting the Danger Bot that watches some aspects of PRs!) whereas using // TODO: definitely would... 😲

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I plan to implement this before making the definitive PR. This comment is just so that I don’t forget about it. :)

@Hadi-1624
Copy link

I believe this is not working in windows at all.
Testing with NVDA screen reader on windows 10. when mudlet connects to a mud, the keyboard focus is on the input field and will refuse to go anywhere else, even if I press the f7 key.

Just to make sure, here's how I imagine the client could be accessible:

  1. screen reader reads incoming text in the output window
  2. Mudlet by default has the keyboard focus on the input window. there should be an implementation in which the keyboard focus and cursor moves from the input to the output window, so that the output window could be navigated by the arrow keys and be read. this preferably should be switched by a hotkey so it could be fast moving between the input and output windows.
  3. Functions that sends the last 10 lines in the output window to the screen reader, which then could be assigned to hotkeys, so pressing control+shift+5 for example, would send the fifth line from bottom to the scren reader to be read.

@ironcross32
Copy link

Hi, the F7 mode isn't activating in this case. I can verify that a connection has been made to the MUD I intended by running OCR on the game window. I am testing on Windows 10.

@bauermann
Copy link
Author

bauermann commented Feb 26, 2022 via email

@bauermann
Copy link
Author

bauermann commented Feb 26, 2022 via email

@mohammedradwan2003
Copy link

hi,
i totally agree with what was said, however let me clarify something
what they ment, a window which contains all text received by the mud, and input window contains all the commands i send
making it easier for us that way, both are separated and can be reached via a hot key
i hope this gets implimented
thanks
mohammed
can't wait to see this huge project coming out

@ironcross32
Copy link

I've posted some messages in the Mudlet Discord under the Mudlet development channel that may be of assistance.

First, rename mLastRenderBottom to mLastRenderedOffset. The old name is
misleading because it actually holds the line that was at the top of the
screen when it was last rendered, not the bottom.

Also add explanation of what mScrollVector means.

These changes help understand the logic at TTextEdit::drawForeground().
@bauermann
Copy link
Author

bauermann commented Feb 26, 2022 via email

@bauermann
Copy link
Author

bauermann commented Feb 26, 2022 via email

@Hadi-1624
Copy link

Hi there bauermann
Thanks for working on accessibility of the client!

I tried to follow your suggestion and enable Caret mode from the options menu but i've faced another problem where, after connecting to a game, pressing alt will not bring the menus up. i've tried pressing alt, pressing it again and pressing down arrow but no luck.
Is there a way to open the option menu by a hotkey?
I do confirm that mudlet default hotkeys work however. package manager and module manager for example, can be opnned by their shortcuts.

@bauermann
Copy link
Author

bauermann commented Feb 26, 2022 via email

@bauermann
Copy link
Author

bauermann commented Feb 26, 2022 via email

@ironcross32
Copy link

I'm 85% sure that QT will not do what you want. QT does have an accessibility layer, but it is for the controls. All of the controls unrelated to the actual game window do already seem to work. What needs to happen here is that text needs to be captured and sent to the running screen reader through its API. Unfortunately, there is no solution for this that fits all applications due to working cross-platform, and every screen reader has its own API. So there would need to be contingencies for sending through speech dispatcher in Linux and either writing your own class or using Tolk or Universal Speech on Windows. I have no clue about Mac.

This should be the first priority, because anything else is unimportant until incoming text is automatically read. Maybe if you can get this working under Linux, someone else can come along and duplicate it for Windows.

@bauermann
Copy link
Author

bauermann commented Feb 27, 2022 via email

The current cursor position isn't relevant in the calculation.
This fixes the following warning:

  'TAccessibleTextEdit::text' hides overloaded virtual function

Adjust lineForOffset() and cursorPosition() to take into account the
newlines added by join().

Also, simplify text(int startOffset, int endOffset) using the new
text(QAccessible::Text t) method.
It's partially based on QAccessibleTextWidget::attributes() from Qt 5.15.
Also, remove ‘DocumentContentChanged’ event from TConsole::print() methods
because both call TTextEdit::showNewLines(), which already sends
‘TextInsertEvent’.
Thanks to Stephen Lyons for the suggestion.
Thanks to Stephen Lyons for the suggestion.
@bauermann bauermann force-pushed the issue-3342-text-window-accessibility branch from 4a8de85 to b75ba04 Compare February 27, 2022 05:43
@bauermann
Copy link
Author

Just an initial review...!

Thank you very much for this detailed review! I just force-pushed my branch with the changes corresponding to the resolved comments. I still have to work on the unresolved ones.

@vadi2
Copy link
Member

vadi2 commented Feb 27, 2022

It is far too early to give up on the current cross-platform approach. We've discussed the reasons for this approach previously in #3342, let's not get sidetracked here again as well.

vadi2 and others added 11 commits February 27, 2022 09:06
…ng-tidy

Example warning:

warning: variable lengthSoFar is not initialized [cppcoreguidelines-init-variables]

int lengthSoFar;
    ^
                = 0
Example warning:

warning: Potential memory leak [clang-analyzer-cplusplus.NewDeleteLeaks]
    ⋮
src/TTextEdit.cpp:351:42: note: Memory is allocated
        QAccessible::updateAccessibility(new QAccessibleTextInsertEvent(this,
                                         ^
src/TTextEdit.cpp:355:1: note: Potential memory leak
src/TAccessibleTextEdit.cpp#L374
Using deprecated casting style.  Use static_cast<int>(...) instead (readability/casting)

and

src/TAccessibleTextEdit.cpp#L525
Tab found; better to use spaces (whitespace/tab)
I added that call thinking that some locales with many wide characters would
have a wide ‘a’ character as well. I tested with zh_TW and it wasn't the case,
so remove it.

Thanks to Stephen Lyons for noticing the issue.
Thanks to ironcross32 for the suggestion.
@vadi2
Copy link
Member

vadi2 commented Apr 30, 2022

See #3342 (comment) for an update. I'll continue this work - will start a new PR as I haven't got the rights to push in here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants