Group 36 — Control Manager 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
The control manager of the Trinity toolbox puts buttons, check boxes, radio buttons, scroll bars and text fields in windows (group 34): 24 at most.
The examples open a window with frame 20, 20, 220, 140 (content from (21, 31) to (219, 139)) and put their controls in it: a control Rect is relative to the content, so the button put at (10, 10) is at (31, 41) on screen. The mouse is simulated by calls to 36,9 at the wanted coordinates. The toolbox is reset with 32,19 at the start and at the end.
36,1 New Control Trinity
Creates a control in a window and draws it at once.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | kind: 1 button, 2 check box, 3 radio button, 4 scroll bar, 5 text field |
P1 | uint8 | window |
P2-P3 | addr | address of the Rect, relative to the window content |
P4-P5 | addr | address of the length-prefixed title, or of the buffer of a text field (read in place) |
P6-P7 | uint16 | maximum of a scroll bar, or maximum length of a text field |
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | control number (1 to 24) |
erreur | uint8 | 1 bad parameters, 2 none left |
A scroll bar is vertical when it is higher than wide. Radio buttons are not grouped: the program clears the others. When handling the update event of a window, 36,3 redraws all its controls. On the bench, the 25th control is refused (error 2). NeoBASIC has no keyword for this call.
Firmware documentation text
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 165C02 assembly (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
Erases a control and frees its number.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | control number |
Outputs: none.
Disposing a window frees its controls as well. The freed number is taken by the next control. NeoBASIC has no keyword for this call.
Firmware documentation text
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 : 165C02 assembly (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
Draws every control of a window.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | window |
Outputs: none.
To call after 34,12 in the update handler. The example paints the content in colour 4: the frames of both buttons (white, 15) come back. NeoBASIC has no keyword for this call.
Firmware documentation text
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 1565C02 assembly (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
Redraws a control.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | control number |
Outputs: none.
The button is redrawn entirely: white frame (15), black inside (0). NeoBASIC has no keyword for this call.
Firmware documentation text
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 065C02 assembly (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
Sets the value of a control and redraws it.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | control number |
P1-P2 | uint16 | value: 0 or 1 for boxes, 0 to the maximum for scroll bars |
Outputs: none.
On the bench, a value past the maximum of a scroll bar is brought back to the maximum, without error. NeoBASIC has no keyword for this call.
Firmware documentation text
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)65C02 assembly (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
Returns the value of a control.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | control number |
| Bytes | Type | Meaning |
|---|---|---|
P1-P2 | uint16 | value |
A click (36,9) toggles the check box each time; the radio button goes to 1 and stays there. NeoBASIC has no keyword for this call.
Firmware documentation text
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, 165C02 assembly (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
Sets the flags of a control and redraws it.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | control number |
P1 | uint8 | flags: bit 0 disabled |
Outputs: none.
A disabled control is drawn grey and ignores the mouse (36,9) and keys (36,10). NeoBASIC has no keyword for this call.
Firmware documentation text
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 165C02 assembly (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
Returns the control of the front window under a point, and the part hit.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | int16 | point X |
P2-P3 | int16 | point Y |
| Bytes | Type | Meaning |
|---|---|---|
P4 | uint8 | control (0 if none) |
P5 | uint8 | part: 1 body; scroll bars: 2 first arrow, 3 second arrow, 4 page before the thumb, 5 page after, 6 thumb |
Measured on the bench for the 12 × 100 pixel scroll bar: 8-line arrows at the top and bottom, 4-line thumb (y 79 to 82 for the value 25 out of 50). NeoBASIC has no keyword for this call.
Firmware documentation text
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, 565C02 assembly (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
Has a control track the mouse: to call on mouse down, on each move and on mouse up.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | control number |
P1-P2 | int16 | mouse X |
P3-P4 | int16 | mouse Y |
P5 | uint8 | phase: 0 mouse down, 1 move, 2 mouse up |
| Bytes | Type | Meaning |
|---|---|---|
P6 | uint8 | 1 if the control acted |
A button acts when released inside it, even after leaving it; a box or radio button on release. A scroll bar acts when its value changes: arrows by 1 on mouse down, pages by the maximum divided by 10, thumb on move (dragged by 20 lines, it goes from 1 to 13). A clicked text field then receives the keys of 36,10. NeoBASIC has no keyword for this call.
Firmware documentation text
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 1365C02 assembly (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
Sends a key to a text field.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | control number |
P1 | uint8 | character; 8 or 127 deletes the last one |
| Bytes | Type | Meaning |
|---|---|---|
P2 | uint8 | 1 if the buffer changed |
The buffer is the length-prefixed string given to 36,1, in 6502 RAM: the program reads the text there. A character past the maximum length is refused. NeoBASIC has no keyword for this call.
Firmware documentation text
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 -> abX65C02 assembly (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