Skip to content

Commit

Permalink
shortcuts: Add aria-label and role for shortcut key icons
Browse files Browse the repository at this point in the history
This CL improves the usability of the shortcuts app for screen readers
by adding role=img and an aria-label to each shortcut key icon.
Previously, ChromeVox would skip over icons and not read their name, or
read the key name (e.g. "ZoomToggle" for fullscreen).

I also added a test that goes through and checks that each string ID in
keyToIconNameMap has been loaded into the WebUI.

Bug: b:216049298
Test: browser_tests ShortcutCustomizationApp*
Change-Id: I62d2d042ef03e0854b3d771542c7743671a78527
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4153154
Commit-Queue: Camden Bickel <cambickel@google.com>
Reviewed-by: Michael Checo <michaelcheco@google.com>
Reviewed-by: Jimmy Gong <jimmyxgong@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1091931}
  • Loading branch information
Cam Bickel authored and Chromium LUCI CQ committed Jan 12, 2023
1 parent 6cbf428 commit 2af853c
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@

<div id="key" class="key-container">
<template is="dom-if" if="[[getIconIdForKey(key)]]">
<iron-icon icon="[[getIconIdForKey(key)]]" id="key-icon"></iron-icon>
<div aria-label$="[[getAriaLabelForIcon(key)]]" role="img">
<iron-icon icon="[[getIconIdForKey(key)]]" id="key-icon"></iron-icon>
</div>
</template>
<template is="dom-if" if="[[!getIconIdForKey(key)]]">
<span id="key-text">[[key]]</span>
Expand Down
26 changes: 25 additions & 1 deletion ash/webui/shortcut_customization_ui/resources/js/input_key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import 'chrome://resources/cr_elements/cr_shared_style.css.js';
import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';

import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
import {assert} from 'chrome://resources/js/assert_ts.js';
import {PolymerElementProperties} from 'chrome://resources/polymer/v3_0/polymer/interfaces.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

