Domanda Posso disabilitare control-C?


Esiste un modo per disattivare (temporaneamente) l'effetto di interruzione di control-C in un eseguibile di Haskell in esecuzione shell-in-a-shell?

Contesto: ho un piccolo esercizio che ho impostato ogni anno. È un gioco in cui gli studenti eseguono la chiusura lampo intorno a espressioni che attivano la riscrittura della corrispondenza del modello come applicabile, eseguendo in una finestra della shell utilizzando hncurses. Quando gli studenti hanno terminato l'ultimo puzzle, ottengono una password individuale di cui hanno bisogno per mandarmi. Essendo veterani di Windows e neofiti di Unix, e naturalmente (virtuosamente) pigri, tendono a selezionare la password e digitare control-C. Questo ha l'effetto non intenzionale di interrompere il programma e far scomparire la password. L'unico modo per recuperarlo è ripetere l'esercizio. Che crudele!

Sebbene esistano altri modi per aggirare il problema (ad es., Stampare un messaggio di avviso o scrivere la password su un file), sono curioso di sapere se c'è modo di disattivare il controllo-C.


12
2018-01-23 09:51


origine


risposte:


Sì, devi solo ignorare temporaneamente SIGINT:

import Prelude hiding (catch)
import Control.Exception
import Control.Concurrent
import System.Posix.Signals

-- Ensures the original handler is restored even after an exception.
--
-- installHandler returns the previous signal handler, so if you're
-- tied to some existing main loop, you could instead just keep
-- its return value around for later restoration.
ignoreSignal :: Signal -> IO a -> IO a
ignoreSignal sig = bracket (install Ignore) install . const
  where install handler = installHandler sig handler Nothing

pause :: IO ()
pause = threadDelay 2000000

main :: IO ()
main = do
  ignoreSignal keyboardSignal $ do
    putStrLn "Ctrl+C disabled."
    pause
  putStrLn "\nCtrl+C re-enabled."
  pause

(Puoi anche scrivere keyboardSignal come sigINT se vuoi chiamarlo più direttamente).

Potresti anche sostituire Ignore con Catch m, dove m è un'azione che stampa le indicazioni sul modo corretto di copiare il testo. (Attenzione però: verrà eseguito in un thread Haskell separato).


12
2018-01-23 10:05



Veloce e facile, usa la shell:

stty intr ^T
run your haskell program here
stty intr ^C

Questo ha l'ulteriore vantaggio che i programmi possono ancora essere interrotti.


8
2018-01-23 11:30



Puoi prendere esplicitamente l'eccezione, che credo sia UserInterrupt:

handle (\exception -> do
     case fromException exception of
          Just UserInterrupt -> -- return to problem
          _                  -> error "unhandled exception") playWithStudents

1
2018-01-23 10:13