Obligement - L'Amiga au maximum

Vendredi 29 mars 2024 - 14:36  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in english


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

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


Trucs et astuces

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


Glossaire

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


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


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

C
C
C
C
C
C
C
C
C
C

Programme "Blankershandlers"

Fonction : routine assembleur pour le programme CRBlanker.
Assembleur : Devpac 2.
Assemblage : produire un code reliable sous le nom "blankerhandler.o".

C


[Retour en haut] / [Retour aux articles]