10
votes

Lecture du rapport de périphérique Rapport de l'état ANSI Escape Séquence Répondre

J'essaie de récupérer les coordonnées du curseur dans une borne VT100 à l'aide du code suivant: xxx

J'utilise la séquence d'échappement ANSI suivante:

rapport d'état du périphérique - ESC [6N

rapporte la position du curseur à la application comme (comme si elle est saisie au clavier) ESC [N; MR, où n est la ligne et m est la colonne.

Le code compile et la séquence ANSI est envoyée, mais, lors de la réception, le terminal imprime le ^ [[[x; yr chaîne sur stdout Au lieu de stdin , ce qui le rend impossible pour moi de le récupérer à partir du programme:

 Fenêtre Terminal

Clairement, la chaîne est désignée pour le programme, cependant, je dois donc faire quelque chose de mal à tort. Est-ce que quelqu'un sait ce qu'il est?


0 commentaires

4 Réponses :


4
votes

Votre programme fonctionne mais attend un personnage EOL.

scanf est orienté ligne afin qu'il attend une nouvelle ligne avant le traitement. Essayez d'exécuter votre programme puis appuyez sur la touche Entrée.

La solution consiste à utiliser quelque chose d'autre qui n'a pas besoin d'une nouvelle ligne pour lire l'entrée, puis utilisez SSCANF pour analyser les valeurs.

Vous aurez également besoin de rendre STDIN non bloquant ou vous n'obtiendrez pas l'entrée tant que le tampon est plein ou que STDIN est fermé. Voir cette question Faire blocage de stdin

Vous devez également appeler fflush (stdout); après que votre Printf pour vous assurer qu'il est réellement écrit (PrintF est souvent la ligne tamponnée, donc sans nouvelle ligne, il peut ne pas rincer le tampon).


4 commentaires

N'y a-t-il pas une façon de rendre la commande ANSI ne pas écrire ^ [[x; yr à la borne du tout? Je voudrais extraire silencieusement les coordonnées sans aucun changement visible sur l'écran du terminal. Mais cela écrit sur le terminal (indésirable lors de la création d'une interface graphique textuelle) et modifie ainsi les coordonnées du curseur (ce qui le rend absolument inutile).


C'est pourquoi les malédictions (et les ncurses) existent pour que vous n'ayez pas à vous soucier de tous ces détails.


Bien sûr, mais les ncurses sont un bloatware. C'est pourquoi j'écris mes propres séquences d'échappement ANSI léger ANSI LIB, qui soutient simplement VT100. Mais oui, on dirait que je vais juste avoir à DL NCurses et essayer d'inverser l'ingénieur pour trouver sa solution à ce problème.


Je pense que les ncurses ne tiennent pas une trace de l'endroit où le curseur est en interne ou le déplace vers un emplacement connu avant la sortie. Il faut parce que certains terminaux ne peuvent pas signaler le lieu actuel.



6
votes

Je demande la position du curseur. Si je n'ai pas de réponse après 100 ms (ceci est arbitraire), je suppose que la console n'est pas une ANSI. xxx


0 commentaires

0
votes

Je crois que vous obtenez vraiment la réponse attendue à Stdin. Mais imaginez ce qui se passe réellement:

  • Vous envoyez une demande en tant que séquence d'évacuation à Stdout
  • Le terminal le reçoit et formule une réponse correspondante comme séquence d'évacuation aussi bien
  • La réponse est envoyée à Stdin
  • Scanf est appelé et STDIN est redirigé via la coquille où la bibliothèque Readline est utilisée pour une entrée utilisateur interactive et modifiable
  • readline captures la séquence d'échappement plutôt que de le transmettre au terminal
  • LIVELLINE RÉ-FULLAZ LE RE-FULLALE SANS PAS DE PACAGE ESC pour empêcher l'exécution de la séquence de contrôle, mais la rend plutôt lisible en utilisant uniquement des caractères imprimables
  • La réponse bizarre atteint Scanf mais c'est trop tard
  • La réponse bizarre est également résonnée à STDOUT afin que l'utilisateur puisse voir instantanément ce qu'elle a tapé.

    Pour éviter cela, utilisez un getc () ( == fget (stdin) ) boucle à la place. Si vous rencontrez un ESC ( 0x1b ) que de vider les caractères suivants d'une chaîne jusqu'à ce que vous trouviez le délimiteur final de la séquence ESC (dans votre cas 'n' ). Après cela, vous pouvez utiliser sscanf (esqstring, formaformer, ...) .

    Mais avant de rencontrer la boucle, vous devez Modifier avec TERMIOS en mode RAW (regardez l'exemple de code ci-dessous) . Sinon rien ne serait différent.


0 commentaires

0
votes
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>

void readCoord(void* row, void* col){
    int i = 0;
    char* input = malloc(10);
    printf("\e[6n");
    while(!_kbhit()) _sleep(1);
    while(_kbhit()) *(input + (i++)) = getch();
    *(input + i) = '\0';
    sscanf(input, "\e[%d;%dR", row, col);
}

void main(void){
    int i = 0, r, c;
    char* coord = malloc(10);
    printf("Hello");
    readCoord(&r , &c);
    printf("\nYour coordinate is (%d, %d)", c, r);
}
_kbhit() is used to detect input (DSR are treated as though typed at the keyboard), and
getch() to read and remove the character from standard inputThis program relies on conio.h, which is not a standard and hence not recommended for portable C programs.

0 commentaires