blob: 6202879ccfc980aa897f83c43bcf20ba019fd9aa [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Constant to indicate selection index is not set.
const NO_SELECTION = -1;
/**
* Class to handle text input for improved accuracy and efficiency.
*/
class TextInputManager {
/** @param {!NavigationManager} navigationManager */
constructor(navigationManager) {
/** @private {chrome.automation.AutomationNode} */
this.node_;
/** @private {!NavigationManager} */
this.navigationManager_ = navigationManager;
/** @private {!chrome.accessibilityPrivate.FocusRingInfo} */
this.textInputFocusRing_ = {
id: SAConstants.Focus.TEXT_ID,
rects: [],
type: chrome.accessibilityPrivate.FocusType.DASHED,
color: SAConstants.Focus.PRIMARY_COLOR,
secondaryColor: SAConstants.Focus.SECONDARY_COLOR
};
/** @private {number} */
this.selectionStart_ = NO_SELECTION;
/** @private {number} */
this.selectionEnd_ = NO_SELECTION;
}
/**
* Enters the keyboard and draws the text input focus ring.
* @param {!chrome.automation.AutomationNode} node
*/
enterKeyboard(node) {
if (!SwitchAccessPredicate.isTextInput(node))
return false;
this.node_ = node;
this.drawFocusRingForTextInput_();
return true;
}
/** Resets the focus ring and the focus in |navigationManager_|. */
returnToTextFocus() {
if (!this.node_)
return;
this.clearFocusRingForTextInput_();
this.navigationManager_.exitCurrentScope(this.node_);
this.node_ = null;
}
/**
* Sends a keyEvent to click the center of the provided node.
* @param {!chrome.automation.AutomationNode} node
* @return {boolean} Whether a key was pressed.
*/
pressKey(node) {
if (node.role !== chrome.automation.RoleType.BUTTON)
return false;
if (!this.inVirtualKeyboard(node))
return false;
const x = node.location.left + Math.round(node.location.width / 2);
const y = node.location.top + Math.round(node.location.height / 2);
chrome.accessibilityPrivate.sendSyntheticMouseEvent({
type: chrome.accessibilityPrivate.SyntheticMouseEventType.PRESS,
x: x,
y: y
});
setTimeout(
() => chrome.accessibilityPrivate.sendSyntheticMouseEvent({
type: chrome.accessibilityPrivate.SyntheticMouseEventType.RELEASE,
x: x,
y: y
}),
SAConstants.KEY_PRESS_DURATION_MS);
return true;
}
/**
* Returns the container with a role of keyboard.
* @param {!chrome.automation.AutomationNode} desktop
* @return {chrome.automation.AutomationNode}
*/
getKeyboard(desktop) {
let treeWalker = new AutomationTreeWalker(
desktop, constants.Dir.FORWARD,
{visit: (node) => node.role === chrome.automation.RoleType.KEYBOARD});
const keyboardContainer = treeWalker.next().node;
treeWalker =
new AutomationTreeWalker(keyboardContainer, constants.Dir.FORWARD, {
visit: (node) => SwitchAccessPredicate.isGroup(node, node),
root: (node) => node === keyboardContainer
});
return treeWalker.next().node;
}
/**
* Checks if |node| is in the virtual keyboard.
* @param {!chrome.automation.AutomationNode} node
* @return {boolean}
*/
inVirtualKeyboard(node) {
if (node.role === chrome.automation.RoleType.KEYBOARD)
return true;
if (node.parent)
return this.inVirtualKeyboard(node.parent);
return false;
}
/**
* Draws a dashed focus ring around the active text input, so the user can
* easily reference where they are typing.
* @private
*/
drawFocusRingForTextInput_() {
if (!this.node_)
return;
this.textInputFocusRing_.rects = [this.node_.location];
chrome.accessibilityPrivate.setFocusRings([this.textInputFocusRing_]);
return true;
}
/**
* Clears the focus ring around the active text input.
* @private
*/
clearFocusRingForTextInput_() {
this.textInputFocusRing_.rects = [];
chrome.accessibilityPrivate.setFocusRings([this.textInputFocusRing_]);
}
/**
* IN PROGRESS TEXT SELECTION BELOW
* TODO(rosalindag): Move this into the text navigation file when
* creation of that file is merged
*/
/**
* TODO(rosalindag): Check for value is -1 for selectionStart and
* selectionEnd and handle error.
*
* TODO(rosalindag): Add variables to pass into anchorObject and focusObject.
*
* Sets the selection using the selectionStart and selectionEnd
* as the offset input for setDocumentSelection and the parameter
* textNode as the object input for setDocumentSelection.
* @param {!chrome.automation.AutomationNode} textNode
* @private
*/
setSelection_(textNode) {
chrome.automation.setDocumentSelection({
anchorObject: textNode,
anchorOffset: this.selectionStart_,
focusObject: textNode,
focusOffset: this.selectionEnd_
});
}
/**
* Sets the selectionStart variable based on the selection of the current
* node.
* @public
*/
setSelectStart() {
var textNode = this.navigationManager_.currentNode();
this.selectionStart_ = textNode.textSelStart;
}
/**
* Sets the selectionEnd variable based on the selection of the current node.
* @public
*/
setSelectEnd() {
var textNode = this.navigationManager_.currentNode();
this.selectionEnd_ = textNode.textSelEnd;
this.setSelection_(textNode);
}
}