diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,19 @@
 Brick changelog
 ---------------
 
+0.55
+----
+
+Package changes:
+ * Increased lower bound on `vty` dependency to 5.29.
+
+Bug fixes:
+ * `customMain` now restores the initial terminal input state on
+   shutdown. This means that changes to the input state flags in the last
+   `suspendAndResume` before program exit are no longer propagated to the
+   end user's terminal environment (which could lead to broken or garbled
+   terminal I/O).
+
 0.54
 ----
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -62,6 +62,7 @@
  * [`sudoku-tui`](https://github.com/evanrelf/sudoku-tui), a Sudoku implementation
  * [`summoner-tui`](https://github.com/kowainik/summoner/tree/master/summoner-tui), an interactive frontend to the Summoner tool
  * [`wrapping-editor`](https://github.com/ta0kira/wrapping-editor), an embeddable editor with support for Brick
+ * [`git-brunch`](https://github.com/andys8/git-brunch), a git branch checkout utility
 
 These third-party packages also extend `brick`:
 
diff --git a/brick.cabal b/brick.cabal
--- a/brick.cabal
+++ b/brick.cabal
@@ -1,5 +1,5 @@
 name:                brick
-version:             0.54
+version:             0.55
 synopsis:            A declarative terminal user interface library
 description:
   Write terminal user interfaces (TUIs) painlessly with 'brick'! You
@@ -114,7 +114,7 @@
     Brick.Widgets.Internal
 
   build-depends:       base <= 4.14.0.0,
-                       vty >= 5.24,
+                       vty >= 5.29,
                        transformers,
                        data-clist >= 0.1,
                        directory >= 1.2.5.0,
diff --git a/src/Brick/Main.hs b/src/Brick/Main.hs
--- a/src/Brick/Main.hs
+++ b/src/Brick/Main.hs
@@ -75,6 +75,8 @@
   , nextEvent
   , mkVty
   , defaultConfig
+  , restoreInputState
+  , inputIface
   )
 import Graphics.Vty.Attributes (defAttr)
 
@@ -202,6 +204,10 @@
 -- | The custom event loop entry point to use when the simpler ones
 -- don't permit enough control. Returns the final application state
 -- after the application halts.
+--
+-- Note that this function guarantees that the terminal input state
+-- prior to the first Vty initialization is the terminal input state
+-- that is restored on shutdown (regardless of exceptions).
 customMain :: (Ord n)
            => Vty
            -- ^ The initial Vty handle to use.
@@ -221,8 +227,13 @@
            -- ^ The initial application state.
            -> IO s
 customMain initialVty buildVty mUserChan app initialAppState = do
+    let restoreInitialState = restoreInputState $ inputIface initialVty
+
     (s, vty) <- customMainWithVty initialVty buildVty mUserChan app initialAppState
+        `E.catch` (\(e::E.SomeException) -> restoreInitialState >> E.throw e)
+
     shutdown vty
+    restoreInitialState
     return s
 
 -- | Like 'customMain', except the last 'Vty' handle used by the
@@ -526,5 +537,10 @@
 -- specified action. When it returns an application state value, restore
 -- the terminal state, empty the rendering cache, redraw the application
 -- from the new state, and resume the event loop.
+--
+-- Note that any changes made to the terminal's input state are ignored
+-- when Brick resumes execution and are not preserved in the final
+-- terminal input state after the Brick application returns the terminal
+-- to the user.
 suspendAndResume :: IO s -> EventM n (Next s)
 suspendAndResume = return . SuspendAndResume
