5180 fichiers 38.5 Mo 0 téléchargements 231 vues mis à jour il y a 5 heures ui
nitro-v36-with-renderer-v36 / src / hooks / rooms / useRoomKeyboardMovement.ts
useRoomKeyboardMovement.ts 2.8 Ko Télécharger le fichier
import { GetRoomEngine, RoomObjectCategory, RoomUnitWalkComposer } from '@octane/renderer';
import { useEffect, useRef } from 'react';
import { SendMessageComposer } from '../../api';
import { useKeyboardMovement } from '../useKeyboardMovement';
import { useRoom } from './useRoom';

const STEPS: Record<string, [number, number]> = {
    ArrowUp: [-1, -1],
    ArrowDown: [1, 1],
    ArrowLeft: [-1, 1],
    ArrowRight: [1, -1]
};

const REPEAT_DELAY = 180;

/**
 * The room's chat input takes focus on the first keystroke and keeps it, so
 * treating "an input has focus" as "the user is typing" disabled arrow
 * movement for the rest of the session. An empty chat box is not typing:
 * only a message actually being composed should swallow the arrows.
 */
const TEXT_ENTRY_SELECTOR = 'input, textarea, select, [role="combobox"], [role="listbox"], [role="option"], [role="spinbutton"], [role="checkbox"], [role="radio"], [role="slider"], .octane-select-trigger';

/** Native fields and the Base UI controls that take keys (select, number, checkbox, radio, slider). */
export const isTextEntryTarget = (target: EventTarget | null): boolean => {
    if (!(target instanceof HTMLElement)) return false;

    return target.isContentEditable || target.matches(TEXT_ENTRY_SELECTOR);
};

export const isTyping = () => {
    const element = document.activeElement as HTMLElement;

    if (!element) return false;

    if (element.classList.contains('swf-chat-input-field')) {
        return !!(element as HTMLInputElement).value.length;
    }

    return isTextEntryTarget(element);
};

export const useRoomKeyboardMovement = () => {
    const { roomSession = null } = useRoom();
    const [enabled] = useKeyboardMovement();
    const lastStep = useRef(0);

    useEffect(() => {
        if (!enabled || !roomSession) return;

        const onKeyDown = (event: KeyboardEvent) => {
            const step = STEPS[event.key];

            if (!step) return;
            if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;
            if (isTyping()) return;

            event.preventDefault();
            event.stopPropagation();

            const now = Date.now();

            if (now - lastStep.current < REPEAT_DELAY) return;

            const avatar = GetRoomEngine().getRoomObject(roomSession.roomId, roomSession.ownRoomIndex, RoomObjectCategory.UNIT);

            if (!avatar) return;

            const location = avatar.getLocation();

            if (!location) return;

            lastStep.current = now;

            SendMessageComposer(new RoomUnitWalkComposer(Math.round(location.x) + step[0], Math.round(location.y) + step[1]));
        };

        window.addEventListener('keydown', onKeyDown, true);

        return () => window.removeEventListener('keydown', onKeyDown, true);
    }, [enabled, roomSession]);
};
15Sujets
1Dépôts
20Membres
2En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser