Commit f99e3ee6 authored by Josiah K's avatar Josiah K Committed by Chromium LUCI CQ

[Switch Access] UX to support adding device specific keys

Currently, when Switch Access captures a switch, it doesn't care which device it comes from. For example, if you have a Bluetooth switch that emulates keyboard keys '1' and '3', those keys will also be intercepted for Switch Access from your built-in Chromebook keyboard. Ideally, we would be able to distinguish between keys depending on the device they come from. Structural code in place at crrev.com/c/2613009.

Before: https://screenshot.googleplex.com/7StUsjssf5XqmzG
After: https://screenshot.googleplex.com/4EhHjsYdJUqBQ4G

Fixed: 1163371
AX-Relnotes: N/A.
Change-Id: I610e25bd9057db2ecb7b470e3990ef4a27c0444b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2610992
Commit-Queue: Josiah Krutz <josiahk@google.com>
Reviewed-by: default avatarJosiah Krutz <josiahk@google.com>
Reviewed-by: default avatarJimmy Gong <jimmyxgong@chromium.org>
Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#841708}
parent e306d88c
......@@ -981,6 +981,18 @@
<message name="IDS_SETTINGS_ASSIGN_PREVIOUS_SWITCH_LABEL" desc="Label for the setting to assign a switch to the action 'Previous', which moves focus to the previous element.">
Previous
</message>
<message name="IDS_SETTINGS_SWITCH_ACCESS_INTERNAL_DEVICE_TYPE_LABEL" desc="Label to apply to a switch key from the built-in keyboard. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer.">
Built-in Keyboard
</message>
<message name="IDS_SETTINGS_SWITCH_ACCESS_USB_DEVICE_TYPE_LABEL" desc="Label to apply to a switch key from a USB device. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer.">
USB
</message>
<message name="IDS_SETTINGS_SWITCH_ACCESS_BLUETOOTH_DEVICE_TYPE_LABEL" desc="Label to apply to a switch key from a Bluetooth device. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer.">
Bluetooth
</message>
<message name="IDS_SETTINGS_SWITCH_ACCESS_UNKNOWN_DEVICE_TYPE_LABEL" desc="Label to apply to a switch key from an unknown device. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer.">
Unknown
</message>
<message name="IDS_SETTINGS_SWITCH_ACCESS_AUTO_SCAN_HEADING" desc="Heading for the settings section containing preferences around Switch Access automatically scanning between elements.">
Auto-scan
</message>
......@@ -1018,6 +1030,9 @@ Press an assigned switch to remove assignment.
<message name="IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WARN_CANNOT_REMOVE_LAST_SELECT_SWITCH" desc="A message warning the user that they cannot remove the last switch for the Select action. The text for the 'Select' action should be the same as the text from IDS_SETTINGS_ASSIGN_SELECT_SWITCH_LABEL. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer.">
Can’t remove the only switch assigned to Select. Press any key to exit.
</message>
<message name="IDS_SETTINGS_SWITCH_AND_DEVICE_TYPE" desc="Label describing a switch key and the type of device where the switch key exists. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer.">
<ph name="SWITCH">$1<ex>backspace</ex></ph> (<ph name="DEVICE_TYPE">$2<ex>USB</ex></ph>)
</message>
<message name="IDS_SETTINGS_ASSIGN_SWITCH_SUB_LABEL_0_SWITCHES" desc="A sub-label for the link that brings up a dialog to assign a switch key to an action. Mentions zero switches assigned. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer.">
0 switches assigned
</message>
......
78fd8642607158a85cccfdae2f9010d31159557a
\ No newline at end of file
8f25638a049f853967bb36884a5268cc1a6bb900
\ No newline at end of file
68520afc794c4bbe462225083e5ffd4260609c21
\ No newline at end of file
89ff98103ccc56bed9c14266bb14d98f21e95062
\ No newline at end of file
b68015e4ec78c3b22610a284e6180f8bcaa676d1
\ No newline at end of file
......@@ -129,9 +129,9 @@ js_type_check("closure_compile_module") {
# ":os_a11y_page.m",
":os_a11y_page_browser_proxy.m",
":switch_access_action_assignment_dialog.m",
":switch_access_constants.m",
# ":switch_access_subpage.m",
":switch_access_subpage_browser_proxy.m",
":tts_subpage.m",
......
......@@ -91,7 +91,7 @@
class$="icon [[computeIcon_(assignment, assignmentState_)]]-icon"
aria-label="[[computeIconLabel_(assignment, assignmentState_)]]">
</iron-icon>
[[assignment.key]]
[[getLabelForAssignment_(assignment)]]
</div>
</template>
</template>
......
......@@ -36,18 +36,6 @@
previous: 'settings.a11y.switch_access.previous.device_key_codes'
};
/**
* Possible device types for Switch Access.
* @enum {string}
* @private
*/
/* #export */ const SwitchAccessDeviceType = {
INTERNAL: 'internal',
USB: 'usb',
BLUETOOTH: 'bluetooth',
UNKNOWN: 'unknown'
};
/**
* Various icons representing the state of a given key assignment.
* @enum {string}
......@@ -59,9 +47,44 @@
};
/**
* @typedef {!Array<!Object<string, !Array<!SwitchAccessDeviceType>>>}
* Mapping of a stringified key code to a list of Switch Access device types
* for that key code.
* @typedef {!Object<string, !Array<!SwitchAccessDeviceType>>}
*/
let SwitchAccessKeyAssignmentInfoMapping;
/**
* @param {!SwitchAccessDeviceType} deviceType
* @return {string}
*/
let SwitchAccessKeyAssignmentInfoList;
/* #export */ function getLabelForDeviceType(deviceType) {
switch (deviceType) {
case SwitchAccessDeviceType.INTERNAL:
return I18nBehavior.i18nAdvanced(
'switchAccessInternalDeviceTypeLabel', {});
case SwitchAccessDeviceType.USB:
return I18nBehavior.i18nAdvanced('switchAccessUsbDeviceTypeLabel', {});
case SwitchAccessDeviceType.BLUETOOTH:
return I18nBehavior.i18nAdvanced(
'switchAccessBluetoothDeviceTypeLabel', {});
case SwitchAccessDeviceType.UNKNOWN:
return I18nBehavior.i18nAdvanced(
'switchAccessUnknownDeviceTypeLabel', {});
}
throw new Error('Invalid device type.');
}
/**
* Converts assignment object to pretty-formatted label.
* E.g. {key: 'Escape', device: 'usb'} -> 'Escape (USB)'
* @param {{key: string, device: !SwitchAccessDeviceType}} assignment
* @return {string}
*/
/* #export */ function getLabelForAssignment(assignment) {
return I18nBehavior.i18nAdvanced('switchAndDeviceType', {
substitutions: [assignment.key, getLabelForDeviceType(assignment.device)]
});
}
Polymer({
is: 'settings-switch-access-action-assignment-dialog',
......@@ -93,8 +116,7 @@ Polymer({
/**
* Assignments for the current action.
* @private {Array<!{key: string, devices:
* !Array<!SwitchAccessDeviceType>}>}
* @private {!Array<{key: string, device: !SwitchAccessDeviceType}>}
*/
assignments_: {
type: Array,
......@@ -113,12 +135,14 @@ Polymer({
/**
* A dictionary containing all Switch Access key codes (mapped from
* actions).
* Each key code is another object, mapping a stringified key code to a list
* of Switch Access device types for that key code.
* TODO: Consider changing from list of devices to a set/map of devices,
* to guarantee uniqueness and better represent the underlying state (a
* device either is or isn't associated with a given key code, and order of
* devices doesn't matter)
* @private {{
* select: SwitchAccessKeyAssignmentInfoList,
* next: SwitchAccessKeyAssignmentInfoList,
* previous: SwitchAccessKeyAssignmentInfoList
* select: SwitchAccessKeyAssignmentInfoMapping,
* next: SwitchAccessKeyAssignmentInfoMapping,
* previous: SwitchAccessKeyAssignmentInfoMapping
* }}
*/
keyCodes_: {
......@@ -150,14 +174,14 @@ Polymer({
/** @private {!string} */
currentKey_: String,
/** @private {!string} */
unexpectedKey_: String,
/** @private {?number} */
currentKeyCode_: {
type: Number,
value: null,
},
/** @private {!SwitchAccessDeviceType} */
currentDeviceType_: String,
},
/** @private {?SwitchAccessSubpageBrowserProxy} */
......@@ -234,6 +258,7 @@ Polymer({
handleKeyEventInWaitForKey_(event) {
this.currentKeyCode_ = event.keyCode;
this.currentKey_ = event.key;
this.currentDeviceType_ = event.device;
if (!this.currentKey_) {
this.assignmentState_ = AssignmentState.WARN_UNRECOGNIZED_KEY;
......@@ -242,7 +267,9 @@ Polymer({
// Check for pre-existing assignments in actions other than the current one.
for (const action of Object.values(SwitchAccessCommand)) {
if (!this.keyCodes_[action][event.keyCode]) {
if (!this.keyCodes_[action][event.keyCode] ||
!this.keyCodes_[action][event.keyCode].includes(
this.currentDeviceType_)) {
continue;
}
......@@ -261,7 +288,9 @@ Polymer({
return;
}
this.assignmentState_ = AssignmentState.WAIT_FOR_CONFIRMATION;
this.push('assignments_', this.currentKey_);
this.push(
'assignments_',
{key: this.currentKey_, device: this.currentDeviceType_});
},
/**
......@@ -272,21 +301,30 @@ Polymer({
* @private
*/
handleKeyEventInWaitForConfirmation_(event) {
if (this.currentKeyCode_ === event.keyCode) {
// Confirmed.
// TODO: resolve to specific device type once UI is hooked up;
// |event.device| has the Switch Access device type.
this.keyCodes_[this.action][this.currentKeyCode_] = [
SwitchAccessDeviceType.INTERNAL, SwitchAccessDeviceType.USB,
SwitchAccessDeviceType.BLUETOOTH
];
this.$.switchAccessActionAssignmentDialog.close();
if (this.currentKeyCode_ !== event.keyCode ||
this.currentDeviceType_ !== event.device) {
this.assignmentState_ = AssignmentState.WARN_NOT_CONFIRMED;
return;
}
// Not confirmed.
this.unexpectedKey_ = event.key;
this.assignmentState_ = AssignmentState.WARN_NOT_CONFIRMED;
// Save the key to |this.keyCodes_| for inclusion into prefs later.
const keyAssignmentInfoMapping = this.keyCodes_[this.action];
if (!keyAssignmentInfoMapping) {
throw new Error('Expected valid pref for action: ' + this.action);
}
let devices = keyAssignmentInfoMapping[this.currentKeyCode_];
if (!devices) {
// |this.currentKeyCode_| was not set as a switch key for |this.action|
// before.
devices = [];
keyAssignmentInfoMapping[this.currentKeyCode_] = devices;
}
if (!devices.includes(event.device)) {
// A new device for the current key code has been added.
devices.push(event.device);
}
this.$.switchAccessActionAssignmentDialog.close();
},
/**
......@@ -297,14 +335,18 @@ Polymer({
* @private
*/
handleKeyEventInWaitForConfirmationRemoval_(event) {
if (this.currentKeyCode_ !== event.keyCode) {
this.unexpectedKey_ = event.key;
if (this.currentKeyCode_ !== event.keyCode ||
this.currentDeviceType_ !== event.device) {
this.assignmentState_ = AssignmentState.WARN_NOT_CONFIRMED_REMOVAL;
return;
}
// Remove this key code.
delete this.keyCodes_[this.action][this.currentKeyCode_];
// Remove this device type for this key code.
const devices = this.keyCodes_[this.action][this.currentKeyCode_];
devices.splice(devices.indexOf(event.device), 1);
if (!devices.length) {
delete this.keyCodes_[this.action][this.currentKeyCode_];
}
this.$.switchAccessActionAssignmentDialog.close();
},
......@@ -315,8 +357,8 @@ Polymer({
},
/**
* @param {!Object<SwitchAccessCommand, !Array<!{key: string, devices:
* !Array<SwitchAccessDeviceType>}>>} value
* @param {!Object<SwitchAccessCommand, !Array<{key: string, device:
* !SwitchAccessDeviceType}>>} value
* @private
*/
onAssignmentsChanged_(value) {
......@@ -341,6 +383,15 @@ Polymer({
}
},
/**
* @param {{key: string, device: !SwitchAccessDeviceType}} assignment
* @return {string}
* @private
*/
getLabelForAssignment_(assignment) {
return getLabelForAssignment(assignment);
},
/**
* @param {SwitchAccessCommand} action
* @return {string}
......@@ -355,12 +406,13 @@ Polymer({
/**
* Returns the image to use for the assignment's icon. The value must match
* one of iron-icon's os-settings:(*) icon names.
* @param {string} assignment
* @param {{key: string, device: !SwitchAccessDeviceType}} assignment
* @return {AssignmentIcon}
* @private
*/
computeIcon_(assignment) {
if (assignment !== this.currentKey_) {
if (assignment.key !== this.currentKey_ ||
assignment.device !== this.currentDeviceType_) {
return AssignmentIcon.ASSIGNED;
}
......@@ -382,7 +434,7 @@ Polymer({
/**
* Returns the icon label describing the icon for the specified assignment.
* @param {string} assignment
* @param {{key: string, device: !SwitchAccessDeviceType}} assignment
* @return {string}
* @private
*/
......@@ -403,7 +455,7 @@ Polymer({
/**
* @param {!AssignmentState} assignmentState
* @param {!Array<string>} assignments
* @param {!Array<{key: string, device: !SwitchAccessDeviceType}>} assignments
* @return {string}
* @private
*/
......
......@@ -11,3 +11,14 @@
PREVIOUS: 'previous',
SELECT: 'select'
};
/**
* Possible device types for Switch Access.
* @enum {string}
*/
/* #export */ const SwitchAccessDeviceType = {
INTERNAL: 'internal',
USB: 'usb',
BLUETOOTH: 'bluetooth',
UNKNOWN: 'unknown'
};
\ No newline at end of file
......@@ -12,7 +12,7 @@
<link rel="import" href="../../settings_shared_css.html">
<link rel="import" href="switch_access_action_assignment_dialog.html">
<link rel="import" href="switch_access_constants.html">
+<link rel="import" href="switch_access_subpage_browser_proxy.html">
<link rel="import" href="switch_access_subpage_browser_proxy.html">
<dom-module id="settings-switch-access-subpage">
<template>
......
......@@ -49,21 +49,21 @@ Polymer({
notify: true,
},
/** @private {Array<string>} */
/** @private {!Array<{key: string, device: !SwitchAccessDeviceType}>} */
selectAssignments_: {
type: Array,
value: [],
notify: true,
},
/** @private {Array<string>} */
/** @private {!Array<{key: string, device: !SwitchAccessDeviceType}>} */
nextAssignments_: {
type: Array,
value: [],
notify: true,
},
/** @private {Array<string>} */
/** @private {!Array<{key: string, device: !SwitchAccessDeviceType}>} */
previousAssignments_: {
type: Array,
value: [],
......@@ -202,23 +202,34 @@ Polymer({
},
/**
* @param {!Object<SwitchAccessCommand, !Array<string>>} value
* @param {!Object<SwitchAccessCommand, !Array<{key: string, device:
* !SwitchAccessDeviceType}>>} value
* @private
*/
onAssignmentsChanged_(value) {
// TODO: include |v.devices| for each key in UI.
this.selectAssignments_ = value[SwitchAccessCommand.SELECT].map(v => v.key);
this.nextAssignments_ = value[SwitchAccessCommand.NEXT].map(v => v.key);
this.previousAssignments_ =
value[SwitchAccessCommand.PREVIOUS].map(v => v.key);
this.selectAssignments_ = value[SwitchAccessCommand.SELECT];
this.nextAssignments_ = value[SwitchAccessCommand.NEXT];
this.previousAssignments_ = value[SwitchAccessCommand.PREVIOUS];
},
/**
* @param {!Array<string>} switches List of switch names
* @return {string} (e.g. 'Alt, Backspace, Enter, and 4 more switches')
* @param {{key: string, device: !SwitchAccessDeviceType}} assignment
* @return {string}
* @private
*/
getAssignSwitchSubLabel_(switches) {
getLabelForAssignment_(assignment) {
return getLabelForAssignment(assignment);
},
/**
* @param {!Array<{key: string, device: !SwitchAccessDeviceType}>} assignments
* List of assignments
* @return {string} (e.g. 'Alt (USB), Backspace, Enter, and 4 more switches')
* @private
*/
getAssignSwitchSubLabel_(assignments) {
const switches =
assignments.map(assignment => this.getLabelForAssignment_(assignment));
switch (switches.length) {
case 0:
return this.i18n('assignSwitchSubLabel0Switches');
......
......@@ -106,7 +106,7 @@ os_settings_auto_imports = settings_auto_imports +
"chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_account_manager_browser_proxy.html|NearbyAccountManagerBrowserProxy,NearbyAccountManagerBrowserProxyImpl",
"chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_receive_manager.html|setReceiveManagerForTesting,getReceiveManager,observeReceiveManager",
"chrome/browser/resources/settings/chromeos/nearby_share_page/types.html|NearbyShareDataUsage,dataUsageStringToEnum",
"chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_constants.html|SwitchAccessCommand",
"chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_constants.html|SwitchAccessCommand,SwitchAccessDeviceType",
"chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_subpage_browser_proxy.html|SwitchAccessSubpageBrowserProxy,SwitchAccessSubpageBrowserProxyImpl",
"chrome/browser/resources/settings/chromeos/os_a11y_page/tts_subpage_browser_proxy.html|TtsSubpageBrowserProxy,TtsSubpageBrowserProxyImpl",
"chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.html|generateOptions,getFirstPartyInputMethodEngineId,getOptionLabelName,getOptionMenuItems,getOptionUiType,getOptionUrl,hasOptionsPageInSettings,InputToolCode,isNumberValue,OPTION_DEFAULT,OptionType,UiType",
......
......@@ -509,6 +509,14 @@ void AccessibilitySection::AddLoadTimeData(
{"assignSelectSwitchLabel", IDS_SETTINGS_ASSIGN_SELECT_SWITCH_LABEL},
{"assignNextSwitchLabel", IDS_SETTINGS_ASSIGN_NEXT_SWITCH_LABEL},
{"assignPreviousSwitchLabel", IDS_SETTINGS_ASSIGN_PREVIOUS_SWITCH_LABEL},
{"switchAccessInternalDeviceTypeLabel",
IDS_SETTINGS_SWITCH_ACCESS_INTERNAL_DEVICE_TYPE_LABEL},
{"switchAccessUsbDeviceTypeLabel",
IDS_SETTINGS_SWITCH_ACCESS_USB_DEVICE_TYPE_LABEL},
{"switchAccessBluetoothDeviceTypeLabel",
IDS_SETTINGS_SWITCH_ACCESS_BLUETOOTH_DEVICE_TYPE_LABEL},
{"switchAccessUnknownDeviceTypeLabel",
IDS_SETTINGS_SWITCH_ACCESS_UNKNOWN_DEVICE_TYPE_LABEL},
{"switchAccessActionAssignmentDialogAssignedIconLabel",
IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ASSIGNED_ICON_LABEL},
{"switchAccessActionAssignmentDialogAddAssignmentIconLabel",
......@@ -535,6 +543,7 @@ void AccessibilitySection::AddLoadTimeData(
IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WAIT_FOR_CONFIRMATION_REMOVAL_PROMPT},
{"switchAccessActionAssignmentDialogWarnCannotRemoveLastSelectSwitch",
IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WARN_CANNOT_REMOVE_LAST_SELECT_SWITCH},
{"switchAndDeviceType", IDS_SETTINGS_SWITCH_AND_DEVICE_TYPE},
{"noSwitchesAssigned", IDS_SETTINGS_NO_SWITCHES_ASSIGNED},
{"switchAccessActionAssignmentDialogExit",
IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_EXIT},
......
......@@ -137,15 +137,17 @@ void SwitchAccessHandler::OnKeyEvent(ui::KeyEvent* event) {
base::DictionaryValue response;
response.SetIntPath("keyCode", static_cast<int>(event->key_code()));
response.SetStringPath("key", GetStringForKeyboardCode(event->key_code()));
ui::InputDeviceType deviceType = ui::INPUT_DEVICE_UNKNOWN;
int source_device_id = event->source_device_id();
for (const auto& keyboard :
ui::DeviceDataManager::GetInstance()->GetKeyboardDevices()) {
if (source_device_id == keyboard.id) {
response.SetStringPath("device", GetSwitchAccessDevice(keyboard.type));
deviceType = keyboard.type;
break;
}
}
response.SetStringPath("device", GetSwitchAccessDevice(deviceType));
FireWebUIListener("switch-access-got-key-press-for-assignment", response);
}
......@@ -186,17 +188,18 @@ void SwitchAccessHandler::OnSwitchAccessAssignmentsUpdated() {
auto* keycodes = prefs_->GetDictionary(info.pref_name);
base::ListValue keys;
for (const auto& item : keycodes->DictItems()) {
base::DictionaryValue key;
int key_code;
if (!base::StringToInt(item.first, &key_code)) {
NOTREACHED();
return;
}
key.SetStringPath("key", GetStringForKeyboardCode(
static_cast<ui::KeyboardCode>(key_code)));
key.SetPath("devices", item.second.Clone());
keys.Append(std::move(key));
for (const base::Value& device_type : item.second.GetList()) {
base::DictionaryValue key;
key.SetStringPath("key", GetStringForKeyboardCode(
static_cast<ui::KeyboardCode>(key_code)));
key.SetStringPath("device", device_type.GetString());
keys.Append(std::move(key));
}
}
response.SetPath(info.action_name_for_js, std::move(keys));
}
......
......@@ -101,7 +101,7 @@ suite('ManageAccessibilityPageTests', function() {
*/
function getSublabelForSelectUpdates(keys) {
cr.webUIListenerCallback('switch-access-assignments-changed', {
select: keys.map(key => ({key, devices: ['internal']})),
select: keys.map(key => ({key, device: 'usb'})),
next: [],
previous: []
});
......@@ -120,10 +120,10 @@ suite('ManageAccessibilityPageTests', function() {
// Simulate a pref change for the select action.
cr.webUIListenerCallback(
'switch-access-assignments-changed',
{select: [{key: 'a', devices: ['internal']}], next: [], previous: []});
{select: [{key: 'a', device: 'usb'}], next: [], previous: []});
assertEquals(1, page.selectAssignments_.length);
assertEquals('a', page.selectAssignments_[0]);
assertDeepEquals({key: 'a', device: 'usb'}, page.selectAssignments_[0]);
assertEquals(0, page.nextAssignments_.length);
assertEquals(0, page.previousAssignments_.length);
});
......@@ -132,24 +132,29 @@ suite('ManageAccessibilityPageTests', function() {
initPage();
assertEquals('0 switches assigned', getSublabelForSelectUpdates([]));
assertEquals('Backspace', getSublabelForSelectUpdates(['Backspace']));
assertEquals('Backspace (USB)', getSublabelForSelectUpdates(['Backspace']));
assertEquals(
'Backspace, Tab', getSublabelForSelectUpdates(['Backspace', 'Tab']));
'Backspace (USB), Tab (USB)',
getSublabelForSelectUpdates(['Backspace', 'Tab']));
assertEquals(
'Backspace, Tab, Enter',
'Backspace (USB), Tab (USB), Enter (USB)',
getSublabelForSelectUpdates(['Backspace', 'Tab', 'Enter']));
assertEquals(
'Backspace, Tab, Enter, and 1 more switch',
'Backspace (USB), Tab (USB), Enter (USB), ' +
'and 1 more switch',
getSublabelForSelectUpdates(['Backspace', 'Tab', 'Enter', 'a']));
assertEquals(
'Backspace, Tab, Enter, and 2 more switches',
'Backspace (USB), Tab (USB), Enter (USB), ' +
'and 2 more switches',
getSublabelForSelectUpdates(['Backspace', 'Tab', 'Enter', 'a', 'b']));
assertEquals(
'Backspace, Tab, Enter, and 3 more switches',
'Backspace (USB), Tab (USB), Enter (USB), ' +
'and 3 more switches',
getSublabelForSelectUpdates(
['Backspace', 'Tab', 'Enter', 'a', 'b', 'c']));
assertEquals(
'Backspace, Tab, Enter, and 4 more switches',
'Backspace (USB), Tab (USB), Enter (USB), ' +
'and 4 more switches',
getSublabelForSelectUpdates(
['Backspace', 'Tab', 'Enter', 'a', 'b', 'c', 'd']));
});
......@@ -171,9 +176,11 @@ suite('ManageAccessibilityPageTests', function() {
// Simulate pressing 'a' twice.
cr.webUIListenerCallback(
'switch-access-got-key-press-for-assignment', {key: 'a', keyCode: 65});
'switch-access-got-key-press-for-assignment',
{key: 'a', keyCode: 65, device: 'usb'});
cr.webUIListenerCallback(
'switch-access-got-key-press-for-assignment', {key: 'a', keyCode: 65});
'switch-access-got-key-press-for-assignment',
{key: 'a', keyCode: 65, device: 'usb'});
// This should cause the dialog to close.
await browserProxy.methodCalled(
......@@ -191,9 +198,11 @@ suite('ManageAccessibilityPageTests', function() {
// Simulate pressing 'a', and then 'b'.
cr.webUIListenerCallback(
'switch-access-got-key-press-for-assignment', {key: 'a', keyCode: 65});
'switch-access-got-key-press-for-assignment',
{key: 'a', keyCode: 65, device: 'usb'});
cr.webUIListenerCallback(
'switch-access-got-key-press-for-assignment', {key: 'b', keyCode: 66});
'switch-access-got-key-press-for-assignment',
{key: 'b', keyCode: 66, device: 'usb'});
const element = page.$$('#switchAccessActionAssignmentDialog');
await test_util.waitAfterNextRender(element);
......
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