diff --git a/src/cdk/a11y/list-key-manager.spec.ts b/src/cdk/a11y/list-key-manager.spec.ts index bba6ecf9d65d..499b5a628266 100644 --- a/src/cdk/a11y/list-key-manager.spec.ts +++ b/src/cdk/a11y/list-key-manager.spec.ts @@ -461,6 +461,26 @@ describe('Key managers', () => { expect(keyManager.activeItem).toBe(itemList.items[1]); })); + it('should handle non-letter characters', fakeAsync(() => { + itemList.items = [ + new FakeFocusable('[]'), + new FakeFocusable('321'), + new FakeFocusable('`!?') + ]; + + keyManager.onKeydown(createKeyboardEvent('keydown', 192, undefined, '`')); // types "`" + tick(debounceInterval); + expect(keyManager.activeItem).toBe(itemList.items[2]); + + keyManager.onKeydown(createKeyboardEvent('keydown', 51, undefined, '3')); // types "3" + tick(debounceInterval); + expect(keyManager.activeItem).toBe(itemList.items[1]); + + keyManager.onKeydown(createKeyboardEvent('keydown', 219, undefined, '[')); // types "[" + tick(debounceInterval); + expect(keyManager.activeItem).toBe(itemList.items[0]); + })); + }); }); diff --git a/src/cdk/a11y/list-key-manager.ts b/src/cdk/a11y/list-key-manager.ts index 1ccbedc7ce80..47fafcfa1856 100644 --- a/src/cdk/a11y/list-key-manager.ts +++ b/src/cdk/a11y/list-key-manager.ts @@ -9,7 +9,7 @@ import {QueryList} from '@angular/core'; import {Subject} from 'rxjs/Subject'; import {Subscription} from 'rxjs/Subscription'; -import {UP_ARROW, DOWN_ARROW, TAB, A, Z} from '@angular/cdk/keycodes'; +import {UP_ARROW, DOWN_ARROW, TAB, A, Z, ZERO, NINE} from '@angular/cdk/keycodes'; import {RxChain, debounceTime, filter, map, doOperator} from '@angular/cdk/rxjs'; /** @@ -107,17 +107,19 @@ export class ListKeyManager { case UP_ARROW: this.setPreviousItemActive(); break; case TAB: this.tabOut.next(); return; default: - if (event.keyCode >= A && event.keyCode <= Z) { - // Attempt to use the `event.key` which also maps it to the user's keyboard language, - // otherwise fall back to `keyCode` and `fromCharCode` which always resolve to English. - this._letterKeyStream.next(event.key ? - event.key.toLocaleUpperCase() : - String.fromCharCode(event.keyCode)); + const keyCode = event.keyCode; + + // Attempt to use the `event.key` which also maps it to the user's keyboard language, + // otherwise fall back to resolving alphanumeric characters via the keyCode. + if (event.key && event.key.length === 1) { + this._letterKeyStream.next(event.key.toLocaleUpperCase()); + } else if ((keyCode >= A && keyCode <= Z) || (keyCode >= ZERO && keyCode <= NINE)) { + this._letterKeyStream.next(String.fromCharCode(keyCode)); } - // Note that we return here, in order to avoid preventing - // the default action of non-navigational keys. - return; + // Note that we return here, in order to avoid preventing + // the default action of non-navigational keys. + return; } this._pressedLetters = []; diff --git a/src/cdk/keycodes/keycodes.ts b/src/cdk/keycodes/keycodes.ts index 312174fbd3de..d1ddf1231f03 100644 --- a/src/cdk/keycodes/keycodes.ts +++ b/src/cdk/keycodes/keycodes.ts @@ -22,3 +22,5 @@ export const BACKSPACE = 8; export const DELETE = 46; export const A = 65; export const Z = 90; +export const ZERO = 48; +export const NINE = 91;