Hallo liebes Forum,
Ich habe da mal eine Frage zu Curses:
das abfangen von Tasten die gedrückt werden ist soweit ja kein Problem.
STRG+Buchstabe ergibt auch eine andere Taste als nur Buchstabe.
Ich würde aber gerne darauf reagieren wenn jemand nur die STRG-Taste drückt, und wenn er sie wieder los lässt.
Sprich: ich möchte, dass mein Programm Teile des Bildschirms ändert um darauf aufmerksam zu machen, dass mit STRG-Kombination andere Eingaben möglich sind.
Kann mir da jemand weiterhelfen?
Gruß
sparrow
STRG - Tastendruck Curses
Curses-Terminals setzen auf dem ACSII-Modus (xlate) auf, d.h. die Auswertung der scan codes (raw) geschieht innerhalb des Tastaturtreibers (kernelseitig). Der Druck eines einzelnen modifier keys wird curses (oder besser dem Terminal) nicht mitgeteilt. Vielmehr setzt der Treiber ein entsprechendes Flag und erst mit dem Druck einer zweiten Taste wird ein Zeichen generiert, welches am Terminal ankommt.
Terminals sind für den Austausch von kodierten Zeichen (ASCII) konzipiert worden (von Fernschreibern herkommend - tty), daher macht es Sinn, die Tasten standardmäßig als ASCII-Zeichen weiterzureichen. Die Steuerkommandos des Terminals sind dann nichts weiter als eine bestimmte Abfolge von Zeichen, die das Terminal entsprechend interpretiert. Das Terminal selbst unterstützt eine Reihe von Arbeitsmodi, mit denen Funktionalität hinzu- oder abgeschaltet werden können. So weist z.B. das kanonische Flag (ICANON) das Terminal an, den internen Zeilerpuffer zu verwenden und die Eingabe erst mit dem Zeilenende an die Anwendung weiterzugeben.
Bibliotheken wie curses "bügeln" die Funktionvielfalt und Eigenheiten der Terminals halbwegs glatt. Hierzu wird in der Regel die Eingabe auf "dumm" gestellt (raw-Modus des Terminals - Zeichen werden 1:1 weitergegeben) und die Ausgabe wird terminaltypgerecht aufbereitet (mit Escapecodes versehen usw.).
Zurück zu Deiner Frage:
Mit ioctl() kann man das Terminal anweisen, nicht die ASCII-Kodierung sondern die scan codes (raw) oder die key codes (medium raw) vom Tastaturtreiber zu erhalten. Der Raw-Modus der Tastatureingabe ist nicht zu verwechseln mit dem raw-Modus des Terminals. Ersteres entscheidet darüber, wie das Terminal die Eingabe erhält, letzteres was es mit der Eingabe macht.
Mit dem Befehl showkey kannst Du an der Shell testen, ob Deine Konfiguration überhaupt den Eingriff in den Tastaturtreiber zulässt. Im Quellcode findest Du auch die nötige Vorgehensweise.
Ich weiss leider nicht, inwieweit die Sache per POSIX standardisiert ist. Es kann daher sein, dass das nur für Linux gilt, oder scan und key codes plattformabhängig sind. Windows geht hier einen ganz anderen Weg, da Du aber von curses sprachst, hab ich das aussen vor gelassen.
Edit:
Hab grad mal nachgeschaut, zumindest im Teil der Terminalspezifikation von POSIX konnte ich nichts über eine Standardisierung der Tastatureingabe finden. Falls nicht alle Unices von einander abgeschrieben haben, dürften die codes und die Zugriffsmöglichkeit hierauf sehr verschieden sein.
Edit2:
Fast hätt ichs vergessen - unter X kommst du so nicht zum Ziel, da X seinerseits an der Systemkonsole (/dev/console) im raw-Modus lauscht und die scan modes in Events übersetzt. Du könntest aber die Keyboardevents im X abfangen. Ob die ganze Sache den Aufwand wert ist, musst Du selber wissen.
Terminals sind für den Austausch von kodierten Zeichen (ASCII) konzipiert worden (von Fernschreibern herkommend - tty), daher macht es Sinn, die Tasten standardmäßig als ASCII-Zeichen weiterzureichen. Die Steuerkommandos des Terminals sind dann nichts weiter als eine bestimmte Abfolge von Zeichen, die das Terminal entsprechend interpretiert. Das Terminal selbst unterstützt eine Reihe von Arbeitsmodi, mit denen Funktionalität hinzu- oder abgeschaltet werden können. So weist z.B. das kanonische Flag (ICANON) das Terminal an, den internen Zeilerpuffer zu verwenden und die Eingabe erst mit dem Zeilenende an die Anwendung weiterzugeben.
Bibliotheken wie curses "bügeln" die Funktionvielfalt und Eigenheiten der Terminals halbwegs glatt. Hierzu wird in der Regel die Eingabe auf "dumm" gestellt (raw-Modus des Terminals - Zeichen werden 1:1 weitergegeben) und die Ausgabe wird terminaltypgerecht aufbereitet (mit Escapecodes versehen usw.).
Zurück zu Deiner Frage:
Mit ioctl() kann man das Terminal anweisen, nicht die ASCII-Kodierung sondern die scan codes (raw) oder die key codes (medium raw) vom Tastaturtreiber zu erhalten. Der Raw-Modus der Tastatureingabe ist nicht zu verwechseln mit dem raw-Modus des Terminals. Ersteres entscheidet darüber, wie das Terminal die Eingabe erhält, letzteres was es mit der Eingabe macht.
Mit dem Befehl showkey kannst Du an der Shell testen, ob Deine Konfiguration überhaupt den Eingriff in den Tastaturtreiber zulässt. Im Quellcode findest Du auch die nötige Vorgehensweise.
Ich weiss leider nicht, inwieweit die Sache per POSIX standardisiert ist. Es kann daher sein, dass das nur für Linux gilt, oder scan und key codes plattformabhängig sind. Windows geht hier einen ganz anderen Weg, da Du aber von curses sprachst, hab ich das aussen vor gelassen.
Edit:
Hab grad mal nachgeschaut, zumindest im Teil der Terminalspezifikation von POSIX konnte ich nichts über eine Standardisierung der Tastatureingabe finden. Falls nicht alle Unices von einander abgeschrieben haben, dürften die codes und die Zugriffsmöglichkeit hierauf sehr verschieden sein.
Edit2:
Fast hätt ichs vergessen - unter X kommst du so nicht zum Ziel, da X seinerseits an der Systemkonsole (/dev/console) im raw-Modus lauscht und die scan modes in Events übersetzt. Du könntest aber die Keyboardevents im X abfangen. Ob die ganze Sache den Aufwand wert ist, musst Du selber wissen.
Hallo Jerch,
vielen Dank für deine ausführliche Antwort.
Zum Einsatz von curses: ich will ein Programm schreiben, dass ohne große Abhängigkeiten in der Konsole eines *nix laufen kann. Gut, man kann jetzt darüber streiten ob Python eine große Abhängigkeit ist, aber Just for Fun werkel ich im Augenblick lieber unter Python als in C oder C++.
Windows muss das nicht unterstützen, vor allem auch weil es viel mit dem Dateisystem tun wird, und da eh zu große Unterschiede zwischen der Posix- und der Windows-Welt gibt.
Das Programm soll unabhängig von X arbeiten können, sonst könnte ich auch direkt auf ein Toolkit ausweichen. Es soll aber vor allem die Arbeit in der Shell vereinfachen. Ich mag ja Fenster und nettes aussehen, aber auf Servern ist das nicht immer der Fall und da soll das Programm im Zweifelsfall auch laufen.
Gruß
Sparrow
vielen Dank für deine ausführliche Antwort.
Zum Einsatz von curses: ich will ein Programm schreiben, dass ohne große Abhängigkeiten in der Konsole eines *nix laufen kann. Gut, man kann jetzt darüber streiten ob Python eine große Abhängigkeit ist, aber Just for Fun werkel ich im Augenblick lieber unter Python als in C oder C++.
Windows muss das nicht unterstützen, vor allem auch weil es viel mit dem Dateisystem tun wird, und da eh zu große Unterschiede zwischen der Posix- und der Windows-Welt gibt.
Das Programm soll unabhängig von X arbeiten können, sonst könnte ich auch direkt auf ein Toolkit ausweichen. Es soll aber vor allem die Arbeit in der Shell vereinfachen. Ich mag ja Fenster und nettes aussehen, aber auf Servern ist das nicht immer der Fall und da soll das Programm im Zweifelsfall auch laufen.
Gruß
Sparrow
Unter X sind auch die Terminalemulatoren betroffen. Falls Du lokal root-Rechte hast, kannst Du showkey ja mal ausprobieren unter X. Du solltest allerdings vorher alle Daten speichern und ein sync machen, da Du X höchstwahrscheinlich neu starten musst. Während showkey als root läuft, bekommt X keine Eingabe mehr - das hilft Dir nicht weiter.
Im Prinzip erhalten xterm & Co die Eingabe über X:
- X startet und heftet sich an /dev/console (im raw-Modus)
- Du startest xterm
- X liest Tastureingabe von /dev/console und generiert keyboard event
- X routet Fokusregeln entsprechend die Events zum Zielclient (hier xterm)
- Client wertet Events aus (Terminalemulator fragt Events ab und generiert nach eigenem Regelset Zeichen, die in den Master des Pseudoterminals geschrieben werden)
- Shell/Anwendung XY am Slave kann die Eingabe nun erhalten
Die Übersetzung der XEvents passiert viel früher, nämlich im Terminalemulator selbst. Abhilfe schafft da ein eigener Terminalemulator
@remote:
Über ssh geht das leider auch nicht, da das Terminal ASCII weiterreicht. Pseudoterminals erhalten generell nur indirekt die Tastatureingabe über /dev/console (unter Linux).
Ich würde Dir raten, von einer solche Funktionalität abzusehen. Die Implementation ist viel zu schwierig umzusetzen und der Gewinn an Bedienkomfort marginal.
Im Prinzip erhalten xterm & Co die Eingabe über X:
- X startet und heftet sich an /dev/console (im raw-Modus)
- Du startest xterm
- X liest Tastureingabe von /dev/console und generiert keyboard event
- X routet Fokusregeln entsprechend die Events zum Zielclient (hier xterm)
- Client wertet Events aus (Terminalemulator fragt Events ab und generiert nach eigenem Regelset Zeichen, die in den Master des Pseudoterminals geschrieben werden)
- Shell/Anwendung XY am Slave kann die Eingabe nun erhalten
Die Übersetzung der XEvents passiert viel früher, nämlich im Terminalemulator selbst. Abhilfe schafft da ein eigener Terminalemulator
@remote:
Über ssh geht das leider auch nicht, da das Terminal ASCII weiterreicht. Pseudoterminals erhalten generell nur indirekt die Tastatureingabe über /dev/console (unter Linux).
Ich würde Dir raten, von einer solche Funktionalität abzusehen. Die Implementation ist viel zu schwierig umzusetzen und der Gewinn an Bedienkomfort marginal.
Hallo Jerch,
nochmal vielen Dank für deine Mühe.
Ich schätze ich werde das einfach so lösen, dass ich Optionale Funktionen so einbinde, dass ich mit den Funktionstasten zwischen den "Menüs" hin und her springen kann.
Das ist dann leicht veränderte User-Experience... aber hey, wir sind in einem Terminal.
Gruß
Sparrow
nochmal vielen Dank für deine Mühe.
Ich schätze ich werde das einfach so lösen, dass ich Optionale Funktionen so einbinde, dass ich mit den Funktionstasten zwischen den "Menüs" hin und her springen kann.
Das ist dann leicht veränderte User-Experience... aber hey, wir sind in einem Terminal.
Gruß
Sparrow