Могу ли я отключить управление-C?
Есть ли способ отключить (временно) прерывающий эффект управления C в обычном исполняемом исполняемом файле Haskell?
Контекст: У меня есть небольшое упражнение, которое я устанавливаю каждый год. Это игра, в которой ученики застегивают молнию вокруг выражений, запускающих шаблон, переписывая, как это применимо, и запускаются в окне оболочки с помощью hncurses. Когда ученики закончили последнюю загадку, они получают индивидуальный пароль, который им нужно отправить мне. Будучи ветеранами Windows и новичками Unix, и, конечно, (виртуозно) ленивыми, они склонны выбирать пароль и тип control-C. Это имеет непреднамеренный эффект прерывания программы и заставляет их пароль исчезать. Единственный способ восстановить это - повторить упражнение. Как жестоко!
В то время как есть другие способы, я мог бы решить проблему (например, печатать предупреждающее сообщение или записывать пароль в файл), мне любопытно узнать, есть ли способ отключить контроль-C.
Ответы
Ответ 1
Да, вам просто нужно временно игнорировать 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
(Вы также можете написать keyboardSignal
как sigINT
, если хотите называть его более прямым.)
Вы также можете заменить Ignore
на Catch m
, где m
- это какое-то действие, которое печатает руководство по правильному способу копирования текста. (Будь осторожен, он будет работать в отдельном потоке Haskell.)
Ответ 2
Быстро и просто, используйте оболочку:
stty intr ^T
run your haskell program here
stty intr ^C
У этого есть дополнительное преимущество, что программы все еще могут быть прерваны.
Ответ 3
Вы можете явно поймать исключение, которое, я считаю, UserInterrupt
:
handle (\exception -> do
case fromException exception of
Just UserInterrupt -> -- return to problem
_ -> error "unhandled exception") playWithStudents