mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-21 03:22:11 +00:00
fix(GamepadSupport): fix issue with multiple handler events being fired
This commit is contained in:
parent
b36ebcb4c6
commit
41865276d5
3 changed files with 56 additions and 20 deletions
|
|
@ -29,6 +29,8 @@ const useVideo = require('./useVideo');
|
||||||
const styles = require('./styles');
|
const styles = require('./styles');
|
||||||
const Video = require('./Video');
|
const Video = require('./Video');
|
||||||
|
|
||||||
|
const GAMEPAD_HANDLER_ID = 'player';
|
||||||
|
|
||||||
const Player = ({ urlParams, queryParams }) => {
|
const Player = ({ urlParams, queryParams }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { chromecast, shell, core } = useServices();
|
const { chromecast, shell, core } = useServices();
|
||||||
|
|
@ -344,12 +346,12 @@ const Player = ({ urlParams, queryParams }) => {
|
||||||
}, [onSeekPrev, onSeekNext, onVolumeUp, onVolumeDown]);
|
}, [onSeekPrev, onSeekNext, onVolumeUp, onVolumeDown]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
gamepad.on('buttonA', onPlayPause);
|
gamepad.on('buttonA', GAMEPAD_HANDLER_ID, onPlayPause);
|
||||||
gamepad.on('analog', onGamepadSeekAndVol);
|
gamepad.on('analog', GAMEPAD_HANDLER_ID, onGamepadSeekAndVol);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
gamepad.off('buttonA', onPlayPause);
|
gamepad.off('buttonA', GAMEPAD_HANDLER_ID);
|
||||||
gamepad.off('analog', onGamepadSeekAndVol);
|
gamepad.off('analog', GAMEPAD_HANDLER_ID);
|
||||||
};
|
};
|
||||||
}, [onPlayPause, onGamepadSeekAndVol]);
|
}, [onPlayPause, onGamepadSeekAndVol]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { createContext } from 'react';
|
import { createContext } from 'react';
|
||||||
|
|
||||||
const GamepadContext = createContext<{
|
const GamepadContext = createContext<{
|
||||||
on: (event: string, callback: (data?: any) => void) => void;
|
on: (event: string, id: string, callback: (data?: any) => void) => void;
|
||||||
off: (event: string, callback: (data?: any) => void) => void;
|
off: (event: string, id: string) => void;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
export default GamepadContext;
|
export default GamepadContext;
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,73 @@
|
||||||
import React, { useEffect, useRef, useState, useCallback } from 'react';
|
import React, { useEffect, useRef, useState, useCallback } from 'react';
|
||||||
|
import useToast from 'stremio/common/Toast/useToast';
|
||||||
import GamepadContext from './GamepadContext';
|
import GamepadContext from './GamepadContext';
|
||||||
|
|
||||||
type GamepadEventHandlers = Record<string, ((data?: any) => void)[]>;
|
type GamepadEventHandlers = Map<string, Map<string, (data?: any) => void>>;
|
||||||
|
|
||||||
const GamepadProvider: React.FC<{
|
const GamepadProvider: React.FC<{
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}> = ({ enabled, children }) => {
|
}> = ({ enabled, children }) => {
|
||||||
|
const toast = useToast();
|
||||||
const [connectedGamepads, setConnectedGamepads] = useState<number>(0);
|
const [connectedGamepads, setConnectedGamepads] = useState<number>(0);
|
||||||
const lastButtonState = useRef<number[]>([]);
|
const lastButtonState = useRef<number[]>([]);
|
||||||
const lastButtonPressedTime = useRef<number>(0);
|
const lastButtonPressedTime = useRef<number>(0);
|
||||||
const axisTimer = useRef<number>(0);
|
const axisTimer = useRef<number>(0);
|
||||||
const eventHandlers = useRef<GamepadEventHandlers>({});
|
const eventHandlers = useRef<GamepadEventHandlers>(new Map());
|
||||||
|
|
||||||
const on = useCallback((event: string, callback: (data?: any) => void) => {
|
const on = useCallback((event: string, id: string, callback: (data?: any) => void) => {
|
||||||
if (!eventHandlers.current[event]) {
|
if (!eventHandlers.current.has(event)) {
|
||||||
eventHandlers.current[event] = [];
|
eventHandlers.current.set(event, new Map());
|
||||||
}
|
}
|
||||||
eventHandlers.current[event].push(callback);
|
|
||||||
|
const handlers = eventHandlers.current.get(event)!;
|
||||||
|
|
||||||
|
// Ensure only one handler per component
|
||||||
|
handlers.set(id, callback);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const off = useCallback((event: string, callback: (data?: any) => void) => {
|
const off = useCallback((event: string, id: string) => {
|
||||||
if (eventHandlers.current[event]) {
|
eventHandlers.current.get(event)?.delete(id);
|
||||||
eventHandlers.current[event] = eventHandlers.current[event].filter(
|
|
||||||
(cb) => cb !== callback
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const emit = (event: string, data?: any) => {
|
const emit = (event: string, data?: any) => {
|
||||||
if (eventHandlers.current[event]) {
|
if (eventHandlers.current.has(event)) {
|
||||||
eventHandlers.current[event].forEach((callback) => callback(data));
|
eventHandlers.current.get(event)!.forEach((callback) => callback(data));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onGamepadConnected = () => {
|
||||||
|
// @ts-ignore
|
||||||
|
toast.show({
|
||||||
|
type: 'info',
|
||||||
|
title: 'Gamepad detected',
|
||||||
|
timeout: 4000,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onGamepadDisconnected = () => {
|
||||||
|
// @ts-ignore
|
||||||
|
toast.show({
|
||||||
|
type: 'info',
|
||||||
|
title: 'Gamepad disconnected',
|
||||||
|
timeout: 4000,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (enabled) {
|
||||||
|
window.addEventListener('gamepadconnected', onGamepadConnected);
|
||||||
|
window.addEventListener('gamepaddisconnected', onGamepadDisconnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (enabled) {
|
||||||
|
window.removeEventListener('gamepadconnected', onGamepadConnected);
|
||||||
|
window.removeEventListener('gamepaddisconnected', onGamepadDisconnected);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [enabled]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof navigator.getGamepads !== 'function') return;
|
if (typeof navigator.getGamepads !== 'function') return;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue