UNPKG

expo-key-event

Version:

Provides an interface for reading key events such as from external bluetooth keyboards on Android, iOS and Web.

152 lines (134 loc) 4.07 kB
import { useCallback, useEffect, useState } from "react"; import { KeyPressEvent, KeyReleaseEvent } from "../ExpoKeyEvent.types"; export interface UseKeyEventOptions { /** * Pass 'false' to prevent automatic key event listening * - Use startListening/stopListening to control the listener manually * @default true */ listenOnMount?: boolean; /** * Prevent reloading the app when pressing 'r' (not applicable on web) * @default false */ preventReload?: boolean; /** * Pass 'true' to enable onKeyRelease events (defaults to false for backward compatibility) * @default false */ listenToRelease?: boolean; /** * Pass 'true' to capture modifier keys (shift, ctrl, alt, meta) and repeat flag * @default false */ captureModifiers?: boolean; } // New API - options object export function useKeyEvent( options?: UseKeyEventOptions, ): ReturnType<typeof useKeyEventImpl>; /** * Legacy API - positional parameters (for backwards compatibility) * @deprecated Use `useKeyEvent( options?: UseKeyEventOptions )` instead */ export function useKeyEvent( listenOnMount?: boolean, preventReload?: boolean, listenToRelease?: boolean, ): ReturnType<typeof useKeyEventImpl>; export function useKeyEvent( optionsOrListenOnMount?: UseKeyEventOptions | boolean, preventReload?: boolean, listenToRelease?: boolean, ) { // Backwards compatibility: detect if using old API (boolean) or new API (object/undefined) let options: UseKeyEventOptions; if (typeof optionsOrListenOnMount === "boolean") { // Legacy API: positional parameters (boolean explicitly passed) options = { listenOnMount: optionsOrListenOnMount, preventReload: preventReload ?? false, listenToRelease: listenToRelease ?? false, }; } else { // New API: options object or undefined (defaults to {}) options = optionsOrListenOnMount ?? {}; } return useKeyEventImpl(options); } function useKeyEventImpl({ listenOnMount = true, preventReload = false, listenToRelease = false, captureModifiers = false, }: UseKeyEventOptions) { const [keyEvent, setKeyEvent] = useState<KeyPressEvent | null>(null); const [keyReleaseEvent, setKeyReleaseEvent] = useState<KeyReleaseEvent | null>(null); const onKeyDown = useCallback( (event: KeyboardEvent) => { const pressEvent: any = { key: event.code, eventType: "press", }; if (captureModifiers) { pressEvent.shiftKey = event.shiftKey; pressEvent.ctrlKey = event.ctrlKey; pressEvent.altKey = event.altKey; pressEvent.metaKey = event.metaKey; pressEvent.repeat = event.repeat; } setKeyEvent(pressEvent); }, [captureModifiers], ); const onKeyUp = useCallback( (event: KeyboardEvent) => { const releaseEvent: any = { key: event.code, eventType: "release", }; if (captureModifiers) { releaseEvent.shiftKey = event.shiftKey; releaseEvent.ctrlKey = event.ctrlKey; releaseEvent.altKey = event.altKey; releaseEvent.metaKey = event.metaKey; releaseEvent.repeat = false; // Key up events are never repeats } setKeyReleaseEvent(releaseEvent); }, [captureModifiers], ); const startListening = useCallback(() => { addEventListener("keydown", onKeyDown); if (listenToRelease) { addEventListener("keyup", onKeyUp); } }, [onKeyDown, onKeyUp, listenToRelease]); const stopListening = useCallback(() => { removeEventListener("keydown", onKeyDown); if (listenToRelease) { removeEventListener("keyup", onKeyUp); } }, [onKeyDown, onKeyUp, listenToRelease]); useEffect(() => { if (listenOnMount) startListening(); return () => { stopListening(); }; }, [listenOnMount, startListening, stopListening]); return { /** * Start listening for key events */ startListening, /** * Stop listening for key events */ stopListening, keyEvent, keyReleaseEvent, }; }