-
-
Notifications
You must be signed in to change notification settings - Fork 980
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[
web
] Add keyboard support to gesture handler (#3035)
## Description By default, all native android and web components support keyboard navigation and option to press elements with `Enter` or `Spacebar` keys. Gestures and components provided by Gesture Handler lack the latter option. This PR adds keyboard support to the entirety of gesture handler, allowing it to replace mouse or finger navigation. ## Test plan - try navigating around the example app using just the following keys: `Tab`, `Shift-Tab`, `Space`, `Enter` ## Gallery <details> <summary> Expand </summary> https://github.com/user-attachments/assets/3523142a-c786-4dc2-aa84-f49d96d03ecd https://github.com/user-attachments/assets/488c7716-91ed-42aa-8a6c-49a90db5002a </details>
- Loading branch information
Showing
4 changed files
with
98 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,5 +2,6 @@ export enum PointerType { | |
TOUCH, | ||
STYLUS, | ||
MOUSE, | ||
KEY, | ||
OTHER, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { AdaptedEvent, EventTypes } from '../interfaces'; | ||
import EventManager from './EventManager'; | ||
import { PointerType } from '../../PointerType'; | ||
|
||
export default class KeyboardEventManager extends EventManager<HTMLElement> { | ||
private activationKeys = ['Enter', ' ']; | ||
private cancelationKeys = ['Tab']; | ||
private isPressed = false; | ||
|
||
private keyDownCallback = (event: KeyboardEvent): void => { | ||
if (this.cancelationKeys.indexOf(event.key) !== -1 && this.isPressed) { | ||
this.dispatchEvent(event, EventTypes.CANCEL); | ||
return; | ||
} | ||
|
||
if (this.activationKeys.indexOf(event.key) === -1) { | ||
return; | ||
} | ||
|
||
this.dispatchEvent(event, EventTypes.DOWN); | ||
}; | ||
|
||
private keyUpCallback = (event: KeyboardEvent): void => { | ||
if (this.activationKeys.indexOf(event.key) === -1 || !this.isPressed) { | ||
return; | ||
} | ||
|
||
this.dispatchEvent(event, EventTypes.UP); | ||
}; | ||
|
||
private dispatchEvent(event: KeyboardEvent, eventType: EventTypes) { | ||
if (!(event.target instanceof HTMLElement)) { | ||
return; | ||
} | ||
|
||
const adaptedEvent = this.mapEvent(event, eventType); | ||
|
||
switch (eventType) { | ||
case EventTypes.UP: | ||
this.isPressed = false; | ||
this.onPointerUp(adaptedEvent); | ||
break; | ||
case EventTypes.DOWN: | ||
this.isPressed = true; | ||
this.onPointerDown(adaptedEvent); | ||
break; | ||
case EventTypes.CANCEL: | ||
this.isPressed = false; | ||
this.onPointerCancel(adaptedEvent); | ||
break; | ||
} | ||
} | ||
|
||
public registerListeners(): void { | ||
this.view.addEventListener('keydown', this.keyDownCallback); | ||
this.view.addEventListener('keyup', this.keyUpCallback); | ||
} | ||
|
||
public unregisterListeners(): void { | ||
this.view.addEventListener('keydown', this.keyDownCallback); | ||
this.view.addEventListener('keyup', this.keyUpCallback); | ||
} | ||
|
||
protected mapEvent( | ||
event: KeyboardEvent, | ||
eventType: EventTypes | ||
): AdaptedEvent { | ||
const viewRect = (event.target as HTMLElement).getBoundingClientRect(); | ||
|
||
const viewportPosition = { | ||
x: viewRect?.x + viewRect?.width / 2, | ||
y: viewRect?.y + viewRect?.height / 2, | ||
}; | ||
|
||
const relativePosition = { | ||
x: viewRect?.width / 2, | ||
y: viewRect?.height / 2, | ||
}; | ||
|
||
return { | ||
x: viewportPosition.x, | ||
y: viewportPosition.y, | ||
offsetX: relativePosition.x, | ||
offsetY: relativePosition.y, | ||
pointerId: 0, | ||
eventType: eventType, | ||
pointerType: PointerType.KEY, | ||
time: event.timeStamp, | ||
}; | ||
} | ||
} |