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

Let screen readers catch cursor position #2543

Open
shindere opened this issue Jan 24, 2022 · 56 comments
Open

Let screen readers catch cursor position #2543

shindere opened this issue Jan 24, 2022 · 56 comments

Comments

@shindere
Copy link

TErmux is almost usable with a screen reader like
brltt.

One major barrier to its use, though, is that brltty does not know where
the cursor is. More specifically, no matter her the crr iviually,
brlttyshows it at the botom-right of the reen.

Could this please be fixed?

If made usable with brltty, termux could become a fundamental app for
visually impaired persons, especially since braille notetakesrs like HIMS
Braille Sense 6 are running
Android.

@agnostic-apollo
Copy link
Member

Hey. The issue is that the TerminalView is not really a text field (EditText) used by android accessibility service and so there is no concept of "cursor position" for it. Consider it more like an image with pixels. Termux app does publish the text shown in the terminal as contentDescription added in #344.

My guess was that cursor being reported at bottom right was because of terminal not being a text field, which I confirmed by installing the brltty android app from https://play.google.com/store/apps/details?id=org.a11y.brltty.android as documented in https://brltty.app/archive/Android/brltty-on-android.html. I enabled logcat logging in accessibility settings and enabled Cursor Tracking log category. Brltty logged the following entries when I opened the terminal with extra keys mode, then switched to text input view mode, then typed 3 characters and then switched back to extra keys mode. The text input view is an EditText, so it reports the cursor position correctly. The cursor position for terminal is always 0,1, but changes to 0,40 in input text view mode and updates when text is changed. There are some extra entries generated during swipe action when switching to text input mode.

The log entries are from brltty/Programs/update.c

W/brltty: cursor tracking: scr=237 csr=[0,1]->[0,47] win=[0,1]->[0,47]
W/brltty: cursor tracking: scr=237 csr=[0,47]->[0,42] win=[0,43]->[0,43]
W/brltty: cursor tracking: scr=237 csr=[0,42]->[0,40] win=[0,41]->[0,41]
W/brltty: cursor tracking: scr=237 csr=[0,47]->[0,40] win=[0,41]->[0,40]
W/brltty: cursor tracking: scr=237 csr=[0,40]->[1,40] win=[0,40]->[1,40]
W/brltty: cursor tracking: scr=237 csr=[1,40]->[2,40] win=[1,40]->[2,40]
W/brltty: cursor tracking: scr=237 csr=[2,40]->[3,40] win=[2,40]->[3,40]
W/brltty: cursor tracking: scr=237 csr=[3,40]->[0,1] win=[3,40]->[0,1]

As for whether this can be fixed or not, I am currently not sure since I don't really have experience with accessibility services. However, there seems to be support in android for custom views as documented at https://developer.android.com/guide/topics/ui/accessibility/custom-views. Maybe custom events can be published with updated AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY in View.onInitializeAccessibilityNodeInfo(). Chromium seems to be doing something similar in OWebContentsAccessibility. But not sure if its the right thing for termux terminal.

I will try looking into this. I don't have a braille screen reader device, so that may be an issue too and may need someone who does for testing.

@shindere
Copy link
Author

shindere commented Feb 5, 2022 via email

@agnostic-apollo
Copy link
Member

You are welcome. Cool, will let you know in case I need testing.

@shindere
Copy link
Author

shindere commented Feb 5, 2022 via email

@agnostic-apollo
Copy link
Member

Yeah, I understand and hope this gets fixed somehow. I'll try prioritizing this.

@shindere
Copy link
Author

shindere commented Feb 5, 2022 via email

@sthibaul
Copy link

sthibaul commented Feb 5, 2022

I don't know anything about the accessibility stack on Android.

@webczat
Copy link

webczat commented Jun 15, 2022

note there is an alternative accessibility method which is using an actual linux specific console screenreader. had some success with fenrir but it required proot setup and some way for it to contact the external pulseaudio, I don't even remember what I did.

@shindere
Copy link
Author

shindere commented Jun 15, 2022 via email

@agnostic-apollo
Copy link
Member

agnostic-apollo commented Jun 16, 2022

I was actually looking into this yesterday before you guys messaged.

