Keyboard
Key presses reach React as two built-in events,
keyDown and keyUp. They are window-wide: they fire for every key the app
window receives, whichever element has focus, and they are typed in every
generated bevy.ts without any Rust code or registration. There are no
per-element key handlers.
Usage
import { useEffect } from "react";
import { bevy } from "./bevy"; // generated
function Menu({ onClose }: { onClose: () => void }) {
useEffect(
() =>
bevy.on("keyDown", (e) => {
if (e.key === "Escape") onClose();
}),
[onClose],
);
return <node>{/* … */}</node>;
}The events
keyDownfires when a key is pressed, and again for each OS auto-repeat while it is held (withrepeat: true).keyUpfires when the key is released.
Both carry a KeyboardEventData (importable from your ./bevy module):
| Field | Type | Meaning |
|---|---|---|
key |
string |
The logical key: the typed character ("a", "A", "1") or a key name |
code |
string |
The physical key, independent of the keyboard layout ("KeyA", "Digit1") |
text |
string | null |
The text the key produces, if any; null for arrows, modifiers and the like |
repeat |
boolean |
Whether this keyDown is an OS auto-repeat |
ctrlKey |
boolean |
A Control key is held |
shiftKey |
boolean |
A Shift key is held |
altKey |
boolean |
An Alt key is held |
metaKey |
boolean |
A Super key (Windows, Command) is held |
- Key names are Bevy's, which mostly match the web's:
"Enter","Escape","Tab","Backspace","ArrowLeft","Shift". The space bar is"Space"(the web uses" "); itstextis" ". codevalues are Bevy'sKeyCodenames, which follow the web'scodevalues for most keys ("Enter","Space","ArrowLeft","ShiftLeft"). The Windows/Command keys are"SuperLeft"and"SuperRight".- Match shortcuts on
keywhen the character matters ("?","+") and oncodewhen the position does (WASD on any layout). - The modifier flags show the state at the end of the frame the key event
arrived in: either side counts, and a modifier's own
keyDownalready has its flag set.
Filter auto-repeat out when a key should act once per press:
bevy.on("keyDown", (e) => {
if (e.repeat) return;
if (e.code === "KeyS" && e.ctrlKey) save();
});Text input and focus
Because the events are window-wide, they also fire while the user types in an
<editableText>. Keep single-key shortcuts
from firing during text entry by tracking the input's focus:
const typing = useRef(false);
useEffect(
() =>
bevy.on("keyDown", (e) => {
if (typing.current) return;
if (e.key === "m") toggleMap();
}),
[],
);
<editableText
onFocus={() => (typing.current = true)}
onBlur={() => (typing.current = false)}
/>;The same holds on the Bevy side: systems that read ButtonInput<KeyCode>
see every keystroke, including the ones typed into an <editableText>, and
React can't stop them. If gameplay keys must pause while the player types,
tell Bevy with a message from onFocus
and onBlur.
Limits
- No per-element
onKeyDownand nopreventDefault: a listener can't keep a key from an<editableText>or from Bevy systems. - Each key event is one trip across the bridge. That suits shortcuts and
menus; continuous input such as character movement belongs in a Bevy system
reading
ButtonInput<KeyCode>. - Events are not buffered: a key pressed before a listener subscribes is missed.
The built-in event types are listed in the generated
bevy.ts reference.
bevy-react