Tachibana
Langue : français

Groupe 35 — Gestionnaire de menus Trinity

35,1 New Menu · 35,2 Draw Menu Bar · 35,3 Menu Select · 35,4 Menu Track · 35,5 Menu Track End · 35,6 Set Item Flags · 35,7 Dispose Menu · 35,8 Get Item Flags · 35,9 Set Menu Bar Bounds · 35,10 Menu Key

Le gestionnaire de menus de la boîte à outils de Trinity tient une barre de menus en haut de l'écran (12 lignes) et jusqu'à 6 menus déroulants, décrits par des descripteurs en RAM du 6502.

À la souris : 35,3 sur un clic, 35,4 à chaque mouvement, 35,5 au relâchement. Au clavier : 35,10 avec le code de chaque touche. Les exemples appellent ces fonctions avec des coordonnées et des codes de touches fixes, sans souris ni clavier réels, et remettent la boîte à outils à zéro avec 32,19 au début et à la fin.

Les deux menus des exemples : « Fichier » (Ouvrir, Fermer inactif, un séparateur, Quitter) et « Edition » (Copier coché, Coller).

35,1 New Menu Trinity

Ajoute un menu à la barre des menus, à partir d'un descripteur en RAM du 6502, et rend son numéro.

Entrées
OctetsTypeRôle
P0-P1addradresse du descripteur (lu sur place)
Sorties
OctetsTypeRôle
P2uint8numéro du menu (1 à 6)
erreuruint82 s'il ne reste plus de menu libre

Descripteur : titre précédé de sa longueur, puis jusqu'à 16 articles, chacun un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) suivi de son texte précédé de sa longueur (31 caractères au plus), enfin l'octet $FF. Il doit rester intact : le firmware le relit et y écrit (35,6). La barre occupe les 12 premières lignes de l'écran (fond blanc, titres noirs en police 6 × 8) ; les fenêtres doivent rester dessous. Au banc, le septième menu est refusé. 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). Adds a menu to the menu bar from the descriptor at Parameters:0,1 in 6502 RAM and returns its number (1-6) in Parameter:2 (error 2 if none left). The descriptor is read in place and must stay intact : a length-prefixed title, then up to 16 items, each a flags byte (bit 0 disabled, bit 1 checked, bit 7 separator) followed by a length-prefixed text (31 characters at most), ended by a $FF byte. The menu bar (12 lines at the top of the screen, titles in the 6x8 font) is redrawn ; keep windows below it.

C (llvm-mos)
/* Ajouter un menu à la barre (groupe 35, 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)
        ;
}

/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
   un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
    0, 6, 'O', 'u', 'v', 'r', 'i', 'r',           /* article 1 */
    1, 6, 'F', 'e', 'r', 'm', 'e', 'r',           /* article 2, inactif */
    0x80, 0,                                    /* article 3 : séparateur */
    0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF };   /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
    2, 6, 'C', 'o', 'p', 'i', 'e', 'r',           /* coché */
    0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };

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 uint8_t nouveau(uint8_t *menu) {         /* 35,1 New Menu : rend le numéro */
    libre();
    p16(0, (uint16_t)menu);
    api(35, 1);
    return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) {   /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
    libre();
    p16(0, x);
    p16(2, y);
    api(35, f);
    return ControlPort.params[4];               /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) {                         /* 35,5 Menu Track End : menu et article choisis */
    libre();
    api(35, 5);
    choix_menu = ControlPort.params[0];
    choix_article = ControlPort.params[1];
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus aucun menu */
    libre();
    api(32, 19);
}

int main(void) {
    uint8_t a, b, i, e;
    reinit();
    a = nouveau(fichier);
    b = nouveau(edition);
    for (i = 0; i < 5; i++)                     /* menus 3 à 6, puis un septième */
        nouveau(edition);
    e = ControlPort.error;
    reinit();
    printf("Menus : %u et %u ; septieme : erreur %u\n", a, b, e);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Menus : 1 et 2 ; septieme : erreur 2
Mad Pascal
// Ajouter un menu à la barre (groupe 35, fonction 1, Trinity).
program mn1;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
        0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'),          // article 1
        1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'),          // article 2, inactif
        $80, 0,                                                                     // article 3 : séparateur
        0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF);   // article 4
    edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
        2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'),          // coché
        0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);

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

function nouveau(menu: pointer): byte;          // 35,1 New Menu : rend le numéro
begin
  NeoWaitMessage;
  wordParams[0] := word(menu);
  appel(1);
  result := NeoMessage.params[2];
end;

function point(f: byte; x, y: smallint): byte;  // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
  NeoWaitMessage;
  wordParams[0] := word(x);
  wordParams[1] := word(y);
  appel(f);
  result := NeoMessage.params[4];               // 35,3 : menu déroulé, 0 si aucun titre touché
end;

var choix_menu, choix_article: byte;

procedure fin;                                  // 35,5 Menu Track End : menu et article choisis
begin
  NeoWaitMessage;
  appel(5);
  choix_menu := NeoMessage.params[0];
  choix_article := NeoMessage.params[1];
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus aucun menu
begin
  NeoWaitMessage;
  NeoSendMessage(32, 19);
  NeoWaitMessage;
end;

var a, b, i, e: byte;
begin
  reinit;
  a := nouveau(@fichier);
  b := nouveau(@edition);
  for i := 1 to 5 do nouveau(@edition);         // menus 3 à 6, puis un septième
  e := NeoMessage.error;
  reinit;
  writeln('Menus : ', a, ' et ', b, ' ; septieme : erreur ', e);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Menus : 1 et 2 ; septieme : erreur 2
NeoBASIC
10 ' Ajouter un menu a la barre (groupe 35, fonction 1, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000 : a = mn
40 q = ed : gosub 8000 : b = mn
50 for k = 1 to 5 : gosub 8000 : next k : ' menus 3 a 6, puis un septieme
60 e7 = e : gosub 8300
70 print "Menus : ";a;" et ";b;" ; septieme : erreur ";e7
80 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
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 :
Menus : 1 et 2 ; septieme : erreur 2
Assembleur 65C02 (64tass)
; Ajouter un menu à la barre (groupe 35, 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:  lda #<b0
        ldx #>b0
        jsr envoi
        lda #<b1
        ldx #>b1
        jsr envoi
        lda ControlPort+6          ; P2 : numéro du menu
        sta a
        lda #<b2
        ldx #>b2
        jsr envoi
        lda ControlPort+6          ; P2 : numéro du menu
        sta b
        ldx #5                     ; menus 3 à 6, puis un septième
_n:     phx
        lda #<b2
        ldx #>b2
        jsr envoi
        plx
        dex
        bne _n
        lda ControlPort+2
        sta e
        lda #<b3
        ldx #>b3
        jsr envoi
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda a
        jsr decimal
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda b
        jsr decimal
        lda #<t6
        ldx #>t6
        jsr ecrire
        lda e
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
        .text "Fichier"
        .byte 0, 6
        .text "Ouvrir"             ; article 1
fermer: .byte 1, 6
        .text "Fermer"             ; article 2, inactif
        .byte $80, 0               ; article 3 : séparateur
        .byte 0, 7
        .text "Quitter"            ; article 4
        .byte $FF
edition: .byte 7
        .text "Edition"
        .byte 2, 6
        .text "Copier"             ; coché
        .byte 0, 6
        .text "Coller"
        .byte $FF
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
b1:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word fichier
a:      .byte 0
b2:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word edition
b:      .byte 0
e:      .byte 0
b3:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
t4:     .text "Menus : ", 0
t5:     .text " et ", 0
t6:     .text " ; septieme : 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

; 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 :
Menus : 1 et 2 ; septieme : erreur 2

35,2 Draw Menu Bar Trinity

Redessine la barre des menus, par exemple après que le programme a dessiné dessus.

Entrées : aucune.

Sorties : aucune.

L'exemple peint la barre en couleur 4 avec 32,8, puis la fait redessiner : le fond redevient blanc (15). NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Redraws the menu bar (after the program drew over it, for instance).

C (llvm-mos)
/* Redessiner la barre des menus (groupe 35, 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)
        ;
}

/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
   un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
    0, 6, 'O', 'u', 'v', 'r', 'i', 'r',           /* article 1 */
    1, 6, 'F', 'e', 'r', 'm', 'e', 'r',           /* article 2, inactif */
    0x80, 0,                                    /* article 3 : séparateur */
    0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF };   /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
    2, 6, 'C', 'o', 'p', 'i', 'e', 'r',           /* coché */
    0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };

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 uint8_t nouveau(uint8_t *menu) {         /* 35,1 New Menu : rend le numéro */
    libre();
    p16(0, (uint16_t)menu);
    api(35, 1);
    return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) {   /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
    libre();
    p16(0, x);
    p16(2, y);
    api(35, f);
    return ControlPort.params[4];               /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) {                         /* 35,5 Menu Track End : menu et article choisis */
    libre();
    api(35, 5);
    choix_menu = ControlPort.params[0];
    choix_article = ControlPort.params[1];
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus aucun menu */
    libre();
    api(32, 19);
}

typedef struct { int16_t g, h, d, b; } Rect;
static Rect barre = {0, 0, 320, 12};

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];
}

int main(void) {
    uint8_t p1, p2, p3, t;
    reinit();
    nouveau(fichier);
    p1 = pixel(1, 2);                           /* fond de la barre */
    t = pixel(5, 2);                            /* texte du titre */
    libre(); ControlPort.params[0] = 4; api(32, 4);
    libre(); p16(0, (uint16_t)&barre); api(32, 8);   /* le programme peint par-dessus la barre */
    p2 = pixel(1, 2);
    libre(); api(35, 2);                        /* Draw Menu Bar */
    p3 = pixel(1, 2);
    reinit();
    printf("Barre : %u (titre %u), peinte : %u, redessinee : %u\n", p1, t, p2, p3);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Barre : 15 (titre 0), peinte : 4, redessinee : 15
Mad Pascal
// Redessiner la barre des menus (groupe 35, fonction 2, Trinity).
program mn2;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
        0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'),          // article 1
        1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'),          // article 2, inactif
        $80, 0,                                                                     // article 3 : séparateur
        0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF);   // article 4
    edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
        2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'),          // coché
        0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);

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

function nouveau(menu: pointer): byte;          // 35,1 New Menu : rend le numéro
begin
  NeoWaitMessage;
  wordParams[0] := word(menu);
  appel(1);
  result := NeoMessage.params[2];
end;

function point(f: byte; x, y: smallint): byte;  // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
  NeoWaitMessage;
  wordParams[0] := word(x);
  wordParams[1] := word(y);
  appel(f);
  result := NeoMessage.params[4];               // 35,3 : menu déroulé, 0 si aucun titre touché
end;

var choix_menu, choix_article: byte;

procedure fin;                                  // 35,5 Menu Track End : menu et article choisis
begin
  NeoWaitMessage;
  appel(5);
  choix_menu := NeoMessage.params[0];
  choix_article := NeoMessage.params[1];
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus aucun menu
begin
  NeoWaitMessage;
  NeoSendMessage(32, 19);
  NeoWaitMessage;
end;

type Rect = record g, h, d, b: smallint; end;
var barre: Rect;
    p1, p2, p3, t: byte;
begin
  barre.g := 0; barre.h := 0; barre.d := 320; barre.b := 12;
  reinit;
  nouveau(@fichier);
  p1 := NeoGetPixel(1, 2);                      // fond de la barre
  t := NeoGetPixel(5, 2);                       // texte du titre
  NeoWaitMessage;
  NeoMessage.params[0] := 4;
  NeoSendMessage(32, 4);
  NeoWaitMessage;
  wordParams[0] := word(@barre);
  NeoSendMessage(32, 8);                        // le programme peint par-dessus la barre
  NeoWaitMessage;
  p2 := NeoGetPixel(1, 2);
  appel(2);                                     // Draw Menu Bar
  p3 := NeoGetPixel(1, 2);
  reinit;
  writeln('Barre : ', p1, ' (titre ', t, '), peinte : ', p2, ', redessinee : ', p3);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Barre : 15 (titre 0), peinte : 4, redessinee : 15
NeoBASIC
10 ' Redessiner la barre des menus (groupe 35, fonction 2, Trinity)
15 gosub 7000
20 ba = alloc(8) : doke ba, 0 : doke ba + 2, 0 : doke ba + 4, 320 : doke ba + 6, 12
30 gosub 8300
40 q = fi : gosub 8000
50 p1 = point(1, 2) : t = point(5, 2) : ' fond de la barre, texte du titre
60 while peek($ff00) : wend : poke $ff04, 4 : poke $ff01, 4 : poke $ff00, 32
70 while peek($ff00) : wend : doke $ff04, ba : poke $ff01, 8 : poke $ff00, 32 : ' le programme peint par-dessus la barre
80 while peek($ff00) : wend : p2 = point(1, 2)
90 f = 2 : gosub 8110 : ' Draw Menu Bar
100 p3 = point(1, 2)
110 gosub 8300
120 print "Barre : ";p1;" (titre ";t;"), peinte : ";p2;", redessinee : ";p3
130 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
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 :
Barre : 15 (titre 0), peinte : 4, redessinee : 15
Assembleur 65C02 (64tass)
; Redessiner la barre des menus (groupe 35, 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:  lda #<b0
        ldx #>b0
        jsr envoi
        lda #<b1
        ldx #>b1
        jsr envoi
        lda #1
        ldy #2
        jsr pixel
        sta p1
        lda #5
        ldy #2
        jsr pixel
        sta t
        lda #<b2
        ldx #>b2
        jsr envoi
        lda #<b3
        ldx #>b3
        jsr envoi
        lda #1
        ldy #2
        jsr pixel
        sta p2
        lda #<b4
        ldx #>b4
        jsr envoi
        lda #1
        ldy #2
        jsr pixel
        sta p3
        lda #<b5
        ldx #>b5
        jsr envoi
        lda #<t6
        ldx #>t6
        jsr ecrire
        lda p1
        jsr decimal
        lda #<t7
        ldx #>t7
        jsr ecrire
        lda t
        jsr decimal
        lda #<t8
        ldx #>t8
        jsr ecrire
        lda p2
        jsr decimal
        lda #<t9
        ldx #>t9
        jsr ecrire
        lda p3
        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

; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
        .text "Fichier"
        .byte 0, 6
        .text "Ouvrir"             ; article 1
fermer: .byte 1, 6
        .text "Fermer"             ; article 2, inactif
        .byte $80, 0               ; article 3 : séparateur
        .byte 0, 7
        .text "Quitter"            ; article 4
        .byte $FF
edition: .byte 7
        .text "Edition"
        .byte 2, 6
        .text "Copier"             ; coché
        .byte 0, 6
        .text "Coller"
        .byte $FF
barre:  .word 0, 0, 320, 12
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
b1:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word fichier
p1:     .byte 0
t:      .byte 0
b2:     .byte 32, 4, 1, 4          ; 32,4 : couleur 4
b3:     .byte 32, 8, 2             ; 32,8 : le programme peint par-dessus la barre
        .word barre
p2:     .byte 0
b4:     .byte 35, 2, 0             ; Draw Menu Bar
p3:     .byte 0
b5:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
t6:     .text "Barre : ", 0
t7:     .text " (titre ", 0
t8:     .text "), peinte : ", 0
t9:     .text ", redessinee : ", 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

; 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 :
Barre : 15 (titre 0), peinte : 4, redessinee : 15

35,3 Menu Select Trinity

À appeler sur un clic : si un titre de menu est touché, déroule ce menu et rend son numéro.

Entrées
OctetsTypeRôle
P0-P1int16X de la souris
P2-P3int16Y de la souris
Sorties
OctetsTypeRôle
P4uint8menu déroulé (0 si aucun titre touché)

Le programme appelle ensuite 35,4 à chaque mouvement de la souris et 35,5 au relâchement du bouton. Rien n'est sauvé sous le menu déroulé : à sa fermeture, la zone est effacée et les fenêtres qu'il couvrait reçoivent un événement de mise à jour (groupe 33). Au banc, « Fichier » occupe x 0 à 49 et « Edition » x 54 à 103. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

To call on a mouse down at Parameters:0,1 (X), Parameters:2,3 (Y) : if a menu title is hit, the menu is pulled down and its number returned in Parameter:4 (0 otherwise). The program then calls Menu Track on every mouse move and Menu Track End on the mouse up. Nothing is saved under the pull-down : when it closes, the area is erased and the windows it covered get an update event (group 33).

C (llvm-mos)
/* Dérouler un menu sur un clic (groupe 35, 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)
        ;
}

/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
   un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
    0, 6, 'O', 'u', 'v', 'r', 'i', 'r',           /* article 1 */
    1, 6, 'F', 'e', 'r', 'm', 'e', 'r',           /* article 2, inactif */
    0x80, 0,                                    /* article 3 : séparateur */
    0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF };   /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
    2, 6, 'C', 'o', 'p', 'i', 'e', 'r',           /* coché */
    0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };

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 uint8_t nouveau(uint8_t *menu) {         /* 35,1 New Menu : rend le numéro */
    libre();
    p16(0, (uint16_t)menu);
    api(35, 1);
    return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) {   /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
    libre();
    p16(0, x);
    p16(2, y);
    api(35, f);
    return ControlPort.params[4];               /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) {                         /* 35,5 Menu Track End : menu et article choisis */
    libre();
    api(35, 5);
    choix_menu = ControlPort.params[0];
    choix_article = ControlPort.params[1];
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus aucun menu */
    libre();
    api(32, 19);
}

int main(void) {
    uint8_t a, b, c;
    reinit();
    nouveau(fichier);
    nouveau(edition);
    a = point(3, 10, 5);                        /* Menu Select sur le titre « Fichier »... */
    fin();
    b = point(3, 60, 5);                        /* ... sur « Edition » */
    fin();
    c = point(3, 10, 100);                      /* hors de la barre : rien n'est déroulé */
    reinit();
    printf("Fichier : %u, Edition : %u, hors de la barre : %u\n", a, b, c);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Fichier : 1, Edition : 2, hors de la barre : 0
Mad Pascal
// Dérouler un menu sur un clic (groupe 35, fonction 3, Trinity).
program mn3;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
        0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'),          // article 1
        1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'),          // article 2, inactif
        $80, 0,                                                                     // article 3 : séparateur
        0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF);   // article 4
    edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
        2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'),          // coché
        0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);

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

function nouveau(menu: pointer): byte;          // 35,1 New Menu : rend le numéro
begin
  NeoWaitMessage;
  wordParams[0] := word(menu);
  appel(1);
  result := NeoMessage.params[2];
end;

function point(f: byte; x, y: smallint): byte;  // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
  NeoWaitMessage;
  wordParams[0] := word(x);
  wordParams[1] := word(y);
  appel(f);
  result := NeoMessage.params[4];               // 35,3 : menu déroulé, 0 si aucun titre touché
end;

var choix_menu, choix_article: byte;

procedure fin;                                  // 35,5 Menu Track End : menu et article choisis
begin
  NeoWaitMessage;
  appel(5);
  choix_menu := NeoMessage.params[0];
  choix_article := NeoMessage.params[1];
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus aucun menu
begin
  NeoWaitMessage;
  NeoSendMessage(32, 19);
  NeoWaitMessage;
end;

var a, b, c: byte;
begin
  reinit;
  nouveau(@fichier);
  nouveau(@edition);
  a := point(3, 10, 5);                         // Menu Select sur le titre « Fichier »...
  fin;
  b := point(3, 60, 5);                         // ... sur « Edition »
  fin;
  c := point(3, 10, 100);                       // hors de la barre : rien n'est déroulé
  reinit;
  writeln('Fichier : ', a, ', Edition : ', b, ', hors de la barre : ', c);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Fichier : 1, Edition : 2, hors de la barre : 0
