Python:内置键盘信号/中断

11 投票
3 回答
6565 浏览
提问于 2025-04-16 14:39

我现在需要为一个程序提供多个键盘中断。有没有简单的方法可以使用信号类来实现这一点?我现在使用的是 SIGINT/Ctrl+C,但找不到其他的键盘映射。

如果能有超过两个信号就好了。我该如何定义更多的信号,或者有没有更好的方法来捕捉“用户的中断”?

以下是当前代码的高层次视图:

 def shutdown(signal, frame):
       if(signal==2): #sigint
          print 'do something'
       elif signal==XX:
          print 'do something else'
       # continued...

 signal.signal(signal.SIGINT, shutdown)
 signal.signal(signal.SOMEOTHERTYPE, shutdown)


 print 'start'
 t = Thread(target=run)
 t.setDaemon(True)
 t.start()

 print 'Done, press ctrl c, or ctrl ? '
 signal.pause()

3 个回答

0

我不太确定有没有现成的方法可以定义新的信号,并把它们和键盘事件关联起来。

如果你需要这种灵活性,可能需要用一个接口线程,这个线程会一直在前台运行,监听键盘事件。然后它可以用你喜欢的方式和其他线程进行沟通。

7

在Linux系统中,按下Ctrl+\会发送一个叫做SIGQUIT的信号。

11

提到的 Ctrl+\ 是由你的终端软件来解释的,这个按键的功能是通过 stty 来设置的。除非你有办法自定义你的终端软件,否则你只能使用一些已经内置的信号。

根据你需要的功能多少,或者你想要实现的程度,另一种选择是自己写一个简单的“进程执行终端”。这其实就是一个脚本,它可以为你执行一个应用程序,并把你的终端设置为原始模式,这样它就能处理你按下的键,并执行自定义的操作。

下面是一个非常简单的例子,说明我想表达的意思。如果你愿意,也可以通过 cursesurwid 来做类似的事情。

为了处理进程的输出,你需要捕捉 stdout/stderr 的内容,并把它们美观地显示在屏幕上。如果你手动操作终端,可以使用 ANSI 转义序列,或者使用 urwid 的小部件在滚动窗口中显示输出等等。这个想法也可以扩展到其他图形用户界面系统(如 wx、tkinter 等),但这里提到的是终端控制。

下面是 term.py,它实现了一个基本的原始终端解释器:

import os, signal, subprocess, sys, tty, termios

sigmap = {
    '\x15': signal.SIGUSR1,     # ctrl-u
    '\x1c': signal.SIGQUIT,     # ctrl-\
    '\x08': signal.SIGHUP,      # ctrl-h
    '\x09': signal.SIGINT,      # ctrl-i
    }
# setup tty
fd = sys.stdin.fileno()
old_tc = termios.tcgetattr(fd)
tty.setraw(fd)
# spawn command as a child proc
cmd = sys.argv[1:]
proc = subprocess.Popen(cmd)
while 1:
    try:
        ch = sys.stdin.read(1)
        # example of ansi escape to move cursor down and to column 0
        print '\033[1Eyou entered', repr(ch)
        if ch == 'q':
            break
        signum = sigmap.get(ch)
        if signum:
            os.kill(proc.pid, signum)
    finally:
        pass
termios.tcsetattr(fd, termios.TCSANOW, old_tc)
sys.exit()

这里是一个简单的 target.py 脚本,用来旋转并打印它接收到的信号:

import signal, sys, time

def handler(num, _):
    print 'got:', sigmap.get(num, '<other>')
    if num == signal.SIGINT:
        sys.exit(1)
    return 1

signames = ['SIGINT','SIGHUP','SIGQUIT','SIGUSR1']
sigmap = dict((getattr(signal, k), k) for k in signames)
for name in signames:
    signal.signal(getattr(signal, name), handler)
while 1:
    time.sleep(1)

使用示例:

% python term.py python target.py
you entered 'h'
you entered 'i'
you entered '\x1c'
                  got: SIGQUIT
you entered '\x15'
                  got: SIGUSR1
you entered '\x08'
                  got: SIGHUP
you entered '\t'
                got: SIGINT
you entered 'q'

撰写回答