WinComm/forms/protocol.md
Scott Duensing ae2aef0119 Add remote forms system: DFM converter, server library, and client engine
Text-based protocol for serving Delphi-designed forms over serial.
dfm2form converts binary DFM (TPF0) to protocol commands on Linux.
formsrv loads .form files and sends/receives via pluggable transport.
formcli creates native Win 3.1 controls and routes events back to server.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 18:35:54 -06:00

135 lines
4.6 KiB
Markdown

# Remote Forms Protocol
## Overview
Text-based protocol for remote GUI. A C server on Linux sends form/control
commands over a transport layer; a Delphi 1.0 client on Windows 3.1 creates
native controls and sends user events back.
## Message Format
- One command per message.
- Transport delivers whole messages (today: newline-delimited over serial).
- Strings are double-quoted with escapes: `\"` `\\` `\n` `\r` `\t`.
- Bare tokens (IDs, numbers, type names) are whitespace-delimited.
- IDs are positive integers assigned by the server.
## Server → Client Commands
### FORM.CREATE
FORM.CREATE <formId> <width> <height> "<title>"
Create a new form with the given dimensions and title. The form is not
shown until FORM.SHOW is sent.
### FORM.SHOW
FORM.SHOW <formId>
### FORM.HIDE
FORM.HIDE <formId>
### FORM.DESTROY
FORM.DESTROY <formId>
Free the form and all its controls.
### CTRL.CREATE
CTRL.CREATE <formId> <ctrlId> <type> <left> <top> <width> <height> [Key="val" ...]
Create a control on the specified form. Inline key/value properties are
applied immediately after creation. See Control Types and Properties below.
### CTRL.SET
CTRL.SET <formId> <ctrlId> Key="val" [Key="val" ...]
Update one or more properties on an existing control.
### EVENT.BIND
EVENT.BIND <formId> <ctrlId> <eventName>
Wire an opt-in event handler. Auto-wired events do not need explicit binding.
### EVENT.UNBIND
EVENT.UNBIND <formId> <ctrlId> <eventName>
Remove an event handler.
## Client → Server Events
EVENT <formId> <ctrlId> <eventName> [<data>]
Event data varies by event type:
| Event | Data |
|-----------|-------------------------------|
| Click | (none) |
| DblClick | (none) |
| Change | `"new text"` |
| Select | `<index> "selected text"` |
| KeyDown | `<vkCode>` |
| KeyUp | `<vkCode>` |
| MouseDown | `<x> <y> <button>` |
| MouseUp | `<x> <y> <button>` |
| MouseMove | `<x> <y> <button>` |
| Enter | (none) |
| Exit | (none) |
| Close | (none) |
## Control Types
| Type | Delphi Class | Auto-wired Events |
|----------|-------------|-------------------|
| Label | TLabel | (none) |
| Edit | TEdit | Change |
| Button | TButton | Click |
| CheckBox | TCheckBox | Click |
| ListBox | TListBox | Select |
| ComboBox | TComboBox | Select, Change |
| Memo | TMemo | Change |
Opt-in events (require EVENT.BIND): DblClick, KeyDown, KeyUp, Enter, Exit,
MouseDown, MouseUp, MouseMove.
## Properties
| Property | Applies To | Value Format |
|------------|-------------------------------|-------------------------------------------|
| Caption | Label, Button, CheckBox | Quoted string |
| Text | Edit, ComboBox, Memo | Quoted string (`\n` for line breaks) |
| Items | ListBox, ComboBox | Quoted string (`\n`-delimited) |
| Checked | CheckBox | 0 or 1 |
| Enabled | All | 0 or 1 |
| Visible | All | 0 or 1 |
| MaxLength | Edit | Integer |
| ReadOnly | Edit, Memo | 0 or 1 |
| ScrollBars | Memo | 0-3 (ssNone..ssBoth) |
| ItemIndex | ListBox, ComboBox | Integer (-1 = none) |
| TabOrder | All windowed controls | Integer |
## String Encoding
- Strings in the protocol are always double-quoted.
- Escape sequences: `\"` (literal quote), `\\` (literal backslash),
`\n` (newline), `\r` (carriage return), `\t` (tab).
- Multi-line values (Memo text, ListBox items) use `\n` within a single
quoted string.
## Transport Layer
The protocol is transport-agnostic. Messages are delivered via:
```
int ReadMessage(char *buf, int maxLen); // returns bytes read, 0 = none
void WriteMessage(const char *buf); // sends complete message
```
Current transport: newline-delimited serial (messages terminated by CR+LF).
The transport handles framing; protocol layer never sees delimiters.