Dans cet article, je vais vous montrer comment utiliser le langage Go pour obtenir une entrée de terminal en temps réel. Cette fois, je voudrais vous présenter uniquement le système d'exploitation UNIX. Dans le cas de Windows, il semble que cela puisse être réalisé avec l'API fournie par Microsoft ... (recherche insuffisante)
En mettant le terminal en mode non canonique, vous pouvez obtenir une entrée instantanément. Pour passer en mode non canonique, vous devez modifier les valeurs dans les champs de la structure termios. Dans ce qui suit, chaque mode est expliqué avec un exemple de code et un manuel Linux.
Avant de discuter du mode non canonique, parlons d'abord du mode canonique. Pour faire simple, c'est l'état par défaut. L'entrée est acceptée jusqu'à ce que vous appuyiez sur Entrée.
Citation manuel de traduction en japonais pour Linux
--L'entrée se fait ligne par ligne. La ligne d'entrée devient disponible lorsque le caractère de saut de ligne est tapé. Les délimiteurs de ligne sont NL, EOL, EOL2 et EOF au début d'une ligne. Pour les non-EOF, le tampon renvoyé par read (2) comprend également des séparateurs de ligne
L'édition de ligne est activée (ERASE, KILL ont un effet; WERASE, REPRINT, LNEXT ont également un effet si l'indicateur IEXTEN est activé). read (2) renvoie au plus une ligne d'entrée. Si read (2) demande moins d'octets que la ligne d'entrée courante, seul le même nombre d'octets demandés sera lu et les caractères restants seront lus lors de la lecture suivante (2).
Mode non canonique, ce mode peut accepter des entrées en temps réel. Vous pouvez définir le nombre de caractères acceptés avec MIN (c_cc [VMIN]). Par exemple, si c_cc [VMIN] = 3, l'entrée sera terminée et le programme sera chargé lorsque 3 caractères seront saisis. Vous pouvez définir le délai d'expiration avec TIME (c_cc [VTIME]) et le mettre à 0 si vous n'avez pas besoin de délai.
Citation manuel de traduction en japonais pour Linux
--En mode non canonique, l'entrée est immédiatement disponible (l'utilisateur n'a pas besoin de taper des sauts de ligne), aucun traitement d'entrée n'est effectué et l'édition de ligne est désactivée. Les paramètres de MIN (c_cc [VMIN]) et TIME (c_cc [VTIME]) déterminent les conditions dans lesquelles read (2) se termine.
En langage C, utilisez les fonctions de "termios.h" pour accéder à la structure termios. J'emprunterai le package pkg / term créé par des volontaires afin qu'il puisse également être utilisé dans le langage Go. Lorsque vous modifiez les paramètres de la structure termios, utilisez Tcgetattr () pour obtenir les paramètres actuels, puis effectuez les réglages nécessaires pour les opérations sur les bits. Pour les paramètres qui peuvent être définis, reportez-vous au Manuel de traduction en japonais pour Linux. À propos, les indicateurs qui peuvent être utilisés en langage C pourraient également être utilisés dans le package pkg / term. Une fois que vous avez terminé les paramètres requis, vous pouvez les refléter avec Tcsetattr ().
sample.go
package main
import (
"fmt"
"syscall"
"github.com/pkg/term/termios"
)
func main() {
var ttystate syscall.Termios
//Obtenir les paramètres du terminal
termios.Tcgetattr(uintptr(syscall.Stdin), &ttystate)
//Modifier les paramètres du terminal
setNonCanonicalMode(&ttystate)
//Obtenez une entrée standard
bufCh := make(chan []byte, 1)
go readBuffer(bufCh)
for {
fmt.Printf("Ce que vous avez tapé: %c\n", <-bufCh)
}
}
//Définir en mode non canonique
func setNonCanonicalMode(attr *syscall.Termios) {
//Désactiver le mode canonique (&^ AND NOT)
attr.Lflag &^= syscall.ICANON
//Nombre minimum de caractères lors de la lecture=Un personnage
attr.Cc[syscall.VMIN] = 1
//Délai d'expiration lors de la lecture non canonique= 0
attr.Cc[syscall.VTIME] = 0
//Refléter les paramètres modifiés
termios.Tcsetattr(uintptr(syscall.Stdin), termios.TCSANOW, attr)
}
//Obtenez la valeur du tampon
func readBuffer(bufCh chan []byte) {
buf := make([]byte, 1024)
for {
if n, err := syscall.Read(syscall.Stdin, buf); err == nil {
bufCh <- buf[:n]
}
}
}
Lorsque le code ci-dessus est exécuté, le comportement est le suivant. Printf est exécuté après l'affichage de la clé saisie à l'écran. En passant, si vous augmentez la valeur de VMIN, vous pouvez obtenir plusieurs valeurs.
Outre les fonctionnalités du mode non canonique, les touches que vous saisissez n'apparaissent pas à l'écran. De plus, comme le traitement spécial ne fonctionne pas, vous ne pouvez pas forcer l'arrêt avec Ctrl + C.
Citation manuel de traduction en japonais pour Linux
-L'entrée est possible caractère par caractère, l'écho est désactivé et tout traitement spécial pour les caractères d'entrée / sortie du terminal est désactivé.
Il s'agit d'un modèle défini en mode Raw comme indiqué dans Manuel de traduction en japonais pour Linux. (* J'ai commenté les parties que j'ai jugées inutiles.) Vous pouvez le régler selon le manuel sans penser comme le code ci-dessous, mais je pense qu'il est préférable de sélectionner le paramètre de réglage selon les besoins.
sample.go
package main
import (
"fmt"
"syscall"
"github.com/pkg/term/termios"
)
func main() {
var ttystate syscall.Termios
//Obtenir les paramètres du terminal
termios.Tcgetattr(uintptr(syscall.Stdin), &ttystate)
//Modifier les paramètres du terminal * Modifier ici
//setNonCanonicalMode(&ttystate)
setRawMode(&ttystate)
bufCh := make(chan []byte, 1)
go readBuffer(bufCh)
for {
fmt.Printf("Ce que vous avez tapé: %c\n", <-bufCh)
}
}
//Mettre en mode brut
func setRawMode(attr *syscall.Termios) {
//La valeur définie est[https://linuxjm.osdn.jp/html/LDP_man-pages/man3/termios.3.html]Cité de
//Si vous effacez OPOST, la sortie sera étrange dans votre environnement, alors commentez
//Ctrl lorsque ISIG est désactivé+Commentez car il est difficile de déboguer car C ne peut pas être pressé
//Dans le manuel, la taille des caractères est spécifiée comme CS8, mais elle est jugée inutile dans cette vérification et commentée.
attr.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON
//attr.Oflag &^= syscall.OPOST
attr.Cflag &^= syscall.CSIZE | syscall.PARENB
//attr.Cflag |= syscall.CS8
attr.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN //| syscall.ISIG
attr.Cc[syscall.VMIN] = 1
attr.Cc[syscall.VTIME] = 0
//Refléter les paramètres modifiés
termios.Tcsetattr(uintptr(syscall.Stdin), termios.TCSANOW, attr)
}
//Obtenez la valeur du tampon
func readBuffer(bufCh chan []byte) {
//réduction
}
Contrairement au mode non canonique ci-dessus, la touche enfoncée n'est pas affichée à l'écran.
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/termios.3.html https://www.slideshare.net/c-bata/golang-ui https://grimoire.f5.si/archives/125
Il y a beaucoup d'informations sur les termios gérés en langage C, mais il y a eu peu de cas où cela a été fait en langage Go. J'ai commencé à chercher à créer une commande blague, mais cela a pris plus de temps que prévu. J'ai rédigé un article pour moi dans le futur et pour ceux qui sont également bloqués. C'était intéressant de pouvoir toucher les couches basses auxquelles je ne pense généralement pas.
Recommended Posts