mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 10:37:03 -06:00
A right click on an unselected shape opened the slide's context menu (Layout, Reset Slide...) because only the primary button reached the pointer tool; the shape had to be left-clicked first. The right-button press now goes through Session::pointer as PointerKind::ContextClick (`contextclick` on the control channel and MCP) and selects like PowerPoint before the menu opens: an unselected shape is selected alone (a text box or placeholder is not put into text editing, nothing is dragged), a selected shape keeps the selection, multiple selection included, and empty slide clears it. In the box whose text is being edited, the caret and text selection stay, and the context menu offers text items (Paragraph, Bullets, Numbering, Link) next to Cut, Copy and Paste, which act on the selected text.
34 lines
2.9 KiB
Markdown
34 lines
2.9 KiB
Markdown
# Control protocol
|
||
|
||
Start the app with `--control <port>`. The server listens on `127.0.0.1` only and speaks JSON
|
||
lines: one request object per line, one reply per line.
|
||
|
||
```json
|
||
{"id": 1, "method": "engine.execute", "params": {"command": "shape.insert", "params": {"preset": "roundRect", "rect": [100, 100, 240, 120], "text": "Hello"}}}
|
||
{"id": 1, "ok": true, "result": {"id": 258}}
|
||
```
|
||
|
||
Coordinates are slide points (1/72 inch; a 16:9 slide is 960 × 540) unless noted.
|
||
|
||
| Method | Params | What it does |
|
||
|---|---|---|
|
||
| `engine.execute` / `ui.menu.invoke` / `command` | `{command, params}` | Run any command (see `engine.commands`; `deckcraft-cli describe ID` documents one) |
|
||
| `engine.commands` | — | Every command: id, label, menu path, shortcut, params doc, enabled / disabled reason |
|
||
| `document.inspect` | — | Slides, sections, layouts, shapes, selection |
|
||
| `ui.inspect` | — | UI state, active tool, window/canvas/slide rects, dialog, `home` (the File tab open over a presentation), `backstage` (its page, also the start screen), slide show state, documents, perf (fps, render ms) |
|
||
| `ui.tool.select` | `{tool, preset?}` | `select`, `text`, `shape` + preset, any preset name, `curve`, `freeform`, `scribble`, `pen`, `highlighter`, `eraser` |
|
||
| `ui.pointer` | `{events: [{kind: down\|drag\|up\|move\|doubleclick\|tripleclick\|contextclick, x, y, mods?}], mods?}` | Drive the active tool in slide points through the same code path as the mouse (`contextclick`: the right-button press that selects before the context menu) |
|
||
| `ui.key` / `ui.text` | `{key, shift?, alt?, cmd?}` / `{text}` | Keyboard input (also drives a running slide show) |
|
||
| `ui.ime` | `{preedit, active?: [start, end]}` / `{commit}` | An input method's composition through egui, as a real one arrives: shown in place on the slide or in a focused field; `{"preedit": ""}` cancels |
|
||
| `ui.move` / `ui.click` / `ui.drag` | screen points | Real egui pointer input — reaches every widget, menu and pane |
|
||
| `ui.set` | `{tab?, view?, pane?, notes?, zoom?, brightness?, ruler?, gridlines?, guides?, …}` | UI state (returns the full state) |
|
||
| `ui.dialog.open` / `ui.dialog.close` | `{id, fields?}` | Open or close a dialog by id; `fields` pre-fills its fields (About: `{"tab": "contributors"}` or `"models"`) |
|
||
| `ui.screenshot` | `{path?}` | PNG of the whole window (base64 when no path) |
|
||
| `ui.render` | `{path?, slide?, scale?}` | Render a slide headlessly |
|
||
| `ui.resize` / `ui.focus` | | Window control |
|
||
| `show.start` / `show.end` | `{from?: slide index, presenter?, reading?}` | Slide show |
|
||
| `app.open` / `app.save` / `app.export` / `app.quit` | `{path, …}` | Files (export takes the `file.export` params, e.g. `{"path": "deck.pdf", "layout": "handouts", "perPage": 3}`) |
|
||
|
||
The MCP server (`deckcraft-cli mcp`, see [mcp.md](mcp.md)) wraps the same methods for Claude
|
||
and other agents; `deckcraft-cli app METHOD [JSON]` sends one request from a shell.
|