I have managed to find a way to send terminal cursor position via AccessibilityNodeInfo.extras. There doesn't seem to be any other valid fields that could be used. Moreover, more custom data can be sent as well or specially returned if requested by accessibility apps.

Check #2840. You can download termux apk build from https://github.com/termux/termux-app/actions/runs/2509869570. Note that if you installed termux from F-Droid, then installation github build will fail since it will have different signing keys, so you would need to uninstall termux and all plugin apps first. Check https://github.com/termux/termux-app#Installation.

You would also need to apply the brltty app patch to get the values. Currently, its just logging the values and not setting screen reader cursor. Log Accessibility Events will have to be enabled in advanced brltty settings. Let me know if I should open a pull request for this.

The issue is that I don't have experience with screen readers or terminal support for screen readers and don't know how this should ideally be implemented and how useful cursor position is. The terminal is two dimensional, but screen readers seem to be one dimensional, basically a single row with limited text characters. So there is some mapping going on as well. Moreover, in non text edit mode (outside nano, etc), the user may want to read text at the top of the terminal and cursor would be at the bottom waiting for new commands, so content description would have to start at the top and not at the cursor at command line. In text edit mode, the cursor would be aligned with text to be read, so likely more ideal. But even in text edit mode, when the cursor is at extreme right of terminal, there may still be text available to the right on the line of the file being read, in that case cursor position would still be same, even after horizontal scrolling.

The brltty app is also not considering if text field is multiline and cursor tracking trky is at wrong offset and even returning to text field after app switch seems to be broken.

Are there some standards available that should be supported by terminals for screen readers? There is some info on cursors at http://brltty.app/doc/Manual-BRLTTY/English/BRLTTY-5.html#ss5.1

I need more info on what's expected by a screen reader or a blind person so that an ideal system can be designed since obviously there are issues.

Console screen readers are available too and it might be possible to add native packages for them in termux. There was also work being done audio desktop like emacspeak at termux/termux-packages#6504

Android accessibility also has support for virtual views. So, for the terminal, I should be able to implement something like 3 modes. Possibly extras keys can be used to switch between the modes, but users would have to configure the extra keys, so not sure how convenient that would be at app install.

  • Window mode in which entire terminal text is set as content description and terminal is considered a single view.
  • Line mode in which each row is a separate view, allowing users to move between rows and having their text read.
  • Character mode in which each row and column is a separate view.

Currently, termux is using window mode and setting content description to the entire terminal text that is visible so TalkBalk starts reading text from the top everytime, which would obviously be annoying and time wasting. So line and character mode may be useful as well. It would also have to be decided if view mode should apply to all opened terminal sessions or only current one. I also don't know how screen readers handle incoming text, I am assuming its buffered and can be scrolled through and read separate from android.

Android has a sample for virtual views as well.

https://github.com/Miserlou/Android-SDK-Samples/blob/master/ApiDemos/src/com/example/android/apis/accessibility/AccessibilityNodeProviderActivity.java

Chromium also has extended accessibility support.

https://github.com/chromium/chromium/tree/main/content/public/android/java/src/org/chromium/content/browser/accessibility

Improving accessibility support via Android APIs would require collaboration will brltty devs, possibly @DaveMielke who seem to be handling android side. Any input on above would be appreciated.

@webczat
Copy link

webczat commented Jun 16, 2022

unsure if screenreaders which use speech can easily be made to work well with any kind of terminal on android. I hope it's possible but might not be, as their usage is kinda different compared to desktop screenreaders. Might be far better in case of braille, but I don't have any braille display. Console screenreaders can work in theory, in practice I managed to get a setup using proot archlinux and pulseaudio, it worked but was noticeably slower to be honest. Console screenreaders which are not linux specific often grab a pseudoterminal and don't care about anything else, just intercepting characters coming into or out of a pseudoterminal, so no support from termux is needed in that case except things these screenreaders want to use which normally don't work or things like sound/speech synthesis.

@agnostic-apollo
Copy link
Member

Well, proot is going to be slow, hence native support if possible would be better.

@webczat
Copy link

webczat commented Jun 16, 2022

well if any console screenreader would work without proot that would be something too. the one I have in mind probably doesn't.

@DaveMielke
Copy link

DaveMielke commented Jun 16, 2022 via email

