Tachibana
Language: English

Group 35 — Menu Manager 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

The menu manager of the Trinity toolbox keeps a menu bar at the top of the screen (12 lines) and up to 6 pull-down menus, described by descriptors in 6502 RAM.

With the mouse: 35,3 on a click, 35,4 on each move, 35,5 on release. With the keyboard: 35,10 with the code of each key. The examples call these functions with fixed coordinates and key codes, without a real mouse or keyboard, and reset the toolbox with 32,19 at the start and at the end.

The two menus of the examples: "Fichier" (Ouvrir, Fermer disabled, a separator, Quitter) and "Edition" (Copier checked, Coller).

35,1 New Menu Trinity

Adds a menu to the menu bar, from a descriptor in 6502 RAM, and returns its number.

Inputs
BytesTypeMeaning
P0-P1addraddress of the descriptor (read in place)
Outputs
BytesTypeMeaning
P2uint8menu number (1 to 6)
erreuruint82 if no menu is left

Descriptor: title preceded by its length, then up to 16 items, each a flags byte (bit 0 disabled, bit 1 checked, bit 7 separator) followed by its text preceded by its length (31 characters at most), and finally the byte $FF. It must stay intact: the firmware reads it again and writes into it (35,6). The bar takes the first 12 lines of the screen (white background, black titles in the 6 × 8 font); windows must stay below it. On the bench, the seventh menu is refused. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 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.
Output observed in the Phosphoneo emulator, Trinity firmware 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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Menus : 1 et 2 ; septieme : erreur 2
65C02 assembly (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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Menus : 1 et 2 ; septieme : erreur 2

35,2 Draw Menu Bar Trinity

Redraws the menu bar, for instance after the program has drawn over it.

Inputs: none.

Outputs: none.

The example paints the bar in colour 4 with 32,8, then has it redrawn: the background turns white (15) again. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 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.
Output observed in the Phosphoneo emulator, Trinity firmware 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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Barre : 15 (titre 0), peinte : 4, redessinee : 15
65C02 assembly (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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Barre : 15 (titre 0), peinte : 4, redessinee : 15

35,3 Menu Select Trinity

To call on a mouse down: if a menu title is hit, pulls that menu down and returns its number.

Inputs
BytesTypeMeaning
P0-P1int16mouse X
P2-P3int16mouse Y
Outputs
BytesTypeMeaning
P4uint8menu pulled down (0 if no title was hit)

The program then calls 35,4 on every mouse move and 35,5 when the button is released. 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). On the bench, "Fichier" covers x 0 to 49 and "Edition" x 54 to 103. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 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.
Output observed in the Phosphoneo emulator, Trinity firmware 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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Fichier : 1, Edition : 2, hors de la barre : 0
65C02 assembly (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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Fichier : 1, Edition : 2, hors de la barre : 0

35,4 Menu Track Trinity

Highlights the item under the mouse in the pulled down menu; over another title, pulls that menu down.

Inputs
BytesTypeMeaning
P0-P1int16mouse X
P2-P3int16mouse Y

Outputs: none.

On the bench, items are 10 lines high each, from line 13. A disabled item or a separator is never chosen: 35,5 then returns 0, 0. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 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.
Output observed in the Phosphoneo emulator, Trinity firmware 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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ouvrir : 1, 1 ; inactif : 0, 0
Autre titre : 2, 1
65C02 assembly (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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ouvrir : 1, 1 ; inactif : 0, 0
Autre titre : 2, 1

35,5 Menu Track End Trinity

Closes the pulled down menu and returns the chosen menu and item.

Inputs: none.

Outputs
BytesTypeMeaning
P0uint8chosen menu (0 if none)
P1uint8chosen item, from 1 (0 if none)

Button released outside the menu: nothing is chosen. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 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.
Output observed in the Phosphoneo emulator, Trinity firmware 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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Quitter : 1, 4 ; dehors : 0, 0
65C02 assembly (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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Quitter : 1, 4 ; dehors : 0, 0

35,6 Set Item Flags Trinity

Changes the flags of an item (bit 0 disabled, bit 1 checked), in the descriptor.

Inputs
BytesTypeMeaning
P0uint8menu number
P1uint8item number (1, 2...)
P2uint8flags

Outputs: none.

The byte is written into the program's descriptor: the example reads it back. The item is redrawn if its menu is pulled down. In Mad Pascal, the descriptor must be a variable: a constant array is read at compile time and the firmware's write does not show. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 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.
Output observed in the Phosphoneo emulator, Trinity firmware 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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Avant : 0, 0 ; actif : 1, 2
Octet dans le descripteur : 2
65C02 assembly (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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Avant : 0, 0 ; actif : 1, 2
Octet dans le descripteur : 2

35,7 Dispose Menu Trinity

Removes a menu from the menu bar.

Inputs
BytesTypeMeaning
P0uint8menu number

Outputs: none.

The following titles move left: once "Fichier" is removed, "Edition" is hit at (10, 5). NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 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.
Output observed in the Phosphoneo emulator, Trinity firmware 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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Apres retrait : en (10, 5) : 2, en (60, 5) : 0
65C02 assembly (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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Apres retrait : en (10, 5) : 2, en (60, 5) : 0

35,8 Get Item Flags Trinity

Returns the flags of an item.

Inputs
BytesTypeMeaning
P0uint8menu number
P1uint8item number (1, 2...)
Outputs
BytesTypeMeaning
P2uint8flags (bit 0 disabled, bit 1 checked, bit 7 separator)

The separator returns 128 (bit 7), the checked item 2. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 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.
Output observed in the Phosphoneo emulator, Trinity firmware 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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Fichier : 0 1 128 0 ; Copier : 2
65C02 assembly (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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Fichier : 0 1 128 0 ; Copier : 2

35,9 Set Menu Bar Bounds Trinity

Keeps the menu bar between two X positions instead of the whole screen width.

Inputs
BytesTypeMeaning
P0-P1int16left edge
P2-P3int16right edge, excluded (0: full width)
Outputs
BytesTypeMeaning
erreuruint81 if the left edge is negative or the right one is not past the left one

The first title starts at the left edge plus 4; a click outside the bar hits nothing, and a pull-down never goes past the right 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. 32,19 gives back the full width. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 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.
Output observed in the Phosphoneo emulator, Trinity firmware 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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
En (10, 5) : 0, en (110, 5) : 1
Bornes a l'envers : erreur 1
65C02 assembly (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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
En (10, 5) : 0, en (110, 5) : 1
Bornes a l'envers : erreur 1

35,10 Menu Key Trinity

Drives the menus from the keyboard, with a key code.

Inputs
BytesTypeMeaning
P0uint8key code (message2 of a key event, group 33)
Outputs
BytesTypeMeaning
P0uint80 key not used, 1 menu down, 2 item chosen, 3 menu closed without a choice
P1uint8chosen menu (if P0 = 2)
P2uint8chosen item (if P0 = 2)

With the bar closed, F10 ($43) pulls the first menu down with its first enabled item highlighted; any other key returns 0 and stays with the program. With a menu down: Left ($50) and Right ($4F) change menu, Up ($52) and Down ($51) move between enabled items (separators and disabled items skipped, wrapping), Enter ($28) chooses, Escape ($29) or F10 closes. The mouse (35,3 to 35,5) keeps working. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 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.
Output observed in the Phosphoneo emulator, Trinity firmware 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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Touche a : 0
F10 : 1, bas : 1, Entree : 2 (menu 1, article 4)
F10, droite : 1, Echap : 3
65C02 assembly (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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Touche a : 0
F10 : 1, bas : 1, Entree : 2 (menu 1, article 4)
F10, droite : 1, Echap : 3

← The Neo6502 API