xterm Rückgabe einlesen...???
@mutetella: Die Gefahr mit dem dazwischen funken dürfte eigentlich immer bestehen. Es reicht ja, wenn man auf dem Terminal vorher ein anderes Programm asynchron gestartet hat, welches jederzeit etwas in das Terminal schreiben könnte. Oder Nachrichten vom System oder vom Administrator die in allen Terminals erscheinen.
Lässt sich die Cursorposition eigentlich nicht auch über 'termios' abfragen. Ähnlich wie 'TIOCGWINSZ'? Hab' schon 'termbits.h' und 'termios.h' durchgeschaut, kann aber nichts finden, was darauf hinweist. Ich bin da jetzt wirklich auch a bisl zu schwach auf der Brust...
mutetella
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit )
@BlackJack:
Wobei diese Dinge aber nicht in 'stdin' landen und demnach auch keine Probleme bereiten.
Nur: Warum landen die eigentlich nicht in 'stdin'? Werden die vom OS automatisch gekapselt oder so?
mutetella
Wobei diese Dinge aber nicht in 'stdin' landen und demnach auch keine Probleme bereiten.
Nur: Warum landen die eigentlich nicht in 'stdin'? Werden die vom OS automatisch gekapselt oder so?
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit )
@mutetella: Wenn Du belauschst was auf dem Terminal ausgegeben wird, dann müsstest Du diese Ausgaben auch mitbekommen.
@BlackJack:
Also vielleicht ist ja meine Vorgehensweise nicht richtig:
Nachdem ich also von Terminal 2 aus ein 'q' ins Terminal 1 geschrieben habe erscheint dieses zwar an der aktuellen Cursorposition, wird aber von 'sys.stdin.read(1)' nicht erfasst.
mutetella
Also vielleicht ist ja meine Vorgehensweise nicht richtig:
Code: Alles auswählen
#terminal '/dev/pts/1':
>>> old_settings = termios.tcgetattr(sys.stdin)
>>> byte = ''
>>> try:
... tty.setraw(sys.stdin)
... while not byte == 'q':
... byte = sys.stdin.read(1)
... finally:
... termios.tcsetattr(sys.stdin, termios.TCSAFLUSH, old_settings)
...
Code: Alles auswählen
#terminal '/dev/pts/2':
>>> other_terminal = os.open('/dev/pts/1', os.O_RDWR)
>>> os.write(other_terminal, 'q')
>>>
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit )
Du kannst schlichtweg die Eingabe ins Terminal (ich meine hier STDIN des Masters) nicht am STDIN des Programmes lesen. Nochmal:mutetella hat geschrieben:Also vielleicht ist ja meine Vorgehensweise nicht richtig:
Code: Alles auswählen
Pseudoterminalpaar mit xterm und Python:
xterm ---- #master out: -----> in: #slave ---- Python (Terminalausgabe wird zu Programmeingabe)
in: <----- out: (Programmausgabe wird zu Terminaleingabe)
Jetzt schreibst Du das 'q' in '/dev/pts/1', also dem slave, ergo landet es im STDIN des Master (dem xterm-Prozess). Da der Master ohne Eingriff in den Kernel nur einmal geöffnet sein darf, kommst Du an diese Daten von aussen nicht mehr ran. (Das Mitlesen war früher hier noch einfacher möglich.)
Zu sys.stdout.write('\033[18t'):
Hier habe ich mich getäuscht - xterm schreibt den Rückgabewert tatsächlich nochmal raus, und dieser landet dann in STDIN des Programmes. Daher Dein Erfolg mit STDIN.
Zur Cursorposition:
Unter xterm funktioniert z.B. '\E[6n'.
Allerdings lese ich in meinem Beispiel doch nicht den master, sondern den slave aus. Ich lese '/dev/pts/1' aus und schreibe vom anderen Terminal aus in dieselbe Datei hinein.jerch hat geschrieben:Jetzt schreibst Du das 'q' in '/dev/pts/1', also dem slave, ergo landet es im STDIN des Master (dem xterm-Prozess). (...)
Es müsste doch folgendes passieren:
Code: Alles auswählen
S1 = '/dev/pts/1'
S2 = '/dev/pts/2'
MA = '/dev/ptmx'
S2_out -> in_MA_out -> in_S1_out -> in_MA_out -> screen
2 Dinge, die ich in diesem Zusammenhang ebenfalls noch nicht wirklich verstanden habe:
- Wie kann zwischen 'STDIN', 'STDOUT' und 'STDERR' unterschieden werden, nachdem doch alle 3 auf dieselbe Datei verweisen? Die nötigen flags vorausgesetzt konnte ich noch keinen Unterschied feststellen, ob ich descriptor 0 oder 1 zur Ein- oder Ausgabe verwende.
- Weshalb bleiben die restlichen bytes bei Zeichen, die > 1 byte sind bei der Eingabe via 'sys.stdin.read(1)' im Puffer erhalten, wohingegen bei der Eingabe via 'os.read(slave, 1)' die restlichen bytes aus dem Puffer ('/dev/pts/..' ?) verschwinden. Beispiel:
Code: Alles auswählen
def raw_read(manner): if manner == 'os': slave = os.open(os.ttyname(0), os.O_RDONLY) read_ = functools.partial(os.read, slave) else: read_ = sys.stdin.read try: old = termios.tcgetattr(sys.stdin) tty.setraw(sys.stdin) return read_(1) finally: termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old)
Code: Alles auswählen
>>> raw_read('os') #Pfeiltaste links ('\x1b[D') tippen '\x1b' #erstes byte wird gelesen >>> [D #restliche bytes landen in stdout >>> raw_read('sys') #Pfeiltaste links ('\x1b[D') tippen '\x1b' #erstes byte wird gelesen >>> raw_read('sys') '[' #zweites byte wird gelesen >>> raw-read('sys') 'D' #drittes byte wird gelesen
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit )
Etwas ausführlicher, was in Deinem obigen Bsp. passiert:
Die Schreibaktion des zweiten Python-Prozesses landet im Master und wird dort von xterm gelesen und am Bildschirm ausgegeben. Um etwas am STDIN des Slave-Prozesses zu sehen, muss es vom Master-Prozess in Master geschrieben werden. Das passiert z.B. bei Keyboard-Input, hier schreibt xterm die Zeichen in master. Je nach Terminaleinstellung werden diese Zeichen vom Pseudoterminal nur nach slave geleitet (echo off) oder nochmal nach master gespiegelt (echo on). Das ist Teil des Terminalprocessings (termios und Konsorten), welches sicherstellt, dass der slave-Prozess eine Terminalumgebung zu sehen bekommt.
Die Auftrennung von STDIN, STDOUT ist historisch bedingt, als die Terminal Ein-/Ausgabe physisch getrennt waren. Hier gibts ein Paar Hintergrund-Infos zu TTYs - http://www.linusakesson.net/programming/tty/index.php
Am Linux-Textterminal ist diese Trennung auch noch gut nachvollziehbar, da sind Ein-/Ausgabe noch sehr nah am Keyboard-/Displaytreiber.
Auch ermöglicht diese Auftrennung in Sende- und Empfangskanal sehr elegante Pipe-Umleitungen, ohne die Bash-Skripting ziemlich alt aussehen würde.
Zu Deinem sys.stdin.read vs os.read Problem - da müsste man mal schauen, wie sys.stdin.read implementiert ist und wie es mit dem Byteparameter umgeht. os.read(fd, n) liest 1 bis n Bytes, keinesfalls mehr, während sys.stdin.read(n) auf n bytes wartet. Wahrscheinlich konsumiert sys.stdin.read mehr Bytes vom fd (und puffert diese), wodurch der Input geleert wird. Im Falle von os.read verbleiben diese im fd und werden mit dem Umschalten des Terminals in `finally` an den Master-Prozess gespiegelt und von diesem dargestellt (die Zeichen landen dabei nicht in STDOUT).
Code: Alles auswählen
Prozess am Master Pseudoterminal Prozess am slave
------- read write ----------------
| | <----------- <---- <-------- | STDOUT |
| xterm | write master(/dev/ptmx) slave(/dev/pts/1) read | Python |
| | ------------> ----> | --------> | STDIN |
------- Terminal-Processing | ----------------
|
---> Output (Display über X) |
<--- Input (Keyboard über X) |
| zweiter Python-Prozess an /dev/pts/2 <----> anderer Master
| -------------------- (zB. 2. xterm)
--- | öffnet /dev/pts/1 |
| und schreibt 'q' |
--------------------
Die Auftrennung von STDIN, STDOUT ist historisch bedingt, als die Terminal Ein-/Ausgabe physisch getrennt waren. Hier gibts ein Paar Hintergrund-Infos zu TTYs - http://www.linusakesson.net/programming/tty/index.php
Am Linux-Textterminal ist diese Trennung auch noch gut nachvollziehbar, da sind Ein-/Ausgabe noch sehr nah am Keyboard-/Displaytreiber.
Auch ermöglicht diese Auftrennung in Sende- und Empfangskanal sehr elegante Pipe-Umleitungen, ohne die Bash-Skripting ziemlich alt aussehen würde.
Zu Deinem sys.stdin.read vs os.read Problem - da müsste man mal schauen, wie sys.stdin.read implementiert ist und wie es mit dem Byteparameter umgeht. os.read(fd, n) liest 1 bis n Bytes, keinesfalls mehr, während sys.stdin.read(n) auf n bytes wartet. Wahrscheinlich konsumiert sys.stdin.read mehr Bytes vom fd (und puffert diese), wodurch der Input geleert wird. Im Falle von os.read verbleiben diese im fd und werden mit dem Umschalten des Terminals in `finally` an den Master-Prozess gespiegelt und von diesem dargestellt (die Zeichen landen dabei nicht in STDOUT).
@jerch:
Ich bin dabei, zu verstehen, was mit meinem 'q' und all dem anderen Getippe passiert... Danke für Deine Hilfe!
Um nochmal auf das eigentliche Thema zurückzukommen: Du verwendest in Deinem 'winsize()'-Beispiel ein poll-Objekt, um zu überprüfen, ob etwas auf STDIN zum Auslesen wartet. Dazu überprüfst Du, ob ein POLLOUT-event stattfindet. Damit hab' ich ein wenig herumgespielt und gesehen, dass egal, ob Daten vorhanden sind oder nicht, 'poll_obj.poll(10)' immer denselben Zustand, dass Daten zum Auslesen vorhanden seien, meldet.
Warum ist das so? Verkürztes Beispiel:
mutetella
Ich bin dabei, zu verstehen, was mit meinem 'q' und all dem anderen Getippe passiert... Danke für Deine Hilfe!
Um nochmal auf das eigentliche Thema zurückzukommen: Du verwendest in Deinem 'winsize()'-Beispiel ein poll-Objekt, um zu überprüfen, ob etwas auf STDIN zum Auslesen wartet. Dazu überprüfst Du, ob ein POLLOUT-event stattfindet. Damit hab' ich ein wenig herumgespielt und gesehen, dass egal, ob Daten vorhanden sind oder nicht, 'poll_obj.poll(10)' immer denselben Zustand, dass Daten zum Auslesen vorhanden seien, meldet.
Warum ist das so? Verkürztes Beispiel:
Code: Alles auswählen
def raw_read(length, default=''):
with jerch_terminal.raw_terminal():
result = ''
f = os.open(os.ttyname(0), os.O_RDWR)
poll_ = select.poll()
poll_.register(f, select.POLLOUT)
sys.stdout.write(default)
sys.stdout.flush()
first = poll_.poll(10)
result = os.read(f, length)
poll_.modify(f, select.POLLOUT)
last = poll_.poll(10)
os.close(f)
return first, last, result
Code: Alles auswählen
>>> raw_read(32, '\033[?6n')
([(28, 4)], [(28, 4)], '\x1b[?26;1R')
>>> raw_read(3)
([(28, 4)], [(28, 4)], 'a')
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit )
Genau so verhält es sich offensichtlich. Bin gerade auf diese Antwort gestoßen, die Deine Vermutung bestätigt.jerch hat geschrieben:Zu Deinem sys.stdin.read vs os.read Problem - da müsste man mal schauen, wie sys.stdin.read implementiert ist und wie es mit dem Byteparameter umgeht. os.read(fd, n) liest 1 bis n Bytes, keinesfalls mehr, während sys.stdin.read(n) auf n bytes wartet. Wahrscheinlich konsumiert sys.stdin.read mehr Bytes vom fd (und puffert diese), wodurch der Input geleert wird. Im Falle von os.read verbleiben diese im fd und werden mit dem Umschalten des Terminals in `finally` an den Master-Prozess gespiegelt und von diesem dargestellt (die Zeichen landen dabei nicht in STDOUT).
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit )