-
Notifications
You must be signed in to change notification settings - Fork 4
Screen reader not reading out adjusted force if mass moved twice #146
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
Comments
This does not happen on the Mass number-spinner-sliders. |
@jessegreenberg and @zepumph, just an FYI that this might not be a new bug. VoiceOver recovers quite easily, so it is not something that really sticks out. That said, I can reproduce it easily. |
Thanks for reporting. I am not able to reproduce with NVDA. @zepumph I will have access to a mac on Friday, I can take a look then. It sounds like we are missing the alert content. I can see the alerts in the a11y-view. My initial guess would be to increase the |
@jessegreenberg, I agree, I am not sure we want to increase the delay, but we can see if that has something to do with it. |
@jessegreenberg thanks, let me know if there is anything I can do to help. |
This doesn't happen every time you press arrow keys multiple times in a row, but it happens frequently. I still haven't been able to get it to happen for the mass spinners. EDITS to avoid spamming with new comments:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<input type="range" id="range-1" aria-orientation="horizontal" style="position: absolute; top: 100px;">
<input type="range" id="range-2">
<p id='live-element' aria-live="polite"></p>
</body>
<script type="text/javascript">
const range1 = document.getElementById( 'range-1');
const range2 = document.getElementById( 'range-2');
const liveElement = document.getElementById( 'live-element' );
let counter = 0;
let timeoutId = null;
const alertLater = ( alert ) => {
if ( timeoutId !== null )
window.clearTimeout( timeoutId );
timeoutId = window.setTimeout( () => {
liveElement.textContent = alert + ' ' + (++counter);
}, 1000 );
}
let topCounter = 0;
range1.addEventListener( 'change', ( event ) => {
range1.setAttribute( 'aria-valuetext', 'value: ' + range1.value );
alertLater( 'First Slider Changed' );
range1.style.top = 10 * topCounter++ + 'px';
} );
range2.addEventListener( 'change', ( event ) => {
range2.setAttribute( 'aria-valuetext', 'value: ' + range2.value );
alertLater( 'Second Slider Changed' );
} );
</script>
</html> I also tried disabling the css positioning of PDOM elements altogether and still saw the bug.
|
OK, so I think this is related to the length of the text used in <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<input type="range" id="range-1" aria-orientation="horizontal">
<input type="range" id="range-2">
<p id='live-element' aria-live="polite"></p>
</body>
<script type="text/javascript">
const range1 = document.getElementById( 'range-1');
const range2 = document.getElementById( 'range-2');
const liveElement = document.getElementById( 'live-element' );
let counter = 0;
let timeoutId = null;
const alertLater = ( alert ) => {
if ( timeoutId !== null )
window.clearTimeout( timeoutId );
timeoutId = window.setTimeout( () => {
liveElement.textContent = alert + ' ' + (++counter);
}, 1000 );
}
let topCounter = 0;
range1.addEventListener( 'change', ( event ) => {
range1.setAttribute( 'aria-valuetext', 'a very long aria-valuetext string that will take time to read: ' + range1.value );
alertLater( 'First Slider Changed' );
} );
range2.addEventListener( 'change', ( event ) => {
range2.setAttribute( 'aria-valuetext', 'a very long aria-valuetext string that will take time to read: ' + range2.value );
alertLater( 'Second Slider Changed' );
} );
</script>
</html> ValueChangeUtterance was added to work around this exact issue but assumed that the value-text would only be spoken once per interaction. In this case, the aria-valuetext is spoken twice or more to notify the user of each value change so we need to wait about the amount of time the screen reader reads all of the We should submit a bug report to Apple about this, alerts should be working in this case. We could probably work around this by creating a method that is like "make alertStableDelay dependent on the speed at which the user changed an input value so that VoiceOver has time to read queued aria-valuetext updates". We would probably add this workaround in AccessibleValueHandler. |
This diff is sort of what I was thinking, but I haven't tested it with GFLB yet. diff --git a/js/accessibility/AccessibleValueHandler.js b/js/accessibility/AccessibleValueHandler.js
index 46e6db4..d43a327 100644
--- a/js/accessibility/AccessibleValueHandler.js
+++ b/js/accessibility/AccessibleValueHandler.js
@@ -31,6 +31,8 @@ define( require => {
const SunConstants = require( 'SUN/SunConstants' );
const timer = require( 'AXON/timer' );
const Util = require( 'DOT/Util' );
+ const utteranceQueue = require( 'SCENERY_PHET/accessibility/utteranceQueue' );
+ const ValueChangeUtterance = require( 'SCENERY_PHET/accessibility/ValueChangeUtterance' );
const AccessibleValueHandler = {
@@ -127,6 +129,10 @@ define( require => {
*/
a11yCreateValueChangeAriaValueText: _.identity,
+ a11yCreateValueChangeAlert: () => {
+ return 'Alert Generated';
+ },
+
/**
* List the dependencies this Node's PDOM descriptions have. This should not include the valueProperty, but
* should list any Properties who's change should trigger description update for this Node.
@@ -247,6 +253,19 @@ define( require => {
// @private - {null|function} see options for doc
this.a11yCreateOnFocusAriaValueText = options.a11yCreateOnFocusAriaValueText;
+ // @private {null|function} see options for doc
+ this.a11yCreateValueChangeAlert = options.a11yCreateValueChangeAlert;
+
+ // @private {number} - number of times the input has changed in value before the valueChangeUtterance made
+ // was able to be spoken, only applicable if using a11yCreateValueChangeAlert
+ this.timesChangedBeforeAlerting = 0;
+
+ // @private - The utterance sent to the utteranceQueue when the value changes, alert content generated by
+ // optional a11yCreateValueChangeAlert. The alertStableDelay on this utterance will increase if the input
+ // receives many interactions before the utterance can be announced so that VoiceOver has time to read the
+ // aria-valuetext before the alert.
+ this.valueChangeUtterance = new ValueChangeUtterance();
+
this.setA11yDependencies( options.a11yDependencies );
// listeners, must be unlinked in dispose
@@ -265,7 +284,7 @@ define( require => {
// when the property changes, be sure to update the accessible input value and aria-valuetext which is read
// by assistive technology when the value changes
- const valuePropertyListener = () => {
+ const valuePropertyListener = ( value, oldValue ) => {
const formattedValue = this.getA11yFormattedValue();
@@ -276,6 +295,23 @@ define( require => {
// update the PDOM input value on Property change
this.inputValue = formattedValue;
+
+ if ( this.a11yCreateValueChangeAlert ) {
+ this.valueChangeUtterance.reset();
+
+ this.valueChangeUtterance.alert = this.a11yCreateValueChangeAlert( formattedValue, value, oldValue );
+
+ if ( utteranceQueue.hasUtterance( this.valueChangeUtterance ) ) {
+ this.timesChangedBeforeAlerting++;
+ }
+ else {
+ this.timesChangedBeforeAlerting = 1;
+ }
+ const delayTime = this.timesChangedBeforeAlerting * ValueChangeUtterance.DEFAULT_STABLE_DELAY;
+ this.valueChangeUtterance.alertStableDelay = delayTime;
+
+ utteranceQueue.addToBack( this.valueChangeUtterance );
+ }
};
this._valueProperty.link( valuePropertyListener );
I think VoiceOver does collapse some of the back to back aria-valuetext so maybe we only have to increase alertStableDelay by a factor of 2 or 3 in this case, but I don't know for certain yet. @zepumph what do you think about this? It adds complexity to AccessibleValueHandler. It is brittle because it only works with certain user settings. That is true for ValueChangeUtterance, but this increases the investment into this workaround. It is an issue with VoiceOver and I don't know if we should spend time changing AccessibleValueHandler and slider usages for this. I am not certain that this will actually work. On the other hand, is it generally beneficial to have a valueChangeUtterance come with AccessibleValueHandler since often we want |
@jessegreenberg let's talk about this tomorrow! @twant and I noticed the following thoughts:
|
There definitely could be, it just seemed like a reasonable starting place. 1000 was determined to be a decent workaround value for this issue when there is only one aria-valuetext to read. So the thought was to multiply this by the number of times we expect aria-valuetext to be read when keys are pressed multiple times.
From what I have seen, it is the length of the aria-valuetext, not the length of the alert. So this variable represents the number of times we expect VO to read an aria-valuetext before reading an alert. |
I was preparing a bug report for Apple when I realized that the example HTML where this is happening is still pretty complicated. And when I removed the window.setTimeout in #146 (comment) the problem went away. So this isn't as straight forward as I thought, its more like there is a window of time where sending an alert to VoiceOver is bad. If set immediately on |
This HTML does resolve the issue. <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<input type="range" id="range-1">
<input type="range" id="range-2">
<p id='live-element' aria-live="polite"></p>
</body>
<script type="text/javascript">
const range1 = document.getElementById( 'range-1');
const range2 = document.getElementById( 'range-2');
const liveElement = document.getElementById( 'live-element' );
let counter = 0;
let timeoutId = null;
let changeCountBeforeAlerting = 0;
let alertContent = null;
const alertLater = ( alert ) => {
'use strict';
window.clearTimeout( timeoutId );
if ( alertContent !== null ) {
changeCountBeforeAlerting++
}
else {
changeCountBeforeAlerting = 0;
}
alertContent = alert + ' ' + (++counter);
timeoutId = window.setTimeout( () => {
liveElement.textContent = alertContent;
alertContent = null;
changeCountBeforeAlerting = 0;
}, 1000 * ( changeCountBeforeAlerting + 1 ) );
}
let topCounter = 0;
range1.addEventListener( 'change', ( event ) => {
range1.setAttribute( 'aria-valuetext', 'a very long aria-valuetext string that will take time to read: ' + range1.value );
alertLater( 'First Slider Changed' );
} );
range2.addEventListener( 'change', ( event ) => {
range2.setAttribute( 'aria-valuetext', 'a very long aria-valuetext string that will take time to read: ' + range2.value );
alertLater( 'Second Slider Changed' );
} );
</script>
</html> As @zepumph and @twant mentioned, this delay is probably much longer than it needs to be. VO reads at most 2 aria-valuetext updates when keys are pressed multiple times, so maybe we just need to delay by 1000 * 2 ms in this case. |
… change its alertStableDelay when there are multiple interactions before an alert can be spoken, see phetsims/gravity-force-lab-basics#146
@jessegreenberg and I worked on this, basically committing the diff that @jessegreenberg created in #146 (comment). We found that it worked very well, and couldn't reproduce the bug with the changes, but there are a lot of factors at play here:
We didn't commit our hacky changes to GFLB, so currently there is no way to test this. I will work on a better solution this afternoon, and then ask @terracoda to review. |
@jessegreenberg refreshed phetdev (dev.39) and now the bug is much more reproduce-able. How strange! |
@terracoda I added some temporary code to GFLB so that we could test this out. If it seems like the direction we should go, then I can clean it up. Let me know what you think. |
@zepumph, I think you nailed it. The alerts are no longer stopping. Assigning back to you. |
May be related to this known issue:
If it is and the above solution is effective, it may be worth expanding to other sims. |
Thanks @KatieWoe for tagging those issues. I'll let @zepumph comment, but I don't think either of those issues are related. The Ohm's Law issue was about information in I'll let @zepumph comment further about whether this issue is completed and ready to close. |
I think this is ready to be closed, but I did happen on one last todo from #156: this.positionUtterance = new ValueChangeUtterance(); // TODO: delete me depending on https://github.com/phetsims/gravity-force-lab-basics/issues/146 Usages are already commented out so I think this can be removed, but I will let @zepumph comment for certain. |
Ah I see some other TODO code related to this so it may not be quite ready
|
I did the needed refactoring, and now the only things pointing to this issue are the warnings @jessegreenberg and I added purposefully. I think this is ready to close. @terracoda can you just give a once over to make sure the descriptions still sound as expected? |
@zepumph, all still sounds good on MacOS 10.13.6 with VoiceOver and Safari 12.1.1. |
For phetsims/qa#333
Test Device
Jordan
Operating System
Mac OS 10.14.5
Browser
Safari 12.1.1
Problem Description
If either mass if moved more than once in either direction, the screen reader will read the new distance of the two masses, but it will not read out the new adjusted force.
Steps to Reproduce
1: Go to the sim, turn on Voice Over
2: Using keyboard nav, select a mass
3: Move the mass with the arrow keys at least twice in one direction
Visuals
https://drive.google.com/open?id=16wYOZK75nVWuJ9aPZKKshZ6KvugHFhld
The text was updated successfully, but these errors were encountered: