Home   Archives    Hardware   Programmation   Challenges   Forum   Le Mag    Faq   La Communauté   L'Equipe
 
L'équipe progG de Ti-Fr

Voici les nicks de vos serviteurs ;-)

chickensaver_john
Kevin Kofler
Thibaut
janjan2
TiMad
Iceman89
fréka
Zewoo
Squale92
Verstand
ZdRUbAl
UtOpIaH

et nEUrOne ...

Une idée ?
Une idée pour améliorez cette partie? ou tout simplement vous souhaitez participer à l'élaborations des tutos.
Mailez-nous ici

Les raccourcis
 

Chapitre XVIII


    Jusqu'à maintenant, nous avons utilisé la fonction ngetchx() pour lire le clavier. mais, cette fonction est très lente, car elle lit aussi les port de communication I/O. De plus, le problème de cette fonction est qu'elle met en pause l'exécution du programme, jusqu'à ce qu'une touche soit pressée. Il est donc impossible (ou presque) de gérer le clavier avec cette fonction si l'on veut, en même temps afficher des animations à l'écran, ou effectuer quoi que ce soit d'autre...
    Certes, il existe la fonction kbhit, qui permet de lire au clavier sans déclencher de pause, ce qui permet d'utiliser des animations, mais cette fonction n'est pas aussi rapide que _rowread...
    En conclusion, si vous souhaitez créer un programme affichant des animations, et acceptant des pressions au clavier, comme pour un jeux d'action, par exemple, il vous faudra utiliser _rowread pour obtenir quelque chose de rapide...

    Cette fonction, qui semble assez complexe à utiliser ne l'est en fait pas tant que cela : le tout est d'en comprendre les bases, afin de pouvoir les ré-appliquer... C'est ce que va (j'espère !) vous permettre de faire ce chapitre...

 

I:\ Manipulations préliminaires :

    La fonction _rowread lit le clavier, mais à bas niveau. En fait, la lecture du clavier par cette fonction est basée sur l'AUTO_INT_1. (Il s'agit d'une sorte de compteur à rebours quasi-permanent de la TI.). Si le "compteur à rebours" arrive à 0, cela déclenche des "évènements", qui peuvent interférer avec cette fonction. Donc, il est particulièrement recommandé de désactiver l'AUTO_INT_1.
    Cependant, les niveaux de gris sont basés sur cet AUTO_INT (voir la page qui traite de la gestion des niveaux de gris).!!! Quel ennui pour les jeux, n'est-ce pas ?!?
    Pour éviter ce problème, nous utiliserons une voie détournée : nous ne désactiverons pas l'AUTO_INT_1, mais nous le "remplacerons".... Ainsi, il n'y aura pas d'interférence avec _rowread, et, oh miracle, les niveaux de gris fonctionneront ! De plus, les indicateurs de la Status Line (2nd, <>, @, ...) n'apparaîtront plus à l'écran, ce qui permettra d'utiliser les touches HAND (sur 92+) ou 2nd (Sur 89) pour le déclenchement des tirs, par exemple dans le cas d'un jeu d'action, sans que l'affichage soit perturbé par ceux-ci.

    Pour rediriger l'AUTO_INT_1, nous utiliserons l'Interrupt qui a été inclut dans ce but dans TIGCC, le DUMMY_HANDLER.

    Au début de notre programme, il faudra ainsi inclure la ligne de code suivante, qui permettra de déclarer la sauvegarde de l'AUTO_INT_1, afin de le restaurer avant la fin du programme :
        INT_HANDLER save_int_1;

    Ensuite, au moment ou vous souhaiterez commencer à utiliser _rowread, il vous faudra inclure les lignes de code suivantes :
        save_int_1 = GetIntVec (AUTO_INT_1);
        SetIntVec (AUTO_INT_1, DUMMY_HANDLER);
    Ces fonctions vous permettront de sauvegarde l'AUTO_INT_1, puis d'installer le votre (en l'occurrence, DUMMY_HANDLER) à la place.
    Attention, l'utilisation de fonction de lecture du clavier à Haut Niveau, telles ngetchx() ré-activerons l'AUTO_INT_1, ou pourront être à l'origine d'un plantage s'il n'est pas activé... 

    Enfin, à la fin de votre programme, il vous faudra impérativement penser à ré-activer l'AUTO_INT_1, afin d'éviter toute "barre noire" assez désagréable lorsqu'on vient de passer un bon moment sur un jeu ! pour cela, il vous faut utiliser la fonction suivante :
        SetIntVec (AUTO_INT_1, save_int_1);

 

II:\ La lecture du clavier avec _rowread :

    Cette fonction a un mode de fonctionnement assez exotique, car elle lit la "Matrice Clavier", qui est différente sur TI-89 et Ti-92plus, puisque les claviers eux-même sont différents...

    Voilà comment la matrice clavier est organisée, sur TI-89 puis sur TI-92plus :

TI-89:
  Colonne
Ligne
  Bit 7  
  Bit 6  
  Bit 5  
  Bit 4  
  Bit 3  
  Bit 2  
  Bit 1  
  Bit 0  
Bit 0
Alpha
Diamant
Shift
2nd
Droite
Bas
Gauche
Haut
Bit 1
F5
CLEAR
^
/
*
-
+
ENTER
Bit 2
F4
Delete
T
,
9
6
3
(-)
Bit 3
F3
CATLG
Z
)
8
5
2
.
Bit 4
F2
MODE
Y
(
7
4
1
0
Bit 5
F1
HOME
X
=
|
EE
STO->
APPS
Bit 6

NON AFFECTÉES !!!

ESC

TI-92plus:
  Colonne
Ligne
  Bit 7  
  Bit 6  
  Bit 5  
  Bit 4  
  Bit 3  
  Bit 2  
  Bit 1  
  Bit 0  
Bit 0
Bas
Droite
Haut
Gauche
HAND
Shift
Diamant
2nd
Bit 1
3
2
1
F8
W
S
Z

Non
affectées

Bit 2
6
5
4
F3
E
D
X
Bit 3
9
8
7
F7
R
F
C
STO->
Bit 4
,
)
(
F2
T
G
V
Espace
Bit 5
TAN
COS
SIN
F6
Y
H
B
/
Bit 6
P
ENTER2
LN
F1
U
J
N
^
Bit 7
*
APPS
CLEAR
F5
I
K
M
=
Bit 8
ESC
MODE
+
O
L
Thêta
Delete
Bit 9
(-)
.
0
F4
Q
A
ENTER1
-

Pour TI-92plus, ENTER1 correspond aux deux touches ENTER du clavier alphanumérique, et ENTER2 correspond à la touche ENTER localisée sous le pavé multidirectionnel.

    Utilisation de _rowread avec la matrice clavier :

    En fait, _rowread prend en argument une valeur de type short, qui correspond à la transcription en Hexadécimal de la valeur en binaire de la colonne... C'est compliqué, n'est-ce pas ? Eh bien, NON : c'est une simple impression sur le papier : quand vous aurez utilisé cette fonction deux ou trois fois, vous vous direz que c'était vraiment simple !
    Ensuite, elle renvoie la valeur de la ligne correspondant au test ...

    Je penses que le mieux pour que vous compreniez ce que je veux dire est que je fournisse un exemple :

Partons de l'exemple de la lecture de la Touche MODE. 

    Sur TI-89 : La touche MODE est sur cette calculatrice la troisième de sa colonne, en partant du bas. La colonne, si on ne veut conserver que cette touche, aura donc, en binaire, comme valeur : 1101111. Il convient à présent de convertir cette valeur en hexadécimal (ce que votre TI sait faire !), et qui donne, dans ce cas : 0x10. (Rappel : Depuis la version 0.91 de TIGCC, il est possible d'utiliser des valeurs en binaire, mais, pour raison de compatibilité avec les anciennes versions, je vous conseille de les transcrire tout de même en hexadécimal).
        Donc, pour tester la ligne qui correspond à la touche MODE, il faudra utiliser _rowread(0x6F)...
    Cette fonction renvoie la valeur (en hexadécimal, correspondant à la valeur en binaire) de la ligne correspondant à celle qui a été marquée par un "0" dans l'argument de la fonction. Ainsi, la ligne correspondant à la touche MODE aura pour valeur, si celle-ci a été pressée : 01000000 (puisque la touche MODE est la seconde en partant de la gauche). Cela correspond à 0x40 en hexadécimal.
    Donc, pour tester le fait que la touche MODE ait été pressée, il faudra faire :
        if(_rowread(0x6F)&0x40)
        {
            // instructions à exécuter si MODE a été pressé...
        }

    Sur TI-92plus : La touche MODE est sur cette calculatrice la seconde de sa colonne, en partant du bas. La colonne, si on ne veut conserver que cette touche, aura donc, en binaire, comme valeur : 1011111111. Il convient à présent de convertir cette valeur en hexadécimal (ce que votre TI sait faire !), et qui donne, dans ce cas : 0x2FF. (Rappel : Depuis la version 0.91 de TIGCC, il est possible d'utiliser des valeurs en binaire, mais, pour raison de compatibilité avec les anciennes versions, je vous conseille de les transcrire tout de même en hexadécimal).
        Donc, pour tester la ligne qui correspond à la touche MODE, il faudra utiliser _rowread(0x2FF)...
    Cette fonction renvoie la valeur (en hexadécimal, correspondant à la valeur en binaire) de la ligne correspondant à celle qui a été marquée par un "0" dans l'argument de la fonction. Ainsi, la ligne correspondant à la touche MODE aura pour valeur, si celle-ci a été pressée : 00100000 (puisque la touche MODE est la seconde en partant de la gauche). Cela correspond à 0x20 en hexadécimal.
    Donc, pour tester le fait que la touche MODE ait été pressée, il faudra faire :
        if(_rowread(0x2FF)&0x20)
        {
            // instructions à exécuter si MODE a été pressé...
        }

 

    Quelques valeurs les plus couramment utilisées :

    Maintenant que je vous ai expliqué le fonctionnement général, je crois qu'il serait bon que je vous fournisse quelques cas précis. En effet, je ne suis pas sûr que mes explications aient été très claire :-).

    Sur TI-92plus :

Touche de la TI
Valeur binaire
Valeur hexadécimale
Instruction de test : if(....)
Colonne
Ligne
Colonne
Ligne
Gauche

1111111110

00010000
0x3FE
0x10
_rowread(0x3FE)&0x10
Droite
1111111110
01000000
0x3FE
0x40
_rowread(0x3FE)&0x40
Haut
1111111110
00100000
0x3FE
0x20
_rowread(0x3FE)&0x20
Bas
1111111110
10000000
0x3FE
0x80
_rowread(0x3FE)&0x80
HAND
1111111110
00001000
0x3FE
0x8
_rowread(0x3FE)&0x8
2nd
1111111110
00000001
0x3FE
0x1
_rowread(0x3FE)&0x1
F1
1110111111
00010000
0x3BF
0x10
_rowread(0x3BF)&0x10
ESC
1011111111
01000000
0x2FF
0x40
_rowread(0x2FF)&0x40

    Sur la TI-89 :

Touche de la TI
Valeur binaire
Valeur hexadécimale
Instruction de test : if(....)
Colonne
Ligne
Colonne
Ligne
Gauche

1111110

00000010
0x7E
0x2
_rowread(0x7E)&0x2
Droite
1111110
00001000
0x7E
0x8
_rowread(0x7E)&0x8
Haut
1111110
00000001
0x7E
0x1
_rowread(0x7E)&0x1
Bas
1111110
00000100
0x7E
0x4
_rowread(0x7E)&0x4
Alpha
1111110
10000000
0x7E
0x80
_rowread(0x7E)&0x80
2nd
1111110
00010000
0x7E
0x10
_rowread(0x7E)&0x10
F1
1011111
10000000
0x5F
0x80
_rowread(0x5F)&0x80
ESC
0111111
00000001
0x3F
0x1
_rowread(0x3F)&0x1

Si vous vous rendez compte qu'une des valeurs que je donne ici ne fonctionne pas, merci de me le signaler immédiatement, afin que je puisse corriger cette erreur au plus vite ! (En précisant dans quel tableau se trouve l'erreur.). Merci.

 

III:\ Exemple de source utilisant _rowread :

    Ce petit programme va afficher un sprite en mouvement automatique en bas de l'écran, à la vitesse maximale qui lui sera autorisée, et un autre, plus gros, que vous pourrez déplacer à votre guise dans la zone qui lui est assignée.
    Étant donné que la fonction _rowread prend en argument des valeurs différentes sur TI-89 est sur TI-92plus, ce programme comporte une boucle conditionnelle qui s'exécute si la largeur de l'écran est égale à 160 (=> TI-89), et une autre si elle est différente de 160 (=> TI-92plus). Dans un jeu, par exemple, il vaudrait mieux créer deux sources spécifiques, l'un pour TI-89, et l'autre pour TI-92plus, ce qui permettrait d'économiser de l'espace mémoire. Par contre, le programme ne serait plus utilisable à la fois sur TI-89 et sur TI-92plus.

#define OPTIMIZE_ROM_CALLS
#define SAVE_SCREEN
#include <tigcclib.h>

short _ti92plus, _ti89;

void _main(void)
{
// Déclaration des sprites qui seront utilisés pour les animations. sprite_TI et sprite_TI_vide correspondent à deux sprites de 32x32 pixels, qui seront animés par l'utilisateur du programme, et sprite_comic et sprite_comic_vide correspondent aux sprites qui seront utilisés pour l'animation automatique.
  static unsigned long sprite_TI[] = {0xFF000, 0x700E00, 0x1800180, 0x2000040, 0x4000020, 0x87C3E10, 0x10824108, 0x20442204, 0x20381C04, 0x40018002, 0x40018002, 0x40018002, 0x8003C001, 0x8007E001, 0x8007E001, 0x8005A001, 0x80000001, 0x80000001, 0x80000001, 0x800FF001, 0x4115A882, 0x41E00782, 0x41400282, 0x21400284, 0x20200404, 0x1015A808, 0x80FF010, 0x4000020, 0x2000040, 0x1800180, 0x700E00, 0xFF000};
  static unsigned long sprite_TI_vide[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
  static unsigned short sprite_animation[] = {0x180, 0x660, 0x1818, 0x2004, 0x2664, 0x4002, 0x4182, 0x8181, 0x8181, 0x4812, 0x4422, 0x23C4, 0x2004, 0x1818, 0x660, 0x180};
  static unsigned short sprite_animation_vide[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
/* 
Déclaration des variables qui seront utilisées dans le programme :
    pos_x_comic correspond à la position en X du sprite auto-animé (il ne se déplace que horizontalement).
    pos_x_TI et pos_y_TI correspondent à la position en X et en Y du sprite qui sera animé par l'utilisateur du programme.
    aller_retour aura pour valeur 1 si le sprite auto-animé se déplace de la gauche vers la droite, et 0 dans le sens contraire.
    quitter aura pour valeur 0 tant que l'utilisateur n'aura pas appuyé sur ESC, dans le but de quitter le programme.
    Enfin, save_int_1 correspond à la sauvegarde de l'AUTO_INT_1.
*/
 
short pos_x_comic = 0;
 
short pos_x_TI = 0, pos_y_TI = 0;
 
short quitter = 0;
 
short aller_retour = 0;
  INT_HANDLER save_int_1;

// Initialisation des variables qui doivent l'être, ainsi que sauvegarde de l'AUTO_INT_1, et effacement de l'écran.
  pos_x_TI
= 0;
  pos_y_TI = 18;
 
save_int_1 = GetIntVec(AUTO_INT_1);
  SetIntVec(AUTO_INT_1, DUMMY_HANDLER);
  ClrScr();

// Affichage de l'écran de départ, avant l'animation. Toutes les fonctions utilisées ici ont déjà été étudiées dans ce tutorial.
 
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI, LCD_MEM, A_OR);
  DrawLine(0, 16, LCD_WIDTH, 16, A_THICK1);
  FontSetSys(F_8x10);
 
DrawStrXY((LCD_WIDTH-DrawStrWidth("_rowread DEMO", F_8x10))/2, 2, "_rowread DEMO", A_SHADED);
 
Sprite16(0, 0, 16, sprite_animation, LCD_MEM, A_OR);
 
Sprite16(LCD_WIDTH-16, 0, 16, sprite_animation, LCD_MEM, A_OR);

 
do
  {
// gestion du sprite automatique : Au début, il est effacé (grâce à l'affichage d'un sprite vide), puis, sa position est modifiée en fonction de sa position actuelle, et, enfin, il est redessiné à sa nouvelle position.
   
Sprite16(LCD_WIDTH-pos_x_comic-16, LCD_HEIGHT-16, 16, sprite_animation_vide, LCD_MEM, A_XOR);
   
if(pos_x_comic<LCD_WIDTH-16 && aller_retour==1)
    {
      pos_x_comic++;
    }
    else if(pos_x_comic>0 && aller_retour==0)
    {
      pos_x_comic--;
    }
   
if(pos_x_comic==LCD_WIDTH-16 && aller_retour==1)
    {
      aller_retour = 0;
    }
   
if(pos_x_comic==0 && aller_retour==0)
    {
      aller_retour = 1;
    }
   
Sprite16(LCD_WIDTH-pos_x_comic-16, LCD_HEIGHT-16, 16, sprite_animation, LCD_MEM, A_OR);

// Cette partie correspond à la TI-92plus :
   
if(LCD_WIDTH != 160)
    {
     
if(_rowread(0x3FE)&0x10 && pos_x_TI>0) //Gauche
     
{
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI_vide, LCD_MEM, A_XOR);
        pos_x_TI--;
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI, LCD_MEM, A_OR);
      }
     
if(_rowread(0x3FE)&0x40 && pos_x_TI<LCD_WIDTH-32) //Droite
     
{
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI_vide, LCD_MEM, A_XOR);
        pos_x_TI++;
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI, LCD_MEM, A_OR);
      }
     
if(_rowread(0x3FE)&0x80 && pos_y_TI<LCD_HEIGHT-32-16) //Bas
     
{
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI_vide, LCD_MEM, A_XOR);
        pos_y_TI++;
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI, LCD_MEM, A_OR);
      }
     
