Package Ada pour mise en forme d’écran/console

Ada et les commandes d’échappement ANSI

Présentation…

Il n’existe pas de paquet ( « package » ) standard Ada pour des opérations d’écran telles que l’effacement de l’écran, le déplacement du curseur, la mise en couleur de l’affichage des caractères, etc. Il serait souhaitable qu’une telle librairie existe, et que ses caractéristiques et son implémentation la fasse être standard. C’est ce que vous propose le Site des Hiboux, avec cette solution basée sur une norme parfaitement standard et bien implantée sur toutes les consoles de tous les systèmes : les commandes d’échappement ANSI.

Avant-propos

La norme en informatique est depuis longtemps d’utiliser des interfaces en mode graphique. Cependant les interfaces en mode texte on l’avantage d’être infiniment plus portables et beaucoup moins gourmandes en ressources. Malheureusement, les applications fonctionnant en mode texte évoquent presque systématiquement d’austères interfaces en ligne de commande. Cette page et ce package sont donc accompagnées du vœux d’encourager les développeur(se)s à démontrer que les interfaces textes peuvent être de bonnes interfaces, utiles et utilisables, légères et ergonomiques.

Si vous êtes pressé(e)s, vous pouvez passez directement à la deuxième moitié de la page, là où se trouvent le fichiers de spécification et le fichier d’implémentation. Les remarques et astuces au sujet de l’utilisation de ce paquet sont également données dans le fichier de spécification.

Un petit programme simple de test et d’exemple d’utilisation de ce paquet peut être obtenu sur cette page : Un programme d’exemple d’utilisation de « ANSI_Console » .

Ce paquet se veut aussi rendre service aux débutant(e)s en Ada, afin de faciliter l’acquisition de bon souvenirs des premières expériences avec ce langage. Avoir à sa disposition un paquet permettant de faire de belles sorties d’écran, laissera sûrement de bons souvenirs et stimulera beaucoup d’entre vous ( mais n’oubliez pas qu’on peut aussi aller loin avec des applications en mode texte, et que ce n’est pas réservé au débutant-e-s ). À ce titre, cette page contient des commentaires qui paraîtront surprenants aux habitué(e)s, qui seront utiles aux apprenant(e)s. Je souhaite que les codes et les explications soient assez bien faites pour au moins ne pas donner de mauvais exemples. Mais ce paquet n’est pas non-plus un cas d’école, et on y trouvera donc pas nécessairement des questions qui intéressent des étudiant(e)s au prime abord. Ce qui n’enlève rien à son intérêt, je le souhaite.

Pour toutes questions ou commentaires, n’hésitez pas à passer par la page de commentaire du site  ( les commentaires ne sont pas archivés sur le site et restent privés ).

Que sont et à quoi servent les commandes d’échappement ANSI

Vous connaissez tous/toutes le jeux de caractères ANSI ainsi que les caractères de commandes de 0 à 31. Ces caractères de commande correspondent aux fameux CR Carriage Return ), LF Line Feed ), la tabulation, et d’autres encore dont le sens s’est le plus souvent fait oublié. Mais ce ne sont pas ces commandes qui permettront des opérations avancées sur les écrans texte ( les consoles ).

Parmi ces commandes, il en existe une qui ouvre la porte à d’autres commandes. La commande 27, dite commande d’échappement, permet d’autres codes de commandes que ceux de 0 à 31. Cette commande d’échappement a été conçue pour permettre l’usage de chaînes de commande ( des chaînes de caractères commandant des instructions supplémentaires ) à définir selon les systèmes. Rien de standard n’était prévu, et il est vrai que cette commande d’échappement permet toujours d’exécuter des commandes spécifiques à certains systèmes. Toutes-fois, par bonheur, une série de commandes tellement utiles qu’elles se sont répandue sur tous les systèmes, s’est vu attribuer le statut de standard.

Ces commandes se présentent sous la forme d’une chaîne de caractères. On enverra cette chaîne de commande sur le terminal ( écran ou console ), exactement de la même manière que l’on enverrait un chaîne de texte à afficher. Pour que cette chaîne soit effectivement interprétée comme une chaîne de commande, on enverra seulement tout d’abord le code de la commande d’échappement, c’est à dire le code 27.

L’utilisation de ces commandes ne demande rien de plus que les opérations habituelles de sortie de caractères. Mais notez bien qu’elle n’ont de sens que si l’envoie des caractères se fait vers un terminal, cela va de soit. On pourra tout de même, cela aura du sens, les écrire dans un fichier si ce fichier est à terme destiné à être envoyé vers la console. Avec un peu d’imagination, vous comprendrez l’intérêt potentiel de cette astuce pour certaines applications.

La référence des commande d’échappement

Vous pourrez trouver deux références des commandes d’échappement ANSInote 1 ] : ANSI escape codes ( informel )  ou encore ANSI escape codes ( complet, mais informel ) . La première référence, la plus simple, est la plus recommandée, car correspondant mieux à la réalité concrète des terminaux. La plupart des terminaux ne reconnaissent en effet pas toutes les commandes ANSI. Le première est également plus lisible.

En lisant cette référence, faites attention à distinguer les caractères faisant partie des chaînes de commande, et le texte indiquant les paramètres sous forme symbolique, car il ne sont pas distingués. Un exemple vous en dira plus. Là ou il est dit que « ESC[PnA » est la commande permettant de déplacer le curseur vers le haut, il faut comprendre que « Pn » doit être remplacé par un valeur numérique. Pour déplacer le curseur de 2 caractères vers le haut, on émettra donc la commande « ESC[2A ». La forme symbolique des paramètres vous est donnez en haut de page, et elle est toujours sur deux lettres, la première étant toujours la lettre « P ». Remarquez bien qu’on écrit pas la valeur numérique ( octet ) dans le flux texte, mais qu’on écrit la valeur en chiffres. Ce qui est normal, puisque l’on envoie les commandes sous forme de chaîne. On enverra pas non plus le texte ESC, mais bien le caractère spécial dont le code est 27. L’écriture ESC est donc ici une représentation. En résumé, pour déplacer le curseur de deux positions vers le haut, on enverra sur le terminal, tout d’abord le caractère spécial dont le code est 27, puis immédiatement à sa suite, la chaîne « [2A ». Il est préférable d’envoyer le tout en une seule fois.

S’assurez que le système supporte les commande ANSI

Comme dit précédemment, les commandes ANSI sont implémentées sur tous les systèmes. Mais sous MS-DOS par exemple, elles sont par défaut inactives. Pour les rendre effectives, vous devrez éventuellement ajouter la ligne suivante dans le fichier « config.sys » :

DEVICE=C:\WINDOWS\COMMAND\ANSI.SYS

ou encore sous les vrais ( les anciens ) systèmes MS-DOS ou Windows 3.x :

DEVICE=C:\DOS\ANSI.SYS

La commande « DEVICE » pourra être au choix également remplacée par « DEVICEHIGH » pour charger le pilote en mémoire haute. Cette ligne dans le fichier « config.sys » demande au MS-DOS de charger le pilote ANSI. La commande peut également prendre un paramètre « /R » sur les systèmes équipés pour les handicapé(e)s. Pour plus d’informations sur les fonctions d’accessibilité sous MS-DOS, veuillez consulter la documentation de MS-DOS. Si la commande correspondante ou équivalente n’est pas déjà présente dans le fichier de configuration et que vous l’ajoutez, il vous faudra donc redémarrez pour que la modification prenne effet.

Sous Linux, le pilote ANSI est le plus souvent présent par défaut, mais pas toujours. Il n’y est pas toujours présent sous forme d’un pilote indépendant, mais implémenté en tant que fonctionnalité du gestionnaire de console. Ainsi, cela dépendra du programme avec lequel vous travailler en console. Quand vous travailler en console depuis l’interface graphique, ce programme n’est pas toujours le même que lorsque vous travailler en mode texte, et il se peut donc que les commandes ANSI soient reconnues dans un cas mais pas dans l’autre. A titre d’exemple, le programme Konsole ( la console fournie avec les environnements de bureau Gnome ) reconnaît les commandes ANSI. Les gestionnaire de console de certains systèmes minimalistes ne reconnaissent pas les commandes ANSI.

Pour plus d’informations sur le support des commandes ANSI avec les consoles Linux, référez-vous à l’un ou l’autre des forums dédiés à Linux sur la toile, tel que Guide Linux . Pour information rapide, si dans votre documentation il apparaît qu’une émulation de terminal est compatible VT100 ou VT102 ( plus courant ), alors c’est OK, car ces protocoles sont basés sur ANSI.

Le paquet Ada

Le paquet Ada sera nommé « ANSI_Console ». Le source ici fourni est garanti être compilable avec la compilateur GNAT de AdaCore. Les fichiers de spécification et d’implémentation seront respectivement « ANSI_Console.ads » et « ANSI_Console.adb ».

Choix pour l’interface du paquet

L’interface devra définir l’intégralité des fonctions décrites dans la référence ( informelle ). Ceci ne posera aucun soucis particulier. Les procédures opèrent sur un flux de sortie. Celui-ci peut être soit le flux de sortie standard, soit un autre flux ouvert pour l’occasion. Il y aura donc deux jeux de procédures identiques : l’une sans paramètre de flux, et agissant sur le flux d’E/S standard, et l’autre prenant un paramètre de flux.

Pour plus de consistance, un type « Stream_Type » sera défini dans la spécification, et celui ci sera l’importation du type de flux de la librairie standard d’Ada. Ce type sera précisément le type « Ada.Text_IO.File_Type » ( un type fichier, certes, mais perçu par le paquet comme un flux ).

Il existe dans la librairie standard d’Ada, deux versions de flux texte : l’une pour les caractères standards ( dit ANSI, justement ), et l’autre pour les flux adaptés à Unicode ( remarquez au passage que le type « Wide_Character » ne peut en fait contenir que les caractères du BMP d’Unicode, et ne permet donc pas de représenter tout Unicode ). Mais comme rien ne semble démontrer que les commandes d’échappement ANSI fonctionnent avec les flux Unicode, c’est à dire sur les consoles Unicode, il n’y aura pas de version dédiée aux affichages Unicode.

Les paramètres symboliques décrits en introduction de la référence devront êtres définis et précisés dans l’interface.

  • « Pn » : paramètre numérique sans contrainte particulière. Il apparaît que ce type de paramètre n’est utilisé que dans les commandes de mouvement du curseur. Un type spécifique sera donc créé.
  • « Ps » : code de fonction. Un type énuméré sera le bienvenue ici.
  • « PL » : numéro de ligne. À priori, on pourrait penser que ce type pourrait être implémenté par un « Natural », sans autres contraintes. La référence défini les résolutions d’écran reconnues par les commandes ANSI, mais dans la réalité d’autres résolutions son possibles, et il serait mal venu de donner une contrainte arbitraire. Mais si une limite était clairement défini, alors ce type pourrait être contraint. Pour permettre l’éventuelle mise à jour de la spécification dans ce sens, tout en préservant la compatibilité des codes qui auront éventuellement été basé sur ce paquet, un sous-type de « Natural » sera défini, contraint à l’intervalle de 1 à 1024 ( ce qui devrait être suffisant ). ANSI attribut le numéro 0 à la première ligne. Mais il sera plus commode de lui donner le numéro 1 ( c’est l’usage le plus répandu avec les librairies textes ). L’implémentation se chargera de corriger.
  • « Pc » : numéro de colonne. Mêmes commentaires que pour « PL ».

Comme les deux jeux de constantes de couleur définies pour la couleur d’avant plan et d’avant plan comprennent les mêmes nom de couleurs, mais diffèrent seulement par leur codes, il n’y aura qu’un seul type couleur ( la question du codage ne doit pas apparaître dans l’interface publique ).

Avec ANSI, les modes graphiques, les modes de texte, et les couleurs d’avant et arrière plan sont prises en charge par une seule chaîne de commande, qui peut fixer un ou plusieurs de ces aspect en même temps. Dans ce paquet, cela fera l’objet d’autant de procédure différentes. Cette solution est préférable à celle d’avoir une seule fonction à plusieurs paramètres pour laquelle il faudrait ajouter pour chaque paramètre, un valeur énumérée spéciale désignant que le paramètre actuellement actif doit rester inchangé. Cette solution ferait un peu parasitage, et la simplification est une bonne chose.

Le mode graphique numéro 7 a une fonction particulière : il sert à basculer l’état Enable line wrapping. Cette fonctionnalité n’a pas sa place dans une fonction fixant le mode graphique, et a donc encore moins sa place dans des constantes de mode graphique. Cette fonctionnalité fera donc l’objet d’une procédure individuelle, l’une pour autoriser le Wrapping, et l’autre pour le désactiver. D’ailleurs ce mode numéro 7 fonctionne différemment avec Set mode et Reset Mode. Ceci justifie encore plus de déplacer l’effet de ce pseudo mode vers deux procédures spécifiques.

Pour la commande d’affection des touches à une chaîne de caractères, plutôt que de créer une valeur énumérée pour toutes les combinaisons, deux types énumérés sont créés. Le premier énumère les touches, et le deuxième énumère l’état de la touche auxiliaire Crtl, Shift, etc ). Ceci permet de réduire le nombre de constante ( tout comme on distingue les nombres et les chiffres ), et permet une meilleur expressivité des textes sources utilisant ce paquet.

Certaines combinaisons de touches ne sont pas autorisé par ANSI. Une exception est donc définie. Les applications devrait donc être conçues de manière à ne pas utiliser ces combinaisons illégales. Mais pour ce donner une chance de ne pas commettre d’erreur à l’exécution, il serait bon d’avoir une fonction qui teste si une combinaison de touches données est valide ou pas. Cette fonction pourrait être utile dans le cas d’une application permettant à l’utilisateur de définir lui même ses combinaisons. L’application pourrait alors s’assurer de la validité de la combinaison, et signaler les impossibilités à l’utilisateur(rice).

Il était tentant d’appliquer des clauses de représentation aux types énumérés… mais c’est inutile, car cela ne permet pas récupérer le code correspondant au niveau d’Ada. L’usage de constantes à valeurs privées a été envisagé, mais l’utilisation de constantes énumérées se montre être une meilleure interface ( plus nette aussi ) : on imagine bien par exemple une application énumérer les résolutions d’écran disponibles.

Certaines séquences de caractères sont à interpréter de manière particulière. Cela est dut au codage employé pour les touches ne représentant pas des caractères, comme les touches de fonctions F1, F2, etc. ), les touches de curseurs… Une procédure de lecture des touches est donc fournis.

Il existe un caractère dont l’émission produit un effet particulier : le code ASCII numéro 7, qui produit un beep. Un procédure d’émission de ce caractère est ajoutée par convenance.

La gestion du clavier est assez complexe ( ce qui est normal pour une interface ou la clavier est le seul organe de contrôle ), et souffre d’interférence avec le système dessous MS-DOS, Windows, BSD, etc. ). La fonction « Get_Key » ne renvoie jamais un code de touche pour les caractères imprimables en dehors des lettres et chiffres. Cette restriction apporte plus de cohérence et de stabilité au travers de tous les claviers. De plus, il est conseillé de n’utiliser les touches modifiantes Alt, Ctrl et Shift ), seulement qu’avec les touche de commandes F1 à F12, Insert, Home, Page up, Del, End, Page down, et touches de curseurs ). Le bon fonctionnement des autres combinaisons de touches n’est pas garantie. Notez aussi que les touches du pavé numérique avec Num lock activé ne se distinguent parfois pas des autres touches de commandes ( cela peut dépendre des systèmes ). Il ne faudra donc pas, dans les applications, attacher une trop grand importance à la distinction entre les touches de commande habituelles et celles du pavé numérique.