@shindere
Copy link
Author

shindere commented Jun 16, 2022 via email

@DaveMielke
Copy link

DaveMielke commented Jun 16, 2022 via email

@agnostic-apollo
Copy link
Member

Could you please explain to me what your goal is?

The short term goal is to fix cursor position of the terminal being assumed by brltty.

The long term goal is to improve accessibility support for termux app and terminal. I don't know what kind of data or features screen readers or blind people would want from a terminal in terms of easier accessibility, so those goals are yet to be decided on. I also don't have a screen reader myself to test stuff out.

You mentioned that brltty doesn't work with multi-line text views. That isn't correct. It works fine with them.

The vertical offset doesn't seem to be correct in logs and is not 0 on first line and changes and something like 13 as per my tests, also gets messed up if I switch back to gmail email send edit screen, I don't know if it works well with the screen reader even with faulty values, or at least what I am assuming are faulty.

So all I need to do is to install the termux app?

You can install termux from https://github.com/termux/termux-app/actions/runs/2509869570 if you want to test the pull request #2840. You need apt-android-7 variants, like termux-app_v0.118.0+bd6347d-apt-android-7-github-debug_universal, unless you know your phone's arch. Don't use apt-android-5 variants, they are only for android 5/6, with legacy/unsupported packages.

That should hopefully be easily fixable. Is termmux using a TextView for the console content or is it using some other kind of view.

Termux uses a custom TerminalView, which is not a TextView or EditText.

https://github.com/termux/termux-app/blob/master/terminal-view/src/main/java/com/termux/view/TerminalView.java

How does termmux not knowing where the cursor is manifest itself?

Termux knows the cursor position. But since its not an EditText, brltty and other accessibility apps don't know the cursor position. Terminal apps/packages/text editors get position with a request for Cursor Position Report (CPR), but android accessibility can't use that obviously.

No text being selected is indicated by the start and the end of the selection being both set to the same offset, which is exactly where the cursor is. Put another way, text not selected is simply the devolved case of the selected text having a length of zero.

Issue with EditText is that its linear. The start and end index is based on position inside the linear text. The terminal is 2D, so cursor position is the row and column. However, we can extract all the text out of the terminal and convert row and column into a start and end index inside the text, but I am not sure if users want that, since users may want actual row and column when using a terminal.

I have opened the pull request #2840 in which termux sends the row and column via AccessibilityNodeInfo.extras to accessibility apps like brltty. You can apply this patch in your app to get the values. I don't know how you will get the row and column to the screen reader though, since they are not start and end index as already explained.

@DaveMielke
Copy link

DaveMielke commented Jun 16, 2022 via email

@agnostic-apollo
Copy link
Member

agnostic-apollo commented Jun 16, 2022

Firstly, I should add that I wasn't the one who implemented setting the entire terminal text to content description. It was before my time.

Secondly, yes I understand that content description should basically only be used to describe the content.

What I want to do is start fresh. What is the best way a terminal can transmit its text (not really its fonts and graphics) to a screen reader via android accessibility and what would make navigating the terminal easier for blind users, specially in respect to cursor. Note that terminals have two modes, one normal mode in which cursor is always at bottom waiting for new commands and another text edit mode used by nano, emacs, etc in which cursor can move around anywhere user wants.

I can make the TerminalView appear as TextView with virtual views for accessibility services, with the entire terminal as a single TextView, each line as a separate TextView or each character of each row and columns as a TextView. I discussed that in #2543 (comment). But I am not sure what's ideal since I don't have experience with screen readers.

Btw, by extra keys, it means the toolbar shown at the bottom in the terminal, with keys like HOME, and arrow keys, etc. It can be configured with custom keys via ~/.termux/termux.properties file, will require running termux-reload-settings for changes to take effect. If you swipe left on it, it will open an edit text that can be used to send text to terminal.

https://wiki.termux.com/wiki/Touch_Keyboard#Extra_Keys_Row

https://wiki.termux.com/wiki/Touch_Keyboard#Text_Input_View

https://wiki.termux.com/wiki/Terminal_Settings

Also I can't just convert the terminal view itself to TextView since terminals are very complicated and not just text. I can only make it appear as a TextView, possibly with virtual views. I haven't tested that yet though.

