xterm Rückgabe einlesen...???

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Hallo,

ich weiß jetzt schon gar nicht genau, wie ich meine Frage überhaupt formulieren soll... :wink:

Was ich möchte ist folgendes:

Code: Alles auswählen

>>> sys.stdout.write('\033[18t')
>>> ;20;62t
Wenn ich also diesen String an xterm sende und damit dessen Funktion zur Rückgabe der Terminalgröße aufrufe, erhalte ich als Rückgabe ';rows;colst'.
Wobei 'erhalten' in diesem Fall eben nicht stimmt. xterm schreibt die Info ins Terminal.
Was muss ich tun, damit ich aus der Rückgabe einen String zum Auslesen erhalte? Dass xterm seinen Rückgabewert eben nicht einfach ins Terminal sondern z. B. in eine Datei schreibt?

Es gibt natürlich verschiedene Wege, die Terminalgröße auszulesen. Die Lösungen, die ich dabei bisher gefunden habe, lesen dazu mit Hilfe des 'fcntl'-Moduls 'termios'-Konstanten aus und wandeln diese dann um.
Nachdem ich das, was mit 'fcntl.ioctl' bzw. 'fcntl.fcntl' passiert nicht wirklich verstehe, komme ich damit auch nicht weiter...

Code: Alles auswählen

>>> fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, '1234')
'\x14\x00>\x00'
>>> struct.unpack('hh', _)
(20, 62)
>>>fcntl.fcntl(sys.stdout, sys.stdout.write('\033[18t'), ';00;00t')
TypeError: an integer is required
>>> ;20;62t
Das Argument ';00;00t' ist blödsinnig, die Doku sagt ja auch, dass 'fcntl' bei einem String ein binary erwartet. Als Fehlermeldung kommt aber dann '... integer is required'. Wahrscheinlich wird es egal sein, was ich als Argument angebe, weil die Operation (write('\033[18t')) eben überhaupt nichts zurückgibt.

Mehr Licht bitte!!

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Ich verstehe jetzt gerade das Problem nicht!? Mit dem `ioctl()`-Aufruf bekommst Du ja die (aktuelle) Höhe und Breite. Was soll das nachfolgende `fcntl()` bewirken? Wo da gemeckert wird ist übrigens schon das zweite Argument. Das muss eine numerische Konstante sein und nicht das `None` welches die `write()`-Methode liefert.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

BlackJack hat geschrieben:Was soll das nachfolgende `fcntl()` bewirken?
Ich suche nach einem Weg, den Wert, den xterm in die Konsole schreibt, abzufangen.
Mit der 'write()'-Methode bewirke ich ja nur, dass xterm die Funktion startet und eine Information auf den Bildschirm schreibt. Und eben diese Information hätte ich gern abgefangen.
Mein 'fcntl'-Beispiel ist zugegebenermaßen insofern blödsinnig, weil die 'write()'-Methode 'None' zurückgibt. Abfangen möchte ich das, was die xterm Funktion, die durch die Escape-Sequenz, die ich über die 'write()'-Methode an xterm sende aufgerufen wird, liefert.
'termios' bekommt diese Information ja auch irgendwie von xterm. Nur wie?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Ich nehme mal an statt `termios` meintest Du `ioctl()`. Und das bekommt die Information vom `ioctl()`-Aufruf auf C-Ebene. Die Python-Methode ist nur eine dünne Schicht über die gleichnamige C-Funktion, die üblicherweise auf Unixoiden Systemen vorhanden ist. Die Funktion hat eine sehr vage Schnittstelle und man muss sich die Dokumentation des jeweiligen Treibers anschauen, der hinter der „Datei“ steckt. Beim Terminal kann man zum Beispiel so etwas wie Höhe und Breite abfragen oder Modi umschalten, bei Dateien die Soundkarten repräsentieren, die Samplerate einstellen, und so weiter.

