Information sur le Langage C Linux et utilisation de Geany et CodeBlock

EN CONSTRUCTION...

Buts de cette page Web.

Le but de cette page et des vidéos qui lui sont associées n'est pas d'aborder les bases de la programmation en Langage C, mais d'aborder des points particuliers, tels que ceux décrits dans la table des matières.

Table des matières   Liens internes à cette page

1) Quelques références de sites Web et de vidéos.
2) Installation minimale et recommandées.
3) Geany, un éditeur de texte pratique.
4) Code::Blocks, un IDE.
5) Mes conventions de notation.
6) Un premier exemple, "Hello world" avec suppléments.
7) printf, les "specifiers" ou les "data type".
8) None blocking "getc()", lecture d'un caractère au clavier, sans arrêter l'exécution.
9) Lecture des touches pressées du clavier, sans arrêter l'exécution.
les code escape

 

1) Quelques références de sites Web et de vidéos   Top

Pour la numérotation des lignes, j'ai utilisé le site suivant : https://jsfiddle.net/tovic/AbpRD/.
J'ai repris le code et je l'ai simplifié.

Pour la coloration syntaxique du code en langage C, L'outil de coloration syntaxique du site suivant est utilisable :
https://highlightjs.org/.
Autre information sur : highlight.js
Vu qu'il ne faisait pas exactement ce que je voulais, il est trop généraliste et trop compliqué pour moi, j'ai écrit un petit programme en javascript qui fait la coloration syntaxique.
Le code javascript est disponible ici.
Regardez aussi le code source de cette page pour les styles CSS associés, mis en début du code html.
Regardez en fin de code pour l'appelle aux fonctions de coloration et de numérotation.

Je me suis rapproché de la coloration syntaxique par défaut de l'éditeur de textes geany.
J'ai ajouté une coloration pour les symboles + - * / ( ) = [ ] { }

Pour les bases de la programmation en langage C, voici de très bonnes vidéos.
Publié sur Youtube par FormationVidéo
Il a une série de 29 vidéos d'introduction, plus d'autres vidéos, sur le langage C.
Il a également des vidéos d'introductions au C++ et sur d'autres langages.
161001 Langage C #1 - introduction
171222
171222 Langage C #23 - introduction SDL
171222
171222
Une page Web sur le Langage C que j'ai écrite il y a quelques années.

2) Installation minimale et recommandées.   Top

sudo apt install gcc
sudo apt install build-essential

3) Geany, un éditeur de texte pratique.   Top

Le site Web de référence de geany.

Geany est un éditeur de texte, multi usage, que j'utilise souvent pour de petites modifications de code HTML, CSS, javascript et pour des petits programmes en langage C ou C++.
C'est lui que j'ai utilisé pour les exemples qui suivent.

Pour l'installer :
sudo apt install geany


4) Code::Blocks, un IDE.   Top

Code::Blocks est un IDE "Integrated Development Environment" "Environnement de Développement Intégré".
Je le trouve pratique pour de gros projets.
Pour de petits tests, je lui préfère geany.
Je ne l'utiliserai pas par la suite.
Le site Web de référence de Code::Blocks.

Pour installer Code::Blocks, taper dans un Terminal :
sudo apt install codeblocks
Votre mot de passe administrateur vous sera demandé.

Il existe beaucoup d'autres Environnement de Développement, Qt, Visual studio, Netbeans, Eclipse, Atome, Brackets, etc.

5) Mes conventions de notation.   Top

J'utilise un dérivé de la notation hongroise
Chaque variable commence par des minuscules qui indiquent le type de la variable, suivit d'une majuscule qui est le début du nom de la variable.
Voici mes conventions de notation hongroise :
préfixes	description
n   int (entier sur 4 octets, ou 2 sur certains systèmes)
l	  long int (entier long)
v   float ou double (nombre à virgule flottante, 4 ou 8 octets)
c   char (caractère un octet)
b   byte (caractère non signé)  == uc  (unsigned char)
f   flag = boolean (booléen true/false un octet)
w   word (mot = double octet ou quadruple entier)
sz  zero-terminated string (chaine de caractères terminée par un char zéro)
o   object (objet)
str	string (chaine de caractères)

