Inherits juce::Thread.
|
| | RemoteServer () |
| | RemoteServer (const Options &) |
| | ~RemoteServer () override |
| bool | start () |
| | Starts listening.
|
| void | stop () |
| | Stops listening and disconnects any client.
|
| bool | isRunning () const noexcept |
| int | getPort () const noexcept |
| const Options & | getOptions () const noexcept |
| void | addCommand (const juce::String &name, const juce::String &description, const juce::String &argsSpec, CommandHandler handler) |
| | Adds a command that runs on the message thread.
|
| void | addAsyncCommand (const juce::String &name, const juce::String &description, const juce::String &argsSpec, AsyncCommandHandler handler) |
| | Adds a command that runs on the server thread.
|
| void | removeCommand (const juce::String &name) |
| void | addComponentInfoProvider (ComponentInfoProvider) |
| | Registers a hook that can add fields to every component description.
|
| void | log (const juce::String &line) |
| | Appends a line to the buffer returned by the log command.
|
| juce::var | describeComponent (juce::Component &, bool full=false) |
| | Describes a component as a json object, including fields from the registered providers.
|
| juce::var | describeTree (juce::Component &, int depth=-1, bool visibleOnly=true, int maxNodes=5000) |
| | Describes a component and its descendants.
|
|
| static juce::Array< juce::Component * > | findComponents (const juce::String &selector, bool visibleOnly=true, juce::Component *root=nullptr) |
| | Returns every component matching a selector.
|
| static juce::Component * | findComponent (const juce::String &selector, bool visibleOnly=true, juce::Component *root=nullptr) |
| | Returns the first component matching a selector, or nullptr.
|
| static juce::String | getClassName (juce::Component &) |
| | Demangled class name of a component, e.g.
|
| static juce::String | getComponentPath (juce::Component &) |
| | Index path of a component, e.g.
|
| static juce::String | getComponentText (juce::Component &) |
| | Text shown by a component if it is a button, label, text editor or combo box.
|
| static juce::var | getComponentValue (juce::Component &) |
| | Value of a component if it is a slider, toggle button, combo box, etc.
|
| static juce::String | setComponentValue (juce::Component &, const juce::var &value) |
| | Sets the value of a standard component.
|
| static juce::var | getArg (const juce::var &args, const char *name, const juce::var &defaultValue={}) |
| | Reads an argument with a default.
|
| static bool | injectMouse (juce::Point< float > screenPos, juce::ModifierKeys mods, juce::Component *target=nullptr) |
| | Synthesises a mouse event through the component peer, so it travels the same route as a real one.
|
| static bool | injectWheel (juce::Point< float > screenPos, float deltaX, float deltaY, juce::ModifierKeys mods, juce::Component *target=nullptr) |
| static bool | injectKey (const juce::KeyPress &, juce::Component *target=nullptr) |
| | Sends a key press to the focused peer, or the peer owning target.
|
| static juce::Component * | getComponentAt (juce::Point< int > screenPos) |
| | The deepest component under a screen position, across all desktop windows.
|
| static juce::ComponentPeer * | getPeerAt (juce::Point< int > screenPos) |
| | The peer under a screen position, if any.
|
| static juce::ComponentPeer * | getFocusedPeer () |
| | The focused peer, falling back to the first one.
|
| static void | setMoveRealCursor (bool shouldMove) noexcept |
| | See Options::moveRealCursor.
|
| static bool | getMoveRealCursor () noexcept |
A small TCP server that lets an external process drive a JUCE UI.
Intended for UI automation, scripted testing and AI coding agents. Clients connect over a local socket and exchange newline-delimited JSON:
-> {"id": 1, "cmd": "tree", "args": {"depth": 2}}
<- {"id": 1, "ok": true, "result": {...}}
<- {"id": 2, "ok": false, "error": "No component matches '#missing'"}
Built in commands cover the component tree (tree, find, describe, at, windows), input (click, drag, mouse, wheel, key, type, focus), state (get, set, press, resize), screenshots and waiting. Products add their own with addCommand(), and can decorate every component description with addComponentInfoProvider().
Nothing happens unless you create and start a server, so it is safe to compile into a shared module. Only start it in development builds.
Components are addressed with a tiny selector language. A selector is a space separated list of steps, each step narrowing the search to the descendants of the previous matches:
#id component ID (Component::getComponentID) .ClassName class name, with or without namespace name component name, or button / label text ~text substring match of name, text or id @x,y deepest component at a screen point /0/3/1 index path: desktop window 0, child 3, child 1 any component step[n] nth match of that step
e.g. "#sidebar .TextButton[2]" or "Save" or "@120,240"
gin::RemoteServer::Options opts;
opts.port = 27182;
remote = std::make_unique<gin::RemoteServer> (opts);
remote->addCommand ("loadPreset", "Load a preset by name", R"({"name":"string!: preset name"})",
[this] (const juce::var& args)
{
if (! loadPreset (args["name"].toString()))
return gin::RemoteServer::CommandResult::fail ("No such preset");
return gin::RemoteServer::CommandResult (juce::var (true));
});
remote->start();
A command line client and MCP server live in tools/gin_remote.