Du bekommst Doch aber die Information, warum willst Du das jetzt unbedingt über die Ausgabe im Terminal noch einmal lösen? Eine Lösung davon würde — zumindest unter Linux — wahrscheinlich über das entsprechende ”Pseudoterminal-Gerät” gehen.

Beziehungsweise: Hast Du schon versucht das auf `sys.stdin()` abzugreifen?

PS: Ich bekomme bei ``sys.stdout.write('\033[18t')`` übrigens gar nichts ausgegeben.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

BlackJack hat geschrieben:Ich nehme mal an statt `termios` meintest Du `ioctl()`.
Ja, inzwischen nehme ich das auch an... :wink:
BlackJack hat geschrieben:..., warum willst Du das jetzt unbedingt ... noch einmal lösen?
Die Lösungen, die ich zum Auslesen der Terminalgröße gefunden habe, lösten in mir auf den ersten Blick nur ein 'O mein Gott!!!' aus. Anweisungen wie

Code: Alles auswählen

struct.unpack('hh', fcntl.ioctl(2, termios.TIOCGWINSZ, '1234'))
sind nicht gerade das, wovon ich nachts träume... und nachdem mir

Code: Alles auswählen

sys.stdout.write('\033[18t')
auch die 2 gewünschten Werte liefert wollte ich den vermeintlich einfachen Weg gehen...
BlackJack hat geschrieben:Hast Du schon versucht das auf `sys.stdin()` abzugreifen?
Ja, das war mein erster Impuls. Ich dachte, wer auf das Terminal schreibt muss dies ja über 'stdin' tun. Hat aber nicht funktioniert, weil ich keine befriedigende Lösung finde, die mir alles, was in 'stdin' landet, abfängt. War alles immer ein wenig 'gefährlich'... :) und meine Werte hätte ich dann auch noch mühsam herausfischen müssen.
Ich versuchte dann den in meinen Augen erstmal einfacheren Weg in der bash:

Code: Alles auswählen

$ echo -e '\033[18t' > size
$ cat size

$ ;20;62t
Selbes Spiel also wie auf der Pythonshell... ;-( Wie auch immer, selbst wenn ich noch zu einer Lösung käme, letztlich wäre es nur ein Hack...

Was ich, ausgehend von folgender Anweisung, noch nicht verstehe:

Code: Alles auswählen

>>> fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, '1234')
'\x14\x00>\x00'
  • Anstelle von 'sys.stdout' könnte ich auch eine '1' ('sys.stdout.fileno()') übergeben. 'sys.stdout' ist vom type 'file', '1' ist 'int'. Geschieht bei der Übergabe also etwas in der Art?

    Code: Alles auswählen

    if isinstance(fd, int):
        fd = [sys.stdin, sys.stdout, sys.stderr][fd]
    oder stecken hinter 0, 1, und 2 noch irgendwelche magischen Dinge?
  • termios.TIOCGWINSZ == 21523
    Besteht irgendeine Verbindung zwischen der Escape-Sequenz '\033[18t]' und 21523? Oder welche Bedeutung hat 21523?
  • Es spielt keine Rolle, ob ich zuletzt '1234', '0000', 'blub' oder sonstwas übergebe. Das einzige, was ich daran erkenne ist die Länge des Strings, der zurückgegeben wird. Warum dann nicht einfach 1, 2, 3 etc. als Längenangabe?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
lunar

@mutetella: Nun, es handelt sich eben um eine C-Schnittstelle. Die sind nie schön, zumindest nicht für Python-Programmierer. Zu Deinen Fragen:

Auf Ebene des Betriebssystems wird jede offene Datei durch einen numerischen Dateideskriptor repräsentiert. Umgekehrt wird also ein Schuh daraus: Bei der Übergabe eines Dateiobjekts an "ioctl" wird ".fileno()" aufgerufen. Der so erhaltene Dateideskriptor wird dann an den (in C implementierten) "ioctl"-Systemaufruf weitergegeben.

