Table of contents
Playnote > IPC input
Playnote accepts synthetic input via an IPC interface transporting JSON objects. These inputs can control only the UI. This is useful for automated testing and may in the future be expanded with higher-level commands, such as letting Twitch chat control song selection.
Caution
IPC input cannot control gameplay.
On Linux, IPC uses an abstract socket named @playnote-ipc-<uid>. On Windows, it uses a named pipe at \\.\pipe\dev.playnote.Playnote-<sid>, where <sid> is the current Windows user's security identifier.
Lifecycle
A client connection begins with an information query:
{"type": "ipc.info"}
The server replies with the current instance kind:
graphical: the normal game instanceheadless: a running command-line process
{"type": "ipc.info", "kind": "graphical"}
Naturally, only a graphical instance will accept synthetic inputs.
All future messages receive an acknowledgement. This verifies only that the message was received and is valid JSON matching the expected schema. The command may still fail if its values are unexpected; semantic failures are logged only by the running instance.
Note
An
ipc.acceptedresponse does not mean that the requested action succeeded.
{"type": "ipc.accepted"}
{"type": "ipc.rejected", "reason": "..."}
Input syntax
Button actions use the following messages:
{"type": "input", "version": 1, "action": "accept"}
{"type": "input", "version": 1, "action": "cancel"}
{"type": "input", "version": 1, "action": "start"}
{"type": "input", "version": 1, "action": "select"}
Navigation additionally accepts:
coarse: Optional boolean, defaulting tofalse. Requests larger semantic steps, such as moving by a word or page.index: Optional0or1, defaulting to0. Identifies the P1 or P2 side when relevant.
{"type": "input", "version": 1, "action": "next"}
{"type": "input", "version": 1, "action": "previous", "coarse": true, "index": 1}
Adjustment additionally accepts:
precision: Optional boolean, defaulting tofalse. Requests a finer adjustment step.index: Same as above.
{"type": "input", "version": 1, "action": "increase"}
{"type": "input", "version": 1, "action": "decrease", "precision": true, "index": 1}
Example
A Python client for Linux:
import json
import os
import socket
endpoint = "\0playnote-ipc-{}".format(os.getuid())
with socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) as client:
client.connect(endpoint)
client.sendall(json.dumps({"type": "ipc.info"}).encode())
info = json.loads(client.recv(64 * 1024))
if info.get("kind") != "graphical":
raise RuntimeError("Playnote is not running as a graphical instance")
client.sendall(json.dumps({
"type": "input",
"version": 1,
"action": "accept",
}).encode())
acknowledgement = json.loads(client.recv(64 * 1024))
if acknowledgement.get("type") != "ipc.accepted":
raise RuntimeError(acknowledgement)