if(_rowread(0x3FE)&0x20 && pos_y_TI>18) //Haut
     
{
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI_vide, LCD_MEM, A_XOR);
        pos_y_TI--;
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI, LCD_MEM, A_OR);
      }
     
if(_rowread(0x2FF)&0x40) // Esc
     
{
       
quitter = 1;
      }
    }

// Et cette partie est detinée à la TI-89 :
   
if(LCD_WIDTH == 160)
    {
     
if(_rowread(0x7E)&0x2 && pos_x_TI>0) //Gauche
     
{
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI_vide, LCD_MEM, A_XOR);
        pos_x_TI--;
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI, LCD_MEM, A_OR);
      }
     
if(_rowread(0x7E)&0x8 && pos_x_TI<LCD_WIDTH-32) //Droite
     
{
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI_vide, LCD_MEM, A_XOR);
        pos_x_TI++;
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI, LCD_MEM, A_OR);
      }
     
if(_rowread(0x7E)&0x4 && pos_y_TI<LCD_HEIGHT-32-16) //Bas
     
{
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI_vide, LCD_MEM, A_XOR);
        pos_y_TI++;
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI, LCD_MEM, A_OR);
      }
     
if(_rowread(0x7E)&0x1 && pos_y_TI>18) //Haut
     
{
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI_vide, LCD_MEM, A_XOR);
        pos_y_TI--;
       
