Per impostazione predefinita, l'input standard è bufferizzato e utilizza la modalità canonica. Ciò consente di modificare l'input. Quando premi il tasto Invio, l'input può essere letto da Python.
Se vuoi un accesso di livello inferiore all'input puoi usare tty.setraw()
sul descrittore di file di input standard. Questo ti permette di leggere un carattere alla volta usando sys.stdin.read(1)
. Nota che in questo caso lo script Python sarà responsabile della gestione dei caratteri speciali e perderai alcune delle funzionalità come l'eco dei caratteri e l'eliminazione. Per maggiori informazioni dai un'occhiata a termios(3).
Puoi leggere le sequenze di escape utilizzate per i tasti su e giù su Wikipedia.
Dovresti essere in grado di replicare il comportamento standard della shell se gestisci tutto in un unico processo.
Potresti anche provare a usare un sottoprocesso (non riferito al modulo - puoi usare fork()
o popen()
). Dovresti analizzare l'input non bufferizzato nel processo principale e inviarlo allo stdin (che può essere bufferizzato) del sottoprocesso. Probabilmente avrai bisogno di una comunicazione tra processi per condividere la cronologia con il processo principale.
Ecco un esempio del codice necessario per acquisire l'input in questo modo. Nota che sta eseguendo solo un'elaborazione di base e necessita di più lavoro per adattarsi al tuo caso d'uso.
import sys
import tty
import termios
def getchar():
fd = sys.stdin.fileno()
attr = termios.tcgetattr(fd)
try:
tty.setraw(fd)
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSANOW, attr)
EOT = '\x04' # CTRL+D
ESC = '\x1b'
CSI = '['
line = ''
while True:
c = getchar()
if c == EOT:
print('exit')
break
elif c == ESC:
if getchar() == CSI:
x = getchar()
if x == 'A':
print('UP')
elif x == 'B':
print('DOWN')
elif c == '\r':
print([line])
line = ''
else:
line += c
Python ha un modulo tastiera con molte funzionalità. Installalo, magari con questo comando:
pip install keyboard
quindi usalo nel codice come questo:
import keyboard
keyboard.add_hotkey('up', lambda: keyboard.write('write command retrieved from the history of your shell here'))
keyboard.wait('esc')
oppure potresti usare la funzione on_press_keyUsing the function on_press_key:
keyboard.on_press_key("p", lambda _:print("You pressed p"))
Ha bisogno di una funzione di callback. Ho usato _ perché la funzione della tastiera restituisce l'evento della tastiera a quella funzione.
Una volta eseguito, eseguirà la funzione quando viene premuto il tasto. Puoi fermare tutti gli hook eseguendo questa riga:
keyboard.unhook_all()
per informazioni dettagliate puoi vedere un post simile su StackOverflow, spero che questo aiuti a rilevare la pressione dei tasti in Python?
Nota laterale: hai menzionato il metodo fork() sopra In python possiamo usare il
processo secondario modulo integrato qui, quindi importa sottoprocesso e siamo a posto. La funzione run in particolare viene utilizzata qui per eseguire comandi in una subshell. Per coloro che provengono da C, questo ci evita di andare a fare il fork e creare un processo figlio e quindi aspettare che il figlio finisca l'esecuzione, lascia che Python se ne occupi questa volta.
codice di esempio per eseguire i comandi inseriti dall'utente
def execute_commands(command):
try:
subprocess.run(command.split())
except Exception:
print("psh: command not found: {}".format(command))