Commit e68fe0ec authored by David Tseng's avatar David Tseng Committed by Commit Bot

Prevent repeated output

In some instances, we receive a significant number of attribute changes within a short delay.

This change throws away attribute changes that generate the same output on the same target.

Test: manually on settings page. Verify that ChromeVox only announces the radio button once rather than > 30 times (and plays the radio button earcon 30 times).
Change-Id: I92127ad074b3a73ce269077cae6b69ba71f59c52
Reviewed-on: https://chromium-review.googlesource.com/1211972
Commit-Queue: David Tseng <dtseng@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#589700}
parent 88ff34cd
......@@ -293,8 +293,16 @@ Background.prototype = {
for (var prop in opt_speechProps)
o.format('!' + prop);
if (!skipOutput)
if (!skipOutput) {
o.go();
if (range.start.node) {
// Update the DesktopAutomationHandler's state as well to ensure event
// handlers don't repeat this output.
DesktopAutomationHandler.instance.updateLastAttributeState(
range.start.node, o);
}
}
},
/**
......
......@@ -48,6 +48,12 @@ DesktopAutomationHandler = function(node) {
/** @private {AutomationNode} */
this.lastValueTarget_ = null;
/** @private {AutomationNode} */
this.lastAttributeTarget_;
/** @private {Output} */
this.lastAttributeOutput_;
/** @private {string} */
this.lastRootUrl_ = '';
......@@ -151,6 +157,11 @@ DesktopAutomationHandler.prototype = {
output.withRichSpeechAndBraille(
ChromeVoxState.instance.currentRange, prevRange, evt.type);
output.go();
// Update some state here to ensure attribute changes don't duplicate
// output.
this.lastAttributeTarget_ = evt.target;
this.lastAttributeOutput_ = output;
},
/**
......@@ -166,12 +177,17 @@ DesktopAutomationHandler.prototype = {
if (prev.contentEquals(cursors.Range.fromNode(evt.target)) ||
evt.target.state.focused) {
// Intentionally skip setting range.
new Output()
.withRichSpeechAndBraille(
cursors.Range.fromNode(evt.target), prev,
Output.EventType.NAVIGATE)
.go();
var prevTarget = this.lastAttributeTarget_;
this.lastAttributeTarget_ = evt.target;
var prevOutput = this.lastAttributeOutput_;
this.lastAttributeOutput_ = new Output().withRichSpeechAndBraille(
cursors.Range.fromNode(evt.target), prev, Output.EventType.NAVIGATE);
if (evt.target == prevTarget && prevOutput &&
prevOutput.equals(this.lastAttributeOutput_))
return;
this.lastAttributeOutput_.go();
}
},
......@@ -466,6 +482,17 @@ DesktopAutomationHandler.prototype = {
this.shouldIgnoreDocumentSelectionFromAction_ = val;
},
/**
* Update the state for the last attribute change that occurred in ChromeVox
* output.
* @param {!AutomationNode} node
* @param {!Output} output
*/
updateLastAttributeState: function(node, output) {
this.lastAttributeTarget_ = node;
this.lastAttributeOutput_ = output;
},
/**
* Provides all feedback once a change event in a text field fires.
* @param {!AutomationEvent} evt
......
......@@ -1050,6 +1050,27 @@ Output.prototype = {
chrome.accessibilityPrivate.setFocusRing(this.locations_);
},
/**
* @return {boolean} True if this object is equal to |rhs|.
*/
equals: function(rhs) {
if (this.speechBuffer_.length != rhs.speechBuffer_.length ||
this.brailleBuffer_.length != rhs.brailleBuffer_.length)
return false;
for (var i = 0; i < this.speechBuffer_.length; i++) {
if (this.speechBuffer_[i].toString() != rhs.speechBuffer_[i].toString())
return false;
}
for (var j = 0; j < this.brailleBuffer_.length; j++) {
if (this.brailleBuffer_[j].toString() != rhs.brailleBuffer_[j].toString())
return false;
}
return true;
},
/**
* Renders the given range using optional context previous range and event
* type.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment