Skip to content

Commit d6a0a2d

Browse files
committed
fix(cdk/a11y): fake mousedown detection not working
Our approach to detecting fake `mousedown` events from screen readers doesn't appear to work with a recent version of NVDA. These changes switch to using `offsetX` and `offsetY` instead. Fixes #22549.
1 parent 4caf039 commit d6a0a2d

File tree

4 files changed

+9
-8
lines changed

4 files changed

+9
-8
lines changed

src/cdk/a11y/fake-event-detection.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88

99
/** Gets whether an event could be a faked `mousedown` event dispatched by a screen reader. */
1010
export function isFakeMousedownFromScreenReader(event: MouseEvent): boolean {
11-
// We can typically distinguish between these faked mousedown events and real mousedown events
12-
// using the "buttons" property. While real mousedowns will indicate the mouse button that was
13-
// pressed (e.g. "1" for the left mouse button), faked mousedowns will usually set the property
14-
// value to 0.
15-
return event.buttons === 0;
11+
// Some screen readers will dispatch a fake `mousedown` event when pressing enter or space on
12+
// a clickable element. We can distinguish these events when both `offsetX` and `offsetY` are
13+
// zero. Note that there's an edge case where the user could click the 0x0 spot of the screen
14+
// themselves, but that is unlikely to contain interaction elements. Historially we used to check
15+
// `event.buttons === 0`, however that no longer works on recent versions of NVDA.
16+
return event.offsetX === 0 && event.offsetY === 0;
1617
}
1718

1819
/** Gets whether an event could be a faked `touchstart` event dispatched by a screen reader. */

src/cdk/a11y/focus-monitor/focus-monitor.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ describe('FocusMonitor', () => {
151151
// Simulate focus via a fake mousedown from a screen reader.
152152
dispatchMouseEvent(buttonElement, 'mousedown');
153153
const event = createMouseEvent('mousedown');
154-
Object.defineProperty(event, 'buttons', {get: () => 0});
154+
Object.defineProperties(event, {offsetX: {get: () => 0}, offsetY: {get: () => 0}});
155155
dispatchEvent(buttonElement, event);
156156

157157
buttonElement.focus();

src/cdk/a11y/input-modality/input-modality-detector.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ describe('InputModalityDetector', () => {
134134

135135
// Create a fake screen-reader mouse event.
136136
const event = createMouseEvent('mousedown');
137-
Object.defineProperty(event, 'buttons', {get: () => 0});
137+
Object.defineProperties(event, {offsetX: {get: () => 0}, offsetY: {get: () => 0}});
138138
dispatchEvent(document, event);
139139

140140
expect(detector.mostRecentModality).toBe('keyboard');

src/material/core/ripple/ripple.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ describe('MatRipple', () => {
181181

182182
it('should ignore fake mouse events from screen readers', fakeAsync(() => {
183183
const event = createMouseEvent('mousedown');
184-
Object.defineProperty(event, 'buttons', {get: () => 0});
184+
Object.defineProperties(event, {offsetX: {get: () => 0}, offsetY: {get: () => 0}});
185185

186186
dispatchEvent(rippleTarget, event);
187187
tick(enterDuration);

0 commit comments

Comments
 (0)