Sprite32(pos_x_TI, pos_y_TI, 32, sprite_TI, LCD_MEM, A_OR);
      }
     
if(_rowread(0x23F)&0x1) // Esc
     
{
       
quitter = 1;
      }
    }

  }
while(quitter != 1); // répète la boucle Do tant que quitter est différent de 1, c'est-à-dire tant que l'utilisateur n'a pas appuyé sur ESC.

  SetIntVec(AUTO_INT_1, save_int_1); // Restaure l'AUTO_INT_1

}

IV:\ Lecture de plusieurs touches :

    La fonction _rowread permet, comme nous venons de le voir, de lire les touches pressées au clavier une par une. mais cette fonction permet aussi de lire des pressions simultanées.
    Pour cela, il vous suffit de masquer plusieurs colonne, ou d'analyser les résultats de plusieurs bits d'une ligne.

    Pour lire plusieurs colonnes, il faudra placer plusieurs "0" dans la définition binaire de l'argument, et, pour lire plusieurs touches sur une même ligne, il suffira de lire si, dans la réponse hexadécimale traduite en binaire, plusieurs bits sont sur "1".

    Juste un petit avertissement : si trois touches formant trois angles d'un rectangle (au niveau de la matrice clavier) sont pressées en même temps, la calculatrice considérera que la touche formant le quatrième angle de ce rectangle l'est aussi. Cela est du à la gestion du clavier par la TI... Mais, je doute que ceci vous gène particulièrement : il est souvent plus simple de lire les touches unes par unes, sauf dans le cas où vous voulez obtenir 2nd+haut, ou quelque chose de ce type...

 

V:\ Conclusion de ce chapitre :

    Et voilà, j'espère que vous avez compris ce que j'ai tenté de vous expliquer dans ce chapitre. Si tel n'est pas le cas, persévérez, car cette fonction vaut vraiment la peine de se fatiguer à étudier son fonctionnement.
    Ce que vous pouvez faire pour vous rendre compte de vos nouvelles capacités, c'est essayer de développer un jeu, à partir de maintenant : avec tous ce que nous avons à présent vu (Niveaux de gris, Sprites, Graphismes, _rowread, ...), cela devrait vous être possible...

    Pour ce chapitre, je tiens à remercier tout particulièrement Liquid (alias Psigames) et Otheos pour leurs nombreux reports d'erreurs.

Retour au menu général

Chapitre XIX


 


Copyright © Ti-Fr v2.0 1999-2002