开发者

Python: Built-in Keyboard Signal/Interrupts

I currently need to provide multiple keyboard interrupts for a program. Is there an easy way to do this with the signal class? I currently use the SIGINT/Ctrl+C but I can't find any other keyboard mappings.

Would be nice to have more than 2 signals. How can I either define more signals or is there a better way to capture an "interrupt from a user"?

Here is a highlevel view of the current code:

 def shutdown(signal, frame):开发者_StackOverflow
       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()


The Ctrl+\ that has been mentioned is interpreted by your terminal software, and the key binding is configured through stty. Unless you have some way of customizing your terminal software you'll only be able to use the few signals that are already built in.

Depending on how much functionality you need or how far you want to take it, another option is to write your own simple "process execution terminal". This would be a script that executes an app for you and places your terminal in raw mode so that it can process keystrokes which perform custom actions.

Below is an oversimplified example showing what I mean. You could also do something similar via curses or urwid if you like.

To handle process output you'd need to capture the stdout/stderr of and display it nicely to the screen, using ANSI escape sequences if you are manipulating the terminal manually, or using an urwid widget to display the output in a scrolling window, etc. The same idea would also extend to other GUI systems (wx, tkinter, etc) but terminal control was mentioned.

Here is term.py which implements a basic raw terminal interpreter:

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()

Here is a simple target.py script to spin and print the signals it receives:

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)

Usage example:

% 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'


On Linux systems, Ctrl+\ will generate a signal.SIGQUIT signal.


I'm not sure if there's a premixed way to define new signals and map them to keyboard events.

If you need that sort of flexibility, you might have to use an interface thread that remains in the foreground and listens for keyboard events. It could then communicate with other threads any way you like.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