I'm making a silly terminal game, that uses keyboard input to control a character moving around a board. When the user presses a key, my code responds correctly, using getChar
, but the character that the users presses also appears in the terminal. Is there a way to receive keyboard input in a terminal app, without displaying what the user typed?
Edit: I'm on Mac, but would be good to know on all platforms.
Basically there are two things you have to do in order to reach your goal:
You have to disable any buffering in the terminal, so that your program gets the pressed keys at once (and you don't have to confirm with ENTER).
hSetBuffering stdin NoBuffering
Then you have to ensure the character isn't echoed back to the terminal.
hSetEcho stdin False
Please note that just before your program exits it has to restore the previous settings in order to allow further usage of the terminal.
Putting everything together the code will look like this:
import System.IO
import Control.Exception (bracket)
withHiddenTerminalInput :: IO a -> IO a
withHiddenTerminalInput io = bracket
(do prevBuff <- hGetBuffering stdin
prevEcho <- hGetEcho stdin
hSetBuffering stdin NoBuffering
hSetEcho stdin False
return (prevBuff, prevEcho)
)
(\(prevBuff, prevEcho) -> do
hSetBuffering stdin prevBuff
hSetEcho stdin prevEcho
)
(const io)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With