NeoBASIC
10 ' Derouler un menu sur un clic (groupe 35, fonction 3, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000 : q = ed : gosub 8000
40 f = 3 : x = 10 : y = 5 : gosub 8100 : a = r : gosub 8200 : ' Menu Select sur le titre « Fichier »...
50 f = 3 : x = 60 : gosub 8100 : b = r : gosub 8200 : ' ... sur « Edition »
60 f = 3 : x = 10 : y = 100 : gosub 8100 : c = r : ' hors de la barre : rien n'est deroule
70 gosub 8300
80 print "Fichier : ";a;", Edition : ";b;", hors de la barre : ";c
90 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
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 :
Fichier : 1, Edition : 2, hors de la barre : 0
Assembleur 65C02 (64tass)
; Dérouler un menu sur un clic (groupe 35, 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 #<b0
        ldx #>b0
        jsr envoi
        lda #<b1
        ldx #>b1
        jsr envoi
        lda #<b2
        ldx #>b2
        jsr envoi
        lda #<b3
        ldx #>b3
        jsr envoi
        lda ControlPort+8          ; P4 : menu déroulé
        sta a
        lda #<b4
        ldx #>b4
        jsr envoi
        lda #<b5
        ldx #>b5
        jsr envoi
        lda ControlPort+8          ; P4 : menu déroulé
        sta b
        lda #<b6
        ldx #>b6
        jsr envoi
        lda #<b7
        ldx #>b7
        jsr envoi
        lda ControlPort+8          ; P4 : menu déroulé
        sta c
        lda #<b8
        ldx #>b8
        jsr envoi
        lda #<t9
        ldx #>t9
        jsr ecrire
        lda a
        jsr decimal
        lda #<t10
        ldx #>t10
        jsr ecrire
        lda b
        jsr decimal
        lda #<t11
        ldx #>t11
        jsr ecrire
        lda c
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
        .text "Fichier"
        .byte 0, 6
        .text "Ouvrir"             ; article 1
fermer: .byte 1, 6
        .text "Fermer"             ; article 2, inactif
        .byte $80, 0               ; article 3 : séparateur
        .byte 0, 7
        .text "Quitter"            ; article 4
        .byte $FF
edition: .byte 7
        .text "Edition"
        .byte 2, 6
        .text "Copier"             ; coché
        .byte 0, 6
        .text "Coller"
        .byte $FF
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
b1:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word fichier
b2:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word edition
b3:     .byte 35, 3, 4             ; Menu Select sur le titre « Fichier »...
        .word 10, 5
a:      .byte 0
b4:     .byte 35, 5, 0             ; 35,5 : Menu Track End
b5:     .byte 35, 3, 4             ; ... sur « Edition »
        .word 60, 5
b:      .byte 0
b6:     .byte 35, 5, 0             ; 35,5 : Menu Track End
b7:     .byte 35, 3, 4             ; hors de la barre : rien n'est déroulé
        .word 10, 100
c:      .byte 0
b8:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
t9:     .text "Fichier : ", 0
t10:    .text ", Edition : ", 0
t11:    .text ", hors de la barre : ", 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

; 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 :
Fichier : 1, Edition : 2, hors de la barre : 0

35,4 Menu Track Trinity

Met en évidence l'article sous la souris dans le menu déroulé ; sur un autre titre, déroule ce menu.

Entrées
OctetsTypeRôle
P0-P1int16X de la souris
P2-P3int16Y de la souris

Sorties : aucune.

Au banc, les articles font 10 lignes chacun, à partir de la ligne 13. Un article inactif ou un séparateur n'est jamais choisi : 35,5 rend alors 0, 0. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Highlights the item under Parameters:0,1 (X), Parameters:2,3 (Y) in the pulled down menu ; moving over another title pulls that menu down instead.

C (llvm-mos)
/* Suivre la souris dans un menu (groupe 35, 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)
        ;
}

/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
   un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
    0, 6, 'O', 'u', 'v', 'r', 'i', 'r',           /* article 1 */
    1, 6, 'F', 'e', 'r', 'm', 'e', 'r',           /* article 2, inactif */
    0x80, 0,                                    /* article 3 : séparateur */
    0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF };   /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
    2, 6, 'C', 'o', 'p', 'i', 'e', 'r',           /* coché */
    0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };

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 uint8_t nouveau(uint8_t *menu) {         /* 35,1 New Menu : rend le numéro */
    libre();
    p16(0, (uint16_t)menu);
    api(35, 1);
    return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) {   /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
    libre();
    p16(0, x);
    p16(2, y);
    api(35, f);
    return ControlPort.params[4];               /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) {                         /* 35,5 Menu Track End : menu et article choisis */
    libre();
    api(35, 5);
    choix_menu = ControlPort.params[0];
    choix_article = ControlPort.params[1];
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus aucun menu */
    libre();
    api(32, 19);
}

int main(void) {
    uint8_t m1, a1, m2, a2, m3, a3;
    reinit();
    nouveau(fichier);
    nouveau(edition);
    point(3, 10, 5);
    point(4, 15, 18);                           /* Menu Track sur le premier article (lignes 13 à 22) */
    fin(); m1 = choix_menu; a1 = choix_article;
    point(3, 10, 5);
    point(4, 15, 28);                           /* article 2, inactif */
    fin(); m2 = choix_menu; a2 = choix_article;
    point(3, 10, 5);
    point(4, 60, 5);                            /* passer sur un autre titre déroule son menu */
    point(4, 65, 18);
    fin(); m3 = choix_menu; a3 = choix_article;
    reinit();
    printf("Ouvrir : %u, %u ; inactif : %u, %u\nAutre titre : %u, %u\n", m1, a1, m2, a2, m3, a3);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Ouvrir : 1, 1 ; inactif : 0, 0
Autre titre : 2, 1
Mad Pascal
// Suivre la souris dans un menu (groupe 35, fonction 4, Trinity).
program mn4;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
        0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'),          // article 1
        1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'),          // article 2, inactif
        $80, 0,                                                                     // article 3 : séparateur
        0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF);   // article 4
    edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
        2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'),          // coché
        0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);

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

function nouveau(menu: pointer): byte;          // 35,1 New Menu : rend le numéro
begin
  NeoWaitMessage;
  wordParams[0] := word(menu);
  appel(1);
  result := NeoMessage.params[2];
end;

function point(f: byte; x, y: smallint): byte;  // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
  NeoWaitMessage;
  wordParams[0] := word(x);
  wordParams[1] := word(y);
  appel(f);
  result := NeoMessage.params[4];               // 35,3 : menu déroulé, 0 si aucun titre touché
end;

var choix_menu, choix_article: byte;

procedure fin;                                  // 35,5 Menu Track End : menu et article choisis
begin
  NeoWaitMessage;
  appel(5);
  choix_menu := NeoMessage.params[0];
  choix_article := NeoMessage.params[1];
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus aucun menu
begin
  NeoWaitMessage;
  NeoSendMessage(32, 19);
  NeoWaitMessage;
end;

var m1, a1, m2, a2, m3, a3: byte;
begin
  reinit;
  nouveau(@fichier);
  nouveau(@edition);
  point(3, 10, 5);
  point(4, 15, 18);                             // Menu Track sur le premier article (lignes 13 à 22)
  fin; m1 := choix_menu; a1 := choix_article;
  point(3, 10, 5);
  point(4, 15, 28);                             // article 2, inactif
  fin; m2 := choix_menu; a2 := choix_article;
  point(3, 10, 5);
  point(4, 60, 5);                              // passer sur un autre titre déroule son menu
  point(4, 65, 18);
  fin; m3 := choix_menu; a3 := choix_article;
  reinit;
  writeln('Ouvrir : ', m1, ', ', a1, ' ; inactif : ', m2, ', ', a2);
  writeln('Autre titre : ', m3, ', ', a3);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Ouvrir : 1, 1 ; inactif : 0, 0
Autre titre : 2, 1
NeoBASIC
10 ' Suivre la souris dans un menu (groupe 35, fonction 4, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000 : q = ed : gosub 8000
40 f = 3 : x = 10 : y = 5 : gosub 8100
50 f = 4 : x = 15 : y = 18 : gosub 8100 : ' Menu Track sur le premier article (lignes 13 a 22)
60 gosub 8200 : m1 = cm : a1 = ca
70 f = 3 : x = 10 : y = 5 : gosub 8100
80 f = 4 : x = 15 : y = 28 : gosub 8100 : ' article 2, inactif
90 gosub 8200 : m2 = cm : a2 = ca
100 f = 3 : x = 10 : y = 5 : gosub 8100
110 f = 4 : x = 60 : y = 5 : gosub 8100 : ' passer sur un autre titre deroule son menu
120 f = 4 : x = 65 : y = 18 : gosub 8100
130 gosub 8200 : m3 = cm : a3 = ca
140 gosub 8300
150 print "Ouvrir : ";m1;", ";a1;" ; inactif : ";m2;", ";a2
160 print "Autre titre : ";m3;", ";a3
170 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
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 :
Ouvrir : 1, 1 ; inactif : 0, 0
Autre titre : 2, 1
Assembleur 65C02 (64tass)
; Suivre la souris dans un menu (groupe 35, 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 #<b0
        ldx #>b0
        jsr envoi
        lda #<b1
        ldx #>b1
        jsr envoi
        lda #<b2
        ldx #>b2
        jsr envoi
        lda #<b3
        ldx #>b3
        jsr envoi
        lda #<b4
        ldx #>b4
        jsr envoi
        lda #<b5
        ldx #>b5
        jsr envoi
        lda ControlPort+4          ; menu choisi
        sta m1
        lda ControlPort+5          ; article choisi
        sta a1
        lda #<b6
        ldx #>b6
        jsr envoi
        lda #<b7
        ldx #>b7
        jsr envoi
        lda #<b8
        ldx #>b8
        jsr envoi
        lda ControlPort+4          ; menu choisi
        sta m2
        lda ControlPort+5          ; article choisi
        sta a2
        lda #<b9
        ldx #>b9
        jsr envoi
        lda #<b10
        ldx #>b10
        jsr envoi
        lda #<b11
        ldx #>b11
        jsr envoi
        lda #<b12
        ldx #>b12
        jsr envoi
        lda ControlPort+4          ; menu choisi
        sta m3
        lda ControlPort+5          ; article choisi
        sta a3
        lda #<b13
        ldx #>b13
        jsr envoi
        lda #<t14
        ldx #>t14
        jsr ecrire
        lda m1
        jsr decimal
        lda #<t15
        ldx #>t15
        jsr ecrire
        lda a1
        jsr decimal
        lda #<t16
        ldx #>t16
        jsr ecrire
        lda m2
        jsr decimal
        lda #<t17
        ldx #>t17
        jsr ecrire
        lda a2
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t18
        ldx #>t18
        jsr ecrire
        lda m3
        jsr decimal
        lda #<t19
        ldx #>t19
        jsr ecrire
        lda a3
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
        .text "Fichier"
        .byte 0, 6
        .text "Ouvrir"             ; article 1
fermer: .byte 1, 6
        .text "Fermer"             ; article 2, inactif
        .byte $80, 0               ; article 3 : séparateur
        .byte 0, 7
        .text "Quitter"            ; article 4
        .byte $FF
edition: .byte 7
        .text "Edition"
        .byte 2, 6
        .text "Copier"             ; coché
        .byte 0, 6
        .text "Coller"
        .byte $FF
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
b1:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word fichier
b2:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word edition
b3:     .byte 35, 3, 4             ; 35,3 : Menu Select
        .word 10, 5
b4:     .byte 35, 4, 4             ; Menu Track sur le premier article (lignes 13 à 22)
        .word 15, 18
b5:     .byte 35, 5, 0             ; 35,5 : Menu Track End
m1:     .byte 0
a1:     .byte 0
b6:     .byte 35, 3, 4             ; 35,3 : Menu Select
        .word 10, 5
b7:     .byte 35, 4, 4             ; article 2, inactif
        .word 15, 28
b8:     .byte 35, 5, 0             ; 35,5 : Menu Track End
m2:     .byte 0
a2:     .byte 0
b9:     .byte 35, 3, 4             ; 35,3 : Menu Select
        .word 10, 5
b10:    .byte 35, 4, 4             ; passer sur un autre titre déroule son menu
        .word 60, 5
b11:    .byte 35, 4, 4             ; 35,4 : Menu Track
        .word 65, 18
b12:    .byte 35, 5, 0             ; 35,5 : Menu Track End
m3:     .byte 0
a3:     .byte 0
b13:    .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
t14:    .text "Ouvrir : ", 0
t15:    .text ", ", 0
t16:    .text " ; inactif : ", 0
t17:    .text ", ", 0
t18:    .text "Autre titre : ", 0
t19:    .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

; 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 :
Ouvrir : 1, 1 ; inactif : 0, 0
Autre titre : 2, 1

35,5 Menu Track End Trinity

Ferme le menu déroulé et rend le menu et l'article choisis.

Entrées : aucune.

Sorties
OctetsTypeRôle
P0uint8menu choisi (0 si rien)
P1uint8article choisi, à partir de 1 (0 si rien)

Bouton relâché hors du menu : rien n'est choisi. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Closes the pulled down menu and returns the chosen menu in Parameter:0 and item in Parameter:1 (1..), both 0 if nothing enabled was chosen.

C (llvm-mos)
/* Fermer le menu et lire le choix (groupe 35, 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)
        ;
}

/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
   un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
    0, 6, 'O', 'u', 'v', 'r', 'i', 'r',           /* article 1 */
    1, 6, 'F', 'e', 'r', 'm', 'e', 'r',           /* article 2, inactif */
    0x80, 0,                                    /* article 3 : séparateur */
    0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF };   /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
    2, 6, 'C', 'o', 'p', 'i', 'e', 'r',           /* coché */
    0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };

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 uint8_t nouveau(uint8_t *menu) {         /* 35,1 New Menu : rend le numéro */
    libre();
    p16(0, (uint16_t)menu);
    api(35, 1);
    return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) {   /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
    libre();
    p16(0, x);
    p16(2, y);
    api(35, f);
    return ControlPort.params[4];               /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) {                         /* 35,5 Menu Track End : menu et article choisis */
    libre();
    api(35, 5);
    choix_menu = ControlPort.params[0];
    choix_article = ControlPort.params[1];
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus aucun menu */
    libre();
    api(32, 19);
}

