UNPKG

react-native-gesture-handler

Version:

Declarative API exposing native platform touch and gesture system to React Native

134 lines (111 loc) 3.63 kB
import { AdaptedEvent, EventTypes } from '../interfaces'; import EventManager from './EventManager'; import { PointerType } from '../../PointerType'; export default class KeyboardEventManager extends EventManager<HTMLElement> { private static activationKeys = ['Enter', ' ']; private static cancelationKeys = ['Tab']; private isPressed = false; private static registeredStaticListeners = false; private static instances: Set<KeyboardEventManager> = new Set(); private static keyUpStaticCallback = (event: KeyboardEvent): void => { // We need a global listener, as in some cases, keyUp event gets stop-propagated. // Then, if we used only component-level listeners the gesture would never end, // causing other gestues to fail. if (this.activationKeys.indexOf(event.key) === -1) { return; } this.instances.forEach((item) => { item.onKeyUp(event); }); }; private keyDownCallback = (event: KeyboardEvent): void => { if ( KeyboardEventManager.cancelationKeys.indexOf(event.key) !== -1 && this.isPressed ) { this.dispatchEvent(event, EventTypes.CANCEL); return; } if (KeyboardEventManager.activationKeys.indexOf(event.key) === -1) { return; } this.dispatchEvent(event, EventTypes.DOWN); }; private onKeyUp = (event: KeyboardEvent): void => { if ( KeyboardEventManager.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); KeyboardEventManager.instances.add(this); if (!KeyboardEventManager.registeredStaticListeners) { KeyboardEventManager.registeredStaticListeners = true; document.addEventListener( 'keyup', KeyboardEventManager.keyUpStaticCallback, { capture: true } ); } } public unregisterListeners(): void { this.view.removeEventListener('keydown', this.keyDownCallback); KeyboardEventManager.instances.delete(this); if (KeyboardEventManager.instances.size === 0) { document.removeEventListener( 'keyup', KeyboardEventManager.keyUpStaticCallback, { capture: true } ); KeyboardEventManager.registeredStaticListeners = false; } } 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, }; } }