1
1
import sys
2
2
import termios
3
3
from copy import copy
4
+ from io import StringIO
4
5
from select import select
5
6
6
7
from ._config import config
@@ -12,53 +13,71 @@ class ReadChar:
12
13
13
14
def __init__ (self , cfg : config = None ) -> None :
14
15
self .config = cfg if cfg is not None else config
16
+ self ._buffer = StringIO ()
15
17
16
18
def __enter__ (self ) -> "ReadChar" :
17
19
self .fd = sys .stdin .fileno ()
18
20
term = termios .tcgetattr (self .fd )
19
21
self .old_settings = copy (term )
20
- term [3 ] &= ~ (termios .ICANON | termios .ECHO | termios .IGNBRK | termios .BRKINT )
22
+
23
+ term [3 ] &= ~ (
24
+ termios .ICANON # don't require ENTER
25
+ | termios .ECHO # don't echo
26
+ | termios .IGNBRK
27
+ | termios .BRKINT
28
+ )
29
+ term [6 ][termios .VMIN ] = 0 # imideatly process every input
30
+ term [6 ][termios .VTIME ] = 0
21
31
termios .tcsetattr (self .fd , termios .TCSAFLUSH , term )
22
32
return self
23
33
24
34
def __exit__ (self , type , value , traceback ) -> None :
25
- termios .tcsetattr (self .fd , termios .TCSADRAIN , self .old_settings )
35
+ termios .tcsetattr (self .fd , termios .TCSAFLUSH , self .old_settings )
36
+
37
+ def __update (self ) -> None :
38
+ """check stdin and update the interal buffer if it holds data"""
39
+ if sys .stdin in select ([sys .stdin ], [], [], 0 )[0 ]:
40
+ pos = self ._buffer .tell ()
41
+ data = sys .stdin .read ()
42
+ self ._buffer .write (data )
43
+ self ._buffer .seek (pos )
26
44
27
45
@property
28
46
def key_waiting (self ) -> bool :
29
47
"""True if a key has been pressed and is waiting to be read. False if not."""
30
- return sys .stdin in select ([sys .stdin ], [], [], 0 )[0 ]
48
+ self .__update ()
49
+ pos = self ._buffer .tell ()
50
+ next_byte = self ._buffer .read (1 )
51
+ self ._buffer .seek (pos )
52
+ return bool (next_byte )
31
53
32
54
def char (self ) -> str :
33
55
"""Reads a singel char from the input stream and returns it as a string of
34
56
length one. Does not require the user to press ENTER."""
35
- return sys .stdin .read (1 )
57
+ self .__update ()
58
+ return self ._buffer .read (1 )
36
59
37
60
def key (self ) -> str :
38
61
"""Reads a keypress from the input stream and returns it as a string. Keypressed
39
62
consisting of multiple characterrs will be read completly and be returned as a
40
63
string matching the definitions in `key.py`.
41
64
Does not require the user to press ENTER."""
42
- c1 = self .char ()
65
+ self .__update ()
43
66
67
+ c1 = self .char ()
44
68
if c1 in self .config .INTERRUPT_KEYS :
45
69
raise KeyboardInterrupt
46
-
47
70
if c1 != "\x1B " :
48
71
return c1
49
-
50
72
c2 = self .char ()
51
73
if c2 not in "\x4F \x5B " :
52
74
return c1 + c2
53
-
54
75
c3 = self .char ()
55
76
if c3 not in "\x31 \x32 \x33 \x35 \x36 " :
56
77
return c1 + c2 + c3
57
-
58
78
c4 = self .char ()
59
79
if c4 not in "\x30 \x31 \x33 \x34 \x35 \x37 \x38 \x39 " :
60
80
return c1 + c2 + c3 + c4
61
-
62
81
c5 = self .char ()
63
82
return c1 + c2 + c3 + c4 + c5
64
83
0 commit comments