Tachibana
Langue : français

Groupe 36 — Gestionnaire de contrôles Trinity

36,1 New Control · 36,2 Dispose Control · 36,3 Draw Controls · 36,4 Draw Control · 36,5 Set Control Value · 36,6 Get Control Value · 36,7 Set Control Flags · 36,8 Find Control · 36,9 Track Control · 36,10 Key Control

Le gestionnaire de contrôles de la boîte à outils de Trinity place dans les fenêtres (groupe 34) des boutons, cases à cocher, boutons radio, barres de défilement et champs de texte : 24 au plus.

Les exemples ouvrent une fenêtre de cadre 20, 20, 220, 140 (contenu de (21, 31) à (219, 139)) et y posent leurs contrôles : un Rect de contrôle est relatif au contenu, si bien que le bouton posé en (10, 10) est en (31, 41) à l'écran. La souris est simulée par des appels à 36,9 aux coordonnées voulues. La boîte à outils est remise à zéro avec 32,19 au début et à la fin.

36,1 New Control Trinity

Crée un contrôle dans une fenêtre et le dessine aussitôt.

Entrées
OctetsTypeRôle
P0uint8type : 1 bouton, 2 case à cocher, 3 bouton radio, 4 barre de défilement, 5 champ de texte
P1uint8fenêtre
P2-P3addradresse du Rect, relatif au contenu de la fenêtre
P4-P5addradresse du titre précédé de sa longueur, ou du tampon d'un champ de texte (lus sur place)
P6-P7uint16maximum d'une barre de défilement, ou longueur maximale d'un champ de texte
Sorties
OctetsTypeRôle
P0uint8numéro du contrôle (1 à 24)
erreuruint81 paramètres invalides, 2 plus de contrôle libre

Une barre de défilement est verticale quand elle est plus haute que large. Les boutons radio ne sont pas groupés : c'est au programme de décocher les autres. Au traitement de l'événement de mise à jour d'une fenêtre, 36,3 redessine tous ses contrôles. Au banc, le 25e contrôle est refusé (erreur 2). NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Toolbox (Trinity, T-12, ADR-01 of the fork). Creates a control of kind Parameter:0 (1 button, 2 check box, 3 radio button, 4 scroll bar - vertical when higher than wide -, 5 text field) in window Parameter:1, with the Rect at Parameters:2,3 relative to the content of the window, the length-prefixed title (or, for a text field, the text buffer) at Parameters:4,5 read in place, and Parameters:6,7 = maximum value of a scroll bar or maximum length of a text field ; returns the control number (1-24) in Parameter:0 (error 1 bad parameters, 2 none left). The control is drawn at once ; redraw all the controls of a window with Draw Controls when handling its update event. Radio buttons are not grouped : the program clears the others.

C (llvm-mos)
/* Créer un contrôle (groupe 36, fonction 1, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;

/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A";             /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
    libre();
    api(32, 19);
}
static void ouvrir(void) {                      /* 34,1 : une fenêtre avec barre de titre */
    reinit();
    libre();
    p16(0, (uint16_t)&cadre);
    p16(2, (uint16_t)titre);
    ControlPort.params[4] = 1;
    api(34, 1);
    fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
   au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
    libre();
    ControlPort.params[0] = type;
    ControlPort.params[1] = fenetre;
    p16(2, (uint16_t)r);
    p16(4, (uint16_t)t);
    p16(6, max);
    api(36, 1);
    return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) {             /* 36,6 Get Control Value */
    libre();
    ControlPort.params[0] = c;
    api(36, 6);
    return ControlPort.params[1] | ControlPort.params[2] << 8;
}

static Rect rb = {10, 10, 70, 24}, rc = {10, 30, 110, 42}, rs = {180, 0, 192, 100};
static const char ok[] = "\002OK", option[] = "\006Option";

int main(void) {
    uint8_t b, c, s, e;
    ouvrir();
    b = controle(1, &rb, ok, 0);                /* bouton */
    c = controle(2, &rc, option, 0);            /* case à cocher */
    s = controle(4, &rs, titre, 50);            /* barre de défilement verticale (plus haute que large), maximum 50 */
    controle(6, &rb, ok, 0);                    /* type inconnu : refusé */
    e = ControlPort.error;
    reinit();
    printf("Bouton %u, case %u, barre %u ; type 6 : erreur %u\n", b, c, s, e);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Bouton 1, case 2, barre 3 ; type 6 : erreur 1
Mad Pascal
// Créer un contrôle (groupe 36, fonction 1, Trinity).
program ct1;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)

// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A'));   // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
    fenetre: byte;

procedure poser(var r: Rect; g, h, d, b: smallint);
begin
  r.g := g; r.h := h; r.d := d; r.b := b;
end;

procedure appel(g, f: byte);                    // appel g,f (paramètres déjà posés)
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
  NeoWaitMessage;
  appel(32, 19);
end;

procedure ouvrir;                               // 34,1 : une fenêtre avec barre de titre
begin
  reinit;
  poser(cadre, 20, 20, 220, 140);
  wordParams[0] := word(@cadre);
  wordParams[1] := word(@titre);
  NeoMessage.params[4] := 1;
  appel(34, 1);
  fenetre := NeoMessage.params[5];
end;

// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := t;
  NeoMessage.params[1] := fenetre;
  wordParams[1] := word(r);
  wordParams[2] := word(s);
  wordParams[3] := max;
  appel(36, 1);
  result := NeoMessage.params[0];
end;

function valeur(c: byte): word;                 // 36,6 Get Control Value
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  appel(36, 6);
  result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

const ok: array[0..2] of byte = (2, ord('O'), ord('K'));
      option: array[0..6] of byte = (6, ord('O'), ord('p'), ord('t'), ord('i'), ord('o'), ord('n'));
var rb, rc, rs: Rect;
    b, c, s, e: byte;
begin
  poser(rb, 10, 10, 70, 24); poser(rc, 10, 30, 110, 42); poser(rs, 180, 0, 192, 100);
  ouvrir;
  b := controle(1, @rb, @ok, 0);                // bouton
  c := controle(2, @rc, @option, 0);            // case à cocher
  s := controle(4, @rs, @titre, 50);            // barre de défilement verticale (plus haute que large), maximum 50
  controle(6, @rb, @ok, 0);                     // type inconnu : refusé
  e := NeoMessage.error;
  reinit;
  writeln('Bouton ', b, ', case ', c, ', barre ', s, ' ; type 6 : erreur ', e);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Bouton 1, case 2, barre 3 ; type 6 : erreur 1
NeoBASIC
10 ' Creer un controle (groupe 36, fonction 1, Trinity)
20 gosub 7000
30 g = 10 : h = 10 : d = 70 : b = 24 : gosub 8000 : rb = q : s$ = "OK" : gosub 7900 : ok = ch
40 ty = 1 : mx = 0 : gosub 7100 : bt = cn : ' bouton
50 g = 10 : h = 30 : d = 110 : b = 42 : gosub 8000 : s$ = "Option" : gosub 7900
60 ty = 2 : gosub 7100 : ca = cn : ' case a cocher
70 g = 180 : h = 0 : d = 192 : b = 100 : gosub 8000 : ch = tf
80 ty = 4 : mx = 50 : gosub 7100 : ba = cn : ' barre de defilement verticale (plus haute que large), maximum 50
90 q = rb : ch = ok : ty = 6 : mx = 0 : gosub 7100 : e6 = e : ' type inconnu : refuse
100 gosub 8300
110 print "Bouton ";bt;", case ";ca;", barre ";ba;" ; type 6 : erreur ";e6
120 end
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Bouton 1, case 2, barre 3 ; type 6 : erreur 1
Assembleur 65C02 (64tass)
; Créer un contrôle (groupe 36, fonction 1, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr ouvrir
        lda #<cb
        ldx #>cb
        jsr controle
        sta b
        lda #<cc
        ldx #>cc
        jsr controle
        sta c
        lda #<cs
        ldx #>cs
        jsr controle
        sta s
        lda #<c6
        ldx #>c6
        jsr controle
        lda ControlPort+2
        sta e
        lda #<b0
        ldx #>b0
        jsr envoi
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda b
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda c
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda s
        jsr decimal
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda e
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

rb:     .word 10, 10, 70, 24
rc:     .word 10, 30, 110, 42
rs:     .word 180, 0, 192, 100
ok:     .byte 2
        .text "OK"
option: .byte 6
        .text "Option"
cb:     .byte 1                  ; bouton
        .word rb, ok, 0
b:      .byte 0
cc:     .byte 2                  ; case à cocher
        .word rc, option, 0
c:      .byte 0
cs:     .byte 4                  ; barre verticale (plus haute que large), maximum 50
        .word rs, titre, 50
s:      .byte 0
c6:     .byte 6                  ; type inconnu : refusé
        .word rb, ok, 0
e:      .byte 0
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset
t1:     .text "Bouton ", 0
t2:     .text ", case ", 0
t3:     .text ", barre ", 0
t4:     .text " ; type 6 : erreur ", 0

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
        ldx #>raz
        jsr envoi
        lda #<nfen
        ldx #>nfen
        jsr envoi
        lda ControlPort+9
        sta fen
        rts
raz:    .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen:   .byte 34, 1, 5
        .word cadre, titre
        .byte 1
cadre:  .word 20, 20, 220, 140
titre:  .byte 1
        .text "A"                  ; chaînes précédées de leur longueur, lues sur place
fen:    .byte 0

; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
        sta blk
        stx blk+1
        jsr WaitMessage
        ldy #0
        lda (blk),y
        sta ControlPort+4          ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
        lda fen
        sta ControlPort+5          ; P1 : fenêtre
        ldy #1
_ctl:   lda (blk),y
        sta ControlPort+5,y        ; P2-P7 : Rect, titre, maximum
        iny
        cpy #7
        bne _ctl
        lda #36
        ldx #1
        jsr appel
        lda ControlPort+4
        rts

; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        lda #36
        ldx #6
        jsr appel
        lda ControlPort+5
        rts

; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        ldx #4
_sv:    lda pt,x
        sta ControlPort+5,x        ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
        dex
        bpl _sv
        lda #36
        ldx #9
        jsr appel
        lda ControlPort+10
        rts
pt:     .word 0, 0
        .byte 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Bouton 1, case 2, barre 3 ; type 6 : erreur 1

36,2 Dispose Control Trinity

Efface un contrôle et libère son numéro.

Entrées
OctetsTypeRôle
P0uint8numéro du contrôle

Sorties : aucune.

Fermer une fenêtre libère aussi ses contrôles. Le numéro libéré est repris par le contrôle suivant. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Erases and frees control Parameter:0. Disposing a window frees its controls.

C (llvm-mos)
/* Supprimer un contrôle (groupe 36, fonction 2, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;

/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A";             /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
    libre();
    api(32, 19);
}
static void ouvrir(void) {                      /* 34,1 : une fenêtre avec barre de titre */
    reinit();
    libre();
    p16(0, (uint16_t)&cadre);
    p16(2, (uint16_t)titre);
    ControlPort.params[4] = 1;
    api(34, 1);
    fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
   au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
    libre();
    ControlPort.params[0] = type;
    ControlPort.params[1] = fenetre;
    p16(2, (uint16_t)r);
    p16(4, (uint16_t)t);
    p16(6, max);
    api(36, 1);
    return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) {             /* 36,6 Get Control Value */
    libre();
    ControlPort.params[0] = c;
    api(36, 6);
    return ControlPort.params[1] | ControlPort.params[2] << 8;
}

static Rect rb = {10, 10, 70, 24}, rc = {10, 30, 110, 42};
static const char ok[] = "\002OK", option[] = "\006Option";

int main(void) {
    uint8_t b, t, n;
    ouvrir();
    b = controle(1, &rb, ok, 0);
    controle(2, &rc, option, 0);
    libre(); ControlPort.params[0] = b; api(36, 2);   /* Dispose Control : effacé, numéro libéré */
    libre(); p16(0, 40); p16(2, 45); api(36, 8);      /* 36,8 : plus rien à la place du bouton */
    t = ControlPort.params[4];
    n = controle(1, &rb, ok, 0);
    reinit();
    printf("Apres suppression : en (40, 45) : %u, nouveau : %u\n", t, n);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Apres suppression : en (40, 45) : 0, nouveau : 1
Mad Pascal
// Supprimer un contrôle (groupe 36, fonction 2, Trinity).
program ct2;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)

// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A'));   // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
    fenetre: byte;

procedure poser(var r: Rect; g, h, d, b: smallint);
begin
  r.g := g; r.h := h; r.d := d; r.b := b;
end;

procedure appel(g, f: byte);                    // appel g,f (paramètres déjà posés)
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
  NeoWaitMessage;
  appel(32, 19);
end;

procedure ouvrir;                               // 34,1 : une fenêtre avec barre de titre
begin
  reinit;
  poser(cadre, 20, 20, 220, 140);
  wordParams[0] := word(@cadre);
  wordParams[1] := word(@titre);
  NeoMessage.params[4] := 1;
  appel(34, 1);
  fenetre := NeoMessage.params[5];
end;

// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := t;
  NeoMessage.params[1] := fenetre;
  wordParams[1] := word(r);
  wordParams[2] := word(s);
  wordParams[3] := max;
  appel(36, 1);
  result := NeoMessage.params[0];
