import React from "react"; import { GameState, IntentName, PlayerIntentState } from "../data/GameState"; import { UpdaterGeneratorType2 } from "../lib/util/updaterGenerator"; type Props = { updaters: UpdaterGeneratorType2<PlayerIntentState, GameState>; intent: PlayerIntentState; }; type State = { keyIntentConfig: keyToIntentMap; }; // TODO: enumerate all the keyboard keys we care about type BrowserKeys = string; /** * Holds the mapping of which keyboard keys (as interpreted by the browser) * map to which intents, e.g. "up arrow" means "pan left" */ type keyToIntentMap = { [key in BrowserKeys]?: IntentName; }; const defaultKeyIntentConfig = { w: IntentName.PAN_NORTH, a: IntentName.PAN_WEST, s: IntentName.PAN_SOUTH, d: IntentName.PAN_EAST, ArrowUp: IntentName.PAN_NORTH, ArrowLeft: IntentName.PAN_WEST, ArrowDown: IntentName.PAN_SOUTH, ArrowRight: IntentName.PAN_EAST, "<": IntentName.TRAVEL_OUT, ">": IntentName.TRAVEL_IN, }; export class KeyboardControlComponent extends React.Component<Props, State> { constructor(props: Props) { super(props); this.state = { keyIntentConfig: defaultKeyIntentConfig, }; document.addEventListener("keydown", this.handleKeydown); document.addEventListener("keyup", this.handleKeyup); } // NOTE(bowei): does using e.repeat here break when window loses focus?? handleKeydown = (e: KeyboardEvent) => { const { keyIntentConfig } = this.state; const key: BrowserKeys = e.key; const configuredIntent = keyIntentConfig[key]; if ( e.repeat === false && configuredIntent !== undefined && configuredIntent !== IntentName.NOOP ) { this.props.updaters.newIntent[configuredIntent].enqueueUpdate(() => { this.props.updaters.newIntent[configuredIntent].enqueueUpdate( () => false ); return true; }); this.props.updaters.activeIntent[configuredIntent].enqueueUpdate( () => true ); } }; handleKeyup = (e: KeyboardEvent) => { const { keyIntentConfig } = this.state; const key: BrowserKeys = e.key; const configuredIntent = keyIntentConfig[key]; if ( configuredIntent !== undefined && configuredIntent !== IntentName.NOOP ) { this.props.updaters.activeIntent[configuredIntent].enqueueUpdate( () => false ); this.props.updaters.endedIntent[configuredIntent].enqueueUpdate(() => { this.props.updaters.endedIntent[configuredIntent].enqueueUpdate( () => false ); return true; }); } }; componentWillUnmount() { document.removeEventListener("keydown", this.handleKeydown); document.removeEventListener("keyup", this.handleKeyup); } render() { return "hi"; } }