Groupe 36 — Gestionnaire de contrôles Trinity
36,1 New Control · 36,2 Dispose Control · 36,3 Draw Controls · 36,4 Draw Control · 36,5 Set Control Value · 36,6 Get Control Value · 36,7 Set Control Flags · 36,8 Find Control · 36,9 Track Control · 36,10 Key Control
Le gestionnaire de contrôles de la boîte à outils de Trinity place dans les fenêtres (groupe 34) des boutons, cases à cocher, boutons radio, barres de défilement et champs de texte : 24 au plus.
Les exemples ouvrent une fenêtre de cadre 20, 20, 220, 140 (contenu de (21, 31) à (219, 139)) et y posent leurs contrôles : un Rect de contrôle est relatif au contenu, si bien que le bouton posé en (10, 10) est en (31, 41) à l'écran. La souris est simulée par des appels à 36,9 aux coordonnées voulues. La boîte à outils est remise à zéro avec 32,19 au début et à la fin.
36,1 New Control Trinity
Crée un contrôle dans une fenêtre et le dessine aussitôt.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | type : 1 bouton, 2 case à cocher, 3 bouton radio, 4 barre de défilement, 5 champ de texte |
P1 | uint8 | fenêtre |
P2-P3 | addr | adresse du Rect, relatif au contenu de la fenêtre |
P4-P5 | addr | adresse du titre précédé de sa longueur, ou du tampon d'un champ de texte (lus sur place) |
P6-P7 | uint16 | maximum d'une barre de défilement, ou longueur maximale d'un champ de texte |
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du contrôle (1 à 24) |
erreur | uint8 | 1 paramètres invalides, 2 plus de contrôle libre |
Une barre de défilement est verticale quand elle est plus haute que large. Les boutons radio ne sont pas groupés : c'est au programme de décocher les autres. Au traitement de l'événement de mise à jour d'une fenêtre, 36,3 redessine tous ses contrôles. Au banc, le 25e contrôle est refusé (erreur 2). NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Toolbox (Trinity, T-12, ADR-01 of the fork). Creates a control of kind Parameter:0 (1 button, 2 check box, 3 radio button, 4 scroll bar - vertical when higher than wide -, 5 text field) in window Parameter:1, with the Rect at Parameters:2,3 relative to the content of the window, the length-prefixed title (or, for a text field, the text buffer) at Parameters:4,5 read in place, and Parameters:6,7 = maximum value of a scroll bar or maximum length of a text field ; returns the control number (1-24) in Parameter:0 (error 1 bad parameters, 2 none left). The control is drawn at once ; redraw all the controls of a window with Draw Controls when handling its update event. Radio buttons are not grouped : the program clears the others.
C (llvm-mos)
/* Créer un contrôle (groupe 36, fonction 1, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A"; /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
libre();
api(32, 19);
}
static void ouvrir(void) { /* 34,1 : une fenêtre avec barre de titre */
reinit();
libre();
p16(0, (uint16_t)&cadre);
p16(2, (uint16_t)titre);
ControlPort.params[4] = 1;
api(34, 1);
fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
libre();
ControlPort.params[0] = type;
ControlPort.params[1] = fenetre;
p16(2, (uint16_t)r);
p16(4, (uint16_t)t);
p16(6, max);
api(36, 1);
return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) { /* 36,6 Get Control Value */
libre();
ControlPort.params[0] = c;
api(36, 6);
return ControlPort.params[1] | ControlPort.params[2] << 8;
}
static Rect rb = {10, 10, 70, 24}, rc = {10, 30, 110, 42}, rs = {180, 0, 192, 100};
static const char ok[] = "\002OK", option[] = "\006Option";
int main(void) {
uint8_t b, c, s, e;
ouvrir();
b = controle(1, &rb, ok, 0); /* bouton */
c = controle(2, &rc, option, 0); /* case à cocher */
s = controle(4, &rs, titre, 50); /* barre de défilement verticale (plus haute que large), maximum 50 */
controle(6, &rb, ok, 0); /* type inconnu : refusé */
e = ControlPort.error;
reinit();
printf("Bouton %u, case %u, barre %u ; type 6 : erreur %u\n", b, c, s, e);
return 0;
}Bouton 1, case 2, barre 3 ; type 6 : erreur 1Mad Pascal
// Créer un contrôle (groupe 36, fonction 1, Trinity).
program ct1;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A')); // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
fenetre: byte;
procedure poser(var r: Rect; g, h, d, b: smallint);
begin
r.g := g; r.h := h; r.d := d; r.b := b;
end;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
NeoWaitMessage;
appel(32, 19);
end;
procedure ouvrir; // 34,1 : une fenêtre avec barre de titre
begin
reinit;
poser(cadre, 20, 20, 220, 140);
wordParams[0] := word(@cadre);
wordParams[1] := word(@titre);
NeoMessage.params[4] := 1;
appel(34, 1);
fenetre := NeoMessage.params[5];
end;
// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
NeoWaitMessage;
NeoMessage.params[0] := t;
NeoMessage.params[1] := fenetre;
wordParams[1] := word(r);
wordParams[2] := word(s);
wordParams[3] := max;
appel(36, 1);
result := NeoMessage.params[0];
end;
function valeur(c: byte): word; // 36,6 Get Control Value
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
appel(36, 6);
result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;
procedure p16(i: byte; v: word); // paramètre 16 bits en Pi, Pi+1
begin
NeoMessage.params[i] := lo(v);
NeoMessage.params[i + 1] := hi(v);
end;
const ok: array[0..2] of byte = (2, ord('O'), ord('K'));
option: array[0..6] of byte = (6, ord('O'), ord('p'), ord('t'), ord('i'), ord('o'), ord('n'));
var rb, rc, rs: Rect;
b, c, s, e: byte;
begin
poser(rb, 10, 10, 70, 24); poser(rc, 10, 30, 110, 42); poser(rs, 180, 0, 192, 100);
ouvrir;
b := controle(1, @rb, @ok, 0); // bouton
c := controle(2, @rc, @option, 0); // case à cocher
s := controle(4, @rs, @titre, 50); // barre de défilement verticale (plus haute que large), maximum 50
controle(6, @rb, @ok, 0); // type inconnu : refusé
e := NeoMessage.error;
reinit;
writeln('Bouton ', b, ', case ', c, ', barre ', s, ' ; type 6 : erreur ', e);
end.Bouton 1, case 2, barre 3 ; type 6 : erreur 1NeoBASIC
10 ' Creer un controle (groupe 36, fonction 1, Trinity)
20 gosub 7000
30 g = 10 : h = 10 : d = 70 : b = 24 : gosub 8000 : rb = q : s$ = "OK" : gosub 7900 : ok = ch
40 ty = 1 : mx = 0 : gosub 7100 : bt = cn : ' bouton
50 g = 10 : h = 30 : d = 110 : b = 42 : gosub 8000 : s$ = "Option" : gosub 7900
60 ty = 2 : gosub 7100 : ca = cn : ' case a cocher
70 g = 180 : h = 0 : d = 192 : b = 100 : gosub 8000 : ch = tf
80 ty = 4 : mx = 50 : gosub 7100 : ba = cn : ' barre de defilement verticale (plus haute que large), maximum 50
90 q = rb : ch = ok : ty = 6 : mx = 0 : gosub 7100 : e6 = e : ' type inconnu : refuse
100 gosub 8300
110 print "Bouton ";bt;", case ";ca;", barre ";ba;" ; type 6 : erreur ";e6
120 end
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnBouton 1, case 2, barre 3 ; type 6 : erreur 1Assembleur 65C02 (64tass)
; Créer un contrôle (groupe 36, fonction 1, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr ouvrir
lda #<cb
ldx #>cb
jsr controle
sta b
lda #<cc
ldx #>cc
jsr controle
sta c
lda #<cs
ldx #>cs
jsr controle
sta s
lda #<c6
ldx #>c6
jsr controle
lda ControlPort+2
sta e
lda #<b0
ldx #>b0
jsr envoi
lda #<t1
ldx #>t1
jsr ecrire
lda b
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda c
jsr decimal
lda #<t3
ldx #>t3
jsr ecrire
lda s
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda e
jsr decimal
lda #13
jsr WriteCharacter
rts
rb: .word 10, 10, 70, 24
rc: .word 10, 30, 110, 42
rs: .word 180, 0, 192, 100
ok: .byte 2
.text "OK"
option: .byte 6
.text "Option"
cb: .byte 1 ; bouton
.word rb, ok, 0
b: .byte 0
cc: .byte 2 ; case à cocher
.word rc, option, 0
c: .byte 0
cs: .byte 4 ; barre verticale (plus haute que large), maximum 50
.word rs, titre, 50
s: .byte 0
c6: .byte 6 ; type inconnu : refusé
.word rb, ok, 0
e: .byte 0
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t1: .text "Bouton ", 0
t2: .text ", case ", 0
t3: .text ", barre ", 0
t4: .text " ; type 6 : erreur ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
ldx #>raz
jsr envoi
lda #<nfen
ldx #>nfen
jsr envoi
lda ControlPort+9
sta fen
rts
raz: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen: .byte 34, 1, 5
.word cadre, titre
.byte 1
cadre: .word 20, 20, 220, 140
titre: .byte 1
.text "A" ; chaînes précédées de leur longueur, lues sur place
fen: .byte 0
; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
sta blk
stx blk+1
jsr WaitMessage
ldy #0
lda (blk),y
sta ControlPort+4 ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
lda fen
sta ControlPort+5 ; P1 : fenêtre
ldy #1
_ctl: lda (blk),y
sta ControlPort+5,y ; P2-P7 : Rect, titre, maximum
iny
cpy #7
bne _ctl
lda #36
ldx #1
jsr appel
lda ControlPort+4
rts
; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
jsr WaitMessage
pla
sta ControlPort+4
lda #36
ldx #6
jsr appel
lda ControlPort+5
rts
; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
jsr WaitMessage
pla
sta ControlPort+4
ldx #4
_sv: lda pt,x
sta ControlPort+5,x ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
dex
bpl _sv
lda #36
ldx #9
jsr appel
lda ControlPort+10
rts
pt: .word 0, 0
.byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Bouton 1, case 2, barre 3 ; type 6 : erreur 136,2 Dispose Control Trinity
Efface un contrôle et libère son numéro.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du contrôle |
Sorties : aucune.
Fermer une fenêtre libère aussi ses contrôles. Le numéro libéré est repris par le contrôle suivant. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Erases and frees control Parameter:0. Disposing a window frees its controls.
C (llvm-mos)
/* Supprimer un contrôle (groupe 36, fonction 2, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A"; /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
libre();
api(32, 19);
}
static void ouvrir(void) { /* 34,1 : une fenêtre avec barre de titre */
reinit();
libre();
p16(0, (uint16_t)&cadre);
p16(2, (uint16_t)titre);
ControlPort.params[4] = 1;
api(34, 1);
fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
libre();
ControlPort.params[0] = type;
ControlPort.params[1] = fenetre;
p16(2, (uint16_t)r);
p16(4, (uint16_t)t);
p16(6, max);
api(36, 1);
return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) { /* 36,6 Get Control Value */
libre();
ControlPort.params[0] = c;
api(36, 6);
return ControlPort.params[1] | ControlPort.params[2] << 8;
}
static Rect rb = {10, 10, 70, 24}, rc = {10, 30, 110, 42};
static const char ok[] = "\002OK", option[] = "\006Option";
int main(void) {
uint8_t b, t, n;
ouvrir();
b = controle(1, &rb, ok, 0);
controle(2, &rc, option, 0);
libre(); ControlPort.params[0] = b; api(36, 2); /* Dispose Control : effacé, numéro libéré */
libre(); p16(0, 40); p16(2, 45); api(36, 8); /* 36,8 : plus rien à la place du bouton */
t = ControlPort.params[4];
n = controle(1, &rb, ok, 0);
reinit();
printf("Apres suppression : en (40, 45) : %u, nouveau : %u\n", t, n);
return 0;
}Apres suppression : en (40, 45) : 0, nouveau : 1Mad Pascal
// Supprimer un contrôle (groupe 36, fonction 2, Trinity).
program ct2;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A')); // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
fenetre: byte;
procedure poser(var r: Rect; g, h, d, b: smallint);
begin
r.g := g; r.h := h; r.d := d; r.b := b;
end;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
NeoWaitMessage;
appel(32, 19);
end;
procedure ouvrir; // 34,1 : une fenêtre avec barre de titre
begin
reinit;
poser(cadre, 20, 20, 220, 140);
wordParams[0] := word(@cadre);
wordParams[1] := word(@titre);
NeoMessage.params[4] := 1;
appel(34, 1);
fenetre := NeoMessage.params[5];
end;
// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
NeoWaitMessage;
NeoMessage.params[0] := t;
NeoMessage.params[1] := fenetre;
wordParams[1] := word(r);
wordParams[2] := word(s);
wordParams[3] := max;
appel(36, 1);
result := NeoMessage.params[0];
end;
function valeur(c: byte): word; // 36,6 Get Control Value
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
appel(36, 6);
result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;
procedure p16(i: byte; v: word); // paramètre 16 bits en Pi, Pi+1
begin
NeoMessage.params[i] := lo(v);
NeoMessage.params[i + 1] := hi(v);
end;
const ok: array[0..2] of byte = (2, ord('O'), ord('K'));
option: array[0..6] of byte = (6, ord('O'), ord('p'), ord('t'), ord('i'), ord('o'), ord('n'));
var rb, rc: Rect;
b, t, n: byte;
begin
poser(rb, 10, 10, 70, 24); poser(rc, 10, 30, 110, 42);
ouvrir;
b := controle(1, @rb, @ok, 0);
controle(2, @rc, @option, 0);
NeoWaitMessage; NeoMessage.params[0] := b; appel(36, 2); // Dispose Control : effacé, numéro libéré
wordParams[0] := 40; wordParams[1] := 45; appel(36, 8); // 36,8 : plus rien à la place du bouton
t := NeoMessage.params[4];
n := controle(1, @rb, @ok, 0);
reinit;
writeln('Apres suppression : en (40, 45) : ', t, ', nouveau : ', n);
end.Apres suppression : en (40, 45) : 0, nouveau : 1NeoBASIC
10 ' Supprimer un controle (groupe 36, fonction 2, Trinity)
20 gosub 7000
30 g = 10 : h = 10 : d = 70 : b = 24 : gosub 8000 : rb = q : s$ = "OK" : gosub 7900 : ok = ch
40 ty = 1 : mx = 0 : gosub 7100 : bt = cn
50 g = 10 : h = 30 : d = 110 : b = 42 : gosub 8000 : s$ = "Option" : gosub 7900 : ty = 2 : gosub 7100
60 while peek($ff00) : wend : poke $ff04, bt : f = 2 : gosub 8110 : ' Dispose Control : efface, numero libere
70 while peek($ff00) : wend : doke $ff04, 40 : doke $ff06, 45 : f = 8 : gosub 8110 : t = peek($ff08) : ' 36,8 : plus rien
80 q = rb : ch = ok : ty = 1 : gosub 7100 : n = cn
90 gosub 8300
100 print "Apres suppression : en (40, 45) : ";t;", nouveau : ";n
110 end
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnApres suppression : en (40, 45) : 0, nouveau : 1Assembleur 65C02 (64tass)
; Supprimer un contrôle (groupe 36, fonction 2, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr ouvrir
lda #<cb
ldx #>cb
jsr controle
sta b
lda #<cc
ldx #>cc
jsr controle
jsr WaitMessage
lda b
sta ControlPort+4
lda #36
ldx #2 ; Dispose Control : effacé, numéro libéré
jsr appel
lda #<b0
ldx #>b0
jsr envoi
lda ControlPort+8
sta t
lda #<cb
ldx #>cb
jsr controle
sta n
lda #<b1
ldx #>b1
jsr envoi
lda #<t2
ldx #>t2
jsr ecrire
lda t
jsr decimal
lda #<t3
ldx #>t3
jsr ecrire
lda n
jsr decimal
lda #13
jsr WriteCharacter
rts
rb: .word 10, 10, 70, 24
rc: .word 10, 30, 110, 42
ok: .byte 2
.text "OK"
option: .byte 6
.text "Option"
cb: .byte 1 ; bouton
.word rb, ok, 0
b: .byte 0
cc: .byte 2 ; case à cocher
.word rc, option, 0
b0: .byte 36, 8, 4 ; 36,8 : plus rien à la place du bouton
.word 40, 45
t: .byte 0
n: .byte 0
b1: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t2: .text "Apres suppression : en (40, 45) : ", 0
t3: .text ", nouveau : ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
ldx #>raz
jsr envoi
lda #<nfen
ldx #>nfen
jsr envoi
lda ControlPort+9
sta fen
rts
raz: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen: .byte 34, 1, 5
.word cadre, titre
.byte 1
cadre: .word 20, 20, 220, 140
titre: .byte 1
.text "A" ; chaînes précédées de leur longueur, lues sur place
fen: .byte 0
; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
sta blk
stx blk+1
jsr WaitMessage
ldy #0
lda (blk),y
sta ControlPort+4 ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
lda fen
sta ControlPort+5 ; P1 : fenêtre
ldy #1
_ctl: lda (blk),y
sta ControlPort+5,y ; P2-P7 : Rect, titre, maximum
iny
cpy #7
bne _ctl
lda #36
ldx #1
jsr appel
lda ControlPort+4
rts
; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
jsr WaitMessage
pla
sta ControlPort+4
lda #36
ldx #6
jsr appel
lda ControlPort+5
rts
; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
jsr WaitMessage
pla
sta ControlPort+4
ldx #4
_sv: lda pt,x
sta ControlPort+5,x ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
dex
bpl _sv
lda #36
ldx #9
jsr appel
lda ControlPort+10
rts
pt: .word 0, 0
.byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Apres suppression : en (40, 45) : 0, nouveau : 136,3 Draw Controls Trinity
Dessine tous les contrôles d'une fenêtre.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | fenêtre |
Sorties : aucune.
À appeler après 34,12 dans le traitement de la mise à jour. L'exemple peint le contenu en couleur 4 : les cadres des deux boutons (blancs, 15) reviennent. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Draws every control of window Parameter:0 (to call after Set Port in the update handler).
C (llvm-mos)
/* Redessiner les contrôles d'une fenêtre (groupe 36, fonction 3, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A"; /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
libre();
api(32, 19);
}
static void ouvrir(void) { /* 34,1 : une fenêtre avec barre de titre */
reinit();
libre();
p16(0, (uint16_t)&cadre);
p16(2, (uint16_t)titre);
ControlPort.params[4] = 1;
api(34, 1);
fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
libre();
ControlPort.params[0] = type;
ControlPort.params[1] = fenetre;
p16(2, (uint16_t)r);
p16(4, (uint16_t)t);
p16(6, max);
api(36, 1);
return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) { /* 36,6 Get Control Value */
libre();
ControlPort.params[0] = c;
api(36, 6);
return ControlPort.params[1] | ControlPort.params[2] << 8;
}
static uint8_t pixel(int16_t x, int16_t y) { /* 5,33 : couleur du fond en (x, y) */
libre();
p16(0, x);
p16(2, y);
api(5, 33);
return ControlPort.params[0];
}
static Rect ecran = {0, 0, 320, 240};
static void barbouiller(void) { /* le programme peint tout le contenu en couleur 4 */
libre(); ControlPort.params[0] = fenetre; api(34, 12); /* 34,12 Set Port */
libre(); ControlPort.params[0] = 4; api(32, 4);
libre(); p16(0, (uint16_t)&ecran); api(32, 8);
}
static Rect r1 = {10, 10, 70, 24}, r2 = {80, 10, 140, 24};
static const char ok[] = "\002OK", non[] = "\003Non";
int main(void) {
uint8_t a1, a2, b1, b2;
putchar(12); /* écran effacé : on relit des pixels */
ouvrir();
controle(1, &r1, ok, 0); /* deux boutons, cadres en (31, 41) et (101, 41) */
controle(1, &r2, non, 0);
barbouiller();
a1 = pixel(31, 41); a2 = pixel(101, 41);
libre(); ControlPort.params[0] = fenetre; api(36, 3); /* Draw Controls */
b1 = pixel(31, 41); b2 = pixel(101, 41);
reinit();
printf("Cadres peints : %u %u, redessines : %u %u\n", a1, a2, b1, b2);
return 0;
}Cadres peints : 4 4, redessines : 15 15Mad Pascal
// Redessiner les contrôles d'une fenêtre (groupe 36, fonction 3, Trinity).
program ct3;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A')); // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
fenetre: byte;
procedure poser(var r: Rect; g, h, d, b: smallint);
begin
r.g := g; r.h := h; r.d := d; r.b := b;
end;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
NeoWaitMessage;
appel(32, 19);
end;
procedure ouvrir; // 34,1 : une fenêtre avec barre de titre
begin
reinit;
poser(cadre, 20, 20, 220, 140);
wordParams[0] := word(@cadre);
wordParams[1] := word(@titre);
NeoMessage.params[4] := 1;
appel(34, 1);
fenetre := NeoMessage.params[5];
end;
// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
NeoWaitMessage;
NeoMessage.params[0] := t;
NeoMessage.params[1] := fenetre;
wordParams[1] := word(r);
wordParams[2] := word(s);
wordParams[3] := max;
appel(36, 1);
result := NeoMessage.params[0];
end;
function valeur(c: byte): word; // 36,6 Get Control Value
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
appel(36, 6);
result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;
procedure p16(i: byte; v: word); // paramètre 16 bits en Pi, Pi+1
begin
NeoMessage.params[i] := lo(v);
NeoMessage.params[i + 1] := hi(v);
end;
var ecran: Rect;
procedure barbouiller; // le programme peint tout le contenu en couleur 4
begin
poser(ecran, 0, 0, 320, 240);
NeoWaitMessage; NeoMessage.params[0] := fenetre; appel(34, 12); // 34,12 Set Port
NeoMessage.params[0] := 4; appel(32, 4);
wordParams[0] := word(@ecran); appel(32, 8);
end;
const ok: array[0..2] of byte = (2, ord('O'), ord('K'));
non: array[0..3] of byte = (3, ord('N'), ord('o'), ord('n'));
var r1, r2: Rect;
a1, a2, b1, b2: byte;
begin
write(chr(12)); // écran effacé : on relit des pixels
poser(r1, 10, 10, 70, 24); poser(r2, 80, 10, 140, 24);
ouvrir;
controle(1, @r1, @ok, 0); // deux boutons, cadres en (31, 41) et (101, 41)
controle(1, @r2, @non, 0);
barbouiller;
a1 := NeoGetPixel(31, 41); a2 := NeoGetPixel(101, 41);
NeoWaitMessage; NeoMessage.params[0] := fenetre; appel(36, 3); // Draw Controls
b1 := NeoGetPixel(31, 41); b2 := NeoGetPixel(101, 41);
reinit;
writeln('Cadres peints : ', a1, ' ', a2, ', redessines : ', b1, ' ', b2);
end.Cadres peints : 4 4, redessines : 15 15NeoBASIC
10 ' Redessiner les controles d'une fenetre (groupe 36, fonction 3, Trinity)
20 cls : ' ecran efface : on relit des pixels
30 gosub 7000
40 g = 10 : h = 10 : d = 70 : b = 24 : gosub 8000 : s$ = "OK" : gosub 7900 : ty = 1 : mx = 0 : gosub 7100
50 g = 80 : d = 140 : gosub 8000 : s$ = "Non" : gosub 7900 : gosub 7100 : ' cadres en (31, 41) et (101, 41)
60 gosub 2000
70 a1 = point(31, 41) : a2 = point(101, 41)
80 while peek($ff00) : wend : poke $ff04, fw : f = 3 : gosub 8110 : ' Draw Controls
90 b1 = point(31, 41) : b2 = point(101, 41)
100 gosub 8300
110 print "Cadres peints : ";a1;" ";a2;", redessines : ";b1;" ";b2
120 end
2000 ' le programme peint tout le contenu en couleur 4
2010 ec = alloc(8) : doke ec, 0 : doke ec + 2, 0 : doke ec + 4, 320 : doke ec + 6, 240
2020 while peek($ff00) : wend : poke $ff04, fw : poke $ff01, 12 : poke $ff00, 34 : ' 34,12 Set Port
2030 while peek($ff00) : wend : poke $ff04, 4 : poke $ff01, 4 : poke $ff00, 32
2040 while peek($ff00) : wend : doke $ff04, ec : poke $ff01, 8 : poke $ff00, 32
2050 while peek($ff00) : wend : return
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnCadres peints : 4 4, redessines : 15 15Assembleur 65C02 (64tass)
; Redessiner les contrôles d'une fenêtre (groupe 36, fonction 3, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
jsr ouvrir
lda #<c1
ldx #>c1
jsr controle
lda #<c2
ldx #>c2
jsr controle
jsr barbouiller
lda #31
ldy #41
jsr pixel
sta a1
lda #101
ldy #41
jsr pixel
sta a2
jsr WaitMessage
lda fen
sta ControlPort+4
lda #36
ldx #3 ; Draw Controls
jsr appel
lda #31
ldy #41
jsr pixel
sta b1
lda #101
ldy #41
jsr pixel
sta b2
lda #<b0
ldx #>b0
jsr envoi
lda #<t1
ldx #>t1
jsr ecrire
lda a1
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda a2
jsr decimal
lda #<t3
ldx #>t3
jsr ecrire
lda b1
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda b2
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
r1: .word 10, 10, 70, 24
r2: .word 80, 10, 140, 24
ok: .byte 2
.text "OK"
non: .byte 3
.text "Non"
c1: .byte 1 ; deux boutons, cadres en (31, 41)...
.word r1, ok, 0
c2: .byte 1 ; ... et (101, 41)
.word r2, non, 0
a1: .byte 0
a2: .byte 0
b1: .byte 0
b2: .byte 0
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t1: .text "Cadres peints : ", 0
t2: .text " ", 0
t3: .text ", redessines : ", 0
t4: .text " ", 0
; Le programme peint tout le contenu en couleur 4.
barbouiller:
jsr WaitMessage
lda fen
sta ControlPort+4
lda #34
ldx #12 ; 34,12 Set Port
jsr appel
lda #<coul
ldx #>coul
jsr envoi
lda #<peint
ldx #>peint
jsr envoi
rts
coul: .byte 32, 4, 1, 4
peint: .byte 32, 8, 2
.word ecran
ecran: .word 0, 0, 320, 240
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
ldx #>raz
jsr envoi
lda #<nfen
ldx #>nfen
jsr envoi
lda ControlPort+9
sta fen
rts
raz: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen: .byte 34, 1, 5
.word cadre, titre
.byte 1
cadre: .word 20, 20, 220, 140
titre: .byte 1
.text "A" ; chaînes précédées de leur longueur, lues sur place
fen: .byte 0
; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
sta blk
stx blk+1
jsr WaitMessage
ldy #0
lda (blk),y
sta ControlPort+4 ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
lda fen
sta ControlPort+5 ; P1 : fenêtre
ldy #1
_ctl: lda (blk),y
sta ControlPort+5,y ; P2-P7 : Rect, titre, maximum
iny
cpy #7
bne _ctl
lda #36
ldx #1
jsr appel
lda ControlPort+4
rts
; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
jsr WaitMessage
pla
sta ControlPort+4
lda #36
ldx #6
jsr appel
lda ControlPort+5
rts
; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
jsr WaitMessage
pla
sta ControlPort+4
ldx #4
_sv: lda pt,x
sta ControlPort+5,x ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
dex
bpl _sv
lda #36
ldx #9
jsr appel
lda ControlPort+10
rts
pt: .word 0, 0
.byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Cadres peints : 4 4, redessines : 15 1536,4 Draw Control Trinity
Redessine un contrôle.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du contrôle |
Sorties : aucune.
Le bouton est redessiné en entier : cadre blanc (15), intérieur noir (0). NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Redraws control Parameter:0.
C (llvm-mos)
/* Redessiner un contrôle (groupe 36, fonction 4, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A"; /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
libre();
api(32, 19);
}
static void ouvrir(void) { /* 34,1 : une fenêtre avec barre de titre */
reinit();
libre();
p16(0, (uint16_t)&cadre);
p16(2, (uint16_t)titre);
ControlPort.params[4] = 1;
api(34, 1);
fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
libre();
ControlPort.params[0] = type;
ControlPort.params[1] = fenetre;
p16(2, (uint16_t)r);
p16(4, (uint16_t)t);
p16(6, max);
api(36, 1);
return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) { /* 36,6 Get Control Value */
libre();
ControlPort.params[0] = c;
api(36, 6);
return ControlPort.params[1] | ControlPort.params[2] << 8;
}
static uint8_t pixel(int16_t x, int16_t y) { /* 5,33 : couleur du fond en (x, y) */
libre();
p16(0, x);
p16(2, y);
api(5, 33);
return ControlPort.params[0];
}
static Rect ecran = {0, 0, 320, 240};
static void barbouiller(void) { /* le programme peint tout le contenu en couleur 4 */
libre(); ControlPort.params[0] = fenetre; api(34, 12); /* 34,12 Set Port */
libre(); ControlPort.params[0] = 4; api(32, 4);
libre(); p16(0, (uint16_t)&ecran); api(32, 8);
}
static Rect rb = {10, 10, 70, 24};
static const char ok[] = "\002OK";
int main(void) {
uint8_t b, c1, i1, c2, i2;
putchar(12);
ouvrir();
b = controle(1, &rb, ok, 0);
barbouiller();
c1 = pixel(31, 41); i1 = pixel(35, 43); /* cadre et intérieur du bouton */
libre(); ControlPort.params[0] = b; api(36, 4); /* Draw Control */
c2 = pixel(31, 41); i2 = pixel(35, 43);
reinit();
printf("Peint : %u, %u ; redessine : cadre %u, dedans %u\n", c1, i1, c2, i2);
return 0;
}Peint : 4, 4 ; redessine : cadre 15, dedans 0Mad Pascal
// Redessiner un contrôle (groupe 36, fonction 4, Trinity).
program ct4;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A')); // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
fenetre: byte;
procedure poser(var r: Rect; g, h, d, b: smallint);
begin
r.g := g; r.h := h; r.d := d; r.b := b;
end;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
NeoWaitMessage;
appel(32, 19);
end;
procedure ouvrir; // 34,1 : une fenêtre avec barre de titre
begin
reinit;
poser(cadre, 20, 20, 220, 140);
wordParams[0] := word(@cadre);
wordParams[1] := word(@titre);
NeoMessage.params[4] := 1;
appel(34, 1);
fenetre := NeoMessage.params[5];
end;
// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
NeoWaitMessage;
NeoMessage.params[0] := t;
NeoMessage.params[1] := fenetre;
wordParams[1] := word(r);
wordParams[2] := word(s);
wordParams[3] := max;
appel(36, 1);
result := NeoMessage.params[0];
end;
function valeur(c: byte): word; // 36,6 Get Control Value
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
appel(36, 6);
result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;
procedure p16(i: byte; v: word); // paramètre 16 bits en Pi, Pi+1
begin
NeoMessage.params[i] := lo(v);
NeoMessage.params[i + 1] := hi(v);
end;
var ecran: Rect;
procedure barbouiller; // le programme peint tout le contenu en couleur 4
begin
poser(ecran, 0, 0, 320, 240);
NeoWaitMessage; NeoMessage.params[0] := fenetre; appel(34, 12); // 34,12 Set Port
NeoMessage.params[0] := 4; appel(32, 4);
wordParams[0] := word(@ecran); appel(32, 8);
end;
const ok: array[0..2] of byte = (2, ord('O'), ord('K'));
var rb: Rect;
b, c1, i1, c2, i2: byte;
begin
write(chr(12));
poser(rb, 10, 10, 70, 24);
ouvrir;
b := controle(1, @rb, @ok, 0);
barbouiller;
c1 := NeoGetPixel(31, 41); i1 := NeoGetPixel(35, 43); // cadre et intérieur du bouton
NeoWaitMessage; NeoMessage.params[0] := b; appel(36, 4); // Draw Control
c2 := NeoGetPixel(31, 41); i2 := NeoGetPixel(35, 43);
reinit;
writeln('Peint : ', c1, ', ', i1, ' ; redessine : cadre ', c2, ', dedans ', i2);
end.Peint : 4, 4 ; redessine : cadre 15, dedans 0NeoBASIC
10 ' Redessiner un controle (groupe 36, fonction 4, Trinity)
20 cls
30 gosub 7000
40 g = 10 : h = 10 : d = 70 : b = 24 : gosub 8000 : s$ = "OK" : gosub 7900 : ty = 1 : mx = 0 : gosub 7100 : bt = cn
50 gosub 2000
60 c1 = point(31, 41) : i1 = point(35, 43) : ' cadre et interieur du bouton
70 while peek($ff00) : wend : poke $ff04, bt : f = 4 : gosub 8110 : ' Draw Control
80 c2 = point(31, 41) : i2 = point(35, 43)
90 gosub 8300
100 print "Peint : ";c1;", ";i1;" ; redessine : cadre ";c2;", dedans ";i2
110 end
2000 ' le programme peint tout le contenu en couleur 4
2010 ec = alloc(8) : doke ec, 0 : doke ec + 2, 0 : doke ec + 4, 320 : doke ec + 6, 240
2020 while peek($ff00) : wend : poke $ff04, fw : poke $ff01, 12 : poke $ff00, 34 : ' 34,12 Set Port
2030 while peek($ff00) : wend : poke $ff04, 4 : poke $ff01, 4 : poke $ff00, 32
2040 while peek($ff00) : wend : doke $ff04, ec : poke $ff01, 8 : poke $ff00, 32
2050 while peek($ff00) : wend : return
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnPeint : 4, 4 ; redessine : cadre 15, dedans 0Assembleur 65C02 (64tass)
; Redessiner un contrôle (groupe 36, fonction 4, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
jsr ouvrir
lda #<cb
ldx #>cb
jsr controle
sta b
jsr barbouiller
lda #31
ldy #41
jsr pixel
sta c1
lda #35
ldy #43
jsr pixel
sta i1
; cadre et intérieur du bouton
jsr WaitMessage
lda b
sta ControlPort+4
lda #36
ldx #4 ; Draw Control
jsr appel
lda #31
ldy #41
jsr pixel
sta c2
lda #35
ldy #43
jsr pixel
sta i2
lda #<b0
ldx #>b0
jsr envoi
lda #<t1
ldx #>t1
jsr ecrire
lda c1
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda i1
jsr decimal
lda #<t3
ldx #>t3
jsr ecrire
lda c2
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda i2
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
rb: .word 10, 10, 70, 24
ok: .byte 2
.text "OK"
cb: .byte 1 ; bouton
.word rb, ok, 0
b: .byte 0
c1: .byte 0
i1: .byte 0
c2: .byte 0
i2: .byte 0
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t1: .text "Peint : ", 0
t2: .text ", ", 0
t3: .text " ; redessine : cadre ", 0
t4: .text ", dedans ", 0
; Le programme peint tout le contenu en couleur 4.
barbouiller:
jsr WaitMessage
lda fen
sta ControlPort+4
lda #34
ldx #12 ; 34,12 Set Port
jsr appel
lda #<coul
ldx #>coul
jsr envoi
lda #<peint
ldx #>peint
jsr envoi
rts
coul: .byte 32, 4, 1, 4
peint: .byte 32, 8, 2
.word ecran
ecran: .word 0, 0, 320, 240
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
ldx #>raz
jsr envoi
lda #<nfen
ldx #>nfen
jsr envoi
lda ControlPort+9
sta fen
rts
raz: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen: .byte 34, 1, 5
.word cadre, titre
.byte 1
cadre: .word 20, 20, 220, 140
titre: .byte 1
.text "A" ; chaînes précédées de leur longueur, lues sur place
fen: .byte 0
; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
sta blk
stx blk+1
jsr WaitMessage
ldy #0
lda (blk),y
sta ControlPort+4 ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
lda fen
sta ControlPort+5 ; P1 : fenêtre
ldy #1
_ctl: lda (blk),y
sta ControlPort+5,y ; P2-P7 : Rect, titre, maximum
iny
cpy #7
bne _ctl
lda #36
ldx #1
jsr appel
lda ControlPort+4
rts
; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
jsr WaitMessage
pla
sta ControlPort+4
lda #36
ldx #6
jsr appel
lda ControlPort+5
rts
; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
jsr WaitMessage
pla
sta ControlPort+4
ldx #4
_sv: lda pt,x
sta ControlPort+5,x ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
dex
bpl _sv
lda #36
ldx #9
jsr appel
lda ControlPort+10
rts
pt: .word 0, 0
.byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Peint : 4, 4 ; redessine : cadre 15, dedans 036,5 Set Control Value Trinity
Donne une valeur à un contrôle et le redessine.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du contrôle |
P1-P2 | uint16 | valeur : 0 ou 1 pour les cases, 0 au maximum pour les barres |
Sorties : aucune.
Au banc, une valeur au-delà du maximum d'une barre est ramenée au maximum, sans erreur. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Sets the value of control Parameter:0 to Parameters:1,2 (0/1 for boxes, 0..max for scroll bars) and redraws it.
C (llvm-mos)
/* Donner une valeur à un contrôle (groupe 36, fonction 5, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A"; /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
libre();
api(32, 19);
}
static void ouvrir(void) { /* 34,1 : une fenêtre avec barre de titre */
reinit();
libre();
p16(0, (uint16_t)&cadre);
p16(2, (uint16_t)titre);
ControlPort.params[4] = 1;
api(34, 1);
fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
libre();
ControlPort.params[0] = type;
ControlPort.params[1] = fenetre;
p16(2, (uint16_t)r);
p16(4, (uint16_t)t);
p16(6, max);
api(36, 1);
return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) { /* 36,6 Get Control Value */
libre();
ControlPort.params[0] = c;
api(36, 6);
return ControlPort.params[1] | ControlPort.params[2] << 8;
}
static Rect rc = {10, 30, 110, 42}, rs = {180, 0, 192, 100};
static const char option[] = "\006Option";
static uint8_t donner(uint8_t c, uint16_t v) { /* Set Control Value */
libre();
ControlPort.params[0] = c;
p16(1, v);
api(36, 5);
return ControlPort.error;
}
int main(void) {
uint8_t c, s, e;
uint16_t vc, v1, v2;
ouvrir();
c = controle(2, &rc, option, 0);
s = controle(4, &rs, titre, 50);
donner(c, 1);
vc = valeur(c);
donner(s, 25);
v1 = valeur(s);
e = donner(s, 99); /* au-delà du maximum : ramené à 50 */
v2 = valeur(s);
reinit();
printf("Case : %u ; barre : %u, puis 99 -> %u (erreur %u)\n", vc, v1, v2, e);
return 0;
}Case : 1 ; barre : 25, puis 99 -> 50 (erreur 0)Mad Pascal
// Donner une valeur à un contrôle (groupe 36, fonction 5, Trinity).
program ct5;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A')); // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
fenetre: byte;
procedure poser(var r: Rect; g, h, d, b: smallint);
begin
r.g := g; r.h := h; r.d := d; r.b := b;
end;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
NeoWaitMessage;
appel(32, 19);
end;
procedure ouvrir; // 34,1 : une fenêtre avec barre de titre
begin
reinit;
poser(cadre, 20, 20, 220, 140);
wordParams[0] := word(@cadre);
wordParams[1] := word(@titre);
NeoMessage.params[4] := 1;
appel(34, 1);
fenetre := NeoMessage.params[5];
end;
// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
NeoWaitMessage;
NeoMessage.params[0] := t;
NeoMessage.params[1] := fenetre;
wordParams[1] := word(r);
wordParams[2] := word(s);
wordParams[3] := max;
appel(36, 1);
result := NeoMessage.params[0];
end;
function valeur(c: byte): word; // 36,6 Get Control Value
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
appel(36, 6);
result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;
procedure p16(i: byte; v: word); // paramètre 16 bits en Pi, Pi+1
begin
NeoMessage.params[i] := lo(v);
NeoMessage.params[i + 1] := hi(v);
end;
const option: array[0..6] of byte = (6, ord('O'), ord('p'), ord('t'), ord('i'), ord('o'), ord('n'));
function donner(c: byte; v: word): byte; // Set Control Value
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
p16(1, v);
appel(36, 5);
result := NeoMessage.error;
end;
var rc, rs: Rect;
c, s, e: byte;
vc, v1, v2: word;
begin
poser(rc, 10, 30, 110, 42); poser(rs, 180, 0, 192, 100);
ouvrir;
c := controle(2, @rc, @option, 0);
s := controle(4, @rs, @titre, 50);
donner(c, 1);
vc := valeur(c);
donner(s, 25);
v1 := valeur(s);
e := donner(s, 99); // au-delà du maximum : ramené à 50
v2 := valeur(s);
reinit;
writeln('Case : ', vc, ' ; barre : ', v1, ', puis 99 -> ', v2, ' (erreur ', e, ')');
end.Case : 1 ; barre : 25, puis 99 -> 50 (erreur 0)NeoBASIC
10 ' Donner une valeur a un controle (groupe 36, fonction 5, Trinity)
20 gosub 7000
30 g = 10 : h = 30 : d = 110 : b = 42 : gosub 8000 : s$ = "Option" : gosub 7900 : ty = 2 : mx = 0 : gosub 7100 : ca = cn
40 g = 180 : h = 0 : d = 192 : b = 100 : gosub 8000 : ch = tf : ty = 4 : mx = 50 : gosub 7100 : ba = cn
50 c = ca : vv = 1 : gosub 2000 : c = ca : gosub 7200 : vc = v
60 c = ba : vv = 25 : gosub 2000 : gosub 7200 : v1 = v
70 vv = 99 : gosub 2000 : e9 = e : gosub 7200 : v2 = v : ' au-dela du maximum : ramene a 50
80 gosub 8300
90 print "Case : ";vc;" ; barre : ";v1;", puis 99 -> ";v2;" (erreur ";e9;")"
100 end
2000 ' Set Control Value : controle c, valeur vv
2010 while peek($ff00) : wend : poke $ff04, c : doke $ff05, vv : f = 5 : goto 8110
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnCase : 1 ; barre : 25, puis 99 -> 50 (erreur 0)Assembleur 65C02 (64tass)
; Donner une valeur à un contrôle (groupe 36, fonction 5, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr ouvrir
lda #<cc
ldx #>cc
jsr controle
sta c
lda #<cs
ldx #>cs
jsr controle
sta s
jsr WaitMessage
lda c
sta ControlPort+4
lda #1
sta ControlPort+5
stz ControlPort+6
lda #36
ldx #5 ; Set Control Value
jsr appel
lda c
jsr valeur
sta vc
jsr WaitMessage
lda s
sta ControlPort+4
lda #25
sta ControlPort+5
stz ControlPort+6
lda #36
ldx #5 ; Set Control Value
jsr appel
lda s
jsr valeur
sta v1
jsr WaitMessage
lda s
sta ControlPort+4
lda #99
sta ControlPort+5
stz ControlPort+6
lda #36
ldx #5 ; au-delà du maximum : ramené à 50
jsr appel
lda ControlPort+2
sta e
lda s
jsr valeur
sta v2
lda #<b0
ldx #>b0
jsr envoi
lda #<t1
ldx #>t1
jsr ecrire
lda vc
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda v1
jsr decimal
lda #<t3
ldx #>t3
jsr ecrire
lda v2
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda e
jsr decimal
lda #<t5
ldx #>t5
jsr ecrire
lda #13
jsr WriteCharacter
rts
rc: .word 10, 30, 110, 42
rs: .word 180, 0, 192, 100
option: .byte 6
.text "Option"
cc: .byte 2 ; case à cocher
.word rc, option, 0
c: .byte 0
cs: .byte 4 ; barre, maximum 50
.word rs, titre, 50
s: .byte 0
vc: .byte 0
v1: .byte 0
e: .byte 0
v2: .byte 0
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t1: .text "Case : ", 0
t2: .text " ; barre : ", 0
t3: .text ", puis 99 -> ", 0
t4: .text " (erreur ", 0
t5: .text ")", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
ldx #>raz
jsr envoi
lda #<nfen
ldx #>nfen
jsr envoi
lda ControlPort+9
sta fen
rts
raz: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen: .byte 34, 1, 5
.word cadre, titre
.byte 1
cadre: .word 20, 20, 220, 140
titre: .byte 1
.text "A" ; chaînes précédées de leur longueur, lues sur place
fen: .byte 0
; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
sta blk
stx blk+1
jsr WaitMessage
ldy #0
lda (blk),y
sta ControlPort+4 ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
lda fen
sta ControlPort+5 ; P1 : fenêtre
ldy #1
_ctl: lda (blk),y
sta ControlPort+5,y ; P2-P7 : Rect, titre, maximum
iny
cpy #7
bne _ctl
lda #36
ldx #1
jsr appel
lda ControlPort+4
rts
; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
jsr WaitMessage
pla
sta ControlPort+4
lda #36
ldx #6
jsr appel
lda ControlPort+5
rts
; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
jsr WaitMessage
pla
sta ControlPort+4
ldx #4
_sv: lda pt,x
sta ControlPort+5,x ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
dex
bpl _sv
lda #36
ldx #9
jsr appel
lda ControlPort+10
rts
pt: .word 0, 0
.byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Case : 1 ; barre : 25, puis 99 -> 50 (erreur 0)36,6 Get Control Value Trinity
Rend la valeur d'un contrôle.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du contrôle |
| Octets | Type | Rôle |
|---|---|---|
P1-P2 | uint16 | valeur |
Un clic (36,9) fait basculer la case à cocher à chaque fois ; le bouton radio passe à 1 et y reste. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Returns the value of control Parameter:0 in Parameters:1,2.
C (llvm-mos)
/* Lire la valeur d'un contrôle (groupe 36, fonction 6, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A"; /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
libre();
api(32, 19);
}
static void ouvrir(void) { /* 34,1 : une fenêtre avec barre de titre */
reinit();
libre();
p16(0, (uint16_t)&cadre);
p16(2, (uint16_t)titre);
ControlPort.params[4] = 1;
api(34, 1);
fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
libre();
ControlPort.params[0] = type;
ControlPort.params[1] = fenetre;
p16(2, (uint16_t)r);
p16(4, (uint16_t)t);
p16(6, max);
api(36, 1);
return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) { /* 36,6 Get Control Value */
libre();
ControlPort.params[0] = c;
api(36, 6);
return ControlPort.params[1] | ControlPort.params[2] << 8;
}
static uint8_t suivre(uint8_t c, int16_t x, int16_t y, uint8_t phase) { /* 36,9 Track Control : 1 si le contrôle a agi */
libre();
ControlPort.params[0] = c;
p16(1, x);
p16(3, y);
ControlPort.params[5] = phase; /* 0 bouton enfoncé, 1 mouvement, 2 bouton relâché */
api(36, 9);
return ControlPort.params[6];
}
static uint8_t clic(uint8_t c, int16_t x, int16_t y) { /* enfoncé puis relâché au même endroit */
suivre(c, x, y, 0);
return suivre(c, x, y, 2);
}
static Rect rc = {10, 30, 110, 42}, rr = {10, 48, 110, 60};
static const char option[] = "\006Option", radio[] = "\005Radio";
int main(void) {
uint8_t c, r;
uint16_t c0, c1, c2, r1, r2;
ouvrir();
c = controle(2, &rc, option, 0); /* case à cocher, en (31, 61) à l'écran */
r = controle(3, &rr, radio, 0); /* bouton radio, en (31, 79) */
c0 = valeur(c);
clic(c, 40, 65); c1 = valeur(c); /* la case bascule à chaque clic */
clic(c, 40, 65); c2 = valeur(c);
clic(r, 40, 82); r1 = valeur(r); /* le bouton radio reste à 1 */
clic(r, 40, 82); r2 = valeur(r);
reinit();
printf("Case : %u, %u, %u ; radio : %u, %u\n", c0, c1, c2, r1, r2);
return 0;
}Case : 0, 1, 0 ; radio : 1, 1Mad Pascal
// Lire la valeur d'un contrôle (groupe 36, fonction 6, Trinity).
program ct6;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A')); // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
fenetre: byte;
procedure poser(var r: Rect; g, h, d, b: smallint);
begin
r.g := g; r.h := h; r.d := d; r.b := b;
end;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
NeoWaitMessage;
appel(32, 19);
end;
procedure ouvrir; // 34,1 : une fenêtre avec barre de titre
begin
reinit;
poser(cadre, 20, 20, 220, 140);
wordParams[0] := word(@cadre);
wordParams[1] := word(@titre);
NeoMessage.params[4] := 1;
appel(34, 1);
fenetre := NeoMessage.params[5];
end;
// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
NeoWaitMessage;
NeoMessage.params[0] := t;
NeoMessage.params[1] := fenetre;
wordParams[1] := word(r);
wordParams[2] := word(s);
wordParams[3] := max;
appel(36, 1);
result := NeoMessage.params[0];
end;
function valeur(c: byte): word; // 36,6 Get Control Value
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
appel(36, 6);
result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;
procedure p16(i: byte; v: word); // paramètre 16 bits en Pi, Pi+1
begin
NeoMessage.params[i] := lo(v);
NeoMessage.params[i + 1] := hi(v);
end;
function suivre(c: byte; x, y: smallint; phase: byte): byte; // 36,9 Track Control : 1 si le contrôle a agi
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
p16(1, word(x));
p16(3, word(y));
NeoMessage.params[5] := phase; // 0 bouton enfoncé, 1 mouvement, 2 bouton relâché
appel(36, 9);
result := NeoMessage.params[6];
end;
function clic(c: byte; x, y: smallint): byte; // enfoncé puis relâché au même endroit
begin
suivre(c, x, y, 0);
result := suivre(c, x, y, 2);
end;
const option: array[0..6] of byte = (6, ord('O'), ord('p'), ord('t'), ord('i'), ord('o'), ord('n'));
radio: array[0..5] of byte = (5, ord('R'), ord('a'), ord('d'), ord('i'), ord('o'));
var rc, rr: Rect;
c, r: byte;
c0, c1, c2, r1, r2: word;
begin
poser(rc, 10, 30, 110, 42); poser(rr, 10, 48, 110, 60);
ouvrir;
c := controle(2, @rc, @option, 0); // case à cocher, en (31, 61) à l'écran
r := controle(3, @rr, @radio, 0); // bouton radio, en (31, 79)
c0 := valeur(c);
clic(c, 40, 65); c1 := valeur(c); // la case bascule à chaque clic
clic(c, 40, 65); c2 := valeur(c);
clic(r, 40, 82); r1 := valeur(r); // le bouton radio reste à 1
clic(r, 40, 82); r2 := valeur(r);
reinit;
writeln('Case : ', c0, ', ', c1, ', ', c2, ' ; radio : ', r1, ', ', r2);
end.Case : 0, 1, 0 ; radio : 1, 1NeoBASIC
10 ' Lire la valeur d'un controle (groupe 36, fonction 6, Trinity)
20 gosub 7000
30 g = 10 : h = 30 : d = 110 : b = 42 : gosub 8000 : s$ = "Option" : gosub 7900 : ty = 2 : mx = 0 : gosub 7100 : ca = cn : ' case, en (31, 61)
40 h = 48 : b = 60 : gosub 8000 : s$ = "Radio" : gosub 7900 : ty = 3 : gosub 7100 : ra = cn : ' bouton radio, en (31, 79)
50 c = ca : gosub 7200 : c0 = v
60 x = 40 : y = 65 : gosub 7400 : gosub 7200 : c1 = v : ' la case bascule a chaque clic
70 gosub 7400 : gosub 7200 : c2 = v
80 c = ra : y = 82 : gosub 7400 : gosub 7200 : r1 = v : ' le bouton radio reste a 1
90 gosub 7400 : gosub 7200 : r2 = v
100 gosub 8300
110 print "Case : ";c0;", ";c1;", ";c2;" ; radio : ";r1;", ";r2
120 end
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnCase : 0, 1, 0 ; radio : 1, 1Assembleur 65C02 (64tass)
; Lire la valeur d'un contrôle (groupe 36, fonction 6, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr ouvrir
lda #<cc
ldx #>cc
jsr controle
sta c
lda #<cr
ldx #>cr
jsr controle
sta r
lda c
jsr valeur
sta c0
lda #<40
sta pt
lda #>40
sta pt+1
lda #65
sta pt+2
stz pt+3
lda #0 ; la case bascule à chaque clic
sta pt+4
lda c
jsr suivre
lda #<40
sta pt
lda #>40
sta pt+1
lda #65
sta pt+2
stz pt+3
lda #2 ; relâché
sta pt+4
lda c
jsr suivre
lda c
jsr valeur
sta c1
lda #<40
sta pt
lda #>40
sta pt+1
lda #65
sta pt+2
stz pt+3
lda #0 ; enfoncé
sta pt+4
lda c
jsr suivre
lda #<40
sta pt
lda #>40
sta pt+1
lda #65
sta pt+2
stz pt+3
lda #2 ; relâché
sta pt+4
lda c
jsr suivre
lda c
jsr valeur
sta c2
lda #<40
sta pt
lda #>40
sta pt+1
lda #82
sta pt+2
stz pt+3
lda #0 ; le bouton radio reste à 1
sta pt+4
lda r
jsr suivre
lda #<40
sta pt
lda #>40
sta pt+1
lda #82
sta pt+2
stz pt+3
lda #2 ; relâché
sta pt+4
lda r
jsr suivre
lda r
jsr valeur
sta r1
lda #<40
sta pt
lda #>40
sta pt+1
lda #82
sta pt+2
stz pt+3
lda #0 ; enfoncé
sta pt+4
lda r
jsr suivre
lda #<40
sta pt
lda #>40
sta pt+1
lda #82
sta pt+2
stz pt+3
lda #2 ; relâché
sta pt+4
lda r
jsr suivre
lda r
jsr valeur
sta r2
lda #<b0
ldx #>b0
jsr envoi
lda #<t1
ldx #>t1
jsr ecrire
lda c0
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda c1
jsr decimal
lda #<t3
ldx #>t3
jsr ecrire
lda c2
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda r1
jsr decimal
lda #<t5
ldx #>t5
jsr ecrire
lda r2
jsr decimal
lda #13
jsr WriteCharacter
rts
rc: .word 10, 30, 110, 42
rr: .word 10, 48, 110, 60
option: .byte 6
.text "Option"
radio: .byte 5
.text "Radio"
cc: .byte 2 ; case à cocher, en (31, 61) à l'écran
.word rc, option, 0
c: .byte 0
cr: .byte 3 ; bouton radio, en (31, 79)
.word rr, radio, 0
r: .byte 0
c0: .byte 0
c1: .byte 0
c2: .byte 0
r1: .byte 0
r2: .byte 0
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t1: .text "Case : ", 0
t2: .text ", ", 0
t3: .text ", ", 0
t4: .text " ; radio : ", 0
t5: .text ", ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
ldx #>raz
jsr envoi
lda #<nfen
ldx #>nfen
jsr envoi
lda ControlPort+9
sta fen
rts
raz: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen: .byte 34, 1, 5
.word cadre, titre
.byte 1
cadre: .word 20, 20, 220, 140
titre: .byte 1
.text "A" ; chaînes précédées de leur longueur, lues sur place
fen: .byte 0
; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
sta blk
stx blk+1
jsr WaitMessage
ldy #0
lda (blk),y
sta ControlPort+4 ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
lda fen
sta ControlPort+5 ; P1 : fenêtre
ldy #1
_ctl: lda (blk),y
sta ControlPort+5,y ; P2-P7 : Rect, titre, maximum
iny
cpy #7
bne _ctl
lda #36
ldx #1
jsr appel
lda ControlPort+4
rts
; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
jsr WaitMessage
pla
sta ControlPort+4
lda #36
ldx #6
jsr appel
lda ControlPort+5
rts
; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
jsr WaitMessage
pla
sta ControlPort+4
ldx #4
_sv: lda pt,x
sta ControlPort+5,x ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
dex
bpl _sv
lda #36
ldx #9
jsr appel
lda ControlPort+10
rts
pt: .word 0, 0
.byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Case : 0, 1, 0 ; radio : 1, 136,7 Set Control Flags Trinity
Change les options d'un contrôle et le redessine.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du contrôle |
P1 | uint8 | options : bit 0 inactif |
Sorties : aucune.
Un contrôle inactif est dessiné en gris et ignore la souris (36,9) et les touches (36,10). NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Sets the flags of control Parameter:0 (bit 0 disabled : drawn grey, ignores tracking and keys) and redraws it.
C (llvm-mos)
/* Rendre un contrôle inactif (groupe 36, fonction 7, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A"; /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
libre();
api(32, 19);
}
static void ouvrir(void) { /* 34,1 : une fenêtre avec barre de titre */
reinit();
libre();
p16(0, (uint16_t)&cadre);
p16(2, (uint16_t)titre);
ControlPort.params[4] = 1;
api(34, 1);
fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
libre();
ControlPort.params[0] = type;
ControlPort.params[1] = fenetre;
p16(2, (uint16_t)r);
p16(4, (uint16_t)t);
p16(6, max);
api(36, 1);
return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) { /* 36,6 Get Control Value */
libre();
ControlPort.params[0] = c;
api(36, 6);
return ControlPort.params[1] | ControlPort.params[2] << 8;
}
static uint8_t suivre(uint8_t c, int16_t x, int16_t y, uint8_t phase) { /* 36,9 Track Control : 1 si le contrôle a agi */
libre();
ControlPort.params[0] = c;
p16(1, x);
p16(3, y);
ControlPort.params[5] = phase; /* 0 bouton enfoncé, 1 mouvement, 2 bouton relâché */
api(36, 9);
return ControlPort.params[6];
}
static uint8_t clic(uint8_t c, int16_t x, int16_t y) { /* enfoncé puis relâché au même endroit */
suivre(c, x, y, 0);
return suivre(c, x, y, 2);
}
static Rect rc = {10, 30, 110, 42};
static const char option[] = "\006Option";
static void options(uint8_t c, uint8_t o) { /* Set Control Flags : bit 0 inactif */
libre();
ControlPort.params[0] = c;
ControlPort.params[1] = o;
api(36, 7);
}
int main(void) {
uint8_t c, a1, a2;
uint16_t v1, v2;
ouvrir();
c = controle(2, &rc, option, 0);
options(c, 1); /* inactif : dessiné en gris, ignore la souris */
a1 = clic(c, 40, 65); v1 = valeur(c);
options(c, 0);
a2 = clic(c, 40, 65); v2 = valeur(c);
reinit();
printf("Inactive : %u, valeur %u ; active : %u, valeur %u\n", a1, v1, a2, v2);
return 0;
}Inactive : 0, valeur 0 ; active : 1, valeur 1Mad Pascal
// Rendre un contrôle inactif (groupe 36, fonction 7, Trinity).
program ct7;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A')); // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
fenetre: byte;
procedure poser(var r: Rect; g, h, d, b: smallint);
begin
r.g := g; r.h := h; r.d := d; r.b := b;
end;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
NeoWaitMessage;
appel(32, 19);
end;
procedure ouvrir; // 34,1 : une fenêtre avec barre de titre
begin
reinit;
poser(cadre, 20, 20, 220, 140);
wordParams[0] := word(@cadre);
wordParams[1] := word(@titre);
NeoMessage.params[4] := 1;
appel(34, 1);
fenetre := NeoMessage.params[5];
end;
// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
NeoWaitMessage;
NeoMessage.params[0] := t;
NeoMessage.params[1] := fenetre;
wordParams[1] := word(r);
wordParams[2] := word(s);
wordParams[3] := max;
appel(36, 1);
result := NeoMessage.params[0];
end;
function valeur(c: byte): word; // 36,6 Get Control Value
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
appel(36, 6);
result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;
procedure p16(i: byte; v: word); // paramètre 16 bits en Pi, Pi+1
begin
NeoMessage.params[i] := lo(v);
NeoMessage.params[i + 1] := hi(v);
end;
function suivre(c: byte; x, y: smallint; phase: byte): byte; // 36,9 Track Control : 1 si le contrôle a agi
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
p16(1, word(x));
p16(3, word(y));
NeoMessage.params[5] := phase; // 0 bouton enfoncé, 1 mouvement, 2 bouton relâché
appel(36, 9);
result := NeoMessage.params[6];
end;
function clic(c: byte; x, y: smallint): byte; // enfoncé puis relâché au même endroit
begin
suivre(c, x, y, 0);
result := suivre(c, x, y, 2);
end;
const option: array[0..6] of byte = (6, ord('O'), ord('p'), ord('t'), ord('i'), ord('o'), ord('n'));
procedure options(c, o: byte); // Set Control Flags : bit 0 inactif
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
NeoMessage.params[1] := o;
appel(36, 7);
end;
var rc: Rect;
c, a1, a2: byte;
v1, v2: word;
begin
poser(rc, 10, 30, 110, 42);
ouvrir;
c := controle(2, @rc, @option, 0);
options(c, 1); // inactif : dessiné en gris, ignore la souris
a1 := clic(c, 40, 65); v1 := valeur(c);
options(c, 0);
a2 := clic(c, 40, 65); v2 := valeur(c);
reinit;
writeln('Inactive : ', a1, ', valeur ', v1, ' ; active : ', a2, ', valeur ', v2);
end.Inactive : 0, valeur 0 ; active : 1, valeur 1NeoBASIC
10 ' Rendre un controle inactif (groupe 36, fonction 7, Trinity)
20 gosub 7000
30 g = 10 : h = 30 : d = 110 : b = 42 : gosub 8000 : s$ = "Option" : gosub 7900 : ty = 2 : mx = 0 : gosub 7100 : c = cn
40 o = 1 : gosub 2000 : ' inactif : dessine en gris, ignore la souris
50 x = 40 : y = 65 : gosub 7400 : a1 = ag : gosub 7200 : v1 = v
60 o = 0 : gosub 2000
70 gosub 7400 : a2 = ag : gosub 7200 : v2 = v
80 gosub 8300
90 print "Inactive : ";a1;", valeur ";v1;" ; active : ";a2;", valeur ";v2
100 end
2000 ' Set Control Flags : controle c, options o (bit 0 inactif)
2010 while peek($ff00) : wend : poke $ff04, c : poke $ff05, o : f = 7 : goto 8110
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnInactive : 0, valeur 0 ; active : 1, valeur 1Assembleur 65C02 (64tass)
; Rendre un contrôle inactif (groupe 36, fonction 7, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr ouvrir
lda #<cc
ldx #>cc
jsr controle
sta c
jsr WaitMessage
lda c
sta ControlPort+4
lda #1
sta ControlPort+5
lda #36
ldx #7 ; Set Control Flags, bit 0 : inactif, ignore la souris
jsr appel
lda #<40
sta pt
lda #>40
sta pt+1
lda #65
sta pt+2
stz pt+3
lda #0 ; enfoncé
sta pt+4
lda c
jsr suivre
lda #<40
sta pt
lda #>40
sta pt+1
lda #65
sta pt+2
stz pt+3
lda #2 ; relâché
sta pt+4
lda c
jsr suivre
sta a1
lda c
jsr valeur
sta v1
jsr WaitMessage
lda c
sta ControlPort+4
lda #0
sta ControlPort+5
lda #36
ldx #7 ; Set Control Flags : actif
jsr appel
lda #<40
sta pt
lda #>40
sta pt+1
lda #65
sta pt+2
stz pt+3
lda #0 ; enfoncé
sta pt+4
lda c
jsr suivre
lda #<40
sta pt
lda #>40
sta pt+1
lda #65
sta pt+2
stz pt+3
lda #2 ; relâché
sta pt+4
lda c
jsr suivre
sta a2
lda c
jsr valeur
sta v2
lda #<b0
ldx #>b0
jsr envoi
lda #<t1
ldx #>t1
jsr ecrire
lda a1
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda v1
jsr decimal
lda #<t3
ldx #>t3
jsr ecrire
lda a2
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda v2
jsr decimal
lda #13
jsr WriteCharacter
rts
rc: .word 10, 30, 110, 42
option: .byte 6
.text "Option"
cc: .byte 2 ; case à cocher
.word rc, option, 0
c: .byte 0
a1: .byte 0
v1: .byte 0
a2: .byte 0
v2: .byte 0
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t1: .text "Inactive : ", 0
t2: .text ", valeur ", 0
t3: .text " ; active : ", 0
t4: .text ", valeur ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
ldx #>raz
jsr envoi
lda #<nfen
ldx #>nfen
jsr envoi
lda ControlPort+9
sta fen
rts
raz: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen: .byte 34, 1, 5
.word cadre, titre
.byte 1
cadre: .word 20, 20, 220, 140
titre: .byte 1
.text "A" ; chaînes précédées de leur longueur, lues sur place
fen: .byte 0
; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
sta blk
stx blk+1
jsr WaitMessage
ldy #0
lda (blk),y
sta ControlPort+4 ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
lda fen
sta ControlPort+5 ; P1 : fenêtre
ldy #1
_ctl: lda (blk),y
sta ControlPort+5,y ; P2-P7 : Rect, titre, maximum
iny
cpy #7
bne _ctl
lda #36
ldx #1
jsr appel
lda ControlPort+4
rts
; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
jsr WaitMessage
pla
sta ControlPort+4
lda #36
ldx #6
jsr appel
lda ControlPort+5
rts
; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
jsr WaitMessage
pla
sta ControlPort+4
ldx #4
_sv: lda pt,x
sta ControlPort+5,x ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
dex
bpl _sv
lda #36
ldx #9
jsr appel
lda ControlPort+10
rts
pt: .word 0, 0
.byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Inactive : 0, valeur 0 ; active : 1, valeur 136,8 Find Control Trinity
Rend le contrôle de la fenêtre de devant sous un point, et la partie touchée.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X du point |
P2-P3 | int16 | Y du point |
| Octets | Type | Rôle |
|---|---|---|
P4 | uint8 | contrôle (0 si aucun) |
P5 | uint8 | partie : 1 corps ; barres : 2 première flèche, 3 seconde flèche, 4 page avant le curseur, 5 page après, 6 curseur |
Relevé au banc pour la barre de 12 × 100 pixels : flèches de 8 lignes en haut et en bas, curseur de 4 lignes (y 79 à 82 pour la valeur 25 sur 50). NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Returns in Parameter:4 the control of the frontmost window under Parameters:0,1 (X), Parameters:2,3 (Y) (0 if none) and in Parameter:5 the part : 1 body ; scroll bars : 2 first arrow, 3 second arrow, 4 page before the thumb, 5 page after, 6 thumb.
C (llvm-mos)
/* Trouver le contrôle sous un point (groupe 36, fonction 8, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A"; /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
libre();
api(32, 19);
}
static void ouvrir(void) { /* 34,1 : une fenêtre avec barre de titre */
reinit();
libre();
p16(0, (uint16_t)&cadre);
p16(2, (uint16_t)titre);
ControlPort.params[4] = 1;
api(34, 1);
fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
libre();
ControlPort.params[0] = type;
ControlPort.params[1] = fenetre;
p16(2, (uint16_t)r);
p16(4, (uint16_t)t);
p16(6, max);
api(36, 1);
return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) { /* 36,6 Get Control Value */
libre();
ControlPort.params[0] = c;
api(36, 6);
return ControlPort.params[1] | ControlPort.params[2] << 8;
}
static Rect rb = {10, 10, 70, 24}, rs = {180, 0, 192, 100};
static const char ok[] = "\002OK";
static const int16_t py[6] = {45, 33, 125, 50, 80, 110};
static const int16_t px[6] = {40, 205, 205, 205, 205, 205};
static const char *nom[6] = {"Bouton", "Fleche du haut", "Fleche du bas", "Page avant", "Curseur", "Page apres"};
int main(void) {
uint8_t s, i, c[6], z[6];
ouvrir();
controle(1, &rb, ok, 0);
s = controle(4, &rs, titre, 50); /* barre en x 201 à 212, y 31 à 130 */
libre(); ControlPort.params[0] = s; p16(1, 25); api(36, 5); /* curseur au milieu : y 79 à 82 */
for (i = 0; i < 6; i++) {
libre(); p16(0, px[i]); p16(2, py[i]); api(36, 8); /* Find Control */
c[i] = ControlPort.params[4];
z[i] = ControlPort.params[5];
}
reinit();
for (i = 0; i < 6; i++)
printf("%s : %u, %u\n", nom[i], c[i], z[i]);
return 0;
}Bouton : 1, 1
Fleche du haut : 2, 2
Fleche du bas : 2, 3
Page avant : 2, 4
Curseur : 2, 6
Page apres : 2, 5Mad Pascal
// Trouver le contrôle sous un point (groupe 36, fonction 8, Trinity).
program ct8;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A')); // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
fenetre: byte;
procedure poser(var r: Rect; g, h, d, b: smallint);
begin
r.g := g; r.h := h; r.d := d; r.b := b;
end;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
NeoWaitMessage;
appel(32, 19);
end;
procedure ouvrir; // 34,1 : une fenêtre avec barre de titre
begin
reinit;
poser(cadre, 20, 20, 220, 140);
wordParams[0] := word(@cadre);
wordParams[1] := word(@titre);
NeoMessage.params[4] := 1;
appel(34, 1);
fenetre := NeoMessage.params[5];
end;
// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
NeoWaitMessage;
NeoMessage.params[0] := t;
NeoMessage.params[1] := fenetre;
wordParams[1] := word(r);
wordParams[2] := word(s);
wordParams[3] := max;
appel(36, 1);
result := NeoMessage.params[0];
end;
function valeur(c: byte): word; // 36,6 Get Control Value
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
appel(36, 6);
result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;
procedure p16(i: byte; v: word); // paramètre 16 bits en Pi, Pi+1
begin
NeoMessage.params[i] := lo(v);
NeoMessage.params[i + 1] := hi(v);
end;
const ok: array[0..2] of byte = (2, ord('O'), ord('K'));
px: array[0..5] of word = (40, 205, 205, 205, 205, 205);
py: array[0..5] of word = (45, 33, 125, 50, 80, 110);
var rb, rs: Rect;
s, i: byte;
c, z: array[0..5] of byte;
begin
poser(rb, 10, 10, 70, 24); poser(rs, 180, 0, 192, 100);
ouvrir;
controle(1, @rb, @ok, 0);
s := controle(4, @rs, @titre, 50); // barre en x 201 à 212, y 31 à 130
NeoWaitMessage; NeoMessage.params[0] := s; p16(1, 25); appel(36, 5); // curseur au milieu : y 79 à 82
for i := 0 to 5 do begin
NeoWaitMessage;
wordParams[0] := px[i];
wordParams[1] := py[i];
appel(36, 8); // Find Control
c[i] := NeoMessage.params[4];
z[i] := NeoMessage.params[5];
end;
reinit;
writeln('Bouton : ', c[0], ', ', z[0]);
writeln('Fleche du haut : ', c[1], ', ', z[1]);
writeln('Fleche du bas : ', c[2], ', ', z[2]);
writeln('Page avant : ', c[3], ', ', z[3]);
writeln('Curseur : ', c[4], ', ', z[4]);
writeln('Page apres : ', c[5], ', ', z[5]);
end.Bouton : 1, 1
Fleche du haut : 2, 2
Fleche du bas : 2, 3
Page avant : 2, 4
Curseur : 2, 6
Page apres : 2, 5NeoBASIC
10 ' Trouver le controle sous un point (groupe 36, fonction 8, Trinity)
20 gosub 7000
30 g = 10 : h = 10 : d = 70 : b = 24 : gosub 8000 : s$ = "OK" : gosub 7900 : ty = 1 : mx = 0 : gosub 7100
40 g = 180 : h = 0 : d = 192 : b = 100 : gosub 8000 : ch = tf : ty = 4 : mx = 50 : gosub 7100 : ba = cn : ' x 201 a 212, y 31 a 130
50 while peek($ff00) : wend : poke $ff04, ba : doke $ff05, 25 : f = 5 : gosub 8110 : ' curseur au milieu : y 79 a 82
60 dim c(5), z(5)
70 for k = 0 to 5 : read x, y
80 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y : f = 8 : gosub 8110 : ' Find Control
90 c(k) = peek($ff08) : z(k) = peek($ff09) : next k
100 data 40, 45, 205, 33, 205, 125, 205, 50, 205, 80, 205, 110
110 gosub 8300
120 for k = 0 to 5 : read n$ : print n$;" : ";c(k);", ";z(k) : next k
130 data "Bouton", "Fleche du haut", "Fleche du bas", "Page avant", "Curseur", "Page apres"
140 end
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnBouton : 1, 1
Fleche du haut : 2, 2
Fleche du bas : 2, 3
Page avant : 2, 4
Curseur : 2, 6
Page apres : 2, 5Assembleur 65C02 (64tass)
; Trouver le contrôle sous un point (groupe 36, fonction 8, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr ouvrir
lda #<cb
ldx #>cb
jsr controle
lda #<cs
ldx #>cs
jsr controle
sta s
jsr WaitMessage
lda s
sta ControlPort+4
lda #25
sta ControlPort+5
stz ControlPort+6
lda #36
ldx #5 ; Set Control Value 25 : curseur en y 79 à 82
jsr appel
lda #<b0
ldx #>b0
jsr envoi
lda ControlPort+8 ; P4 : contrôle
sta c0
lda ControlPort+9 ; P5 : partie
sta z0
lda #<b1
ldx #>b1
jsr envoi
lda ControlPort+8 ; P4 : contrôle
sta c1
lda ControlPort+9 ; P5 : partie
sta z1
lda #<b2
ldx #>b2
jsr envoi
lda ControlPort+8 ; P4 : contrôle
sta c2
lda ControlPort+9 ; P5 : partie
sta z2
lda #<b3
ldx #>b3
jsr envoi
lda ControlPort+8 ; P4 : contrôle
sta c3
lda ControlPort+9 ; P5 : partie
sta z3
lda #<b4
ldx #>b4
jsr envoi
lda ControlPort+8 ; P4 : contrôle
sta c4
lda ControlPort+9 ; P5 : partie
sta z4
lda #<b5
ldx #>b5
jsr envoi
lda ControlPort+8 ; P4 : contrôle
sta c5
lda ControlPort+9 ; P5 : partie
sta z5
lda #<b6
ldx #>b6
jsr envoi
lda #<t7
ldx #>t7
jsr ecrire
lda c0
jsr decimal
lda #<t8
ldx #>t8
jsr ecrire
lda z0
jsr decimal
lda #13
jsr WriteCharacter
lda #<t9
ldx #>t9
jsr ecrire
lda c1
jsr decimal
lda #<t10
ldx #>t10
jsr ecrire
lda z1
jsr decimal
lda #13
jsr WriteCharacter
lda #<t11
ldx #>t11
jsr ecrire
lda c2
jsr decimal
lda #<t12
ldx #>t12
jsr ecrire
lda z2
jsr decimal
lda #13
jsr WriteCharacter
lda #<t13
ldx #>t13
jsr ecrire
lda c3
jsr decimal
lda #<t14
ldx #>t14
jsr ecrire
lda z3
jsr decimal
lda #13
jsr WriteCharacter
lda #<t15
ldx #>t15
jsr ecrire
lda c4
jsr decimal
lda #<t16
ldx #>t16
jsr ecrire
lda z4
jsr decimal
lda #13
jsr WriteCharacter
lda #<t17
ldx #>t17
jsr ecrire
lda c5
jsr decimal
lda #<t18
ldx #>t18
jsr ecrire
lda z5
jsr decimal
lda #13
jsr WriteCharacter
rts
rb: .word 10, 10, 70, 24
rs: .word 180, 0, 192, 100
ok: .byte 2
.text "OK"
cb: .byte 1 ; bouton
.word rb, ok, 0
cs: .byte 4 ; barre en x 201 à 212, y 31 à 130
.word rs, titre, 50
s: .byte 0
b0: .byte 36, 8, 4 ; 36,8 : Find Control
.word 40, 45
c0: .byte 0
z0: .byte 0
b1: .byte 36, 8, 4 ; 36,8 : Find Control
.word 205, 33
c1: .byte 0
z1: .byte 0
b2: .byte 36, 8, 4 ; 36,8 : Find Control
.word 205, 125
c2: .byte 0
z2: .byte 0
b3: .byte 36, 8, 4 ; 36,8 : Find Control
.word 205, 50
c3: .byte 0
z3: .byte 0
b4: .byte 36, 8, 4 ; 36,8 : Find Control
.word 205, 80
c4: .byte 0
z4: .byte 0
b5: .byte 36, 8, 4 ; 36,8 : Find Control
.word 205, 110
c5: .byte 0
z5: .byte 0
b6: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t7: .text "Bouton : ", 0
t8: .text ", ", 0
t9: .text "Fleche du haut : ", 0
t10: .text ", ", 0
t11: .text "Fleche du bas : ", 0
t12: .text ", ", 0
t13: .text "Page avant : ", 0
t14: .text ", ", 0
t15: .text "Curseur : ", 0
t16: .text ", ", 0
t17: .text "Page apres : ", 0
t18: .text ", ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
ldx #>raz
jsr envoi
lda #<nfen
ldx #>nfen
jsr envoi
lda ControlPort+9
sta fen
rts
raz: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen: .byte 34, 1, 5
.word cadre, titre
.byte 1
cadre: .word 20, 20, 220, 140
titre: .byte 1
.text "A" ; chaînes précédées de leur longueur, lues sur place
fen: .byte 0
; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
sta blk
stx blk+1
jsr WaitMessage
ldy #0
lda (blk),y
sta ControlPort+4 ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
lda fen
sta ControlPort+5 ; P1 : fenêtre
ldy #1
_ctl: lda (blk),y
sta ControlPort+5,y ; P2-P7 : Rect, titre, maximum
iny
cpy #7
bne _ctl
lda #36
ldx #1
jsr appel
lda ControlPort+4
rts
; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
jsr WaitMessage
pla
sta ControlPort+4
lda #36
ldx #6
jsr appel
lda ControlPort+5
rts
; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
jsr WaitMessage
pla
sta ControlPort+4
ldx #4
_sv: lda pt,x
sta ControlPort+5,x ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
dex
bpl _sv
lda #36
ldx #9
jsr appel
lda ControlPort+10
rts
pt: .word 0, 0
.byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Bouton : 1, 1
Fleche du haut : 2, 2
Fleche du bas : 2, 3
Page avant : 2, 4
Curseur : 2, 6
Page apres : 2, 536,9 Track Control Trinity
Fait suivre la souris à un contrôle : à appeler au clic, à chaque mouvement et au relâchement.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du contrôle |
P1-P2 | int16 | X de la souris |
P3-P4 | int16 | Y de la souris |
P5 | uint8 | phase : 0 bouton enfoncé, 1 mouvement, 2 bouton relâché |
| Octets | Type | Rôle |
|---|---|---|
P6 | uint8 | 1 si le contrôle a agi |
Un bouton agit s'il est relâché dedans, même après en être sorti ; une case ou un bouton radio au relâchement. Une barre agit quand sa valeur change : flèches de 1 dès l'enfoncement, pages du maximum divisé par 10, curseur au mouvement (glissé de 20 lignes, il passe de 1 à 13). Un champ de texte cliqué reçoit ensuite les touches de 36,10. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Tracks control Parameter:0 from the mouse : Parameters:1,2 (X), Parameters:3,4 (Y), Parameter:5 = phase (0 mouse down, 1 move, 2 mouse up). Parameter:6 is 1 when the control acted : button released inside it (highlighted while the pointer is inside), box toggled or radio set on mouse up, scroll bar value changed (arrows by 1, pages by max/10, thumb dragged), text field clicked (give it the keys with Key Control).
C (llvm-mos)
/* Suivre la souris sur un contrôle (groupe 36, fonction 9, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A"; /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
libre();
api(32, 19);
}
static void ouvrir(void) { /* 34,1 : une fenêtre avec barre de titre */
reinit();
libre();
p16(0, (uint16_t)&cadre);
p16(2, (uint16_t)titre);
ControlPort.params[4] = 1;
api(34, 1);
fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
libre();
ControlPort.params[0] = type;
ControlPort.params[1] = fenetre;
p16(2, (uint16_t)r);
p16(4, (uint16_t)t);
p16(6, max);
api(36, 1);
return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) { /* 36,6 Get Control Value */
libre();
ControlPort.params[0] = c;
api(36, 6);
return ControlPort.params[1] | ControlPort.params[2] << 8;
}
static uint8_t suivre(uint8_t c, int16_t x, int16_t y, uint8_t phase) { /* 36,9 Track Control : 1 si le contrôle a agi */
libre();
ControlPort.params[0] = c;
p16(1, x);
p16(3, y);
ControlPort.params[5] = phase; /* 0 bouton enfoncé, 1 mouvement, 2 bouton relâché */
api(36, 9);
return ControlPort.params[6];
}
static uint8_t clic(uint8_t c, int16_t x, int16_t y) { /* enfoncé puis relâché au même endroit */
suivre(c, x, y, 0);
return suivre(c, x, y, 2);
}
static Rect rb = {10, 10, 70, 24}, rs = {180, 0, 192, 100};
static const char ok[] = "\002OK";
int main(void) {
uint8_t b, s, a1, a2, a3, a4;
uint16_t v1, v2;
ouvrir();
b = controle(1, &rb, ok, 0);
s = controle(4, &rs, titre, 50);
suivre(b, 40, 45, 0); /* bouton : enfoncé dedans, sorti, relâché dedans */
suivre(b, 100, 100, 1);
a1 = suivre(b, 40, 45, 2);
a2 = suivre(s, 205, 125, 0); /* flèche du bas : agit dès l'enfoncement, +1 */
suivre(s, 205, 125, 2);
v1 = valeur(s);
suivre(s, 205, 42, 0); /* curseur (y 40 à 43 pour la valeur 1), glissé de 20 lignes */
a3 = suivre(s, 205, 62, 1);
a4 = suivre(s, 205, 62, 2);
v2 = valeur(s);
reinit();
printf("Bouton : %u ; fleche : %u, valeur %u\n", a1, a2, v1);
printf("Curseur glisse : %u puis %u, valeur %u\n", a3, a4, v2);
return 0;
}Bouton : 1 ; fleche : 1, valeur 1
Curseur glisse : 1 puis 0, valeur 13Mad Pascal
// Suivre la souris sur un contrôle (groupe 36, fonction 9, Trinity).
program ct9;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A')); // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
fenetre: byte;
procedure poser(var r: Rect; g, h, d, b: smallint);
begin
r.g := g; r.h := h; r.d := d; r.b := b;
end;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
NeoWaitMessage;
appel(32, 19);
end;
procedure ouvrir; // 34,1 : une fenêtre avec barre de titre
begin
reinit;
poser(cadre, 20, 20, 220, 140);
wordParams[0] := word(@cadre);
wordParams[1] := word(@titre);
NeoMessage.params[4] := 1;
appel(34, 1);
fenetre := NeoMessage.params[5];
end;
// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
NeoWaitMessage;
NeoMessage.params[0] := t;
NeoMessage.params[1] := fenetre;
wordParams[1] := word(r);
wordParams[2] := word(s);
wordParams[3] := max;
appel(36, 1);
result := NeoMessage.params[0];
end;
function valeur(c: byte): word; // 36,6 Get Control Value
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
appel(36, 6);
result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;
procedure p16(i: byte; v: word); // paramètre 16 bits en Pi, Pi+1
begin
NeoMessage.params[i] := lo(v);
NeoMessage.params[i + 1] := hi(v);
end;
function suivre(c: byte; x, y: smallint; phase: byte): byte; // 36,9 Track Control : 1 si le contrôle a agi
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
p16(1, word(x));
p16(3, word(y));
NeoMessage.params[5] := phase; // 0 bouton enfoncé, 1 mouvement, 2 bouton relâché
appel(36, 9);
result := NeoMessage.params[6];
end;
function clic(c: byte; x, y: smallint): byte; // enfoncé puis relâché au même endroit
begin
suivre(c, x, y, 0);
result := suivre(c, x, y, 2);
end;
const ok: array[0..2] of byte = (2, ord('O'), ord('K'));
var rb, rs: Rect;
b, s, a1, a2, a3, a4: byte;
v1, v2: word;
begin
poser(rb, 10, 10, 70, 24); poser(rs, 180, 0, 192, 100);
ouvrir;
b := controle(1, @rb, @ok, 0);
s := controle(4, @rs, @titre, 50);
suivre(b, 40, 45, 0); // bouton : enfoncé dedans, sorti, relâché dedans
suivre(b, 100, 100, 1);
a1 := suivre(b, 40, 45, 2);
a2 := suivre(s, 205, 125, 0); // flèche du bas : agit dès l'enfoncement, +1
suivre(s, 205, 125, 2);
v1 := valeur(s);
suivre(s, 205, 42, 0); // curseur (y 40 à 43 pour la valeur 1), glissé de 20 lignes
a3 := suivre(s, 205, 62, 1);
a4 := suivre(s, 205, 62, 2);
v2 := valeur(s);
reinit;
writeln('Bouton : ', a1, ' ; fleche : ', a2, ', valeur ', v1);
writeln('Curseur glisse : ', a3, ' puis ', a4, ', valeur ', v2);
end.Bouton : 1 ; fleche : 1, valeur 1
Curseur glisse : 1 puis 0, valeur 13NeoBASIC
10 ' Suivre la souris sur un controle (groupe 36, fonction 9, Trinity)
20 gosub 7000
30 g = 10 : h = 10 : d = 70 : b = 24 : gosub 8000 : s$ = "OK" : gosub 7900 : ty = 1 : mx = 0 : gosub 7100 : bt = cn
40 g = 180 : h = 0 : d = 192 : b = 100 : gosub 8000 : ch = tf : ty = 4 : mx = 50 : gosub 7100 : ba = cn
50 c = bt : x = 40 : y = 45 : ph = 0 : gosub 7300 : ' bouton : enfonce dedans, sorti, relache dedans
60 x = 100 : y = 100 : ph = 1 : gosub 7300
70 x = 40 : y = 45 : ph = 2 : gosub 7300 : a1 = ag
80 c = ba : x = 205 : y = 125 : ph = 0 : gosub 7300 : a2 = ag : ' fleche du bas : agit des l'enfoncement, +1
90 ph = 2 : gosub 7300 : gosub 7200 : v1 = v
100 y = 42 : ph = 0 : gosub 7300 : ' curseur (y 40 a 43 pour la valeur 1), glisse de 20 lignes
110 y = 62 : ph = 1 : gosub 7300 : a3 = ag
120 ph = 2 : gosub 7300 : a4 = ag : gosub 7200 : v2 = v
130 gosub 8300
140 print "Bouton : ";a1;" ; fleche : ";a2;", valeur ";v1
150 print "Curseur glisse : ";a3;" puis ";a4;", valeur ";v2
160 end
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnBouton : 1 ; fleche : 1, valeur 1
Curseur glisse : 1 puis 0, valeur 13Assembleur 65C02 (64tass)
; Suivre la souris sur un contrôle (groupe 36, fonction 9, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr ouvrir
lda #<cb
ldx #>cb
jsr controle
sta b
lda #<cs
ldx #>cs
jsr controle
sta s
lda #<40
sta pt
lda #>40
sta pt+1
lda #45
sta pt+2
stz pt+3
lda #0 ; bouton : enfoncé dedans...
sta pt+4
lda b
jsr suivre
lda #<100
sta pt
lda #>100
sta pt+1
lda #100
sta pt+2
stz pt+3
lda #1 ; ... sorti...
sta pt+4
lda b
jsr suivre
lda #<40
sta pt
lda #>40
sta pt+1
lda #45
sta pt+2
stz pt+3
lda #2 ; ... relâché dedans
sta pt+4
lda b
jsr suivre
sta a1
lda #<205
sta pt
lda #>205
sta pt+1
lda #125
sta pt+2
stz pt+3
lda #0 ; flèche du bas : agit dès l'enfoncement, +1
sta pt+4
lda s
jsr suivre
sta a2
lda #<205
sta pt
lda #>205
sta pt+1
lda #125
sta pt+2
stz pt+3
lda #2 ; relâché
sta pt+4
lda s
jsr suivre
lda s
jsr valeur
sta v1
lda #<205
sta pt
lda #>205
sta pt+1
lda #42
sta pt+2
stz pt+3
lda #0 ; curseur (y 40 à 43 pour la valeur 1)...
sta pt+4
lda s
jsr suivre
lda #<205
sta pt
lda #>205
sta pt+1
lda #62
sta pt+2
stz pt+3
lda #1 ; ... glissé de 20 lignes
sta pt+4
lda s
jsr suivre
sta a3
lda #<205
sta pt
lda #>205
sta pt+1
lda #62
sta pt+2
stz pt+3
lda #2 ; relâché
sta pt+4
lda s
jsr suivre
sta a4
lda s
jsr valeur
sta v2
lda #<b0
ldx #>b0
jsr envoi
lda #<t1
ldx #>t1
jsr ecrire
lda a1
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda a2
jsr decimal
lda #<t3
ldx #>t3
jsr ecrire
lda v1
jsr decimal
lda #13
jsr WriteCharacter
lda #<t4
ldx #>t4
jsr ecrire
lda a3
jsr decimal
lda #<t5
ldx #>t5
jsr ecrire
lda a4
jsr decimal
lda #<t6
ldx #>t6
jsr ecrire
lda v2
jsr decimal
lda #13
jsr WriteCharacter
rts
rb: .word 10, 10, 70, 24
rs: .word 180, 0, 192, 100
ok: .byte 2
.text "OK"
cb: .byte 1 ; bouton
.word rb, ok, 0
b: .byte 0
cs: .byte 4 ; barre, maximum 50
.word rs, titre, 50
s: .byte 0
a1: .byte 0
a2: .byte 0
v1: .byte 0
a3: .byte 0
a4: .byte 0
v2: .byte 0
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t1: .text "Bouton : ", 0
t2: .text " ; fleche : ", 0
t3: .text ", valeur ", 0
t4: .text "Curseur glisse : ", 0
t5: .text " puis ", 0
t6: .text ", valeur ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
ldx #>raz
jsr envoi
lda #<nfen
ldx #>nfen
jsr envoi
lda ControlPort+9
sta fen
rts
raz: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen: .byte 34, 1, 5
.word cadre, titre
.byte 1
cadre: .word 20, 20, 220, 140
titre: .byte 1
.text "A" ; chaînes précédées de leur longueur, lues sur place
fen: .byte 0
; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
sta blk
stx blk+1
jsr WaitMessage
ldy #0
lda (blk),y
sta ControlPort+4 ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
lda fen
sta ControlPort+5 ; P1 : fenêtre
ldy #1
_ctl: lda (blk),y
sta ControlPort+5,y ; P2-P7 : Rect, titre, maximum
iny
cpy #7
bne _ctl
lda #36
ldx #1
jsr appel
lda ControlPort+4
rts
; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
jsr WaitMessage
pla
sta ControlPort+4
lda #36
ldx #6
jsr appel
lda ControlPort+5
rts
; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
jsr WaitMessage
pla
sta ControlPort+4
ldx #4
_sv: lda pt,x
sta ControlPort+5,x ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
dex
bpl _sv
lda #36
ldx #9
jsr appel
lda ControlPort+10
rts
pt: .word 0, 0
.byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Bouton : 1 ; fleche : 1, valeur 1
Curseur glisse : 1 puis 0, valeur 1336,10 Key Control Trinity
Envoie une touche à un champ de texte.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du contrôle |
P1 | uint8 | caractère ; 8 ou 127 efface le dernier |
| Octets | Type | Rôle |
|---|---|---|
P2 | uint8 | 1 si le tampon a changé |
Le tampon est la chaîne précédée de sa longueur donnée à 36,1, en RAM du 6502 : le programme y lit le texte. Un caractère au-delà de la longueur maximale est refusé. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Sends the key Parameter:1 to text field Parameter:0 : printable characters are appended to its buffer (up to the maximum length), 8 or 127 deletes the last one ; Parameter:2 is 1 if the buffer changed. The buffer is the length-prefixed string given to New Control, in 6502 RAM.
C (llvm-mos)
/* Envoyer une touche à un champ de texte (groupe 36, fonction 10, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Rect de QuickDraw : gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
/* La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu. */
static Rect cadre = {20, 20, 220, 140};
static const char titre[] = "\001A"; /* chaînes précédées de leur longueur, lues sur place */
static uint8_t fenetre;
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus de fenêtre ni de contrôle */
libre();
api(32, 19);
}
static void ouvrir(void) { /* 34,1 : une fenêtre avec barre de titre */
reinit();
libre();
p16(0, (uint16_t)&cadre);
p16(2, (uint16_t)titre);
ControlPort.params[4] = 1;
api(34, 1);
fenetre = ControlPort.params[5];
}
/* 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle. */
static uint8_t controle(uint8_t type, Rect *r, const char *t, uint16_t max) {
libre();
ControlPort.params[0] = type;
ControlPort.params[1] = fenetre;
p16(2, (uint16_t)r);
p16(4, (uint16_t)t);
p16(6, max);
api(36, 1);
return ControlPort.params[0];
}
static uint16_t valeur(uint8_t c) { /* 36,6 Get Control Value */
libre();
ControlPort.params[0] = c;
api(36, 6);
return ControlPort.params[1] | ControlPort.params[2] << 8;
}
static uint8_t suivre(uint8_t c, int16_t x, int16_t y, uint8_t phase) { /* 36,9 Track Control : 1 si le contrôle a agi */
libre();
ControlPort.params[0] = c;
p16(1, x);
p16(3, y);
ControlPort.params[5] = phase; /* 0 bouton enfoncé, 1 mouvement, 2 bouton relâché */
api(36, 9);
return ControlPort.params[6];
}
static uint8_t clic(uint8_t c, int16_t x, int16_t y) { /* enfoncé puis relâché au même endroit */
suivre(c, x, y, 0);
return suivre(c, x, y, 2);
}
static Rect rt = {10, 70, 150, 84};
static char tampon[5] = "\002ab"; /* longueur, puis le texte ; maximum 4 caractères */
static uint8_t touche(uint8_t c, uint8_t k) { /* Key Control : 1 si le tampon a changé */
libre();
ControlPort.params[0] = c;
ControlPort.params[1] = k;
api(36, 10);
return ControlPort.params[2];
}
static void afficher(void) {
uint8_t i;
for (i = 1; i <= tampon[0]; i++)
putchar(tampon[i]);
putchar('\n');
}
int main(void) {
uint8_t t, x, y, z;
ouvrir();
t = controle(5, &rt, tampon, 4);
clic(t, 40, 105); /* le champ est cliqué */
x = touche(t, 'X');
y = touche(t, 'Y');
z = touche(t, 'Z'); /* plein : refusé */
reinit();
printf("X : %u, Y : %u, Z : %u -> ", x, y, z);
afficher();
ouvrir();
t = controle(5, &rt, tampon, 4);
touche(t, 8); /* 8 (ou 127) efface le dernier caractère */
reinit();
printf("Effacement -> ");
afficher();
return 0;
}X : 1, Y : 1, Z : 0 -> abXY
Effacement -> abXMad Pascal
// Envoyer une touche à un champ de texte (groupe 36, fonction 10, Trinity).
program ct10;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
// La fenêtre : contenu de (21, 31) à (219, 139). Les contrôles sont placés dans le contenu.
const titre: array[0..1] of byte = (1, ord('A')); // chaînes précédées de leur longueur, lues sur place
var cadre: Rect;
fenetre: byte;
procedure poser(var r: Rect; g, h, d, b: smallint);
begin
r.g := g; r.h := h; r.d := d; r.b := b;
end;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
begin
NeoWaitMessage;
appel(32, 19);
end;
procedure ouvrir; // 34,1 : une fenêtre avec barre de titre
begin
reinit;
poser(cadre, 20, 20, 220, 140);
wordParams[0] := word(@cadre);
wordParams[1] := word(@titre);
NeoMessage.params[4] := 1;
appel(34, 1);
fenetre := NeoMessage.params[5];
end;
// 36,1 New Control : type (1 bouton, 2 case, 3 radio, 4 barre de défilement, 5 champ de texte), Rect relatif
// au contenu, titre (ou tampon du champ), maximum ; rend le numéro du contrôle.
function controle(t: byte; r, s: pointer; max: word): byte;
begin
NeoWaitMessage;
NeoMessage.params[0] := t;
NeoMessage.params[1] := fenetre;
wordParams[1] := word(r);
wordParams[2] := word(s);
wordParams[3] := max;
appel(36, 1);
result := NeoMessage.params[0];
end;
function valeur(c: byte): word; // 36,6 Get Control Value
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
appel(36, 6);
result := NeoMessage.params[1] + NeoMessage.params[2] shl 8;
end;
procedure p16(i: byte; v: word); // paramètre 16 bits en Pi, Pi+1
begin
NeoMessage.params[i] := lo(v);
NeoMessage.params[i + 1] := hi(v);
end;
function suivre(c: byte; x, y: smallint; phase: byte): byte; // 36,9 Track Control : 1 si le contrôle a agi
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
p16(1, word(x));
p16(3, word(y));
NeoMessage.params[5] := phase; // 0 bouton enfoncé, 1 mouvement, 2 bouton relâché
appel(36, 9);
result := NeoMessage.params[6];
end;
function clic(c: byte; x, y: smallint): byte; // enfoncé puis relâché au même endroit
begin
suivre(c, x, y, 0);
result := suivre(c, x, y, 2);
end;
var tampon: array[0..4] of byte = (2, ord('a'), ord('b'), 0, 0); // longueur, puis le texte ; maximum 4 caractères
rt: Rect;
t, x, y, z: byte;
function touche(c, k: byte): byte; // Key Control : 1 si le tampon a changé
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
NeoMessage.params[1] := k;
appel(36, 10);
result := NeoMessage.params[2];
end;
procedure afficher;
var i: byte;
begin
for i := 1 to tampon[0] do write(chr(tampon[i]));
writeln;
end;
begin
poser(rt, 10, 70, 150, 84);
ouvrir;
t := controle(5, @rt, @tampon, 4);
clic(t, 40, 105); // le champ est cliqué
x := touche(t, ord('X'));
y := touche(t, ord('Y'));
z := touche(t, ord('Z')); // plein : refusé
reinit;
write('X : ', x, ', Y : ', y, ', Z : ', z, ' -> ');
afficher;
ouvrir;
t := controle(5, @rt, @tampon, 4);
touche(t, 8); // 8 (ou 127) efface le dernier caractère
reinit;
write('Effacement -> ');
afficher;
end.X : 1, Y : 1, Z : 0 -> abXY
Effacement -> abXNeoBASIC
10 ' Envoyer une touche a un champ de texte (groupe 36, fonction 10, Trinity)
20 tp = alloc(5) : poke tp, 2 : poke tp + 1, asc("a") : poke tp + 2, asc("b") : ' longueur, puis le texte ; maximum 4
30 gosub 7000
40 g = 10 : h = 70 : d = 150 : b = 84 : gosub 8000 : rt = q : ch = tp : ty = 5 : mx = 4 : gosub 7100 : c = cn
50 x = 40 : y = 105 : gosub 7400 : ' le champ est clique
60 k = asc("X") : gosub 2000 : kx = kc
70 k = asc("Y") : gosub 2000 : ky = kc
80 k = asc("Z") : gosub 2000 : kz = kc : ' plein : refuse
90 gosub 8300
100 print "X : ";kx;", Y : ";ky;", Z : ";kz;" -> ";
110 gosub 3000
120 gosub 7000 : q = rt : ch = tp : ty = 5 : mx = 4 : gosub 7100 : c = cn
130 k = 8 : gosub 2000 : ' 8 (ou 127) efface le dernier caractere
140 gosub 8300
150 print "Effacement -> "; : gosub 3000
160 end
2000 ' Key Control : touche k au champ c ; kc = 1 si le tampon a change
2010 while peek($ff00) : wend : poke $ff04, c : poke $ff05, k : f = 10 : gosub 8110 : kc = peek($ff06) : return
3000 for i = 1 to peek(tp) : print chr$(peek(tp + i)); : next i : print : return
7000 ' une fenetre avec barre de titre (34,1) : contenu de (21, 31) a (219, 139) ; numero dans fw
7010 gosub 8300 : cf = alloc(8) : doke cf, 20 : doke cf + 2, 20 : doke cf + 4, 220 : doke cf + 6, 140
7020 s$ = "A" : gosub 7900 : tf = ch
7030 while peek($ff00) : wend : doke $ff04, cf : doke $ff06, tf : poke $ff08, 1 : poke $ff01, 1 : poke $ff00, 34
7040 while peek($ff00) : wend : fw = peek($ff09) : return
7100 ' 36,1 New Control : type ty (1 bouton, 2 case, 3 radio, 4 barre, 5 champ), Rect q relatif au contenu,
7110 ' titre (ou tampon) ch, maximum mx ; numero dans cn, erreur dans e
7120 while peek($ff00) : wend : poke $ff04, ty : poke $ff05, fw : doke $ff06, q : doke $ff08, ch : doke $ff0a, mx
7130 f = 1 : gosub 8110 : cn = peek($ff04) : return
7200 ' 36,6 Get Control Value du controle c, dans v
7210 while peek($ff00) : wend : poke $ff04, c : f = 6 : gosub 8110 : v = deek($ff05) : return
7300 ' 36,9 Track Control : controle c en (x, y), phase ph (0 enfonce, 1 mouvement, 2 relache) ; ag = 1 s'il a agi
7310 while peek($ff00) : wend : poke $ff04, c : doke $ff05, x : doke $ff07, y : poke $ff09, ph
7320 f = 9 : gosub 8110 : ag = peek($ff0a) : return
7400 ' clic : enfonce puis relache en (x, y)
7410 ph = 0 : gosub 7300 : ph = 2 : goto 7300
7900 ' chaine s$ precedee de sa longueur, dans un bloc neuf ch (lue sur place)
7910 ch = alloc(len(s$) + 1) : poke ch, len(s$) : for i = 1 to len(s$) : poke ch + i, asc(mid$(s$, i, 1)) : next i : return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (droite et bas exclus)
8010 q = alloc(8) : doke q, g : doke q + 2, h : doke q + 4, d : doke q + 6, b : return
8100 ' appel 36,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 36
8120 while peek($ff00) : wend : e = peek($ff02) : return
8300 ' 32,19 Toolbox Reset : plus de fenetre ni de controle
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnX : 1, Y : 1, Z : 0 -> abXY
Effacement -> abXAssembleur 65C02 (64tass)
; Envoyer une touche à un champ de texte (groupe 36, fonction 10, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr ouvrir
lda #<ct
ldx #>ct
jsr controle
sta t
lda #<40
sta pt
lda #>40
sta pt+1
lda #105
sta pt+2
stz pt+3
lda #0 ; le champ est cliqué
sta pt+4
lda t
jsr suivre
lda #<40
sta pt
lda #>40
sta pt+1
lda #105
sta pt+2
stz pt+3
lda #2 ; relâché
sta pt+4
lda t
jsr suivre
jsr WaitMessage
lda t
sta ControlPort+4
lda #'X'
sta ControlPort+5
lda #36
ldx #10 ; Key Control
jsr appel
lda ControlPort+6 ; P2 : 1 si le tampon a changé
sta x
jsr WaitMessage
lda t
sta ControlPort+4
lda #'Y'
sta ControlPort+5
lda #36
ldx #10 ; Key Control
jsr appel
lda ControlPort+6 ; P2 : 1 si le tampon a changé
sta y
jsr WaitMessage
lda t
sta ControlPort+4
lda #'Z'
sta ControlPort+5
lda #36
ldx #10 ; plein : refusé
jsr appel
lda ControlPort+6 ; P2 : 1 si le tampon a changé
sta z
lda #<b0
ldx #>b0
jsr envoi
lda #<t1
ldx #>t1
jsr ecrire
lda x
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda y
jsr decimal
lda #<t3
ldx #>t3
jsr ecrire
lda z
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
jsr afficher
jsr ouvrir
lda #<ct
ldx #>ct
jsr controle
sta t
jsr WaitMessage
lda t
sta ControlPort+4
lda #8
sta ControlPort+5
lda #36
ldx #10 ; 8 (ou 127) efface le dernier caractère
jsr appel
lda #<b5
ldx #>b5
jsr envoi
lda #<t6
ldx #>t6
jsr ecrire
jsr afficher
rts
rt: .word 10, 70, 150, 84
tampon: .byte 2 ; longueur, puis le texte ; maximum 4 caractères
.text "ab"
.fill 2
ct: .byte 5 ; champ de texte, maximum 4
.word rt, tampon, 4
t: .byte 0
x: .byte 0
y: .byte 0
z: .byte 0
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t1: .text "X : ", 0
t2: .text ", Y : ", 0
t3: .text ", Z : ", 0
t4: .text " -> ", 0
b5: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t6: .text "Effacement -> ", 0
; Affiche le tampon (chaîne précédée de sa longueur), puis passe à la ligne.
afficher:
ldx #0
_af: cpx tampon
beq _fa
lda tampon+1,x
jsr WriteCharacter
inx
bra _af
_fa: lda #13
jmp WriteCharacter
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Une fenêtre avec barre de titre (34,1) : contenu de (21, 31) à (219, 139) ; numéro dans fen.
ouvrir: lda #<raz
ldx #>raz
jsr envoi
lda #<nfen
ldx #>nfen
jsr envoi
lda ControlPort+9
sta fen
rts
raz: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus de fenêtre ni de contrôle
nfen: .byte 34, 1, 5
.word cadre, titre
.byte 1
cadre: .word 20, 20, 220, 140
titre: .byte 1
.text "A" ; chaînes précédées de leur longueur, lues sur place
fen: .byte 0
; 36,1 New Control : bloc en A/X (type, Rect relatif au contenu, titre ou tampon, maximum) ; numéro dans A.
controle:
sta blk
stx blk+1
jsr WaitMessage
ldy #0
lda (blk),y
sta ControlPort+4 ; P0 : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ)
lda fen
sta ControlPort+5 ; P1 : fenêtre
ldy #1
_ctl: lda (blk),y
sta ControlPort+5,y ; P2-P7 : Rect, titre, maximum
iny
cpy #7
bne _ctl
lda #36
ldx #1
jsr appel
lda ControlPort+4
rts
; 36,6 Get Control Value du contrôle A : valeur (8 bits bas) dans A.
valeur: pha
jsr WaitMessage
pla
sta ControlPort+4
lda #36
ldx #6
jsr appel
lda ControlPort+5
rts
; 36,9 Track Control : contrôle A, point et phase dans le bloc pt (X, Y, phase) ; A = 1 si le contrôle a agi.
suivre: pha
jsr WaitMessage
pla
sta ControlPort+4
ldx #4
_sv: lda pt,x
sta ControlPort+5,x ; P1-P2 : X, P3-P4 : Y, P5 : 0 enfoncé, 1 mouvement, 2 relâché
dex
bpl _sv
lda #36
ldx #9
jsr appel
lda ControlPort+10
rts
pt: .word 0, 0
.byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0X : 1, Y : 1, Z : 0 -> abXY
Effacement -> abX