modificateurs	description
u   unsigned (non signé)
p   pointer (pointeur)
a   array (tableau)
g_  global variable (variable globale)

exemple :
paulExemple1  pointeur sur un tableau d'entiers long non signés.
Chez moi, l'indentation de la fermeture des blocs d'instruction   }   est décalée pour se trouver à la suite du bloc, cela me parrait plus naturel.

Pour moi, la lisibilité du code prime sur sa longueur du code et même parfois sur son efficacité.
Par exemple, les commandes suivantes son à bannir, c'est à mon avis une erreur qu'elles ne provoquent pas d'erreur.
if (a = b == 1) { ... }
if (a++ == 1) { ... }  // L'incrémentation est faite après le test.
if (++b == 1) { ... }  // L'incrémentation est faite avant le test.
Remplacer le premier exemple par :
a = b;
if (b == 1) { ... }
C'est une ligne de plus, mais plus lisible et évite des risques d'erreurs.

Remplacer l'autre exemple par :
a++;  // Ou a += 1:
if (a == 2) { ... }

b++;  // Ou b += 1:
if (b == 1) { ... }

Je compile tous mes code avec le but d'obtenir 0 warnings.
Tout "warning" doit être considéré comme une erreur.


6) Un premier exemple, "Hello world" avec suppléments.   Top

Il est coutume d'écrire un premier programme qui affiche "Hello world".
Le jeux de caractères par défaut est codé en utf-8, donc les caractères accentués sont affichés.

J'ai ajouté les fonctionnalités suivantes :
Le programme "Hello world" :

7) printf, les "specifiers" ou les "data type".   Top

printf les "specifiers", c'est très clairement expliqué.
data types de wikipedia".
Quelques "specifiers", c'est incomplet et moins bien que les deux liens ci-dessus.
%d (%i)  %u  %x  %X  %ld  %lu  %lx  %lld  %llu  %f  %e  %g  %c  %s  %%
Quelques exemples :
string.h, la bibliothèque de manipulation de chaines de caractères en C.
sprintf, conversion de nombre et plus en string.


8) None blocking "getc()", lecture d'un caractère au clavier, sans arrêter l'exécution.   Top

Le programme getc(), non blocant

9) Lecture des touches pressées du clavier, sans arrêter l'exécution.   Top

Permet de voir les différents codes des touches.
Chaque touche a un code.
À partir de ce code, on peut connaître le symbole qui lui est associé.
Ce symbole est modifié en fonction de l'état des touches Shift, Alt Gr, Ctrl, et Caps Lock.
On obtient également le UNICODE du symbole correspondant, s'il y en a un.
On obtient également le code UTF-8 du symbole correspondant, s'il y en a un.
Tous les caractères ont un UNICODE et un code UTF-8, mais certains symboles, comme "HOME", "END, "Page Up", ... n'ont pas de UNICODE ni de code UTF-8.

Pour des convertisseurs : UNICODE - UTF-8 - caractères, voici trois liens :
Convertisseur de code Unicode 13.0/ISO 10646:2020, très bien, beaucoup de codage.
Quelques tables de caractères
UTF-8 encoding table and Unicode characters
Wikipedia sur UTF-8, explique clairement le lien entre UNICODE et UTF-8.
Il est assez simple de convertir un UNICODE en UTF-8 et inversément.
Le codage UTF-32 est égale à l'UNICODE, c'est son avantage, mais il prend beaucoup de place.
Si le nombre UNICODE < 256, alors il correspond au code ISO/CEI 8859-1, utilisé par défaut sous Windows.
Le programme Keyboard_state(), non blocant
/*
ex0030_keyboard_state.c

Pour la compilation : 
gcc -Wall -o ex0030_keyboard_state  ex0030_keyboard_state.c -lX11  -lxkbcommon

Dans Geany, Construire > Définir les commande de construction > Build   pour  F9
gcc -Wall -o "%e"  "%f" -lX11 -lxkbcommon

Pour X11 c.f. /usr/include/X11
Pour xkbcommon c.f. /usr/include/xkbcommon
Il cherche les fichiers dans :
/usr/lib/x86_64-linux-gnu/libxkbcommon  avec l'extension  .so  ou  .a
/usr/lib/x86_64-linux-gnu/libX11  avec l'extension  .so  ou  .a

Voir :
/usr/include/linux/input.h
/usr/include/stdio.h    c.f. https://man7.org/linux/man-pages/man3/stdio.3.html

Pour les code clavier
/usr/include/linux/input-event-codes.h
Il y a un décalage de 8 entre le keycode défini ici et celui qu'il faut transmettre à  XkbKeycodeToKeysym  !?!

https://www.kernel.org/doc/man-pages/   Manuel

La fonction XQueryKeymap  retourne un vecteur de bits indiquant l'état du clavier.

c.f. :
https://linux.die.net/man/3/xquerykeymap
https://www.systutorials.com/docs/linux/man/3-XQueryKeymap/
https://tronche.com/gui/x/xlib/function-index.html

Un  keycode  est le code d'une touche clavier
un  keysym   est le code du symbole qui lui est associé.
un  keyunicode  est le  unicode  du caractère
un  keyutf8  est la séquence d'octets du code utf-8 du caractère
Il y a aussi le nom du symbole associé
Finalement, il y a le caractère lui-même.

La page suivante donne des explications sur le codage UTF-8, 
en particulier, comment passer de  UNICODE  à  UTF-8  dans les deux sens. C'est assez simple.
https://fr.wikipedia.org/wiki/UTF-8

Pour voir les  caractères associés au  keysym  : 
https://www.commentcamarche.net/faq/6988-redefinir-les-touches-du-clavier   autre réf. en français, intéressante.


Commande à taper dans un Terminal pour voir les codes des touches :
xev    !!!!!!!!!!!!!!!!!!

Commande permetant depuis un Terminal de connaître l'état des touches et de les modifier.
xset  
c.f. : https://www.computerhope.com/unix/uxset.htm

Autre commande permettant d'agir sur le clavier :
xdotool

// Pour tkinter, c.f. la table complète de correspondance des <bind Key-keysym> :
// https://man.cx/keysyms

*********************************************************************/

#include <stdio.h>  // Pour : printf(...)  

#include <X11/XKBlib.h>  // Pour XkbKeycodeToKeysym(...)

// Pour des mesures de temps, non essentiel, mais utilisé dans ce programme.
#include <time.h>

// C.f. : https://github.com/xkbcommon/libxkbcommon/tree/master/src
// Pour les fonctions :
// xkb_keysym_to_utf8, qui retourne le code utf-8 de la touche lorsqu'elle représente un caractère
// xkb_keysym_to_utf32, qui retourne le code unicode de la touche lorsqu'elle représente un caractère
// Il faut inclure l'option de compilation : -lxkbcommon
#include <xkbcommon/xkbcommon.h>  // Inclu <stdio.h>, donc il n'est pas indispensable d'include <stdio.h> dans ce programme.

// Pour afficher les caractères selon leur code utf-8 ou unicode
// Pour la fonction : setlocale(LC_ALL, "");
#include <locale.h>

// C.f. : https://fr.wikipedia.org/wiki/ISO/CEI_10646
// La norme  ISO/CEI 10646  tente de définir un système de codage universel pour tous les systèmes d'écriture.
// C'est le fondement du standard Unicode.
// C'est le même codage que l'UTF-32, qui code chaque caractère par son Unicode.
// L'UTF-8 code chaque caractère sur 1, 2, 3 ou 4 octets, suivant le caractère. Les caractères ASCII sont codés sur un octet, il y a compatibilité.
// Test que __STDC_ISO_10646 est défini
#ifndef __STDC_ISO_10646__
#error "Oops, our wide chars are not Unicode codepoints, sorry!"
#endif


int convertUnicode_utf8(int nOption, uint32_t *pwUnicode, unsigned char *acUtf8) {
//================================================================================
// Conversion de UNICODE en UTF-8 et inverse.
// La fonction est inutile, car ces conversions existent déjà en C, c.f. plus bas.
// C.f. : https://fr.wikipedia.org/wiki/UTF-8
// Si nOption == 0, conversion de UNICODE vers UTF-8
// Sinon, conversion de UTF-8 vers UNICODE
// acUtf8 doit être un tableau de longueur au moins 5 pour la conversion vers UTF-8. Il terminera par 0
// Sinon, c'est lui qui contient le code UTF-8 à convertir en UNICODE.
// L'UNICODE < 255 correspond au codage ISO/CEI 8859-1   C.f. : https://fr.wikipedia.org/wiki/Unicode#Plan_multilingue_de_base_(PMB,_0000_à_FFFF)
// Retourne 0 si la conversion c'est bien produite, 1 s'il y a eu une erreur.

if (nOption == 0) { // Conversion vers UTF-8
  
  if (*pwUnicode <= 0x7F) { // Code ASCII
    // Codage UTF-8 sur 1 octet
    acUtf8[0] = (char)*pwUnicode;
    acUtf8[1] = 0;
    return 0;
    }
  
  if (*pwUnicode <= 0x7FF) { // 0x7FF = 2047
    // Codage UTF-8 sur 2 octets
    acUtf8[2] = 0;
    acUtf8[1] = (char)(0x80 + *pwUnicode % 0x40); // 6 bits de poids faible, bits 0 à 5
    acUtf8[0] = (char)(0xC0 + *pwUnicode / 0x40); // 5 bits de poids fort, bits 6 à 11  ==  6 bits de poids fort vu que le bit_11 == 0
    return 0;
    }

  if (*pwUnicode <= 0xFFFF) { // 0xFFFF = 65'535
    // Codage UTF-8 sur 3 octets
    acUtf8[3] = 0;
    acUtf8[2] = (char)(0x80 +  *pwUnicode % 0x40); // 6 bits de poids faible, bits 0 à 5
    acUtf8[1] = (char)(0x80 + (*pwUnicode / 0x40) % 0x40); // bits 6 à 11
    acUtf8[0] = (char)(0xE0 + (*pwUnicode / 0x1000) % 0x40); // bits 12 à 15
    return 0;
    }

  if (*pwUnicode <= 0x10FFFF) { // 0x10FFFF = 1'114'111
    // Codage UTF-8 sur 4 octets
    acUtf8[4] = 0;
    acUtf8[3] = (char)(0x80 + *pwUnicode % 0x40); // 6 bits de poids faible, bits 0 à 5
    acUtf8[2] = (char)(0x80 + (*pwUnicode / 0x40) % 0x40); // bits 6 à 11
    acUtf8[1] = (char)(0x80 + (*pwUnicode / 0x1000) % 0x40); // bits 12 à 17   (0x40 * 0x40 = 0x1000)
    acUtf8[0] = (char)(0xF0 + (*pwUnicode / 0x40000) % 0x40); // bits 18 à 21  (0x40 * 0x40 * 0x40 = 0x40000)
    return 0;
    }
  }
else { // Conversion vers UNICODE

  if ((acUtf8[0] & 0x80) == 0) { // Code ASCII
    // Codage UTF-8 sur 1 octet
    *pwUnicode = acUtf8[0];
    return 0;
    }

  if ((acUtf8[0] & 0xE0) == 0xC0) {
    // Codage UTF-8 sur 2 octets
    *pwUnicode = (acUtf8[0] & 0x3F) * 0x40 + (acUtf8[1] & 0x3F); // 2 paquets de 6 bits. Lit bit n°11 (celui de gauche) est toujours à 0.
    return 0;
    }

  if ((acUtf8[0] & 0xF0) == 0xE0) {
    // Codage UTF-8 sur 3 octets
    *pwUnicode = (acUtf8[0] & 0x0F) * 0x1000 + (acUtf8[1] & 0x3F) * 0x40 + (acUtf8[2] & 0x3F); // 1 paquet de 4 bits et 2 paquets de 6 bits.
    return 0;
    }

  if ((acUtf8[0] & 0xF0) == 0xF0) {
    // Codage UTF-8 sur 4 octets
    *pwUnicode = (acUtf8[0] & 0x07) * 0x40000 + (acUtf8[1] & 0x3F) * 0x1000 + (acUtf8[2] & 0x3F) * 0x40 + (acUtf8[3] & 0x3F); // 1 paquet de 3 bits et 3 paquets de 6 bits.
    return 0;
    }
  }

return 1;
} // convertUnicode_utf8


