[英]How do I accept input from arrow keys, or accept directional input?
这可能是一个xy问题,但我正在尝试构建一个基于内核的文本编辑器,类似于vim
或nano
,我知道如何使用转义字符清除屏幕,然后重新打印,我可以让它接受字符,但我不知道如何让它接受箭头输入导航。 我认为它们有ASCII值,但显然不是。 有没有办法使用箭头,还是我必须进行导航模式和插入模式像vim
?
我也曾简短地玩curses
,但这是令人望而却步的,因为据我所知,必须为它打开一个全新的窗口,这与我所拥有的单个终端窗口的视觉不兼容。
编辑: curses
也是禁止,因为它清除了窗口,我不想要。
curses
正是你想要的。 事实上,我相信vim实现了与curses的接口。
尝试将以下代码放入名为test_curses.py
的文件中:
import curses
screen = curses.initscr()
screen.addstr("Hello World!!!")
screen.refresh()
screen.getch()
curses.endwin()
现在打开一个终端 (不是IDLE!一个真正的终端!)并通过以下方式运行它:
python test_curses.py
你应该看到终端被清除了, Hello World!!!
写作出现了。 按任意键,程序将停止,恢复旧的终端内容。
请注意, curses
库并不像您习惯的那样简单且“用户友好”。 我建议阅读教程 (不幸的是C语言,但python接口大致相同)
我结束使用此问题的代码,并修改__init__
语句,使其在列表中最多接受3个字符。
import sys
class _Getch:
"""Gets a single character from standard input. Does not echo to the
screen."""
def __init__(self):
self.impl = _GetchUnix()
def __call__(self):# return self.impl()
charlist = []
counter = 0
for i in range(3):
try:charlist.append(self.impl())
except:pass
if charlist[i] not in [chr(27),chr(91)]:#TODO sort out escape vs arrow duh use len()
break
if len(charlist) > 1:
if charlist == [chr(27),chr(27)]:
break
if len(charlist) == 3:
if charlist[2] == 'a'
return 'u-arr'
if charlist[2] == 'b'
return 'd-arr'
if charlist[2] == 'c'
return 'r-arr'
if charlist[2] == 'd'
return 'l-arr'
if len(charlist == 2):
if charlist == [chr(27),chr(27)]
return chr(27)
if len(charlist == 1)
return charlist[0]
return ''
class _GetchUnix:
def __init__(self):
import tty, sys
def __call__(self):
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
这允许我从编辑器的键盘获取箭头键以及所有其他字符和转义序列。 它使得“Getch”类不是严格意义上的get char
克隆,因为它返回一个字符串,但它更有用。
用于构建命令行客户端的Python包click
还附带了一个允许您获取按键事件的实现:
import click
key = click.getchar()
它将键表示作为Unicode字符返回,并且“箭头键之类的东西将以平台的本机转义格式显示。”
import click
click.echo('Continue? [yn] ', nl=False)
c = click.getchar()
click.echo()
if c == 'y':
click.echo('We will go on')
elif c == 'n':
click.echo('Abort!')
else:
click.echo('Invalid input :(')
按箭头键或按下时的任何其他键执行所需操作
# key_event_handler.py
import sys
import select
import pty
import os
import time
import fcntl
import tty
import termios
def __select( iwtd, owtd, ewtd, timeout=None):
'''This is a wrapper around select.select() that ignores signals. If
select.select raises a select.error exception and errno is an EINTR
error then it is ignored. Mainly this is used to ignore sigwinch
(terminal resize). '''
# if select() is interrupted by a signal (errno==EINTR) then
# we loop back and enter the select() again.
if timeout is not None:
end_time = time.time() + timeout
while True:
try:
return select.select(iwtd, owtd, ewtd, timeout)
except select.error:
err = sys.exc_info()[1]
if err.args[0] == errno.EINTR:
# if we loop back we have to subtract the
# amount of time we already waited.
if timeout is not None:
timeout = end_time - time.time()
if timeout < 0:
return([], [], [])
else:
# something else caused the select.error, so
# this actually is an exception.
raise
STDIN_FILENO=pty.STDIN_FILENO
STDOUT_FILENO=pty.STDOUT_FILENO
string_type=bytes
sys.stdout.write(string_type())
sys.stdout.flush()
buffer = string_type()
mode = tty.tcgetattr(STDIN_FILENO)
tty.setraw(STDIN_FILENO)
try:
while True:
r, w, e = __select([STDIN_FILENO], [], [],timeout=1)
if STDIN_FILENO in r:
#It accepts all keys from keyboard
data=os.read(STDIN_FILENO, 1)
#Bellow line returns ASCII value of a charector
ascii_value=ord(data[0])
##########################################################################
## Your code goes here ##
## ##
# Do some action here by matching the ASCII value #
# you can handle your program by making use of special keys like #
# Backspace, Ctrl, Ctrl+A,Ctrl+B, Ctrl+C, ...Ctrl+Z, Esc,F1, ...,F12 ....#
# Tab,Enter,Arrow keys,Alphabetic and Numeric keys are also supported #
##########################################################################
# #
#To Print use bellow line rather than print or sys.stdout.write(data) #
#os.write(STDOUT_FILENO,data) #
## #
##########################################################################
finally:
tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)
然后打开终端并运行
key_event_handler.py
这个程序主要是捕获按键和按下ascii键,这个程序也可以用于多线程应用程序中的非阻塞I / O
我知道我迟到了,但我真的很喜欢@elbaschid提到的click
包。 我不知道为什么他没有被投票 - 也许是因为他的例子没有显示如何处理专门的光标键。
这是我的0.02美元:
#!/usr/bin/python
import click
printable = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
while True:
click.echo('Continue? [yn] ', nl=False)
c = click.getchar()
click.echo()
if c == 'y':
click.echo('We will go on')
elif c == 'n':
click.echo('Abort!')
break
elif c == '\x1b[D':
click.echo('Left arrow <-')
elif c == '\x1b[C':
click.echo('Right arrow ->')
else:
click.echo('Invalid input :(')
click.echo('You pressed: "' + ''.join([ '\\'+hex(ord(i))[1:] if i not in printable else i for i in c ]) +'"' )
这会处理光标键,并作为奖励打印它尚未识别的任何键盘快捷键的py-string表示。 例如,Ctrl-s是"\\x13"
。 您可以稍后在另一个内部使用它
elif c == ??
我试图将编辑添加到@elbaschid的答案,但它被拒绝了¯\\ _(ツ)_ /¯。 如果你也喜欢我的答案,请给他信任
令人敬畏的库,用于快速命令行原型设计。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.