Android build v1.1.2
This commit is contained in:
+45
-6
@@ -9,6 +9,7 @@ import {
|
||||
useState,
|
||||
type ReactNode,
|
||||
} from 'react'
|
||||
import { Capacitor } from '@capacitor/core'
|
||||
|
||||
export type InputDevice = 'pc' | 'controller'
|
||||
export type ControllerIconStyle = 'xbox' | 'playstation' | 'nintendo'
|
||||
@@ -126,6 +127,9 @@ const PREFERENCES_STORAGE_KEY = 'ashen-halls-input-preferences-v1'
|
||||
const GAME_ACTION_EVENT = 'ashen-halls-game-action'
|
||||
const NATIVE_CONTROLLER_EVENT = 'ashen-halls-native-controller'
|
||||
const FOCUSABLE_SELECTOR = 'button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"])'
|
||||
const GAMEPAD_COMBAT_POLL_MS = 1000 / 60
|
||||
const GAMEPAD_MENU_POLL_MS = 1000 / 30
|
||||
const GAMEPAD_BROWSER_DISCONNECTED_POLL_MS = 250
|
||||
|
||||
let lastControllerFocus: HTMLElement | null = null
|
||||
|
||||
@@ -400,6 +404,14 @@ function gamepadTokens(gamepad: Gamepad) {
|
||||
return tokens
|
||||
}
|
||||
|
||||
function isCombatActive() {
|
||||
return Boolean(document.querySelector('[data-combat-active="true"]'))
|
||||
}
|
||||
|
||||
function firstConnectedGamepad() {
|
||||
return Array.from(navigator.getGamepads?.() ?? []).find(Boolean) ?? null
|
||||
}
|
||||
|
||||
function setInputValue(input: HTMLInputElement | HTMLTextAreaElement, nextValue: string) {
|
||||
const prototype = input instanceof HTMLTextAreaElement
|
||||
? HTMLTextAreaElement.prototype
|
||||
@@ -422,6 +434,7 @@ export function InputProvider({ children }: { children: ReactNode }) {
|
||||
const keyboardInputRef = useRef(keyboardInput)
|
||||
const previousTokensRef = useRef(new Set<string>())
|
||||
const repeatRef = useRef<Record<string, number>>({})
|
||||
const gamepadConnectedRef = useRef(Capacitor.isNativePlatform())
|
||||
|
||||
useEffect(() => {
|
||||
bindingsRef.current = bindings
|
||||
@@ -664,9 +677,21 @@ export function InputProvider({ children }: { children: ReactNode }) {
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
let frame = 0
|
||||
const poll = (time: number) => {
|
||||
const gamepad = Array.from(navigator.getGamepads?.() ?? []).find(Boolean)
|
||||
let timer = 0
|
||||
const nextDelay = () => {
|
||||
if (!Capacitor.isNativePlatform() && !gamepadConnectedRef.current) {
|
||||
return GAMEPAD_BROWSER_DISCONNECTED_POLL_MS
|
||||
}
|
||||
return isCombatActive() ? GAMEPAD_COMBAT_POLL_MS : GAMEPAD_MENU_POLL_MS
|
||||
}
|
||||
const clearControllerState = () => {
|
||||
previousTokensRef.current = new Set()
|
||||
repeatRef.current = {}
|
||||
}
|
||||
const poll = () => {
|
||||
const time = performance.now()
|
||||
const gamepad = firstConnectedGamepad()
|
||||
gamepadConnectedRef.current = Capacitor.isNativePlatform() || Boolean(gamepad)
|
||||
const currentTokens = gamepad ? gamepadTokens(gamepad) : new Set<string>()
|
||||
const previousTokens = previousTokensRef.current
|
||||
|
||||
@@ -692,10 +717,24 @@ export function InputProvider({ children }: { children: ReactNode }) {
|
||||
if (!currentTokens.has(token)) delete repeatRef.current[token]
|
||||
})
|
||||
previousTokensRef.current = currentTokens
|
||||
frame = window.requestAnimationFrame(poll)
|
||||
if (!gamepad) clearControllerState()
|
||||
timer = window.setTimeout(poll, nextDelay())
|
||||
}
|
||||
const onGamepadConnected = () => {
|
||||
gamepadConnectedRef.current = true
|
||||
}
|
||||
const onGamepadDisconnected = () => {
|
||||
gamepadConnectedRef.current = Boolean(firstConnectedGamepad())
|
||||
if (!gamepadConnectedRef.current) clearControllerState()
|
||||
}
|
||||
window.addEventListener('gamepadconnected', onGamepadConnected)
|
||||
window.addEventListener('gamepaddisconnected', onGamepadDisconnected)
|
||||
timer = window.setTimeout(poll, 0)
|
||||
return () => {
|
||||
window.clearTimeout(timer)
|
||||
window.removeEventListener('gamepadconnected', onGamepadConnected)
|
||||
window.removeEventListener('gamepaddisconnected', onGamepadDisconnected)
|
||||
}
|
||||
frame = window.requestAnimationFrame(poll)
|
||||
return () => window.cancelAnimationFrame(frame)
|
||||
}, [assignBinding, dispatchControllerToken])
|
||||
|
||||
const contextValue = useMemo<InputContextValue>(() => ({
|
||||
|
||||
Reference in New Issue
Block a user