end;

function valeur(c: byte): word;                 // 36,6 Get Control Value
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  appel(36, 6);
  result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

const ok: array[0..2] of byte = (2, ord('O'), ord('K'));
      option: array[0..6] of byte = (6, ord('O'), ord('p'), ord('t'), ord('i'), ord('o'), ord('n'));
var rb, rc: Rect;
    b, t, n: byte;
begin
  poser(rb, 10, 10, 70, 24); poser(rc, 10, 30, 110, 42);
  ouvrir;
  b := controle(1, @rb, @ok, 0);
  controle(2, @rc, @option, 0);
  NeoWaitMessage; NeoMessage.params[0] := b; appel(36, 2);   // Dispose Control : effacé, numéro libéré
  wordParams[0] := 40; wordParams[1] := 45; appel(36, 8);   // 36,8 : plus rien à la place du bouton
  t := NeoMessage.params[4];
  n := controle(1, @rb, @ok, 0);
  reinit;
  writeln('Apres suppression : en (40, 45) : ', t, ', nouveau : ', n);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Apres suppression : en (40, 45) : 0, nouveau : 1
NeoBASIC
10 ' Supprimer un controle (groupe 36, fonction 2, Trinity)
20 gosub 7000
30 g = 10 : h = 10 : d = 70 : b = 24 : gosub 8000 : rb = q : s$ = "OK" : gosub 7900 : ok = ch
40 ty = 1 : mx = 0 : gosub 7100 : bt = cn
50 g = 10 : h = 30 : d = 110 : b = 42 : gosub 8000 : s$ = "Option" : gosub 7900 : ty = 2 : gosub 7100
60 while peek($ff00) : wend : poke $ff04, bt : f = 2 : gosub 8110 : ' Dispose Control : efface, numero libere
70 while peek($ff00) : wend : doke $ff04, 40 : doke $ff06, 45 : f = 8 : gosub 8110 : t = peek($ff08) : ' 36,8 : plus rien
80 q = rb : ch = ok : ty = 1 : gosub 7100 : n = cn
90 gosub 8300
100 print "Apres suppression : en (40, 45) : ";t;", nouveau : ";n
110 end
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Apres suppression : en (40, 45) : 0, nouveau : 1
Assembleur 65C02 (64tass)
; Supprimer un contrôle (groupe 36, fonction 2, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr ouvrir
        lda #<cb
        ldx #>cb
        jsr controle
        sta b
        lda #<cc
        ldx #>cc
        jsr controle
        jsr WaitMessage
        lda b
        sta ControlPort+4
        lda #36
        ldx #2                  ; Dispose Control : effacé, numéro libéré
        jsr appel
        lda #<b0
        ldx #>b0
        jsr envoi
        lda ControlPort+8
        sta t
        lda #<cb
        ldx #>cb
        jsr controle
        sta n
        lda #<b1
        ldx #>b1
        jsr envoi
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda t
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda n
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

rb:     .word 10, 10, 70, 24
rc:     .word 10, 30, 110, 42
ok:     .byte 2
        .text "OK"
option: .byte 6
        .text "Option"
cb:     .byte 1                  ; bouton
        .word rb, ok, 0
b:      .byte 0
cc:     .byte 2                  ; case à cocher
        .word rc, option, 0
b0:     .byte 36, 8, 4             ; 36,8 : plus rien à la place du bouton
        .word 40, 45
t:      .byte 0
n:      .byte 0
b1:     .byte 32, 19, 0            ; 32,19 Toolbox Reset
t2:     .text "Apres suppression : en (40, 45) : ", 0
t3:     .text ", nouveau : ", 0

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
        ldx #>raz
        jsr envoi
        lda #<nfen
        ldx #>nfen
        jsr envoi
        lda ControlPort+9
        sta fen
        rts
raz:    .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen:   .byte 34, 1, 5
        .word cadre, titre
        .byte 1
cadre:  .word 20, 20, 220, 140
titre:  .byte 1
        .text "A"                  ; chaînes précédées de leur longueur, lues sur place
fen:    .byte 0

; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
        sta blk
        stx blk+1
        jsr WaitMessage
        ldy #0
        lda (blk),y
        sta ControlPort+4          ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
        lda fen
        sta ControlPort+5          ; P1 : fenêtre
        ldy #1
_ctl:   lda (blk),y
        sta ControlPort+5,y        ; P2-P7 : Rect, titre, maximum
        iny
        cpy #7
        bne _ctl
        lda #36
        ldx #1
        jsr appel
        lda ControlPort+4
        rts

; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        lda #36
        ldx #6
        jsr appel
        lda ControlPort+5
        rts

; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        ldx #4
_sv:    lda pt,x
        sta ControlPort+5,x        ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
        dex
        bpl _sv
        lda #36
        ldx #9
        jsr appel
        lda ControlPort+10
        rts
pt:     .word 0, 0
        .byte 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Apres suppression : en (40, 45) : 0, nouveau : 1

36,3 Draw Controls Trinity

Dessine tous les contrôles d'une fenêtre.

Entrées
OctetsTypeRôle
P0uint8fenêtre

Sorties : aucune.

À appeler après 34,12 dans le traitement de la mise à jour. L'exemple peint le contenu en couleur 4 : les cadres des deux boutons (blancs, 15) reviennent. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Draws every control of window Parameter:0 (to call after Set Port in the update handler).

C (llvm-mos)
/* Redessiner les contrôles d'une fenêtre (groupe 36, fonction 3, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;

/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A";             /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
    libre();
    api(32, 19);
}
static void ouvrir(void) {                      /* 34,1 : une fenêtre avec barre de titre */
    reinit();
    libre();
    p16(0, (uint16_t)&cadre);
    p16(2, (uint16_t)titre);
    ControlPort.params[4] = 1;
    api(34, 1);
    fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
   au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
    libre();
    ControlPort.params[0] = type;
    ControlPort.params[1] = fenetre;
    p16(2, (uint16_t)r);
    p16(4, (uint16_t)t);
    p16(6, max);
    api(36, 1);
    return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) {             /* 36,6 Get Control Value */
    libre();
    ControlPort.params[0] = c;
    api(36, 6);
    return ControlPort.params[1] | ControlPort.params[2] << 8;
}

static uint8_t pixel(int16_t x, int16_t y) {   /* 5,33 : couleur du fond en (x, y) */
    libre();
    p16(0, x);
    p16(2, y);
    api(5, 33);
    return ControlPort.params[0];
}
static Rect ecran = {0, 0, 320, 240};
static void barbouiller(void) {                 /* le programme peint tout le contenu en couleur 4 */
    libre(); ControlPort.params[0] = fenetre; api(34, 12);   /* 34,12 Set Port */
    libre(); ControlPort.params[0] = 4; api(32, 4);
    libre(); p16(0, (uint16_t)&ecran); api(32, 8);
}

static Rect r1 = {10, 10, 70, 24}, r2 = {80, 10, 140, 24};
static const char ok[] = "\002OK", non[] = "\003Non";

int main(void) {
    uint8_t a1, a2, b1, b2;
    putchar(12);                                /* écran effacé : on relit des pixels */
    ouvrir();
    controle(1, &r1, ok, 0);                    /* deux boutons, cadres en (31, 41) et (101, 41) */
    controle(1, &r2, non, 0);
    barbouiller();
    a1 = pixel(31, 41); a2 = pixel(101, 41);
    libre(); ControlPort.params[0] = fenetre; api(36, 3);   /* Draw Controls */
    b1 = pixel(31, 41); b2 = pixel(101, 41);
    reinit();
    printf("Cadres peints : %u %u, redessines : %u %u\n", a1, a2, b1, b2);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Cadres peints : 4 4, redessines : 15 15
Mad Pascal
// Redessiner les contrôles d'une fenêtre (groupe 36, fonction 3, Trinity).
program ct3;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)

// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A'));   // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
    fenetre: byte;

procedure poser(var r: Rect; g, h, d, b: smallint);
begin
  r.g := g; r.h := h; r.d := d; r.b := b;
end;

procedure appel(g, f: byte);                    // appel g,f (paramètres déjà posés)
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
  NeoWaitMessage;
  appel(32, 19);
end;

procedure ouvrir;                               // 34,1 : une fenêtre avec barre de titre
begin
  reinit;
  poser(cadre, 20, 20, 220, 140);
  wordParams[0] := word(@cadre);
  wordParams[1] := word(@titre);
  NeoMessage.params[4] := 1;
  appel(34, 1);
  fenetre := NeoMessage.params[5];
end;

// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := t;
  NeoMessage.params[1] := fenetre;
  wordParams[1] := word(r);
  wordParams[2] := word(s);
  wordParams[3] := max;
  appel(36, 1);
  result := NeoMessage.params[0];
end;

function valeur(c: byte): word;                 // 36,6 Get Control Value
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  appel(36, 6);
  result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

var ecran: Rect;

procedure barbouiller;                          // le programme peint tout le contenu en couleur 4
begin
  poser(ecran, 0, 0, 320, 240);
  NeoWaitMessage; NeoMessage.params[0] := fenetre; appel(34, 12);   // 34,12 Set Port
  NeoMessage.params[0] := 4; appel(32, 4);
  wordParams[0] := word(@ecran); appel(32, 8);
end;

const ok: array[0..2] of byte = (2, ord('O'), ord('K'));
      non: array[0..3] of byte = (3, ord('N'), ord('o'), ord('n'));
var r1, r2: Rect;
    a1, a2, b1, b2: byte;
begin
  write(chr(12));                               // écran effacé : on relit des pixels
  poser(r1, 10, 10, 70, 24); poser(r2, 80, 10, 140, 24);
  ouvrir;
  controle(1, @r1, @ok, 0);                     // deux boutons, cadres en (31, 41) et (101, 41)
  controle(1, @r2, @non, 0);
  barbouiller;
  a1 := NeoGetPixel(31, 41); a2 := NeoGetPixel(101, 41);
  NeoWaitMessage; NeoMessage.params[0] := fenetre; appel(36, 3);   // Draw Controls
  b1 := NeoGetPixel(31, 41); b2 := NeoGetPixel(101, 41);
  reinit;
  writeln('Cadres peints : ', a1, ' ', a2, ', redessines : ', b1, ' ', b2);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Cadres peints : 4 4, redessines : 15 15
NeoBASIC
10 ' Redessiner les controles d'une fenetre (groupe 36, fonction 3, Trinity)
20 cls : ' ecran efface : on relit des pixels
30 gosub 7000
40 g = 10 : h = 10 : d = 70 : b = 24 : gosub 8000 : s$ = "OK" : gosub 7900 : ty = 1 : mx = 0 : gosub 7100
50 g = 80 : d = 140 : gosub 8000 : s$ = "Non" : gosub 7900 : gosub 7100 : ' cadres en (31, 41) et (101, 41)
60 gosub 2000
70 a1 = point(31, 41) : a2 = point(101, 41)
80 while peek($ff00) : wend : poke $ff04, fw : f = 3 : gosub 8110 : ' Draw Controls
90 b1 = point(31, 41) : b2 = point(101, 41)
100 gosub 8300
110 print "Cadres peints : ";a1;" ";a2;", redessines : ";b1;" ";b2
120 end
2000 ' le programme peint tout le contenu en couleur 4
2010 ec = alloc(8) : doke ec, 0 : doke ec + 2, 0 : doke ec + 4, 320 : doke ec + 6, 240
2020 while peek($ff00) : wend : poke $ff04, fw : poke $ff01, 12 : poke $ff00, 34 : ' 34,12 Set Port
2030 while peek($ff00) : wend : poke $ff04, 4 : poke $ff01, 4 : poke $ff00, 32
2040 while peek($ff00) : wend : doke $ff04, ec : poke $ff01, 8 : poke $ff00, 32
2050 while peek($ff00) : wend : return
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Cadres peints : 4 4, redessines : 15 15
Assembleur 65C02 (64tass)
; Redessiner les contrôles d'une fenêtre (groupe 36, fonction 3, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #12                    ; écran effacé : on relit des pixels
        jsr WriteCharacter
        jsr ouvrir
        lda #<c1
        ldx #>c1
        jsr controle
        lda #<c2
        ldx #>c2
        jsr controle
        jsr barbouiller
        lda #31
        ldy #41
        jsr pixel
        sta a1
        lda #101
        ldy #41
        jsr pixel
        sta a2
        jsr WaitMessage
        lda fen
        sta ControlPort+4
        lda #36
        ldx #3                     ; Draw Controls
        jsr appel
        lda #31
        ldy #41
        jsr pixel
        sta b1
        lda #101
        ldy #41
        jsr pixel
        sta b2
        lda #<b0
        ldx #>b0
        jsr envoi
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda a1
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda a2
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda b1
        jsr decimal
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda b2
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel:  pha
        jsr WaitMessage
        pla
        sta ControlPort+4          ; P0-P1 : X
        stz ControlPort+5
        sty ControlPort+6          ; P2-P3 : Y
        stz ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

r1:     .word 10, 10, 70, 24
r2:     .word 80, 10, 140, 24
ok:     .byte 2
        .text "OK"
non:    .byte 3
        .text "Non"
c1:     .byte 1                  ; deux boutons, cadres en (31, 41)...
        .word r1, ok, 0
c2:     .byte 1                  ; ... et (101, 41)
        .word r2, non, 0
