on master help sign in
start refactoring input layer into a nice interface structure
b301324Corey O'Connor
cbits/set_term_timing.c−1
@@ -11,4 +11,3 @@ void vty_set_term_timing(void)
11 trm.c_cc[VTIME] = 0;
11 trm.c_cc[VTIME] = 0;
12 tcsetattr(STDIN_FILENO, TCSANOW, &trm);
12 tcsetattr(STDIN_FILENO, TCSANOW, &trm);
13}
13}
14−
src/Graphics/Vty.hs+18−10
@@ -41,6 +41,8 @@ import Graphics.Vty.Input
41import Graphics.Vty.Output
41import Graphics.Vty.Output
42import Graphics.Vty.Picture
42import Graphics.Vty.Picture
43
43
44+import Control.Concurrent
45+
44import Data.IORef
46import Data.IORef
45
47
46import qualified System.Console.Terminfo as Terminfo
48import qualified System.Console.Terminfo as Terminfo
@@ -69,7 +71,9 @@ data Vty = Vty
69 update :: Picture -> IO ()
71 update :: Picture -> IO ()
70 -- | Get one Event object, blocking if necessary.
72 -- | Get one Event object, blocking if necessary.
71 , next_event :: IO Event
73 , next_event :: IO Event
74+ -- | The input interface. See 'Input'
75+ , input_iface :: Input
72− -- | The output interface. See `Output`
76+ -- | The output interface. See 'Output'
73 , output_iface :: Output
77 , output_iface :: Output
74 -- | Refresh the display. Normally the library takes care of refreshing. Nonetheless, some
78 -- | Refresh the display. Normally the library takes care of refreshing. Nonetheless, some
75 -- other program might output to the terminal and mess the display. In that case the user
79 -- other program might output to the terminal and mess the display. In that case the user
@@ -91,14 +95,17 @@ mkVty = mkVtyEscDelay defaultEscDelay
91-- \todo move input init into terminal interface
95-- \todo move input init into terminal interface
92mkVtyEscDelay :: Int -> IO Vty
96mkVtyEscDelay :: Int -> IO Vty
93mkVtyEscDelay escDelay = do
97mkVtyEscDelay escDelay = do
94− term_info <- Terminfo.setupTermFromEnv
98+ input <- input_for_current_terminal escDelay
95− t <- output_for_current_terminal
99+ out <- output_for_current_terminal
96− reserve_display t
100+ reserve_display out
97− (kvar, endi) <- initTermInput escDelay term_info
101+ intMkVty input out
98− intMkVty kvar ( endi >> release_display t >> release_terminal t ) t
99
102
100−intMkVty :: IO Event -> IO () -> Output -> IO Vty
103+intMkVty :: Input -> Output -> IO Vty
101−intMkVty kvar fend out = do
104+intMkVty input out = do
105+ let shutdown_io = do
106+ shutdown_input input
107+ release_display out
108+ release_terminal out
102 last_pic_ref <- newIORef Nothing
109 last_pic_ref <- newIORef Nothing
103 last_update_ref <- newIORef Nothing
110 last_update_ref <- newIORef Nothing
104
111
@@ -141,7 +148,7 @@ intMkVty kvar fend out = do
141 >> readIORef last_pic_ref
148 >> readIORef last_pic_ref
142 >>= maybe ( return () ) ( \pic -> inner_update pic )
149 >>= maybe ( return () ) ( \pic -> inner_update pic )
143
150
144− let gkey = do k <- kvar
151+ let gkey = do k <- readChan $ event_channel input
145 case k of
152 case k of
146 (EvResize _ _) -> inner_refresh
153 (EvResize _ _) -> inner_refresh
147 >> display_bounds out
154 >> display_bounds out
@@ -150,8 +157,9 @@ intMkVty kvar fend out = do
150
157
151 return $ Vty { update = inner_update
158 return $ Vty { update = inner_update
152 , next_event = gkey
159 , next_event = gkey
160+ , input_iface = input
153 , output_iface = out
161 , output_iface = out
154 , refresh = inner_refresh
162 , refresh = inner_refresh
155− , shutdown = fend
163+ , shutdown = shutdown_io
156 }
164 }
157
165
src/Graphics/Vty/Input.hs+27−14
@@ -4,8 +4,10 @@ module Graphics.Vty.Input ( Key(..)
4 , Modifier(..)
4 , Modifier(..)
5 , Button(..)
5 , Button(..)
6 , Event(..)
6 , Event(..)
7− , initTermInput
7+ , Input(..)
8 , defaultEscDelay
8 , defaultEscDelay
9+ , input_for_current_terminal
10+ , input_for_name_and_io
9 )
11 )
10 where
12 where
11
13
@@ -15,11 +17,12 @@ import Graphics.Vty.Input.Terminfo
15
17
16import Control.Concurrent
18import Control.Concurrent
17
19
18−import System.Console.Terminfo
20+import qualified System.Console.Terminfo as Terminfo
19−
21+import System.Environment
20import System.Posix.Signals.Exts
22import System.Posix.Signals.Exts
21import System.Posix.Terminal
23import System.Posix.Terminal
22import System.Posix.IO (stdInput)
24import System.Posix.IO (stdInput)
25+import System.Posix.Types (Fd)
23
26
24-- Right, I'm mostly guessing on these details. So, as far as I can figure:
27-- Right, I'm mostly guessing on these details. So, as far as I can figure:
25--
28--
@@ -45,6 +48,13 @@ import System.Posix.IO (stdInput)
45defaultEscDelay :: Int
48defaultEscDelay :: Int
46defaultEscDelay = 10000
49defaultEscDelay = 10000
47
50
51+-- | Set up the current terminal for input.
52+-- This determines the current terminal then invokes 'input_for_name_and_io'
53+input_for_current_terminal :: Int -> IO Input
54+input_for_current_terminal escDelay = do
55+ term_name <- getEnv "TERM"
56+ input_for_name_and_io escDelay term_name stdInput
57+
48-- | Set up the terminal for input. Returns a function which reads key
58-- | Set up the terminal for input. Returns a function which reads key
49-- events, and a function for shutting down the terminal access.
59-- events, and a function for shutting down the terminal access.
50--
60--
@@ -71,26 +81,29 @@ defaultEscDelay = 10000
71-- * IEXTEN disabled
81-- * IEXTEN disabled
72-- - extended functions are disabled. Uh. Whatever these are.
82-- - extended functions are disabled. Uh. Whatever these are.
73--
83--
74−initTermInput :: Int -> Terminal -> IO (IO Event, IO ())
84+input_for_name_and_io :: Int -> String -> Fd -> IO Input
75−initTermInput escDelay terminal = do
85+input_for_name_and_io escDelay term_name term_in = do
86+ terminal <- Terminfo.setupTerm term_name
76− attr <- getTerminalAttributes stdInput
87+ attr <- getTerminalAttributes term_in
77 let attr' = foldl withoutMode attr [ StartStopOutput, KeyboardInterrupts
88 let attr' = foldl withoutMode attr [ StartStopOutput, KeyboardInterrupts
78 , EnableEcho, ProcessInput, ExtendedFunctions
89 , EnableEcho, ProcessInput, ExtendedFunctions
79 ]
90 ]
80− setTerminalAttributes stdInput attr' Immediately
91+ setTerminalAttributes term_in attr' Immediately
92+ -- TODO: pass Fd to set_term_timing
81 set_term_timing
93 set_term_timing
82 let classify_table = classify_table_for_term terminal
94 let classify_table = classify_table_for_term terminal
83− (eventChannel, shutdown_input) <- initInputForFd escDelay classify_table stdInput
95+ (eventChannel, shutdown_event_processing) <- initInputForFd escDelay classify_table term_in
84 let pokeIO = Catch $ do
96 let pokeIO = Catch $ do
85 let e = error "(getsize in input layer)"
97 let e = error "(getsize in input layer)"
86− setTerminalAttributes stdInput attr' Immediately
98+ setTerminalAttributes term_in attr' Immediately
87 writeChan eventChannel (EvResize e e)
99 writeChan eventChannel (EvResize e e)
88 _ <- installHandler windowChange pokeIO Nothing
100 _ <- installHandler windowChange pokeIO Nothing
89 _ <- installHandler continueProcess pokeIO Nothing
101 _ <- installHandler continueProcess pokeIO Nothing
102+ return $ Input
103+ { event_channel = eventChannel
90− let shutdown_input' = do
104+ , shutdown_input = do
91− shutdown_input
105+ shutdown_event_processing
92 _ <- installHandler windowChange Ignore Nothing
106 _ <- installHandler windowChange Ignore Nothing
93 _ <- installHandler continueProcess Ignore Nothing
107 _ <- installHandler continueProcess Ignore Nothing
94− setTerminalAttributes stdInput attr Immediately
108+ setTerminalAttributes term_in attr Immediately
95− return (readChan eventChannel, shutdown_input')
109+ }
96−
src/Graphics/Vty/Input/Internal.hs+7−2
@@ -22,6 +22,11 @@ import System.Posix.IO ( fdReadBuf
22 )
22 )
23import System.Posix.Types (Fd(..))
23import System.Posix.Types (Fd(..))
24
24
25+data Input = Input
26+ { event_channel :: Chan Event
27+ , shutdown_input :: IO ()
28+ }
29+
25data KClass
30data KClass
26 = Valid Key [Modifier]
31 = Valid Key [Modifier]
27 | Invalid
32 | Invalid
@@ -141,11 +146,11 @@ initInputForFd escDelay classify_table input_fd = do
141 noInputThreadId <- forkIO $ noInputThread
146 noInputThreadId <- forkIO $ noInputThread
142 -- TODO(corey): killThread is a bit risky for my tastes.
147 -- TODO(corey): killThread is a bit risky for my tastes.
143 -- H - somewhat mitigated by sending a magic terminate character?
148 -- H - somewhat mitigated by sending a magic terminate character?
144− let shutdown_input = do
149+ let shutdown_event_processing = do
145 writeChan inputChannel '\xFFFD'
150 writeChan inputChannel '\xFFFD'
146 killThread noInputThreadId
151 killThread noInputThreadId
147 killThread eventThreadId
152 killThread eventThreadId
148 killThread inputThreadId
153 killThread inputThreadId
149− return (eventChannel, shutdown_input)
154+ return (eventChannel, shutdown_event_processing)
150
155
151foreign import ccall "vty_set_term_timing" set_term_timing :: IO ()
156foreign import ccall "vty_set_term_timing" set_term_timing :: IO ()
test/VerifyUsingMockInput.hs+2−2
@@ -107,12 +107,12 @@ assert_events_from_syn_input table input_spec expected_events = do
107 let max_duration = sum [t | Delay t <- input_spec] + min_detectable_delay
107 let max_duration = sum [t | Delay t <- input_spec] + min_detectable_delay
108 event_count = length expected_events
108 event_count = length expected_events
109 (output_fd, input_fd) <- createPipe
109 (output_fd, input_fd) <- createPipe
110− (output, shutdown_input) <- initInputForFd test_esc_sample_delay table output_fd
110+ (output, shutdown_event_processing) <- initInputForFd test_esc_sample_delay table output_fd
111 events_ref <- newIORef []
111 events_ref <- newIORef []
112 let write_wait_close = do
112 let write_wait_close = do
113 synthesize_input input_spec input_fd
113 synthesize_input input_spec input_fd
114 threadDelay min_detectable_delay
114 threadDelay min_detectable_delay
115− shutdown_input
115+ shutdown_event_processing
116 threadDelay min_detectable_delay
116 threadDelay min_detectable_delay
117 closeFd input_fd
117 closeFd input_fd
118 closeFd output_fd
118 closeFd output_fd