Comment obtenir la largeur de la fenêtre du terminal?

Je travaille sur un système embarqué utilisant C et linux . L’utilisateur peut se connecter au périphérique via SSH ou un câble série de console. Il peut le faire via PuTTY ou Tera Term. Ma question est, après qu’il soit connecté, comment puis-je connaître la largeur de sa fenêtre? J’ai essayé différentes approches, elles fonctionnent si je simule mon système sur un PC Linux, mais aucune d’entre elles ne fonctionne sur le périphérique:

  1. ioctl()

     struct winsize ws; ioctl(..., TIOCGWINSZ, &ws); 

    Cette méthode fonctionne sur pc, mais renvoie toujours 0 sur le périphérique.

  2. tgetnum()

     setupterm((char *)0, 1, (int *)0); CGR_INT columns = tgetnum("co"); 

    Cette méthode fonctionne sur pc, mais renvoie toujours 80×24 sur le périphérique.

  3. getmaxyx()

     CGR_INT xdim; CGR_INT ydim; initscr(); refresh(); getmaxyx(stdscr, ydim, xdim); 

    Cette méthode fonctionne sur pc, mais renvoie toujours 0 sur le périphérique

J’utilise ce code pour imprimer un groupe de signes d’égalité en tant que diviseur. Fonctionne dans la plupart des cases / termes que j’ai essayés. Vous ne savez pas de quels appareils vous parlez. La peine d’essayer je suppose 😉

 #include  #include  #include  int main(int argc, char *argv[]) { struct winsize ws; ioctl(0, TIOCGWINSZ, &ws); int i=0; for(;i<10*ws.ws_col;++i) printf("="); printf("\n"); return 0; } 

TIOCGWINSZ est la voie à suivre. Votre appareil en question doit annoncer sa taille, sinon cela ne fonctionnera pas. Prenons xterm comme exemple:

 device —— ttyS driver —— ttyS0 devnode —— screen/minicom xterm —— pty devnode —— pty driver —— pts devnode —— bash 

xterm fait ioctl (TIOCSWINSZ) la première fois qu’il est créé pour informer le pilote tty de la taille de la fenêtre. bash et les programmes qui en découlent peuvent alors s’enquérir. Si vous redimensionnez la fenêtre xterm, il indiquera la nouvelle taille au pilote tty. Xterm émettra également SIGWINCH à son processus enfant (bash dans ce cas) pour l’informer du changement de taille.

Rien de tout cela ne se produit avec des appareils (comme le vôtre) qui n’ont aucune idée de ce à quoi ils sont connectés. Le pilote tty ne sait pas non plus ce qui est connecté. Xterm peut indiquer la taille au pilote, car il peut émettre un ioctl, mais les ioctls ne sont pas transportés via un port série, par exemple. Ce qu’il faudrait en théorie, c’est un pilote de kernel spécialisé qui sait comment communiquer les changements de taille à votre périphérique particulier (peut-être un protocole au-dessus du port série de sorte qu’aucune réécriture d’un composant principal ne soit nécessaire).

Notez que le périphérique connecté peut ne même pas avoir le concept de région fixe. Par exemple, une imprimante peut être considérée comme ayant un nombre de lignes pratiquement infini.

ncurses suppose simplement 80×24 s’il voit 0x0, parce que le programmeur l’a défini ainsi. Cette taille peut ne pas être correcte, et dans la pratique ce n’est généralement pas le cas, car les utilisateurs peuvent redimensionner leurs fenêtres (même s’ils ne le peuvent pas, comme sur tty1, ils peuvent toujours utiliser des éléments tels que screen (1) et réduire la taille à moins de 80×24 ).

Une ligne série n’a pas de moyen de négocier la taille du terminal. Lancer un vrai xterm et.al. Sur une paire de périphériques TTY / PTY, TIOCSWINSZ la paire TIOCSWINSZ / TIOCGWINSZ ioctl() pour transmettre ces informations.

Traditionnellement, ces informations étaient conservées dans termcap ou terminfo propos des termcap physiques réels avec une couche de verre avec phosphore, tels qu’un DEC VT220. Il s’agit d’une firebase database fixe statique de valeurs connue à l’avance, qui était exacte à l’époque où un “terminal” était littéralement ce matériel fixe, mais qui ne fonctionne pas très bien à notre époque où les terminaux ne sont qu’un programme. qui attire vers un framebuffer ou similaire.

Je suggérerais que la meilleure méthode serait d’essayer TIOCGWINSZ , si cela échoue, utilisez tgetnum("co") terminfo , et si cela échoue, présumez simplement 80×24.