Der Wert der "TIOCGWINSZ"-Konstante kann Dir vollkommen egal sein. Mit der Escape-Sequenz hat der Wert nichts zu tun.

Der letzte Parameter hängt von der gewählten IOCTL-Operation ab. Im Falle von TIOCGWINSZ ist dies eine Struktur mit vier "short"-Feldern, wovon nur die ersten zwei benutzt werden. Zwei "short"-Felder zu je 16 Bit ergeben in der Summe 32 Bit, also einen Byte-String der Länge vier.

Lies die Dokumentation der entsprechenden C-Funktion ioctl(2) sowie die Dokumentation zu TTY-IOCTL-Operationen tty_ioctl(4). C-Kenntnisse vorausgesetzt, hilft Dir das beim Verständnis dieses Aufrufs. Besitzt Du keine C-Kenntnisse, dann lasse besser die Finger von diesen Schnittstellen und eigene Dir erst einmal rudimentäre C-Kenntnisse an.
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Als Alternative:

Code: Alles auswählen

import curses
curses.setupterm()
print 'Columns:', curses.tigetnum('cols')
print 'Lines:', curses.tigetnum('lines')
BlackJack

@mutetella: Wie lunar schon sagte: Man begibt sich damit auf C-Ebene und ziemlich nah ans System. Das sieht dann etwas anders aus als typisches Python. Davon träumt man Nachts nicht — oder nur ungern — aber ein ``echo -e '\033[18t' > size`` kann einem auch Albträume bereiten. Zumindest ich finde einen Aufruf einer Low-Level-Funktion innerhalb eines Prozesses schöner als einen externen Prozess mit einer Bash zu starten, die dann eine ``echo``-Anweisung interpretiert, die eine Terminal-Escape-Sequenz ausgibt, die vom Terminal geparst werden muss, wo intern daraufhin sehr wahrscheinlich irgendwo der ioctl()-Aufruf gemacht wird, dessen Ergebnis dann als Zeichenkette geliefert wird. Dazu kommt noch, dass die ``-e``-Option nicht POSIX-Standard ist — das also nicht mit jeder Shell funktioniert.

Wenn ich den ganzen Aufwand vergleiche der da abläuft, würde ich den `ioctl()`-Aufruf bevorzugen.

Allerdings erst nachdem ich die Dokumentation konsultiert habe. Die sagt nämlich, dass die Ergebnisstruktur *vier* Felder vom Typ ``unsigned short`` hat. Die letzten beiden werden zwar zumindest bei Linux nicht verwendet, aber ich würde trotzdem den Platz dafür vorsehen. Wenn da doch Daten hingeschrieben werden, darf man sich sonst nicht wundern, dass das Programm hart abstürzen könnte.

Und ich würde statt `struct` heutzutage `ctypes` verwenden, um das Ergebnis auseinander zu nehmen.

Code: Alles auswählen

import fcntl
import sys
import termios
from ctypes import c_ushort, sizeof, Structure


class WinSize(Structure):
    _fields_ = [
        ('rows', c_ushort),
        ('columns', c_ushort),
        ('x_pixels', c_ushort), # Unused.
        ('y_pixels', c_ushort), # Unused.
    ]
    
    @classmethod
    def from_file(cls, tty_file):
        result = fcntl.ioctl(tty_file, termios.TIOCGWINSZ, '\0' * sizeof(cls))
        return cls.from_buffer_copy(result)


def main():
    size = WinSize.from_file(sys.stdout)
    print 'Console size: %dx%d' % (size.columns, size.rows)
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Was spricht denn gegen `curses`?
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

snafu hat geschrieben:Was spricht denn gegen `curses`?
'curses' dokumentiert Änderungen der 'terminfo' nur für das WindowObject, das nach einem 'initscr()' zurückgegeben wird.
Solange ich 'curses' nicht initialisiere sind die Werte aus 'tigetnum()' nur Anfangswerte und werden z. B. nach einer Änderung der Fenstergröße nicht aktualisiert.

