2011-03-29 2 views
10

Je dois actuellement fournir plusieurs interruptions de clavier pour un programme. Y at-il un moyen facile de le faire avec la classe de signal? J'utilise actuellement le SIGINT/Ctrl+C mais je ne trouve pas d'autres mappages de clavier.Python: signal/interruptions du clavier intégré

Serait agréable d'avoir plus de 2 signaux. Comment puis-je définir plus de signaux ou existe-t-il un meilleur moyen de capturer une "interruption d'un utilisateur"?

Voici une vue du code de haute activité actuelle:

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

'2' est toujours vrai. – delnan

+0

sur quelle plateforme? le signal de support sur Windows manque beaucoup de signaux ... –

+0

Son tagged, linux. – Nix

Répondre

11

Le Ctrl+\ qui a été mentionné est interprété par votre logiciel de terminal et la liaison de clé est configurée via stty. Sauf si vous avez un moyen de personnaliser votre logiciel de terminal, vous ne pourrez utiliser que les quelques signaux déjà intégrés.

Selon la fonctionnalité dont vous avez besoin ou la distance que vous souhaitez prendre, une autre option est écrire votre propre "terminal d'exécution de processus". Il s'agit d'un script qui exécute une application pour vous et place votre terminal en mode brut afin qu'il puisse traiter les frappes qui exécutent des actions personnalisées. Ci-dessous, un exemple simplifié qui montre ce que je veux dire. Vous pouvez également faire quelque chose de similaire via curses ou urwid si vous le souhaitez.

Pour gérer la sortie de processus, vous aurez besoin de capturer le stdout/stderr de et l'afficher bien à l'écran, en utilisant si vous manipulez le terminal manuellement ou à l'aide d'un widget urwid pour afficher la sortie dans une fenêtre de défilement, etc. La même idée s'appliquerait également aux autres systèmes GUI (wx, tkinter, etc.) mais le contrôle terminal a été mentionné.

Voici term.py qui met en oeuvre un interprète terminal première de base:

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

est ici un simple script target.py pour faire tourner et imprimer les signaux qu'il reçoit:

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) 

Exemple d'utilisation:

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

Sur les systèmes Linux, Ctrl + \ va générer un signal de signal.SIGQUIT.

+1

Existe-t-il un moyen de définir de nouveaux? Ou plus? – Nix

0

Je ne suis pas sûr s'il existe une façon prémélangée de définir de nouveaux signaux et de les mapper aux événements clavier.

Si vous avez besoin de ce type de flexibilité, vous devrez peut-être utiliser un thread d'interface qui reste au premier plan et qui écoute les événements du clavier. Il pourrait alors communiquer avec d'autres threads comme vous le souhaitez.

Questions connexes