a1:     .byte 0
a2:     .byte 0
b1:     .byte 0
b2:     .byte 0
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset
t1:     .text "Cadres peints : ", 0
t2:     .text " ", 0
t3:     .text ", redessines : ", 0
t4:     .text " ", 0

; Le programme peint tout le contenu en couleur 4.
barbouiller:
        jsr WaitMessage
        lda fen
        sta ControlPort+4
        lda #34
        ldx #12                    ; 34,12 Set Port
        jsr appel
        lda #<coul
        ldx #>coul
        jsr envoi
        lda #<peint
        ldx #>peint
        jsr envoi
        rts
coul:   .byte 32, 4, 1, 4
peint:  .byte 32, 8, 2
        .word ecran
ecran:  .word 0, 0, 320, 240

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
        ldx #>raz
        jsr envoi
        lda #<nfen
        ldx #>nfen
        jsr envoi
        lda ControlPort+9
        sta fen
        rts
raz:    .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen:   .byte 34, 1, 5
        .word cadre, titre
        .byte 1
cadre:  .word 20, 20, 220, 140
titre:  .byte 1
        .text "A"                  ; chaînes précédées de leur longueur, lues sur place
fen:    .byte 0

; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
        sta blk
        stx blk+1
        jsr WaitMessage
        ldy #0
        lda (blk),y
        sta ControlPort+4          ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
        lda fen
        sta ControlPort+5          ; P1 : fenêtre
        ldy #1
_ctl:   lda (blk),y
        sta ControlPort+5,y        ; P2-P7 : Rect, titre, maximum
        iny
        cpy #7
        bne _ctl
        lda #36
        ldx #1
        jsr appel
        lda ControlPort+4
        rts

; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        lda #36
        ldx #6
        jsr appel
        lda ControlPort+5
        rts

; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        ldx #4
_sv:    lda pt,x
        sta ControlPort+5,x        ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
        dex
        bpl _sv
        lda #36
        ldx #9
        jsr appel
        lda ControlPort+10
        rts
pt:     .word 0, 0
        .byte 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Cadres peints : 4 4, redessines : 15 15

36,4 Draw Control Trinity

Redessine un contrôle.

Entrées
OctetsTypeRôle
P0uint8numéro du contrôle

Sorties : aucune.

Le bouton est redessiné en entier : cadre blanc (15), intérieur noir (0). NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Redraws control Parameter:0.

C (llvm-mos)
/* Redessiner un contrôle (groupe 36, fonction 4, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;

/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A";             /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
    libre();
    api(32, 19);
}
static void ouvrir(void) {                      /* 34,1 : une fenêtre avec barre de titre */
    reinit();
    libre();
    p16(0, (uint16_t)&cadre);
    p16(2, (uint16_t)titre);
    ControlPort.params[4] = 1;
    api(34, 1);
    fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
   au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
    libre();
    ControlPort.params[0] = type;
    ControlPort.params[1] = fenetre;
    p16(2, (uint16_t)r);
    p16(4, (uint16_t)t);
    p16(6, max);
    api(36, 1);
    return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) {             /* 36,6 Get Control Value */
    libre();
    ControlPort.params[0] = c;
    api(36, 6);
    return ControlPort.params[1] | ControlPort.params[2] << 8;
}

static uint8_t pixel(int16_t x, int16_t y) {   /* 5,33 : couleur du fond en (x, y) */
    libre();
    p16(0, x);
    p16(2, y);
    api(5, 33);
    return ControlPort.params[0];
}
static Rect ecran = {0, 0, 320, 240};
static void barbouiller(void) {                 /* le programme peint tout le contenu en couleur 4 */
    libre(); ControlPort.params[0] = fenetre; api(34, 12);   /* 34,12 Set Port */
    libre(); ControlPort.params[0] = 4; api(32, 4);
    libre(); p16(0, (uint16_t)&ecran); api(32, 8);
}

static Rect rb = {10, 10, 70, 24};
static const char ok[] = "\002OK";

int main(void) {
    uint8_t b, c1, i1, c2, i2;
    putchar(12);
    ouvrir();
    b = controle(1, &rb, ok, 0);
    barbouiller();
    c1 = pixel(31, 41); i1 = pixel(35, 43);     /* cadre et intérieur du bouton */
    libre(); ControlPort.params[0] = b; api(36, 4);   /* Draw Control */
    c2 = pixel(31, 41); i2 = pixel(35, 43);
    reinit();
    printf("Peint : %u, %u ; redessine : cadre %u, dedans %u\n", c1, i1, c2, i2);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Peint : 4, 4 ; redessine : cadre 15, dedans 0
Mad Pascal
// Redessiner un contrôle (groupe 36, fonction 4, Trinity).
program ct4;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)

// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A'));   // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
    fenetre: byte;

procedure poser(var r: Rect; g, h, d, b: smallint);
begin
  r.g := g; r.h := h; r.d := d; r.b := b;
end;

procedure appel(g, f: byte);                    // appel g,f (paramètres déjà posés)
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
  NeoWaitMessage;
  appel(32, 19);
end;

procedure ouvrir;                               // 34,1 : une fenêtre avec barre de titre
begin
  reinit;
  poser(cadre, 20, 20, 220, 140);
  wordParams[0] := word(@cadre);
  wordParams[1] := word(@titre);
  NeoMessage.params[4] := 1;
  appel(34, 1);
  fenetre := NeoMessage.params[5];
end;

// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := t;
  NeoMessage.params[1] := fenetre;
  wordParams[1] := word(r);
  wordParams[2] := word(s);
  wordParams[3] := max;
  appel(36, 1);
  result := NeoMessage.params[0];
end;

function valeur(c: byte): word;                 // 36,6 Get Control Value
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  appel(36, 6);
  result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

var ecran: Rect;

procedure barbouiller;                          // le programme peint tout le contenu en couleur 4
begin
  poser(ecran, 0, 0, 320, 240);
  NeoWaitMessage; NeoMessage.params[0] := fenetre; appel(34, 12);   // 34,12 Set Port
  NeoMessage.params[0] := 4; appel(32, 4);
  wordParams[0] := word(@ecran); appel(32, 8);
end;

const ok: array[0..2] of byte = (2, ord('O'), ord('K'));
var rb: Rect;
    b, c1, i1, c2, i2: byte;
begin
  write(chr(12));
  poser(rb, 10, 10, 70, 24);
  ouvrir;
  b := controle(1, @rb, @ok, 0);
  barbouiller;
  c1 := NeoGetPixel(31, 41); i1 := NeoGetPixel(35, 43);   // cadre et intérieur du bouton
  NeoWaitMessage; NeoMessage.params[0] := b; appel(36, 4);   // Draw Control
  c2 := NeoGetPixel(31, 41); i2 := NeoGetPixel(35, 43);
  reinit;
  writeln('Peint : ', c1, ', ', i1, ' ; redessine : cadre ', c2, ', dedans ', i2);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Peint : 4, 4 ; redessine : cadre 15, dedans 0
NeoBASIC
10 ' Redessiner un controle (groupe 36, fonction 4, Trinity)
20 cls
30 gosub 7000
40 g = 10 : h = 10 : d = 70 : b = 24 : gosub 8000 : s$ = "OK" : gosub 7900 : ty = 1 : mx = 0 : gosub 7100 : bt = cn
50 gosub 2000
60 c1 = point(31, 41) : i1 = point(35, 43) : ' cadre et interieur du bouton
70 while peek($ff00) : wend : poke $ff04, bt : f = 4 : gosub 8110 : ' Draw Control
80 c2 = point(31, 41) : i2 = point(35, 43)
90 gosub 8300
100 print "Peint : ";c1;", ";i1;" ; redessine : cadre ";c2;", dedans ";i2
110 end
2000 ' le programme peint tout le contenu en couleur 4
2010 ec = alloc(8) : doke ec, 0 : doke ec + 2, 0 : doke ec + 4, 320 : doke ec + 6, 240
2020 while peek($ff00) : wend : poke $ff04, fw : poke $ff01, 12 : poke $ff00, 34 : ' 34,12 Set Port
2030 while peek($ff00) : wend : poke $ff04, 4 : poke $ff01, 4 : poke $ff00, 32
2040 while peek($ff00) : wend : doke $ff04, ec : poke $ff01, 8 : poke $ff00, 32
2050 while peek($ff00) : wend : return
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Peint : 4, 4 ; redessine : cadre 15, dedans 0
Assembleur 65C02 (64tass)
; Redessiner un contrôle (groupe 36, fonction 4, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #12                    ; écran effacé : on relit des pixels
        jsr WriteCharacter
        jsr ouvrir
        lda #<cb
        ldx #>cb
        jsr controle
        sta b
        jsr barbouiller
        lda #31
        ldy #41
        jsr pixel
        sta c1
        lda #35
        ldy #43
        jsr pixel
        sta i1
                                   ; cadre et intérieur du bouton
        jsr WaitMessage
        lda b
        sta ControlPort+4
        lda #36
        ldx #4                  ; Draw Control
        jsr appel
        lda #31
        ldy #41
        jsr pixel
        sta c2
        lda #35
        ldy #43
        jsr pixel
        sta i2
        lda #<b0
        ldx #>b0
        jsr envoi
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda c1
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda i1
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda c2
        jsr decimal
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda i2
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel:  pha
        jsr WaitMessage
        pla
        sta ControlPort+4          ; P0-P1 : X
        stz ControlPort+5
        sty ControlPort+6          ; P2-P3 : Y
        stz ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

rb:     .word 10, 10, 70, 24
ok:     .byte 2
        .text "OK"
cb:     .byte 1                  ; bouton
        .word rb, ok, 0
b:      .byte 0
c1:     .byte 0
i1:     .byte 0
c2:     .byte 0
i2:     .byte 0
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset
t1:     .text "Peint : ", 0
t2:     .text ", ", 0
t3:     .text " ; redessine : cadre ", 0
t4:     .text ", dedans ", 0

; Le programme peint tout le contenu en couleur 4.
barbouiller:
        jsr WaitMessage
        lda fen
        sta ControlPort+4
        lda #34
        ldx #12                    ; 34,12 Set Port
        jsr appel
        lda #<coul
        ldx #>coul
        jsr envoi
        lda #<peint
        ldx #>peint
        jsr envoi
        rts
coul:   .byte 32, 4, 1, 4
peint:  .byte 32, 8, 2
        .word ecran
ecran:  .word 0, 0, 320, 240

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
        ldx #>raz
        jsr envoi
        lda #<nfen
        ldx #>nfen
        jsr envoi
        lda ControlPort+9
        sta fen
        rts
raz:    .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen:   .byte 34, 1, 5
        .word cadre, titre
        .byte 1
cadre:  .word 20, 20, 220, 140
titre:  .byte 1
        .text "A"                  ; chaînes précédées de leur longueur, lues sur place
fen:    .byte 0

; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
        sta blk
        stx blk+1
        jsr WaitMessage
        ldy #0
        lda (blk),y
        sta ControlPort+4          ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
        lda fen
        sta ControlPort+5          ; P1 : fenêtre
        ldy #1
_ctl:   lda (blk),y
        sta ControlPort+5,y        ; P2-P7 : Rect, titre, maximum
        iny
        cpy #7
        bne _ctl
        lda #36
        ldx #1
        jsr appel
        lda ControlPort+4
        rts

; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        lda #36
        ldx #6
        jsr appel
        lda ControlPort+5
        rts

; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        ldx #4
_sv:    lda pt,x
        sta ControlPort+5,x        ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
        dex
        bpl _sv
        lda #36
        ldx #9
        jsr appel
        lda ControlPort+10
        rts
pt:     .word 0, 0
        .byte 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Peint : 4, 4 ; redessine : cadre 15, dedans 0

36,5 Set Control Value Trinity

Donne une valeur à un contrôle et le redessine.

Entrées
OctetsTypeRôle
P0uint8numéro du contrôle
P1-P2uint16valeur : 0 ou 1 pour les cases, 0 au maximum pour les barres

Sorties : aucune.

Au banc, une valeur au-delà du maximum d'une barre est ramenée au maximum, sans erreur. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Sets the value of control Parameter:0 to Parameters:1,2 (0/1 for boxes, 0..max for scroll bars) and redraws it.

C (llvm-mos)
/* Donner une valeur à un contrôle (groupe 36, fonction 5, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;

/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A";             /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
    libre();
    api(32, 19);
}
static void ouvrir(void) {                      /* 34,1 : une fenêtre avec barre de titre */
    reinit();
    libre();
    p16(0, (uint16_t)&cadre);
    p16(2, (uint16_t)titre);
    ControlPort.params[4] = 1;
    api(34, 1);
    fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
   au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
    libre();
    ControlPort.params[0] = type;
    ControlPort.params[1] = fenetre;
    p16(2, (uint16_t)r);
    p16(4, (uint16_t)t);
    p16(6, max);
    api(36, 1);
    return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) {             /* 36,6 Get Control Value */
    libre();
    ControlPort.params[0] = c;
    api(36, 6);
    return ControlPort.params[1] | ControlPort.params[2] << 8;
}

static Rect rc = {10, 30, 110, 42}, rs = {180, 0, 192, 100};
static const char option[] = "\006Option";

static uint8_t donner(uint8_t c, uint16_t v) {  /* Set Control Value */
    libre();
    ControlPort.params[0] = c;
    p16(1, v);
    api(36, 5);
    return ControlPort.error;
}

int main(void) {
    uint8_t c, s, e;
    uint16_t vc, v1, v2;
    ouvrir();
    c = controle(2, &rc, option, 0);
    s = controle(4, &rs, titre, 50);
    donner(c, 1);
    vc = valeur(c);
    donner(s, 25);
    v1 = valeur(s);
    e = donner(s, 99);                          /* au-delà du maximum : ramené à 50 */
    v2 = valeur(s);
    reinit();
    printf("Case : %u ; barre : %u, puis 99 -> %u (erreur %u)\n", vc, v1, v2, e);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Case : 1 ; barre : 25, puis 99 -> 50 (erreur 0)
Mad Pascal
// Donner une valeur à un contrôle (groupe 36, fonction 5, Trinity).
program ct5;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)

// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A'));   // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
    fenetre: byte;

procedure poser(var r: Rect; g, h, d, b: smallint);
begin
  r.g := g; r.h := h; r.d := d; r.b := b;
end;

procedure appel(g, f: byte);                    // appel g,f (paramètres déjà posés)
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
  NeoWaitMessage;
  appel(32, 19);
end;

procedure ouvrir;                               // 34,1 : une fenêtre avec barre de titre
begin
  reinit;
  poser(cadre, 20, 20, 220, 140);
  wordParams[0] := word(@cadre);
  wordParams[1] := word(@titre);
  NeoMessage.params[4] := 1;
  appel(34, 1);
  fenetre := NeoMessage.params[5];
end;

// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := t;
  NeoMessage.params[1] := fenetre;
  wordParams[1] := word(r);
  wordParams[2] := word(s);
  wordParams[3] := max;
  appel(36, 1);
  result := NeoMessage.params[0];
end;

function valeur(c: byte): word;                 // 36,6 Get Control Value
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  appel(36, 6);
  result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

const option: array[0..6] of byte = (6, ord('O'), ord('p'), ord('t'), ord('i'), ord('o'), ord('n'));

function donner(c: byte; v: word): byte;        // Set Control Value
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  p16(1, v);
  appel(36, 5);
  result := NeoMessage.error;
end;

var rc, rs: Rect;
    c, s, e: byte;
    vc, v1, v2: word;
begin
  poser(rc, 10, 30, 110, 42); poser(rs, 180, 0, 192, 100);
  ouvrir;
  c := controle(2, @rc, @option, 0);
  s := controle(4, @rs, @titre, 50);
  donner(c, 1);
  vc := valeur(c);
  donner(s, 25);
  v1 := valeur(s);
  e := donner(s, 99);                           // au-delà du maximum : ramené à 50
  v2 := valeur(s);
  reinit;
  writeln('Case : ', vc, ' ; barre : ', v1, ', puis 99 -> ', v2, ' (erreur ', e, ')');
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Case : 1 ; barre : 25, puis 99 -> 50 (erreur 0)
NeoBASIC
10 ' Donner une valeur a un controle (groupe 36, fonction 5, Trinity)
20 gosub 7000
30 g = 10 : h = 30 : d = 110 : b = 42 : gosub 8000 : s$ = "Option" : gosub 7900 : ty = 2 : mx = 0 : gosub 7100 : ca = cn
40 g = 180 : h = 0 : d = 192 : b = 100 : gosub 8000 : ch = tf : ty = 4 : mx = 50 : gosub 7100 : ba = cn
50 c = ca : vv = 1 : gosub 2000 : c = ca : gosub 7200 : vc = v
60 c = ba : vv = 25 : gosub 2000 : gosub 7200 : v1 = v
70 vv = 99 : gosub 2000 : e9 = e : gosub 7200 : v2 = v : ' au-dela du maximum : ramene a 50
80 gosub 8300
90 print "Case : ";vc;" ; barre : ";v1;", puis 99 -> ";v2;" (erreur ";e9;")"
100 end
2000 ' Set Control Value : controle c, valeur vv
2010 while peek($ff00) : wend : poke $ff04, c : doke $ff05, vv : f = 5 : goto 8110
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Case : 1 ; barre : 25, puis 99 -> 50 (erreur 0)
Assembleur 65C02 (64tass)
; Donner une valeur à un contrôle (groupe 36, fonction 5, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr ouvrir
        lda #<cc
        ldx #>cc
        jsr controle
        sta c
        lda #<cs
        ldx #>cs
        jsr controle
        sta s
        jsr WaitMessage
        lda c
        sta ControlPort+4
        lda #1
        sta ControlPort+5
        stz ControlPort+6
        lda #36
        ldx #5                  ; Set Control Value
        jsr appel
        lda c
        jsr valeur
        sta vc
        jsr WaitMessage
        lda s
        sta ControlPort+4
        lda #25
        sta ControlPort+5
        stz ControlPort+6
        lda #36
        ldx #5                  ; Set Control Value
        jsr appel
        lda s
        jsr valeur
        sta v1
        jsr WaitMessage
        lda s
        sta ControlPort+4
        lda #99
        sta ControlPort+5
        stz ControlPort+6
        lda #36
        ldx #5                  ; au-delà du maximum : ramené à 50
        jsr appel
        lda ControlPort+2
        sta e
        lda s
        jsr valeur
        sta v2
        lda #<b0
        ldx #>b0
        jsr envoi
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda vc
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda v1
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda v2
        jsr decimal
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda e
        jsr decimal
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda #13
        jsr WriteCharacter
        rts

rc:     .word 10, 30, 110, 42
rs:     .word 180, 0, 192, 100
option: .byte 6
        .text "Option"
cc:     .byte 2                  ; case à cocher
        .word rc, option, 0
c:      .byte 0
cs:     .byte 4                  ; barre, maximum 50
        .word rs, titre, 50
s:      .byte 0
vc:     .byte 0
v1:     .byte 0
e:      .byte 0
v2:     .byte 0
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset
t1:     .text "Case : ", 0
t2:     .text " ; barre : ", 0
t3:     .text ", puis 99 -> ", 0
t4:     .text " (erreur ", 0
t5:     .text ")", 0

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
        ldx #>raz
        jsr envoi
        lda #<nfen
        ldx #>nfen
        jsr envoi
        lda ControlPort+9
        sta fen
        rts
raz:    .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen:   .byte 34, 1, 5
        .word cadre, titre
        .byte 1
cadre:  .word 20, 20, 220, 140
titre:  .byte 1
        .text "A"                  ; chaînes précédées de leur longueur, lues sur place
fen:    .byte 0

; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
        sta blk
        stx blk+1
        jsr WaitMessage
        ldy #0
        lda (blk),y
        sta ControlPort+4          ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
        lda fen
        sta ControlPort+5          ; P1 : fenêtre
        ldy #1
_ctl:   lda (blk),y
        sta ControlPort+5,y        ; P2-P7 : Rect, titre, maximum
        iny
        cpy #7
        bne _ctl
        lda #36
        ldx #1
        jsr appel
        lda ControlPort+4
        rts

; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        lda #36
        ldx #6
        jsr appel
        lda ControlPort+5
        rts

; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        ldx #4
_sv:    lda pt,x
        sta ControlPort+5,x        ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
        dex
        bpl _sv
        lda #36
        ldx #9
        jsr appel
        lda ControlPort+10
        rts
pt:     .word 0, 0
        .byte 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Case : 1 ; barre : 25, puis 99 -> 50 (erreur 0)

36,6 Get Control Value Trinity

Rend la valeur d'un contrôle.

Entrées
OctetsTypeRôle
P0uint8numéro du contrôle
Sorties
OctetsTypeRôle
P1-P2uint16valeur

Un clic (36,9) fait basculer la case à cocher à chaque fois ; le bouton radio passe à 1 et y reste. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Returns the value of control Parameter:0 in Parameters:1,2.

C (llvm-mos)
/* Lire la valeur d'un contrôle (groupe 36, fonction 6, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;

/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A";             /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
    libre();
    api(32, 19);
}
static void ouvrir(void) {                      /* 34,1 : une fenêtre avec barre de titre */
    reinit();
    libre();
    p16(0, (uint16_t)&cadre);
    p16(2, (uint16_t)titre);
    ControlPort.params[4] = 1;
    api(34, 1);
    fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
   au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
    libre();
    ControlPort.params[0] = type;
    ControlPort.params[1] = fenetre;
    p16(2, (uint16_t)r);
    p16(4, (uint16_t)t);
    p16(6, max);
    api(36, 1);
    return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) {             /* 36,6 Get Control Value */
    libre();
    ControlPort.params[0] = c;
    api(36, 6);
    return ControlPort.params[1] | ControlPort.params[2] << 8;
}

static uint8_t suivre(uint8_t c, int16_t x, int16_t y, uint8_t phase) {   /* 36,9 Track Control : 1 si le contrôle a agi */
    libre();
    ControlPort.params[0] = c;
    p16(1, x);
    p16(3, y);
    ControlPort.params[5] = phase;              /* 0 bouton enfoncé, 1 mouvement, 2 bouton relâché */
    api(36, 9);
    return ControlPort.params[6];
}
static uint8_t clic(uint8_t c, int16_t x, int16_t y) {   /* enfoncé puis relâché au même endroit */
    suivre(c, x, y, 0);
    return suivre(c, x, y, 2);
}

static Rect rc = {10, 30, 110, 42}, rr = {10, 48, 110, 60};
static const char option[] = "\006Option", radio[] = "\005Radio";

int main(void) {
    uint8_t c, r;
    uint16_t c0, c1, c2, r1, r2;
    ouvrir();
    c = controle(2, &rc, option, 0);            /* case à cocher, en (31, 61) à l'écran */
    r = controle(3, &rr, radio, 0);             /* bouton radio, en (31, 79) */
    c0 = valeur(c);
    clic(c, 40, 65); c1 = valeur(c);            /* la case bascule à chaque clic */
    clic(c, 40, 65); c2 = valeur(c);
    clic(r, 40, 82); r1 = valeur(r);            /* le bouton radio reste à 1 */
    clic(r, 40, 82); r2 = valeur(r);
    reinit();
    printf("Case : %u, %u, %u ; radio : %u, %u\n", c0, c1, c2, r1, r2);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Case : 0, 1, 0 ; radio : 1, 1
Mad Pascal
// Lire la valeur d'un contrôle (groupe 36, fonction 6, Trinity).
program ct6;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)

// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A'));   // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
    fenetre: byte;

procedure poser(var r: Rect; g, h, d, b: smallint);
begin
  r.g := g; r.h := h; r.d := d; r.b := b;
end;

procedure appel(g, f: byte);                    // appel g,f (paramètres déjà posés)
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
  NeoWaitMessage;
  appel(32, 19);
end;

procedure ouvrir;                               // 34,1 : une fenêtre avec barre de titre
begin
  reinit;
  poser(cadre, 20, 20, 220, 140);
  wordParams[0] := word(@cadre);
  wordParams[1] := word(@titre);
  NeoMessage.params[4] := 1;
  appel(34, 1);
  fenetre := NeoMessage.params[5];
end;

// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := t;
  NeoMessage.params[1] := fenetre;
  wordParams[1] := word(r);
  wordParams[2] := word(s);
  wordParams[3] := max;
  appel(36, 1);
  result := NeoMessage.params[0];
end;

function valeur(c: byte): word;                 // 36,6 Get Control Value
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  appel(36, 6);
  result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

function suivre(c: byte; x, y: smallint; phase: byte): byte;   // 36,9 Track Control : 1 si le contrôle a agi
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  p16(1, word(x));
  p16(3, word(y));
  NeoMessage.params[5] := phase;                // 0 bouton enfoncé, 1 mouvement, 2 bouton relâché
  appel(36, 9);
  result := NeoMessage.params[6];
end;

function clic(c: byte; x, y: smallint): byte;   // enfoncé puis relâché au même endroit
begin
  suivre(c, x, y, 0);
  result := suivre(c, x, y, 2);
end;

const option: array[0..6] of byte = (6, ord('O'), ord('p'), ord('t'), ord('i'), ord('o'), ord('n'));
      radio: array[0..5] of byte = (5, ord('R'), ord('a'), ord('d'), ord('i'), ord('o'));
var rc, rr: Rect;
    c, r: byte;
    c0, c1, c2, r1, r2: word;
begin
  poser(rc, 10, 30, 110, 42); poser(rr, 10, 48, 110, 60);
  ouvrir;
  c := controle(2, @rc, @option, 0);            // case à cocher, en (31, 61) à l'écran
  r := controle(3, @rr, @radio, 0);             // bouton radio, en (31, 79)
  c0 := valeur(c);
  clic(c, 40, 65); c1 := valeur(c);             // la case bascule à chaque clic
  clic(c, 40, 65); c2 := valeur(c);
  clic(r, 40, 82); r1 := valeur(r);             // le bouton radio reste à 1
  clic(r, 40, 82); r2 := valeur(r);
  reinit;
  writeln('Case : ', c0, ', ', c1, ', ', c2, ' ; radio : ', r1, ', ', r2);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Case : 0, 1, 0 ; radio : 1, 1
