Skip to content

forge3d.Input & Key

Per-frame keyboard and mouse state snapshots.


Input

Input dataclass

Immutable snapshot of input state for a single rendered frame.

Created by the viewer's event loop; passed to @app.on_update and available via viewer.input after each :meth:Viewer.draw call.

All keys are plain strings — use :class:Key constants or raw lowercase strings ('w', 'space', 'f1').

Mouse buttons: 0 = left, 1 = right, 2 = middle.

key_held

key_held(key: str) -> bool

True while the key is physically held down.

key_pressed

key_pressed(key: str) -> bool

True only during the first frame the key was pressed.

key_released

key_released(key: str) -> bool

True only during the first frame the key was released.

any_key_held

any_key_held(*keys: str) -> bool

True if any of the given keys are held.

all_keys_held

all_keys_held(*keys: str) -> bool

True if all of the given keys are held simultaneously.

axis

axis(neg_key: str, pos_key: str) -> float

Return a [-1, 1] float axis from two opposing keys.

Positive when pos_key is held, negative when neg_key is held, zero when neither or both are held. Replaces the common pattern::

float(inp.key_held(Key.D)) - float(inp.key_held(Key.A))

mouse_pos

mouse_pos() -> tuple[float, float]

Current cursor position in pixels (x, y) from top-left.

mouse_delta

mouse_delta() -> tuple[float, float]

Cursor movement since last frame (dx, dy) in pixels.

mouse_button

mouse_button(button: int = 0) -> bool

True while the given mouse button is held (0=left, 1=right, 2=mid).

scroll_delta

scroll_delta() -> float

Mouse wheel scroll this frame (positive = scroll up / zoom in).


Key

Key

Keyboard key name constants.

All values are lowercase strings that match the names used internally by the viewer's event back-end. Pass them to :meth:Input.key_held etc.

Examples::

inp.key_held(f3d.Key.SPACE)
inp.key_pressed('w')         # raw strings work too

InputBuilder (v1.1.0)

InputBuilder module-attribute

InputBuilder = _InputBuilder

Usage examples

With Viewer (built-in integration)

viewer = f3d.Viewer(world)
while viewer.is_open:
    inp = viewer.input          # updated each draw()
    if inp.key_pressed(f3d.Key.SPACE):
        world.apply_impulse(ball, (0, 0, 8))
    if inp.key_held(f3d.Key.RIGHT):
        world.apply_impulse(ball, (3 * dt, 0, 0))
    dx, dy = inp.mouse_delta()
    cam.rotate(d_azimuth=dx * 0.3)
    world.step()
    viewer.draw()

With a custom window (advanced)

InputBuilder exposes low-level callback methods that any windowing library can drive. For example, wiring up a raw glfw window manually:

import glfw
import forge3d as f3d

builder = f3d.InputBuilder()

def key_cb(win, key, sc, action, mods):
    from forge3d.render.realtime.window_renderer import _glfw_key_name
    name = _glfw_key_name(key, sc)
    if name:
        if action in (glfw.PRESS, glfw.REPEAT):
            builder.on_key_down(name)
        elif action == glfw.RELEASE:
            builder.on_key_up(name)

glfw.set_key_callback(window, key_cb)

while not glfw.window_should_close(window):
    glfw.poll_events()
    inp = builder.build()

    if inp.key_held(f3d.Key.W):
        car.apply_force(forward * 500)

    world.step()
    builder.end_frame()

glfw-native input

New code should use f3d.Viewer directly — glfw callbacks are wired up automatically and InputBuilder is managed internally.

Key constants reference

# Letters
f3d.Key.W, f3d.Key.A, f3d.Key.S, f3d.Key.D   # WASD movement

# Arrows
f3d.Key.UP, f3d.Key.DOWN, f3d.Key.LEFT, f3d.Key.RIGHT

# Special
f3d.Key.SPACE, f3d.Key.ESCAPE, f3d.Key.ENTER
f3d.Key.SHIFT, f3d.Key.CTRL, f3d.Key.ALT

# Function keys
f3d.Key.F1 ... f3d.Key.F12

# Raw strings also work
inp.key_held('w')        # same as key_held(f3d.Key.W)
inp.key_pressed('space')