Eine weitere Möglichkeit wäre es, die Umgebungsvariablen 'LINES' und 'COLUMNS' auszulesen. Das funktioniert aber offensichtlich auch nicht auf jedem System bzw. jeder Umgebung.
Obwohl beide Variablen bei mir im OS vorhanden sind, liefern mir 'os.getenv('LINES')' bzw. 'os.environ['LINES']' keine Ergebnisse. Auf anderen Systemen wohl schon, konnte ich aber nicht testen.

Die 'ioctl()'-Lösung finde ich inzwischen am besten und BlackJack's Beispiel (mal wieder) am 'schönsten' zumal sich damit sehr einfach weitere Strukturen zum Auslesen von Terminalinformationen bauen lassen.

Was ich dabei aber noch nicht verstehe:
  • Würde es einen Unterschied machen, wenn ich statt '\0' -> '\x00' verwende?
  • Warum überhaupt '\0' und nicht irgendeinen String?
  • Warum muss hier überhaupt etwas angegeben werden?
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

mutetella hat geschrieben:Was ich dabei aber noch nicht verstehe:
  • [...]
  • Warum muss hier überhaupt etwas angegeben werden?
Aus der Doku:
[...]With the argument missing or an integer value, the return value of this function is the integer return value of the C fcntl() call. When the argument is a string it represents a binary structure, e.g. created by struct.pack(). The binary data is copied to a buffer whose address is passed to the C fcntl() call. The return value after a successful call is the contents of the buffer, converted to a string object. The length of the returned string will be the same as the length of the arg argument.
Man bestimmt mit der Länge des Strings also die Länge des Rückgabewertes. Diese muss natürlich korrekt sein, damit `ctypes` es richtig parsen kann.
BlackJack

@mutetella: $LINES und $COLUMNS werden zum Beispiel von der Bash zur Verfügung gestellt. Allerdings werden beide nicht an gestartete Prozesse exportiert.

Unterschied '\0' und '\x00':

Code: Alles auswählen

In [198]: print repr('\0'), repr('\x00'), '\0' == '\x00'
'\x00' '\x00' True
Macht also keinen, ausser weniger zu tippen. :-)

Warum irgendein anderes Zeichen als '\0'? Nullbytes sind halt IMHO irgendwie eine „natürliche“ Wahl um ”nichts” zu repräsentieren.

Eigentlich nimmt die C-Funktion `ioctl()` nach dem `opt`-Argument beliebig viele Argumente, je nach dem was der konkrete Treiber den man anspricht für das gegebene `opt` an weiteren Werten erwartet. Die meisten beschränken sich aber auf *ein* Argument was in der Regel entweder eine Zahl oder ein Zeiger auf einen Speicherbereich ist. Das mussten die Entwickler nun irgend wie auf Python-Typen abbilden. Also kann man da eine Zahl übergeben Python-`int` → C-`int`, oder eine Zeichenkette, weil das in Python halt einem Speicherbereich mit Bytes in C am nächsten kommt. `ioctl()` (Python) kopiert dann die Bytes der Zeichenkette in einen neuen Speicherbereich und ruft `ioctl()` (C) mit einem Zeiger darauf als drittem Argument auf. Kopieren ist notwendig, weil Python-Zeichenketten nicht verändert werden dürfen, aber `ioctl()`-Aufrufe so einen Speicherbereich auch gerne mal zum abspeichern von komplexeren Ergebnissen verwenden. Wie in diesem Fall mit der Bildschirmgrösse.

Einfach nur die Länge angeben kann man nicht, weil eine Zahl mit der Länge nicht unterschieden werden kann von einer Zahl die als Zahl übergeben werden soll.

Es gibt auch Aufrufe die einen Zeiger auf einen Speicherbereich erwarten in dem Daten stehen. Es ist also nicht immer so, dass man eine scheinbar unwichtige Zeichenkette übergibt, bei der nur die Länge interessiert.