NeoBASIC
10 ' Lire la valeur d'un controle (groupe 36, fonction 6, Trinity)
20 gosub 7000
30 g = 10 : h = 30 : d = 110 : b = 42 : gosub 8000 : s$ = "Option" : gosub 7900 : ty = 2 : mx = 0 : gosub 7100 : ca = cn : ' case, en (31, 61)
40 h = 48 : b = 60 : gosub 8000 : s$ = "Radio" : gosub 7900 : ty = 3 : gosub 7100 : ra = cn : ' bouton radio, en (31, 79)
50 c = ca : gosub 7200 : c0 = v
60 x = 40 : y = 65 : gosub 7400 : gosub 7200 : c1 = v : ' la case bascule a chaque clic
70 gosub 7400 : gosub 7200 : c2 = v
80 c = ra : y = 82 : gosub 7400 : gosub 7200 : r1 = v : ' le bouton radio reste a 1
90 gosub 7400 : gosub 7200 : r2 = v
100 gosub 8300
110 print "Case : ";c0;", ";c1;", ";c2;" ; radio : ";r1;", ";r2
120 end
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Case : 0, 1, 0 ; radio : 1, 1
Assembleur 65C02 (64tass)
; Lire la valeur d'un contrôle (groupe 36, fonction 6, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr ouvrir
        lda #<cc
        ldx #>cc
        jsr controle
        sta c
        lda #<cr
        ldx #>cr
        jsr controle
        sta r
        lda c
        jsr valeur
        sta c0
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #65
        sta pt+2
        stz pt+3
        lda #0                  ; la case bascule à chaque clic
        sta pt+4
        lda c
        jsr suivre
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #65
        sta pt+2
        stz pt+3
        lda #2                  ; relâché
        sta pt+4
        lda c
        jsr suivre
        lda c
        jsr valeur
        sta c1
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #65
        sta pt+2
        stz pt+3
        lda #0                  ; enfoncé
        sta pt+4
        lda c
        jsr suivre
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #65
        sta pt+2
        stz pt+3
        lda #2                  ; relâché
        sta pt+4
        lda c
        jsr suivre
        lda c
        jsr valeur
        sta c2
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #82
        sta pt+2
        stz pt+3
        lda #0                  ; le bouton radio reste à 1
        sta pt+4
        lda r
        jsr suivre
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #82
        sta pt+2
        stz pt+3
        lda #2                  ; relâché
        sta pt+4
        lda r
        jsr suivre
        lda r
        jsr valeur
        sta r1
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #82
        sta pt+2
        stz pt+3
        lda #0                  ; enfoncé
        sta pt+4
        lda r
        jsr suivre
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #82
        sta pt+2
        stz pt+3
        lda #2                  ; relâché
        sta pt+4
        lda r
        jsr suivre
        lda r
        jsr valeur
        sta r2
        lda #<b0
        ldx #>b0
        jsr envoi
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda c0
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda c1
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda c2
        jsr decimal
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda r1
        jsr decimal
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda r2
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

rc:     .word 10, 30, 110, 42
rr:     .word 10, 48, 110, 60
option: .byte 6
        .text "Option"
radio:  .byte 5
        .text "Radio"
cc:     .byte 2                  ; case à cocher, en (31, 61) à l'écran
        .word rc, option, 0
c:      .byte 0
cr:     .byte 3                  ; bouton radio, en (31, 79)
        .word rr, radio, 0
r:      .byte 0
c0:     .byte 0
c1:     .byte 0
c2:     .byte 0
r1:     .byte 0
r2:     .byte 0
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset
t1:     .text "Case : ", 0
t2:     .text ", ", 0
t3:     .text ", ", 0
t4:     .text " ; radio : ", 0
t5:     .text ", ", 0

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
        ldx #>raz
        jsr envoi
        lda #<nfen
        ldx #>nfen
        jsr envoi
        lda ControlPort+9
        sta fen
        rts
raz:    .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen:   .byte 34, 1, 5
        .word cadre, titre
        .byte 1
cadre:  .word 20, 20, 220, 140
titre:  .byte 1
        .text "A"                  ; chaînes précédées de leur longueur, lues sur place
fen:    .byte 0

; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
        sta blk
        stx blk+1
        jsr WaitMessage
        ldy #0
        lda (blk),y
        sta ControlPort+4          ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
        lda fen
        sta ControlPort+5          ; P1 : fenêtre
        ldy #1
_ctl:   lda (blk),y
        sta ControlPort+5,y        ; P2-P7 : Rect, titre, maximum
        iny
        cpy #7
        bne _ctl
        lda #36
        ldx #1
        jsr appel
        lda ControlPort+4
        rts

; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        lda #36
        ldx #6
        jsr appel
        lda ControlPort+5
        rts

; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        ldx #4
_sv:    lda pt,x
        sta ControlPort+5,x        ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
        dex
        bpl _sv
        lda #36
        ldx #9
        jsr appel
        lda ControlPort+10
        rts
pt:     .word 0, 0
        .byte 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Case : 0, 1, 0 ; radio : 1, 1

36,7 Set Control Flags Trinity

Change les options d'un contrôle et le redessine.

Entrées
OctetsTypeRôle
P0uint8numéro du contrôle
P1uint8options : bit 0 inactif

Sorties : aucune.

Un contrôle inactif est dessiné en gris et ignore la souris (36,9) et les touches (36,10). NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Sets the flags of control Parameter:0 (bit 0 disabled : drawn grey, ignores tracking and keys) and redraws it.

C (llvm-mos)
/* Rendre un contrôle inactif (groupe 36, fonction 7, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;

/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A";             /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
    libre();
    api(32, 19);
}
static void ouvrir(void) {                      /* 34,1 : une fenêtre avec barre de titre */
    reinit();
    libre();
    p16(0, (uint16_t)&cadre);
    p16(2, (uint16_t)titre);
    ControlPort.params[4] = 1;
    api(34, 1);
    fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
   au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
    libre();
    ControlPort.params[0] = type;
    ControlPort.params[1] = fenetre;
    p16(2, (uint16_t)r);
    p16(4, (uint16_t)t);
    p16(6, max);
    api(36, 1);
    return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) {             /* 36,6 Get Control Value */
    libre();
    ControlPort.params[0] = c;
    api(36, 6);
    return ControlPort.params[1] | ControlPort.params[2] << 8;
}

static uint8_t suivre(uint8_t c, int16_t x, int16_t y, uint8_t phase) {   /* 36,9 Track Control : 1 si le contrôle a agi */
    libre();
    ControlPort.params[0] = c;
    p16(1, x);
    p16(3, y);
    ControlPort.params[5] = phase;              /* 0 bouton enfoncé, 1 mouvement, 2 bouton relâché */
    api(36, 9);
    return ControlPort.params[6];
}
static uint8_t clic(uint8_t c, int16_t x, int16_t y) {   /* enfoncé puis relâché au même endroit */
    suivre(c, x, y, 0);
    return suivre(c, x, y, 2);
}

static Rect rc = {10, 30, 110, 42};
static const char option[] = "\006Option";

static void options(uint8_t c, uint8_t o) {     /* Set Control Flags : bit 0 inactif */
    libre();
    ControlPort.params[0] = c;
    ControlPort.params[1] = o;
    api(36, 7);
}

int main(void) {
    uint8_t c, a1, a2;
    uint16_t v1, v2;
    ouvrir();
    c = controle(2, &rc, option, 0);
    options(c, 1);                              /* inactif : dessiné en gris, ignore la souris */
    a1 = clic(c, 40, 65); v1 = valeur(c);
    options(c, 0);
    a2 = clic(c, 40, 65); v2 = valeur(c);
    reinit();
    printf("Inactive : %u, valeur %u ; active : %u, valeur %u\n", a1, v1, a2, v2);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Inactive : 0, valeur 0 ; active : 1, valeur 1
Mad Pascal
// Rendre un contrôle inactif (groupe 36, fonction 7, Trinity).
program ct7;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)

// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A'));   // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
    fenetre: byte;

procedure poser(var r: Rect; g, h, d, b: smallint);
begin
  r.g := g; r.h := h; r.d := d; r.b := b;
end;

procedure appel(g, f: byte);                    // appel g,f (paramètres déjà posés)
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
  NeoWaitMessage;
  appel(32, 19);
end;

procedure ouvrir;                               // 34,1 : une fenêtre avec barre de titre
begin
  reinit;
  poser(cadre, 20, 20, 220, 140);
  wordParams[0] := word(@cadre);
  wordParams[1] := word(@titre);
  NeoMessage.params[4] := 1;
  appel(34, 1);
  fenetre := NeoMessage.params[5];
end;

// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := t;
  NeoMessage.params[1] := fenetre;
  wordParams[1] := word(r);
  wordParams[2] := word(s);
  wordParams[3] := max;
  appel(36, 1);
  result := NeoMessage.params[0];
end;

function valeur(c: byte): word;                 // 36,6 Get Control Value
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  appel(36, 6);
  result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

function suivre(c: byte; x, y: smallint; phase: byte): byte;   // 36,9 Track Control : 1 si le contrôle a agi
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  p16(1, word(x));
  p16(3, word(y));
  NeoMessage.params[5] := phase;                // 0 bouton enfoncé, 1 mouvement, 2 bouton relâché
  appel(36, 9);
  result := NeoMessage.params[6];
end;

function clic(c: byte; x, y: smallint): byte;   // enfoncé puis relâché au même endroit
begin
  suivre(c, x, y, 0);
  result := suivre(c, x, y, 2);
end;

const option: array[0..6] of byte = (6, ord('O'), ord('p'), ord('t'), ord('i'), ord('o'), ord('n'));

procedure options(c, o: byte);                  // Set Control Flags : bit 0 inactif
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  NeoMessage.params[1] := o;
  appel(36, 7);
end;

var rc: Rect;
    c, a1, a2: byte;
    v1, v2: word;
begin
  poser(rc, 10, 30, 110, 42);
  ouvrir;
  c := controle(2, @rc, @option, 0);
  options(c, 1);                                // inactif : dessiné en gris, ignore la souris
  a1 := clic(c, 40, 65); v1 := valeur(c);
  options(c, 0);
  a2 := clic(c, 40, 65); v2 := valeur(c);
  reinit;
  writeln('Inactive : ', a1, ', valeur ', v1, ' ; active : ', a2, ', valeur ', v2);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Inactive : 0, valeur 0 ; active : 1, valeur 1
NeoBASIC
10 ' Rendre un controle inactif (groupe 36, fonction 7, Trinity)
20 gosub 7000
30 g = 10 : h = 30 : d = 110 : b = 42 : gosub 8000 : s$ = "Option" : gosub 7900 : ty = 2 : mx = 0 : gosub 7100 : c = cn
40 o = 1 : gosub 2000 : ' inactif : dessine en gris, ignore la souris
50 x = 40 : y = 65 : gosub 7400 : a1 = ag : gosub 7200 : v1 = v
60 o = 0 : gosub 2000
70 gosub 7400 : a2 = ag : gosub 7200 : v2 = v
80 gosub 8300
90 print "Inactive : ";a1;", valeur ";v1;" ; active : ";a2;", valeur ";v2
100 end
2000 ' Set Control Flags : controle c, options o (bit 0 inactif)
2010 while peek($ff00) : wend : poke $ff04, c : poke $ff05, o : f = 7 : goto 8110
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Inactive : 0, valeur 0 ; active : 1, valeur 1
Assembleur 65C02 (64tass)
; Rendre un contrôle inactif (groupe 36, fonction 7, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr ouvrir
        lda #<cc
        ldx #>cc
        jsr controle
        sta c
        jsr WaitMessage
        lda c
        sta ControlPort+4
        lda #1
        sta ControlPort+5
        lda #36
        ldx #7                  ; Set Control Flags, bit 0 : inactif, ignore la souris
        jsr appel
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #65
        sta pt+2
        stz pt+3
        lda #0                  ; enfoncé
        sta pt+4
        lda c
        jsr suivre
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #65
        sta pt+2
        stz pt+3
        lda #2                  ; relâché
        sta pt+4
        lda c
        jsr suivre
        sta a1
        lda c
        jsr valeur
        sta v1
        jsr WaitMessage
        lda c
        sta ControlPort+4
        lda #0
        sta ControlPort+5
        lda #36
        ldx #7                  ; Set Control Flags : actif
        jsr appel
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #65
        sta pt+2
        stz pt+3
        lda #0                  ; enfoncé
        sta pt+4
        lda c
        jsr suivre
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #65
        sta pt+2
        stz pt+3
        lda #2                  ; relâché
        sta pt+4
        lda c
        jsr suivre
        sta a2
        lda c
        jsr valeur
        sta v2
        lda #<b0
        ldx #>b0
        jsr envoi
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda a1
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda v1
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda a2
        jsr decimal
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda v2
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

rc:     .word 10, 30, 110, 42
option: .byte 6
        .text "Option"
cc:     .byte 2                  ; case à cocher
        .word rc, option, 0
c:      .byte 0
a1:     .byte 0
v1:     .byte 0
a2:     .byte 0
v2:     .byte 0
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset
t1:     .text "Inactive : ", 0
t2:     .text ", valeur ", 0
t3:     .text " ; active : ", 0
t4:     .text ", valeur ", 0

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
        ldx #>raz
        jsr envoi
        lda #<nfen
        ldx #>nfen
        jsr envoi
        lda ControlPort+9
        sta fen
        rts
raz:    .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen:   .byte 34, 1, 5
        .word cadre, titre
        .byte 1
cadre:  .word 20, 20, 220, 140
titre:  .byte 1
        .text "A"                  ; chaînes précédées de leur longueur, lues sur place
fen:    .byte 0

; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
        sta blk
        stx blk+1
        jsr WaitMessage
        ldy #0
        lda (blk),y
        sta ControlPort+4          ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
        lda fen
        sta ControlPort+5          ; P1 : fenêtre
        ldy #1
_ctl:   lda (blk),y
        sta ControlPort+5,y        ; P2-P7 : Rect, titre, maximum
        iny
        cpy #7
        bne _ctl
        lda #36
        ldx #1
        jsr appel
        lda ControlPort+4
        rts

; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        lda #36
        ldx #6
        jsr appel
        lda ControlPort+5
        rts

; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        ldx #4
_sv:    lda pt,x
        sta ControlPort+5,x        ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
        dex
        bpl _sv
        lda #36
        ldx #9
        jsr appel
        lda ControlPort+10
        rts
pt:     .word 0, 0
        .byte 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Inactive : 0, valeur 0 ; active : 1, valeur 1

36,8 Find Control Trinity

Rend le contrôle de la fenêtre de devant sous un point, et la partie touchée.

Entrées
OctetsTypeRôle
P0-P1int16X du point
P2-P3int16Y du point
Sorties
OctetsTypeRôle
P4uint8contrôle (0 si aucun)
P5uint8partie : 1 corps ; barres : 2 première flèche, 3 seconde flèche, 4 page avant le curseur, 5 page après, 6 curseur

Relevé au banc pour la barre de 12 × 100 pixels : flèches de 8 lignes en haut et en bas, curseur de 4 lignes (y 79 à 82 pour la valeur 25 sur 50). NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Returns in Parameter:4 the control of the frontmost window under Parameters:0,1 (X), Parameters:2,3 (Y) (0 if none) and in Parameter:5 the part : 1 body ; scroll bars : 2 first arrow, 3 second arrow, 4 page before the thumb, 5 page after, 6 thumb.

C (llvm-mos)
/* Trouver le contrôle sous un point (groupe 36, fonction 8, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;

/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A";             /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
    libre();
    api(32, 19);
}
static void ouvrir(void) {                      /* 34,1 : une fenêtre avec barre de titre */
    reinit();
    libre();
    p16(0, (uint16_t)&cadre);
    p16(2, (uint16_t)titre);
    ControlPort.params[4] = 1;
    api(34, 1);
    fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
   au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
    libre();
    ControlPort.params[0] = type;
    ControlPort.params[1] = fenetre;
    p16(2, (uint16_t)r);
    p16(4, (uint16_t)t);
    p16(6, max);
    api(36, 1);
    return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) {             /* 36,6 Get Control Value */
    libre();
    ControlPort.params[0] = c;
    api(36, 6);
    return ControlPort.params[1] | ControlPort.params[2] << 8;
}