int main() {
//==========
//time_t tNow = time(NULL);  // Temps en secondes, pas assez précis pour moi
clock_t tNow  = clock();   // Maintenant, en nombre de cycles d'horloge
clock_t tLast = clock();   // Temps du dernier affichage, nombre de cycles
unsigned char abKeys_return[32];  // Tableau de bits représentant l'état des touches du clavier
XKeyboardState structKeyboardState;  // État du Caps Lock, du Num Lock et du Scroll Lock. C'est un "struct", 
                                     // c.f. : https://linux.die.net/man/3/xkeyboardcontrol   et   https://doc.servo.org/x11/xlib/struct.XKeyboardState.html
int nKeyCode = 0;
int nKeyCodeMem = 0; // Code de la touche pressée, correspondant à une autre touche que Shift, Ctrl, Alt, Alt Gr, Super  (Super = la touche Windows).
unsigned int wEventMask = 0;  // ShiftMask==1;  LockMask==2;  CtrlMask==4;  Mod1Mask==8 (Alt);  Mod2Mask==16;  Mod3Mask==32;
                              // C.f. : /usr/include/X11/X.h                Mod4Mask==64;       Mod5Mask==128
// Pour indiquer les touches Shift, Ctrl, Alt, Alt Gr, Super pressées.
Bool fShift_L = False;
Bool fShift_R = False;
Bool fCtrl_L = False;
Bool fCtrl_R = False;
Bool fAlt_L = False;
// Bool fAlt_R = False;  N'existe pas
Bool fAlt_Gr = False;
Bool fSuper_L = False;
Bool fSuper_R = False;
Bool fCaps_Lock = False;
Bool fNum_Lock = False;

KeySym ulKeysym;   // KeySym du caractère du clavier. Si < 255, correspond au UNICODE du caractère, mais pas sinon.
uint32_t wKeyUnicode; // UNICODE du caractère
uint32_t wKeyUnicode2; // UNICODE du caractère, pour éviter l'affichage des caractères de contrôle
char acUtf8_string[13]; // Pour avoir la suite d'octets du codage UTF-8  du caractère.
unsigned char abUtf8_code[8]; // Pour avoir le codage UTF-8 d'un caractère, utile pour imprimer le caractère.
int nLenUTF8 = 0; // Longueur du codage UTF-8, de 1 à 4 octets.   ==1 octet pour les caractères ASCII


// Pour que les caractères  UNICODE  non ASCII puissent s'afficher.
setlocale(LC_ALL, "");

printf("\ec"); // Efface le contenu du Terminal

//printf("XK_Shift_L = %xd", XK_Shift_L); // = 0xffe1 C.f. /usr/include/X11/keysmdef.h
printf("\n\n");
printf("\e[s"); // sauve la position courante du curseur

while (1) {  // Boucle infinie
  // Attend de quelques centièmes de secondes
  // 1.0*(tNow - tLast)/CLOCKS_PER_SEC)  donne le temps en secondes, en virgule flottante
  tLast = clock();
  while (1.0*(tNow - tLast)/CLOCKS_PER_SEC < 0.05) { tNow = clock(); }

  // Lecture de l'état des touches du clavier
  Display* dpy = XOpenDisplay(NULL);
  XQueryKeymap( dpy, (char*)abKeys_return ); // c.f. https://tronche.com/gui/x/xlib/input/XQueryKeymap.html

  // Lecture de l'état du Caps Lock et du Num Lock
  XGetKeyboardControl(dpy, &structKeyboardState); 
  // structKeyboardState.led_mask & 1 != 0  si Caps Lock est ON
  // structKeyboardState.led_mask & 2 != 0  si Num Lock est ON
  // structKeyboardState.led_mask & 4'294'961'148 != 0  si Scroll Lock est ON    4'294'961'148 == 2^32 - 6142 == 2^32 - 2^12 - 2^11 + 4

  // Parcours toutes les touches du clavier, pour déterminer celles qui sont pressées.
  // Tiens compte de Shift, Alt Gr, Ctrl et Windows key  pour mémoriser une touche qui a une chance de correspondre à un caractère.
  // Si plusieurs touche de caractères sont pressées simultanément,
  // affiche le code de chacune des touches, mais ne traite entièrement que celle de plus grand code  (nKeyCodeMem).
  wEventMask = 0;
  nKeyCode = 0;
  nKeyCodeMem  = 0;
  fShift_L = False;  fShift_R = False;  fCtrl_L = False;  fCtrl_R = False;  fAlt_L = False;  fAlt_Gr = False;  
  fSuper_L = False;  fSuper_R = False;  fCaps_Lock = False;  fNum_Lock = False;  
  for (int nn=0; nn<32; nn++) {
    for (int kk=0; kk<8; kk++) {
      nKeyCode = 0;
      if ((abKeys_return[nn] & (1<<kk)) > 0) nKeyCode = 8*nn + kk;
      if (nKeyCode ==  50) { // Shift Gauche pressée
        fShift_L = True;
        wEventMask |= ShiftMask;
        }
      else if (nKeyCode ==  62) { // Shift Droite pressée
        fShift_R = True;
        wEventMask |= ShiftMask;
        }
      else if (nKeyCode == 108) { // Alt Gr pressée
        fAlt_Gr = True;
        wEventMask |= 2;
        }
      else if (nKeyCode ==  37) { // Ctrl Gauche pressée
        fCtrl_L = True;
        }
      else if (nKeyCode ==  64) { // Alt Gauche pressée
        fAlt_L = True;
        }
      else if (nKeyCode == 105) { // Ctrl Gauche pressée
        fCtrl_R = True;
        }
      else if (nKeyCode == 133) { // Super Gauche pressée // Windows key ( == Super key )
        fSuper_L = True;
        }
      else if (nKeyCode == 134) { // Super Droit pressée
        fSuper_R = True;
        }
        
      else if (nKeyCode != 0) nKeyCodeMem = nKeyCode; 
      } // for
    } // for

  // Change l'état majuscule - minuscule, mais seulement pour des lettres.
  if ( (structKeyboardState.led_mask & 1) > 0) { 
    // Caps Lock est  ON
    fCaps_Lock = True;
    ulKeysym = XkbKeycodeToKeysym(dpy, nKeyCodeMem, 0, 0);  // Lecture du caractère correspondant à la touche pressée. 
                                                             // Pas de distinction majuscule - minucules à cet endroit.    
    if ( (ulKeysym >= 'a') && (ulKeysym <= 'z') ) {
      if ( (wEventMask & ShiftMask) == 0 ) wEventMask |= ShiftMask;
      else                                 wEventMask &= ~ShiftMask;
      }
    }
  if ( (structKeyboardState.led_mask & 2) > 0) fNum_Lock = True;
    
  // Conversion de l'état du clavier en un caractère correspondant
  ulKeysym = XkbKeycodeToKeysym(dpy, nKeyCodeMem, 0, wEventMask);

  XCloseDisplay(dpy);

  // Numérotation
  for (int nn=0; nn<16; nn++) printf("%4x", nn);
  
  // Affichage de l'état du Caps Lock (1) et du Num Lock (2)
  printf("  Caps + Num Lock = %ld \n", structKeyboardState.led_mask);
  
  // Affichage des 16 premier octets d'état du clavier
  for (int nn=0; nn<16; nn++) printf("%4d", (unsigned  char)abKeys_return[nn]);
  printf("\n\n");

  // Numérotation
  for (int nn=16; nn<32; nn++) printf("%4d", nn);
  printf("\n");
  
  // Affichage des 16 premier octets d'état du clavier
  for (int nn=16; nn<32; nn++) printf("%4x", (unsigned  char)abKeys_return[nn]);
  printf("\n");

  // Pour effacer deux lignes
  printf("                                                                                              \n"); 
  printf("                                                                                                  \n\e[2A"); // "\e[2A"  pour remonter de deux lignes
  
  // Affichage des codes clavier  keycode  des touches pressées. 
  // Il peut y en avoir plusieurs, en particulier Shift, Ctrl, Alt, Alt Gr et la touche windows.
  // Pour la correspondance entre la touche et le symbole, pour le clavier Américain, c.f. :
  // /usr/include/linux/input-event-code.h    Il y a un décalage de  8.   C.f le programme  xev  pour comparer.
  for (int nn=0; nn<32; nn++) {
    for (int kk=0; kk<8; kk++) {
      if ((abKeys_return[nn] & (1<<kk)) > 0) printf("%4d", 8*nn + kk);
      } // for
    } // for

  // Affiche l'état des touches Shift, Ctrl, Alt, Alt Gr, Super, Caps Lock et Num Lock
  printf("\nShift-Crtl-alt-super   Lock(Caps, Num) =");
  if (fShift_L) printf("  S_L");
  if (fShift_R) printf("  S_R");
  if (fAlt_Gr) printf("  A_Gr");
  if (fCtrl_L) printf("  C_L");
  if (fCtrl_R) printf("  C_R");
  if (fAlt_L) printf("  A_L");
  if (fSuper_L) printf("  Sup_L");
  if (fSuper_R) printf("  Sup_R");
  printf("   ");
  if (fCaps_Lock) printf("  Caps_Lock");
  if (fNum_Lock) printf("  Num_Lock");
  printf("\n");
  
  // Affichage du UNICODE de symbole correspondant à la touche pressée, ainsi que du symbole lui-même.
  if (ulKeysym != 0){
    // Converti le code du caractère en son UNICODE
    wKeyUnicode = xkb_keysym_to_utf32((xkb_keysym_t)ulKeysym);

    // Pour avoir le code UTF-8 du caractère tapé au clavier               abUtf8_code doit être de taille au moins 7.
    // c.f. https://xkbcommon.org/doc/0.2.0/group__keysyms.html
    // Convertit le code du caractère (ulLeysym) en son codage UTF-8 (abUtf8_code) et retourne le nombre d'octets UTF-8 du codage.
    nLenUTF8 = xkb_keysym_to_utf8((xkb_keysym_t)ulKeysym, (char*)abUtf8_code, 8);  // abUtf8_code[nLenUTF8-1] == 0
    if (nLenUTF8 == 2)
       sprintf(acUtf8_string, "         %2x", abUtf8_code[0]);
    else if (nLenUTF8 == 3)
       sprintf(acUtf8_string, "      %2x %2x", abUtf8_code[0], abUtf8_code[1]);
    else if (nLenUTF8 == 4)
       sprintf(acUtf8_string, "  %2x %2x %2x", abUtf8_code[0], abUtf8_code[1], abUtf8_code[2]);
    else if (nLenUTF8 == 5)
       sprintf(acUtf8_string, "%2x %2x %2x %2x", abUtf8_code[0], abUtf8_code[1], abUtf8_code[2], abUtf8_code[3]);

  
    printf("Keycode  Keysym  UNICODE(dec, hex)  UTF-8(hex.)     Symbole  Caractère    Shift & Alt Gr\n");
    printf("                                                                                                  \n\e[1A"); // Pour effacer la ligne suivante et la remplacer
    
    wKeyUnicode2 = wKeyUnicode;
    if (wKeyUnicode2 < 32) wKeyUnicode2 = 32; // Remplace les caratères de contrôle par un espace

    printf("%7d %7ld  %7u, %#7x %12s %12s     %lc        ", nKeyCodeMem, ulKeysym, wKeyUnicode, wKeyUnicode, acUtf8_string, XKeysymToString(ulKeysym), wKeyUnicode2);
    if (fShift_L) printf("  S_L");
    if (fShift_R) printf("  S_R");
    if (fAlt_Gr) printf("  A_Gr");
    if (fCtrl_L) printf("  C_L");
    if (fCtrl_R) printf("  C_R");

    //convertUnicode_utf8(0, &wKeyUnicode, abUtf8_code);  printf("  %x  %x  %x  %s", abUtf8_code[0], abUtf8_code[1], abUtf8_code[2], abUtf8_code); // Pour vérification
    //convertUnicode_utf8(1, &wKeyUnicode, abUtf8_code);  printf("  %#x", wKeyUnicode); // Pour vérification

    printf("\n");
    }
  else printf("\n\n");    

  //printf("\e[9A"); // remonte le curseur de 9 lignes. La commande suivante est meilleure
  printf("\e[u"); // restore la position du curseur
  
  if (abKeys_return[1] == 2) break;  // ESC pressé, arrêt du programme
  } // while
} // main



Home arrow c_lang.html
Mise à jour le 4 juin 2021 par Libre Gisin.