on master help sign in
use threaded runtime and forkOS to resolve issues with VMIN and VTIME
c9155d7Corey O'Connor
CHANGELOG+1
@@ -1,4 +1,5 @@
15.0.0
15.0.0
2+ * all projects using vty must be compiled with -threaded.
2 * input handling changes
3 * input handling changes
3 * KASCII is now KChar
4 * KASCII is now KChar
4 * KPN5 is now KCenter
5 * KPN5 is now KCenter
src/Graphics/Vty/Input.hs+5−3
@@ -28,9 +28,11 @@
28-- 3. ESC used as meta in a key combination: ESC byte, no other bytes read within
28-- 3. ESC used as meta in a key combination: ESC byte, no other bytes read within
29-- control-seq-period. Bytes up until next valid input block are the input events plus meta.
29-- control-seq-period. Bytes up until next valid input block are the input events plus meta.
30--
30--
31−-- This, as best I can figure, is what VMIN and VTIME are supposed to be for. For some reason vty
31+-- If the current runtime is the threaded runtime then the terminal's VMIN and VTIME parameters can
32−-- implements the timing in the library. I'm not sure if this is an advantage or not. Getting this
32+-- be applied to implement the above rules.
33−-- right has provided a strangely interesting task so I haven't cared to determine.
33+-- If the current runtime does not support forkOS then there is currently no implementation. Vty
34+-- used to implement a parser which did tricky things with non-blocking reads and timers. This could
35+-- be revived.
34module Graphics.Vty.Input ( Key(..)
36module Graphics.Vty.Input ( Key(..)
35 , Modifier(..)
37 , Modifier(..)
36 , Button(..)
38 , Button(..)
src/Graphics/Vty/Input/Internal.hs+11−9
@@ -86,6 +86,8 @@ makeLenses ''InputState
86
86
87type InputM a = StateT InputState (ReaderT Input IO) a
87type InputM a = StateT InputState (ReaderT Input IO) a
88
88
89+-- this must be run on an OS thread dedicated to this input handling.
90+-- otherwise the terminal timing read behavior will block the execution of the lightweight threads.
89loop_input_processor :: InputM ()
91loop_input_processor :: InputM ()
90loop_input_processor = do
92loop_input_processor = do
91 read_from_device >>= add_bytes_to_process
93 read_from_device >>= add_bytes_to_process
@@ -117,7 +119,7 @@ read_from_device = do
117apply_timing_config :: Fd -> Config -> IO ()
119apply_timing_config :: Fd -> Config -> IO ()
118apply_timing_config fd config =
120apply_timing_config fd config =
119 let vtime = min 255 $ singleEscPeriod config `div` 100000
121 let vtime = min 255 $ singleEscPeriod config `div` 100000
120− in set_term_timing fd 0 vtime
122+ in set_term_timing fd 1 vtime
121
123
122parse_event :: InputM Event
124parse_event :: InputM Event
123parse_event = do
125parse_event = do
@@ -152,16 +154,16 @@ compile table = cl' where
152 -- create a map from strings to event
154 -- create a map from strings to event
153 event_for_input = flip M.lookup (M.fromList table)
155 event_for_input = flip M.lookup (M.fromList table)
154 cl' [] = Prefix
156 cl' [] = Prefix
157+ cl' input_block = case event_for_input input_block of
158+ Just (EvKey k m) -> Valid k m []
155− cl' input_block = case S.member input_block prefix_set of
159+ Nothing -> case S.member input_block prefix_set of
156− True -> Prefix
160+ True -> Prefix
157− -- if the input_block is exactly what is expected for an event then consume the whole
161+ -- if the input_block is exactly what is expected for an event then consume the whole
158− -- block and return the event
162+ -- block and return the event
159− False -> case event_for_input input_block of
160− Just (EvKey k m) -> Valid k m []
161 -- look up progressively large prefixes of the input block until an event is found
163 -- look up progressively large prefixes of the input block until an event is found
162 -- H: There will always be one match. The prefix_set contains, by definition, all
164 -- H: There will always be one match. The prefix_set contains, by definition, all
163 -- prefixes of an event.
165 -- prefixes of an event.
164− Nothing ->
166+ False ->
165 let input_prefixes = init $ inits input_block
167 let input_prefixes = init $ inits input_block
166 in case mapMaybe (\s -> (,) s `fmap` event_for_input s) input_prefixes of
168 in case mapMaybe (\s -> (,) s `fmap` event_for_input s) input_prefixes of
167 (s,EvKey k m) : _ -> Valid k m (drop (length s) input_block)
169 (s,EvKey k m) : _ -> Valid k m (drop (length s) input_block)
@@ -218,7 +220,7 @@ initInputForFd config_ref classify_table input_fd = do
218 <*> pure (writeIORef stop_flag True)
220 <*> pure (writeIORef stop_flag True)
219 <*> pure config_ref
221 <*> pure config_ref
220 <*> pure input_fd
222 <*> pure input_fd
221− _ <- forkIO $ run_input_processor_loop classify_table input stop_flag
223+ _ <- forkOS $ run_input_processor_loop classify_table input stop_flag
222 return input
224 return input
223
225
224foreign import ccall "vty_set_term_timing" set_term_timing :: Fd -> Int -> Int -> IO ()
226foreign import ccall "vty_set_term_timing" set_term_timing :: Fd -> Int -> Int -> IO ()
test/vty-examples.cabal+4
@@ -25,6 +25,7 @@ executable vty-interactive-terminal-test
25
25
26 default-language: Haskell2010
26 default-language: Haskell2010
27 default-extensions: ScopedTypeVariables
27 default-extensions: ScopedTypeVariables
28+ ghc-options: -threaded
28
29
29 build-depends: vty,
30 build-depends: vty,
30 base >= 4 && < 5,
31 base >= 4 && < 5,
@@ -48,6 +49,7 @@ executable vty-event-echo
48
49
49 default-language: Haskell2010
50 default-language: Haskell2010
50 default-extensions: ScopedTypeVariables
51 default-extensions: ScopedTypeVariables
52+ ghc-options: -threaded
51
53
52 build-depends: vty,
54 build-depends: vty,
53 base >= 4 && < 5,
55 base >= 4 && < 5,
@@ -66,6 +68,7 @@ executable vty-rouge
66
68
67 default-language: Haskell2010
69 default-language: Haskell2010
68 default-extensions: ScopedTypeVariables
70 default-extensions: ScopedTypeVariables
71+ ghc-options: -threaded
69
72
70 build-depends: vty,
73 build-depends: vty,
71 base >= 4 && < 5,
74 base >= 4 && < 5,
@@ -85,6 +88,7 @@ executable vty-benchmark
85
88
86 default-language: Haskell2010
89 default-language: Haskell2010
87 default-extensions: ScopedTypeVariables
90 default-extensions: ScopedTypeVariables
91+ ghc-options: -threaded
88
92
89 build-depends: vty,
93 build-depends: vty,
90 base >= 4 && < 5,
94 base >= 4 && < 5,