Maybe we can bring attention of someone who has worked on console screen reader support, they may be able to give some helpful info.

@DaveMielke
Copy link

DaveMielke commented Jun 16, 2022 via email

@DaveMielke
Copy link

DaveMielke commented Jun 16, 2022 via email

@shindere
Copy link
Author

shindere commented Jun 24, 2022 via email

@agnostic-apollo
Copy link
Member

I'll get back soon, got busy with other stuff. I implemented cursor positioning based on if both start and end selection indexes are same as suggested and as used by brltty. Need to do more testing to ensure everything is right.

Terminals are word wrapped as well, so standard selection index does not apply and each word wrap is a separate line.

@shindere
Copy link
Author

shindere commented Jun 24, 2022 via email

@DaveMielke
Copy link

DaveMielke commented Jun 24, 2022 via email

@agnostic-apollo
Copy link
Member

Note that brltty also supports selected text. So, if text is selected (which, on Android, also means that there's then no cursor) just set the start/end of the selection as needed.

I want to add text selection support but issue with terminal is that selection can be done anywhere in scroll back history, so if user is at bottom and selection is somewhere above in history, the selection text won't be visible or part of currently viewed text. Or only end cursor will be part of text. Although, could be handled by if both start and end indexes are visible, but user may want to select non visible and visible text as well, so gets complicated.

________________
|               |
|   Scroll back |
|  ^............|
| ........^     |
|_______________|                   
|               |
| Viewable text |
| on screen     |
|               |
|_______________|

That shouldn't matter. Just place newline (\n) separators at the right places within the TextView, and set the cursor position (or text selection) according to offsets within that same TextView.

Not using TextView currently, just setting visible text to AccessibilityNodeInfo.setText() and cursor to AccessibilityNodeInfo.setTextSelection(). The text passed is word wrapped as it looks when a user views a terminal. But since terminal stores cursor as row and column, and not index inside the word wrapped text (after newlines), need to translate row and column to a single index inside the text passed. It seemed to be working fine in brltty logs, just want to ensure there are no wrong offsets or calculations.

@DaveMielke
Copy link

DaveMielke commented Jun 24, 2022 via email

@shindere
Copy link
Author

shindere commented Jun 24, 2022 via email

@DaveMielke
Copy link

DaveMielke commented Jun 24, 2022 via email

@agnostic-apollo
Copy link
Member

agnostic-apollo commented Jun 24, 2022

Regardless of what's actually visible, a TextView always contains all of the text. A user should be able to select a huge chunk of text, which, of course, may not all fit on the screen. That's okay and should be allowed. Just set the selection start/end, and let screen scrolling handle it for sighted users and brltty handle it for braille users.

In context of terminal, I don't think that would be wise. Firstly, user wouldn't know what's actually on the screen if I pass entire terminal text and Talkback will also start reading from top of scroll back history every time instead of visible terminal.
Secondly, the terminal by default has 2000 rows and somewhere around 80 columns, so passing 2000*80=160KB on each terminal text update possibly happening many times a second is not really efficient and if accessibility is using binder transactions, which likely it is to transfer data to other apps, then that would trigger TransactionTooLargeException, since max limits are around 100KB, would need to test if it does trigger exception, not sure how browsers handle that. Rows can be increased to 50000, resulting in 4MB data, although likely a blind man may not do that.

When termux shares terminal text, it truncates the data to 100KB to prevent exceptions. I guess, when user goes into selection mode, then can start sending all the text, or after truncation.

https://www.reddit.com/r/tasker/comments/prro8t/autoshare_crashed_when_i_pasted_the_file_path/

@shindere
Copy link
Author

shindere commented Jun 24, 2022 via email

@shindere
Copy link
Author

shindere commented Jun 24, 2022 via email

@agnostic-apollo
Copy link
Member

agnostic-apollo commented Jun 24, 2022

If using termux without a sighted user, I'd definitely like it if I
could have the very same terminal than on Linux in terms of dimensions,
i.e. 25 rows of 80 columns.

You may be able to do that in landscape mode, not in portrait mode since rows would be greater than columns. I guess terminal margin could be adjusted with terminal-margin-horizontal and terminal-margin-vertical properties and/or terminal zoomed to appropriate font size with pinch and zoom of fingers to get that in portrait mode too.

@shindere
Copy link
Author

shindere commented Jun 24, 2022 via email

@DaveMielke
Copy link

DaveMielke commented Jun 24, 2022 via email

@shindere
Copy link
Author

shindere commented Jun 24, 2022 via email

@agnostic-apollo
Copy link
Member

The device is
called a BrailleSens 6, from HIMS.

You would still need to configure termux as per your rows and columns requirements so that data is sent to braille device accordingly. In future, shell APIs are planned to configure terminal font size, margins, rows, etc.

@DaveMielke
Copy link

DaveMielke commented Oct 11, 2022 via email

@shindere
Copy link
Author

shindere commented Oct 11, 2022 via email

@agnostic-apollo
Copy link
Member

Why not get out of the business of hard-coding these sizes.

The sizes are not technically hardcoded, just defaults exists. Pinch and zoom exists as you said to change the sizes. Terminal by default fills whatever the available space exists on the screen, other than keyboard if its open, just like how pretty much all android apps behave. In landscape mode, this results in columns being more than rows.

There are plans to add APIs to resize from command line, others have requested it too. I wasn't aware that blind people would prefer restricted sizes, so will keep it under consideration when implementing, specially allowing users to break aspect ratio. It won't happen in next release coming soon, but cursor position fix should be available.

@shindere
Copy link
Author

shindere commented Oct 11, 2022 via email

@agnostic-apollo
Copy link
Member

t would be helpful to have a mode where the size of the terminal does not take this space and orientation of the screen into account,

Yes, you are right, that will have to be taken care off too. Current, the font size is what defines the row and columns and font size is what's changed when pinch zoom is done.

What do you mean by "restricted"?

Not fill screen and use less than the available screen space.

If you need some testing I can try,

Sure, will let you know, you won't need to build, you would be able to download from github actions. But if you installed termux from F-Droid instead of Github, then will have to uninstall F-Droid version first since it has different signing key for apk.

@shindere
Copy link
Author

shindere commented Oct 11, 2022 via email

@agnostic-apollo
Copy link
Member

Would things really happen that way?

25 rows in landscape at all times would consume less than half the display size.

How many rows and columns does it have,approximately?

Depends on device display size and font size set by user. For me, 30-40 rows with keyboard open and 60-80 rows with it closed. Cols are around 75-80.

@shindere
Copy link
Author

shindere commented Oct 11, 2022 via email

@DaveMielke
Copy link

DaveMielke commented Oct 11, 2022 via email

@DaveMielke
Copy link

DaveMielke commented Oct 11, 2022 via email

@shindere
Copy link
Author

shindere commented Oct 11, 2022 via email

@DaveMielke
Copy link

DaveMielke commented Oct 12, 2022 via email

@shindere
Copy link
Author

shindere commented Oct 12, 2022 via email

@DaveMielke
Copy link

DaveMielke commented Oct 12, 2022 via email

@shindere
Copy link
Author

shindere commented Oct 12, 2022 via email

@Grimler91
Copy link
Member

A user on irc, "bgtlover", pointed out that one low hanging fruit that might help with accessibility would be to make the text input view the default when in (some sort of) accesibility mode.

@shindere
Copy link
Author

shindere commented Oct 12, 2022 via email

@Archenoth
Copy link
Contributor

Archenoth commented Oct 12, 2022

Seems indeed interesting! What is it that prevents from makingit the
default view or even the only view? Is it because it has a less
appealing rendering?

Oh! It's more an input mode rather than anything that renders a terminal.

It's usually accessed by swiping the extra "terminal keys" (A thing that lets you use arrow keys, or hit modifier keys without external hardware) off the screen to make way for a native input, which is easier to type on since you are no longer restricted to the "one character at a time" thing terminals do, and can benefit from OS support like autocompletion, or other things normal text boxes do that an addressed character display might not

A sighted user would probably gain more benefit from the extra keys over the native input in most general situations, but that might not hold true if you are using a screen reader, so switching the default when an accessibility mode is enabled might be a good first step at making things a little easier in those cases

@shindere
Copy link
Author

shindere commented Oct 15, 2022 via email

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

No branches or pull requests

7 participants