Jetzt mit `ctypes` in der Standardbibliothek könnten die Python-Entwickler eigentlich `ctypes`-Strukturen als dritte Möglichkeit implementieren.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Vielen herzlichen Dank für Eure Mühe! Da bekommt man fast schon Lust auf C... :shock:

Der Vollständigkeit halber hier noch eine 'Hauruck-Lösung':

Code: Alles auswählen

def winsize():
    stty_return = subprocess.Popen(
        'stty size', shell=True, 
        stdout=subprocess.PIPE).communicate()[0].split()
    return int(stty_return[0]), int(stty_return[1])
Wobei ich definitiv bei 'ioctl()' bleib'...

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@mutetella:

Deiner Annahme, die Ausgabe von sys.stdout.write('\033[18t') am STDIN lesen zu können, liegt ein Misverständnis über die Funktionsweise von Terminals zugrunde.
Kurze Erklärung hierzu:
Ausgehend vom einfachsten Fall, dem klassischen Textterminal, haben wir 2 Komponenten auf Terminalseite - eine Eingabe (Tastatur) und eine Ausgabe (Display). Das Programm, welches STDIN, STDOUT und STDERR erhält, "sitzt" dem Terminal gegenüber (hier dein Pythonscript). In der Terminalgrundeinstellung wird STDIN von der Eingabe des Terminals gefüttert (Du tippst etwas und kannst es im Programm am STDIN lesen) und gleichzeitig vom Terminaltreiber an die Ausgabe weitergeleitet (ECHO, Du siehst was Du tippst quasi sofort auf dem Display). Alles was dein Programm nach STDOUT schreibt landet in der Ausgabe und nicht nochmal im STDIN. Und das ist nämlich hier der Fall - Du schreibst nach STDOUT.
Jetzt fragst Du Dich wahrscheinlich, warum da etwas ganz anderes ankommt, als Du geschrieben hast. Der Grund dafür ist - Terminals verhalten sich wie Pipes mit der Möglichkeit zur Interpretation der Daten (von einfacher Datenmanipulation bis zu komplexen Zustandsänderungen des Terminals).
Das Ganze wird im Falle von Pseudoterminals und Terminalemulatoren unter X noch etwas komplizierter, da hier die "Geräteseite" (master) vom Emulator, also wiederum einem Programm, repräsentiert wird. Die Kaskade für xterm sieht dann stark vereinfacht ungefähr so aus:

Code: Alles auswählen

Ein-/ausgabe (Monitor + Keyboardtreiber im Kernel) <---> Systemkonsole <---> X (routet Key- und Displayevents) <---> Terminalemulator (xterm) <---> Python
Trotzdem ist es möglich, an die Ausgabe von sys.stdout.write('\033[18t') ranzukommen, Bsp:

Code: Alles auswählen

import os, sys
from select import poll, POLLIN
from posix_term import cbreak_terminal
# echo und kanonischer Modus off
with cbreak_terminal():
    # hole terminal des programms
    slave = os.ttyname(0)
    f = os.open(slave, os.O_RDONLY)
    # nutzt poll um zu prüfen, ob Daten am Terminal eingegangen sind
    poll_obj = poll()
    poll_obj.register(f, POLLIN)
    sys.stdout.write('\033[18t')
    sys.stdout.flush()
    result = 'nix'
    # falls Daten am Terminal lies sie in result ein
    for fd, event in poll_obj.poll(10):
        if fd == f and event & POLLIN:
            result = os.read(f, 1024)
    print repr(result)
    os.close(f)