Certaines combinaison de touches pouvant êtres assignées, ne sont pas nécessairement reconnu sans assignation ; par exemple les combinaisons Alt+X ne sont pas reconnues pour elles-mêmes, si elles n’ont pas été assignées. Néanmoins, les touches de fonctions et de commandes le sont toujours. Raison de plus donc pour préférer l’usage de celles-ci.

N’oubliez pas que l’assignation de touches influe sur la reconnaissance des touches par la fonction « Get_Key ». Il est préférable donc d’assigner les touches de manière à ce qu’elle renvoie des chaînes de caractères imprimables, ce qui offre la meilleur garantie de fonctionnement en minimisant les interférences de bas niveaux.

Pour y pallier, il est également possible de normaliser l’assignation des touches. Une fonction propre à ce paquet sera mise en œuvre à l’avenir, qui sera destiné à normaliser l’assignation de touches destinées à correspondre à des commandes plutôt qu’à des chaînes de texte. Cette stratégie de normalisation sera propre à ce paquet, et n’est pas défini par ANSI ( mais ne sera pas incompatible non-plus avec ANSI… car ANSI ne dit simplement rien à ce sujet ). Cette nouvelle fonctionnalité sera ajoutée à « Get_Key », et préservera la compatibilité du code utilisant ce paquet. À cette occasion, un didacticiel complet sur l’emploie du clavier se mis en ligne. Comme le sujet peut sembler complexe, un didacticiel simplifié sera également publié, permettant le développement rapide d’applications, sans avoir à passer trop de temps sur la question ( ce qui sera utile par exemple aux étudiant(e)s en Ada ).

Remarques et astuces

  • L’effacement de l’écran correspond en fait au remplissage de l’écran avec des blanc qui auront donc la couleur de fond active au moment de l’appel. Si la couleur active est le jaune, un effacement de l’écran effacera donc l’écran en le rendant tout jaune.
  • L’effacement de l’écran employant la couleur de fond, les applications devraient commencer par définir cette couleur au moment de leur initialisation.
  • L’attribut de texte gras est en fait affiché comme surbrillance ( couleur claire ) sur la plupart des écrans. Comme il est préférable que le texte soit clair sur fond moins clair, les applications devraient probablement toujours donner l’attribut gras à tous les textes. Il en va inversement avec l’attribut de texte non-gras, qui est affiché en couleur sombre ou pâle sur la plupart des consoles.
  • Une sortie de texte ( en dehors des émissions de commandes ANSI ) peut, si le texte amène le curseur en fin de ligne, finalement amener le curseur à la ligne suivante. Les applications employant se paquet devront prévoir ce fait. La désactivation du Line wrapping ( fonction fournie dans ce paquet ), permet de l’éviter d’une autre manière.
  • Dans la suite de la remarque précédente, si le curseur arrive en fin de ligne, alors qu’il est sur la dernière ligne de l’écran, alors un défilement de l’écran pourra se produire. En dehors de toute certitude à ce sujet, l’application devra donc éviter de faire des affichage sur la position inférieure-droite.. et même pour être plus consistante, elle pourra même en fait ne pas produire d’affichage sur la dernière ligne ( sauf à bien le gérer ). Certain système permettent d’empêcher le défilement de l’écran, mais ces méthodes ne font pas partie des commandes ANSI.
  • Ce paquet est ré-entrant, et il est donc sûre pour le multitâche.

Texte source de l’interface du paquet

