Suivez-nous sur X
|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : Assembleur - une seconde commande Ask
(Article écrit par Frédéric Delacroix et extrait d'Amiga News - juillet/août 1996)
|
|
Les rares d'entre vous qui utilisent AmigaDOS pour l'écriture de fichiers "batch" trouvent peut-être la commande Ask un peu
pauvre avec son mode Y/N. Il y a bien sûr la fonction RequestChoice du Kickstart 3.0 pour des choix un peu plus élaborés,
mais elle casse "l'ambiance" du Shell. Voici une troisième solution.
Je dois tout d'abord vous avouer que ceci me sert principalement à vous présenter une possibilité assez méconnue de la dos.library,
mais certains trouveront peut-être une réelle utilité à ce programme dans la vie de tous les jours.
Cahier des charges
De quoi avons-nous besoin ? Les principaux défauts de Ask sont le fait qu'elle n'accepte que "Y" et "N" comme réponse et qu'il
faille valider la réponse en appuyant sur la touche retour-chariot. Ce serait bien qu'un programme prenne en compte la réponse
dès l'appui sur la touche. On voudrait également permettre de multiples réponses (la condition précédente les limitant à une
seule touche) autres que Y/N.
Tant qu'à faire, prévoyons un mode multicommandes où on pourrait recevoir plusieurs réponses comme "A", "B", "C" ou "1", "2",
"?", et un mode (baptisé "ASK") se comportant comme une commande Ask dont on pourrait changer les réponses attendues et
renvoyant les mêmes codes de retour, rendant facile un test par IF WARN et consorts.
La solution
Le principal problème est la première condition, tout le reste n'étant qu'artifices de programmation auxquels vous êtes habitués.
En effet, la fenêtre du Shell que vous utilisez est une fenêtre CON:, c'est-à-dire une console en mode "cuisiné" (par opposition
à "cru"), où toute ligne est éditable et n'est envoyée au programme qu'après la touche retour-chariot pressée. Tant que vous
éditez la ligne, le programme en lecture de la console attend et n'a aucune connaissance de ce que vous faites. Il y a cependant
un autre type de fenêtre : les fenêtres RAW:, correspondant au mode "cru" (traduction de RAW) du gestionnaire de console d'AmigaDOS.
Dans ce mode RAW, tout événement satisfait immédiatement la demande de lecture qui est retournée au programme après conversion
ANSI (c'est-à-dire en caractère ASCII ou chaîne ANSI pour les touches de fonction). Il n'y a également pas d'écho automatique
des caractères à l'écran. La solution consiste donc à faire passer la fenêtre de console du Shell du mode CON au mode RAW.
Ceci se fait par le type de paquet ACTION_SCREEN_MODE ou, à partir du Kickstart 2.0, par la fonction SetMode() de la dos.library
(ce qui est beaucoup plus facile). Cependant, un tel passage peut échouer, par exemple à cause de l'utilisation simultanée de
la console par plusieurs tâches (lancées par Run).
Il suffit donc de passer en paramètres à cette fonction le canal d'entrée (obtenu par Input()) et le mode voulu (1 pour RAW,
0 pour CON) et le tour est joué. C'est le stratagème utilisé par l'assembleur lorsqu'il a fini l'assemblage et vous demande
d'appuyer sur une touche.
Le programme
Baptisé ReadKey, il respecte le cahier des charges décrit ci-dessus. Les arguments et les codes de retour sont détaillés
dans le source du programme, je vous y renvoie pour l'usage. La présence (ou non) du mot-clé COMMANDS détermine respectivement
le mode multicommandes ou le mode Ask. On a également conservé la possibilité de quitter le programme en appuyant sur
la touche "Esc" quel que soit le mode. J'ai de plus ajouté un temps limite grâce à la fonction WaitForChar() de la dos.library.
Ce temps est à exprimer en microsecondes (je n'avais pas envie d'allonger le programme avec une routine de multiplication par
1000000).
Remarquons qu'il n'est pas possible, même en mode multicommandes, d'utiliser les apostrophes inverses pour récupérer la lettre
produite, étant donné que lorsque le programme est appelé entre de telles apostrophes, le canal retourné par Input() n'est plus
valide. Ceci est une restriction de l'AmigaShell. On peut toutefois ruser en détournant la sortie en ENV:Variable puis en la
récupérant par un GetEnv Variable.
Tel qu'il est écrit, ce programme ne sait traiter que les séquences d'un seul caractère. Il ne saura donc par exemple distinguer
les séquences ANSI des touches de curseur par exemple. A vous d'écrire la version 2.0. :-)
Sur ce, je vous laisse avec le listage du programme et un petit script (pardon, scénario ;-)) AmigaDOS pour vous amuser pendant
ces vacances que je vous souhaite excellentes.
Fichier FillData
.bra {
.ket }
; script de test pour ReadKey:
; execute FillData
; créée un fichier base de données à partir des informations saisies au
; clavier dans le Shell. Ah le bon temps des interfaces simples!
lab EncoreUn
echo "Nom : " NOLINE
set >NIL: str ?
echo >>{DATABASE} "*N"
echo >>{DATABASE} $str
echo "Prénom: " NOLINE
set >NIL: str ?
echo >>{DATABASE} $str
echo "Sexe : (H)omme"
echo " (F)emme"
echo " (S)ans"
ReadKey >>{DATABASE} COMMANDS="hfs"
echo "Utilisateur de (M)S-DOS ou (A)migaOS ?"
ReadKey YES=m NO=a
if warn
echo >>{DATABASE} "Individu peu fréquentable."
else
echo >>{DATABASE} "Personne respectable."
endif
echo "Encore un ?"
ReadKey YES=o NO=n
if warn
skip EncoreUn BACK
endif
type {DATABASE}
|
Fichier ReadKey.s
; Programme: ReadKey, version 1.0
;
; arguments:
; COMMANDS/K: si spécifié, demande le mode multicommandes,
; seules les touches indiquées seront reconnues
; (plus ESC). Le caractère correspondant est affiché
; à l'écran; utilisation > possible, par ex:
; ReadKey >ENV:Variable COMMANDS="ABC"
; (on ne peut malheureusement pas utiliser les apostrophes
; inverses avec l'AmigaShell d'origine, mais on peut ruser
; de cette façon).
; YES et NO: Ne sont pris en compte que si COMMANDS n'est pas spécifié,
; pour le mode "ASK": se comporte alors comme la commande
; Ask, avec les touches indiquées pour Y et N (par défaut:
; y et n). Attention à la casse.
; TIMEOUT: Temps limite au-delà duquel le programme se termine. Infini
; si TIMEOUT est à 0. Exprimé en microsecondes (!).
; Par défaut:0.
;
; codes de retour:
; OK (0): YES en mode ASK, touche reconnue (et affichée) en mode
; multicommandes.
; WARN (5): NO en mode ASK.
; ERROR (10): temps limite dépassé ou ESC rencontré.
; FAIL (20): erreur grave d'initialisation du programme.
include exec/exec.i
include exec/exec_lib.i
include dos/dos.i
include dos/dos_lib.i
Start moveq #20,d7 ; code de retour: erreur fatale
move.l 4.w,a6
move.l a6,Exec.Base
lea DOS.Name(pc),a1 ; ouverture de la dos.library
moveq #37,d0
jsr _LVOOpenLibrary(a6)
move.l d0,DOS.Base
beq NoDOS
move.l #Args.Template,d1 ; lecture des arguments
move.l #Args.Array,d2
moveq #0,d3
move.l DOS.Base(pc),a6
jsr _LVOReadArgs(a6)
move.l d0,Args.RDArgs
beq CloseDOS
jsr _LVOInput(a6) ; canal standard d'entrée
move.l d0,Input.Handle ; (normalement la fenêtre du Shell)
beq.s FreeArgs
move.l d0,d1
moveq #1,d2 ; passe en mode RAW
jsr _LVOSetMode(a6)
tst.w d0 ; réussi ?
beq.s FreeArgs
moveq #10,d7 ; code de retour: temps limite dépassé
move.l Input.Handle(pc),d1
jsr _LVOFlush(a6)
GetLoop move.l Input.Handle(pc),d1
move.l TimeOut.Arg(pc),d2
beq.s .NoWaitForChar ; pas de timeout: attendre par Read().
jsr _LVOWaitForChar(a6)
tst.l d0
beq.s ToCON ; si timeout
.NoWaitForChar
move.l Input.Handle(pc),d1
move.l #Char.Buf,d2
moveq #1,d3
jsr _LVORead(a6)
moveq #20,d7 ; code de retour: erreur fatale
cmp.l d0,d3 ; 1 caractère lu?
bne.s ToCON ; non: erreur fatale
move.b Char.Buf(pc),d6 ; l'octet lu
tst.l Commands.Arg ; mode Ask ou mode multicommandes?
bne.s MultiCommands
moveq #5,d7 ; code de retour correspondant à YES
move.l Yes.Arg(pc),a0
cmp.b (a0),d6
beq.s ToCON ; fini
moveq #0,d7 ; code de retour correspondant à NO
move.l No.Arg(pc),a0
cmp.b (a0),d6
beq.s ToCON
moveq #10,d7 ; code de retour pour l'échappement
cmp.b #27,Char.Buf ; escape
bne GetLoop
ToCON move.l Input.Handle(pc),d1
moveq #0,d2 ; passe en mode CON
jsr _LVOSetMode(a6) ; ne peut échouer
FreeArgs
move.l Args.RDArgs(pc),d1
move.l DOS.Base(pc),a6
jsr _LVOFreeArgs(a6)
CloseDOS
move.l DOS.Base(pc),a1
move.l Exec.Base(pc),a6
jsr _LVOCloseLibrary(a6)
NoDOS move.l d7,d0
rts
MultiCommands
move.l Commands.Arg(pc),a0
.SearchCmd
cmp.b (a0)+,d6
beq.s .Found
tst.b -1(a0)
bne.s .SearchCmd
; caractère non trouvé
moveq #10,d7 ; code de retour pour l'échappement
cmp.b #27,Char.Buf ; escape
beq ToCON
bra GetLoop ; demande un autre caractère
.Found move.l #Char.Buf,d1
moveq #2,d2
jsr _LVOWriteChars(a6) ; affiche le caractère à l'écran
moveq #0,d7 ; code de retour: OK
bra ToCON
Exec.Base dc.l 0
DOS.Base dc.l 0
Args.RDArgs dc.l 0
Input.Handle dc.l 0
Args.Array
Commands.Arg dc.l 0
Yes.Arg dc.l Y.String
No.Arg dc.l N.String
TimeOut.Arg dc.l 0
DOS.Name dc.b "dos.library",0
Args.Template dc.b "COMMANDS/K,YES,NO,TIMEOUT/N",0
Y.String dc.b "y",0 ; minuscules/majuscules importantes!
N.String dc.b "n",0
Char.Buf dc.b 0 ; le caractère lu
dc.b 10 ; et le saut de ligne pour l'affichage.
|
|