In diesem Artikel werde ich Ihnen zeigen, wie Sie die Go-Sprache verwenden, um Terminaleingaben in Echtzeit zu erhalten. Dieses Mal möchte ich nur das UNIX-basierte Betriebssystem vorstellen. Im Fall von Windows scheint es, dass es mit der von Microsoft bereitgestellten API realisiert werden kann ... (unzureichende Forschung)
Wenn Sie das Terminal in den nicht-kanonischen Modus versetzen, können Sie sofort Eingaben erhalten. Um in den nicht-kanonischen Modus zu gelangen, müssen Sie die Werte in den Feldern der Termios-Struktur ändern. Im Folgenden wird jeder Modus mit Beispielcode und Linux-Handbuch erläutert.
<a id="Was ist der kanonische Modus? >>>
Bevor wir den nicht-kanonischen Modus diskutieren, wollen wir zunächst über den kanonischen Modus sprechen. Einfach ausgedrückt ist dies der Standardstatus. Die Eingabe wird akzeptiert, bis die Eingabetaste gedrückt wird.
Zitat Japanisches Übersetzungshandbuch für Linux
Die Eingabe erfolgt zeilenweise. Die Eingabezeile wird verfügbar, wenn das Zeilenumbruchzeichen eingegeben wird. Zeilenbegrenzer sind NL, EOL, EOL2 und EOF am Zeilenanfang. Für Nicht-EOF enthält der von read (2) zurückgegebene Puffer auch Zeilentrennzeichen
Die Zeilenbearbeitung ist aktiviert (ERASE, KILL wirken sich aus; WERASE, REPRINT, LNEXT wirken sich auch aus, wenn das IEXTEN-Flag gesetzt ist). read (2) gibt höchstens eine Eingabezeile zurück. Wenn read (2) weniger Bytes als die aktuelle Eingabezeile anfordert, wird nur die gleiche Anzahl angeforderter Bytes gelesen und die verbleibenden Zeichen werden beim nächsten Lesevorgang gelesen (2).
<a id="Was ist der nicht-kanonische Modus? >>>
Nicht-kanonischer Modus, dieser Modus kann Eingaben in Echtzeit akzeptieren. Sie können die Anzahl der akzeptierten Zeichen mit MIN (c_cc [VMIN]) einstellen. Wenn beispielsweise c_cc [VMIN] = 3 ist, wird die Eingabe abgeschlossen und das Programm wird geladen, wenn 3 Zeichen eingegeben werden. Sie können das Zeitlimit mit TIME (c_cc [VTIME]) festlegen und auf 0 setzen, wenn Sie das Zeitlimit nicht benötigen.
Zitat Japanisches Übersetzungshandbuch für Linux
- Im nicht-kanonischen Modus ist die Eingabe sofort verfügbar (der Benutzer muss keine Zeilenumbrüche eingeben), es wird keine Eingabeverarbeitung durchgeführt und die Zeilenbearbeitung ist deaktiviert. Die Einstellungen von MIN (c_cc [VMIN]) und TIME (c_cc [VTIME]) bestimmen die Bedingungen, unter denen das Lesen (2) abgeschlossen wird.
Verwenden Sie in der Sprache C die Funktionen von "termios.h", um auf die Termios-Struktur zuzugreifen. Ich werde das von Freiwilligen erstellte pkg / term package ausleihen, damit es auch in der Go-Sprache verwendet werden kann. Wenn Sie die Parameter der Termios-Struktur ändern, verwenden Sie Tcgetattr (), um die aktuellen Einstellungen abzurufen, und nehmen Sie dann die erforderlichen Einstellungen für Bitoperationen vor. Informationen zu den Parametern, die eingestellt werden können, finden Sie im Japanischen Übersetzungshandbuch für Linux. Übrigens könnten die Flags, die in der Sprache C verwendet werden können, grundsätzlich auch im Paket pkg / term verwendet werden. Sobald Sie die erforderlichen Einstellungen vorgenommen haben, können Sie sie mit Tcsetattr () wiedergeben.
sample.go
package main
import (
"fmt"
"syscall"
"github.com/pkg/term/termios"
)
func main() {
var ttystate syscall.Termios
//Terminaleinstellungen abrufen
termios.Tcgetattr(uintptr(syscall.Stdin), &ttystate)
//Terminaleinstellungen ändern
setNonCanonicalMode(&ttystate)
//Holen Sie sich Standardeingabe
bufCh := make(chan []byte, 1)
go readBuffer(bufCh)
for {
fmt.Printf("Was du eingegeben hast: %c\n", <-bufCh)
}
}
//In den nicht-kanonischen Modus versetzen
func setNonCanonicalMode(attr *syscall.Termios) {
//Kanonischen Modus deaktivieren (&^ AND NOT)
attr.Lflag &^= syscall.ICANON
//Mindestanzahl von Zeichen beim Lesen=Ein Charakter
attr.Cc[syscall.VMIN] = 1
//Timeout-Zeit beim Lesen nicht kanonisch= 0
attr.Cc[syscall.VTIME] = 0
//Reflektieren Sie die geänderten Einstellungen
termios.Tcsetattr(uintptr(syscall.Stdin), termios.TCSANOW, attr)
}
//Holen Sie sich den Wert des Puffers
func readBuffer(bufCh chan []byte) {
buf := make([]byte, 1024)
for {
if n, err := syscall.Read(syscall.Stdin, buf); err == nil {
bufCh <- buf[:n]
}
}
}
Wenn der obige Code ausgeführt wird, ist das Verhalten wie folgt. Printf wird ausgeführt, nachdem der eingegebene Schlüssel auf dem Bildschirm angezeigt wird. Wenn Sie den Wert von VMIN erhöhen, können Sie übrigens mehrere Werte erhalten.
Zusätzlich zu den Funktionen des nicht-kanonischen Modus werden die von Ihnen eingegebenen Tasten nicht auf dem Bildschirm angezeigt. Da die spezielle Verarbeitung nicht funktioniert, können Sie die Beendigung mit Strg + C nicht erzwingen.
Zitat Japanisches Übersetzungshandbuch für Linux
-Eingabe ist zeichenweise möglich, Echo ist deaktiviert und alle speziellen Verarbeitungen für Eingabe- / Ausgabezeichen des Terminals sind deaktiviert.
Es handelt sich um ein Muster, das auf den Raw-Modus eingestellt ist, wie in Japanisches Übersetzungshandbuch für Linux gezeigt. (* Ich habe die Teile auskommentiert, die ich für unnötig befunden habe.) Sie können es gemäß dem Handbuch einstellen, ohne wie im folgenden Code zu denken, aber ich denke, es ist besser, den Einstellungsparameter nach Bedarf auszuwählen.
sample.go
package main
import (
"fmt"
"syscall"
"github.com/pkg/term/termios"
)
func main() {
var ttystate syscall.Termios
//Terminaleinstellungen abrufen
termios.Tcgetattr(uintptr(syscall.Stdin), &ttystate)
//Terminaleinstellungen ändern * Hier ändern
//setNonCanonicalMode(&ttystate)
setRawMode(&ttystate)
bufCh := make(chan []byte, 1)
go readBuffer(bufCh)
for {
fmt.Printf("Was du eingegeben hast: %c\n", <-bufCh)
}
}
//Auf Raw-Modus einstellen
func setRawMode(attr *syscall.Termios) {
//Der eingestellte Wert ist[https://linuxjm.osdn.jp/html/LDP_man-pages/man3/termios.3.html]Zitiert aus
//Wenn Sie OPOST löschen, ist die Ausgabe in Ihrer Umgebung seltsam. Kommentieren Sie sie aus
//Strg, wenn ISIG deaktiviert ist+Kommentieren Sie aus, da das Debuggen schwierig ist, da C nicht gedrückt werden kann
//Im Handbuch wird die Zeichengröße als CS8 angegeben, sie wird jedoch bei dieser Überprüfung als unnötig beurteilt und auskommentiert.
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
//Reflektieren Sie die geänderten Einstellungen
termios.Tcsetattr(uintptr(syscall.Stdin), termios.TCSANOW, attr)
}
//Holen Sie sich den Wert des Puffers
func readBuffer(bufCh chan []byte) {
//Kürzung
}
Im Gegensatz zum obigen nicht-kanonischen Modus wird die gedrückte Taste nicht auf dem Bildschirm angezeigt.
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
Es gibt viele Informationen zu Termios, die in der Sprache C behandelt werden, aber es gab nur wenige Fälle, in denen dies in der Sprache Go geschehen ist. Ich habe versucht, einen Scherzbefehl zu erstellen, aber es hat länger gedauert als erwartet. Ich habe in Zukunft einen Artikel für mich und für diejenigen zusammengestellt, die ähnlich gestaut sind. Es war interessant, die niedrigen Schichten berühren zu können, an die ich normalerweise nicht denke.
Recommended Posts