239 lines
12 KiB
Markdown
239 lines
12 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), or `<itemIndex>` (RadioGroup) |
|
|
| DblClick | (none) |
|
|
| Change | `"new text"`, `<position>` (ScrollBar), or `<index>` (TabSet, TabbedNotebook) |
|
|
| 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) |
|
|
| Notify | (none) |
|
|
| SelectCell| `<col> <row>` |
|
|
| SetEditText| `<col> <row> "text"` |
|
|
|
|
## 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 |
|
|
| Image | TImage | (none) |
|
|
| GroupBox | TGroupBox | (none) |
|
|
| RadioButton | TRadioButton | Click |
|
|
| Panel | TPanel | (none) |
|
|
| ScrollBar | TScrollBar | Change |
|
|
| MediaPlayer | TMediaPlayer | (none) |
|
|
| MainMenu | TMainMenu | (none) |
|
|
| PopupMenu | TPopupMenu | (none) |
|
|
| MenuItem | TMenuItem | Click |
|
|
| RadioGroup | TRadioGroup | Click |
|
|
| BitBtn | TBitBtn | Click |
|
|
| SpeedButton | TSpeedButton | Click |
|
|
| TabSet | TTabSet | Change |
|
|
| Notebook | TNotebook | (none) |
|
|
| TabbedNotebook | TTabbedNotebook | Change |
|
|
| MaskEdit | TMaskEdit | Change |
|
|
| Outline | TOutline | (none) |
|
|
| Bevel | TBevel | (none) |
|
|
| Header | THeader | (none) |
|
|
| ScrollBox | TScrollBox | (none) |
|
|
| StringGrid | TStringGrid | SelectCell |
|
|
|
|
MainMenu and PopupMenu use `0 0 0 0` geometry (non-visual). MenuItem
|
|
uses `0 0 0 0` geometry and requires a `Parent` property to specify its
|
|
parent menu or menu item. One MainMenu per form (auto-attached).
|
|
PopupMenu is associated with any control via the `PopupMenu` property.
|
|
|
|
GroupBox and Panel are cosmetic containers (flat parent model — no child
|
|
containment in the protocol). RadioButtons are all in one group per form.
|
|
|
|
Opt-in events (require EVENT.BIND): Click (Image, GroupBox, Panel),
|
|
Notify (MediaPlayer), SetEditText (StringGrid), DblClick, KeyDown,
|
|
KeyUp, Enter, Exit, MouseDown, MouseUp, MouseMove. Menu and
|
|
RadioGroup components do not support opt-in events.
|
|
|
|
## Properties
|
|
|
|
| Property | Applies To | Value Format |
|
|
|-------------|---------------------------------------------|-------------------------------------------|
|
|
| Caption | Label, Button, CheckBox, GroupBox, RadioButton, Panel, MenuItem, RadioGroup, BitBtn, SpeedButton | Quoted string |
|
|
| Text | Edit, ComboBox, Memo, MaskEdit | Quoted string (`\n` for line breaks) |
|
|
| Items | ListBox, ComboBox, RadioGroup, TabSet, Notebook, TabbedNotebook, Outline, Header | Quoted string (`\n`-delimited) |
|
|
| Checked | CheckBox, RadioButton, MenuItem | 0 or 1 |
|
|
| Enabled | All | 0 or 1 |
|
|
| Visible | All | 0 or 1 |
|
|
| MaxLength | Edit, MaskEdit | Integer |
|
|
| ReadOnly | Edit, Memo | 0 or 1 |
|
|
| ScrollBars | Memo | 0-3 (ssNone..ssBoth) |
|
|
| ItemIndex | ListBox, ComboBox, RadioGroup, TabSet, Notebook, TabbedNotebook | Integer (-1 = none) |
|
|
| TabOrder | All windowed controls | Integer |
|
|
| Stretch | Image | 0 or 1 |
|
|
| Center | Image | 0 or 1 |
|
|
| Transparent | Image | 0 or 1 |
|
|
| Picture | Image | Quoted string (filename, BMP only) |
|
|
| BevelOuter | Panel | 0-2 (bvNone, bvLowered, bvRaised) |
|
|
| BevelInner | Panel | 0-2 (bvNone, bvLowered, bvRaised) |
|
|
| BorderStyle | Panel | 0-1 (bsNone, bsSingle) |
|
|
| Kind | ScrollBar, BitBtn | Integer (see below) |
|
|
| Min | ScrollBar | Integer |
|
|
| Max | ScrollBar | Integer |
|
|
| Position | ScrollBar | Integer |
|
|
| LargeChange | ScrollBar | Integer |
|
|
| SmallChange | ScrollBar | Integer |
|
|
| FileName | MediaPlayer | Quoted string (media file path) |
|
|
| DeviceType | MediaPlayer | Quoted string (e.g., `dtWaveAudio`) |
|
|
| AutoOpen | MediaPlayer | 0 or 1 |
|
|
| Command | MediaPlayer | Quoted string (pseudo-property, see below)|
|
|
| Parent | MenuItem | Integer (ctrlId of parent menu/item) |
|
|
| Columns | RadioGroup | Integer (number of columns) |
|
|
| ShortCut | MenuItem | Integer (Delphi ShortCut value) |
|
|
| PopupMenu | Any TControl | Integer (ctrlId of PopupMenu) |
|
|
| Layout | BitBtn, SpeedButton | 0-3 (blGlyphLeft..blGlyphBottom) |
|
|
| NumGlyphs | BitBtn, SpeedButton | Integer (1-4) |
|
|
| GroupIndex | SpeedButton | Integer (0 = no group) |
|
|
| Down | SpeedButton | 0 or 1 |
|
|
| AllowAllUp | SpeedButton | 0 or 1 |
|
|
| EditMask | MaskEdit | Quoted string |
|
|
| OutlineStyle| Outline | 0-6 (osText..osTreePictureText) |
|
|
| Shape | Bevel | 0-5 (bsBox..bsRightLine) |
|
|
| Style | Bevel | 0-1 (bsLowered, bsRaised) |
|
|
| ColCount | StringGrid | Integer (default 5) |
|
|
| RowCount | StringGrid | Integer (default 5) |
|
|
| FixedCols | StringGrid | Integer (default 1) |
|
|
| FixedRows | StringGrid | Integer (default 1) |
|
|
| DefaultColWidth | StringGrid | Integer (pixels) |
|
|
| DefaultRowHeight| StringGrid | Integer (pixels) |
|
|
| Options | StringGrid | Integer (bitmask, see below) |
|
|
| Cells | StringGrid | Quoted string (tab-delimited cols, `\n`-delimited rows) |
|
|
| Cell | StringGrid | Quoted string (`col,row,value`) |
|
|
|
|
File path properties (Picture, FileName) are resolved relative to the
|
|
client's `BasePath` setting. Subdirectories are allowed (e.g.,
|
|
`Picture="images\logo.bmp"` with `BasePath=C:\MYAPP` resolves to
|
|
`C:\MYAPP\images\logo.bmp`).
|
|
|
|
Command is a pseudo-property that triggers a method call on the
|
|
MediaPlayer rather than setting a value. Valid commands: `Open`,
|
|
`Play`, `Stop`, `Close`, `Pause`, `Resume`, `Rewind`, `Next`,
|
|
`Previous`.
|
|
|
|
StringGrid Options is an integer bitmask of TGridOption values:
|
|
|
|
| Bit | Value | Option |
|
|
|--------|--------|---------------------|
|
|
| 0 | 0x0001 | goFixedVertLine |
|
|
| 1 | 0x0002 | goFixedHorzLine |
|
|
| 2 | 0x0004 | goVertLine |
|
|
| 3 | 0x0008 | goHorzLine |
|
|
| 4 | 0x0010 | goRangeSelect |
|
|
| 5 | 0x0020 | goDrawFocusSelected |
|
|
| 6 | 0x0040 | goRowSizing |
|
|
| 7 | 0x0080 | goColSizing |
|
|
| 8 | 0x0100 | goRowMoving |
|
|
| 9 | 0x0200 | goColMoving |
|
|
| 10 | 0x0400 | goEditing |
|
|
| 11 | 0x0800 | goTabs |
|
|
| 12 | 0x1000 | goThumbTracking |
|
|
|
|
Cells is a bulk-load property: columns are tab-delimited, rows are
|
|
`\n`-delimited. Cell is an individual update: `"col,row,value"`.
|
|
|
|
## 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.
|