int main(void) {
    uint8_t m1, a1, m2, a2;
    reinit();
    nouveau(fichier);
    point(3, 10, 5);
    point(4, 15, 48);                           /* article 4, « Quitter » */
    fin(); m1 = choix_menu; a1 = choix_article; /* Menu Track End, au relâchement du bouton */
    point(3, 10, 5);
    point(4, 200, 200);                         /* bouton relâché hors du menu */
    fin(); m2 = choix_menu; a2 = choix_article;
    reinit();
    printf("Quitter : %u, %u ; dehors : %u, %u\n", m1, a1, m2, a2);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Quitter : 1, 4 ; dehors : 0, 0
Mad Pascal
// Fermer le menu et lire le choix (groupe 35, fonction 5, Trinity).
program mn5;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
        0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'),          // article 1
        1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'),          // article 2, inactif
        $80, 0,                                                                     // article 3 : séparateur
        0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF);   // article 4
    edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
        2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'),          // coché
        0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);

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

function nouveau(menu: pointer): byte;          // 35,1 New Menu : rend le numéro
begin
  NeoWaitMessage;
  wordParams[0] := word(menu);
  appel(1);
  result := NeoMessage.params[2];
end;

function point(f: byte; x, y: smallint): byte;  // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
  NeoWaitMessage;
  wordParams[0] := word(x);
  wordParams[1] := word(y);
  appel(f);
  result := NeoMessage.params[4];               // 35,3 : menu déroulé, 0 si aucun titre touché
end;

var choix_menu, choix_article: byte;

procedure fin;                                  // 35,5 Menu Track End : menu et article choisis
begin
  NeoWaitMessage;
  appel(5);
  choix_menu := NeoMessage.params[0];
  choix_article := NeoMessage.params[1];
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus aucun menu
begin
  NeoWaitMessage;
  NeoSendMessage(32, 19);
  NeoWaitMessage;
end;

var m1, a1, m2, a2: byte;
begin
  reinit;
  nouveau(@fichier);
  point(3, 10, 5);
  point(4, 15, 48);                             // article 4, « Quitter »
  fin; m1 := choix_menu; a1 := choix_article;   // Menu Track End, au relâchement du bouton
  point(3, 10, 5);
  point(4, 200, 200);                           // bouton relâché hors du menu
  fin; m2 := choix_menu; a2 := choix_article;
  reinit;
  writeln('Quitter : ', m1, ', ', a1, ' ; dehors : ', m2, ', ', a2);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Quitter : 1, 4 ; dehors : 0, 0
NeoBASIC
10 ' Fermer le menu et lire le choix (groupe 35, fonction 5, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000
40 f = 3 : x = 10 : y = 5 : gosub 8100
50 f = 4 : x = 15 : y = 48 : gosub 8100 : ' article 4, « Quitter »
60 gosub 8200 : m1 = cm : a1 = ca : ' Menu Track End, au relachement du bouton
70 f = 3 : x = 10 : y = 5 : gosub 8100
80 f = 4 : x = 200 : y = 200 : gosub 8100 : ' bouton relache hors du menu
90 gosub 8200 : m2 = cm : a2 = ca
100 gosub 8300
110 print "Quitter : ";m1;", ";a1;" ; dehors : ";m2;", ";a2
120 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
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 :
Quitter : 1, 4 ; dehors : 0, 0
Assembleur 65C02 (64tass)
; Fermer le menu et lire le choix (groupe 35, 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:  lda #<b0
        ldx #>b0
        jsr envoi
        lda #<b1
        ldx #>b1
        jsr envoi
        lda #<b2
        ldx #>b2
        jsr envoi
        lda #<b3
        ldx #>b3
        jsr envoi
        lda #<b4
        ldx #>b4
        jsr envoi
        lda ControlPort+4          ; menu choisi
        sta m1
        lda ControlPort+5          ; article choisi
        sta a1
        lda #<b5
        ldx #>b5
        jsr envoi
        lda #<b6
        ldx #>b6
        jsr envoi
        lda #<b7
        ldx #>b7
        jsr envoi
        lda ControlPort+4          ; menu choisi
        sta m2
        lda ControlPort+5          ; article choisi
        sta a2
        lda #<b8
        ldx #>b8
        jsr envoi
        lda #<t9
        ldx #>t9
        jsr ecrire
        lda m1
        jsr decimal
        lda #<t10
        ldx #>t10
        jsr ecrire
        lda a1
        jsr decimal
        lda #<t11
        ldx #>t11
        jsr ecrire
        lda m2
        jsr decimal
        lda #<t12
        ldx #>t12
        jsr ecrire
        lda a2
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
        .text "Fichier"
        .byte 0, 6
        .text "Ouvrir"             ; article 1
fermer: .byte 1, 6
        .text "Fermer"             ; article 2, inactif
        .byte $80, 0               ; article 3 : séparateur
        .byte 0, 7
        .text "Quitter"            ; article 4
        .byte $FF
edition: .byte 7
        .text "Edition"
        .byte 2, 6
        .text "Copier"             ; coché
        .byte 0, 6
        .text "Coller"
        .byte $FF
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
b1:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word fichier
b2:     .byte 35, 3, 4             ; 35,3 : Menu Select
        .word 10, 5
b3:     .byte 35, 4, 4             ; article 4, « Quitter »
        .word 15, 48
b4:     .byte 35, 5, 0             ; 35,5 : Menu Track End
m1:     .byte 0
a1:     .byte 0
b5:     .byte 35, 3, 4             ; 35,3 : Menu Select
        .word 10, 5
b6:     .byte 35, 4, 4             ; bouton relâché hors du menu
        .word 200, 200
b7:     .byte 35, 5, 0             ; 35,5 : Menu Track End
m2:     .byte 0
a2:     .byte 0
b8:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
t9:     .text "Quitter : ", 0
t10:    .text ", ", 0
t11:    .text " ; dehors : ", 0
t12:    .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

; 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 :
Quitter : 1, 4 ; dehors : 0, 0

35,6 Set Item Flags Trinity

Change les options d'un article (bit 0 inactif, bit 1 coché), dans le descripteur.

Entrées
OctetsTypeRôle
P0uint8numéro du menu
P1uint8numéro de l'article (1, 2...)
P2uint8options

Sorties : aucune.

L'octet est écrit dans le descripteur du programme : l'exemple le relit. L'article est redessiné si son menu est déroulé. En Mad Pascal, le descripteur doit être une variable : un tableau constant est lu à la compilation et l'écriture du firmware ne se voit pas. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Sets the flags (bit 0 disabled, bit 1 checked) of item Parameter:1 of menu Parameter:0 to Parameter:2, in the descriptor ; the item is redrawn if its menu is pulled down.

C (llvm-mos)
/* Activer ou cocher un article (groupe 35, 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)
        ;
}

/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
   un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
    0, 6, 'O', 'u', 'v', 'r', 'i', 'r',           /* article 1 */
    1, 6, 'F', 'e', 'r', 'm', 'e', 'r',           /* article 2, inactif */
    0x80, 0,                                    /* article 3 : séparateur */
    0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF };   /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
    2, 6, 'C', 'o', 'p', 'i', 'e', 'r',           /* coché */
    0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };

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 uint8_t nouveau(uint8_t *menu) {         /* 35,1 New Menu : rend le numéro */
    libre();
    p16(0, (uint16_t)menu);
    api(35, 1);
    return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) {   /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
    libre();
    p16(0, x);
    p16(2, y);
    api(35, f);
    return ControlPort.params[4];               /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) {                         /* 35,5 Menu Track End : menu et article choisis */
    libre();
    api(35, 5);
    choix_menu = ControlPort.params[0];
    choix_article = ControlPort.params[1];
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus aucun menu */
    libre();
    api(32, 19);
}

