UNPKG

use-control

Version:

A powerful set of hooks for elegantly handling keyboard, mouse and gamepad input (soon)

100 lines 4.39 kB
import { useEffect } from 'react'; import { EMPTY, interval, merge } from 'rxjs'; import { distinctUntilChanged, filter, map, switchMap } from 'rxjs/operators'; import { gamepadAxes$, gamepadButtonPress$, gamepadButtonReleased$ } from './input/gamepad'; import { keyEvents$ } from './input/keyboard'; import { mouseDown$, mousePosNormalisedX$, mousePosNormalisedY$, mouseUp$, whichButtonPressed, } from './input/mouse'; export function mouseButton(button) { return { type: 'mouse-button', button: button }; } export function keycode(code) { return { type: 'keycode-button', code: code }; } export function gamepadButton(controllerIndex, code) { return { type: 'gamepad-button', controllerIndex: controllerIndex, code: code }; } export function mouseAxis(axis) { return { type: 'mouse-axis', axis: axis }; } export function gamepadAxis(controllerIndex, axis, threshold) { if (threshold === void 0) { threshold = 0.000001; } return { type: 'gamepad-axis', controllerIndex: controllerIndex, axis: axis, threshold: threshold }; } function buildStream(eventType, inputMap, key) { var keys = inputMap.buttons[key]; return merge.apply(void 0, keys.map(function (k) { switch (k.type) { case 'gamepad-button': var s = eventType === 'down' ? gamepadButtonPress$ : gamepadButtonReleased$; return s.pipe(filter(function (p) { return p.buttonIndex === k.code && p.controllerIndex === k.controllerIndex; })); case 'keycode-button': var keyboardEventType_1 = eventType === 'down' ? 'keydown' : 'keyup'; return keyEvents$.pipe(filter(function (ev) { return k.code === ev.keyCode && ev.type === keyboardEventType_1 && !ev.repeat; })); case 'mouse-button': var m = eventType === 'down' ? mouseDown$ : mouseUp$; return m.pipe(filter(function (ev) { return whichButtonPressed(ev) === k.button; })); } })); } function useButtonEvents(eventType, inputMap, key, sink) { var button$ = buildStream(eventType, inputMap, key); useEffect(function () { var s = button$.subscribe(sink); return function () { return s.unsubscribe(); }; }, [button$, eventType, sink]); } export function useButtonPressed(inputMap, key, sink) { useButtonEvents('down', inputMap, key, sink); } export function useButtonReleased(inputMap, key, sink) { useButtonEvents('up', inputMap, key, sink); } export function useButtonHeld(inputMap, key, intervalMs, sink) { var keys = inputMap.buttons[key]; var pressed$ = buildStream('down', inputMap, key).pipe(map(function (_) { return 'down'; })); var released$ = buildStream('up', inputMap, key).pipe(map(function (_) { return 'up'; })); useEffect(function () { var s = merge(pressed$, released$) .pipe(switchMap(function (ev) { if (ev === 'down') { return interval(intervalMs); } else { return EMPTY; } })) .subscribe(sink); return function () { return s.unsubscribe(); }; }, [keys, intervalMs, sink]); } export function useAxis(inputMap, key, sink) { useEffect(function () { var axes = inputMap.axes[key]; // map each axis to the relevant source stream // & merge them together var streams = merge.apply(void 0, axes.map(function (a) { switch (a.type) { case 'gamepad-axis': return gamepadAxes$.pipe(filter(function (p) { return p.axisIndex === a.axis && p.controllerIndex === a.controllerIndex && Math.abs(p.value) > a.threshold; }), map(function (p) { return p.value; })); case 'mouse-axis': switch (a.axis) { case 'x': return mousePosNormalisedX$; case 'y': return mousePosNormalisedY$; } } })); var sub = streams.pipe(distinctUntilChanged()).subscribe(sink); return function () { return sub.unsubscribe(); }; }, [sink]); } //# sourceMappingURL=actions.js.map