diff --git a/Input-and-Events.md b/Input-and-Events.md new file mode 100644 index 0000000..5f7904e --- /dev/null +++ b/Input-and-Events.md @@ -0,0 +1,162 @@ +# Input and Events + +McRogueFace provides keyboard, mouse, and window event handling through Python callbacks. Events are dispatched through the scene system, allowing different scenes to have different input handlers. + +**Related Pages:** +- [[UI-Widget-Patterns]] - Modal dialogs, buttons, hotbars +- [[Grid-Interaction-Patterns]] - Entity selection, movement, context menus +- [[Writing-Tests]] - Testing input with automation API + +**Key Files:** +- `src/GameEngine.cpp::processEvent()` - Event dispatch +- `src/Scene.cpp::sUserInput()` - Scene input handling +- `src/McRFPy_API.cpp` - Python callback registration + +--- + +## Keyboard Input + +Register a scene-level callback that fires on every key press/release: + +```python +import mcrfpy + +def handle_key(key: str, pressed: bool): + """ + key: Key name (e.g., "W", "Space", "Escape", "Up") + pressed: True on press, False on release + """ + if key == "Escape" and pressed: + mcrfpy.setScene("menu") + +mcrfpy.keypressScene(handle_key) +``` + +### Key Names + +Common key names from SFML: +- Letters: `"A"` through `"Z"` +- Numbers: `"Num0"` through `"Num9"` +- Arrows: `"Up"`, `"Down"`, `"Left"`, `"Right"` +- Special: `"Space"`, `"Enter"`, `"Escape"`, `"Tab"`, `"LShift"`, `"RShift"`, `"LControl"`, `"RControl"` +- Function: `"F1"` through `"F12"` + +--- + +## Mouse Input + +### Element Event Handlers + +All UIDrawables support mouse event callbacks: + +| Property | Signature | When Called | +|----------|-----------|-------------| +| `on_click` | `(x, y, button) -> None` | Mouse button pressed on element | +| `on_enter` | `() -> None` | Mouse enters element bounds | +| `on_exit` | `() -> None` | Mouse leaves element bounds | +| `on_move` | `(x, y) -> None` | Mouse moves within element | + +```python +frame = mcrfpy.Frame(pos=(100, 100), size=(200, 50)) + +frame.on_click = lambda x, y, btn: print(f"Clicked at ({x}, {y}) with button {btn}") +frame.on_enter = lambda: print("Mouse entered") +frame.on_exit = lambda: print("Mouse exited") +``` + +The `hovered` property (read-only) indicates whether the mouse is currently over an element. + +### Grid Cell Events + +Grids provide cell-level mouse events in addition to element events: + +| Property | Signature | Description | +|----------|-----------|-------------| +| `on_cell_click` | `(grid_x, grid_y, button) -> None` | Cell clicked | +| `on_cell_enter` | `(grid_x, grid_y) -> None` | Mouse enters cell | +| `on_cell_exit` | `(grid_x, grid_y) -> None` | Mouse leaves cell | +| `hovered_cell` | `(x, y)` or `None` | Currently hovered cell (read-only) | + +See [[Grid-Interaction-Patterns]] for usage examples. + +### Mouse Position + +```python +# Window coordinates (pixels) +x, y = mcrfpy.getMousePos() +``` + +--- + +## Event Priority + +### Click Dispatch Order + +Clicks are dispatched in reverse render order (front to back): + +1. **UI elements with highest z_index** receive clicks first +2. If handled (callback returns truthy), propagation stops +3. **Entities on grids** receive clicks next +4. **Grid cells** receive clicks last + +### Keyboard Priority + +Keyboard events go only to the current scene's registered callback. There is no concept of "focused" UI elements for keyboard input. + +--- + +## Window Events + +### Resize Events + +Window resize events are not currently exposed directly. Workaround using timer polling: + +```python +last_size = mcrfpy.getWindowSize() + +def check_resize(dt): + global last_size + current = mcrfpy.getWindowSize() + if current != last_size: + on_resize(current) + last_size = current + +mcrfpy.setTimer("resize_check", check_resize, 100) +``` + +--- + +## Testing Input + +Use the automation API to simulate input in tests: + +```python +from mcrfpy import automation + +automation.keypress("W", True) # Press W +automation.keypress("W", False) # Release W +automation.click(100, 200, button=0) # Left-click at position +``` + +See [[Writing-Tests]] for complete testing patterns. + +--- + +## API Reference + +**Module Functions:** +- `mcrfpy.keypressScene(callback)` - Register keyboard handler +- `mcrfpy.getMousePos() -> (int, int)` - Get mouse position +- `mcrfpy.getWindowSize() -> (int, int)` - Get window dimensions + +**UIDrawable Properties:** +- `on_click`, `on_enter`, `on_exit`, `on_move` - Event handlers +- `hovered` - Mouse hover state (read-only) + +**Grid Properties:** +- `on_cell_click`, `on_cell_enter`, `on_cell_exit` - Cell event handlers +- `hovered_cell` - Currently hovered cell (read-only) + +--- + +*Last updated: 2025-11-29* \ No newline at end of file