aboutsummaryrefslogtreecommitdiff
path: root/src/Wetterhorn/Core/Keys.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Wetterhorn/Core/Keys.hs')
-rw-r--r--src/Wetterhorn/Core/Keys.hs190
1 files changed, 74 insertions, 116 deletions
diff --git a/src/Wetterhorn/Core/Keys.hs b/src/Wetterhorn/Core/Keys.hs
index 90c24c4..b979048 100644
--- a/src/Wetterhorn/Core/Keys.hs
+++ b/src/Wetterhorn/Core/Keys.hs
@@ -1,34 +1,17 @@
-module Wetterhorn.Core.Keys
- ( forwardKey,
- forwardEvent,
- KeysM,
- bind,
- subbind,
- subbind_,
- (.+),
- Modifier (..),
- keys,
- ignoreReleaseEvents,
- weak,
- continue,
- WeakKeyMatcher,
- nextKeyEvent,
- nextKeyPress,
- keysWithHandler,
- putKeyHandler,
- KeyHandler,
- )
-where
-
-import Control.Monad (void, when)
+module Wetterhorn.Core.Keys where
+
+import Control.Monad (forever, join, void, when)
+import Control.Monad.Cont.Class
import Control.Monad.Fix (fix)
import Control.Monad.IO.Class
+import Control.Monad.Reader (ReaderT (runReaderT))
import Control.Monad.Reader.Class
-import Control.Monad.State (MonadState (get, put))
+import Control.Monad.State (MonadState (get, put), MonadTrans (lift), StateT, evalStateT, gets)
+import Control.Monad.Trans.Cont
import Data.Bits
import Data.Word
import Wetterhorn.Core.KeyEvent
-import qualified Wetterhorn.Core.KeyEvent as KeyEvent
+import Wetterhorn.Core.KeyEvent qualified as KeyEvent
import Wetterhorn.Core.W
import Wetterhorn.Foreign.WlRoots (wlrSeatKeyboardNotifyKey, wlrSeatSetKeyboard)
@@ -51,8 +34,8 @@ forwardKey keyEvent = do
)
-- | Forwards the current key event to the focused window.
-forwardEvent :: KeysM ()
-forwardEvent = liftW . forwardKey =<< ask
+forwardEvent :: KeyEvent -> KeysM ()
+forwardEvent = liftW . forwardKey
-- | Enumeration of possible modifiers
data Modifier = Shift | Lock | Control | Mod1 | Mod2 | Mod3 | Mod4 | Mod5
@@ -72,29 +55,61 @@ modifierToMask m =
Mod4 -> 6
Mod5 -> 7
+data KeysState = KeysState
+ { -- | Reference to the top. Used for a continue statement.
+ keysTop :: KeysM (),
+ handleContinuation :: KeyContinuation -> W ()
+ }
+
-- | The Keys monad. This monad abstracts away control flow for handling key
-- bindings. This makes it easy to make key-sequence bindings.
-newtype KeysM a = KeysM ((KeyEvent -> W ()) -> KeyEvent -> W (KeysMR a))
+-- newtype KeysM a = KeysM ((KeyEvent -> W ()) -> KeyEvent -> W (KeysMR a))
+newtype KeysM a = KeysM (ContT () (StateT KeysState W) a)
+ deriving (Monad, Functor, Applicative, MonadCont, MonadIO)
+
+-- | KeysM can be lifted from a W action.
+instance Wlike KeysM where
+ liftW = KeysM . lift . lift
-type KeyHandler = KeyEvent -> W ()
+type KeyContinuation = KeyEvent -> W ()
-- Return type in the keysM monad.
-data KeysMR a = NextKey (KeysM a) | Lift a | Continue
-
-keysWithHandler :: (KeyHandler -> W ()) -> KeysM a -> KeyHandler
-keysWithHandler nextAction keysM = fix $ \top ke -> keys' top keysM ke
- where
- keys' top (KeysM fn) ke = do
- e <- fn top ke
- case e of
- NextKey keysM' -> nextAction (keys' top keysM')
- Lift _ -> return ()
- _ -> nextAction top
-
-keys :: KeysM a -> KeyEvent -> W ()
-keys = keysWithHandler putKeyHandler
-
-putKeyHandler :: KeyHandler -> W ()
+-- data KeysMR a = NextKey (KeysM a) | Lift a | Continue
+
+-- keysWithHandler :: (KeyContinuation -> W ()) -> KeysM a -> KeyContinuation
+-- keysWithHandler nextAction keysM = fix $ \top ke -> keys' top keysM ke
+-- where
+-- keys' top (KeysM fn) ke = do
+-- e <- fn top ke
+-- case e of
+-- NextKey keysM' -> nextAction (keys' top keysM')
+-- Lift _ -> return ()
+-- _ -> nextAction top
+
+-- keys :: KeysM a -> KeyEvent -> W ()
+-- keys = keysWithHandler putKeyHandler
+
+useKeysWithContinuation :: (KeyContinuation -> W ()) -> KeysM () -> W ()
+useKeysWithContinuation continuation km@(KeysM c) =
+ evalStateT (evalContT (forever c)) (KeysState km continuation)
+
+useKeys :: KeysM () -> W ()
+useKeys = useKeysWithContinuation putKeyHandler
+
+nextKeyEvent :: KeysM KeyEvent
+nextKeyEvent = do
+ st <- KeysM $ lift get
+ KeysM $
+ shiftT
+ ( \keyHandler ->
+ lift . lift $
+ handleContinuation st (\kp -> evalStateT (keyHandler kp) st)
+ )
+
+continue :: KeysM ()
+continue = join (KeysM (gets keysTop))
+
+putKeyHandler :: KeyContinuation -> W ()
putKeyHandler handler = do
s@State {currentHooks = hooks} <- get
put
@@ -105,63 +120,15 @@ putKeyHandler handler = do
}
}
--- | Returns the next key event. This returns both key pressed and key released
--- events, so it's good to be careful because duplicate casess can happen.
-nextKeyEvent :: KeysM KeyEvent
-nextKeyEvent = KeysM (\_ _ -> return (NextKey (KeysM (\_ -> return . Lift))))
-
-- | Returns the next KeyPressed event. This is likely what 90% of use cases
-- want rather than nextKeyEvent.
nextKeyPress :: KeysM KeyEvent
nextKeyPress = do
k <- nextKeyEvent
if KeyEvent.state k /= KeyPressed
- then forwardEvent >> nextKeyPress
+ then forwardEvent k >> nextKeyPress
else return k
--- | Resets the handling of KeyBindings to the top. Operates like a 'continue'
--- statement in imperative programming languages.
-continue :: KeysM ()
-continue = KeysM $ \_ _ -> return Continue
-
-instance Functor KeysM where
- fmap f (KeysM fn) = KeysM $ \top keyEvent -> do
- e <- fn top keyEvent
- return $
- case e of
- NextKey ma -> NextKey $ fmap f ma
- Lift a -> Lift $ f a
- Continue -> Continue
-
-instance Applicative KeysM where
- pure a = KeysM (\_ _ -> return (Lift a))
- (<*>) mfn ma = do
- fn <- mfn
- fn <$> ma
-
-instance Monad KeysM where
- a >>= fmb = keysJoin (fmap fmb a)
- where
- keysJoin (KeysM f) = KeysM $ \top keyEvent -> do
- e <- f top keyEvent
- case e of
- Lift (KeysM f') -> f' top keyEvent
- NextKey sub -> return $ NextKey $ keysJoin sub
- Continue -> return Continue
-
--- | KeysM can be lifted from a W action.
-instance Wlike KeysM where
- liftW act = KeysM (\_ _ -> Lift <$> act)
-
--- | KeyM can be lifted from an IO action.
-instance MonadIO KeysM where
- liftIO = liftW . wio
-
--- | Monad
-instance MonadReader KeyEvent KeysM where
- ask = KeysM (\_ -> return . Lift)
- local fn (KeysM fn') = KeysM $ \a (fn -> ns) -> fn' a ns
-
--
-- binding EDSL used to expressively create key bindings and subbindings inside
-- a KeysM () context.
@@ -218,32 +185,23 @@ instance MatchKey WeakKeyMatcher where
where
ms = KeyEvent.modifiers ev
-subbind :: (MatchKey m) => m -> KeysM () -> KeysM ()
-subbind m act = do
- ev <- ask
- when (matchKey m ev) $ do
- _ <- nextKeyPress
- act
- continue
+class IsKeysM m where
+ toKeysM :: m a -> KeysM a
--- | Like 'subbind', but does not read the next keypress.
-subbind_ :: (MatchKey m) => m -> KeysM () -> KeysM ()
-subbind_ m act = do
- ev <- ask
- when (matchKey m ev) $ do
- act
- continue
+instance IsKeysM W where
+ toKeysM = liftW
+
+instance IsKeysM KeysM where
+ toKeysM = id
-bind :: (MatchKey m) => m -> W () -> KeysM ()
-bind m act = do
- ev <- ask
+bind :: (MatchKey m, IsKeysM k) => KeyEvent -> m -> k () -> KeysM ()
+bind ev m act = do
when (matchKey m ev) $ do
- liftW act
+ toKeysM act
continue
-ignoreReleaseEvents :: KeysM ()
-ignoreReleaseEvents = do
- ev <- ask
+ignoreReleaseEvents :: KeyEvent -> KeysM ()
+ignoreReleaseEvents ev = do
when (KeyEvent.state ev /= KeyEvent.KeyPressed) $ do
- forwardEvent
+ forwardEvent ev
continue