Panda3D is a framework for 3D rendering and game development for Python and C++ programs.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Panda3D provides comprehensive input handling for keyboard, mouse, and gamepad devices through an event-driven system that integrates seamlessly with the task and messaging systems.
Keyboard input is handled through events generated for key press and release actions.
# Key event patterns
# Press events: key name (e.g., "a", "space", "escape")
# Release events: key name + "-up" (e.g., "a-up", "space-up")
# Common key events
"escape" # Escape key
"space" # Space bar
"enter" # Enter/Return key
"tab" # Tab key
"backspace" # Backspace key
"delete" # Delete key
# Letter keys
"a", "a-up" # A key press/release
"b", "b-up" # B key press/release
# ... (all letters a-z)
# Number keys
"1", "1-up" # Number 1 key
"2", "2-up" # Number 2 key
# ... (numbers 0-9)
# Arrow keys
"arrow_up", "arrow_up-up"
"arrow_down", "arrow_down-up"
"arrow_left", "arrow_left-up"
"arrow_right", "arrow_right-up"
# Function keys
"f1", "f1-up" # Function keys F1-F12
"f2", "f2-up"
# ... (f1 through f12)
# Modifier keys
"shift", "shift-up" # Shift keys
"control", "control-up" # Control keys
"alt", "alt-up" # Alt keys
# Special keys
"home", "home-up"
"end", "end-up"
"page_up", "page_up-up"
"page_down", "page_down-up"
"insert", "insert-up"Mouse input includes button clicks, movement, and wheel events.
# Mouse button events
"mouse1" # Left mouse button press
"mouse1-up" # Left mouse button release
"mouse2" # Middle mouse button press
"mouse2-up" # Middle mouse button release
"mouse3" # Right mouse button press
"mouse3-up" # Right mouse button release
# Mouse wheel events
"wheel_up" # Mouse wheel scroll up
"wheel_down" # Mouse wheel scroll down
# Mouse movement tracking through MouseWatcher
class MouseWatcher:
def hasMouse(self) -> bool:
"""Check if mouse is within window."""
def getMouseX(self) -> float:
"""Get mouse X coordinate (-1 to 1)."""
def getMouseY(self) -> float:
"""Get mouse Y coordinate (-1 to 1)."""
def getMouse(self) -> Vec2:
"""Get mouse position as Vec2."""
def isButtonDown(self, button: int) -> bool:
"""Check if mouse button is currently down."""Track the current state of input devices for continuous input handling.
# Access through base.mouseWatcherNode
mouseWatcher = base.mouseWatcherNode
# Check current input states
def isKeyDown(key: str) -> bool:
"""Check if key is currently pressed."""
return base.mouseWatcherNode.isButtonDown(key)
# Common input state checks
def getMousePos() -> tuple:
"""Get current mouse position."""
if base.mouseWatcherNode.hasMouse():
x = base.mouseWatcherNode.getMouseX()
y = base.mouseWatcherNode.getMouseY()
return (x, y)
return None
def getMouseDelta() -> tuple:
"""Get mouse movement since last frame."""
# Implementation depends on tracking previous position
passBind input events to functions using the event system.
# Basic event binding (from ShowBase or DirectObject)
def accept(event: str, method: callable, extraArgs: list = []) -> None:
"""Bind input event to method."""
def ignore(event: str) -> None:
"""Stop handling input event."""
def ignoreAll() -> None:
"""Stop handling all events."""
# Example event handlers
def handleKeyPress(self):
"""Handle key press event."""
pass
def handleMouseClick(self):
"""Handle mouse click event."""
pass
def handleMouseDrag(self):
"""Handle mouse drag event."""
passCommon input handling patterns for games and applications.
# Movement input handling
MOVEMENT_KEYS = {
"w": Vec3(0, 1, 0), # Forward
"s": Vec3(0, -1, 0), # Backward
"a": Vec3(-1, 0, 0), # Left
"d": Vec3(1, 0, 0), # Right
"q": Vec3(0, 0, 1), # Up
"e": Vec3(0, 0, -1) # Down
}
# Input combinations
def isShiftPressed() -> bool:
"""Check if shift modifier is active."""
return base.mouseWatcherNode.isButtonDown("shift")
def isCtrlPressed() -> bool:
"""Check if control modifier is active."""
return base.mouseWatcherNode.isButtonDown("control")from direct.showbase.ShowBase import ShowBase
from panda3d.core import Vec3
class InputDemo(ShowBase):
def __init__(self):
ShowBase.__init__(self)
# Create player object
self.player = self.loader.loadModel("models/player")
self.player.reparentTo(self.render)
self.player.setPos(0, 10, 0)
# Setup input handling
self.setupInput()
# Movement state
self.keys_pressed = set()
self.mouse_pressed = set()
# Start input update task
self.taskMgr.add(self.updateInput, "update-input")
def setupInput(self):
"""Setup all input event handlers."""
# Movement keys
movement_keys = ["w", "a", "s", "d", "q", "e"]
for key in movement_keys:
self.accept(key, self.onKeyPress, [key])
self.accept(f"{key}-up", self.onKeyRelease, [key])
# Action keys
self.accept("space", self.jump)
self.accept("shift", self.run)
self.accept("shift-up", self.walk)
# Mouse input
self.accept("mouse1", self.onMousePress, [1])
self.accept("mouse1-up", self.onMouseRelease, [1])
self.accept("mouse3", self.onMousePress, [3])
self.accept("mouse3-up", self.onMouseRelease, [3])
# Special keys
self.accept("escape", self.exitGame)
self.accept("f1", self.showHelp)
# Mouse wheel
self.accept("wheel_up", self.zoomIn)
self.accept("wheel_down", self.zoomOut)
def onKeyPress(self, key):
"""Handle key press."""
self.keys_pressed.add(key)
print(f"Key pressed: {key}")
def onKeyRelease(self, key):
"""Handle key release."""
self.keys_pressed.discard(key)
print(f"Key released: {key}")
def onMousePress(self, button):
"""Handle mouse button press."""
self.mouse_pressed.add(button)
# Get mouse position
if self.mouseWatcherNode.hasMouse():
x = self.mouseWatcherNode.getMouseX()
y = self.mouseWatcherNode.getMouseY()
print(f"Mouse {button} pressed at ({x:.2f}, {y:.2f})")
def onMouseRelease(self, button):
"""Handle mouse button release."""
self.mouse_pressed.discard(button)
print(f"Mouse {button} released")
def updateInput(self, task):
"""Update input-based movement."""
dt = globalClock.getDt()
# Calculate movement vector
movement = Vec3(0, 0, 0)
speed = 10.0 # Base speed
# Apply movement keys
if "w" in self.keys_pressed:
movement += Vec3(0, 1, 0)
if "s" in self.keys_pressed:
movement += Vec3(0, -1, 0)
if "a" in self.keys_pressed:
movement += Vec3(-1, 0, 0)
if "d" in self.keys_pressed:
movement += Vec3(1, 0, 0)
if "q" in self.keys_pressed:
movement += Vec3(0, 0, 1)
if "e" in self.keys_pressed:
movement += Vec3(0, 0, -1)
# Apply speed modifiers
if self.isShiftPressed():
speed *= 2.0 # Run speed
# Normalize and apply movement
if movement.length() > 0:
movement.normalize()
movement *= speed * dt
current_pos = self.player.getPos()
self.player.setPos(current_pos + movement)
return task.cont
def isShiftPressed(self):
"""Check if shift is currently pressed."""
return self.mouseWatcherNode.isButtonDown("shift")
def jump(self):
"""Handle jump action."""
print("Jump!")
# Add jump logic here
def run(self):
"""Start running."""
print("Running...")
def walk(self):
"""Stop running."""
print("Walking...")
def zoomIn(self):
"""Zoom camera in."""
pos = self.camera.getPos()
self.camera.setPos(pos * 0.9)
def zoomOut(self):
"""Zoom camera out."""
pos = self.camera.getPos()
self.camera.setPos(pos * 1.1)
def showHelp(self):
"""Show help information."""
print("Help: WASD to move, Shift to run, Space to jump, ESC to exit")
def exitGame(self):
"""Exit the game."""
print("Exiting...")
self.userExit()
app = InputDemo()
app.run()from direct.showbase.DirectObject import DirectObject
from panda3d.core import Vec3
class InputController(DirectObject):
"""Advanced input handling controller."""
def __init__(self, controlled_object):
DirectObject.__init__(self)
self.controlled_object = controlled_object
# Input state
self.keys_down = set()
self.mouse_buttons_down = set()
self.previous_mouse_pos = None
self.mouse_sensitivity = 1.0
# Input settings
self.move_speed = 10.0
self.run_multiplier = 2.0
self.mouse_look_enabled = False
# Setup input bindings
self.setupInputBindings()
# Start update task
self.addTask(self.updateInput, "input-controller")
def setupInputBindings(self):
"""Setup all input event handlers."""
# Movement keys
movement_keys = ["w", "a", "s", "d", "space", "shift"]
for key in movement_keys:
self.accept(key, self.onKeyDown, [key])
self.accept(f"{key}-up", self.onKeyUp, [key])
# Mouse look
self.accept("mouse2", self.enableMouseLook)
self.accept("mouse2-up", self.disableMouseLook)
# Mouse sensitivity
self.accept("=", self.adjustMouseSensitivity, [0.1])
self.accept("-", self.adjustMouseSensitivity, [-0.1])
def onKeyDown(self, key):
"""Handle key press."""
self.keys_down.add(key)
def onKeyUp(self, key):
"""Handle key release."""
self.keys_down.discard(key)
def enableMouseLook(self):
"""Enable mouse look mode."""
self.mouse_look_enabled = True
self.previous_mouse_pos = self.getMousePos()
# Hide cursor
props = WindowProperties()
props.setCursorHidden(True)
base.win.requestProperties(props)
def disableMouseLook(self):
"""Disable mouse look mode."""
self.mouse_look_enabled = False
# Show cursor
props = WindowProperties()
props.setCursorHidden(False)
base.win.requestProperties(props)
def getMousePos(self):
"""Get current mouse position."""
if base.mouseWatcherNode.hasMouse():
return (
base.mouseWatcherNode.getMouseX(),
base.mouseWatcherNode.getMouseY()
)
return None
def updateInput(self, task):
"""Update input processing."""
dt = globalClock.getDt()
# Handle movement
self.updateMovement(dt)
# Handle mouse look
if self.mouse_look_enabled:
self.updateMouseLook()
return task.cont
def updateMovement(self, dt):
"""Update object movement based on input."""
movement = Vec3(0, 0, 0)
# Calculate movement direction
if "w" in self.keys_down:
movement += Vec3(0, 1, 0)
if "s" in self.keys_down:
movement += Vec3(0, -1, 0)
if "a" in self.keys_down:
movement += Vec3(-1, 0, 0)
if "d" in self.keys_down:
movement += Vec3(1, 0, 0)
if "space" in self.keys_down:
movement += Vec3(0, 0, 1)
# Apply speed
speed = self.move_speed
if "shift" in self.keys_down:
speed *= self.run_multiplier
# Apply movement
if movement.length() > 0:
movement.normalize()
movement *= speed * dt
# Transform movement relative to object orientation
movement = self.controlled_object.getRelativeVector(
render, movement
)
current_pos = self.controlled_object.getPos()
self.controlled_object.setPos(current_pos + movement)
def updateMouseLook(self):
"""Update mouse look rotation."""
current_mouse = self.getMousePos()
if current_mouse and self.previous_mouse_pos:
# Calculate mouse delta
dx = current_mouse[0] - self.previous_mouse_pos[0]
dy = current_mouse[1] - self.previous_mouse_pos[1]
# Apply mouse sensitivity
dx *= self.mouse_sensitivity * 100
dy *= self.mouse_sensitivity * 100
# Update object rotation
current_hpr = self.controlled_object.getHpr()
new_h = current_hpr.getX() - dx # Horizontal rotation
new_p = current_hpr.getY() + dy # Vertical rotation
# Clamp vertical rotation
new_p = max(-90, min(90, new_p))
self.controlled_object.setHpr(new_h, new_p, 0)
self.previous_mouse_pos = current_mouse
def adjustMouseSensitivity(self, change):
"""Adjust mouse sensitivity."""
self.mouse_sensitivity = max(0.1, min(5.0,
self.mouse_sensitivity + change))
print(f"Mouse sensitivity: {self.mouse_sensitivity:.1f}")
def cleanup(self):
"""Clean up input controller."""
self.disableMouseLook()
self.removeAllTasks()
self.ignoreAll()from panda3d.core import Vec2
# Mouse coordinates are normalized to -1.0 to 1.0 range
# (0, 0) is center of window
# (-1, -1) is bottom-left corner
# (1, 1) is top-right corner
# Key names follow specific conventions:
# - Letters: "a" through "z"
# - Numbers: "0" through "9"
# - Special: "space", "enter", "escape", "tab", etc.
# - Arrows: "arrow_up", "arrow_down", "arrow_left", "arrow_right"
# - Function: "f1" through "f12"
# - Modifiers: "shift", "control", "alt"
# Mouse button numbers:
MOUSE_LEFT = 1 # Left mouse button
MOUSE_MIDDLE = 2 # Middle mouse button
MOUSE_RIGHT = 3 # Right mouse buttonInstall with Tessl CLI
npx tessl i tessl/pypi-panda3d