|
Udalrich
Anmeldungsdatum: 15. Mai 2019
Beiträge: 533
|
Eine (XFCE-) Konsole habe ich auf die Kodierung „ISO-8859-15“ gestellt (*), um eine compilierte Programmsammlung mit festverdrahteter ISO-Latein-Codierung laufenzulassen („legacy-code“). Die Ausgabe geht prima, also auch mit Umlautzeichen in 8-Bit ISO-Latein, aber bei der Tastatureingabe werden Umlaute nicht richtig angenommen: tippt man einen Umlaut, erscheint noch kein Zeichen, erst beim Drücken einer zweiten Taste erscheinen dann der Umlaut und das zweite Zeichen zusammen und danach wird die nächste Taste auch irgendwie verschluckt. (Das mag intern damit zusammenhängen, daß UTF-8 bei Sonderzeichen zwei Bytes belegt, während ISO-Latein immer mit einem Byte auskommt. Doch dieses Wissen hilft an dieser Stelle hier noch nicht weiter, leider.) Das Umlaute-Eingabe-Problem kann man auch selber erleben, indem man eine Konsole auf ISO-Latein umstellt und dann mal versucht, im Bash-Prompt Umlaute zu tippen: verzögert-doppeltes Ergebnis wie oben beschrieben. Mit dem GNOME-Terminal ist es das gleiche; sollte also nicht an XFCE liegen. Muß ich noch die Tastatur auf ISO-Latein umstellen „irgendwie“ ? Wäre kein Problem, denn ich lasse die Programmsammlung sowieso unter einem eigenen Benutzer laufen. Genaugenommen sogar auf einem eigenen Rechner bzw. in einem eigenen Virtualbox-Gast; d.h. ich könnte sogar systemweit etwas ändern, damit nur diese Umlaute-Eingabe in einer ISO-Latein-Konsole endlich funktioniert. Weiß jemand Rat? Danke. (*) Im xfce4-terminal übers Menü Terminal → Kodierung festlegen → Westeuropäisch → ISO-8859-15
|
|
Udalrich
(Themenstarter)
Anmeldungsdatum: 15. Mai 2019
Beiträge: 533
|
P.S. Die Tasteneingabe für die erwähnte Programmsammlung mache ich über ein kleines Bash-Skript, weil die Tasten sofort verarbeitet werden sollen, nicht erst nach Abschluß durch die Eingabetaste, wie die typischen read(line)-Funktionen in Fortran, C, Java, usw. es tun. Dazu benutzt mein Skript den Bash-Befehl "read" mit Parametern:
read -N1 -s taste
… und kann dann die $taste sofort nach Drücken auswerten im Rahmen der Programmsammlung. Der ähnliche Befehl
showkey --ascii
… reagiert richtig beim Eingeben eines Umlauts, doch zeigt er die Eingabe-Codes ja nur an, während ich ihr Ergebnis benötige, so wie beim „read -N1“-Befehl von Bash. Oder gibt es noch bessere Hilfsprogramme für die direkte Verarbeitung eines Tastendrucks (inklusive Umlauten) in einer ISO-Latein-codierten Konsole?
|
|
kB
Supporter, Wikiteam
Anmeldungsdatum: 4. Oktober 2007
Beiträge: 9837
|
Früher war zwar nicht alles besser, aber früher war klar, dass man die Zeichen-Ausgabe und die Zeichen-Eingabe getrennt umstellen muss. Ich vermute, dass ist immer noch so, aber inzwischen wurde das Eingabesystem mehrfach umgebaut und meine Kenntnisse über die damaligen technischen Zusammenhänge sind zum einen Teil veraltet und den Rest habe ich vergessen. Soweit ich mich erinnere, sind native Konsolen und GUI-Konsolen getrennt zu behandeln, unter X11 ging das irgendwie mit xkeycomp (oder so ähnlich) und bei Wayland ist es sicher anders als unter X11. Unter dem Stein, den Du da aufhebst, wimmelt es von Würmern, Käfern und Schleimpilzen. Leg den Stein lieber wieder hin!
|
|
Udalrich
(Themenstarter)
Anmeldungsdatum: 15. Mai 2019
Beiträge: 533
|
kB schrieb: Unter dem Stein, den Du da aufhebst, wimmelt es von Würmern, Käfern und Schleimpilzen. Leg den Stein lieber wieder hin!
Danke für die Hinweise. Manche Steine müssen leider aufgehoben und entfernt oder angepaßt werden. Da meine erwähnte Konsolen-Programmsammlung u.a. aus entfernten, ISO-Latein-codierten Binärdateien Textteile ausliest und auf Konsole ausgibt, bin ich (ausgabetechnisch) an die ISO-Latein-Codierung der Konsole gebunden. Außerdem wird auf diese Programmsammlung im Ubuntu-Rechner auch per Windows-Remote-Desktop zugegriffen, daher graphische Oberfläche mit GUI-Konsole auf Ubuntu-Seite. Die Kernfrage könnte ich kürzer stellen: Wie richtet man generell einen Ubuntu-Benutzer(zugang) ein, damit er in einer ISO-Latein-codierten GUI-Konsole Programme benutzen kann, welche ISO-Latein-codierte Textausgaben tätigen und Tasten inklusive Umlauten lesen können sollen? „Allein“ an der Umlaut-Eingabe scheitert es momentan. „luit“, „iconv“ usw. lösten mein Problem bisher auch nicht. Deswegen denke ich inzwischen, daß man „weiter unten“, z.B. Tastatur-Treiber (?) auch auf ISO-Latein umstellen müßte. Doch diesbezüglich bin ich als bloßer Anwendungsentwickler am Ende mit meinem …ISO-… Latein. Ich nehme an, daß Ubuntu, wie andere Betriebssysteme auch, früher einmal ganz unter ISO-Latein und erst später unter UTF-8 lief? Früher war das wirklich besser, als wir unterm Schneider CPC noch Z80-Maschinencode machten. ☺
|
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17630
|
Was gibt denn locale aus? Bei mir beispielsweise:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | locale
LANG=de_DE.UTF-8
LANGUAGE=de_DE:en_GB:en_US:en
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC=de_DE.UTF-8
LC_TIME=de_DE.UTF-8
LC_COLLATE="de_DE.UTF-8"
LC_MONETARY=de_DE.UTF-8
LC_MESSAGES="de_DE.UTF-8"
LC_PAPER=de_DE.UTF-8
LC_NAME=de_DE.UTF-8
LC_ADDRESS=de_DE.UTF-8
LC_TELEPHONE=de_DE.UTF-8
LC_MEASUREMENT=de_DE.UTF-8
LC_IDENTIFICATION=de_DE.UTF-8
|
Ich habe mit Tasten und Kodierungen auch schon verschiedenes erlebt und es war nicht erhebend. Aber wenn es sein muss, muss es halt sein.
|
|
Udalrich
(Themenstarter)
Anmeldungsdatum: 15. Mai 2019
Beiträge: 533
|
user_unknown schrieb: Was gibt denn locale aus?
Das gleiche Ergebnis:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | ~$ locale
LANG=de_DE.UTF-8
LANGUAGE=de_DE
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
LC_COLLATE="de_DE.UTF-8"
LC_MONETARY="de_DE.UTF-8"
LC_MESSAGES="de_DE.UTF-8"
LC_PAPER="de_DE.UTF-8"
LC_NAME="de_DE.UTF-8"
LC_ADDRESS="de_DE.UTF-8"
LC_TELEPHONE="de_DE.UTF-8"
LC_MEASUREMENT="de_DE.UTF-8"
LC_IDENTIFICATION="de_DE.UTF-8"
LC_ALL=
|
An den Orts-, Sprach- und Tastatur-Einstellungen von Ubuntu habe ich bisher nichts geändert. Lediglich eine GUI-Konsole auf ISO-Latein-Kodierung umgestellt; im xfce4-terminal übers Menü Terminal → Kodierung festlegen → Westeuropäisch → ISO-8859-15 Das Ergebnis, die problematische Eingabe von Umlauten, ist aber bei anderen Konsolen, z.B. der Gnome-Konsole mit eingestellter ISO-Latein-Kodierung, gleichermaßen vorhanden.
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11278
|
Udalrich schrieb: Deswegen denke ich inzwischen, daß man „weiter unten“, z.B. Tastatur-Treiber (?) auch auf ISO-Latein umstellen müßte. Doch diesbezüglich bin ich als bloßer Anwendungsentwickler am Ende mit meinem …ISO-… Latein.
Musst du denn Text mit iso-8859-15 an das Programm senden oder reicht es die Ausgabe passend zu dekodieren? Nutzt das Programm normalen Text mit Zeilenumbrüchen für die Ein- und Ausgabe oder muss man da noch spezielle Dinge wie Terminal-Escape-Sequenzen beachten?
|
|
kB
Supporter, Wikiteam
Anmeldungsdatum: 4. Oktober 2007
Beiträge: 9837
|
Möglicherweise wird Dich dieses, allerdings nicht mehr aktuelle Howto interessieren: http://tldp.org/HOWTO/Keyboard-and-Console-HOWTO.html Wie ich schon schrieb, verhält sich ein natives Linux-Terminal (wie z.B. über Strg+Alt+F3 zu erreichen) anders als ein GUI-Terminal. Das folgende gilt nur für native Terminals: Mit dem Programm kbd_mode kann man den Arbeitsmodus der Tastatur abfragen und umschalten:
kbd_mode # frage den Arbeitsmodus ab
kbd_mode -a # schaltet den ASCII-Modus ein
kbd_mode -u # schaltet den Unicode-Modus ein Normalerweise ist der Unicode-Modus aktiv. Der ASCII-Modus ist eigentlich nicht 7-bit-ASCII, sondern ein 8-Bit-Modus. Die von der Tastatur produzierten Scancodes werden also in 8-Bit-Zeichen umgesetzt, wie sie auch in den ISO-8859-Zeichensätzen verwendet werden. Inwieweit hier noch sprachspezifische Besonderheiten berücksichtigt werden, durchschaue ich nicht. Jedenfalls produziert meine Tastatur im ASCII-Modus beim Drücken der Umlaut-Tasten die erwarteten 1-Byte-Zeichen für die Umlaute nach ISO-8859. Getestet mit: cat - | hd Nach dem Absetzen des Befehls kann man beliebige Tasten blind drücken. Man erhält aber eine Ausgabe des Befehls erst nach dem Abschluss der Eingabe mit der Eingabetaste (= LF = 0x0a) und EOF (= Strg+D = 0x04)! (Leider schaffe ich kein Copy'n Paste aus dem nativen Terminal.) PS: Die Rückschaltung aus dem nativen Terminal in die GUI-Sitzung funktioniert bei mir übrigens per Strg+Alt+F2. Die Nummern für die Terminal können je nach Situation variieren.
|
|
Udalrich
(Themenstarter)
Anmeldungsdatum: 15. Mai 2019
Beiträge: 533
|
Danke auch an kB und Seahawk1986 für die Darlegungen! seahawk1986 schrieb: Musst du denn Text mit iso-8859-15 an das Programm senden oder reicht es die Ausgabe passend zu dekodieren? Nutzt das Programm normalen Text mit Zeilenumbrüchen für die Ein- und Ausgabe oder muss man da noch spezielle Dinge wie Terminal-Escape-Sequenzen beachten?
Bei der Ausgabe gibt mein Fortran-Programm ISO-Latein-Texte aus inklusive Terminal-Escape-Sequenzen („ECMA-48 CSI“), worüber u.a. die Menüführung abgewickelt ist (eben „legacy code“). Das funktioniert prima sowohl in ISO-Latein- als auch UTF8-Konsolen: bei letzteren bis auf die im Programm festverdrahteten Texte mit Umlauten. Weswegen ich eine ISO-Latein-Konsole benutze. Die Eingabe in der Konsole muß zeichenweise erfolgen, leider nicht zeilenweise wie sonst in Java, Gawk, Fortran üblich, wo dann die Eingabe von Umlauten auch unter ISO-Latein-Konsolen funktionieren würde. Deswegen rufe ich vom Fortran-Programm ein externes kleines Bash-Skript auf, welches den „read“-Befehl benutzt, der bis zu fünf 8bit-Werte liefert, um auch Sonder- und Funktionstasten abzudecken (letztere benötige ich). Das Skript muß den 8bit-ISO-Zahlencode der gedrückten Taste an das Fortran-Programm zurückliefern, was gut funktioniert bis beim Drücken einer Umlaut-Taste, weil Bash inklusive sein „read“ für UTF8 compiliert ist und dies unter ISO-Latein-Konsolen zeigt. (Den in ISO-Latein unbelegten Wertebereich von 131-142 entführe ich für meine Funktionstasten-Kennung, was aber nebensächlich ist.) Fortran :
| integer, parameter :: f1 = 131
integer :: zeichen
call execute_command_line("./skriptchen.sh", exitstat=zeichen)
if (zeichen == f1) then tue-dies-und-das
|
Und Skriptchen.sh :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | unset byte1 byte2 byte3 byte4 byte5
read -N1 -s byte1
read -N1 -s -t 0.001 byte2
read -N1 -s -t 0.001 byte3
read -N1 -s -t 0.001 byte4
read -N1 -s -t 0.001 byte5
taste=$byte1$byte2$byte3$byte4$byte5
unset code
case "$taste" in
$'\x1b\x4f\x50' ) # F1
code=131 ;;
$'\x1b\x5b\x31\x35\x7e' ) # F5
code=135 ;;
# usw
esac
if [ -v code ] ; then
exit $code
fi
printf -v code "%d" "'$taste"
exit $code
|
|
|
Udalrich
(Themenstarter)
Anmeldungsdatum: 15. Mai 2019
Beiträge: 533
|
Weil in einer ISO-Latein-Konsole meine Programmausgabe einwandfrei funktioniert, sollte ich mich wohl auf die Tasteneingabe konzentrieren. kB erwähnte „kbd_mode“, was wirklich gut hülfe, wenn es auch unter GUI-Konsolen funktioneren würde. 😐 Mein bisher benutzter Bash-Befehl read -N1 scheint hochstufig bzw. höherstufig zu arbieten, deswegen versagt er in einer ISO-Latein-Konsole beim Drücken einer Umlaut-Taste, da Linux inklusive Bash gegen UTF-8 compiliert wurde? Hingegen liefert showkey --ascii korrekt den jeweiligen 8bit-Wert gemäß ISO-Latein beim Drücken einer Umlaut-Taste. (Hingegen unter einer standardmäßigen UFT8-Konsole liefert er naturgemäß zwei 8bit-Werte zurück gemäß UFT8-Tabelle.) Doch muß man showkey ausdrücklich mit Strg+D beenden, womit es für meinen Einsatz flachfällt, fürchte ich. Den Quellcode von showkey würde ich schon anschauen, doch leider verstehe ich C nicht gut und Linux-Internes noch weniger. Weswegen ich froh war über das Finden von Bash's read-Funktion. Gibt es vielleicht ein Kommandozeilen-Programm, welches, ähnlich wie „showkey --ascii“, pro Tastendruck dessen uninterpretierten Tastencode zurückliefert und damit bei Umlauten auch in einer ISO-Latein-Konsole funktioniert? Danke für alle Mühen.
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11278
|
Wenn ich das richtig verstehe, bekommt das Skript auf stdin von deinen Terminal-Eingaben in UTF-8 encodierte Bytes.
Ich würde mal versuchen das Bash-Skript durch dieses Python3-Skript zu ersetzen - das transkodiert die Eingabe auf stdin automatisch von utf-8 nach latin9 (aka ISO-8859-15) um und filtert die angegebenen Tastencodes für F-Tasten usw. heraus:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 | #!/usr/bin/env python3
import sys
import select
import tty
import termios
control_characters = {
b'\x1b\x4f\x50': 131, # F1
b'\x1b\x5b\x31\x35\x7e': 135, # F5
}
class NonBlockingConsole:
buffer = b''
control = None
def __enter__(self):
self.old_stdin_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
return self
def __exit__(self, type, value, traceback):
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, self.old_stdin_settings)
def get_data(self):
if select.select([sys.stdin.buffer], [], [], 0) == ([sys.stdin.buffer], [], []):
while True:
self.buffer += sys.stdin.buffer.read(1)
for k, v in control_characters.items():
if self.buffer == k:
sys.exit(v)
if k.startswith(self.buffer):
break
else:
try:
r = self.buffer.decode('utf-8')
except:
pass
else:
self.buffer = b''
return r
with NonBlockingConsole() as nbc:
while True:
r = nbc.get_data()
if r:
sys.exit(ord(r.encode('latin9', errors='replace')))
|
Edit: kleine Optimierung, um stdin nicht unnötig ein zweites Mal zu öffnen.
Edit2: Ah, normale Zeichen sollen auch über den Exit-Code zurückgegeben werden
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11278
|
Wenn man das Skript laufen lässt und im Fortran-Programm von dessen stout liest, ist es vermutlich spürbar performanter als es für jedes Zeichen das Skript neu zu starten.
|
|
Udalrich
(Themenstarter)
Anmeldungsdatum: 15. Mai 2019
Beiträge: 533
|
seahawk1986 schrieb: Wenn ich das richtig verstehe, bekommt das Skript auf stdin von deinen Terminal-Eingaben in UTF-8 encodierte Bytes.
Nein, momentan läuft alles in einem Terminal mit ISO-8859-15-Codierung, kurz ISO-Latein. Ein gegen ISO-Latein (also nicht UTF-8) compiliertes Programm ruft dann mein Bash-Skript auf, welches einen Tastendruck einliest (ohne Eingabetaste) und dessen 8bit ISO-Latein-Byte an den Aufrufer zurückgibt. (Das Bash-Skript ist nötig, weil die bekannten Hochsprachen (u.a. Fortran) mit ihren get(line)-Funktionen typischerweise nur zeilenweise einlesen können, hier aber zeichenweises Einlesen gefragt ist.) Das Bash-Skript funktioniert bei normalen ASCII-Tasten, nicht jedoch bei Umlauten, weil Ubuntu in UTF-8 „denkt“ und daher – immer noch in einem ISO-Latein-Terminal – beim Drücken von z.B. „ä“ erst einen zweiten Tastendruck abwartet, bevor er ein ISO-Latein-Zeichen liefert. Große Ausnahme ist „showkey --ascii“, welches sofort den korrekten Umlaut-Bytecode anzeigt. Einfach mal ein Terminal öffnen, auf ISO-Latein-Codierung umstellen und folgendes auszuführen, dann eine Nicht-Umlaut-Taste drücken und danach das gleiche mit Umlaut-Taste:
read -N1 -s taste; gawk 'BEGIN{ printf("%c", ARGV[1]) }' $tasteIch würde mal versuchen das Bash-Skript durch dieses Python3-Skript zu ersetzen - das transkodiert die Eingabe auf stdin automatisch von utf-8 nach latin9 (aka ISO-8859-15) um und filtert die angegebenen Tastencodes für F-Tasten usw. heraus:
Danke, habe ich versucht, doch leider scheint es nicht zu funtionieren. 1) In einem Terminal mit ISO-Latein wartet das Python-Skript ewig, sobald ich eine Umlauttaste drücke. 2) In einem Terminal mit UTF-8 muß ich beim Drücken einer Umlaut-Taste zwei Tasten drücken. Aber den UTF-8-Fall möchte ich sowieso besser nicht weiter verfolgen, weil er nicht zu meinen ISO-Latein-Textausgaben paßt. Wie würde ein kleines Python-Skript aussehen, welches in einem ISO-Latein-Terminal ein Zeichen einliest und dieses (oder dessen ASCII-Code bzw. ISO-Latein-Code als Bytewert) zurückliefert? Gibt es dann das Problem auch, daß man nach dem Drücken einer Umlaute-Taste noch eine Taste drücken muß, bevor das „Python read“ zurückkommt?
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11278
|
Udalrich schrieb: seahawk1986 schrieb: Wenn ich das richtig verstehe, bekommt das Skript auf stdin von deinen Terminal-Eingaben in UTF-8 encodierte Bytes.
Nein, momentan läuft alles in einem Terminal mit ISO-8859-15-Codierung, kurz ISO-Latein.
Ah ok, dann bekommst du eigentlich schon die gewünschten Bytes, aber die Beschränkung auf ein Zeichen beim read klappt bei Umlauten nicht. (Das Bash-Skript ist nötig, weil die bekannten Hochsprachen (u.a. Fortran) mit ihren get(line)-Funktionen typischerweise nur zeilenweise einlesen können, hier aber zeichenweises Einlesen gefragt ist.)
Ich habe mit Fortran noch nicht wirklich etwas gemacht, aber getc (oder das ältere fgetc) klingt so, als ob man damit Daten Byte für Byte (bzw. char für char) einlesen könnte. Und laut Standard_streams kann Fortran stdin öffnen. Das Bash-Skript funktioniert bei normalen ASCII-Tasten, nicht jedoch bei Umlauten, weil Ubuntu in UTF-8 „denkt“ und daher – immer noch in einem ISO-Latein-Terminal – beim Drücken von z.B. „ä“ erst einen zweiten Tastendruck abwartet, bevor er ein ISO-Latein-Zeichen liefert. Große Ausnahme ist „showkey --ascii“, welches sofort den korrekten Umlaut-Bytecode anzeigt.
Das zeigt bei UTF-8 erwartungsgemäß eine Abfolge von Bytes Einfach mal ein Terminal öffnen, auf ISO-Latein-Codierung umstellen und folgendes auszuführen, dann eine Nicht-Umlaut-Taste drücken und danach das gleiche mit Umlaut-Taste:
read -N1 -s taste; gawk 'BEGIN{ printf("%c", ARGV[1]) }' $taste
Wie es aussieht klappt das Zählen der Zeichen mit -N1 nicht, wenn als erstes ein Byte mit einem Wert > 127 gelesen wird. Ich würde mal versuchen das Bash-Skript durch dieses Python3-Skript zu ersetzen - das transkodiert die Eingabe auf stdin automatisch von utf-8 nach latin9 (aka ISO-8859-15) um und filtert die angegebenen Tastencodes für F-Tasten usw. heraus:
Danke, habe ich versucht, doch leider scheint es nicht zu funtionieren. 1) In einem Terminal mit ISO-Latein wartet das Python-Skript ewig, sobald ich eine Umlauttaste drücke.
Mein Skript ist auf UTF-8 enkodierte Zeichen als Eingabe ausgelegt, d.h. es kommen entweder ASCII-Zeichen (ein Byte groß, das erste Bit ist 0) oder sonstige UTF-8 Zeichen mit einer Abfolge von bis zu 5 Bytes, wobei bei Bytes, bei denen das erste Bit 1 ist, anzeigen, dass man das nächste Byte lesen muss, um das Zeichen dekodieren zu können. Wenn man damit ein Zeichen aus einem 8-Bit Encoding liest, das > 127 ist, hängt das naturgemäß. 2) In einem Terminal mit UTF-8 muß ich beim Drücken einer Umlaut-Taste zwei Tasten drücken. Aber den UTF-8-Fall möchte ich sowieso besser nicht weiter verfolgen, weil er nicht zu meinen ISO-Latein-Textausgaben paßt.
Mit dem Stand des Skripts nach meinem zweiten Edit kann ich das mit xfce4-terminal und UTF-8 unter Ubuntu 18.04 nicht nachvollziehen. Beim Drücken eines Umlauts beendet es sich sofort (z.B. ä → Exit Code 228).
Wie würde ein kleines Python-Skript aussehen, welches in einem ISO-Latein-Terminal ein Zeichen einliest und dieses (oder dessen ASCII-Code bzw. ISO-Latein-Code als Bytewert) zurückliefert?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 | #!/usr/bin/env python3
import array
import fcntl
import os
import sys
import select
import tty
import termios
control_characters = {
b'\x1b\x4f\x50': 131, # F1
b'\x1b\x5b\x31\x35\x7e': 135, # F5
}
class NonBlockingConsole:
def __enter__(self):
self.fd = sys.stdin.fileno()
self.old_stdin_settings = termios.tcgetattr(self.fd)
self.newattr = termios.tcgetattr(self.fd)
self.newattr[3] = self.newattr[3] & ~termios.ICANON & ~termios.ECHO
termios.tcsetattr(self.fd, termios.TCSANOW, self.newattr)
tty.setcbreak(self.fd)
return self
def __exit__(self, type, value, traceback):
termios.tcsetattr(self.fd, termios.TCSADRAIN, self.old_stdin_settings)
def output_char(self, c):
# write hex code of char to stderr
print("output char", hex(c), file=sys.stderr)
# output to stdout:
sys.stdout.buffer.write(chr(c).encode('latin9'))
sys.stdout.buffer.flush()
# alternatively set an exit code:
# sys.exit(c)
def buffer_has_complete_control_character(self):
for k, v in control_characters.items():
if k == self.buffer:
self.output_char(v)
self.buffer = b''
return True
elif k.startswith(self.buffer):
return False
return None
def read_data(self):
self.buffer = b''
buf_ = array.array('i', [0])
fcntl.ioctl(self.fd, termios.FIONREAD, buf_, 1)
self.buffer += os.read(self.fd, buf_[0])
if self.buffer_has_complete_control_character() is None:
for c in self.buffer:
self.output_char(c)
self.buffer = b''
if __name__ == '__main__':
with NonBlockingConsole() as nbc:
while True:
nbc.read_data()
|
Gibt es dann das Problem auch, daß man nach dem Drücken einer Umlaute-Taste noch eine Taste drücken muß, bevor das „Python read“ zurückkommt?
Wenn man wie oben gezeigt einzelne Bytes einliest nicht - für die F-Tasten musste ich das ganze noch mal auf eine ioctl-Operation Umstellen, weil sonst Tastendrücke der F-Tasten erst registriert werden, wenn man die nächste Taste gedrückt hat - nur die Escape-Taste bekomme ich mit dem ioctl-Ansatz leider nicht dazu verwertbare Tastendrücke zu liefern. In der Methode output_char kannst du ein- bzw. auskommentieren, was du für die Ausgabe nutzen möchtest (Debug-Ausgabe auf stderr, stdout, exit-Code).
|
|
kB
Supporter, Wikiteam
Anmeldungsdatum: 4. Oktober 2007
Beiträge: 9837
|
Udalrich schrieb: […] Das Bash-Skript funktioniert bei normalen ASCII-Tasten, nicht jedoch bei Umlauten, weil Ubuntu in UTF-8 „denkt“ und daher – immer noch in einem ISO-Latein-Terminal – beim Drücken von z.B. „ä“ erst einen zweiten Tastendruck abwartet, bevor er ein ISO-Latein-Zeichen liefert.
Das kann man leicht ändern: $ echo $LANG
de_DE.UTF-8
$ read -s -n1 ; echo -n $REPLY | hd
00000000 c3 a4 |..|
00000002
LANG= read -s -n1 ; echo -n $REPLY | hd
00000000 c3 |.|
00000001
$ � Erklärung: Das lief in einem GUI-Terminal, aber in einem nativen verhält es sich genauso. read liest mit der Option -n1 genau ein Zeichen, welches aus einem oder mehreren Byte bestehen kann. Was genau ein Zeichen sein soll, entnimmt read der eingestellten locale. Normalerweise verwendet Ubuntu Unicode, d.h.
ein Zeichen, welches mit einem Byte im Bereich 0 .. 127 beginnt, besteht nur aus diesem einen Byte – das sind die 7-Bit-ASCII-Zeichen ein Zeichen, welches mit einem Byte im Bereich 128 .. 255 beginnt, besteht aus mehreren Byte
Bei Eingabe eines Umlauts wir auf jeden Fall als erstes Byte ein Byte ab 128 erzeugt. Wenn die aus der Variablen LANG gelernte Zeichencodierung nicht einem 8-Bit-Zeichensatz entspricht, wartet read daher auf weitere Bytes, bis es die Bytefolge als vollständiges Zeichen erkennt. Im Beispiel habe ich in beiden Fällen nur die Ä-Taste gedrückt. In einem nativen Terminal kann man zusätzlich per kbd_mode -a auch die Zeichenerzeugung aus Scancodes umstellen auf den 8-Bit-Zeichensatz. Statt einfach die Variable LANG für die Ausführung des read-Befehls zu löschen, ist es natürlich sauberer, explizit den Zeichensatz auf ISO-8859 zu wechseln: $ LANG=de_DE.iso885915@euro
$ read -s -n1 ; echo -n $REPLY | hd
00000000 c3 |�|
00000001
$ �
|