英文:
reading escaped sequences from sys.stdin, bytes after escape are delayed until the next keystroke using select
问题
我正在尝试在Linux中处理按键输入,以便处理箭头键以及普通的字母数字键等。这种潜在简单的方法使用select和stdin可以接收所有按键,但在按下(例如)向上箭头后,我不会立即收到转义后的额外字符,直到我按下另一个键。
这些额外的字符存在,如果我读取它们,但如果它们不存在(例如只按下转义键),那么尝试读取将挂起输入,并且当我获得下一个字符读取时,我不知道它是否是转义序列的一部分(除非查看时间戳)。
我尝试过其他包,但它们都存在问题 - 需要root权限,或者只在有屏幕的情况下工作,例如。
我想要在PC上直接运行此代码,或者通过SSH连接到仅运行服务器的树莓派上。
这是一个简单的测试程序:
#!/usr/bin/env python
import sys
import tty
import termios
import select, time
old_settings = termios.tcgetattr(sys.stdin)
ts = time.time()
try:
tty.setraw(sys.stdin.fileno())
while True:
rlist, _, _ = select.select([sys.stdin], [], [], 2)
if rlist:
# Read a single character
char = sys.stdin.read(1)
if ord(char) == 27:
print('at %6.2f ESCAPE!' % (time.time()-ts), '\x0d')
# at this point any other characers can be read, but you can't check to see if read will block!!!
else:
print('at %6.2f gotta' % (time.time()-ts), char if ord(char) > 32 else '{%d}' % ord(char), '\x0d')
if char == 'x':
break
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
print('byeeeee')
如果我输入'abc
取消注释rlist行,一切都按预期工作:
按下向上箭头键会给我
$ python3 inputer3.py
at 1.38 gotta a
at 2.44 gotta b
at 3.72 gotta c
at 4.88 ESCAPE!
at 9.32 gotta d
at 10.51 ESCAPE!
at 13.42 gotta [
at 13.42 gotta A
at 13.42 gotta e
将rlist行注释掉后,一切都按预期工作:
按下向上箭头键会给我
$ python3 inputer3.py
at 1.33 gotta a
at 2.10 gotta b
at 2.93 gotta c
at 4.66 ESCAPE!
at 5.58 gotta d
at 7.88 ESCAPE!
at 7.88 gotta [
at 7.88 gotta A
at 10.44 gotta e
希望这有助于你理解代码的问题。
英文:
I'm trying to process keystrokes in linux so I can handle arrow keys as well as normal alphnumeric etc keys.
This potentially simple approach using select and stdin delivers all the keys, but after pressing (for example) uparrow, I don't get the extra chars after escape until I press another key.
The extra characters are there if I read them, but if they aren't there (as in just pressing escape), then trying to read will hang the input and when I get the next char read I don 't know if it was part of an escape sequence or not (unless I look at timestamps)
I have tried other packages but they all have problems - requiring root, or only working if there is a screen present for example.
I want to run this code both directly on a PC, or over ssh to a raspberry pi with a server only build.
Here is a trivial test program:
#!/usr/bin/env python
import sys
import tty
import termios
import select, time
old_settings = termios.tcgetattr(sys.stdin)
ts = time.time()
try:
tty.setraw(sys.stdin.fileno())
while True:
rlist, _, _ = select.select([sys.stdin], [], [], 2)
if rlist:
# Read a single character
char = sys.stdin.read(1)
if ord(char) == 27:
print('at %6.2f ESCAPE!' % (time.time()-ts), '\x0d')
# at this point any other characers can be read, but you can't check to see if read will block!!!
else:
print('at %6.2f gotta' % (time.time()-ts), char if ord(char) >32 else '{%d}' % ord(char), '\x0d')
if char == 'x':
break
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
print('byeeeee')
If I type 'abc<esc>d<uparrow>e' you can see the qualifying chars after esc for uparrow don't appear until I type e. If I run the same code without select, then the timings are correct, but the code blocks waiting for all keyboard input so I cannot respond to other events.
$ python3 inputer3.py
at 1.38 gotta a
at 2.44 gotta b
at 3.72 gotta c
at 4.88 ESCAPE!
at 9.32 gotta d
at 10.51 ESCAPE!
at 13.42 gotta [
at 13.42 gotta A
at 13.42 gotta e
Commenting out the rlist lines it all works as expected:
pressing uparrow gives me <esc>[A all with almost identical timestampsL
$ python3 inputer3.py
at 1.33 gotta a
at 2.10 gotta b
at 2.93 gotta c
at 4.66 ESCAPE!
at 5.58 gotta d
at 7.88 ESCAPE!
at 7.88 gotta [
at 7.88 gotta A
at 10.44 gotta e
答案1
得分: 1
Instead of sys.stdin.read
, use os.read
:
#!/usr/bin/env python
import os, sys
import tty
import termios
import select, time
old_settings = termios.tcgetattr(sys.stdin)
ts = time.time()
try:
tty.setraw(sys.stdin.fileno())
while True:
rlist, _, _ = select.select([sys.stdin], [], [], 2)
if rlist:
# Read a single character
# char = sys.stdin.read(1)
char = os.read(sys.stdin.fileno(), 1).decode("utf-8")
if ord(char) == 27:
print('at %6.2f ESCAPE!' % (time.time()-ts), '\x0d')
# at this point any other characters can be read, but you can't check to see if read will block!!!
else:
print('at %6.2f gotta' % (time.time()-ts), char if ord(char) > 32 else '{%d}' % ord(char), '\x0d')
if char == 'x':
break
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
print('byeeeee')
(Note: The code portion has been translated as requested.)
英文:
Instead of sys.stdin.read
, use os.read
:
#!/usr/bin/env python
import os, sys
import tty
import termios
import select, time
old_settings = termios.tcgetattr(sys.stdin)
ts = time.time()
try:
tty.setraw(sys.stdin.fileno())
while True:
rlist, _, _ = select.select([sys.stdin], [], [], 2)
if rlist:
# Read a single character
# char = sys.stdin.read(1)
char = os.read(sys.stdin.fileno(), 1).decode("utf-8")
if ord(char) == 27:
print('at %6.2f ESCAPE!' % (time.time()-ts), '\x0d')
# at this point any other characers can be read, but you can't check to see if read will block!!!
else:
print('at %6.2f gotta' % (time.time()-ts), char if ord(char) >32 else '{%d}' % ord(char), '\x0d')
if char == 'x':
break
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
print('byeeeee')
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论