Skip to content

Commit f5bb0f8

Browse files
Added serial hack
1 parent 9db9e37 commit f5bb0f8

File tree

3 files changed

+161
-1
lines changed

3 files changed

+161
-1
lines changed

TermTk/TTkCore/drivers/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
from .term_pyodide import *
77
elif platform.system() == 'Linux':
88
from .unix import *
9-
from .term_unix import *
9+
import os
10+
if os.environ.get("TERMTK_FORCESERIAL",False):
11+
from .term_unix_serial import *
12+
else:
13+
from .term_unix import *
1014
elif platform.system() == 'Darwin':
1115
from .unix import *
1216
from .term_unix import *
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# MIT License
2+
#
3+
# Copyright (c) 2023 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+
__all__ = ['TTkTerm']
24+
25+
from ..TTkTerm.term_base import TTkTermBase
26+
from .term_unix import *
27+
28+
class _TTkTermSerial():
29+
@staticmethod
30+
def _getTerminalSizeSerial():
31+
import sys, os, tty, select, re
32+
try: import termios, fcntl
33+
except Exception as e:
34+
print(f'ERROR: {e}')
35+
exit(1)
36+
_attr = termios.tcgetattr(sys.stdin)
37+
tty.setcbreak(sys.stdin)
38+
def _read_new():
39+
stdinRead = ''
40+
while rlist := select.select( [sys.stdin], [], [] )[0]:
41+
_fl = fcntl.fcntl(sys.stdin, fcntl.F_GETFL)
42+
fcntl.fcntl(sys.stdin, fcntl.F_SETFL, _fl | os.O_NONBLOCK) # Set the input as NONBLOCK to read the full sequence
43+
stdinRead = sys.stdin.buffer.read()
44+
fcntl.fcntl(sys.stdin, fcntl.F_SETFL, _fl)
45+
try:
46+
stdinRead = stdinRead.decode()
47+
except Exception as e:
48+
yield f"bin: {stdinRead}"
49+
continue
50+
print(f"{len(stdinRead)=}")
51+
if '\033' in stdinRead:
52+
stdinSplit = stdinRead.split('\033')
53+
for ansi in stdinSplit[1:]:
54+
print(f"{ansi=}")
55+
yield ansi
56+
else:
57+
for ch in stdinRead:
58+
yield ch
59+
w,h = 80,24
60+
try:
61+
sys.stdout.write('\033[s\033[999;999H\033[6n\033[u')
62+
sys.stdout.flush()
63+
for stdinRead in _read_new():
64+
if m := re.match(r"\[(\d+);(\d+)R",stdinRead):
65+
h = int(m.group(1))
66+
w = int(m.group(2))
67+
break
68+
finally:
69+
termios.tcsetattr(sys.stdin, termios.TCSANOW, _attr)
70+
return w,h
71+
_w, _h = None,None
72+
73+
@staticmethod
74+
def _getTerminalSize():
75+
if _TTkTermSerial._w is None:
76+
_TTkTermSerial._w, _TTkTermSerial._h = _TTkTermSerial._getTerminalSizeSerial()
77+
return _TTkTermSerial._w, _TTkTermSerial._h
78+
79+
TTkTermBase.getTerminalSize = _getTerminalSize
80+
81+
82+

tests/t.pty/test.serial.001.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/usr/bin/env python3
2+
3+
# MIT License
4+
#
5+
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
6+
#
7+
# Permission is hereby granted, free of charge, to any person obtaining a copy
8+
# of this software and associated documentation files (the "Software"), to deal
9+
# in the Software without restriction, including without limitation the rights
10+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
# copies of the Software, and to permit persons to whom the Software is
12+
# furnished to do so, subject to the following conditions:
13+
#
14+
# The above copyright notice and this permission notice shall be included in all
15+
# copies or substantial portions of the Software.
16+
#
17+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
# SOFTWARE.
24+
25+
# Example from:
26+
# https://stackoverflow.com/questions/40931467/how-can-i-manually-get-my-terminal-to-return-its-character-size
27+
28+
import sys, os, select, signal, re
29+
import logging
30+
31+
try: import fcntl, termios, tty
32+
except Exception as e:
33+
print(f'ERROR: {e}')
34+
exit(1)
35+
36+
# Init
37+
_attr = termios.tcgetattr(sys.stdin)
38+
tty.setcbreak(sys.stdin)
39+
40+
def read_new():
41+
stdinRead = ''
42+
while rlist := select.select( [sys.stdin], [], [] )[0]:
43+
_fl = fcntl.fcntl(sys.stdin, fcntl.F_GETFL)
44+
fcntl.fcntl(sys.stdin, fcntl.F_SETFL, _fl | os.O_NONBLOCK) # Set the input as NONBLOCK to read the full sequence
45+
stdinRead = sys.stdin.buffer.read()
46+
fcntl.fcntl(sys.stdin, fcntl.F_SETFL, _fl)
47+
try:
48+
stdinRead = stdinRead.decode()
49+
except Exception as e:
50+
yield f"bin: {stdinRead}"
51+
continue
52+
print(f"{len(stdinRead)=}")
53+
if '\033' in stdinRead:
54+
stdinSplit = stdinRead.split('\033')
55+
for ansi in stdinSplit[1:]:
56+
print(f"{ansi=}")
57+
yield '<ESC>'+ansi
58+
else:
59+
for ch in stdinRead:
60+
yield ch
61+
62+
try:
63+
sys.stdout.write('\033[s\033[999;999H\033[6n\033[u')
64+
sys.stdout.flush()
65+
for stdinRead in read_new():
66+
print(f"{stdinRead=}")
67+
if m := re.match(r"<ESC>\[(\d+);(\d+)R",stdinRead):
68+
h = int(m.group(1))
69+
w = int(m.group(2))
70+
print(f"{w=} {h=}")
71+
break
72+
finally:
73+
# Reset
74+
termios.tcsetattr(sys.stdin, termios.TCSANOW, _attr)

0 commit comments

Comments
 (0)