Подтвердить что ты не робот

Могу ли я отключить управление-C?

Есть ли способ отключить (временно) прерывающий эффект управления C в обычном исполняемом исполняемом файле Haskell?

Контекст: У меня есть небольшое упражнение, которое я устанавливаю каждый год. Это игра, в которой ученики застегивают молнию вокруг выражений, запускающих шаблон, переписывая, как это применимо, и запускаются в окне оболочки с помощью hncurses. Когда ученики закончили последнюю загадку, они получают индивидуальный пароль, который им нужно отправить мне. Будучи ветеранами Windows и новичками Unix, и, конечно, (виртуозно) ленивыми, они склонны выбирать пароль и тип control-C. Это имеет непреднамеренный эффект прерывания программы и заставляет их пароль исчезать. Единственный способ восстановить это - повторить упражнение. Как жестоко!

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

4b9b3361

Ответ 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