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 : C - CRBlanker (permuter les écrans Intuition)
(Article écrit par Frédéric Mazué et extrait d'Amiga News Tech - mars 1991)
|
|
Vous connaissez sans doute les raccourcis clavier "Commodore-N" et "Commodore-M" qui permettent de passer
l'écran du Workbench en avant ou en arrière de la pile d'écrans. Seulement voilà, il n'est pas possible,
dans le cas où trois écrans sont utilisés, de faire apparaître de cette manière celui du "milieu".
Le programme que je vous propose installe un nouveau raccourci clavier permettant la permutation circulaire
des écrans. De cette manière, chaque écran deviendra accessible sans qu'il soit nécessaire d'utiliser cette
vilaine petite souris toujours ensevelie sous une montagne de documents. Et puisque c'est la mode, nous
allons agrémenter ce programme d'un économiseur d'écran (alias "blanker"). En supposant que les touches
du raccourci soient choisies, voyons d'abord ce qu'il est possible de faire afin de tester si celle-ci
sont actionnées.
Il y a énormément de possibilités sur un Amiga. Il serait possible d'utiliser les messages Intuition, mais
l'inconvénient serait alors la nécessité de la présence d'une fenêtre active. Le même inconvénient se
présenterait avec les périphériques logiques CON: et NEWCON:. Enfin la méthode "je programme Amstrad ou Atari" qui
consisterait à lire en permanence les registres matériels afin de savoir quelles touches sont pressées,
ne vaut pas un clou sur Amiga, car cela minerait les performances du multitâche.
Considérant que notre programme devra être une véritable tâche de fond totalement transparente, voici les deux
bonnes possibilités qu'il nous reste : utiliser le console.device ou utiliser l'input.device. Sans raisons
particulières, j'ai choisi l'input.device.
Input.device
L'input.device est une tâche qui est toujours lancée dès que le système démarre. Elle communique en
permanence avec le clavier et les ports souris/manette afin d'obtenir des événements "crus" en provenance du clavier,
de la souris ou de la manette. De plus, le timer.device travaille en étroite collaboration avec l'input.device
pour la gestion de la vitesse de répétition des touches. Comme tous les périphériques logiques, l'input.device est
programmé à l'aide des routines système, Opendevice(), CloseDevice(), DoIO(), SendIO() et AbortIO().
Les commandes traditionelles START, STOP, INVALID et FLUSH sont implémentées et donc valides. Les
autres commandes standard ne sont pas reconnues. En revanche, l'input.device gère
les commandes spécifiques suivantes : IND_WRITEEVENT, IND_ADDHANDLER, IND_REMHANDLER,
IND_SETTHRESH, IND_SETPERIOD, IND_SETMPORT, IND_SETMTRIG et IND_SETMTYPE.
Ne paniquez pas, voici l'explication de ce charabia :
IND_WRITEEVENT : nous commençons là par une commande tout à fait curieuse qui permet à
l'utilisateur non pas de lire un événement reçu par l'input.device, mais de lui en envoyer un
fabriqué maison qui sera reconnu et traité de la même façon que tout événement extérieur.
Application : il est de cette façon possible de s'amuser en enregistrant par exemple les événements
souris à partir de l'input.device, puis de les "rejouer" en renvoyant les événements à l'aide
de cette commande dans le même input.device.
IND_ADDHANDLER : permet d'ajouter un handler à la chaîne. Quèsaco ? Eh bien un peu plus haut,
j'ai dit qu'il était mauvais de lire en permanence l'état des registres-machine. J'ai également
dit que l'input.device communiquait en permanence avec le clavier et les ports souris/manette... Je vois
des vilains avec un sourire en coin qui pensent que je ne sais même pas ce que je dis. Mais si,
car l'input.device surveille le clavier en permanence, mais à partir de routines
d'interruptions. Autrement dit, la surveillance est permanente mais ne s'effectue pas tout le temps,
seulement au rythme des interruptions de la machine. De même, l'utilisateur qui veut avoir
connaissance et pouvoir traiter les événements, doit lui-même ajouter un handler d'interruption
qui sera chaîné avec les autres selon sa priorité.
La rapidité d'exécution étant de rigueur dans
ce genre d'activité, il est de bon ton d'écrire le handler en assembleur. De plus, les
conditions d'entrée (registres a0 et a1) sont telles que l'utilisation du C ou d'un autre
langage nécessiterait un exercice de style tout à fait inutile, comme on peut sans rendre
compte en examinant le source de l'éternel PopCLI fourni avec toutes les versions passées,
présentes et à venir du Lattice. A titre indicacheveu (c'est tout de même plus poli qu'indicatif)
les handlers d'Intuition ont une priorité de 50 et ceux du console.device,
une priorité de 0. Ainsi, avec un handler de priorité 51, il est possible de bidouiller les
événements avant qu'Intuition n'y touche pour par exemple inverser les mouvements de la
souris (Cf. le programme du RKM Libraries And Devices page 700, Oh quelle belle idée de
virus !).
IND_REMHANDLER permet de supprimer un handler de la chaîne. C'est la commande inverse
de la précédente (si !).
IND_SETTHRESH permet de fixer le délai de répétition des touches.
IND_SETPERIOD permet de fixer le délai à partir duquel commence la répétition
des touches.
IND_SETMPORT permet de déterminer le port souris.
IND_SETMTRIG fixe les conditions qui généreront un événement souris.
IND_SETMTYPE fixe le périphérique logique associé au port de la souris.
Comment écrire un handler ?
C'est très simple : il suffit de savoir qu'en a0, est passé le premier événement et qu'en a1,
est passé le champ "Data" de la structure d'interruption correspondant à votre handler.
Pour ceux qui n'auraient pas tout compris, cet article
explique les interruptions avec suffisamment de détails. Les bienheureux qui possèdent les
RKM pourront également s'y reporter.
L'événement dit "InputEvent" répond d'une structure dont le premier élément pointe sur le prochain,
s'il existe. Ceci permet très facilement d'examiner tous les événements en attente et d'agir
en conséquence. Comme condition de sortie, il suffit de placer la valeur initiale de a0 dans
d0 et c'est tout.
Voyons un peu la structure InputEvent.
struct InputEvent {
struct InputEvent *ie_NextEvent;
UBYTE ie_Class;
UBYTE ie_SubClass;
UWORD ie_Qualifier;
union {
struct {
WORD ie_x;
WORD ie_y;
} ie_xy;
APTR ie_addr;
} ie_position;
struct timeeval ie_TimeStamp;
};
|
Le premier élément est déjà expliqué. Ensuite :
- ie_Class indique la provenance de l'événement : clavier, souris, gadget, menu, etc.
- ie_SubClass nous intéresse peu aujourd'hui : ce champ concerne essentiellement
Intuition et les menus.
- ie_Code donne le code de la touche clavier ou du bouton de souris responsable de
l'événement.
- ie_Qualifier indique quelle touche spéciale (Shift, Ctrl, Alt, Amiga) est actionnée.
- ie_position est une union dans laquelle on trouvera suivant le type d'événement,
soit la position du pointeur de la souris, soit une structure correspondant aux événements temps.
Pour connaître le code de touches, vous pouvez vous reporter au RKM Libraries And Devices
page 658. Quelques valeurs intéressantes :
- Help = $5f
- Esc = $45
- Tab = $42
- F1 à F10 = $50 à $59
- Flèches = $4c à $4e
Pour en terminer avec l'input.device, une petite précision peut-être nécessaire : il ne
faut pas confondre la chaîne de handlers avec la chaîne d'événements. Chaque handler de
la chaîne est une routine à laquelle est passée la chaîne de tous les événements. Autrement
dit, les événements sont tous examinés par tous les handlers. Ce qui justifie le besoin de
rapidité de traitement.
Finalement et pour résumer, ce que nous voulons faire, ce n'est que rajouter un handler au
système, cette routine devant elle aussi examiner toute la chaîne d'événements et prendre ses
dispositions en conséquence. Grâce à tout ceci, nous allons pouvoir écrire notre programme très facilement.
Le timer.device (chronomètre)
Que vient-il faire ici celui-là ? Eh bien, dans notre programme de permutation d'écrans,
je vous ai proposé d'ajouter un économiseur d'écran, c'est-à-dire une routine qui se chargera
d'éteindre l'écran si durant une certaine période, aucun événement clavier ou souris n'est
apparu. Ceci permet d'économiser le phosphore du tube cathodique.
Pour ce faire, nous allons utiliser le timer.device. Nous n'en dirons pas grand-chose aujourd'hui car
ce n'est pas notre propos principal. Le timer.device a pour vocation d'envoyer un message au
port avec lequel il a été ouvert pour signaler la fin d'un délai programmé.
Il est à remarquer que chaque fois que le timer.device décrémente le délai, un événement est
engendré, ce qui signifie que l'on pourrait intercepter tout ceci dans notre routine de
traitement des événements. Si cette possibilité peut être parfois intéressante, dans le cas
qui nous occupe, la simplicité veut tout bonnement attendre de façon on ne peut plus classique,
le signal sur le port message.
Deux timers sinon rien
Il y a en effet deux timer.devices dans notre cher Amiga :
- UNIT_VBLANK.timer, synchronisé avec le blank vertical, de bonne précision, et
généralement suffisant pour la plupart des applications.
- UNIT_MICROHZ.timer, doué d'une précision d'enfer pour ceux qui auraient cassé leur
chronomètre.
Les deux chronomètres se programment de la même façon, si ce n'est que UNIT_VBLANK compte
en secondes et UNIT_MICROHZ en microsecondes. Tout ceci étant dit, voyons un peu...
Le programme
La routine assembleur du handler tout d'abord. Là encore, pas de grosses explications (je
suis si fatigué). L'observateur attentif y verra que si un événement souris est reçu,
un signal est envoyé au programme principal. Donc une petite touchette sur la souris suffira
à réallumer l'écran. Si vous jugez que cette sensibilité est excessive, il vous suffit de
supprimer ce morceau de programme.
Ensuite, dans le cas d'un événement clavier, on regarde si la touche "Help" ($5f)
est pressée. Dans ce cas, on examine alors si l'une des touches "Ctrl" ou "Amiga-gauche"
est pressée. Le signal correspondant sera envoyé au programme principal le cas échéant,
sinon ce sera un signal clavier "simple". Si l'événement est d'une autre nature, aucun
signal n'est envoyé et on passe à l'examen de l'événement suivant s'il y en a un.
Le programme principal maintenant : il est écrit en C car C plus facile. Voyez d'abord
dans l'en-tête, pour les liens, le #DEFINE _main=_tinymain (notez bien les deux caractères
soulignés). Ceci sert à remplacer le _main du C par une routine qui ne s'occupera d'aucune
entiée/sortie. C'est une des manières d'éviter, lorsque le programme est lancé depuis le
Workbench, l'ouverture d'une fenêtre par défaut.
Viennent ensuite les déclarations pour le cback du Lattice, qui permet au programme de se
décrocher du CLI. Si votre compilateur ne dispose pas d'une telle option, ça n'est pas
grave, il vous suffira de lancer votre programme par Run.
Après les diverses déclarations, le main() : d'abord, le programme teste s'il a déjà été
lancé on recherche pour cela un port du nom défini par le programme. Si ce port n'existe
pas, cela signifie que le programme est lancé pour la première fois. Dans ce cas, on crée
le port et l'on continue. Sinon, si le port existe déjà, c'est que le programme
est déjà lancé et on quitte immédiatement.
Ensuite, les bibliothèques et périphériques logiques nécessaires sont ouverts et les signaux alloués.
Puis le handler est installé et le chronomètre est lancé une première fois. Le programme
se met alors en attente des différents signaux.
L'extinction de l'écran est réalisée comme suit : on ouvre un écran Intuition de très petite
hauteur (12) afin d'éviter le problèmes de mémoire. L'encre de fond est mise à 0,
couleur noire. Il reste à éteindre le pointeur de souris. Il est possible d'utiliser pour ce
faire les routines SetPointer() et ClearPointer() d'Intuition. J'ai choisi une autre
solution qui consiste à couper les directement DMA dans le matériel avec la macro OFF_DISPLAY,
histoire de vous donner un exemple de programmation des registres-machine en C.
Un bogue (énorme et monstrueux) du Lattice
La boucle qui attend les signaux est une boucle sans fin. Normallement, une telle boucle
s'écrit en C soit for (;;) soit while (1) mais ne le faites pas ici, car le compilateur
vous fabriquerait n'importe quoi sans pour autant vous envoyer de message d'erreur (normal,
le programme n'en comporte pas). Pas même une petite alerte (warning). Rien.
Ce bogue se manifeste comme suit : si les fonctions sont déclarées avant main() et définies
après, le bogue apparaît. Et si les fonctions sont exprimées avant le main(), le programme est
parfois compilé correctement...
Pour remédier infailliblement à cela, j'utilise while(task), "task" étant l'adresse de base
de la tâche. C'est une constante ultra-sûre. En faisant ainsi, le "while" n'est plus sans test
et le programme est toujours compilé correctement. Ce n'est bien sûr pas la seule solution et
de loin, on aurait même pu écrire le programme tout autrement, mais je n'ai pas pu résister à
la tentation de laisser libre cours à ma médisance. M'enfin, le Lattice n'en reste pas moins
(à mon avis) le meilleur compilateur C disponible sur Amiga. Pour le moment.
Cet énorme bogue du Lattice 5.04 n'a pas été corrigé dans le 5.10.
Programme "CRBlanker.c"
- Fonctions : éteindre moniteur si ordinateur inutilisé après délai réglé par utilisateur. Permuter écrans Intuition.
- Utilisation : "Ctrl + Help" pour régler délai et "Amiga gauche + Help" pour permuter écrans.
- Compilateur : Lattice C 5.10.
- Compilation : lc -cist -v
- Lien : FROM LIB:cback.o+"CRBlanker.o"+"blankerhandler.o" TO "CRBlanker.
LIB LIB:lc.lib LIB:amiga.lib
NODEBUG
SMALLCODE
SMALLDATA
DEFINE =main=_tinymain
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <exec/interrupts.h>
#include <exec/devices.h>
#include <libraries/dos.h>
#include <devices/timer.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <intuition/intuitionbase.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <graphics/gfxmacros.h>
#include <hardware/custom.h>
#include <hardware/dmabits.h>
#include <string.h>
#ifdef LATTICE
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#endif
/***************************************************************************
* DECLARATION POUR CBACK *
***************************************************************************/
#ifdef LATTICE
extern BPTR _Backstdout;
char *_procname = "Blanker";
LONG _BackGroundIo = 1;
LONG _stack = 4000;
LONG _priority = 20;
#endif
/***************************************************************************
* CONSTANTES *
***************************************************************************/
#define PORTNAME "Blanker_Port"
#define TICK 5L /* interval de 5 secondes */
#define Message "CRBIankcr 1.0 par F Mazué"
/***************************************************************************
* VARIABLES GLOBALES *
***************************************************************************/
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
/***************************************************************************
* StringInzo pour gadget de chaîne *
***************************************************************************/
UBYTE Buffer[2] = "";
struct StringInfo MyStringInfo =
{
Buffer,
NULL,
1,
2,
0,
0,
0,
0,
0,0,
NULL,
NULL,
NULL
};
/***************************************************************************
* Gadget de chaîne *
***************************************************************************/
struct Gadget MyGadget =
{
NULL, /* pas d'autre gadget */
95,48, /* position dans la fenêtre */
20,10, /* largeur et hauteur */
GADGHCOMP, /* flags */
RELVERIFY, /* activation */
STRGADGET, /* type de gadget */
NULL,
NULL,
NULL,
NULL,
(APTR)&MyStringInfo, /* pointeur sur Stringlnfo */
0,
NULL
};
/***************************************************************************
* fenêtre pour réglage delai *
***************************************************************************/
struct NewWindow Reglage =
{
100,100, /* position */
250,70, /* dimensions */
1,3, /* couleur de fond et crayon */
GADGETUP, /* flag evenement */
ACTIVATE|GIMMEZEROZERO, /* flags */
&MyGadget, /* pointeur sur gadget de chaîne */
NULL,
"Blanker 1.0 par P MAZUE",
NULL,
NULL,
250,70, /* dimensions mini */
250,70, /* dimensions maxi */
WBENCHSCREEN
};
struct NewScreen NewScreen =
{
0,0,320,12,1,
0,0,
NULL,
SCREENQUIET,
NULL,
NULL,
NULL,
NULL
};
char *text_reglage[] =
{
"(1-9) nb de minutes avant",
"extinction des feux",
"(x ou X) arrête programme"
};
BYTE InputSig = -1;
BYTE PermutSig = -1;
BYTE InitSig = -1;
struct Task *task = NULL;
LONG TimeSigMask = NULL;
LONG InputSigMask = NULL;
LONG PermutSigMask = NULL;
LONG InitSigMask = NULL;
LONG Sig = NULL;
LONG Time_Limite = 24; /* soit deux minutes */
LONG Time_Count = NULL;
LONG Active = NULL;
struct MsgPort *port = NULL,
*inputdevice_port = NULL,
*timedevice_port = NULL;
struct IOStdReq *inputreq = NULL;
struct timerequest *timereq = NULL;
struct Interrupt *InputHandler;
extern struct Custom custom;
struct Custom *cust = &custom;
#define custom (*cust)
/***************************************************************************
* DECLARATION DES FONCTIONS *
***************************************************************************/
extern VOID MyHandler();
VOID Clean_Exit();
VOID LaunchTimer(struct timerequest *tr, LONG secondes);
LONG InitLimite();
/***************************************************************************
* PROGRAMME PRINCIPAL *
***************************************************************************/
VOID main()
{
struct Screen *BlankScreen = NULL;
if (port=(struct MsgPort *)FindPort(PORTNAME))
{
Active = 1L;
Clean_Exit();
}
#ifdef LATTICE
if (_Backscdout)
{
Write(_Backstdout, Message, sizeof(Message));
Close(_Backstdout); /* on libère 1e CLI */
_Backstdout=0;
}
#endif
/***************************************************************************
* Suis-je déjà là ? *
***************************************************************************/
port = (struct MsgPort *)CreatePort(PORTNAME,NULL);
if (!port) Clean_Exit();
/***************************************************************************
* Ouvertures et Initialisations *
***************************************************************************/
if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 0)))
Clean_Exit();
if (!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0)))
Clean_Exit();
if (!(inputdevice_port = CreatePort(NULL, NULL)))
Clean_Exit();
if (!(inputreq = ((struct IOStdReq *) CreateExtIO(inputdevice_port, sizeof(struct IOStdReq)))))
Clean_Exit();
if (OpenDevice( "input.device", NULL, (struct IORequest *)inputreq, NULL))
Clean_Exit();
if (!(timedevice_port = CreatePort(NULL, NULL)))
Clean_Exit();
if (!(timereq = (struct timerequest *) CreateExtIO(timedevice_port, sizeof(struct timerequest))))
Clean_Exit();
if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)timereq, NULL))
Clean_Exit();
TimeSigMask = (1L << timedevice_port->mp_SigBit);
if((InputSig = AllocSignal(-1L)) == -1)
Clean_Exit();
InputSigMask = 1L << InputSig;
if((PermutSig = AllocSignal(-1L)) == -1)
Clean_Exit();
PermutSigMask = 1L << PermutSig;
if((InitSig = AllocSignal(-1L)) == -1)
Clean_Exit();
InitSigMask = 1L << InitSig;
task = (struct Task *)FindTask(NULL);
/***************************************************************************
* Installation du Handler *
***************************************************************************/
if(!(InputHandler = (struct Interrupt *) AllocMem(sizeof(struct Interrupt), MEMF_PUBLIC|MEMF_CLEAR)))
Clean_Exit();
InputHandler->is_Code = (VOID (*)())MyHandler;
InputHandler->is_Data = NULL;
InputHandler->is_Node.ln_Pri = 51;
InputHandler->is_Node.ln_Name = "MyInputHandler";
inputreq->io_Data = (APTR) InputHandler;
inputreq->io_Command = IND_ADDHANDLER;
DoIO((struct IORequest *)inputreq);
LaunchTimer(timereq, TICK);
/***************************************************************************
* *
* L'éternité c'est long ... Surtout vers la fin *
* *
***************************************************************************/
while(task)
{
Sig = Wait(TimeSigMask | InputSigMask | PermutSigMask | InitSigMask);
if ((Sig & InputSigMask) && (BlankScreen == NULL))
Time_Count = NULL;
if ((Sig & InputSigMask) && (BlankScreen != NULL))
{
CloseScreen(BlankScreen);
ON_DISPLAY;
BlankScreen = NULL;
Time_Count = NULL;
}
if (Sig & InitSigMask)
{
if (BlankScreen != NULL)
{
CloseScreen(BlankScreen);
BlankScreen = NULL;
ON_DISPLAY;
}
WBenchToFront();
Time_Limite = InitLimite();
Time_Limite *= 12;
Time_Count = NULL;
}
if (Sig & TimeSigMask)
{
if (BlankScreen == NULL)
{
Time_Count++;
if (Time_Count > Time_Limite)
{
BlankScreen = (struct Screen *)OpenScreen(&NewScreen);
if (BlankScreen != NULL)
{
SetRGB4(&(BlankScreen->ViewPort), 0, 0, 0, 0) ;
OFF_DISPLAY;
}
}
}
LaunchTimer(timereq, TICK);
}
if (Sig & PermutSigMask)
{
if (BlankScreen)
{
CloseScreen(BlankScreen);
BlankScreen = NULL;
ON_DISPLAY;
}
Time_Count = NULL;
ScreenToBack(IntuitionBase->FirstScreen);
}
}
}
/***************************************************************************
* FONCTIONS *
***************************************************************************/
VOID Clean_Exit()
{
if (timereq != NULL)
{
if (timereq->tr_node.io_Device != NULL)
{
CloseDevice((struct IORequest *)timereq);
}
DeleteExtIO((struct IORequest *)timereq);
}
if (inputreq != NULL)
{
if (inputreq->io_Device != NULL)
{
inputreq->io_Command = IND_REMHANDLER;
inputreq->io_Data = (APTR)InputHandler;
DoIO((struct IORequest *)inputreq);
CloseDevice((struct IORequest *)inputreq);
}
DeleteExtIO((struct IORequest *)inputreq);
}
if (InputHandler) FreeMem(InputHandler, sizeof(struct Interrupt));
if (InitSig != -1) FreeSignal(InitSig);
if (PermutSig != -1) FreeSignal(PermutSig);
if (InputSig != -1) FreeSignal(InputSig);
if (timedevice_port) DeletePort(timedevice_port);
if (inputdevice_port) DeletePort(inputdevice_port);
if (GfxBase) CloseLibrary((struct Library *)GfxBase);
if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
if (port && (!Active)) DeletePort(port);
exit(0);
}
VOID LaunchTimer(struct timerequest *tr, LONG secondes)
{
tr->tr_node.io_Command = TR_ADDREQUEST;
tr->tr_time.tv_secs = secondes;
tr->tr_time.tv_micro = 0;
SendIO((struct IORequest *)tr);
}
LONG InitLimite()
{
struct Window *MyWindow;
LONG nb_minute = NULL;
char dummy_string[2];
if ((MyWindow = (struct Window *)OpenWindow(&Reglage)) == NULL)
Clean_Exit();
Move(MyWindow->RPort, 10, 10);
Text(MyWindow->RPort, text_reglage[0], strlen(text_reglage[0]));
Move(MyWindow->RPort, 10, 20);
Text(MyWindow->RPort, text_reglage[1], strlen(text_reglage[1]));
Move(MyWindow->RPort, 10, 40) ;
Text(MyWindow->RPort, text_reglage[2], strlen(text_reglage[2]));
do
{
strcpy(dummy_string, "+O");
ActivateGadget(&MyGadget, MyWindow, 0);
Wait(1L << MyWindow->UserPort->mp_SigBit);
if (Buffer[0] == 'x' | Buffer[0] == 'X')
{
CloseWindow(MyWindow);
Clean_Exit();
}
dummy_string[1] = Buffer[0];
nb_minute = atoi(dummy_string) ;
}
while((Buffer[0] > '9') | (Buffer[0] < '1'));
CloseWindow(MyWindow);
return(nb_minute);
}
|
Mise à jour de juillet 2024 : une archive contenant le listing adapté à vbcc, et avec les
exécutables compilés par SAS C et vbcc, a été réalisée par Yann-Gaël "Tygre" Guéhéneuc et est disponible
sur obligement.free.fr/files/antcrblanker.lha.
Programme "Blankershandlers"
- Fonction : routine assembleur pour le programme CRBlanker.
- Assembleur : Devpac 2.
- Assemblage : produire un code reliable sous le nom "blankerhandler.o".
include exec/exec_lib.i
include exec/io.i
include devices/inputevent.i
XREF _task
XREF _InputSigMask
XREF _PermutSigMask
XREF _InitSigMask
XDEF _MyHandler
_MyHandler
move.l a0,-(sp) ;empiler chaîne d'événement
Loop
move.b ie_Class(a0),d1
move.l _InputSigMask,d0
cmp.b #IECLASS_RAWMOUSE,d1 ;événement souris ?
bne no_mouse
bra envoie_signal ;oui -> envoi signal
no_mouse
cmp.b #IECLASS_RAWKEY,d1
bne Next
move.w ie_Code(a0),d1
cmp.w #$5f,d1 ;touche HELP pressée
bne envoie_signal ;non -> envoi signal clavier simple
move.w ie_Qualifier(a0),d1
btst #IEQUALIFIERB_CONTROL,d1 ;touche contrôle pressée ?
beq suite
move.l _InitSigMask,d0
bra envoie_signal ;envoi signal pour
;ouvrir fenêtre de réglage
suite
btst #IEQUALIFIERB_LCOMMAND,d1 ;touche Amiga gauche pressée ?
beq envoie_signal ;non -> envoi signal clavier simple
move.l _PermutSigMask,d0 ;pour envoi signal
;permutation d'écran
envoie_signal
move.l a0,-(sp)
move.l _task,a1
CALLEXEC Signal
move.l (sp)+,a0
Next
move.l (a0),d0 ;pour positionner flag Z
move.l d0,a0
bne Loop ;prochain événement
move.l (sp)+,d0 ;récupérer liste événement dans D0
rts
|
|