int main(void) {
    uint8_t m, m1, a1, m2, a2;
    reinit();
    m = nouveau(fichier);
    point(3, 10, 5); point(4, 15, 28); fin();   /* « Fermer », inactif */
    m1 = choix_menu; a1 = choix_article;
    libre();
    ControlPort.params[0] = m;
    ControlPort.params[1] = 2;
    ControlPort.params[2] = 2;                  /* Set Item Flags : actif et coché */
    api(35, 6);
    point(3, 10, 5); point(4, 15, 28); fin();
    m2 = choix_menu; a2 = choix_article;
    reinit();
    printf("Avant : %u, %u ; actif : %u, %u\n", m1, a1, m2, a2);
    printf("Octet dans le descripteur : %u\n", fichier[16]);   /* les options sont écrites sur place */
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Avant : 0, 0 ; actif : 1, 2
Octet dans le descripteur : 2
Mad Pascal
// Activer ou cocher un article (groupe 35, fonction 6, Trinity).
program mn6;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
        0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'),          // article 1
        1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'),          // article 2, inactif
        $80, 0,                                                                     // article 3 : séparateur
        0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF);   // article 4
    edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
        2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'),          // coché
        0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);

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

function nouveau(menu: pointer): byte;          // 35,1 New Menu : rend le numéro
begin
  NeoWaitMessage;
  wordParams[0] := word(menu);
  appel(1);
  result := NeoMessage.params[2];
end;

function point(f: byte; x, y: smallint): byte;  // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
  NeoWaitMessage;
  wordParams[0] := word(x);
  wordParams[1] := word(y);
  appel(f);
  result := NeoMessage.params[4];               // 35,3 : menu déroulé, 0 si aucun titre touché
end;

var choix_menu, choix_article: byte;

procedure fin;                                  // 35,5 Menu Track End : menu et article choisis
begin
  NeoWaitMessage;
  appel(5);
  choix_menu := NeoMessage.params[0];
  choix_article := NeoMessage.params[1];
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus aucun menu
begin
  NeoWaitMessage;
  NeoSendMessage(32, 19);
  NeoWaitMessage;
end;

var m, m1, a1, m2, a2: byte;
begin
  reinit;
  m := nouveau(@fichier);
  point(3, 10, 5); point(4, 15, 28); fin;       // « Fermer », inactif
  m1 := choix_menu; a1 := choix_article;
  NeoWaitMessage;
  NeoMessage.params[0] := m;
  NeoMessage.params[1] := 2;
  NeoMessage.params[2] := 2;                    // Set Item Flags : actif et coché
  appel(6);
  point(3, 10, 5); point(4, 15, 28); fin;
  m2 := choix_menu; a2 := choix_article;
  reinit;
  writeln('Avant : ', m1, ', ', a1, ' ; actif : ', m2, ', ', a2);
  writeln('Octet dans le descripteur : ', fichier[16]);   // les options sont écrites sur place
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Avant : 0, 0 ; actif : 1, 2
Octet dans le descripteur : 2
NeoBASIC
10 ' Activer ou cocher un article (groupe 35, fonction 6, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000 : m = mn
40 f = 3 : x = 10 : y = 5 : gosub 8100 : f = 4 : x = 15 : y = 28 : gosub 8100 : gosub 8200 : ' « Fermer », inactif
50 m1 = cm : a1 = ca
60 while peek($ff00) : wend : poke $ff04, m : poke $ff05, 2 : poke $ff06, 2 : f = 6 : gosub 8110 : ' Set Item Flags : actif et coche
70 f = 3 : x = 10 : y = 5 : gosub 8100 : f = 4 : x = 15 : y = 28 : gosub 8100 : gosub 8200
80 m2 = cm : a2 = ca
90 gosub 8300
100 print "Avant : ";m1;", ";a1;" ; actif : ";m2;", ";a2
110 print "Octet dans le descripteur : ";peek(fi + 16) : ' les options sont ecrites sur place
120 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
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 :
Avant : 0, 0 ; actif : 1, 2
Octet dans le descripteur : 2
Assembleur 65C02 (64tass)
; Activer ou cocher un article (groupe 35, 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:  lda #<b0
        ldx #>b0
        jsr envoi
        lda #<b1
        ldx #>b1
        jsr envoi
        lda ControlPort+6          ; P2 : numéro du menu
        sta m
        lda #<b2
        ldx #>b2
        jsr envoi
        lda #<b3
        ldx #>b3
        jsr envoi
        lda #<b4
        ldx #>b4
        jsr envoi
        lda ControlPort+4          ; menu choisi
        sta m1
        lda ControlPort+5          ; article choisi
        sta a1
        jsr WaitMessage
        lda m
        sta ControlPort+4          ; P0 : menu
        lda #2
        sta ControlPort+5          ; P1 : article 2
        sta ControlPort+6          ; P2 : options 2, actif et coché
        lda #35
        ldx #6                  ; Set Item Flags
        jsr appel
        lda #<b5
        ldx #>b5
        jsr envoi
        lda #<b6
        ldx #>b6
        jsr envoi
        lda #<b7
        ldx #>b7
        jsr envoi
        lda ControlPort+4          ; menu choisi
        sta m2
        lda ControlPort+5          ; article choisi
        sta a2
        lda #<b8
        ldx #>b8
        jsr envoi
        lda #<t9
        ldx #>t9
        jsr ecrire
        lda m1
        jsr decimal
        lda #<t10
        ldx #>t10
        jsr ecrire
        lda a1
        jsr decimal
        lda #<t11
        ldx #>t11
        jsr ecrire
        lda m2
        jsr decimal
        lda #<t12
        ldx #>t12
        jsr ecrire
        lda a2
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t13
        ldx #>t13
        jsr ecrire
        lda fermer
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
        .text "Fichier"
        .byte 0, 6
        .text "Ouvrir"             ; article 1
fermer: .byte 1, 6
        .text "Fermer"             ; article 2, inactif
        .byte $80, 0               ; article 3 : séparateur
        .byte 0, 7
        .text "Quitter"            ; article 4
        .byte $FF
edition: .byte 7
        .text "Edition"
        .byte 2, 6
        .text "Copier"             ; coché
        .byte 0, 6
        .text "Coller"
        .byte $FF
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
b1:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word fichier
m:      .byte 0
b2:     .byte 35, 3, 4             ; 35,3 : Menu Select
        .word 10, 5
b3:     .byte 35, 4, 4             ; « Fermer », inactif
        .word 15, 28
b4:     .byte 35, 5, 0             ; 35,5 : Menu Track End
m1:     .byte 0
a1:     .byte 0
b5:     .byte 35, 3, 4             ; 35,3 : Menu Select
        .word 10, 5
b6:     .byte 35, 4, 4             ; 35,4 : Menu Track
        .word 15, 28
b7:     .byte 35, 5, 0             ; 35,5 : Menu Track End
m2:     .byte 0
a2:     .byte 0
b8:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
t9:     .text "Avant : ", 0
t10:    .text ", ", 0
t11:    .text " ; actif : ", 0
t12:    .text ", ", 0
t13:    .text "Octet dans le descripteur : ", 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

; 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 :
Avant : 0, 0 ; actif : 1, 2
Octet dans le descripteur : 2

35,7 Dispose Menu Trinity

Retire un menu de la barre.

Entrées
OctetsTypeRôle
P0uint8numéro du menu

Sorties : aucune.

Les titres suivants se décalent vers la gauche : après le retrait de « Fichier », « Edition » est touché en (10, 5). NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Removes menu Parameter:0 from the menu bar.

C (llvm-mos)
/* Retirer un menu de la barre (groupe 35, 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)
        ;
}

/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
   un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
    0, 6, 'O', 'u', 'v', 'r', 'i', 'r',           /* article 1 */
    1, 6, 'F', 'e', 'r', 'm', 'e', 'r',           /* article 2, inactif */
    0x80, 0,                                    /* article 3 : séparateur */
    0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF };   /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
    2, 6, 'C', 'o', 'p', 'i', 'e', 'r',           /* coché */
    0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };

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 uint8_t nouveau(uint8_t *menu) {         /* 35,1 New Menu : rend le numéro */
    libre();
    p16(0, (uint16_t)menu);
    api(35, 1);
    return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) {   /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
    libre();
    p16(0, x);
    p16(2, y);
    api(35, f);
    return ControlPort.params[4];               /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) {                         /* 35,5 Menu Track End : menu et article choisis */
    libre();
    api(35, 5);
    choix_menu = ControlPort.params[0];
    choix_article = ControlPort.params[1];
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus aucun menu */
    libre();
    api(32, 19);
}

int main(void) {
    uint8_t a, x10, x60;
    reinit();
    a = nouveau(fichier);
    nouveau(edition);
    libre(); ControlPort.params[0] = a; api(35, 7);   /* Dispose Menu */
    x10 = point(3, 10, 5); if (x10) fin();
    x60 = point(3, 60, 5); if (x60) fin();
    reinit();
    printf("Apres retrait : en (10, 5) : %u, en (60, 5) : %u\n", x10, x60);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Apres retrait : en (10, 5) : 2, en (60, 5) : 0
Mad Pascal
// Retirer un menu de la barre (groupe 35, fonction 7, Trinity).
program mn7;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
        0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'),          // article 1
        1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'),          // article 2, inactif
        $80, 0,                                                                     // article 3 : séparateur
        0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF);   // article 4
    edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
        2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'),          // coché
        0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);

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

function nouveau(menu: pointer): byte;          // 35,1 New Menu : rend le numéro
begin
  NeoWaitMessage;
  wordParams[0] := word(menu);
  appel(1);
  result := NeoMessage.params[2];
end;

function point(f: byte; x, y: smallint): byte;  // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
  NeoWaitMessage;
  wordParams[0] := word(x);
  wordParams[1] := word(y);
  appel(f);
  result := NeoMessage.params[4];               // 35,3 : menu déroulé, 0 si aucun titre touché
end;

var choix_menu, choix_article: byte;

procedure fin;                                  // 35,5 Menu Track End : menu et article choisis
begin
  NeoWaitMessage;
  appel(5);
  choix_menu := NeoMessage.params[0];
  choix_article := NeoMessage.params[1];
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus aucun menu
begin
  NeoWaitMessage;
  NeoSendMessage(32, 19);
  NeoWaitMessage;
end;