Da das Terminal, mit welchem Dein Programm verbunden ist, selbst als dateiähnliches Gerät vorliegt, kannst Du hier mitlesen. Allerdings musst Du das Terminal vorher manipulieren und wenigstens den kanonischen Modus abschalten (evtl. noch das ECHO, beides macht hier das cbreak_terminal()), um an die Ausgabe ranzukommen.
Die Methode ist alles andere als zuverlässig oder terminalübergreifend, bei mir interpretiert nur xterm die Escapesequenz entsprechend Deiner Vorgabe. Auch ist es nicht ungefährlich, so auf das Terminal zuzugreifen, da andere Datenstöme (z.B. eine zeitgleiche Eingabe) korrumpiert werden können.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@jerch:
Ich bin jetzt einfach mal meinem ersten, naiven Impuls (was auf meinem Bildschirm erscheint, muss auch durch stdin) gefolgt und zu folgendem Ergebnis (das parsen des Report-Ergebnisses muss natürlich noch verbessert werden) gekommen:

Code: Alles auswählen

# -*- coding: utf-8 -*-

import sys
import termios
import tty


def write2tty(string_):
    sys.stdout.write(string_)
    sys.stdout.flush()

def raw_read(length=1):
    old_term_settings = termios.tcgetattr(sys.stdin)
    tty.setraw(sys.stdin)
    try:
        bytes_ = sys.stdin.read(length)
    finally:
        termios.tcsetattr(sys.stdin, termios.TCSAFLUSH, old_term_settings)
    return bytes_

def report(csi):
    write2tty(csi[0])
    result = ''
    while not result.endswith(csi[2]):
        result += raw_read(1)
    x, y = result[:-1].strip(csi[1]).split(';')
    return int(x), int(y)


ESC = '\033'
CSI = ESC + '['

#CSI reports
#[0]: CSI, [1]: result starts with, [2]: result ends with
CURSOR_POSITION = (CSI + '?6n', CSI + '?', 'R')
WINDOW_SIZE = (CSI + '18t', CSI + '8;', 't')
SCREEN_SIZE = (CSI + '19t', CSI + '9;', 't')


if __name__ == '__main__':
    print report(WINDOW_SIZE)
Was ich jetzt schreibe, schreibe ich mit zugekniffenen Augen, weil ich mir nicht sicher bin, ob das so stimmt:
jerch hat geschrieben:Alles was dein Programm nach STDOUT schreibt landet in der Ausgabe und nicht nochmal im STDIN. Und das ist nämlich hier der Fall - Du schreibst nach STDOUT.
Daraus folgend habe ich Dein Beispiel dahingehend geändert, dass ich 'slave' nicht auf 'POLLIN'- sondern auf 'POLLOUT'-events prüfe.

Code: Alles auswählen

...
    poll_obj.register(f, POLLOUT)
...
        if fd == f and event & POLLOUT:
...
Nach dieser Änderung erhalte ich auch das gewünschte 'result' -> '\x1b[8;22;79t'. Ein 'POLLIN'-event findet nicht statt, von daher funktionierte Deine Lösung nicht.

Zudem widersprechen Deine und meine Lösung Deiner Behauptung, da ich das Ergebnis des durch '\033[18t' angestoßenen xterm-(Kernel?)-Reports an 'stdin' auslese (so wie Dein 'os.read()' ja auch).
Weshalb wird ein 'POLLOUT'- und nicht ein 'POLLIN'-event ausgelöst wird und weshalb stehen die Daten dann nicht in 'stdout' sondern in 'stdin'?
jerch hat geschrieben:Auch ist es nicht ungefährlich, so auf das Terminal zuzugreifen, da andere Datenstöme (z.B. eine zeitgleiche Eingabe) korrumpiert werden können.
Siehst Du diese Gefahr auch dann, wenn die Daten zeichenweise eingelesen und ausgewertet werden? Wenn ich also z. B. ein '\x1b[D' durch das beginnende '\x1b[' als esc-sequence erkenne und am 'D' ein 'left' und auch das Ende der sequence erkenne. Da ist es einem anderen Prozess doch kaum möglich, 'dazwischen zu funken'. Oder?

mutetella

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@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.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

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... :wink:

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@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
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Wenn Du belauschst was auf dem Terminal ausgegeben wird, dann müsstest Du diese Ausgaben auch mitbekommen.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@BlackJack:
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')
>>>
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
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Antworten