static Rect rb = {10, 10, 70, 24}, rs = {180, 0, 192, 100};
static const char ok[] = "\002OK";
static const int16_t py[6] = {45, 33, 125, 50, 80, 110};
static const int16_t px[6] = {40, 205, 205, 205, 205, 205};
static const char *nom[6] = {"Bouton", "Fleche du haut", "Fleche du bas", "Page avant", "Curseur", "Page apres"};

int main(void) {
    uint8_t s, i, c[6], z[6];
    ouvrir();
    controle(1, &rb, ok, 0);
    s = controle(4, &rs, titre, 50);            /* barre en x 201 à 212, y 31 à 130 */
    libre(); ControlPort.params[0] = s; p16(1, 25); api(36, 5);   /* curseur au milieu : y 79 à 82 */
    for (i = 0; i < 6; i++) {
        libre(); p16(0, px[i]); p16(2, py[i]); api(36, 8);   /* Find Control */
        c[i] = ControlPort.params[4];
        z[i] = ControlPort.params[5];
    }
    reinit();
    for (i = 0; i < 6; i++)
        printf("%s : %u, %u\n", nom[i], c[i], z[i]);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Bouton : 1, 1
Fleche du haut : 2, 2
Fleche du bas : 2, 3
Page avant : 2, 4
Curseur : 2, 6
Page apres : 2, 5
Mad Pascal
// Trouver le contrôle sous un point (groupe 36, fonction 8, Trinity).
program ct8;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)

// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A'));   // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
    fenetre: byte;

procedure poser(var r: Rect; g, h, d, b: smallint);
begin
  r.g := g; r.h := h; r.d := d; r.b := b;
end;

procedure appel(g, f: byte);                    // appel g,f (paramètres déjà posés)
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
  NeoWaitMessage;
  appel(32, 19);
end;

procedure ouvrir;                               // 34,1 : une fenêtre avec barre de titre
begin
  reinit;
  poser(cadre, 20, 20, 220, 140);
  wordParams[0] := word(@cadre);
  wordParams[1] := word(@titre);
  NeoMessage.params[4] := 1;
  appel(34, 1);
  fenetre := NeoMessage.params[5];
end;

// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := t;
  NeoMessage.params[1] := fenetre;
  wordParams[1] := word(r);
  wordParams[2] := word(s);
  wordParams[3] := max;
  appel(36, 1);
  result := NeoMessage.params[0];
end;

function valeur(c: byte): word;                 // 36,6 Get Control Value
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  appel(36, 6);
  result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

const ok: array[0..2] of byte = (2, ord('O'), ord('K'));
      px: array[0..5] of word = (40, 205, 205, 205, 205, 205);
      py: array[0..5] of word = (45, 33, 125, 50, 80, 110);
var rb, rs: Rect;
    s, i: byte;
    c, z: array[0..5] of byte;
begin
  poser(rb, 10, 10, 70, 24); poser(rs, 180, 0, 192, 100);
  ouvrir;
  controle(1, @rb, @ok, 0);
  s := controle(4, @rs, @titre, 50);            // barre en x 201 à 212, y 31 à 130
  NeoWaitMessage; NeoMessage.params[0] := s; p16(1, 25); appel(36, 5);   // curseur au milieu : y 79 à 82
  for i := 0 to 5 do begin
    NeoWaitMessage;
    wordParams[0] := px[i];
    wordParams[1] := py[i];
    appel(36, 8);                               // Find Control
    c[i] := NeoMessage.params[4];
    z[i] := NeoMessage.params[5];
  end;
  reinit;
  writeln('Bouton : ', c[0], ', ', z[0]);
  writeln('Fleche du haut : ', c[1], ', ', z[1]);
  writeln('Fleche du bas : ', c[2], ', ', z[2]);
  writeln('Page avant : ', c[3], ', ', z[3]);
  writeln('Curseur : ', c[4], ', ', z[4]);
  writeln('Page apres : ', c[5], ', ', z[5]);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Bouton : 1, 1
Fleche du haut : 2, 2
Fleche du bas : 2, 3
Page avant : 2, 4
Curseur : 2, 6
Page apres : 2, 5
NeoBASIC
10 ' Trouver le controle sous un point (groupe 36, fonction 8, Trinity)
20 gosub 7000
30 g = 10 : h = 10 : d = 70 : b = 24 : gosub 8000 : s$ = "OK" : gosub 7900 : ty = 1 : mx = 0 : gosub 7100
40 g = 180 : h = 0 : d = 192 : b = 100 : gosub 8000 : ch = tf : ty = 4 : mx = 50 : gosub 7100 : ba = cn : ' x 201 a 212, y 31 a 130
50 while peek($ff00) : wend : poke $ff04, ba : doke $ff05, 25 : f = 5 : gosub 8110 : ' curseur au milieu : y 79 a 82
60 dim c(5), z(5)
70 for k = 0 to 5 : read x, y
80 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y : f = 8 : gosub 8110 : ' Find Control
90 c(k) = peek($ff08) : z(k) = peek($ff09) : next k
100 data 40, 45, 205, 33, 205, 125, 205, 50, 205, 80, 205, 110
110 gosub 8300
120 for k = 0 to 5 : read n$ : print n$;" : ";c(k);", ";z(k) : next k
130 data "Bouton", "Fleche du haut", "Fleche du bas", "Page avant", "Curseur", "Page apres"
140 end
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Bouton : 1, 1
Fleche du haut : 2, 2
Fleche du bas : 2, 3
Page avant : 2, 4
Curseur : 2, 6
Page apres : 2, 5
Assembleur 65C02 (64tass)
; Trouver le contrôle sous un point (groupe 36, fonction 8, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr ouvrir
        lda #<cb
        ldx #>cb
        jsr controle
        lda #<cs
        ldx #>cs
        jsr controle
        sta s
        jsr WaitMessage
        lda s
        sta ControlPort+4
        lda #25
        sta ControlPort+5
        stz ControlPort+6
        lda #36
        ldx #5                  ; Set Control Value 25 : curseur en y 79 à 82
        jsr appel
        lda #<b0
        ldx #>b0
        jsr envoi
        lda ControlPort+8          ; P4 : contrôle
        sta c0
        lda ControlPort+9          ; P5 : partie
        sta z0
        lda #<b1
        ldx #>b1
        jsr envoi
        lda ControlPort+8          ; P4 : contrôle
        sta c1
        lda ControlPort+9          ; P5 : partie
        sta z1
        lda #<b2
        ldx #>b2
        jsr envoi
        lda ControlPort+8          ; P4 : contrôle
        sta c2
        lda ControlPort+9          ; P5 : partie
        sta z2
        lda #<b3
        ldx #>b3
        jsr envoi
        lda ControlPort+8          ; P4 : contrôle
        sta c3
        lda ControlPort+9          ; P5 : partie
        sta z3
        lda #<b4
        ldx #>b4
        jsr envoi
        lda ControlPort+8          ; P4 : contrôle
        sta c4
        lda ControlPort+9          ; P5 : partie
        sta z4
        lda #<b5
        ldx #>b5
        jsr envoi
        lda ControlPort+8          ; P4 : contrôle
        sta c5
        lda ControlPort+9          ; P5 : partie
        sta z5
        lda #<b6
        ldx #>b6
        jsr envoi
        lda #<t7
        ldx #>t7
        jsr ecrire
        lda c0
        jsr decimal
        lda #<t8
        ldx #>t8
        jsr ecrire
        lda z0
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t9
        ldx #>t9
        jsr ecrire
        lda c1
        jsr decimal
        lda #<t10
        ldx #>t10
        jsr ecrire
        lda z1
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t11
        ldx #>t11
        jsr ecrire
        lda c2
        jsr decimal
        lda #<t12
        ldx #>t12
        jsr ecrire
        lda z2
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t13
        ldx #>t13
        jsr ecrire
        lda c3
        jsr decimal
        lda #<t14
        ldx #>t14
        jsr ecrire
        lda z3
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t15
        ldx #>t15
        jsr ecrire
        lda c4
        jsr decimal
        lda #<t16
        ldx #>t16
        jsr ecrire
        lda z4
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t17
        ldx #>t17
        jsr ecrire
        lda c5
        jsr decimal
        lda #<t18
        ldx #>t18
        jsr ecrire
        lda z5
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

rb:     .word 10, 10, 70, 24
rs:     .word 180, 0, 192, 100
ok:     .byte 2
        .text "OK"
cb:     .byte 1                  ; bouton
        .word rb, ok, 0
cs:     .byte 4                  ; barre en x 201 à 212, y 31 à 130
        .word rs, titre, 50
s:      .byte 0
b0:     .byte 36, 8, 4             ; 36,8 : Find Control
        .word 40, 45
c0:     .byte 0
z0:     .byte 0
b1:     .byte 36, 8, 4             ; 36,8 : Find Control
        .word 205, 33
c1:     .byte 0
z1:     .byte 0
b2:     .byte 36, 8, 4             ; 36,8 : Find Control
        .word 205, 125
c2:     .byte 0
z2:     .byte 0
b3:     .byte 36, 8, 4             ; 36,8 : Find Control
        .word 205, 50
c3:     .byte 0
z3:     .byte 0
b4:     .byte 36, 8, 4             ; 36,8 : Find Control
        .word 205, 80
c4:     .byte 0
z4:     .byte 0
b5:     .byte 36, 8, 4             ; 36,8 : Find Control
        .word 205, 110
c5:     .byte 0
z5:     .byte 0
b6:     .byte 32, 19, 0            ; 32,19 Toolbox Reset
t7:     .text "Bouton : ", 0
t8:     .text ", ", 0
t9:     .text "Fleche du haut : ", 0
t10:    .text ", ", 0
t11:    .text "Fleche du bas : ", 0
t12:    .text ", ", 0
t13:    .text "Page avant : ", 0
t14:    .text ", ", 0
t15:    .text "Curseur : ", 0
t16:    .text ", ", 0
t17:    .text "Page apres : ", 0
t18:    .text ", ", 0

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
        ldx #>raz
        jsr envoi
        lda #<nfen
        ldx #>nfen
        jsr envoi
        lda ControlPort+9
        sta fen
        rts
raz:    .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen:   .byte 34, 1, 5
        .word cadre, titre
        .byte 1
cadre:  .word 20, 20, 220, 140
titre:  .byte 1
        .text "A"                  ; chaînes précédées de leur longueur, lues sur place
fen:    .byte 0

; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
        sta blk
        stx blk+1
        jsr WaitMessage
        ldy #0
        lda (blk),y
        sta ControlPort+4          ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
        lda fen
        sta ControlPort+5          ; P1 : fenêtre
        ldy #1
_ctl:   lda (blk),y
        sta ControlPort+5,y        ; P2-P7 : Rect, titre, maximum
        iny
        cpy #7
        bne _ctl
        lda #36
        ldx #1
        jsr appel
        lda ControlPort+4
        rts

; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        lda #36
        ldx #6
        jsr appel
        lda ControlPort+5
        rts

; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        ldx #4
_sv:    lda pt,x
        sta ControlPort+5,x        ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
        dex
        bpl _sv
        lda #36
        ldx #9
        jsr appel
        lda ControlPort+10
        rts
pt:     .word 0, 0
        .byte 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Bouton : 1, 1
Fleche du haut : 2, 2
Fleche du bas : 2, 3
Page avant : 2, 4
Curseur : 2, 6
Page apres : 2, 5

36,9 Track Control Trinity

Fait suivre la souris à un contrôle : à appeler au clic, à chaque mouvement et au relâchement.

Entrées
OctetsTypeRôle
P0uint8numéro du contrôle
P1-P2int16X de la souris
P3-P4int16Y de la souris
P5uint8phase : 0 bouton enfoncé, 1 mouvement, 2 bouton relâché
Sorties
OctetsTypeRôle
P6uint81 si le contrôle a agi

Un bouton agit s'il est relâché dedans, même après en être sorti ; une case ou un bouton radio au relâchement. Une barre agit quand sa valeur change : flèches de 1 dès l'enfoncement, pages du maximum divisé par 10, curseur au mouvement (glissé de 20 lignes, il passe de 1 à 13). Un champ de texte cliqué reçoit ensuite les touches de 36,10. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Tracks control Parameter:0 from the mouse : Parameters:1,2 (X), Parameters:3,4 (Y), Parameter:5 = phase (0 mouse down, 1 move, 2 mouse up). Parameter:6 is 1 when the control acted : button released inside it (highlighted while the pointer is inside), box toggled or radio set on mouse up, scroll bar value changed (arrows by 1, pages by max/10, thumb dragged), text field clicked (give it the keys with Key Control).

C (llvm-mos)
/* Suivre la souris sur un contrôle (groupe 36, fonction 9, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;

/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A";             /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
    libre();
    api(32, 19);
}
static void ouvrir(void) {                      /* 34,1 : une fenêtre avec barre de titre */
    reinit();
    libre();
    p16(0, (uint16_t)&cadre);
    p16(2, (uint16_t)titre);
    ControlPort.params[4] = 1;
    api(34, 1);
    fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
   au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
    libre();
    ControlPort.params[0] = type;
    ControlPort.params[1] = fenetre;
    p16(2, (uint16_t)r);
    p16(4, (uint16_t)t);
    p16(6, max);
    api(36, 1);
    return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) {             /* 36,6 Get Control Value */
    libre();
    ControlPort.params[0] = c;
    api(36, 6);
    return ControlPort.params[1] | ControlPort.params[2] << 8;
}

static uint8_t suivre(uint8_t c, int16_t x, int16_t y, uint8_t phase) {   /* 36,9 Track Control : 1 si le contrôle a agi */
    libre();
    ControlPort.params[0] = c;
    p16(1, x);
    p16(3, y);
    ControlPort.params[5] = phase;              /* 0 bouton enfoncé, 1 mouvement, 2 bouton relâché */
    api(36, 9);
    return ControlPort.params[6];
}
static uint8_t clic(uint8_t c, int16_t x, int16_t y) {   /* enfoncé puis relâché au même endroit */
    suivre(c, x, y, 0);
    return suivre(c, x, y, 2);
}

static Rect rb = {10, 10, 70, 24}, rs = {180, 0, 192, 100};
static const char ok[] = "\002OK";

int main(void) {
    uint8_t b, s, a1, a2, a3, a4;
    uint16_t v1, v2;
    ouvrir();
    b = controle(1, &rb, ok, 0);
    s = controle(4, &rs, titre, 50);
    suivre(b, 40, 45, 0);                       /* bouton : enfoncé dedans, sorti, relâché dedans */
    suivre(b, 100, 100, 1);
    a1 = suivre(b, 40, 45, 2);
    a2 = suivre(s, 205, 125, 0);                /* flèche du bas : agit dès l'enfoncement, +1 */
    suivre(s, 205, 125, 2);
    v1 = valeur(s);
    suivre(s, 205, 42, 0);                      /* curseur (y 40 à 43 pour la valeur 1), glissé de 20 lignes */
    a3 = suivre(s, 205, 62, 1);
    a4 = suivre(s, 205, 62, 2);
    v2 = valeur(s);
    reinit();
    printf("Bouton : %u ; fleche : %u, valeur %u\n", a1, a2, v1);
    printf("Curseur glisse : %u puis %u, valeur %u\n", a3, a4, v2);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Bouton : 1 ; fleche : 1, valeur 1
Curseur glisse : 1 puis 0, valeur 13
Mad Pascal
// Suivre la souris sur un contrôle (groupe 36, fonction 9, Trinity).
program ct9;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)

// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A'));   // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
    fenetre: byte;

procedure poser(var r: Rect; g, h, d, b: smallint);
begin
  r.g := g; r.h := h; r.d := d; r.b := b;
end;

procedure appel(g, f: byte);                    // appel g,f (paramètres déjà posés)
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
  NeoWaitMessage;
  appel(32, 19);
end;

procedure ouvrir;                               // 34,1 : une fenêtre avec barre de titre
begin
  reinit;
  poser(cadre, 20, 20, 220, 140);
  wordParams[0] := word(@cadre);
  wordParams[1] := word(@titre);
  NeoMessage.params[4] := 1;
  appel(34, 1);
  fenetre := NeoMessage.params[5];
end;

// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := t;
  NeoMessage.params[1] := fenetre;
  wordParams[1] := word(r);
  wordParams[2] := word(s);
  wordParams[3] := max;
  appel(36, 1);
  result := NeoMessage.params[0];
end;

function valeur(c: byte): word;                 // 36,6 Get Control Value
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  appel(36, 6);
  result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

function suivre(c: byte; x, y: smallint; phase: byte): byte;   // 36,9 Track Control : 1 si le contrôle a agi
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  p16(1, word(x));
  p16(3, word(y));
  NeoMessage.params[5] := phase;                // 0 bouton enfoncé, 1 mouvement, 2 bouton relâché
  appel(36, 9);
  result := NeoMessage.params[6];
end;

function clic(c: byte; x, y: smallint): byte;   // enfoncé puis relâché au même endroit
begin
  suivre(c, x, y, 0);
  result := suivre(c, x, y, 2);
end;

const ok: array[0..2] of byte = (2, ord('O'), ord('K'));
var rb, rs: Rect;
    b, s, a1, a2, a3, a4: byte;
    v1, v2: word;
begin
  poser(rb, 10, 10, 70, 24); poser(rs, 180, 0, 192, 100);
  ouvrir;
  b := controle(1, @rb, @ok, 0);
  s := controle(4, @rs, @titre, 50);
  suivre(b, 40, 45, 0);                         // bouton : enfoncé dedans, sorti, relâché dedans
  suivre(b, 100, 100, 1);
  a1 := suivre(b, 40, 45, 2);
  a2 := suivre(s, 205, 125, 0);                 // flèche du bas : agit dès l'enfoncement, +1
  suivre(s, 205, 125, 2);
  v1 := valeur(s);
  suivre(s, 205, 42, 0);                        // curseur (y 40 à 43 pour la valeur 1), glissé de 20 lignes
  a3 := suivre(s, 205, 62, 1);
  a4 := suivre(s, 205, 62, 2);
  v2 := valeur(s);
  reinit;
  writeln('Bouton : ', a1, ' ; fleche : ', a2, ', valeur ', v1);
  writeln('Curseur glisse : ', a3, ' puis ', a4, ', valeur ', v2);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Bouton : 1 ; fleche : 1, valeur 1
Curseur glisse : 1 puis 0, valeur 13
NeoBASIC
10 ' Suivre la souris sur un controle (groupe 36, fonction 9, Trinity)
20 gosub 7000
30 g = 10 : h = 10 : d = 70 : b = 24 : gosub 8000 : s$ = "OK" : gosub 7900 : ty = 1 : mx = 0 : gosub 7100 : bt = cn
40 g = 180 : h = 0 : d = 192 : b = 100 : gosub 8000 : ch = tf : ty = 4 : mx = 50 : gosub 7100 : ba = cn
50 c = bt : x = 40 : y = 45 : ph = 0 : gosub 7300 : ' bouton : enfonce dedans, sorti, relache dedans
60 x = 100 : y = 100 : ph = 1 : gosub 7300
70 x = 40 : y = 45 : ph = 2 : gosub 7300 : a1 = ag
80 c = ba : x = 205 : y = 125 : ph = 0 : gosub 7300 : a2 = ag : ' fleche du bas : agit des l'enfoncement, +1
90 ph = 2 : gosub 7300 : gosub 7200 : v1 = v
100 y = 42 : ph = 0 : gosub 7300 : ' curseur (y 40 a 43 pour la valeur 1), glisse de 20 lignes
110 y = 62 : ph = 1 : gosub 7300 : a3 = ag
120 ph = 2 : gosub 7300 : a4 = ag : gosub 7200 : v2 = v
130 gosub 8300
140 print "Bouton : ";a1;" ; fleche : ";a2;", valeur ";v1
150 print "Curseur glisse : ";a3;" puis ";a4;", valeur ";v2
160 end
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Bouton : 1 ; fleche : 1, valeur 1
Curseur glisse : 1 puis 0, valeur 13
Assembleur 65C02 (64tass)
; Suivre la souris sur un contrôle (groupe 36, fonction 9, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr ouvrir
        lda #<cb
        ldx #>cb
        jsr controle
        sta b
        lda #<cs
        ldx #>cs
        jsr controle
        sta s
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #45
        sta pt+2
        stz pt+3
        lda #0                  ; bouton : enfoncé dedans...
        sta pt+4
        lda b
        jsr suivre
        lda #<100
        sta pt
        lda #>100
        sta pt+1
        lda #100
        sta pt+2
        stz pt+3
        lda #1                  ; ... sorti...
        sta pt+4
        lda b
        jsr suivre
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #45
        sta pt+2
        stz pt+3
        lda #2                  ; ... relâché dedans
        sta pt+4
        lda b
        jsr suivre
        sta a1
        lda #<205
        sta pt
        lda #>205
        sta pt+1
        lda #125
        sta pt+2
        stz pt+3
        lda #0                  ; flèche du bas : agit dès l'enfoncement, +1
        sta pt+4
        lda s
        jsr suivre
        sta a2
        lda #<205
        sta pt
        lda #>205
        sta pt+1
        lda #125
        sta pt+2
        stz pt+3
        lda #2                  ; relâché
        sta pt+4
        lda s
        jsr suivre
        lda s
        jsr valeur
        sta v1
        lda #<205
        sta pt
        lda #>205
        sta pt+1
        lda #42
        sta pt+2
        stz pt+3
        lda #0                  ; curseur (y 40 à 43 pour la valeur 1)...
        sta pt+4
        lda s
        jsr suivre
        lda #<205
        sta pt
        lda #>205
        sta pt+1
        lda #62
        sta pt+2
        stz pt+3
        lda #1                  ; ... glissé de 20 lignes
        sta pt+4
        lda s
        jsr suivre
        sta a3
        lda #<205
        sta pt
        lda #>205
        sta pt+1
        lda #62
        sta pt+2
        stz pt+3
        lda #2                  ; relâché
        sta pt+4
        lda s
        jsr suivre
        sta a4
        lda s
        jsr valeur
        sta v2
        lda #<b0
        ldx #>b0
        jsr envoi
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda a1
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda a2
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda v1
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda a3
        jsr decimal
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda a4
        jsr decimal
        lda #<t6
        ldx #>t6
        jsr ecrire
        lda v2
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

rb:     .word 10, 10, 70, 24
rs:     .word 180, 0, 192, 100
ok:     .byte 2
        .text "OK"
cb:     .byte 1                  ; bouton
        .word rb, ok, 0
b:      .byte 0
cs:     .byte 4                  ; barre, maximum 50
        .word rs, titre, 50
s:      .byte 0
a1:     .byte 0
a2:     .byte 0
v1:     .byte 0
a3:     .byte 0
a4:     .byte 0
v2:     .byte 0
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset
t1:     .text "Bouton : ", 0
t2:     .text " ; fleche : ", 0
t3:     .text ", valeur ", 0
t4:     .text "Curseur glisse : ", 0
t5:     .text " puis ", 0
t6:     .text ", valeur ", 0

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
        ldx #>raz
        jsr envoi
        lda #<nfen
        ldx #>nfen
        jsr envoi
        lda ControlPort+9
        sta fen
        rts
raz:    .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen:   .byte 34, 1, 5
        .word cadre, titre
        .byte 1
cadre:  .word 20, 20, 220, 140
titre:  .byte 1
        .text "A"                  ; chaînes précédées de leur longueur, lues sur place
fen:    .byte 0

; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
        sta blk
        stx blk+1
        jsr WaitMessage
        ldy #0
        lda (blk),y
        sta ControlPort+4          ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
        lda fen
        sta ControlPort+5          ; P1 : fenêtre
        ldy #1
_ctl:   lda (blk),y
        sta ControlPort+5,y        ; P2-P7 : Rect, titre, maximum
        iny
        cpy #7
        bne _ctl
        lda #36
        ldx #1
        jsr appel
        lda ControlPort+4
        rts

; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        lda #36
        ldx #6
        jsr appel
        lda ControlPort+5
        rts

; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        ldx #4
_sv:    lda pt,x
        sta ControlPort+5,x        ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
        dex
        bpl _sv
        lda #36
        ldx #9
        jsr appel
        lda ControlPort+10
        rts
pt:     .word 0, 0
        .byte 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Bouton : 1 ; fleche : 1, valeur 1
Curseur glisse : 1 puis 0, valeur 13

36,10 Key Control Trinity

Envoie une touche à un champ de texte.

Entrées
OctetsTypeRôle
P0uint8numéro du contrôle
P1uint8caractère ; 8 ou 127 efface le dernier
Sorties
OctetsTypeRôle
P2uint81 si le tampon a changé

Le tampon est la chaîne précédée de sa longueur donnée à 36,1, en RAM du 6502 : le programme y lit le texte. Un caractère au-delà de la longueur maximale est refusé. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Sends the key Parameter:1 to text field Parameter:0 : printable characters are appended to its buffer (up to the maximum length), 8 or 127 deletes the last one ; Parameter:2 is 1 if the buffer changed. The buffer is the length-prefixed string given to New Control, in 6502 RAM.

C (llvm-mos)
/* Envoyer une touche à un champ de texte (groupe 36, fonction 10, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;

/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A";             /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
    libre();
    api(32, 19);
}
static void ouvrir(void) {                      /* 34,1 : une fenêtre avec barre de titre */
    reinit();
    libre();
    p16(0, (uint16_t)&cadre);
    p16(2, (uint16_t)titre);
    ControlPort.params[4] = 1;
    api(34, 1);
    fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
   au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
    libre();
    ControlPort.params[0] = type;
    ControlPort.params[1] = fenetre;
    p16(2, (uint16_t)r);
    p16(4, (uint16_t)t);
    p16(6, max);
    api(36, 1);
    return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) {             /* 36,6 Get Control Value */
    libre();
    ControlPort.params[0] = c;
    api(36, 6);
    return ControlPort.params[1] | ControlPort.params[2] << 8;
}