var a, x10, x60: byte;
begin
  reinit;
  a := nouveau(@fichier);
  nouveau(@edition);
  NeoWaitMessage;
  NeoMessage.params[0] := a;
  appel(7);                                     // Dispose Menu
  x10 := point(3, 10, 5); if x10 <> 0 then fin;
  x60 := point(3, 60, 5); if x60 <> 0 then fin;
  reinit;
  writeln('Apres retrait : en (10, 5) : ', x10, ', en (60, 5) : ', x60);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Apres retrait : en (10, 5) : 2, en (60, 5) : 0
NeoBASIC
10 ' Retirer un menu de la barre (groupe 35, fonction 7, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000 : a = mn : q = ed : gosub 8000
40 while peek($ff00) : wend : poke $ff04, a : f = 7 : gosub 8110 : ' Dispose Menu
50 f = 3 : x = 10 : y = 5 : gosub 8100 : x1 = r : if r then gosub 8200
60 f = 3 : x = 60 : y = 5 : gosub 8100 : x6 = r : if r then gosub 8200
70 gosub 8300
80 print "Apres retrait : en (10, 5) : ";x1;", en (60, 5) : ";x6
90 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
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 retrait : en (10, 5) : 2, en (60, 5) : 0
Assembleur 65C02 (64tass)
; Retirer un menu de la barre (groupe 35, 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:  lda #<b0
        ldx #>b0
        jsr envoi
        lda #<b1
        ldx #>b1
        jsr envoi
        lda ControlPort+6          ; P2 : numéro du menu
        sta a
        lda #<b2
        ldx #>b2
        jsr envoi
        jsr WaitMessage
        lda a
        sta ControlPort+4
        lda #35
        ldx #7                  ; Dispose Menu
        jsr appel
        lda #<b3
        ldx #>b3
        jsr envoi
        lda ControlPort+8          ; P4 : menu déroulé
        sta x1
        lda x1
        beq _s4
        lda #<b5
        ldx #>b5
        jsr envoi
_s4:
        lda #<b6
        ldx #>b6
        jsr envoi
        lda ControlPort+8          ; P4 : menu déroulé
        sta x6
        lda x6
        beq _s7
        lda #<b8
        ldx #>b8
        jsr envoi
_s7:
        lda #<b9
        ldx #>b9
        jsr envoi
        lda #<t10
        ldx #>t10
        jsr ecrire
        lda x1
        jsr decimal
        lda #<t11
        ldx #>t11
        jsr ecrire
        lda x6
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
        .text "Fichier"
        .byte 0, 6
        .text "Ouvrir"             ; article 1
fermer: .byte 1, 6
        .text "Fermer"             ; article 2, inactif
        .byte $80, 0               ; article 3 : séparateur
        .byte 0, 7
        .text "Quitter"            ; article 4
        .byte $FF
edition: .byte 7
        .text "Edition"
        .byte 2, 6
        .text "Copier"             ; coché
        .byte 0, 6
        .text "Coller"
        .byte $FF
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
b1:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word fichier
a:      .byte 0
b2:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word edition
b3:     .byte 35, 3, 4             ; 35,3 : Menu Select
        .word 10, 5
x1:     .byte 0
b5:     .byte 35, 5, 0             ; 35,5 : Menu Track End
b6:     .byte 35, 3, 4             ; 35,3 : Menu Select
        .word 60, 5
x6:     .byte 0
b8:     .byte 35, 5, 0             ; 35,5 : Menu Track End
b9:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
t10:    .text "Apres retrait : en (10, 5) : ", 0
t11:    .text ", en (60, 5) : ", 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

; 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 retrait : en (10, 5) : 2, en (60, 5) : 0

35,8 Get Item Flags Trinity

Rend les options d'un article.

Entrées
OctetsTypeRôle
P0uint8numéro du menu
P1uint8numéro de l'article (1, 2...)
Sorties
OctetsTypeRôle
P2uint8options (bit 0 inactif, bit 1 coché, bit 7 séparateur)

Le séparateur rend 128 (bit 7), l'article coché 2. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Returns the flags of item Parameter:1 of menu Parameter:0 in Parameter:2.

C (llvm-mos)
/* Lire les options d'un article (groupe 35, 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)
        ;
}

/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
   un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
    0, 6, 'O', 'u', 'v', 'r', 'i', 'r',           /* article 1 */
    1, 6, 'F', 'e', 'r', 'm', 'e', 'r',           /* article 2, inactif */
    0x80, 0,                                    /* article 3 : séparateur */
    0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF };   /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
    2, 6, 'C', 'o', 'p', 'i', 'e', 'r',           /* coché */
    0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };

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 uint8_t nouveau(uint8_t *menu) {         /* 35,1 New Menu : rend le numéro */
    libre();
    p16(0, (uint16_t)menu);
    api(35, 1);
    return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) {   /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
    libre();
    p16(0, x);
    p16(2, y);
    api(35, f);
    return ControlPort.params[4];               /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) {                         /* 35,5 Menu Track End : menu et article choisis */
    libre();
    api(35, 5);
    choix_menu = ControlPort.params[0];
    choix_article = ControlPort.params[1];
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus aucun menu */
    libre();
    api(32, 19);
}

static uint8_t options(uint8_t m, uint8_t a) {  /* Get Item Flags */
    libre();
    ControlPort.params[0] = m;
    ControlPort.params[1] = a;
    api(35, 8);
    return ControlPort.params[2];
}

int main(void) {
    uint8_t a, b, f[4], c, i;
    reinit();
    a = nouveau(fichier);
    b = nouveau(edition);
    for (i = 0; i < 4; i++)
        f[i] = options(a, i + 1);
    c = options(b, 1);
    reinit();
    printf("Fichier : %u %u %u %u ; Copier : %u\n", f[0], f[1], f[2], f[3], c);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Fichier : 0 1 128 0 ; Copier : 2
Mad Pascal
// Lire les options d'un article (groupe 35, fonction 8, Trinity).
program mn8;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
        0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'),          // article 1
        1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'),          // article 2, inactif
        $80, 0,                                                                     // article 3 : séparateur
        0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF);   // article 4
    edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
        2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'),          // coché
        0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);

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

function nouveau(menu: pointer): byte;          // 35,1 New Menu : rend le numéro
begin
  NeoWaitMessage;
  wordParams[0] := word(menu);
  appel(1);
  result := NeoMessage.params[2];
end;

function point(f: byte; x, y: smallint): byte;  // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
  NeoWaitMessage;
  wordParams[0] := word(x);
  wordParams[1] := word(y);
  appel(f);
  result := NeoMessage.params[4];               // 35,3 : menu déroulé, 0 si aucun titre touché
end;

var choix_menu, choix_article: byte;

procedure fin;                                  // 35,5 Menu Track End : menu et article choisis
begin
  NeoWaitMessage;
  appel(5);
  choix_menu := NeoMessage.params[0];
  choix_article := NeoMessage.params[1];
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus aucun menu
begin
  NeoWaitMessage;
  NeoSendMessage(32, 19);
  NeoWaitMessage;
end;

function options(m, a: byte): byte;             // Get Item Flags
begin
  NeoWaitMessage;
  NeoMessage.params[0] := m;
  NeoMessage.params[1] := a;
  appel(8);
  result := NeoMessage.params[2];
end;

var a, b, c, i: byte;
    f: array[0..3] of byte;
begin
  reinit;
  a := nouveau(@fichier);
  b := nouveau(@edition);
  for i := 0 to 3 do f[i] := options(a, i + 1);
  c := options(b, 1);
  reinit;
  writeln('Fichier : ', f[0], ' ', f[1], ' ', f[2], ' ', f[3], ' ; Copier : ', c);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Fichier : 0 1 128 0 ; Copier : 2
NeoBASIC
10 ' Lire les options d'un article (groupe 35, fonction 8, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000 : a = mn : q = ed : gosub 8000 : b = mn
40 dim o(3) : for k = 0 to 3 : m = a : t = k + 1 : gosub 2000 : o(k) = op : next k
50 m = b : t = 1 : gosub 2000 : c = op
60 gosub 8300
70 print "Fichier : ";o(0);" ";o(1);" ";o(2);" ";o(3);" ; Copier : ";c
80 end
2000 ' Get Item Flags : article t du menu m, options dans op
2010 while peek($ff00) : wend : poke $ff04, m : poke $ff05, t : f = 8 : gosub 8110
2020 op = peek($ff06) : return
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
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 :
Fichier : 0 1 128 0 ; Copier : 2
Assembleur 65C02 (64tass)
; Lire les options d'un article (groupe 35, 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:  lda #<b0
        ldx #>b0
        jsr envoi
        lda #<b1
        ldx #>b1
        jsr envoi
        lda ControlPort+6          ; P2 : numéro du menu
        sta a
        lda #<b2
        ldx #>b2
        jsr envoi
        lda ControlPort+6          ; P2 : numéro du menu
        sta b
        ldx #1
_o:     phx
        jsr WaitMessage
        plx
        lda a
        sta ControlPort+4          ; P0 : menu
        stx ControlPort+5          ; P1 : article
        phx
        lda #35
        ldx #8                     ; Get Item Flags
        jsr appel
        plx
        lda ControlPort+6
        sta o-1,x
        inx
        cpx #5
        bne _o
        jsr WaitMessage
        lda b
        sta ControlPort+4
        lda #1
        sta ControlPort+5
        lda #35
        ldx #8                  ; Get Item Flags
        jsr appel
        lda ControlPort+6
        sta c
        lda #<b3
        ldx #>b3
        jsr envoi
        lda #<t4
        ldx #>t4
        jsr ecrire
        ldx #0
_a5:   lda #' '
        jsr WriteCharacter
        lda o,x
        jsr decimal
        inx
        cpx #4
        bne _a5
        lda #<t6
        ldx #>t6
        jsr ecrire
        lda c
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
        .text "Fichier"
        .byte 0, 6
        .text "Ouvrir"             ; article 1
fermer: .byte 1, 6
        .text "Fermer"             ; article 2, inactif
        .byte $80, 0               ; article 3 : séparateur
        .byte 0, 7
        .text "Quitter"            ; article 4
        .byte $FF
edition: .byte 7
        .text "Edition"
        .byte 2, 6
        .text "Copier"             ; coché
        .byte 0, 6
        .text "Coller"
        .byte $FF
o:      .fill 4
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
b1:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word fichier
a:      .byte 0
b2:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word edition
b:      .byte 0
c:      .byte 0
b3:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
t4:     .text "Fichier :", 0
t6:     .text " ; Copier : ", 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

; 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 :
Fichier : 0 1 128 0 ; Copier : 2

35,9 Set Menu Bar Bounds Trinity

Limite la barre des menus entre deux abscisses au lieu de toute la largeur de l'écran.

Entrées
OctetsTypeRôle
P0-P1int16bord gauche
P2-P3int16bord droit, exclu (0 : toute la largeur)
Sorties
OctetsTypeRôle
erreuruint81 si le bord gauche est négatif ou si le droit ne dépasse pas le gauche

Le premier titre commence au bord gauche plus 4 ; un clic hors de la barre ne touche rien, et un menu déroulé ne dépasse pas le bord droit. Un menu déroulé est fermé, puis la barre est redessinée à sa nouvelle place ; ce qu'elle couvrait avant est laissé tel quel. 32,19 rend toute la largeur. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Keeps the menu bar between X = Parameters:0,1 (left) and X = Parameters:2,3 (right, excluded) instead of the whole width of the screen (Trinity T-83) : the first title starts at left + 4, clicks outside the bar hit nothing, and a pull-down never goes past the right edge. Right = 0 gives back the full width, which is also the state after a reset ; a right edge past the screen is taken as the screen edge. A pulled down menu is closed, then the bar is redrawn at its new place ; what it covered before is left as it is (the program repaints it). Sets the error flag if left is negative or right is not greater than left.

C (llvm-mos)
/* Limiter la barre des menus (groupe 35, 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)
        ;
}

/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
   un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
    0, 6, 'O', 'u', 'v', 'r', 'i', 'r',           /* article 1 */
    1, 6, 'F', 'e', 'r', 'm', 'e', 'r',           /* article 2, inactif */
    0x80, 0,                                    /* article 3 : séparateur */
    0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF };   /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
    2, 6, 'C', 'o', 'p', 'i', 'e', 'r',           /* coché */
    0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };

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 uint8_t nouveau(uint8_t *menu) {         /* 35,1 New Menu : rend le numéro */
    libre();
    p16(0, (uint16_t)menu);
    api(35, 1);
    return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) {   /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
    libre();
    p16(0, x);
    p16(2, y);
    api(35, f);
    return ControlPort.params[4];               /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) {                         /* 35,5 Menu Track End : menu et article choisis */
    libre();
    api(35, 5);
    choix_menu = ControlPort.params[0];
    choix_article = ControlPort.params[1];
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus aucun menu */
    libre();
    api(32, 19);
}

