Python: встроенный сигнал/прерывания клавиатуры

В настоящее время мне нужно предоставить несколько клавиатурных прерываний для программы. Есть ли простой способ сделать это с помощью класса сигналов? В настоящее время я использую 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()

Ответ 1

Указанный Ctrl+\ интерпретируется вашим программным обеспечением терминала, а привязка клавиш настраивается через stty. Если у вас есть какой-либо способ настройки вашего программного обеспечения терминала, вы сможете использовать только несколько сигналов, которые уже встроены.

В зависимости от того, сколько функциональности вам нужно или насколько вы хотите ее принять, другой вариант - написать собственный простой "терминал выполнения процесса". Это будет script, который выполняет приложение для вас и помещает ваш терминал в необработанный режим, чтобы он мог обрабатывать нажатия клавиш, которые выполняют пользовательские действия.

Ниже приведен упрощенный пример, показывающий, что я имею в виду. Вы также можете сделать что-то подобное через curses или urwid если хотите.

Чтобы обрабатывать вывод процесса, вам нужно будет захватить stdout/stderr и отобразить его на экране, используя ANSI escape-последовательности, если вы манипулируете терминалом вручную или используете виджет urwid для отображения вывода в окне прокрутки и т.д. Такая же идея будет распространяться и на другие GUI-системы (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 script для вращения и печати полученных сигналов:

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'

Ответ 2

В системах Linux, Ctrl +\будет генерировать сигнал. Сигнал SIGQUIT.

Ответ 3

Я не уверен, есть ли предварительный метод определения новых сигналов и сопоставление их с событиями клавиатуры.

Если вам нужна такая гибкость, вам, возможно, придется использовать поток интерфейса, который остается на переднем плане и прослушивает события клавиатуры. Затем он мог общаться с другими потоками любым способом.