1-- Copyright 2009-2010 Corey O'Connor
2module Graphics.Vty.Input ( Key(..)
11import Graphics.Vty.Input.Data
12import Graphics.Vty.Input.Internal
13import Graphics.Vty.Input.Terminfo
18import Control.Monad (when, void)
19import Control.Concurrent
20import Control.Exception
22import System.Console.Terminfo
24import System.Posix.Signals.Exts
25import System.Posix.Terminal
26import System.Posix.IO ( stdInput
32import Foreign ( alloca, poke, peek, Ptr )
37-- | Set up the terminal for input. Returns a function which reads key
38-- events, and a function for shutting down the terminal access.
39initTermInput :: Int -> Terminal -> IO (IO Event, IO ())
40initTermInput escDelay terminal = do
41 eventChannel <- newChan
42 inputChannel <- newChan
43 hadInput <- newEmptyMVar
44 oattr <- getTerminalAttributes stdInput
45 let nattr = foldl withoutMode oattr [ StartStopOutput, KeyboardInterrupts
46 , EnableEcho, ProcessInput, ExtendedFunctions
48 setTerminalAttributes stdInput nattr Immediately
50 let finishAtomicInput = writeChan inputChannel '\xFFFE'
53 _ <- alloca $ \(input_buffer :: Ptr Word8) -> do
55 setFdOption stdInput NonBlockingRead False
56 threadWaitRead stdInput
57 setFdOption stdInput NonBlockingRead True
58 _ <- try readAll :: IO (Either IOException ())
59 when (escDelay == 0) finishAtomicInput
63 bytes_read <- fdReadBuf stdInput input_buffer 1
64 input_char <- fmap (chr . fromIntegral) $ peek input_buffer
65 when (bytes_read > 0) $ do
66 _ <- tryPutMVar hadInput () -- signal input
67 writeChan inputChannel input_char
71 -- | If there is no input for some time, this thread puts '\xFFFE' in the
73 noInputThread :: IO ()
74 noInputThread = when (escDelay > 0) loop
76 takeMVar hadInput -- wait for some input
77 threadDelay escDelay -- microseconds
78 hadNoInput <- isEmptyMVar hadInput -- no input yet?
79 -- TODO(corey): there is a race between here and the inputThread.
84 caps_legacy_table = map_to_legacy_table $ caps_classify_table terminal keys_from_caps_table
85 term_event_classify_table = concat $ caps_legacy_table : ansi_classify_table
86 term_event_classifier = classify term_event_classify_table
88 eventThreadId <- forkIO $ void $ inputToEventThread term_event_classifier inputChannel eventChannel
89 inputThreadId <- forkIO $ inputThread
90 noInputThreadId <- forkIO $ noInputThread
91 let pokeIO = Catch $ do
92 let e = error "(getsize in input layer)"
93 setTerminalAttributes stdInput nattr Immediately
94 writeChan eventChannel (EvResize e e)
95 _ <- installHandler windowChange pokeIO Nothing
96 _ <- installHandler continueProcess pokeIO Nothing
97 -- TODO(corey): killThread is a bit risky for my tastes.
99 killThread eventThreadId
100 killThread inputThreadId
101 killThread noInputThreadId
102 _ <- installHandler windowChange Ignore Nothing
103 _ <- installHandler continueProcess Ignore Nothing
104 setTerminalAttributes stdInput oattr Immediately
105 return (readChan eventChannel, uninit)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list