static uint8_t bornes(int16_t g, int16_t d) {   /* Set Menu Bar Bounds : de g à d (exclu) ; d = 0 : tout l'écran */
    libre();
    p16(0, g);
    p16(2, d);
    api(35, 9);
    return ControlPort.error;
}

int main(void) {
    uint8_t a, b, e;
    reinit();
    nouveau(fichier);
    bornes(100, 300);                           /* le premier titre commence en 104 */
    a = point(3, 10, 5); if (a) fin();
    b = point(3, 110, 5); if (b) fin();
    e = bornes(200, 100);                       /* droite avant gauche : refusé */
    bornes(0, 0);
    reinit();
    printf("En (10, 5) : %u, en (110, 5) : %u\nBornes a l'envers : erreur %u\n", a, b, e);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
En (10, 5) : 0, en (110, 5) : 1
Bornes a l'envers : erreur 1
Mad Pascal
// Limiter la barre des menus (groupe 35, fonction 9, Trinity).
program mn9;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
        0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'),          // article 1
        1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'),          // article 2, inactif
        $80, 0,                                                                     // article 3 : séparateur
        0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF);   // article 4
    edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
        2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'),          // coché
        0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);

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

function nouveau(menu: pointer): byte;          // 35,1 New Menu : rend le numéro
begin
  NeoWaitMessage;
  wordParams[0] := word(menu);
  appel(1);
  result := NeoMessage.params[2];
end;

function point(f: byte; x, y: smallint): byte;  // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
  NeoWaitMessage;
  wordParams[0] := word(x);
  wordParams[1] := word(y);
  appel(f);
  result := NeoMessage.params[4];               // 35,3 : menu déroulé, 0 si aucun titre touché
end;

var choix_menu, choix_article: byte;

procedure fin;                                  // 35,5 Menu Track End : menu et article choisis
begin
  NeoWaitMessage;
  appel(5);
  choix_menu := NeoMessage.params[0];
  choix_article := NeoMessage.params[1];
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus aucun menu
begin
  NeoWaitMessage;
  NeoSendMessage(32, 19);
  NeoWaitMessage;
end;

function bornes(g, d: smallint): byte;          // Set Menu Bar Bounds : de g à d (exclu) ; d = 0 : tout l'écran
begin
  NeoWaitMessage;
  wordParams[0] := word(g);
  wordParams[1] := word(d);
  appel(9);
  result := NeoMessage.error;
end;

var a, b, e: byte;
begin
  reinit;
  nouveau(@fichier);
  bornes(100, 300);                             // le premier titre commence en 104
  a := point(3, 10, 5); if a <> 0 then fin;
  b := point(3, 110, 5); if b <> 0 then fin;
  e := bornes(200, 100);                        // droite avant gauche : refusé
  bornes(0, 0);
  reinit;
  writeln('En (10, 5) : ', a, ', en (110, 5) : ', b);
  writeln('Bornes a l''envers : erreur ', e);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
En (10, 5) : 0, en (110, 5) : 1
Bornes a l'envers : erreur 1
NeoBASIC
10 ' Limiter la barre des menus (groupe 35, fonction 9, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000
40 g = 100 : d = 300 : gosub 2000 : ' le premier titre commence en 104
50 f = 3 : x = 10 : y = 5 : gosub 8100 : a = r : if r then gosub 8200
60 f = 3 : x = 110 : y = 5 : gosub 8100 : b = r : if r then gosub 8200
70 g = 200 : d = 100 : gosub 2000 : e9 = e : ' droite avant gauche : refuse
80 g = 0 : d = 0 : gosub 2000
90 gosub 8300
100 print "En (10, 5) : ";a;", en (110, 5) : ";b
110 print "Bornes a l'envers : erreur ";e9
120 end
2000 ' Set Menu Bar Bounds : de g a d (exclu) ; d = 0 : tout l'ecran
2010 while peek($ff00) : wend : doke $ff04, g : doke $ff06, d : f = 9 : goto 8110
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
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 :
En (10, 5) : 0, en (110, 5) : 1
Bornes a l'envers : erreur 1
Assembleur 65C02 (64tass)
; Limiter la barre des menus (groupe 35, 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:  lda #<b0
        ldx #>b0
        jsr envoi
        lda #<b1
        ldx #>b1
        jsr envoi
        lda #<b2
        ldx #>b2
        jsr envoi
        lda #<b3
        ldx #>b3
        jsr envoi
        lda ControlPort+8          ; P4 : menu déroulé
        sta a
        lda a
        beq _s4
        lda #<b5
        ldx #>b5
        jsr envoi
_s4:
        lda #<b6
        ldx #>b6
        jsr envoi
        lda ControlPort+8          ; P4 : menu déroulé
        sta b
        lda b
        beq _s7
        lda #<b8
        ldx #>b8
        jsr envoi
_s7:
        lda #<b9
        ldx #>b9
        jsr envoi
        lda ControlPort+2
        sta e
        lda #<b10
        ldx #>b10
        jsr envoi
        lda #<b11
        ldx #>b11
        jsr envoi
        lda #<t12
        ldx #>t12
        jsr ecrire
        lda a
        jsr decimal
        lda #<t13
        ldx #>t13
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t14
        ldx #>t14
        jsr ecrire
        lda e
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
        .text "Fichier"
        .byte 0, 6
        .text "Ouvrir"             ; article 1
fermer: .byte 1, 6
        .text "Fermer"             ; article 2, inactif
        .byte $80, 0               ; article 3 : séparateur
        .byte 0, 7
        .text "Quitter"            ; article 4
        .byte $FF
edition: .byte 7
        .text "Edition"
        .byte 2, 6
        .text "Copier"             ; coché
        .byte 0, 6
        .text "Coller"
        .byte $FF
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
b1:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word fichier
b2:     .byte 35, 9, 4             ; Set Menu Bar Bounds : de 100 à 300 (exclu)
        .word 100, 300
b3:     .byte 35, 3, 4             ; 35,3 : Menu Select
        .word 10, 5
a:      .byte 0
b5:     .byte 35, 5, 0             ; 35,5 : Menu Track End
b6:     .byte 35, 3, 4             ; 35,3 : Menu Select
        .word 110, 5
b:      .byte 0
b8:     .byte 35, 5, 0             ; 35,5 : Menu Track End
b9:     .byte 35, 9, 4             ; droite avant gauche : refusé
        .word 200, 100
e:      .byte 0
b10:    .byte 35, 9, 4             ; 0 : tout l'écran
        .word 0, 0
b11:    .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
t12:    .text "En (10, 5) : ", 0
t13:    .text ", en (110, 5) : ", 0
t14:    .text "Bornes a l'envers : 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

; 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 :
En (10, 5) : 0, en (110, 5) : 1
Bornes a l'envers : erreur 1

35,10 Menu Key Trinity

Pilote les menus au clavier, avec le code d'une touche.

Entrées
OctetsTypeRôle
P0uint8code de la touche (message2 d'un événement de touche, groupe 33)
Sorties
OctetsTypeRôle
P0uint80 touche inutilisée, 1 menu déroulé, 2 article choisi, 3 menu fermé sans choix
P1uint8menu choisi (si P0 = 2)
P2uint8article choisi (si P0 = 2)

Barre fermée, F10 ($43) déroule le premier menu, premier article actif en évidence ; toute autre touche rend 0 et reste au programme. Menu déroulé : Gauche ($50) et Droite ($4F) changent de menu, Haut ($52) et Bas ($51) passent d'un article actif à l'autre (séparateurs et articles inactifs sautés, en boucle), Entrée ($28) choisit, Échap ($29) ou F10 ferme. La souris (35,3 à 35,5) fonctionne toujours. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

The menus from the keyboard (Trinity T-89). Pass the key code (message2 of a key down or auto key event, group 33) in Parameter:0. With the bar closed, F10 pulls the first menu down with its first enabled item highlighted. With a menu down : Left and Right pull the previous or next menu down, Up and Down move to the previous or next enabled item (separators and disabled items are skipped ; both wrap), Enter chooses, Escape or F10 closes. On return Parameter:0 is 0 if the key was not used (bar closed and not F10 : the program handles the key), 1 if it was used and a menu is down, 2 if an item was chosen (menu in Parameter:1, item in Parameter:2, as Function 35,5), 3 if the menu was closed without a choice. The mouse (35,3 to 35,5) keeps working.

C (llvm-mos)
/* Piloter les menus au clavier (groupe 35, 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)
        ;
}

/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
   un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
    0, 6, 'O', 'u', 'v', 'r', 'i', 'r',           /* article 1 */
    1, 6, 'F', 'e', 'r', 'm', 'e', 'r',           /* article 2, inactif */
    0x80, 0,                                    /* article 3 : séparateur */
    0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF };   /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
    2, 6, 'C', 'o', 'p', 'i', 'e', 'r',           /* coché */
    0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };

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 uint8_t nouveau(uint8_t *menu) {         /* 35,1 New Menu : rend le numéro */
    libre();
    p16(0, (uint16_t)menu);
    api(35, 1);
    return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) {   /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
    libre();
    p16(0, x);
    p16(2, y);
    api(35, f);
    return ControlPort.params[4];               /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) {                         /* 35,5 Menu Track End : menu et article choisis */
    libre();
    api(35, 5);
    choix_menu = ControlPort.params[0];
    choix_article = ControlPort.params[1];
}
static void reinit(void) {                      /* 32,19 Toolbox Reset : plus aucun menu */
    libre();
    api(32, 19);
}

