IPC controller interface
Amiberry exposes a line-oriented Unix-domain socket when it is built with
USE_IPC_SOCKET=ON. The interface is available on Linux and macOS. It is used
by controller software such as the
Amiberry MCP server,
which presents stable, action-level MCP tools and HTTP endpoints.
Application integrations should use those MCP or HTTP interfaces. The raw commands described here are controller primitives: they expose window-logical coordinates, complete button bitmasks, runtime identities, revisions, and configuration compare-and-set operations. They are not intended as a direct public automation API.
Transport
The first instance listens on $XDG_RUNTIME_DIR/amiberry.sock, or
/tmp/amiberry.sock when XDG_RUNTIME_DIR is not set. Further instances use
amiberry_1.sock through amiberry_9.sock in the same directory.
Each request and response is one newline-terminated record. Request fields are separated by tabs:
COMMAND<TAB>ARGUMENT<TAB>ARGUMENT<NEWLINE>
A response starts with OK or ERROR; any following tab-separated fields are
command-specific. The HELP command lists all commands supported by the
running build.
A connection stays open until the client closes it. A controller can send many requests over one connection or open a new connection per request, and up to 16 controllers can be connected at once. Requests on one connection are answered in order. Amiberry closes a connection whose request grows past 64 KiB without a newline.
Commands run on the emulation thread between frames. Amiberry answers waiting requests for a few milliseconds per frame, at least one per connection, and keeps listening briefly so a controller that sends its next request as soon as it reads the reply is not limited to one request per frame. Requests beyond that budget wait for the next frame. Several requests can therefore take effect in the same emulated frame. A controller that needs the Amiga to observe a state, such as a key or mouse button being held down, must wait between the press and the release instead of relying on one request per frame.
Screenshot-driven GUI automation
The safe controller sequence is:
- Capture a coherent screenshot and geometry snapshot with
SCREENSHOT <path> ACTIONABLE. - Observe the current focus, input configuration, monitor, and revisions with
GET_GUI_AUTOMATION_STATE. - If required, use
SET_GUI_AUTOMATION_CONFIGas a guarded compare-and-set. - Convert the selected screenshot pixel into the window-logical coordinate
space described by the capture, then send it with
SEND_MOUSE_ABS_GUARDED. - Use
RELEASE_MOUSE_BUTTONSfor coordinate-free cleanup after any pressed button, including when geometry or revisions have changed.
Controllers must reject stale captures. Do not replay guarded input after a runtime restart, geometry change, monitor change, or input-configuration revision change. Capture a new actionable screenshot instead.
SCREENSHOT <path> ACTIONABLE
Creates a PNG and atomically returns the geometry which made that exact image actionable. Success has this fixed schema-version-1 field set:
OK
schema_version=1
path=<path>
runtime_id=<process identity>
capture_nonce=<capture identity>
geometry_revision=<unsigned revision>
monitor_id=<active input monitor>
display_mode=<mode>
renderer=<renderer>
image_width=<PNG width>
image_height=<PNG height>
source_x=<source rectangle x>
source_y=<source rectangle y>
source_width=<source rectangle width>
source_height=<source rectangle height>
viewport_x=<window-logical viewport x>
viewport_y=<window-logical viewport y>
viewport_width=<window-logical viewport width>
viewport_height=<window-logical viewport height>
window_width=<window-logical width>
window_height=<window-logical height>
The fields are tab-separated on the wire; they are shown one per line above
for readability. image_* and source_* use screenshot pixels.
viewport_* and window_* use Amiberry window-logical coordinates. A
controller maps a point from the saved image through the source rectangle and
viewport exactly once. Raw absolute IPC commands do not accept screenshot
pixels.
Without ACTIONABLE, SCREENSHOT <path> remains the legacy screenshot
operation and returns only the path. It has no runtime, revision, or geometry
guard and must not be used as a relative-coordinate fallback for automation.
Actionable capture is currently supported by the SDL and OpenGL renderers.
The Vulkan renderer rejects SCREENSHOT <path> ACTIONABLE because its
threaded presentation path cannot yet pair captured surface pixels with the
geometry of the same presented frame. Legacy SCREENSHOT <path> remains
available with Vulkan, but it does not make the image safe for coordinate
automation.
GET_GUI_AUTOMATION_STATE
Takes no arguments. A successful schema-version-1 response contains:
runtime_id,geometry_revision,monitor_id, andgeometry_validpending_tablet_modeandeffective_tablet_modepending_mouse_untrapandeffective_mouse_untrappending_effective_divergedandinput_config_revisionfocus_ready,supported_button_mask, and the currentbutton_mask
Tablet modes are off, mousehack, and real. Mouse-untrap modes are off,
middle, magic, and both. A controller must not send guarded input unless
geometry is valid, focus is ready, and the effective input settings are
compatible.
SET_GUI_AUTOMATION_CONFIG
SET_GUI_AUTOMATION_CONFIG <expected_tablet_mode> <expected_mouse_untrap> <expected_input_config_revision> <tablet_mode> <mouse_untrap>
This command compares the expected pending settings and revision with the live
state before changing the pending settings. Success returns reason=none and
the resulting pending/effective values and input_config_revision. A stale or
externally changed state returns ERROR, reason=input_config_conflict, and
the current state. reason=malformed_request reports invalid arguments.
This compare-and-set is for a controller that temporarily owns settings and later restores only the state it still owns. Public MCP and HTTP users should not invoke it directly.
SEND_MOUSE_ABS_GUARDED
SEND_MOUSE_ABS_GUARDED <x> <y> <button_mask> <runtime_id> <geometry_revision> <monitor_id> <input_config_revision>
x and y are window-logical coordinates derived from the actionable
screenshot metadata. button_mask is the complete desired button mask: bit 0 is
left, bit 1 is right, and bit 2 is middle, so valid masks are 0 through 7. It
is a state assignment, not a named click action.
Amiberry applies the coordinate and button mask together only when all guards
still match. Every response includes schema_version=1, applied, reason,
the current runtime_id, geometry_revision, monitor_id,
input_config_revision, and button_mask; success also returns x and y.
Stable rejection reasons are:
geometry_invalidruntime_mismatchgeometry_revision_mismatchmonitor_mismatchinput_config_revision_mismatchsettings_incompatiblefocus_not_readyunsupported_button_maskcoordinate_out_of_boundsinput_rejectedmalformed_request
On rejection, the guarded mutation is not applied. Controllers should use the returned state to decide whether to retry setup or recapture; they must not blindly replay the same mouse operation.
RELEASE_MOUSE_BUTTONS
Takes no arguments and releases left, right, and middle without requiring a
coordinate or a valid capture. It is unconditional and idempotent. Success
returns schema_version=1 and button_mask=0; a non-zero returned mask is an
error and cleanup remains unconfirmed.
This is the recovery primitive after a partial click or drag. Controller-level click and drag implementations may use short internal dwell intervals (the Amiberry MCP controller currently uses 50 ms between press/move/release phases), but that timing and the raw button-mask sequence are private implementation details rather than public API parameters.
Validation status
The geometry mapping and controller primitives have automated coverage in
tests/test_gfx_geometry.sh and tests/test_ipc_gui_automation.sh, including
HiDPI conversion, revision invalidation, stale-guard rejection, button masks,
and unconditional release. Live end-to-end validation with packaged Amiberry
builds on Linux and macOS is a separate release check and is not implied by
those automated tests.