Voici le contenu du fichier « ANSI_Console.ads »  ( cliquez sur le lien pour télécharger ).

                -- Hint : tabulation size is 3
  
                with Ada.Text_IO;
  
                package ANSI_Console
                -- ----------------------------------------------------------------------------
                -- High Level Text Mode Screen and Console Output.
                -- Also Provide Keystroke Assignement.
                -- ----------------------------------------------------------------------------
                -- This package provide access to high level output to text mode screen
                -- and console. It allows you to set cursor position, text color, erase
                -- screen, and other useful procedures of the like. Enable to assign keystroke
                -- to string : i.e. when the specified keystroke occur, the corresponding
                -- string is recieved on the standard input (to be used with care).
                --
                -- It interfaces all ANSI escapement commands. Symbolic types defined in
                -- the ANSI standard are used to document types definitions founded here.
                -- Procedure names differ from command names found in the ANSI standard.
                -- Generic commande string representations are used to document procedures.
                --
                -- Contact : les-ziboux@rasama.org
                --
                -- To learn further more about this package, you may read the following page :
                -- http://www.les-ziboux.rasama.org/ada-commandes-echappement-ansi.html
                -- Use free of charge as long as the latter link is kept in this file and
                -- given in application credits.
                --
                -- Modified versions are allowed for personal use only and not for distributed
                -- softwares (free of charge or not). Please : send me feed-back for any
                -- request, included suspected bug, request for functionality, suspect wrong
                -- behaviour, and any thing else, and do not distribut modified version.
                --
                -- Saturday, November 25 - 2006 - france (somewhere in europe…)
                -- ----------------------------------------------------------------------------
  
                is
  
                   -- =========================================================================
                   -- Important notes :
                   -- -------------------------------------------------------------------------
                   -- o  Output of text (not of command) that just fit up to
                   --    en of line, may move the cursor to the line below. This
                   --    occur on many systems.
                   -- o  Continuating the previous note, if in the same circumstances, the
                   --    cursor in on the bottom line, the a screen scroll may occur on
                   --    many systems. Applications should care about it, or use a special
                   --    way to avoid this behavior.
                   -- o  As this package is reentrant, it is thread safe.
                   -- o  There is a « Beep » procedure under section of output procedures.
                   -- o  There is a (non-blocking) « Get_Key » procedure under the section
                   --    of input procedures.
                   -- =========================================================================
                   -- Organisation of this specification
                   -- -------------------------------------------------------------------------
                   -- O Screen metrics
                   -- o     Types for screen metrics (screen maximum sizes)
                   -- o     Types for screen positions
                   -- O Keystrokes
                   -- o     Type for normal keys
                   -- o     Type for modifier keys
                   -- O Text output/input and erasing of screen
                   -- o     Type for working on streams other than the standard output.
                   -- o     Simply text output procedures (provided for consistency).
                   -- o     Simply character output procedures (provided for consistency).
                   -- o     Procedure for playing a beep
                   -- o     Simply character input procedures (provided for consistency).
                   -- o     Type for keystroke input
                   -- o     Procedures for keystroke input
                   -- o     Procedures for clearing screen or part of line.
                   -- O Text color and attributes
                   -- o     Type for setting foreground and background text colors
                   -- o     Procedures for setting text color.
                   -- o     Type for setting text attributes
                   -- o     Procedure for setting text attributs (blinking and the like…).
                   -- O Cursor position and movement
                   -- o     Procedure fixing cursor position
                   -- o     Types for making cursor mouvements (deltas).
                   -- o     Procedures moving cursor position
                   -- o     Procedures for saving/restoring cursor position
                   -- O Screen modes (resolution) and output behaviour
                   -- o     Type for setting screen modes (screen resolution)
                   -- o     Procedures for fixing screen mode (screen resolution)
                   -- o     Procedures for fixing screen behaviour (line wrapping)
                   -- O Key assignements
                   -- o     Exception for invalid modifier+key
                   -- o     Procedure for assigning key-stroke to string
  
                   -- =========================================================================
                   -- Screen metrics
                   -- -------------------------------------------------------------------------
  
                   -- Note : screen coordinates are top to down and left to right.
                   -- Note : the upper left corner is (1,1).
  
                   -- Types for screen metrics (screen maximum sizes)
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   Maximum_Screen_Height : constant Positive := 1024;
                   Maximum_Screen_Width  : constant Positive := 1024;
  
                   -- Types for screen positions
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   subtype Vertical_Position_Type   is Positive -- Implements PL
                      range 1..Maximum_Screen_Height;
  
                   subtype Horizontal_Position_Type is Positive -- Implements Pc
                      range 1..Maximum_Screen_Width;
  
                   -- =========================================================================
                   -- Keystrokes
                   -- -------------------------------------------------------------------------
  
                   -- Type for normal keys
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   type Key_Type is ( -- Type for functional keys (those you usualy use)
                      Key_F1,
                      Key_F2,
                      Key_F3,
                      Key_F4,
                      Key_F5,
                      Key_F6,
                      Key_F7,
                      Key_F8,
                      Key_F9,
                      Key_F10,
                      Key_F11,
                      Key_F12,
                      Keypad_Home,
                      Keypad_Up_Arrow,
                      Keypad_Page_Up,
                      Keypad_Left_Arrow,
                      Keypad_Right_Arrow,
                      Keypad_End,
                      Keypad_Down_Arrow,
                      Keypad_Page_Down,
                      Keypad_Insert,
                      Keypad_Delete,
                      Key_Home,
                      Key_Up_Arrow,
                      Key_Page_Up,
                      Key_Left_Arrow,
                      Key_Right_Arrow,
                      Key_End,
                      Key_Down_Arrow,
                      Key_Page_Down,
                      Key_Insert,
                      Key_Delete,
                      Key_Print_Screen,
                      Key_Pause_Break,
                      Key_Escape,
                      Key_Backspace,
                      Key_Enter,
                      Key_Tab,
                      Key_Null,
                      Key_A,
                      Key_B,
                      Key_C,
                      Key_D,
                      Key_E,
                      Key_F,
                      Key_G,
                      Key_H,
                      Key_I,
                      Key_J,
                      Key_K,
                      Key_L,
                      Key_M,
                      Key_N,
                      Key_O,
                      Key_P,
                      Key_Q,
                      Key_R,
                      Key_S,
                      Key_T,
                      Key_U,
                      Key_V,
                      Key_W,
                      Key_X,
                      Key_Y,
                      Key_Z,
                      Key_0,
                      Key_1,
                      Key_2,
                      Key_3,
                      Key_4,
                      Key_5,
                      Key_6,
                      Key_7,
                      Key_8,
                      Key_9,
                      Key_Minus,
                      Key_Equal,
                      Key_Left_Square,
                      Key_Right_Square,
                      Key_Space,
                      Key_Semicolon,
                      Key_Single_Quote,
                      Key_Comma,
                      Key_Dot,
                      Key_Slash,
                      Key_Left_Single_Quote,
                      Keypad_Enter,
                      Keypad_Slash,
                      Keypad_Star,
                      Keypad_Minus,
                      Keypad_Plus,
                      Keypad_Middle); -- 5, in the middle of the numeric keypad
  
                   -- Type for modifier keys
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   type Modifier_Key_Type is ( -- Type for auxiliary keys (the one you
                      No_Modifier_Key,         -- held down while pressing another)
                      Shift_Key,
                      Ctrl_Key,
                      Alt_Key);
  
                   -- =========================================================================
                   -- Text output/input and erasing of screen
                   -- -------------------------------------------------------------------------
  
                   -- Type for working on streams other than the standard output.
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   subtype Stream_Type is Ada.Text_IO.File_Type;
  
                   -- Simply text output procedures (provided for consistency).
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Put (
                      Text   : in String);
  
                   procedure Put (
                      Stream : in Stream_Type;
                      Text   : in String);
  
                   procedure Put (
                      Line   : in Vertical_Position_Type;
                      Column : in Horizontal_Position_Type;
                      Text   : in String);
  
                   procedure Put (
                      Stream : in Stream_Type;
                      Line   : in Vertical_Position_Type;
                      Column : in Horizontal_Position_Type;
                      Text   : in String);
  
                   -- Simply character output procedures (provided for consistency).
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Put (
                      C : in Character);
  
                   procedure Put (
                      Stream : in Stream_Type;
                      C      : in Character);
  
                   procedure Put (
                      Line   : in Vertical_Position_Type;
                      Column : in Horizontal_Position_Type;
                      C      : in Character);
  
                   procedure Put (
                      Stream : in Stream_Type;
                      Line   : in Vertical_Position_Type;
                      Column : in Horizontal_Position_Type;
                      C      : in Character);
  
                   -- Procedure for playing a beep
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Beep; -- Added for convenience - See note below
  
                   procedure Beep (Stream : in Stream_Type);
  
                   -- Note : with console under some modern desktop environements, like
                   -- Windows, the beep function may play the system altert sound instead of a
                   -- beep with the computer speaker.
  
                   -- Simply character input procedures (provided for consistency).
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   -- See notes below about Get procedures
  
                   procedure Get (
                      C : out Character);
  
                   procedure Get ( -- Non-blocking character input.
                      C         : out Character;
                      Available : out Boolean);
  
                   procedure Get (
                      Stream : in Stream_Type;
                      C      : out Character);
  
                   procedure Get ( -- Non-blocking character input.
                      Stream    : in Stream_Type;
                      C         : out Character;
                      Available : out Boolean);
  
                   -- Type for keystroke input
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   type Keystroke_Input_Type is
                   record
                      Key                 : Key_Type;
                      Modifier_Key        : Modifier_Key_Type;
                      C                   : Character;
                      Key_Available       : Boolean;
                      Character_Available : Boolean;
                   end record;
  
                   -- Procedures for keystroke input
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Get_Key ( -- Non-blocking key input - See note below
                      Keystroke_Input : out Keystroke_Input_Type);
  
                   procedure Get_Key (
                      Stream          : in Stream_Type;
                      Keystroke_Input : out Keystroke_Input_Type);
  
                   -- Notes
                   -- -------------------------------------------------------------------------
                   -- Some keystroke only have a specific code. See the list below, of
                   -- recognize keystrokes. Unfortunatly, Ctrl+PageUp has the same code
                   -- as F12. So when you hit Ctrl+PageUp, it appears as F12. There is
                   -- no work around. In general, Key F11 and F12 are not well supported
                   -- by ANSI (multiplicity of codes or ambiguity with some other codes).
                   --
                   -- Get can return special character code, meaning complex keystroke,
                   -- so it is suggested to use Get_Key instead of Get. Get_Key translate
                   -- and convert special code automaticaly, so you don't have to worry
                   -- about them. Get_Key allow you too to get character input, and prevent
                   -- you from errorneously getting special code in place of character input.
                   --
                   -- Get_Key is provided for convenience, and may be incomaptible with Get
                   -- (not all the time but in some circumstance). Some complex key, like F1,
                   -- Page-up and so on, a recieved through complex code, made of two
                   -- conscecutives specials character codes. So you easly guess that Get_Key
                   -- is based on Get, and that a missusage of Get may disturbe Get_Key.
                   -- Althought the « normal » way wit ANSI consoles is to call Get, it
                   -- is strongly adviced that you only use Get_Key in your application.
                   --
                   -- Here is the list of recognize keystrokes…
                   --
                   -- Standalones keys (A-Z and 0-1 are not reported in this list, but
                   -- are recognized too).
                   --
                   -- Key_F1
                   -- Key_F2
                   -- Key_F3
                   -- Key_F4
                   -- Key_F5
                   -- Key_F6
                   -- Key_F7
                   -- Key_F8
                   -- Key_F9
                   -- Key_F10
                   -- Key_F11
                   -- Key_F12
                   -- Key_Home
                   -- Key_Up_Arrow
                   -- Key_Page_Up
                   -- Key_Left_Arrow
                   -- Key_Right_Arrow
                   -- Key_End
                   -- Key_Down_Arrow
                   -- Key_Page_Down
                   -- Key_Insert
                   -- Key_Delete
                   -- Key_Backspace
                   -- Key_Tab
                   -- Key_Enter
                   -- Key_Escape
                   -- Key_Space
                   --
                   -- Keypad keys (there may be not distinguisable on some system)
                   --
                   -- Keypad_Home
                   -- Keypad_Up_Arrow
                   -- Keypad_Page_Up
                   -- Keypad_Left_Arrow
                   -- Keypad_Right_Arrow
                   -- Keypad_End
                   -- Keypad_Down_Arrow
                   -- Keypad_Page_Down
                   -- Keypad_Insert
                   -- Keypad_Delete
                   --
                   -- With ALT modifier
                   --
                   -- Alt_Key + Key_F1
                   -- Alt_Key + Key_F2
                   -- Alt_Key + Key_F3
                   -- Alt_Key + Key_F4
                   -- Alt_Key + Key_F5
                   -- Alt_Key + Key_F6
                   -- Alt_Key + Key_F7
                   -- Alt_Key + Key_F8
                   -- Alt_Key + Key_F9
                   -- Alt_Key + Key_F10
                   -- Alt_Key + Key_F11
                   -- Alt_Key + Key_F12
                   -- Alt_Key + Key_Home
                   -- Alt_Key + Key_Up_Arrow
                   -- Alt_Key + Key_Page_Up
                   -- Alt_Key + Key_Left_Arrow
                   -- Alt_Key + Key_Right_Arrow
                   -- Alt_Key + Key_End
                   -- Alt_Key + Key_Down_Arrow
                   -- Alt_Key + Key_Page_Down
                   -- Alt_Key + Key_Insert
                   -- Alt_Key + Key_Delete
                   --
                   -- With CTRL modifier
                   --
                   -- Ctrl_Key + Key_F1
                   -- Ctrl_Key + Key_F2
                   -- Ctrl_Key + Key_F3
                   -- Ctrl_Key + Key_F4
                   -- Ctrl_Key + Key_F5
                   -- Ctrl_Key + Key_F6
                   -- Ctrl_Key + Key_F7
                   -- Ctrl_Key + Key_F8
                   -- Ctrl_Key + Key_F9
                   -- Ctrl_Key + Key_F10
                   -- Ctrl_Key + Key_F11
                   -- Ctrl_Key + Key_F12
                   -- Ctrl_Key + Key_Home
                   -- Ctrl_Key + Key_Up_Arrow
                   -- Ctrl_Key + Key_Left_Arrow
                   -- Ctrl_Key + Key_Right_Arrow
                   -- Ctrl_Key + Key_End
                   -- Ctrl_Key + Key_Down_Arrow
                   -- Ctrl_Key + Key_Page_Down
                   -- Ctrl_Key + Key_Insert
                   -- Ctrl_Key + Key_Delete
                   -- Ctrl_Key + Keypad_Home
                   -- Ctrl_Key + Keypad_Up_Arrow
                   -- Ctrl_Key + Keypad_Page_Up
                   -- Ctrl_Key + Keypad_Left_Arrow
                   -- Ctrl_Key + Keypad_Right_Arrow
                   -- Ctrl_Key + Keypad_End
                   -- Ctrl_Key + Keypad_Down_Arrow
                   -- Ctrl_Key + Keypad_Page_Down
                   -- Ctrl_Key + Keypad_Insert
                   -- Ctrl_Key + Keypad_Delete
                   -- Ctrl_Key + Key_Tab
                   --
                   -- With SHIFT modifier
                   --
                   -- Shift_Key + Key_F1
                   -- Shift_Key + Key_F2
                   -- Shift_Key + Key_F3
                   -- Shift_Key + Key_F4
                   -- Shift_Key + Key_F5
                   -- Shift_Key + Key_F6
                   -- Shift_Key + Key_F7
                   -- Shift_Key + Key_F8
                   -- Shift_Key + Key_F9
                   -- Shift_Key + Key_F10
                   -- Shift_Key + Key_F11
                   -- Shift_Key + Key_F12
  
                   -- Procedures for clearing screen or part of line.
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   -- Note : erasing use the currently active background color.
  
                   procedure Clear_Screen; -- Implements ESC[2J
  
                   procedure Clear_Screen (Stream : in Stream_Type); -- idem
  
                   procedure Clear_From_Cursor_Up_To_End_Of_Line; -- Implements ESC[K
  
                   procedure Clear_From_Cursor_Up_To_End_Of_Line (Stream : in Stream_Type);
  
                   -- =========================================================================
                   -- Text color and attributes
                   -- -------------------------------------------------------------------------
  
                   -- Type for setting foreground and background text colors
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   type Color_Type is ( -- Implements part of Ps
                      Black,
                      Red,
                      Green,
                      Yellow,
                      Blue,
                      Magenta,
                      Cyan,
                      White);
  
                   -- Procedures for setting text color.
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Set_Text_Color ( -- Implements part of ESC[Ps;…;Psm
                      Color : in Color_Type);
  
                   procedure Set_Text_Color ( -- idem
                      Stream : in Stream_Type;
                      Color  : in Color_Type);
  
                   procedure Set_Background_Color ( -- Implements part of ESC[Ps;…;Psm
                      Color : in Color_Type);
  
                   procedure Set_Background_Color ( -- idem
                      Stream : in Stream_Type;
                      Color  : in Color_Type);
  
                   -- Type for setting text attributes
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   type Text_Attributes_Type is ( -- Implements part of Ps
                      Default_Text_Attributes, -- Restore device defaults - See notes below
                      Bold_Text,   -- Displayed as highligthed on most device (reverse of Thin)
                      Thin_Text,         -- Displayed as faint on most device (reverse of Bold)
                      Standout_Text,       -- Don't know what it stand for (without joking)
                      Underlined_Text,     -- Only works on monochrome displays
                      Blinking_Text,       -- See notes below
                      Reversed_Colors,     -- See notes below
                      Hidden_Text,         -- See notes below
                      Normal_Text,         -- Deactivate all attributes
                      Not_Standout_Text,   -- To remove the standout attribute
                      Not_Underlined_Text, -- To remove the Underlined attribute
                      Not_Blinking_Text,   -- To remove the Blinking attribute
                      Not_Reversed_Text);  -- To remove the Reversed attribute
  
                   -- Notes
                   -- -------------------------------------------------------------------------
                   -- Note : Default_Text_Attributes is not a way of disabling currently
                   -- selected text attributes (use Normal_Text to do that). Instead, it
                   -- modified some text attributes on a not normalised way, while possibly
                   -- preserving some others attributes.
                   --
                   -- Note : Blinking_Text displays the text blinking (on real console) of
                   -- course, but also apply thin/faint style. So if you have, say faint
                   -- blue background color, with blue hightligh text, then the text color
                   -- become faint blue, and is not visible. When using blinking attribute,
                   -- text color and background color must have truly different colors in order
                   -- to be visible.
                   --
                   -- Note : Reversed_Colors is to be used with care. On a 16 colors display,
                   -- it may produce invisible text, due to background color becoming the
                   -- same as the text color. Color combination are to be tested before, of
                   -- course.
                   --
                   -- Note : Hidden_Text is not really invisible, but it is a work on the
                   -- background color (which generally become black).
                   -- -------------------------------------------------------------------------
  
                   -- Procedure for setting text attributs (blinking and the like…).
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Set_Text_Attributes ( -- Implements part of ESC[Ps;…;Psm
                      Text_Attributes : in Text_Attributes_Type);
  
                   procedure Set_Text_Attributes ( -- idem
                      Stream          : in Stream_Type;
                      Text_Attributes : in Text_Attributes_Type);
  
                   -- =========================================================================
                   -- Cursor position and movement
                   -- -------------------------------------------------------------------------
  
                   -- Procedure fixing cursor position
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Move_Cursor_To ( -- Implements ESC[PL;PcH  (same as ESC[PL;Pcf)
                      Line   : in Vertical_Position_Type;
                      Column : in Horizontal_Position_Type);
  
                   procedure Move_Cursor_To ( -- idem
                      Stream : in Stream_Type;
                      Line   : in Vertical_Position_Type;
                      Column : in Horizontal_Position_Type);
  
                   -- Types for making cursor mouvements (deltas).
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   subtype Horizontal_Delta_Type is Natural -- Implements Pn
                      range 0..Maximum_Screen_Height - 1;
  
                   subtype Vertical_Delta_Type   is Natural -- Implements Pn
                      range 0..Maximum_Screen_Width - 1;
  
                   -- Procedures moving cursor position
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Move_Cursor_Up ( -- Implements ESC[PnA
                      Count : in Vertical_Delta_Type);
  
                   procedure Move_Cursor_Up ( -- idem
                      Stream : in Stream_Type;
                      Count  : in Vertical_Delta_Type);
  
                   procedure Move_Cursor_Down ( -- Implements ESC[PnB
                      Count : in Vertical_Delta_Type);
  
                   procedure Move_Cursor_Down ( -- idem
                      Stream : in Stream_Type;
                      Count  : in Vertical_Delta_Type);
  
                   procedure Move_Cursor_Right ( -- Implements ESC[PnC
                      Count : in Horizontal_Delta_Type);
  
                   procedure Move_Cursor_Right ( -- idem
                      Stream : in Stream_Type;
                      Count  : in Horizontal_Delta_Type);
  
                   procedure Move_Cursor_Left ( -- Implements ESC[PnD
                      Count : in Horizontal_Delta_Type);
  
                   procedure Move_Cursor_Left ( -- idem
                      Stream : in Stream_Type;
                      Count  : in Horizontal_Delta_Type);
  
                   -- Procedures for saving/restoring cursor position
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Save_Cursor_Position; -- Implements ESC[s
  
                   procedure Save_Cursor_Position (Stream : in Stream_Type); -- idem
  
                   procedure Restore_Cursor_Position; -- Implements ESC[u
  
                   procedure Restore_Cursor_Position (Stream : in Stream_Type); -- idem
  
                   -- =========================================================================
                   -- Screen modes (resolution) and output behaviour
                   -- -------------------------------------------------------------------------
  
                   -- Type for setting screen modes (screen resolution)
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   -- Note that graphic screen stand for text mode based on graphic screen.
  
                   type Screen_Mode_Type is ( -- Implements part of Ps
                      Monochrome_Text_Mode_40x25,      -- monochrome, text
                      Color_Text_Mode_40x25,           -- color     , text
                      Monochrome_Text_Mode_80x25,      -- monochrome, text
                      Color_Text_Mode_80x25,           -- color     , text
                      Color4_Graphic_Mode_320x200,     -- 4 colors  , graphic
                      Monochrome_Graphic_Mode_320x200, -- monochrome, graphic
                      Monochrome_Graphic_Mode_640x200, -- monochrome, graphic
                      Color_Graphic_Mode_320x200,      -- xxx colors, graphic
                      Color16_Graphic_Mode_640x200,    -- 16 colors , graphic
                      Monochrome_Graphic_Mode_640x350, -- monochrome, graphics
                      Color16_Graphic_Mode_640x350,    -- 16 colors , graphic
                      Monochrome_Graphic_Mode_640x480, -- monochrome, graphic
                      Color16_Graphic_Mode_640x480,    -- 16 colors , graphic
                      Color256_Graphic_Mode_320x200);  -- 256 colors, graphic
  
                   -- Procedures for fixing screen mode (screen resolution)
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Set_Screen_Mode ( -- Implements part of ESC[=Psh
                      Screen_Mode : in Screen_Mode_Type);
  
                   procedure Set_Screen_Mode ( -- idem
                      Stream      : in Stream_Type;
                      Screen_Mode : in Screen_Mode_Type);
  
                   procedure Reset_Screen_Mode ( -- Implements ESC[=Psl
                      Screen_Mode : in Screen_Mode_Type);
  
                   procedure Reset_Screen_Mode ( -- idem
                      Stream      : in Stream_Type;
                      Screen_Mode : in Screen_Mode_Type);
  
                   -- Procedures for fixing screen behaviour (line wrapping)
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Enable_Line_Wrapping; -- Implements part of ESC[=Psh
  
                   procedure Enable_Line_Wrapping (Stream : in Stream_Type); -- idem
  
                   procedure Disable_Line_Wrapping; -- Implements part of ESC[=Psh
  
                   procedure Disable_Line_Wrapping (Stream : in Stream_Type); -- ideù
  
                   -- =========================================================================
                   -- Keystroke assignements
                   -- ------------------------------------------------------------------------
  
                   -- Exception for invalid modifier+key
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   Illegal_Keystroke : exception; -- May be raised by Assign_Keystroke
  
                   -- Procedure for assigning key-stroke to string
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   -- Warning : there is no undo nor reset applying to this functionality.
  
                   -- Be careful that some keystrokes are illegal.
  
                   -- Be sure that application only use legal keystroke, or
                   -- check it with this function (may be useful for interactive keystroke
                   -- assignment from user).
  
                   function Legal_Keystroke (
                      Key          : in Key_Type;
                      Modifier_Key : in Modifier_Key_Type)
                   return Boolean;
  
                   procedure Assign_Keystroke ( -- Implements ESC[code;string;…p
                      Key          : in Key_Type;
                      Modifier_Key : in Modifier_Key_Type;
                      Substitution : in String);
  
                   procedure Assign_Keystroke ( -- idem
                      Stream       : in Stream_Type;
                      Key          : in Key_Type;
                      Modifier_Key : in Modifier_Key_Type;
                      Substitution : in String);
  
                end ANSI_Console;
  
  
  
  
  
          
         
        

Commentaires sur l’implémentation

Il n’est pas nécessaire de documenter l’implémentation ici, car le fichier contient tous les commentaires nécessaires. Il est plus aisé de mettre beaucoup de commentaire dans une fichier d’implémentation que dans un fichier de spécification, car les commentaires concernant les choix effectués lors de la conception de la spécification n’ont pas lieu de venir encombrer la spécification ( surtout lorsqu’il est question de solution envisagé, puis abandonnée… ) c’est inutile pour l’utilisateur(rice) qui ne montre pas un intérêt explicite pour ces questions. Dans un fichier d’implémentation, il en va tout autrement, puisque c’est bien le lieu ou les commentaires, même ceux discutant de solutions envisagées puis éludées, ne sont pas de trop.

Texte source de l’implémentation du paquet

Voici le contenu du fichier « ANSI_Console.adb »  ( cliquez sur le lien pour télécharger ).

                -- Hint : tabulation size is 3
  
                with Ada.Text_IO;
  
                package body ANSI_Console
                -- ----------------------------------------------------------------------------
                -- High Level Text Mode Screen and Console Output.
                -- Also Provide Keystroke Assignement.
                --
                -- Please : be sure your have read the specification before you read
                -- the implementation.
                --
                -- Saturday, November 25 - 2006 - france (somewhere in europe…)
                -- ----------------------------------------------------------------------------
                -- Contact : les-ziboux@rasama.org
                --
                -- To learn further more about this package, you may read the following page :
                -- http://www.les-ziboux.rasama.org/ada-commandes-echappement-ansi.html
                -- Use free of charge as long as the latter link is kept in this file and
                -- given in application credits.
                --
                -- Modified versions are allowed for personal use only and not for distributed
                -- softwares (free of charge or not). Please : send me feed-back for any
                -- request, included suspected bug, request for functionality, suspect wrong
                -- behaviour, and any thing else, and do not distribut modified version.
                --
                -- Saturday, November 25 - 2006 - france (somewhere in europe…)
                -- ----------------------------------------------------------------------------
  
                is
  
                   -- =========================================================================
                   -- Important notes :
                   -- -------------------------------------------------------------------------
                   -- o  This implementation depends on values of
                   --    Maximum_Screen_Height and Maximum_Screen_Width. From those value,
                   --    is deduced the maximum string length represented the corresponding
                   --    value in decimal. Actualy, with this implementation, maximum length
                   --    of both is 4. And maximum length for other decimal strings is 2. So
                   --    the longest is 4.
                   -- o  Output is first prepared in a small buffer, before being sent to
                   --    the output stream. Buffers are local to procedures, so tis way
                   --    the package is reentrant.
  
                   -- =========================================================================
                   -- Organisation of this implementation
                   -- -------------------------------------------------------------------------
                   -- O Command buffer
                   -- o     Type and constantes for buffer size
                   -- o     Type for buffer content
                   -- o     Buffer
                   -- o     Buffer initialisation and appending
                   -- o     Procedures to send the buffer content to the output stream
                   -- O Text output and erasing of screen
                   -- o     Simply text output procedures (provided for consistency).
                   -- o     Simply character output procedures (provided for consistency).
                   -- o     Simply character input procedures (provided for consistency).
                   -- o     Procedures for clearing screen or part of line.
                   -- O Text color and attributes
                   -- o     Procedures for setting text color.
                   -- o     Procedure for setting text attributs (blinking and the like…).
                   -- O Cursor position and movement
                   -- o     Procedure fixing cursor position
                   -- o     Procedures moving cursor position
                   -- o     Procedures for saving/restoring cursor position
                   -- O Screen modes (resolution) and output behaviour
                   -- o     Procedures for fixing screen mode (screen resolution)
                   -- o     Procedures for fixing screen behaviour (line wrapping)
                   -- O Keystroke assignements
                   -- o     Function for keystroke string code
                   -- o     Procedure for assigning key-stroke to string
  
                   -- =========================================================================
                   -- Command buffer
                   -- -------------------------------------------------------------------------
  
                   -- Type and constantes for buffer size
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   -- Maximum buffered string length is 12 (see length details in each
                   -- procedure).
                   Maximum_Buffered_Length : constant Positive := 12;
  
                   subtype Buffer_Count_Type is Natural range 0..Maximum_Buffered_Length;
  
                   subtype Buffer_Index_Type is Buffer_Count_Type
                      range 1..Buffer_Count_Type'Last;
  
                   -- Type for buffer content
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   subtype Buffer_Content_Type is String (Buffer_Index_Type);
  
                   -- Buffer
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   type Buffer_Type is
                   record
                      Count   : Buffer_Count_Type := 0; -- Always initialy empty.
                      Content : Buffer_Content_Type;
                   end record;
  
                   -- Buffer initialisation and appending
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Start (Buffer : out Buffer_Type)
                   is
                   begin
                      Buffer.Count := 2;
                      Buffer.Content (1) := Character'Val (27);
                      Buffer.Content (2) := '[';
                   end;
  
                   procedure Append (Buffer : in out Buffer_Type; C : in Character)
                   is
                   begin
                      Buffer.Count := Buffer.Count + 1;
                      Buffer.Content (Buffer.Count) := C;
                   end;
  
                   procedure Append (Buffer : in out Buffer_Type; S : in String)
                   is
                      i : Buffer_Index_Type;
                      j : Buffer_Index_Type;
                   begin
                      i := Buffer.Count + 1;
                      j := Buffer.Count + S'Length; -- i.e. same as (i - 1) + S'Length
                      Buffer.Content (i..j) := S;
                      Buffer.Count := Buffer.Count + S'Length;
                   end;
  
                   procedure Append (Buffer : in out Buffer_Type; N : in Natural)
                   is
                      E : Natural; -- Expression - to work on a copy of N.
                   begin
                      -- The fastest code…
                      -- 48 is the ASCII code for the character '0' (zero).
                      if N <= 9 then
                         Buffer.Count := Buffer.Count + 1;
                         Buffer.Content (Buffer.Count) := Character'Val (48 + N);
                      elsif N <= 99 then
                         Buffer.Content (Buffer.Count + 1) := Character'Val (48 + N / 10);
                         Buffer.Content (Buffer.Count + 2) := Character'Val (48 + N rem 10);
                         Buffer.Count := Buffer.Count + 2;
                      elsif N <= 999 then
                         E := N;
                         Buffer.Content (Buffer.Count + 3) := Character'Val (48 + E rem 10);
                         E := E / 10;
                         Buffer.Content (Buffer.Count + 2) := Character'Val (48 + E rem 10);
                         Buffer.Content (Buffer.Count + 1) := Character'Val (48 + E / 10);
                         Buffer.Count := Buffer.Count + 3;
                      else
                         E := N;
                         Buffer.Content (Buffer.Count + 4) := Character'Val (48 + E rem 10);
                         E := E / 10;
                         Buffer.Content (Buffer.Count + 3) := Character'Val (48 + E rem 10);
                         E := E / 10;
                         Buffer.Content (Buffer.Count + 2) := Character'Val (48 + E rem 10);
                         Buffer.Content (Buffer.Count + 1) := Character'Val (48 + E / 10);
                         Buffer.Count := Buffer.Count + 4;
                      end if;
                   end;
  
                   -- Procedures to send the buffer content to the output stream
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   -- Constant command strings are sent directly using Put_Command_String,
                   -- bypassing Put via Buffer.
  
                   procedure Put_Command_String (S : in String) renames Ada.Text_IO.Put;
  
                   procedure Put_Command_String (
                      Stream : in Stream_Type;
                      S      : in String)
                   renames Ada.Text_IO.Put;
  
                   procedure Put (Buffer : in Buffer_Type)
                   is
                   begin
                      Put_Command_String (Buffer.Content (Buffer.Content'First..Buffer.Count));
                   end;
  
                   procedure Put (Stream : in Stream_Type; Buffer : in Buffer_Type)
                   is
                   begin
                      Put_Command_String (
                         Stream,
                         Buffer.Content (Buffer.Content'First..Buffer.Count));
                   end;
  
                   -- =========================================================================
                   -- Text output and erasing of screen
                   -- -------------------------------------------------------------------------
  
                   -- Simply text output procedures (provided for consistency).
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Put (Text : in String) renames Ada.Text_IO.Put;
  
                   procedure Put (
                      Stream : in Stream_Type;
                      Text   : in String)
                   renames Ada.Text_IO.Put;
  
                   procedure Put (
                      Line   : in Vertical_Position_Type;
                      Column : in Horizontal_Position_Type;
                      Text   : in String)
                   is
                   begin
                      Move_Cursor_To (Line, Column);
                      Ada.Text_IO.Put (Text);
                   end;
  
                   procedure Put (
                      Stream : in Stream_Type;
                      Line   : in Vertical_Position_Type;
                      Column : in Horizontal_Position_Type;
                      Text   : in String)
                   is
                   begin
                      Move_Cursor_To (Line, Column);
                      Ada.Text_IO.Put (Stream, Text);
                   end;
  
                   -- Simply character output procedures (provided for consistency).
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Put (C : in Character) renames Ada.Text_IO.Put;
  
                   procedure Put (
                      Stream : in Stream_Type;
                      C      : in Character)
                   renames Ada.Text_IO.Put;
  
                   procedure Put (
                      Line   : in Vertical_Position_Type;
                      Column : in Horizontal_Position_Type;
                      C      : in Character)
                   is
                   begin
                      Move_Cursor_To (Line, Column);
                      Ada.Text_IO.Put (C);
                   end;
  
                   procedure Put (
                      Stream : in Stream_Type;
                      Line   : in Vertical_Position_Type;
                      Column : in Horizontal_Position_Type;
                      C      : in Character)
                   is
                   begin
                      Move_Cursor_To (Line, Column);
                      Ada.Text_IO.Put (Stream, C);
                   end;
  
                   procedure Beep is
                   begin
                      Put (Character'Val(7));
                   end;
  
                   procedure Beep (Stream : in Stream_Type) is
                   begin
                      Put (Stream, Character'Val(7));
                   end;
  
                   -- Simply character input procedures (provided for consistency).
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                   procedure Get (C : out Character) renames Ada.Text_IO.Get;
  
                   procedure Get (
                      Stream : in Stream_Type;
                      C      : out Character)
                   renames Ada.Text_IO.Get;
  
                   procedure Get ( -- Non-blocking character input.
                      C         : out Character;
                      Available : out Boolean)
                   renames Ada.Text_IO.Get_Immediate;
  
                   procedure Get ( -- Non-blocking character input.
                      Stream    : in Stream_Type;
                      C         : out Character;
                      Available : out Boolean)
                   renames Ada.Text_IO.Get_Immediate;
  
                   procedure Decode_Key_With_Prefix_0 (
                      Input        : in Character;
                      Key          : out Key_Type;
                      Modifier_Key : out Modifier_Key_Type;
                      Ok           : out Boolean)
                   is
                   begin
                      -- This line factorised here
                      Ok := True;
                      -- Start of job
                      case Character'Pos(Input) is
                      -- Codes indicating no modifier key
                      when  59 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F1;
                      when  60 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F2;
                      when  61 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F3;
                      when  62 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F4;
                      when  63 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F5;
                      when  64 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F6;
                      when  65 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F7;
                      when  66 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F8;
                      when  67 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F9;
                      when  68 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F10;
                      when  71 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Keypad_Home;
                      when  72 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Keypad_Up_Arrow;
                      when  73 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Keypad_Page_Up;
                      when  75 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Keypad_Left_Arrow;
                      when  77 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Keypad_Right_Arrow;
                      when  79 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Keypad_End;
                      when  80 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Keypad_Down_Arrow;
                      when  81 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Keypad_Page_Down;
                      when  82 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Keypad_Insert;
                      when  83 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Keypad_Delete;
                      -- This two ones normally start with prefix 224,
                      -- but may start with prefix 0 on some systems.
                      when 133 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F11;
                      when 134 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F12;
                      -- Codes indicating ALT
                      when 104 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_F1;
                      when 105 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_F2;
                      when 106 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_F3;
                      when 107 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_F4;
                      when 108 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_F5;
                      when 109 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_F6;
                      when 110 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_F7;
                      when 111 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_F8;
                      when 112 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_F9;
                      when 113 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_F10;
                      when 151 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_Home;
                      when 152 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_Up_Arrow;
                      when 153 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_Page_Up;
                      when 155 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_Left_Arrow;
                      when 157 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_Right_Arrow;
                      when 159 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_End;
                      when 160 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_Down_Arrow;
                      when 161 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_Page_Down;
                      when 162 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_Insert;
                      when 163 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_Delete;
                      -- Codes indicating CTRL
                      when  94 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_F1;
                      when  95 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_F2;
                      when  96 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_F3;
                      when  97 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_F4;
                      when  98 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_F5;
                      when  99 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_F6;
                      when 100 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_F7;
                      when 101 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_F8;
                      when 102 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_F9;
                      when 103 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_F10;
                      when 119 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Keypad_Home;
                      when 141 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Keypad_Up_Arrow;
                      when 132 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Keypad_Page_Up;
                      when 115 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Keypad_Left_Arrow;
                      when 116 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Keypad_Right_Arrow;
                      when 117 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Keypad_End;
                      when 145 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Keypad_Down_Arrow;
                      when 118 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Keypad_Page_Down;
                      when 146 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Keypad_Insert;
                      when 147 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Keypad_Delete;
                      when 148 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_Tab;
                      -- Codes indicating SHIFT
                      when  84 =>
                         Modifier_Key := Shift_Key;
                         Key := Key_F1;
                      when  85 =>
                         Modifier_Key := Shift_Key;
                         Key := Key_F2;
                      when  86 =>
                         Modifier_Key := Shift_Key;
                         Key := Key_F3;
                      when  87 =>
                         Modifier_Key := Shift_Key;
                         Key := Key_F4;
                      when  88 =>
                         Modifier_Key := Shift_Key;
                         Key := Key_F5;
                      when  89 =>
                         Modifier_Key := Shift_Key;
                         Key := Key_F6;
                      when  90 =>
                         Modifier_Key := Shift_Key;
                         Key := Key_F7;
                      when  91 =>
                         Modifier_Key := Shift_Key;
                         Key := Key_F8;
                      when  92 =>
                         Modifier_Key := Shift_Key;
                         Key := Key_F9;
                      when  93 =>
                         Modifier_Key := Shift_Key;
                         Key := Key_F10;
                      -- Nothing
                      when others => Ok := False;
                      end case;
                   end;
  
                   procedure Decode_Key_With_Prefix_224 (
                      Input        : in Character;
                      Key          : out Key_Type;
                      Modifier_Key : out Modifier_Key_Type;
                      Ok           : out Boolean)
                   is
                   begin
                      -- This line factorised here
                      Ok := True;
                      -- Start of job
                      case Character'Pos(Input) is
                      -- Codes indicating no modifier key
                      when 133 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F11;
                      when 134 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_F12;
                      when  71 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_Home;
                      when  72 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_Up_Arrow;
                      when  73 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_Page_Up;
                      when  75 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_Left_Arrow;
                      when  77 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_Right_Arrow;
                      when  79 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_End;
                      when  80 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_Down_Arrow;
                      when  81 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_Page_Down;
                      when  82 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_Insert;
                      when  83 =>
                         Modifier_Key := No_Modifier_Key;
                         Key := Key_Delete;
                      -- Codes indicating ALT
                      when 139 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_F11;
                      when 140 =>
                         Modifier_Key := Alt_Key;
                         Key := Key_F12;
                      -- Codes indicating CTRL
                      when 137 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_F11;
                      when 138 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_F12;
                      when 119 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_Home;
                      when 141 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_Up_Arrow;
                      -- Same code as F12
                      --when 134 =>
                      -- Modifier_Key := Ctrl_Key;
                      -- Key := Key_Page_Up;
                      when 115 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_Left_Arrow;
                      when 116 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_Right_Arrow;
                      when 117 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_End;
                      when 145 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_Down_Arrow;
                      when 118 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_Page_Down;
                      when 146 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_Insert;
                      when 147 =>
                         Modifier_Key := Ctrl_Key;
                         Key := Key_Delete;
                      -- Codes indicating SHIFT
                      when 135 =>
                         Modifier_Key := Shift_Key;
                         Key := Key_F11;
                      when 136 =>
                         Modifier_Key := Shift_Key;
                         Key := Key_F12;
                      -- Nothing
                      when others => Ok := False;
                      end case;
                   end;
  
                   procedure Decode_Key_With_No_Prefix (
                      Input        : in Character;
                      Key          : out Key_Type;
                      Modifier_Key : out Modifier_Key_Type;
                      Ok           : out Boolean)
                   is
                   begin
                      -- This line is factorised here
                      Ok := True;
                      Modifier_Key := No_Modifier_Key;
                      -- Start of job
                      case Character'Pos(Input) is
                      when   8 => Key := Key_Backspace;
                      when   9 => Key := Key_Tab;
                      when  13 => Key := Key_Enter;
                      when  27 => Key := Key_Escape;
                      when  32 => Key := Key_Space;
                      when  48 => Key := Key_0;
                      when  49 => Key := Key_1;
                      when  50 => Key := Key_2;
                      when  51 => Key := Key_3;
                      when  52 => Key := Key_4;
                      when  53 => Key := Key_5;
                      when  54 => Key := Key_6;
                      when  55 => Key := Key_7;
                      when  56 => Key := Key_8;
                      when  57 => Key := Key_9;
                      when  65 => Key := Key_A;
                      when  66 => Key := Key_B;
                      when  67 => Key := Key_C;
                      when  68 => Key := Key_D;
                      when  69 => Key := Key_E;
                      when  70 => Key := Key_F;
                      when  71 => Key := Key_G;
                      when  72 => Key := Key_H;
                      when  73 => Key := Key_I;
                      when  74 => Key := Key_J;
                      when  75 => Key := Key_K;
                      when  76 => Key := Key_L;
                      when  77 => Key := Key_M;
                      when  78 => Key := Key_N;
                      when  79 => Key := Key_O;
                      when  80 => Key := Key_P;
                      when  81 => Key := Key_Q;
                      when  82 => Key := Key_R;
                      when  83 => Key := Key_S;
                      when  84 => Key := Key_T;
                      when  85 => Key := Key_U;
                      when  86 => Key := Key_V;
                      when  87 => Key := Key_W;
                      when  88 => Key := Key_X;
                      when  89 => Key := Key_Y;
                      when  90 => Key := Key_Z;
                      when  97 => Key := Key_A;
                      when  98 => Key := Key_B;
                      when  99 => Key := Key_C;
                      when 100 => Key := Key_D;
                      when 101 => Key := Key_E;
                      when 102 => Key := Key_F;
                      when 103 => Key := Key_G;
                      when 104 => Key := Key_H;
                      when 105 => Key := Key_I;
                      when 106 => Key := Key_J;
                      when 107 => Key := Key_K;
                      when 108 => Key := Key_L;
                      when 109 => Key := Key_M;
                      when 110 => Key := Key_N;
                      when 111 => Key := Key_O;
                      when 112 => Key := Key_P;
                      when 113 => Key := Key_Q;
                      when 114 => Key := Key_R;
                      when 115 => Key := Key_S;
                      when 116 => Key := Key_T;
                      when 117 => Key := Key_U;
                      when 118 => Key := Key_V;
                      when 119 => Key := Key_W;
                      when 120 => Key := Key_X;
                      when 121 => Key := Key_Y;
                      when 122 => Key := Key_Z;
                      when others => Ok := False;
                      end case;
                   end;
  
                   procedure Get_Key ( -- Non-blocking key input - See note below
                      Keystroke_Input : out Keystroke_Input_Type)
                   is
                      Input     : Character;
                      Available : Boolean;
                   begin
                      -- This two lines are factorised here.
                      Keystroke_Input.Key_Available := False;
                      Keystroke_Input.Character_Available := False;
                      -- Start of job
                      Get (Input, Available);
                      if not Available then
                         return;
                      end if;
                      case Character'Pos (Input) is
                      when 0 =>
                         Get (Input, Available);
                         if not Available then -- Should we notify an error ?.
                            return;
                         end if;
                         -- Should we notify an error when no key was decoded ?
                         Decode_Key_With_Prefix_0 (
                            Input,
                            Keystroke_Input.Key,
                            Keystroke_Input.Modifier_Key,
                            Keystroke_Input.Key_Available);
                      when 224 =>
                         Get (Input, Available);
                         if not Available then -- Should we notify an error ?.
                            return;
                         end if;
                         -- Should we notify an error when no key was decoded ?
                         Decode_Key_With_Prefix_224 (
                            Input,
                            Keystroke_Input.Key,
                            Keystroke_Input.Modifier_Key,
                            Keystroke_Input.Key_Available);
                      when 240 =>
                         -- This a special case, the only one of this kind.
                         -- Cannot be interpreted… seems to be an error code
                         -- or a placeholder.
                         return;
                      when others =>
                         Keystroke_Input.C := Input;
                         Keystroke_Input.Character_Available := True;
                         Decode_Key_With_No_Prefix (
                            Input,
                            Keystroke_Input.Key,
                            Keystroke_Input.Modifier_Key,
                            Keystroke_Input.Key_Available);
                      end case;
                   end;
  
                   procedure Get_Key (
                      Stream          : in Stream_Type;
                      Keystroke_Input : out Keystroke_Input_Type)
                   is
                      Input     : Character;
                      Available : Boolean;
                   begin
                      -- This two lines are factorised here.
                      Keystroke_Input.Key_Available := False;
                      Keystroke_Input.Character_Available := False;
                      -- Start of job
                      Get (Stream, Input, Available);
                      if not Available then
                         return;
                      end if;
                      case Character'Pos (Input) is
                      when 0 =>
                         Get (Stream, Input, Available);
                         if not Available then -- Should we notify an error ?.
                            return;
                         end if;
                         -- Should we notify an error when no key was decoded ?
                         Decode_Key_With_Prefix_0 (
                            Input,
                            Keystroke_Input.Key,
                            Keystroke_Input.Modifier_Key,
                            Keystroke_Input.Key_Available);
                      when 224 =>
                         Get (Stream, Input, Available);
                         if not Available then -- Should we notify an error ?.
                            return;
                         end if;
                         -- Should we notify an error when no key was decoded ?
                         Decode_Key_With_Prefix_224 (
                            Input,
                            Keystroke_Input.Key,
                            Keystroke_Input.Modifier_Key,
                            Keystroke_Input.Key_Available);
                      when 240 =>
                         -- This a special case, the only one of this kind.
                         -- Cannot be interpreted… seems to be an error code
                         -- or a placeholder.
                         return;
                      when others =>
                         Keystroke_Input.C := Input;
                         Keystroke_Input.Character_Available := True;
                         Decode_Key_With_No_Prefix (
                            Input,
                            Keystroke_Input.Key,
                            Keystroke_Input.Modifier_Key,
                            Keystroke_Input.Key_Available);
                      end case;
                   end;
  
                   -- Procedures for clearing screen or part of line.
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Clear_Screen -- Implements ESC[2J
                   is
                      S : constant String := Character'Val (27) & "[2J";
                   begin
                      -- Maximum string length : 1 + 1 + 1 + 1 = 4
                      Put_Command_String (S);
                   end;
  
                   procedure Clear_Screen (Stream : in Stream_Type)
                   is
                      S : constant String := Character'Val (27) & "[2J";
                   begin
                      Put_Command_String (Stream, S);
                   end;
  
                   procedure Clear_From_Cursor_Up_To_End_Of_Line -- Implements ESC[K
                   is
                      S : constant String := Character'Val (27) & "[K";
                   begin
                      -- Maximum string length : 1 + 1 + 1 = 3
                      Put_Command_String (S);
                   end;
  
                   procedure Clear_From_Cursor_Up_To_End_Of_Line (Stream : in Stream_Type)
                   is
                      S : constant String := Character'Val (27) & "[K";
                   begin
                      Put_Command_String (Stream, S);
                   end;
  
                   -- =========================================================================
                   -- Text color and attributes
                   -- -------------------------------------------------------------------------
  
                   -- Procedures for setting text color.
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   Text_Color_Code : constant array (Color_Type) of Natural := (
                      Black   => 30,
                      Red     => 31,
                      Green   => 32,
                      Yellow  => 33,
                      Blue    => 34,
                      Magenta => 35,
                      Cyan    => 36,
                      White   => 37);
  
                   procedure Set_Text_Color ( -- Implements part of ESC[Ps;…;Psm
                      Color : in Color_Type)
                   is
                      B : Buffer_Type;
                   begin
                      -- Maximum string length : 1 + 1 + 2 + 1 = 5
                      Start (B);
                      Append (B, Text_Color_Code (Color));
                      Append (B, 'm');
                      Put (B);
                   end;
  
                   procedure Set_Text_Color (
                      Stream : in Stream_Type;
                      Color  : in Color_Type)
                   is
                      B : Buffer_Type;
                   begin
                      Start (B);
                      Append (B, Text_Color_Code (Color));
                      Append (B, 'm');
                      Put (Stream, B);
                   end;
  
                   Background_Color_Code : constant array (Color_Type) of Natural := (
                      Black   => 40,
                      Red     => 41,
                      Green   => 42,
                      Yellow  => 43,
                      Blue    => 44,
                      Magenta => 45,
                      Cyan    => 46,
                      White   => 47);
  
                   procedure Set_Background_Color ( -- Implements part of ESC[Ps;…;Psm
                      Color : in Color_Type)
                   is
                      B : Buffer_Type;
                   begin
                      -- Maximum string length : 1 + 1 + 2 + 1 = 5
                      Start (B);
                      Append (B, Background_Color_Code (Color));
                      Append (B, 'm');
                      Put (B);
                   end;
  
                   procedure Set_Background_Color (
                      Stream : in Stream_Type;
                      Color  : in Color_Type)
                   is
                      B : Buffer_Type;
                   begin
                      Start (B);
                      Append (B, Background_Color_Code (Color));
                      Append (B, 'm');
                      Put (Stream, B);
                   end;
  
                   -- Procedure for setting text attributs (blinking and the like…).
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   Text_Attributes_Code : constant array (Text_Attributes_Type) of Natural := (
                      Default_Text_Attributes =>  0,
                      Bold_Text               =>  1,
                      Thin_Text               =>  2,
                      Standout_Text           =>  3,
                      Underlined_Text         =>  4,
                      Blinking_Text           =>  5,
                      Reversed_Colors         =>  7,
                      Hidden_Text             =>  8,
                      Normal_Text             => 22,
                      Not_Standout_Text       => 23,
                      Not_Underlined_Text     => 24,
                      Not_Blinking_Text       => 25,
                      Not_Reversed_Text       => 27);
  
                   procedure Set_Text_Attributes ( -- Implements part of ESC[Ps;…;Psm
                      Text_Attributes : in Text_Attributes_Type)
                   is
                      B : Buffer_Type;
                   begin
                      -- Maximum string length : 1 + 1 + 2 + 1 = 5
                      Start (B);
                      Append (B, Text_Attributes_Code (Text_Attributes));
                      Append (B, 'm');
                      Put (B);
                   end;
  
                   procedure Set_Text_Attributes (
                      Stream          : in Stream_Type;
                      Text_Attributes : in Text_Attributes_Type)
                   is
                      B : Buffer_Type;
                   begin
                      Start (B);
                      Append (B, Text_Attributes_Code (Text_Attributes));
                      Append (B, 'm');
                      Put (Stream, B);
                   end;
  
                   -- =========================================================================
                   -- Cursor position and movement
                   -- -------------------------------------------------------------------------
  
                   -- Procedure fixing cursor position
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Move_Cursor_To ( -- Implements ESC[PL;PcH  (same as ESC[PL;Pcf)
                      Line   : in Vertical_Position_Type;
                      Column : in Horizontal_Position_Type)
                   is
                      B : Buffer_Type;
                   begin
                      -- Maximum string length : 1 + 1 + 4 + 1 + 4 + 1 = 12
                      Start (B);
                      Append (B, Line);
                      Append (B, ';');
                      Append (B, Column);
                      Append (B, 'H');
                      Put (B);
                   end;
  
                   procedure Move_Cursor_To (
                      Stream : in Stream_Type;
                      Line   : in Vertical_Position_Type;
                      Column : in Horizontal_Position_Type)
                   is
                      B : Buffer_Type;
                   begin
                      Start (B);
                      Append (B, Line);
                      Append (B, ';');
                      Append (B, Column);
                      Append (B, 'H');
                      Put (Stream, B);
                   end;
  
                   -- Procedures moving cursor position
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Move_Cursor_Up ( -- Implements ESC[PnA
                      Count : in Vertical_Delta_Type)
                   is
                      B : Buffer_Type;
                   begin
                      -- Maximum string length : 1 + 1 + 4 + 1 = 7
                      Start (B);
                      Append (B, Count);
                      Append (B, 'A');
                      Put (B);
                   end;
  
                   procedure Move_Cursor_Up (
                      Stream : in Stream_Type;
                      Count  : in Vertical_Delta_Type)
                   is
                      B : Buffer_Type;
                   begin
                      Start (B);
                      Append (B, Count);
                      Append (B, 'A');
                      Put (Stream, B);
                   end;
  
                   procedure Move_Cursor_Down ( -- Implements ESC[PnB
                      Count : in Vertical_Delta_Type)
                   is
                      B : Buffer_Type;
                   begin
                      -- Maximum string length : 1 + 1 + 4 + 1 = 7
                      Start (B);
                      Append (B, Count);
                      Append (B, 'B');
                      Put (B);
                   end;
  
                   procedure Move_Cursor_Down (
                      Stream : in Stream_Type;
                      Count  : in Vertical_Delta_Type)
                   is
                      B : Buffer_Type;
                   begin
                      Start (B);
                      Append (B, Count);
                      Append (B, 'B');
                      Put (Stream, B);
                   end;
  
                   procedure Move_Cursor_Right ( -- Implements ESC[PnC
                      Count : in Horizontal_Delta_Type)
                   is
                      B : Buffer_Type;
                   begin
                      -- Maximum string length : 1 + 1 + 4 + 1 = 7
                      Start (B);
                      Append (B, Count);
                      Append (B, 'C');
                      Put (B);
                   end;
  
                   procedure Move_Cursor_Right (
                      Stream : in Stream_Type;
                      Count  : in Horizontal_Delta_Type)
                   is
                      B : Buffer_Type;
                   begin
                      Start (B);
                      Append (B, Count);
                      Append (B, 'C');
                      Put (Stream, B);
                   end;
  
                   procedure Move_Cursor_Left ( -- Implements ESC[PnD
                      Count : in Horizontal_Delta_Type)
                   is
                      B : Buffer_Type;
                   begin
                      -- Maximum string length : 1 + 1 + 4 + 1 = 7
                      Start (B);
                      Append (B, Count);
                      Append (B, 'D');
                      Put (B);
                   end;
  
                   procedure Move_Cursor_Left (
                      Stream : in Stream_Type;
                      Count  : in Horizontal_Delta_Type)
                   is
                      B : Buffer_Type;
                   begin
                      Start (B);
                      Append (B, Count);
                      Append (B, 'D');
                      Put (Stream, B);
                   end;
  
                   -- Procedures for saving/restoring cursor position
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Save_Cursor_Position -- Implements ESC[s
                   is
                      S : constant String := Character'Val (27) & "[s";
                   begin
                      -- Maximum string length : 1 + 1 + 1 = 3
                      Put_Command_String (S);
                   end;
  
                   procedure Save_Cursor_Position (Stream : in Stream_Type)
                   is
                      S : constant String := Character'Val (27) & "[s";
                   begin
                      Put_Command_String (Stream, S);
                   end;
  
                   procedure Restore_Cursor_Position -- Implements ESC[u
                   is
                      S : constant String := Character'Val (27) & "[u";
                   begin
                      -- Maximum string length : 1 + 1 + 1 = 3
                      Put_Command_String (S);
                   end;
  
                   procedure Restore_Cursor_Position (Stream : in Stream_Type)
                   is
                      S : constant String := Character'Val (27) & "[u";
                   begin
                      Put_Command_String (Stream, S);
                   end;
  
                   -- =========================================================================
                   -- Screen modes (resolution) and output behaviour
                   -- -------------------------------------------------------------------------
  
                   -- Procedures for fixing screen mode (screen resolution)
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   Screen_Mode_Code : constant array (Screen_Mode_Type) of Natural := (
                      Monochrome_Text_Mode_40x25      =>  0,
                      Color_Text_Mode_40x25           =>  1,
                      Monochrome_Text_Mode_80x25      =>  2,
                      Color_Text_Mode_80x25           =>  3,
                      Color4_Graphic_Mode_320x200     =>  4,
                      Monochrome_Graphic_Mode_320x200 =>  5,
                      Monochrome_Graphic_Mode_640x200 =>  6,
                      Color_Graphic_Mode_320x200      => 13,
                      Color16_Graphic_Mode_640x200    => 14,
                      Monochrome_Graphic_Mode_640x350 => 15,
                      Color16_Graphic_Mode_640x350    => 16,
                      Monochrome_Graphic_Mode_640x480 => 17,
                      Color16_Graphic_Mode_640x480    => 18,
                      Color256_Graphic_Mode_320x200   => 19);
  
                   procedure Set_Screen_Mode ( -- Implements part of ESC[=Psh
                      Screen_Mode : in Screen_Mode_Type)
                   is
                      B : Buffer_Type;
                   begin
                      -- Maximum string length : 1 + 1 + 1 + 2 + 1 = 6
                      Start (B);
                      Append (B, '=');
                      Append (B, Screen_Mode_Code (Screen_Mode));
                      Append (B, 'h');
                      Put (B);
                   end;
  
                   procedure Set_Screen_Mode (
                      Stream      : in Stream_Type;
                      Screen_Mode : in Screen_Mode_Type)
                   is
                      B : Buffer_Type;
                   begin
                      Start (B);
                      Append (B, '=');
                      Append (B, Screen_Mode_Code (Screen_Mode));
                      Append (B, 'h');
                      Put (Stream, B);
                   end;
  
                   procedure Reset_Screen_Mode ( -- Implements ESC[=Psl
                      Screen_Mode : in Screen_Mode_Type)
                   is
                      B : Buffer_Type;
                   begin
                      -- Maximum string length : 1 + 1 + 1 + 2 + 1 = 6
                      Start (B);
                      Append (B, '=');
                      Append (B, Screen_Mode_Code (Screen_Mode));
                      Append (B, 's');
                      Put (B);
                   end;
  
                   procedure Reset_Screen_Mode (
                      Stream      : in Stream_Type;
                      Screen_Mode : in Screen_Mode_Type)
                   is
                      B : Buffer_Type;
                   begin
                      Start (B);
                      Append (B, '=');
                      Append (B, Screen_Mode_Code (Screen_Mode));
                      Append (B, 's');
                      Put (Stream, B);
                   end;
  
                   -- Procedures for fixing screen behaviour (line wrapping)
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   procedure Enable_Line_Wrapping -- Implements part of ESC[=Psh
                   is
                      S : constant String := Character'Val (27) & "[=7h";
                   begin
                      -- Maximum string length : 1 + 1 + 1 + 1 + 1 = 5
                      Put_Command_String (S);
                   end;
  
                   procedure Enable_Line_Wrapping (Stream : in Stream_Type)
                   is
                      S : constant String := Character'Val (27) & "[=7h";
                   begin
                      Put_Command_String (Stream, S);
                   end;
  
                   procedure Disable_Line_Wrapping -- Implements part of ESC[=Psl
                   is
                      S : constant String := Character'Val (27) & "[=7l";
                   begin
                      -- Maximum string length : 1 + 1 + 1 + 1 + 1 = 5
                      Put_Command_String (S);
                   end;
  
                   procedure Disable_Line_Wrapping (Stream : in Stream_Type)
                   is
                      S : constant String := Character'Val (27) & "[=7l";
                   begin
                      Put_Command_String (Stream, S);
                   end;
  
                   -- =========================================================================
                   -- Keystroke assignements
                   -- ------------------------------------------------------------------------
  
                   -- Function for keystroke string code
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   -- As string lengths vary, an associative array cannot be used,
                   -- so it is implemented as a function built on a case statement.
                   -- The second good raison for using a function in place of an
                   -- associative array, is that an array cannot raise an exception :P
                   --… and we may need to raise Illegal_Keystroke in case of an
                   -- illegal modifier+key combination.
  
                   function Key_String_Code_Whith_No_Modifier_Key (Key : in Key_Type)
                   return String
                   is
                   begin
                      case Key is
                      when Key_F1                => return "0;59";
                      when Key_F2                => return "0;60";
                      when Key_F3                => return "0;61";
                      when Key_F4                => return "0;62";
                      when Key_F5                => return "0;63";
                      when Key_F6                => return "0;64";
                      when Key_F7                => return "0;65";
                      when Key_F8                => return "0;66";
                      when Key_F9                => return "0;67";
                      when Key_F10               => return "0;68";
                      when Key_F11               => return "0;133";
                      when Key_F12               => return "0;134";
                      when Keypad_Home           => return "0;71";
                      when Keypad_Up_Arrow       => return "0;72";
                      when Keypad_Page_Up        => return "0;73";
                      when Keypad_Left_Arrow     => return "0;75";
                      when Keypad_Right_Arrow    => return "0;77";
                      when Keypad_End            => return "0;79";
                      when Keypad_Down_Arrow     => return "0;80";
                      when Keypad_Page_Down      => return "0;81";
                      when Keypad_Insert         => return "0;82";
                      when Keypad_Delete         => return "0;83";
                      when Key_Home              => return "(224;71)";
                      when Key_Up_Arrow          => return "(224;72)";
                      when Key_Page_Up           => return "(224;73)";
                      when Key_Left_Arrow        => return "(224;75)";
                      when Key_Right_Arrow       => return "(224;77)";
                      when Key_End               => return "(224;79)";
                      when Key_Down_Arrow        => return "(224;80)";
                      when Key_Page_Down         => return "(224;81)";
                      when Key_Insert            => return "(224;82)";
                      when Key_Delete            => return "(224;83)";
                      when Key_Print_Screen      => raise Illegal_Keystroke;
                      when Key_Pause_Break       => raise Illegal_Keystroke;
                      when Key_Escape            => raise Illegal_Keystroke;
                      when Key_Backspace         => return "8";
                      when Key_Enter             => return "13";
                      when Key_Tab               => return "9";
                      when Key_Null              => return "0;3";
                      when Key_A                 => return "97";
                      when Key_B                 => return "98";
                      when Key_C                 => return "99";
                      when Key_D                 => return "100";
                      when Key_E                 => return "101";
                      when Key_F                 => return "102";
                      when Key_G                 => return "103";
                      when Key_H                 => return "104";
                      when Key_I                 => return "105";
                      when Key_J                 => return "106";
                      when Key_K                 => return "107";
                      when Key_L                 => return "108";
                      when Key_M                 => return "109";
                      when Key_N                 => return "110";
                      when Key_O                 => return "111";
                      when Key_P                 => return "112";
                      when Key_Q                 => return "113";
                      when Key_R                 => return "114";
                      when Key_S                 => return "115";
                      when Key_T                 => return "116";
                      when Key_U                 => return "117";
                      when Key_V                 => return "118";
                      when Key_W                 => return "119";
                      when Key_X                 => return "120";
                      when Key_Y                 => return "121";
                      when Key_Z                 => return "122";
                      when Key_1                 => return "49";
                      when Key_2                 => return "50";
                      when Key_3                 => return "51";
                      when Key_4                 => return "52";
                      when Key_5                 => return "53";
                      when Key_6                 => return "54";
                      when Key_7                 => return "55";
                      when Key_8                 => return "56";
                      when Key_9                 => return "57";
                      when Key_0                 => return "48";
                      when Key_Minus             => return "45";
                      when Key_Equal             => return "61";
                      when Key_Left_Square       => return "91";
                      when Key_Right_Square      => return "93";
                      when Key_Space             => return "92";
                      when Key_Semicolon         => return "59";
                      when Key_Single_Quote      => return "39";
                      when Key_Comma             => return "44";
                      when Key_Dot               => return "46";
                      when Key_Slash             => return "47";
                      when Key_Left_Single_Quote => return "96";
                      when Keypad_Enter          => return "13";
                      when Keypad_Slash          => return "47";
                      when Keypad_Star           => return "42";
                      when Keypad_Minus          => return "45";
                      when Keypad_Plus           => return "43";
                      when Keypad_Middle         => return "(0;76)";
                      end case;
                   end;
  
                   function Key_String_Code_Whith_Shift_Key (Key : in Key_Type)
                   return String
                   is
                   begin
                      case Key is
                      when Key_F1                => return "0;84";
                      when Key_F2                => return "0;85";
                      when Key_F3                => return "0;86";
                      when Key_F4                => return "0;87";
                      when Key_F5                => return "0;88";
                      when Key_F6                => return "0;89";
                      when Key_F7                => return "0;90";
                      when Key_F8                => return "0;91";
                      when Key_F9                => return "0;92";
                      when Key_F10               => return "0;93";
                      when Key_F11               => return "0;135";
                      when Key_F12               => return "0;136";
                      when Keypad_Home           => return "55";
                      when Keypad_Up_Arrow       => return "56";
                      when Keypad_Page_Up        => return "57";
                      when Keypad_Left_Arrow     => return "52";
                      when Keypad_Right_Arrow    => return "54";
                      when Keypad_End            => return "49";
                      when Keypad_Down_Arrow     => return "50";
                      when Keypad_Page_Down      => return "51";
                      when Keypad_Insert         => return "48";
                      when Keypad_Delete         => return "46";
                      when Key_Home              => return "(224;71)";
                      when Key_Up_Arrow          => return "(224;72)";
                      when Key_Page_Up           => return "(224;73)";
                      when Key_Left_Arrow        => return "(224;75)";
                      when Key_Right_Arrow       => return "(224;77)";
                      when Key_End               => return "(224;79)";
                      when Key_Down_Arrow        => return "(224;80)";
                      when Key_Page_Down         => return "(224;81)";
                      when Key_Insert            => return "(224;82)";
                      when Key_Delete            => return "(224;83)";
                      when Key_Print_Screen      => raise Illegal_Keystroke;
                      when Key_Pause_Break       => raise Illegal_Keystroke;
                      when Key_Escape            => raise Illegal_Keystroke;
                      when Key_Backspace         => return "8";
                      when Key_Enter             => raise Illegal_Keystroke;
                      when Key_Tab               => return "0;15";
                      when Key_Null              => raise Illegal_Keystroke;
                      when Key_A                 => return "65";
                      when Key_B                 => return "66";
                      when Key_C                 => return "66";
                      when Key_D                 => return "68";
                      when Key_E                 => return "69";
                      when Key_F                 => return "70";
                      when Key_G                 => return "71";
                      when Key_H                 => return "72";
                      when Key_I                 => return "73";
                      when Key_J                 => return "74";
                      when Key_K                 => return "75";
                      when Key_L                 => return "76";
                      when Key_M                 => return "77";
                      when Key_N                 => return "78";
                      when Key_O                 => return "79";
                      when Key_P                 => return "80";
                      when Key_Q                 => return "81";
                      when Key_R                 => return "82";
                      when Key_S                 => return "83";
                      when Key_T                 => return "84";
                      when Key_U                 => return "85";
                      when Key_V                 => return "86";
                      when Key_W                 => return "87";
                      when Key_X                 => return "88";
                      when Key_Y                 => return "89";
                      when Key_Z                 => return "90";
                      when Key_1                 => return "33";
                      when Key_2                 => return "64";
                      when Key_3                 => return "35";
                      when Key_4                 => return "36";
                      when Key_5                 => return "37";
                      when Key_6                 => return "94";
                      when Key_7                 => return "38";
                      when Key_8                 => return "42";
                      when Key_9                 => return "40";
                      when Key_0                 => return "41";
                      when Key_Minus             => return "95";
                      when Key_Equal             => return "43";
                      when Key_Left_Square       => return "123";
                      when Key_Right_Square      => return "125";
                      when Key_Space             => return "124";
                      when Key_Semicolon         => return "58";
                      when Key_Single_Quote      => return "34";
                      when Key_Comma             => return "60";
                      when Key_Dot               => return "62";
                      when Key_Slash             => return "63";
                      when Key_Left_Single_Quote => return "126";
                      when Keypad_Enter          => raise Illegal_Keystroke;
                      when Keypad_Slash          => return "47";
                      when Keypad_Star           => return "(0;144)";
                      when Keypad_Minus          => return "45";
                      when Keypad_Plus           => return "43";
                      when Keypad_Middle         => return "53";
                      end case;
                   end;
  
                   function Key_String_Code_Whith_Ctrl_Key (Key : in Key_Type)
                   return String
                   is
                   begin
                      case Key is
                      when Key_F1                => return "0;94";
                      when Key_F2                => return "0;95";
                      when Key_F3                => return "0;96";
                      when Key_F4                => return "0;97";
                      when Key_F5                => return "0;98";
                      when Key_F6                => return "0;99";
                      when Key_F7                => return "0;100";
                      when Key_F8                => return "0;101";
                      when Key_F9                => return "0;102";
                      when Key_F10               => return "0;103";
                      when Key_F11               => return "0;137";
                      when Key_F12               => return "0;138";
                      when Keypad_Home           => return "0;119";
                      when Keypad_Up_Arrow       => return "(0;141)";
                      when Keypad_Page_Up        => return "0;132";
                      when Keypad_Left_Arrow     => return "0;115";
                      when Keypad_Right_Arrow    => return "0;116";
                      when Keypad_End            => return "0;117";
                      when Keypad_Down_Arrow     => return "(0;145)";
                      when Keypad_Page_Down      => return "0;118";
                      when Keypad_Insert         => return "(0;146)";
                      when Keypad_Delete         => return "(0;147)";
                      when Key_Home              => return "(224;119)";
                      when Key_Up_Arrow          => return "(224;141)";
                      when Key_Page_Up           => return "(224;132)";
                      when Key_Left_Arrow        => return "(224;115)";
                      when Key_Right_Arrow       => return "(224;116)";
                      when Key_End               => return "(224;117)";
                      when Key_Down_Arrow        => return "(224;145)";
                      when Key_Page_Down         => return "(224;118)";
                      when Key_Insert            => return "(224;146)";
                      when Key_Delete            => return "(224;147)";
                      when Key_Print_Screen      => return "0;114";
                      when Key_Pause_Break       => return "0;0";
                      when Key_Escape            => raise Illegal_Keystroke;
                      when Key_Backspace         => return "127";
                      when Key_Enter             => return "10";
                      when Key_Tab               => return "(0;148)";
                      when Key_Null              => raise Illegal_Keystroke;
                      when Key_A                 => return "1";
                      when Key_B                 => return "2";
                      when Key_C                 => return "3";
                      when Key_D                 => return "4";
                      when Key_E                 => return "5";
                      when Key_F                 => return "6";
                      when Key_G                 => return "7";
                      when Key_H                 => return "8";
                      when Key_I                 => return "9";
                      when Key_J                 => return "10";
                      when Key_K                 => return "11";
                      when Key_L                 => return "12";
                      when Key_M                 => return "13";
                      when Key_N                 => return "14";
                      when Key_O                 => return "15";
                      when Key_P                 => return "16";
                      when Key_Q                 => return "17";
                      when Key_R                 => return "18";
                      when Key_S                 => return "19";
                      when Key_T                 => return "20";
                      when Key_U                 => return "21";
                      when Key_V                 => return "22";
                      when Key_W                 => return "23";
                      when Key_X                 => return "24";
                      when Key_Y                 => return "25";
                      when Key_Z                 => return "26";
                      when Key_1                 => raise Illegal_Keystroke;
                      when Key_2                 => return "0";
                      when Key_3                 => raise Illegal_Keystroke;
                      when Key_4                 => raise Illegal_Keystroke;
                      when Key_5                 => raise Illegal_Keystroke;
                      when Key_6                 => return "30";
                      when Key_7                 => raise Illegal_Keystroke;
                      when Key_8                 => raise Illegal_Keystroke;
                      when Key_9                 => raise Illegal_Keystroke;
                      when Key_0                 => raise Illegal_Keystroke;
                      when Key_Minus             => return "31";
                      when Key_Equal             => raise Illegal_Keystroke;
                      when Key_Left_Square       => return "27";
                      when Key_Right_Square      => return "29";
                      when Key_Space             => return "28";
                      when Key_Semicolon         => raise Illegal_Keystroke;
                      when Key_Single_Quote      => raise Illegal_Keystroke;
                      when Key_Comma             => raise Illegal_Keystroke;
                      when Key_Dot               => raise Illegal_Keystroke;
                      when Key_Slash             => raise Illegal_Keystroke;
                      when Key_Left_Single_Quote => raise Illegal_Keystroke;
                      when Keypad_Enter          => return "10";
                      when Keypad_Slash          => return "(0;142)";
                      when Keypad_Star           => return "(0;78)";
                      when Keypad_Minus          => return "(0;149)";
                      when Keypad_Plus           => return "(0;150)";
                      when Keypad_Middle         => return "(0;143)";
                      end case;
                   end;
  
                   function Key_String_Code_Whith_Alt_Key (Key : in Key_Type)
                   return String
                   is
                   begin
                      case Key is
                      when Key_F1                => return "0;104";
                      when Key_F2                => return "0;105";
                      when Key_F3                => return "0;106";
                      when Key_F4                => return "0;107";
                      when Key_F5                => return "0;108";
                      when Key_F6                => return "0;109";
                      when Key_F7                => return "0;110";
                      when Key_F8                => return "0;111";
                      when Key_F9                => return "0;112";
                      when Key_F10               => return "0;113";
                      when Key_F11               => return "0;139";
                      when Key_F12               => return "0;140";
                      when Keypad_Home           => raise Illegal_Keystroke;
                      when Keypad_Up_Arrow       => raise Illegal_Keystroke;
                      when Keypad_Page_Up        => raise Illegal_Keystroke;
                      when Keypad_Left_Arrow     => raise Illegal_Keystroke;
                      when Keypad_Right_Arrow    => raise Illegal_Keystroke;
                      when Keypad_End            => raise Illegal_Keystroke;
                      when Keypad_Down_Arrow     => raise Illegal_Keystroke;
                      when Keypad_Page_Down      => raise Illegal_Keystroke;
                      when Keypad_Insert         => raise Illegal_Keystroke;
                      when Keypad_Delete         => raise Illegal_Keystroke;
                      when Key_Home              => return "(224;151)";
                      when Key_Up_Arrow          => return "(224;152)";
                      when Key_Page_Up           => return "(224;153)";
                      when Key_Left_Arrow        => return "(224;155)";
                      when Key_Right_Arrow       => return "(224;157)";
                      when Key_End               => return "(224;159)";
                      when Key_Down_Arrow        => return "(224;154)";
                      when Key_Page_Down         => return "(224;161)";
                      when Key_Insert            => return "(224;162)";
                      when Key_Delete            => return "(224;163)";
                      when Key_Print_Screen      => raise Illegal_Keystroke;
                      when Key_Pause_Break       => raise Illegal_Keystroke;
                      when Key_Escape            => raise Illegal_Keystroke;
                      when Key_Backspace         => return "(0)";
                      when Key_Enter             => return "(0";
                      when Key_Tab               => return "(0;165)";
                      when Key_Null              => raise Illegal_Keystroke;
                      when Key_A                 => return "0;30";
                      when Key_B                 => return "0;48";
                      when Key_C                 => return "0;46";
                      when Key_D                 => return "0;32";
                      when Key_E                 => return "0;18";
                      when Key_F                 => return "0;33";
                      when Key_G                 => return "0;34";
                      when Key_H                 => return "0;35";
                      when Key_I                 => return "0;23";
                      when Key_J                 => return "0;36";
                      when Key_K                 => return "0;37";
                      when Key_L                 => return "0;38";
                      when Key_M                 => return "0;50";
                      when Key_N                 => return "0;49";
                      when Key_O                 => return "0;24";
                      when Key_P                 => return "0;25";
                      when Key_Q                 => return "0;16";
                      when Key_R                 => return "0;19";
                      when Key_S                 => return "0;31";
                      when Key_T                 => return "0;20";
                      when Key_U                 => return "0;22";
                      when Key_V                 => return "0;47";
                      when Key_W                 => return "0;17";
                      when Key_X                 => return "0;45";
                      when Key_Y                 => return "0;21";
                      when Key_Z                 => return "0;44";
                      when Key_1                 => return "0;120";
                      when Key_2                 => return "0;121";
                      when Key_3                 => return "0;122";
                      when Key_4                 => return "0;123";
                      when Key_5                 => return "0;124";
                      when Key_6                 => return "0;125";
                      when Key_7                 => return "0;126";
                      when Key_8                 => return "0;126";
                      when Key_9                 => return "0;127";
                      when Key_0                 => return "0;129";
                      when Key_Minus             => return "0;130";
                      when Key_Equal             => return "0;131";
                      when Key_Left_Square       => return "0;26";
                      when Key_Right_Square      => return "0;27";
                      when Key_Space             => return "0;43";
                      when Key_Semicolon         => return "0;39";
                      when Key_Single_Quote      => return "0;40";
                      when Key_Comma             => return "0;51";
                      when Key_Dot               => return "0;52";
                      when Key_Slash             => return "0;53";
                      when Key_Left_Single_Quote => return "(0;41)";
                      when Keypad_Enter          => return "(0;166)";
                      when Keypad_Slash          => return "(0;74)";
                      when Keypad_Star           => raise Illegal_Keystroke;
                      when Keypad_Minus          => return "(0;164)";
                      when Keypad_Plus           => return "(0;55)";
                      when Keypad_Middle         => raise Illegal_Keystroke;
                      end case;
                   end;
  
                   function Keystroke_String_Code (
                      Key          : in Key_Type;
                      Modifier_Key : in Modifier_Key_Type)
                   return String
                   is
                   begin
                      case Modifier_Key is
                      when No_Modifier_Key =>
                         return Key_String_Code_Whith_No_Modifier_Key (Key);
                      when Shift_Key => return Key_String_Code_Whith_Shift_Key (Key);
                      when Ctrl_Key  => return Key_String_Code_Whith_Ctrl_Key (Key);
                      when Alt_Key   => return Key_String_Code_Whith_Alt_Key (Key);
                      end case;
                   end;
  
                   -- Procedure for assigning key-stroke to string
                   -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
                   function Legal_Keystroke (
                      Key          : in Key_Type;
                      Modifier_Key : in Modifier_Key_Type)
                   return Boolean
                   is
                   begin
                      case Modifier_Key is
                      when No_Modifier_Key =>
                         case Key is
                         when Key_Print_Screen      => return False;
                         when Key_Pause_Break       => return False;
                         when others => return True;
                         end case;
                      when Shift_Key =>
                         case Key is
                         when Key_Print_Screen      => return False;
                         when Key_Pause_Break       => return False;
                         when Key_Enter             => return False;
                         when Key_Null              => return False;
                         when Keypad_Enter          => return False;
                         when others => return True;
                         end case;
                      when Ctrl_Key =>
                         case Key is
                         when Key_Null              => return False;
                         when Key_1                 => return False;
                         when Key_2                 => return False;
                         when Key_3                 => return False;
                         when Key_4                 => return False;
                         when Key_5                 => return False;
                         when Key_6                 => return False;
                         when Key_7                 => return False;
                         when Key_8                 => return False;
                         when Key_9                 => return False;
                         when Key_0                 => return False;
                         when Key_Equal             => return False;
                         when Key_Semicolon         => return False;
                         when Key_Single_Quote      => return False;
                         when Key_Slash             => return False;
                         when Key_Left_Single_Quote => return False;
                         when others => return True;
                         end case;
                      when Alt_Key =>
                         case Key is
                         when Keypad_Home           => return False;
                         when Keypad_Up_Arrow       => return False;
                         when Keypad_Page_Up        => return False;
                         when Keypad_Left_Arrow     => return False;
                         when Keypad_Right_Arrow    => return False;
                         when Keypad_End            => return False;
                         when Keypad_Down_Arrow     => return False;
                         when Keypad_Page_Down      => return False;
                         when Keypad_Insert         => return False;
                         when Keypad_Delete         => return False;
                         when Key_Print_Screen      => return False;
                         when Key_Pause_Break       => return False;
                         when Key_Null              => return False;
                         when Keypad_Star           => return False;
                         when Keypad_Middle         => return False;
                         when others => return True;
                         end case;
                      end case;
                   end;
  
                   procedure Assign_Keystroke ( -- Implements ESC[code;string;…p
                      Key          : in Key_Type;
                      Modifier_Key : in Modifier_Key_Type;
                      Substitution : in String)
                   is
                      B : Buffer_Type;
                   begin
                      -- Maximum string length : 1 + 1 + maximum-code-length + 1 =
                      -- 1 + 1 + 9 + 1 = 12
                      Start (B);
                      Append (B, Keystroke_String_Code (Key, Modifier_Key));
                      Append (B, ';');
                      Put (B);
                      Put_Command_String (Substitution);
                      Put_Command_String ("p");
                   end;
  
                   procedure Assign_Keystroke (
                      Stream       : in Stream_Type;
                      Key          : in Key_Type;
                      Modifier_Key : in Modifier_Key_Type;
                      Substitution : in String)
                   is
                      B : Buffer_Type;
                   begin
                      Start (B);
                      Append (B, Keystroke_String_Code (Key, Modifier_Key));
                      Append (B, ';');
                      Put (Stream, B);
                      Put_Command_String (Stream, Substitution);
                      Put_Command_String (Stream, "p");
                   end;
  
                end ANSI_Console;
  
  
  
  
  
          
         
        

Notes…

[Note 1] - La référence original, donnée lors de la première publication de ce document, semble maintenant indisponible. Adresse originelle : « http://rrbrandt.dyndns.org:60000/docs/tut/redes/ansi.php » . Si vous avez connaissance d’une nouvelle adresse pour ce document, n’hésitez pas à nous en informer.