/* Codes des touches (message2 des événements du groupe 33). */
#define F10 0x43
#define BAS 0x51
#define DROITE 0x4F
#define ENTREE 0x28
#define ECHAP 0x29

static uint8_t touche(uint8_t code) {           /* Menu Key : 0 inutilisée, 1 menu déroulé, 2 choix, 3 fermé */
    libre();
    ControlPort.params[0] = code;
    api(35, 10);
    return ControlPort.params[0];
}

int main(void) {
    uint8_t r0, r1, r2, r3, m, a, r4, r5;
    reinit();
    nouveau(fichier);
    nouveau(edition);
    r0 = touche(4);                             /* « a », barre fermée : le programme garde la touche */
    r1 = touche(F10);                           /* déroule « Fichier », « Ouvrir » en évidence */
    r2 = touche(BAS);                           /* saute l'article inactif et le séparateur : « Quitter » */
    r3 = touche(ENTREE);
    m = ControlPort.params[1];
    a = ControlPort.params[2];
    touche(F10);
    r4 = touche(DROITE);                        /* menu suivant */
    r5 = touche(ECHAP);
    reinit();
    printf("Touche a : %u\nF10 : %u, bas : %u, Entree : %u (menu %u, article %u)\n", r0, r1, r2, r3, m, a);
    printf("F10, droite : %u, Echap : %u\n", r4, r5);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Touche a : 0
F10 : 1, bas : 1, Entree : 2 (menu 1, article 4)
F10, droite : 1, Echap : 3
Mad Pascal
// Piloter les menus au clavier (groupe 35, fonction 10, Trinity).
program mn10;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
        0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'),          // article 1
        1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'),          // article 2, inactif
        $80, 0,                                                                     // article 3 : séparateur
        0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF);   // article 4
    edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
        2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'),          // coché
        0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);

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

function nouveau(menu: pointer): byte;          // 35,1 New Menu : rend le numéro
begin
  NeoWaitMessage;
  wordParams[0] := word(menu);
  appel(1);
  result := NeoMessage.params[2];
end;

function point(f: byte; x, y: smallint): byte;  // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
  NeoWaitMessage;
  wordParams[0] := word(x);
  wordParams[1] := word(y);
  appel(f);
  result := NeoMessage.params[4];               // 35,3 : menu déroulé, 0 si aucun titre touché
end;

var choix_menu, choix_article: byte;

procedure fin;                                  // 35,5 Menu Track End : menu et article choisis
begin
  NeoWaitMessage;
  appel(5);
  choix_menu := NeoMessage.params[0];
  choix_article := NeoMessage.params[1];
end;

procedure reinit;                               // 32,19 Toolbox Reset : plus aucun menu
begin
  NeoWaitMessage;
  NeoSendMessage(32, 19);
  NeoWaitMessage;
end;

const F10 = $43; BAS = $51; DROITE = $4F; ENTREE = $28; ECHAP = $29;   // codes des touches (message2, groupe 33)

function touche(code: byte): byte;              // Menu Key : 0 inutilisée, 1 menu déroulé, 2 choix, 3 fermé
begin
  NeoWaitMessage;
  NeoMessage.params[0] := code;
  appel(10);
  result := NeoMessage.params[0];
end;

var r0, r1, r2, r3, m, a, r4, r5: byte;
begin
  reinit;
  nouveau(@fichier);
  nouveau(@edition);
  r0 := touche(4);                              // « a », barre fermée : le programme garde la touche
  r1 := touche(F10);                            // déroule « Fichier », « Ouvrir » en évidence
  r2 := touche(BAS);                            // saute l'article inactif et le séparateur : « Quitter »
  r3 := touche(ENTREE);
  m := NeoMessage.params[1];
  a := NeoMessage.params[2];
  touche(F10);
  r4 := touche(DROITE);                         // menu suivant
  r5 := touche(ECHAP);
  reinit;
  writeln('Touche a : ', r0);
  writeln('F10 : ', r1, ', bas : ', r2, ', Entree : ', r3, ' (menu ', m, ', article ', a, ')');
  writeln('F10, droite : ', r4, ', Echap : ', r5);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Touche a : 0
F10 : 1, bas : 1, Entree : 2 (menu 1, article 4)
F10, droite : 1, Echap : 3
NeoBASIC
10 ' Piloter les menus au clavier (groupe 35, fonction 10, Trinity)
15 gosub 7000
20 ' codes des touches (message2 des evenements du groupe 33)
30 f1 = $43 : ba = $51 : dr = $4f : en = $28 : ec = $29
40 gosub 8300
50 q = fi : gosub 8000 : q = ed : gosub 8000
60 k = 4 : gosub 2000 : r0 = kr : ' « a », barre fermee : le programme garde la touche
70 k = f1 : gosub 2000 : r1 = kr : ' deroule « Fichier », « Ouvrir » en evidence
80 k = ba : gosub 2000 : r2 = kr : ' saute l'article inactif et le separateur : « Quitter »
90 k = en : gosub 2000 : r3 = kr : m = peek($ff05) : a = peek($ff06)
100 k = f1 : gosub 2000
110 k = dr : gosub 2000 : r4 = kr : ' menu suivant
120 k = ec : gosub 2000 : r5 = kr
130 gosub 8300
140 print "Touche a : ";r0
150 print "F10 : ";r1;", bas : ";r2;", Entree : ";r3;" (menu ";m;", article ";a;")"
160 print "F10, droite : ";r4;", Echap : ";r5
170 end
2000 ' Menu Key : 0 inutilisee, 1 menu deroule, 2 choix, 3 ferme
2010 while peek($ff00) : wend : poke $ff04, k : f = 10 : gosub 8110
2020 kr = peek($ff04) : return
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
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 :
Touche a : 0
F10 : 1, bas : 1, Entree : 2 (menu 1, article 4)
F10, droite : 1, Echap : 3
Assembleur 65C02 (64tass)
; Piloter les menus au clavier (groupe 35, 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:  lda #<b0
        ldx #>b0
        jsr envoi
        lda #<b1
        ldx #>b1
        jsr envoi
        lda #<b2
        ldx #>b2
        jsr envoi
        lda #4                  ; « a », barre fermée : le programme garde la touche
        jsr touche
        sta r0
        lda #F10                ; déroule « Fichier », « Ouvrir » en évidence
        jsr touche
        sta r1
        lda #BAS                ; saute l'article inactif et le séparateur
        jsr touche
        sta r2
        lda #ENTREE             
        jsr touche
        sta r3
        lda ControlPort+5          ; P1 : menu choisi
        sta m
        lda ControlPort+6          ; P2 : article
        sta a
        lda #F10                
        jsr touche
        lda #DROITE             ; menu suivant
        jsr touche
        sta r4
        lda #ECHAP              
        jsr touche
        sta r5
        lda #<b3
        ldx #>b3
        jsr envoi
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda r0
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda r1
        jsr decimal
        lda #<t6
        ldx #>t6
        jsr ecrire
        lda r2
        jsr decimal
        lda #<t7
        ldx #>t7
        jsr ecrire
        lda r3
        jsr decimal
        lda #<t8
        ldx #>t8
        jsr ecrire
        lda m
        jsr decimal
        lda #<t9
        ldx #>t9
        jsr ecrire
        lda a
        jsr decimal
        lda #<t10
        ldx #>t10
        jsr ecrire
        lda #13
        jsr WriteCharacter
        lda #<t11
        ldx #>t11
        jsr ecrire
        lda r4
        jsr decimal
        lda #<t12
        ldx #>t12
        jsr ecrire
        lda r5
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
        .text "Fichier"
        .byte 0, 6
        .text "Ouvrir"             ; article 1
fermer: .byte 1, 6
        .text "Fermer"             ; article 2, inactif
        .byte $80, 0               ; article 3 : séparateur
        .byte 0, 7
        .text "Quitter"            ; article 4
        .byte $FF
edition: .byte 7
        .text "Edition"
        .byte 2, 6
        .text "Copier"             ; coché
        .byte 0, 6
        .text "Coller"
        .byte $FF
; Codes des touches (message2 des événements du groupe 33).
F10    = $43
BAS    = $51
DROITE = $4F
ENTREE = $28
ECHAP  = $29
b0:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
b1:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word fichier
b2:     .byte 35, 1, 2             ; 35,1 : New Menu
        .word edition
r0:     .byte 0
r1:     .byte 0
r2:     .byte 0
r3:     .byte 0
m:      .byte 0
a:      .byte 0
r4:     .byte 0
r5:     .byte 0
b3:     .byte 32, 19, 0            ; 32,19 Toolbox Reset : plus aucun menu
t4:     .text "Touche a : ", 0
t5:     .text "F10 : ", 0
t6:     .text ", bas : ", 0
t7:     .text ", Entree : ", 0
t8:     .text " (menu ", 0
t9:     .text ", article ", 0
t10:    .text ")", 0
t11:    .text "F10, droite : ", 0
t12:    .text ", Echap : ", 0

; Menu Key (35,10) sur la touche A : rend 0 inutilisée, 1 menu déroulé, 2 choix, 3 fermé.
touche: pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        lda #35
        ldx #10
        jsr appel
        lda ControlPort+4
        rts

; 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

; 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 :
Touche a : 0
F10 : 1, bas : 1, Entree : 2 (menu 1, article 4)
F10, droite : 1, Echap : 3

← L'API du Neo6502