static uint8_t suivre(uint8_t c, int16_t x, int16_t y, uint8_t phase) {   /* 36,9 Track Control : 1 si le contrôle a agi */
    libre();
    ControlPort.params[0] = c;
    p16(1, x);
    p16(3, y);
    ControlPort.params[5] = phase;              /* 0 bouton enfoncé, 1 mouvement, 2 bouton relâché */
    api(36, 9);
    return ControlPort.params[6];
}
static uint8_t clic(uint8_t c, int16_t x, int16_t y) {   /* enfoncé puis relâché au même endroit */
    suivre(c, x, y, 0);
    return suivre(c, x, y, 2);
}

static Rect rt = {10, 70, 150, 84};
static char tampon[5] = "\002ab";               /* longueur, puis le texte ; maximum 4 caractères */

static uint8_t touche(uint8_t c, uint8_t k) {   /* Key Control : 1 si le tampon a changé */
    libre();
    ControlPort.params[0] = c;
    ControlPort.params[1] = k;
    api(36, 10);
    return ControlPort.params[2];
}
static void afficher(void) {
    uint8_t i;
    for (i = 1; i <= tampon[0]; i++)
        putchar(tampon[i]);
    putchar('\n');
}

int main(void) {
    uint8_t t, x, y, z;
    ouvrir();
    t = controle(5, &rt, tampon, 4);
    clic(t, 40, 105);                           /* le champ est cliqué */
    x = touche(t, 'X');
    y = touche(t, 'Y');
    z = touche(t, 'Z');                         /* plein : refusé */
    reinit();
    printf("X : %u, Y : %u, Z : %u -> ", x, y, z);
    afficher();
    ouvrir();
    t = controle(5, &rt, tampon, 4);
    touche(t, 8);                               /* 8 (ou 127) efface le dernier caractère */
    reinit();
    printf("Effacement -> ");
    afficher();
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
X : 1, Y : 1, Z : 0 -> abXY
Effacement -> abX
Mad Pascal
// Envoyer une touche à un champ de texte (groupe 36, fonction 10, Trinity).
program ct10;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)

// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A'));   // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
    fenetre: byte;

procedure poser(var r: Rect; g, h, d, b: smallint);
begin
  r.g := g; r.h := h; r.d := d; r.b := b;
end;

procedure appel(g, f: byte);                    // appel g,f (paramètres déjà posés)
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
  NeoWaitMessage;
  appel(32, 19);
end;

procedure ouvrir;                               // 34,1 : une fenêtre avec barre de titre
begin
  reinit;
  poser(cadre, 20, 20, 220, 140);
  wordParams[0] := word(@cadre);
  wordParams[1] := word(@titre);
  NeoMessage.params[4] := 1;
  appel(34, 1);
  fenetre := NeoMessage.params[5];
end;

// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := t;
  NeoMessage.params[1] := fenetre;
  wordParams[1] := word(r);
  wordParams[2] := word(s);
  wordParams[3] := max;
  appel(36, 1);
  result := NeoMessage.params[0];
end;

function valeur(c: byte): word;                 // 36,6 Get Control Value
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  appel(36, 6);
  result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

function suivre(c: byte; x, y: smallint; phase: byte): byte;   // 36,9 Track Control : 1 si le contrôle a agi
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  p16(1, word(x));
  p16(3, word(y));
  NeoMessage.params[5] := phase;                // 0 bouton enfoncé, 1 mouvement, 2 bouton relâché
  appel(36, 9);
  result := NeoMessage.params[6];
end;

function clic(c: byte; x, y: smallint): byte;   // enfoncé puis relâché au même endroit
begin
  suivre(c, x, y, 0);
  result := suivre(c, x, y, 2);
end;

var tampon: array[0..4] of byte = (2, ord('a'), ord('b'), 0, 0);   // longueur, puis le texte ; maximum 4 caractères
    rt: Rect;
    t, x, y, z: byte;

function touche(c, k: byte): byte;              // Key Control : 1 si le tampon a changé
begin
  NeoWaitMessage;
  NeoMessage.params[0] := c;
  NeoMessage.params[1] := k;
  appel(36, 10);
  result := NeoMessage.params[2];
end;

procedure afficher;
var i: byte;
begin
  for i := 1 to tampon[0] do write(chr(tampon[i]));
  writeln;
end;

begin
  poser(rt, 10, 70, 150, 84);
  ouvrir;
  t := controle(5, @rt, @tampon, 4);
  clic(t, 40, 105);                             // le champ est cliqué
  x := touche(t, ord('X'));
  y := touche(t, ord('Y'));
  z := touche(t, ord('Z'));                     // plein : refusé
  reinit;
  write('X : ', x, ', Y : ', y, ', Z : ', z, ' -> ');
  afficher;
  ouvrir;
  t := controle(5, @rt, @tampon, 4);
  touche(t, 8);                                 // 8 (ou 127) efface le dernier caractère
  reinit;
  write('Effacement -> ');
  afficher;
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
X : 1, Y : 1, Z : 0 -> abXY
Effacement -> abX
NeoBASIC
10 ' Envoyer une touche a un champ de texte (groupe 36, fonction 10, Trinity)
20 tp = alloc(5) : poke tp, 2 : poke tp + 1, asc("a") : poke tp + 2, asc("b") : ' longueur, puis le texte ; maximum 4
30 gosub 7000
40 g = 10 : h = 70 : d = 150 : b = 84 : gosub 8000 : rt = q : ch = tp : ty = 5 : mx = 4 : gosub 7100 : c = cn
50 x = 40 : y = 105 : gosub 7400 : ' le champ est clique
60 k = asc("X") : gosub 2000 : kx = kc
70 k = asc("Y") : gosub 2000 : ky = kc
80 k = asc("Z") : gosub 2000 : kz = kc : ' plein : refuse
90 gosub 8300
100 print "X : ";kx;", Y : ";ky;", Z : ";kz;" -> ";
110 gosub 3000
120 gosub 7000 : q = rt : ch = tp : ty = 5 : mx = 4 : gosub 7100 : c = cn
130 k = 8 : gosub 2000 : ' 8 (ou 127) efface le dernier caractere
140 gosub 8300
150 print "Effacement -> "; : gosub 3000
160 end
2000 ' Key Control : touche k au champ c ; kc = 1 si le tampon a change
2010 while peek($ff00) : wend : poke $ff04, c : poke $ff05, k : f = 10 : gosub 8110 : kc = peek($ff06) : return
3000 for i = 1 to peek(tp) : print chr$(peek(tp + i)); : next i : print : return
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
X : 1, Y : 1, Z : 0 -> abXY
Effacement -> abX
Assembleur 65C02 (64tass)
; Envoyer une touche à un champ de texte (groupe 36, fonction 10, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr ouvrir
        lda #<ct
        ldx #>ct
        jsr controle
        sta t
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #105
        sta pt+2
        stz pt+3
        lda #0                  ; le champ est cliqué
        sta pt+4
        lda t
        jsr suivre
        lda #<40
        sta pt
        lda #>40
        sta pt+1
        lda #105
        sta pt+2
        stz pt+3
        lda #2                  ; relâché
        sta pt+4
        lda t
        jsr suivre
        jsr WaitMessage
        lda t
        sta ControlPort+4
        lda #'X'
        sta ControlPort+5
        lda #36
        ldx #10                 ; Key Control
        jsr appel
        lda ControlPort+6          ; P2 : 1 si le tampon a changé
        sta x
        jsr WaitMessage
        lda t
        sta ControlPort+4
        lda #'Y'
        sta ControlPort+5
        lda #36
        ldx #10                 ; Key Control
        jsr appel
        lda ControlPort+6          ; P2 : 1 si le tampon a changé
        sta y
        jsr WaitMessage
        lda t
        sta ControlPort+4
        lda #'Z'
        sta ControlPort+5
        lda #36
        ldx #10                 ; plein : refusé
        jsr appel
        lda ControlPort+6          ; P2 : 1 si le tampon a changé
        sta z
        lda #<b0
        ldx #>b0
        jsr envoi
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda x
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda y
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda z
        jsr decimal
        lda #<t4
        ldx #>t4
        jsr ecrire
        jsr afficher
        jsr ouvrir
        lda #<ct
        ldx #>ct
        jsr controle
        sta t
        jsr WaitMessage
        lda t
        sta ControlPort+4
        lda #8
        sta ControlPort+5
        lda #36
        ldx #10                 ; 8 (ou 127) efface le dernier caractère
        jsr appel
        lda #<b5
        ldx #>b5
        jsr envoi
        lda #<t6
        ldx #>t6
        jsr ecrire
        jsr afficher
        rts

rt:     .word 10, 70, 150, 84
tampon: .byte 2                    ; longueur, puis le texte ; maximum 4 caractères
        .text "ab"
        .fill 2
ct:     .byte 5                  ; champ de texte, maximum 4
        .word rt, tampon, 4
t:      .byte 0
x:      .byte 0
y:      .byte 0
z:      .byte 0
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset
t1:     .text "X : ", 0
t2:     .text ", Y : ", 0
t3:     .text ", Z : ", 0
t4:     .text " -> ", 0
b5:     .byte 32, 19, 0            ; 32,19 Toolbox Reset
t6:     .text "Effacement -> ", 0

; Affiche le tampon (chaîne précédée de sa longueur), puis passe à la ligne.
afficher:
        ldx #0
_af:    cpx tampon
        beq _fa
        lda tampon+1,x
        jsr WriteCharacter
        inx
        bra _af
_fa:    lda #13
        jmp WriteCharacter

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
        ldx #>raz
        jsr envoi
        lda #<nfen
        ldx #>nfen
        jsr envoi
        lda ControlPort+9
        sta fen
        rts
raz:    .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen:   .byte 34, 1, 5
        .word cadre, titre
        .byte 1
cadre:  .word 20, 20, 220, 140
titre:  .byte 1
        .text "A"                  ; chaînes précédées de leur longueur, lues sur place
fen:    .byte 0

; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
        sta blk
        stx blk+1
        jsr WaitMessage
        ldy #0
        lda (blk),y
        sta ControlPort+4          ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
        lda fen
        sta ControlPort+5          ; P1 : fenêtre
        ldy #1
_ctl:   lda (blk),y
        sta ControlPort+5,y        ; P2-P7 : Rect, titre, maximum
        iny
        cpy #7
        bne _ctl
        lda #36
        ldx #1
        jsr appel
        lda ControlPort+4
        rts

; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        lda #36
        ldx #6
        jsr appel
        lda ControlPort+5
        rts

; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        ldx #4
_sv:    lda pt,x
        sta ControlPort+5,x        ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
        dex
        bpl _sv
        lda #36
        ldx #9
        jsr appel
        lda ControlPort+10
        rts
pt:     .word 0, 0
        .byte 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
X : 1, Y : 1, Z : 0 -> abXY
Effacement -> abX

← L'API du Neo6502