Expand Down Expand Up @@ -59,7 +61,10 @@ export const keyToIconNameMap: {[key: string]: string} = {
* 'input-key' is a component wrapper for a single input key. Responsible for
* handling dynamic styling of a single key.
*/
export class InputKeyElement extends PolymerElement {

const InputKeyElementBase = I18nMixin(PolymerElement);

export class InputKeyElement extends InputKeyElementBase {
static get is(): string {
return 'input-key';
}
Expand Down Expand Up @@ -93,6 +98,25 @@ export class InputKeyElement extends PolymerElement {
}
return null;
}

/**
* Returns the GRD string ID for the given key. This function is public and
* static so that it can be used by the test for this element.
*
* @param key The KeyboardEvent.code of a key, e.g. ArrowUp or PrintScreen.
*/
static getAriaLabelStringId(key: string): string {
return `iconLabel${key}`; // e.g. iconLabelArrowUp
}

private getAriaLabelForIcon(): string {
const ariaLabelStringId = InputKeyElement.getAriaLabelStringId(this.key);
assert(
this.i18nExists(ariaLabelStringId),
`String ID ${ariaLabelStringId} should exist, but it doesn't.`);

return this.i18n(ariaLabelStringId);
}
}

declare global {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,54 @@ void AddLocalizedStrings(content::WebUIDataSource* source) {
IDS_SHORTCUT_CUSTOMIZATION_SUBCATEGORY_SYSTEM_APPS},
{"subcategorySystemControls",
IDS_SHORTCUT_CUSTOMIZATION_SUBCATEGORY_SYSTEM_CONTROLS},
{"iconLabelArrowDown", IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ARROW_DOWN},
{"iconLabelArrowLeft", IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ARROW_LEFT},
{"iconLabelArrowRight",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ARROW_RIGHT},
{"iconLabelArrowUp", IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ARROW_UP},
{"iconLabelAudioVolumeDown",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_AUDIO_VOLUME_DOWN},
{"iconLabelAudioVolumeMute",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_AUDIO_VOLUME_MUTE},
{"iconLabelAudioVolumeUp",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_AUDIO_VOLUME_UP},
{"iconLabelBrightnessDown",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_BRIGHTNESS_DOWN},
{"iconLabelBrightnessUp",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_BRIGHTNESS_UP},
{"iconLabelBrowserBack",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_BROWSER_BACK},
{"iconLabelBrowserForward",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_BROWSER_FORWARD},
{"iconLabelBrowserRefresh",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_BROWSER_REFRESH},
{"iconLabelKeyboardBacklightToggle",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_KEYBOARD_BACKLIGHT_TOGGLE},
{"iconLabelKeyboardBrightnessUp",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_KEYBOARD_BRIGHTNESS_UP},
{"iconLabelKeyboardBrightnessDown",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_KEYBOARD_BRIGHTNESS_DOWN},
{"iconLabelLaunchApplication1",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_LAUNCH_APPLICATION1},
{"iconLabelLaunchAssistant",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_LAUNCH_ASSISTANT},
{"iconLabelMediaPlayPause",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_MEDIA_PLAY_PAUSE},
{"iconLabelMediaTrackNext",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_MEDIA_TRACK_NEXT},
{"iconLabelMediaTrackPrevious",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_MEDIA_TRACK_PREVIOUS},
{"iconLabelMicrophoneMuteToggle",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_MICROPHONE_MUTE_TOGGLE},
{"iconLabelOpenLauncher",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_OPEN_LAUNCHER},
{"iconLabelPower", IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_POWER},
{"iconLabelPrintScreen",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_PRINT_SCREEN},
{"iconLabelPrivacyScreenToggle",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_PRIVACY_SCREEN_TOGGLE},
{"iconLabelZoomToggle",
IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ZOOM_TOGGLE},
};

source->AddLocalizedStrings(kLocalizedStrings);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'chrome://shortcut-customization/strings.m.js';
import 'chrome://shortcut-customization/js/input_key.js';
import 'chrome://webui-test/mojo_webui_test_support.js';

import {IronIconElement} from '//resources/polymer/v3_0/iron-icon/iron-icon.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {InputKeyElement} from 'chrome://shortcut-customization/js/input_key.js';
import {InputKeyElement, keyToIconNameMap} from 'chrome://shortcut-customization/js/input_key.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {isVisible} from 'chrome://webui-test/test_util.js';

Expand Down Expand Up @@ -55,4 +56,26 @@ suite('inputKeyTest', function() {
const keyElement = inputKeyElement.shadowRoot!.querySelector('#key-text');
assertFalse(isVisible(keyElement));
});

test('AllIconsHaveValidAriaLabelStringIds', async () => {
inputKeyElement = initInputKeyElement();
for (const keyCode of Object.keys(keyToIconNameMap)) {
const ariaLabelStringId = InputKeyElement.getAriaLabelStringId(keyCode);
assertTrue(
inputKeyElement.i18nExists(ariaLabelStringId),
`String ID ${ariaLabelStringId} should exist, but it doesn't.`);
}
});

test('IconKeyHasAriaLabel', async () => {
inputKeyElement = initInputKeyElement();
inputKeyElement.key = 'PrintScreen';
await flush();

const iconWrapperElement = inputKeyElement.shadowRoot!.querySelector(
'#key > div') as HTMLDivElement;
assertTrue(isVisible(iconWrapperElement));
assertEquals('screenshot', iconWrapperElement.ariaLabel);
assertEquals('img', iconWrapperElement.getAttribute('role'));
});
});
78 changes: 78 additions & 0 deletions chromeos/chromeos_strings.grd
Original file line number Diff line number Diff line change
Expand Up @@ -3717,6 +3717,84 @@ Try tapping the mic to ask me anything.
<message name="IDS_SHORTCUT_CUSTOMIZATION_KEY_ESCAPE" desc="Lowercase name of the keyboard key 'Escape', abbreviated if possible" translateable="false">esc</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_KEY_RETURN" desc="Lowercase name of the keyboard key 'Enter'" translateable="false">enter</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_KEY_BACKSPACE" desc="Lowercase name of the keyboard key 'Backspace'" translateable="false">backspace</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ARROW_DOWN" desc="The text read aloud by the screen reader describing the keyboard icon 'arrow down'." translateable="false">
arrow down
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ARROW_LEFT" desc="The text read aloud by the screen reader describing the keyboard icon 'arrow left'." translateable="false">
arrow left
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ARROW_RIGHT" desc="The text read aloud by the screen reader describing the keyboard icon 'arrow right'." translateable="false">
arrow right
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ARROW_UP" desc="The text read aloud by the screen reader describing the keyboard icon 'arrow up'." translateable="false">
arrow up
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_AUDIO_VOLUME_DOWN" desc="The text read aloud by the screen reader describing the keyboard icon 'volume down'." translateable="false">
volume down
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_AUDIO_VOLUME_MUTE" desc="The text read aloud by the screen reader describing the keyboard icon 'volume mute'." translateable="false">
volume mute
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_AUDIO_VOLUME_UP" desc="The text read aloud by the screen reader describing the keyboard icon 'volume up'." translateable="false">
volume up
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_BRIGHTNESS_DOWN" desc="The text read aloud by the screen reader describing the keyboard icon 'brightness down'." translateable="false">
brightness down
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_BRIGHTNESS_UP" desc="The text read aloud by the screen reader describing the keyboard icon 'brightness up'." translateable="false">
brightness up
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_BROWSER_BACK" desc="The text read aloud by the screen reader describing the keyboard icon 'back'." translateable="false">
back
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_BROWSER_FORWARD" desc="The text read aloud by the screen reader describing the keyboard icon 'forward'." translateable="false">
forward
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_BROWSER_REFRESH" desc="The text read aloud by the screen reader describing the keyboard icon 'refresh'." translateable="false">
refresh
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_KEYBOARD_BACKLIGHT_TOGGLE" desc="The text read aloud by the screen reader describing the keyboard icon 'toggle keyboard backlight'." translateable="false">
toggle keyboard backlight
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_KEYBOARD_BRIGHTNESS_UP" desc="The text read aloud by the screen reader describing the keyboard icon 'keyboard brightness up'." translateable="false">
keyboard brightness up
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_KEYBOARD_BRIGHTNESS_DOWN" desc="The text read aloud by the screen reader describing the keyboard icon 'keyboard brightness down'." translateable="false">
keyboard brightness down
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_LAUNCH_APPLICATION1" desc="The text read aloud by the screen reader describing the keyboard icon 'overview'." translateable="false">
overview
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_LAUNCH_ASSISTANT" desc="The text read aloud by the screen reader describing the keyboard icon 'assistant'." translateable="false">
assistant
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_MEDIA_PLAY_PAUSE" desc="The text read aloud by the screen reader describing the keyboard icon 'play pause'." translateable="false">
play pause
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_MEDIA_TRACK_NEXT" desc="The text read aloud by the screen reader describing the keyboard icon 'next track'." translateable="false">
next track
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_MEDIA_TRACK_PREVIOUS" desc="The text read aloud by the screen reader describing the keyboard icon 'previous track'." translateable="false">
previous track
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_MICROPHONE_MUTE_TOGGLE" desc="The text read aloud by the screen reader describing the keyboard icon 'toggle microphone mute'." translateable="false">
toggle microphone mute
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_OPEN_LAUNCHER" desc="The text read aloud by the screen reader describing the keyboard icon 'launcher'." translateable="false">
launcher
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_POWER" desc="The text read aloud by the screen reader describing the keyboard icon 'power'." translateable="false">
power
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_PRINT_SCREEN" desc="The text read aloud by the screen reader describing the keyboard icon 'screenshot'." translateable="false">
screenshot
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_PRIVACY_SCREEN_TOGGLE" desc="The text read aloud by the screen reader describing the keyboard icon 'toggle privacy screen'." translateable="false">
toggle privacy screen
</message>
<message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ZOOM_TOGGLE" desc="The text read aloud by the screen reader describing the keyboard icon 'full screen'." translateable="false">
full screen
</message>
<!-- End of Shortcut Customization -->

<!-- APN -->
Expand Down

0 comments on commit 2af853c

Please sign in to comment.