[LINUX] [Go language] So erhalten Sie Terminaleingaben in Echtzeit

Einführung

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)

Inhaltsverzeichnis

Fazit

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.

Betriebsumgebung

<a id="Was ist der kanonische Modus? >>>

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? >>>

Was ist nicht-kanonischer 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.

Beispielcode

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.

Demo01

Was ist der Raw-Modus?

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.

Beispielcode

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
}

Demo02 Im Gegensatz zum obigen nicht-kanonischen Modus wird die gedrückte Taste nicht auf dem Bildschirm angezeigt.

Referenzseite

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

abschließend

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

[Go language] So erhalten Sie Terminaleingaben in Echtzeit
[Frage] So erhalten Sie die Daten von Textbereichsdaten in Echtzeit mithilfe der Python-Webframework-Flasche
So schreiben Sie offline in Echtzeit Lösen von E04-Problemen mit Python
Wie bekomme ich Stacktrace in Python?
So ermitteln Sie mit Python den Unterschied zwischen Datum und Uhrzeit in Sekunden
So erhalten Sie Ergebnisse von id in Celery
So steuern Sie Multiprozesse ausschließlich in C-Sprache
So erhalten Sie Hilfe in einer interaktiven Shell
So beheben Sie, wenn der Terminaleingang abnormal wird
So erhalten Sie die Dateien im Ordner [Python]
Lesen von Zeitreihendaten in PyTorch
So verbergen Sie Benutzereingaben in der PySimple-Benutzeroberfläche
So erhalten Sie den Variablennamen selbst in Python
So erhalten Sie mehrere Modellobjekte zufällig in Django
So ermitteln Sie die Anzahl der Stellen in Python
So messen Sie die Verarbeitungszeit mit Python oder Java
Holen Sie sich die Standardausgabe in Echtzeit mit dem Python-Unterprozess
Wie klicke ich mit der rechten Maustaste über die Tastatureingabe in RPA?
Beenden bei Verwendung von Python in Terminal (Mac)
Gehen Sie in die Sprache, um Teil 7 C in der Sprache GO zu sehen und sich daran zu erinnern
So erhalten Sie RGB- und HSV-Histogramme mit OpenCV
So entfernen Sie benutzerdefinierte Serverpiktogramme in message.content
So implementieren Sie vorläufig einen Fortschrittsbalken in einer Skriptsprache
[Django] Wie man Eingabewerte im Voraus mit ModelForm angibt
Ich habe versucht "Wie man eine Methode in Python dekoriert"
Ich habe versucht, die Zeit und die Zeit der C-Sprache zu veranschaulichen
Holen Sie sich die Terminalgröße in Python
Wie man ein Terminal hackt
So erhalten Sie den Anweisungszeiger (= Programmzähler) im Linux-Kernel
So erhalten Sie den letzten (letzten) Wert in einer Liste in Python
So definieren Sie Go-Variablen
Hallo Welt in GO-Sprache
So erhalten Sie alle Schlüssel und Werte im Wörterbuch
[Go] Verwendung von "... (3 Perioden)"
So erhalten Sie eine Liste der integrierten Ausnahmen für Python
Holen Sie sich YouTube Live-Chat-Felder in Echtzeit mit API
Wie man in Python entwickelt
So erhalten Sie einen Überblick über Ihre Daten in Pandas
[Python] Verwendung von input ()
[Shell] So erhalten Sie den Remote-Standardzweig mit Git
Teil 1 Ich habe die Antwort auf das Referenzproblem geschrieben, wie man in Python in Echtzeit offline schreibt
Ich habe versucht, den Datenverkehr mit WebSocket in Echtzeit zu beschreiben
Der Java-Programmierer versuchte (vorerst), die Sprache Go zu berühren.
So erhalten Sie alle möglichen Werte in einem regulären Ausdruck
Repeated @ app.callback in Dash So schreiben Sie Input und State ordentlich
So stellen Sie fest, dass in Python3 ein Kreuzschlüssel eingegeben wurde
So erhalten Sie eine Zeichenfolge aus einem Befehlszeilenargument in Python
<Pandas> Umgang mit Zeitreihendaten in der Pivot-Tabelle
So ermitteln Sie die Scheitelpunktkoordinaten eines Features in ArcPy
Erstellen Sie eine Funktion, um den Inhalt der Datenbank in Go abzurufen
So schreiben Sie offline in Echtzeit Lösen von F01-Problemen mit Python
So berechnen Sie "xx time" in einem Schuss mit Python timedelta
[Python] Wie man PCA mit Python macht