tags:

views:

107

answers:

3

I'm pretty new to Haskell, so I'm looking for a simple-ish way to detect keypresses, rather than using getLine.

If anyone knows any libraries, or some trick to doing this, it would be great!

And if there is a better place to ask this, please direct me there, I'd appreciate it.

+3  A: 
import System.IO

main :: IO ()
main = do
  hSetBuffering stdin NoBuffering
  x <- getChar
  putStrLn ("You pressed: " ++ [x])

I don't know when this is guaranteed to work. Putting the terminal into a "raw" mode is a system-dependent process. But it works for me with GHC 6.12.1 on Linux.

keegan
But it doesn't work on Windows using GHC.
Pedro Rodrigues
That's the issue I've found, it works rather poorly on Windows, and requires a newline before it is submitted.
TaslemGuy
A: 

You can use getChar instead of getLine. This probably isn't what you're looking for, but it's the simplest way.

pressKey :: IO ()
pressKey = do x <- getChar
              return x

But there's an even simpler way. Just write getChar:

pressKey :: IO ()
pressKey = getChar >> putStr "I am a String"

pressKey = putStrLn "Hi" >> getChar >> putStrLn "Bye"
danportin
Your first `pressKey` is exactly equivalent to `getChar` on its own here.
Ollie Saunders
Well, I know that. My point was that x could be used, e.g., "do {x <- getCbar; dosomething (read x :: Int)} or not.
danportin
+2  A: 

If you don't want blocking you can use hReady to detect whether a key has been pressed yet. This is useful for games where you want the program to run and pick up a key press whenever it has happened without pausing the game.

Here's a convenience function I use for this:

ifReadyDo :: Handle -> IO a -> IO (Maybe a)
ifReadyDo hnd x = hReady hnd >>= f
   where f True = x >>= return . Just
         f _    = return Nothing

Which can be used like this:

stdin `ifReadyDo` getChar

Returning a Maybe that is Just if a key was pressed and Nothing otherwise.

Ollie Saunders