Sylvain Maréchal

Révision le 18/11/2005

Réalisation d'une boîte à outils pour les applications Turbo C++ développées en mode texte


Fonction getch_timeout()

Cette fonction fonctionne comme getch(). Sa particularité est de sortir lorsqu'un temps précisé en argument est écoulé.

Elle peut servir de base à toute application en attente d'un choix de l'utilisateur. Le timeout peut être utilisé pour afficher une animation « en tâche de fond ».

Les versions plus évoluées peuvent être utilisées pour réaliser des jeux simples (Tetris, packman, arkanoid; jeux de tirs, serpent etc...)


version de base

long getch_timeout( clock_t timeout )


Argument :

Valeur de retour :


Indications :

On commence par stocker « l'heure de début de la fonction» clockDeb à l'aide de la fonction clock().

On utilise une boucle do {...} while (1);

au sein de cette boucle, on va utiliser la fonction kbit() qui renvoie une valeur non nulle lorsqu'une touche est pressée.

Dans ce cas, on utilise getch() pour extraire le code de touche.

Si le code de touche est nul, alors il s'agit d'une touche étendue et on rappelle getch() afin d'extraire le code étendu.

Dans ces 2 cas, on va renvoyer le code de touche comme indiqué ci-dessus avec return.

Pour mettre le code de touche étendu, on utilise l'opérateur de décalage de bits vers la gauche <<.

Si aucune touche n'a été pressée, on récupére « l'heure actuelle » clockAct.

On soustrait alors clockDeb. Si le temps est supérieur au timeout, on sort de la fonction en renvoyant 0.



On peut utiliser le programme de test suivant (On sort quand on appuie sur Q ou Echap:

int main()

{

while(1)

{

long keyOrTm = getch_timeout(CLOCK_TICK);

if( (char)keyOrTm == 'Q' || keyOrTm == 27 )

{

printf( « On Sort ...\n » );

}

else if( keyOrTm != 0)

{

printf( « Code touche : %d\n », keyOrTm

}

else // keyOrTm == 0

{

printf( « Timeout ecoule » );

}

}

return 0;

}


Evolution 1 : Utilisation d'une variable statique en interne

La fonction précédente a un gros inconvénient. Si on appuie sans arrêt sur des touches, on ne sort jamais en timeout.

Modifier la fonction précédente de manière que l'on sorte de la fonction à chaque fois que le timeout est écoulé, indépendamment de l'appui sur une touche.

Indications :

On rend la variable clockDeb statique.

On l'initialise avec clock() uniquement quand elle est nulle.

Chaque fois que le timeout est écoulé, on réinitialise clockDeb à 0.


Evolution 2 : Tableau de touches acceptées

Modifier la fonction précédente afin qu'elle ne réagisse qu'aux touches connues. Ces touches seront communiquées à la fonction à l'aide d'un tableau.

Le nouveau prototype est

long getch_timeout2( clock_t timeout, long touches[], int nbTouches);


Exemple d'utilisation :

// ... Comme précédement

long touches[] = { 27, 'Q' };

int nbtouches =

sizeof( touches) /sizeof(long); // ici, 8 / 4 = 2

long keyOrTm = getch_timeout2(CLOCK_TICK, touches, nbtouches);

// ....



Evolution 2bis : Gestions des touches étendues

Créer des fonctions permettant d'extraire le code étendu, et le code ascii.

unsigned char code_to_char_ascii( long code );

On utilise l'opérateur binaire & pour mettre les 24 bits de poids forts à 0 et ne conserver que les 8 bits de poids faible.


unsigned char code_to_char_etendu( long code );

On utilise l'opérateur binaire >> pour décaler le code de 8 bits vers la droite, puis on procède comme précédemment pour mettre les 24 bits de poids forts à 0 et ne conserver que les 8 bits de poids faible.


Evolution 3 : Tableau de timeout

Afin d'être capable de gérer plusieurs animations fonctionnant à des vitesses différentes, on passe à la fonction un tableau de timeout.

Le prototype est

long getch_timeout2( clock_t timeouts[] , int nbtimeouts, long touches[], int nbtouches);

On utilise en interne un tableau statique de 32 valeurs maximum à la place de clockDeb.

Le fonctionnement est exactement le même. On doit maintenant boucler sur ce tableau et trouver si le timeout est écoulé pour l'un des éléments. (On suppose que tous les timeouts sont différents. Si ce n'est pas le cas, on ne s'occupe que du premier rencontré. Dans tous les cas, on ne s'occupe que d'un timeout à la fois).

Valeur renvoyée :

On utilise les bits 16 à 23 pour stocker le numéro de timeout qui correspond à l'index du tableau pour lequel le timeout est écoulé (soit de 0 à 31)


Evolution 3bis : Extraction de l'index

On procède comme en 2bis pour créer la fonction

unsigned char code_to_index_timeout( long code );




Fonctions d'affichage

Le but est de créer des outils réutilisables dans les applications.


Affichage d'un menu en bas d'écran

Créer une fonction void affiche_menu( char * tabmenus[], int nbmenus )

Arguments :


Afin d'indiquer à l'utilisateur quelle touche il doit presser, on mettra pour chaque libellé la première lettre majuscule rencontrée en rouge, les autres lettres étant affichées en noir sur fond gris.


Affichage d'une fenêtre avec ombrage

Cette fonction peut être utilisée dans les fonctions suivantes.

void affiche_ombre( int x, int y, int largeur, int hauteur)

Explications détaillées à venir ...

Affichage d'un titre dans une fenêtre

void affiche_titre( int y, const char * titre )

Explications détaillées à venir ...



Affichage du fond avec les caractères semi graphiques

void affiche_fond( char c, int color )

Explications détaillées à venir ...



Affichage d'un tableau dans une fenêtre



struct entete_infos

{

char ** titres_colonne;

int nbcolonnes;

};


struct ligne_infos

{

char ** valeurs_cellules;

int nbcellules

};


struct tableau_infos

{

ligne_infos * tabligneinfos;

int nblignes;

};

void affiche_tableau( entete_infos ei, tableau_infos ti );

Explications détaillées à venir ...



Affichage d'une fenêtre de saisie générique

struct saisie_infos

{

char libelle[20];

char valeur[20];

};

void fenetre_saisie( saisie_infos si[], int nbsi );

Explications détaillées à venir ...