{-# OPTIONS_GHC -Wno-orphans #-}
module KMonad.App.Types
( AppCfg(..)
, AppEnv(..)
, KEnv(..)
, HasAppCfg(..)
, HasAppEnv(..)
, HasKEnv(..)
)
where
import KMonad.Prelude
import UnliftIO.Process (CreateProcess(close_fds), createProcess_, shell)
import KMonad.Keyboard
import KMonad.Keyboard.IO
import KMonad.Model.Action
import KMonad.Model.Button
import KMonad.Model.BEnv
import KMonad.Util
import qualified KMonad.Model.Dispatch as Dp
import qualified KMonad.Model.Hooks as Hs
import qualified KMonad.Model.Sluice as Sl
import qualified KMonad.Model.Keymap as Km
data AppCfg = AppCfg
{ AppCfg -> Acquire KeySink
_keySinkDev :: Acquire KeySink
, AppCfg -> Acquire KeySource
_keySourceDev :: Acquire KeySource
, AppCfg -> LMap Button
_keymapCfg :: LMap Button
, AppCfg -> LayerTag
_firstLayer :: LayerTag
, AppCfg -> Bool
_fallThrough :: Bool
, AppCfg -> Bool
_allowCmd :: Bool
, AppCfg -> Milliseconds
_startDelay :: Milliseconds
, AppCfg -> Maybe Milliseconds
_keyOutDelay :: Maybe Milliseconds
}
makeClassy ''AppCfg
data AppEnv = AppEnv
{
AppEnv -> AppCfg
_keAppCfg :: AppCfg
, AppEnv -> LogFunc
_keLogFunc :: LogFunc
, AppEnv -> KeySink
_keySink :: KeySink
, AppEnv -> KeySource
_keySource :: KeySource
, AppEnv -> Dispatch
_dispatch :: Dp.Dispatch
, AppEnv -> Hooks
_inHooks :: Hs.Hooks
, AppEnv -> Sluice
_sluice :: Sl.Sluice
, AppEnv -> Keymap
_keymap :: Km.Keymap
, AppEnv -> Hooks
_outHooks :: Hs.Hooks
, AppEnv -> TMVar KeyEvent
_outVar :: TMVar KeyEvent
}
makeClassy ''AppEnv
instance HasLogFunc AppEnv where logFuncL :: Lens' AppEnv LogFunc
logFuncL = (LogFunc -> f LogFunc) -> AppEnv -> f AppEnv
forall c. HasAppEnv c => Lens' c LogFunc
Lens' AppEnv LogFunc
keLogFunc
instance HasAppCfg AppEnv where appCfg :: Lens' AppEnv AppCfg
appCfg = (AppCfg -> f AppCfg) -> AppEnv -> f AppEnv
forall c. HasAppEnv c => Lens' c AppCfg
Lens' AppEnv AppCfg
keAppCfg
data KEnv = KEnv
{ KEnv -> AppEnv
_kAppEnv :: AppEnv
, KEnv -> BEnv
_kBEnv :: BEnv
}
makeClassy ''KEnv
instance HasAppCfg KEnv where appCfg :: Lens' KEnv AppCfg
appCfg = (AppEnv -> f AppEnv) -> KEnv -> f KEnv
forall c. HasKEnv c => Lens' c AppEnv
Lens' KEnv AppEnv
kAppEnv((AppEnv -> f AppEnv) -> KEnv -> f KEnv)
-> ((AppCfg -> f AppCfg) -> AppEnv -> f AppEnv)
-> (AppCfg -> f AppCfg)
-> KEnv
-> f KEnv
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(AppCfg -> f AppCfg) -> AppEnv -> f AppEnv
forall c. HasAppCfg c => Lens' c AppCfg
Lens' AppEnv AppCfg
appCfg
instance HasAppEnv KEnv where appEnv :: Lens' KEnv AppEnv
appEnv = (AppEnv -> f AppEnv) -> KEnv -> f KEnv
forall c. HasKEnv c => Lens' c AppEnv
Lens' KEnv AppEnv
kAppEnv
instance HasBEnv KEnv where bEnv :: Lens' KEnv BEnv
bEnv = (BEnv -> f BEnv) -> KEnv -> f KEnv
forall c. HasKEnv c => Lens' c BEnv
Lens' KEnv BEnv
kBEnv
instance HasLogFunc KEnv where logFuncL :: Lens' KEnv LogFunc
logFuncL = (AppEnv -> f AppEnv) -> KEnv -> f KEnv
forall c. HasKEnv c => Lens' c AppEnv
Lens' KEnv AppEnv
kAppEnv((AppEnv -> f AppEnv) -> KEnv -> f KEnv)
-> ((LogFunc -> f LogFunc) -> AppEnv -> f AppEnv)
-> (LogFunc -> f LogFunc)
-> KEnv
-> f KEnv
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(LogFunc -> f LogFunc) -> AppEnv -> f AppEnv
forall env. HasLogFunc env => Lens' env LogFunc
Lens' AppEnv LogFunc
logFuncL
instance MonadK (RIO KEnv) where
myBinding :: RIO KEnv Keycode
myBinding = Getting Keycode KEnv Keycode -> RIO KEnv Keycode
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view ((BEnv -> Const Keycode BEnv) -> KEnv -> Const Keycode KEnv
forall c. HasBEnv c => Lens' c BEnv
Lens' KEnv BEnv
bEnv((BEnv -> Const Keycode BEnv) -> KEnv -> Const Keycode KEnv)
-> ((Keycode -> Const Keycode Keycode)
-> BEnv -> Const Keycode BEnv)
-> Getting Keycode KEnv Keycode
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Keycode -> Const Keycode Keycode) -> BEnv -> Const Keycode BEnv
forall c. HasBEnv c => Lens' c Keycode
Lens' BEnv Keycode
binding)
instance (HasAppEnv e, HasAppCfg e, HasLogFunc e) => MonadKIO (RIO e) where
emit :: KeyEvent -> RIO e ()
emit KeyEvent
e = Getting (TMVar KeyEvent) e (TMVar KeyEvent)
-> RIO e (TMVar KeyEvent)
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (TMVar KeyEvent) e (TMVar KeyEvent)
forall c. HasAppEnv c => Lens' c (TMVar KeyEvent)
Lens' e (TMVar KeyEvent)
outVar RIO e (TMVar KeyEvent) -> (TMVar KeyEvent -> RIO e ()) -> RIO e ()
forall a b. RIO e a -> (a -> RIO e b) -> RIO e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= STM () -> RIO e ()
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM () -> RIO e ())
-> (TMVar KeyEvent -> STM ()) -> TMVar KeyEvent -> RIO e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TMVar KeyEvent -> KeyEvent -> STM ())
-> KeyEvent -> TMVar KeyEvent -> STM ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip TMVar KeyEvent -> KeyEvent -> STM ()
forall a. TMVar a -> a -> STM ()
putTMVar KeyEvent
e
pause :: Milliseconds -> RIO e ()
pause = Int -> RIO e ()
forall (m :: * -> *). MonadIO m => Int -> m ()
threadDelay (Int -> RIO e ())
-> (Milliseconds -> Int) -> Milliseconds -> RIO e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
1000) (Int -> Int) -> (Milliseconds -> Int) -> Milliseconds -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Milliseconds -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral
hold :: Bool -> RIO e ()
hold Bool
b = do
Sluice
sl <- Getting Sluice e Sluice -> RIO e Sluice
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Sluice e Sluice
forall c. HasAppEnv c => Lens' c Sluice
Lens' e Sluice
sluice
Dispatch
di <- Getting Dispatch e Dispatch -> RIO e Dispatch
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Dispatch e Dispatch
forall c. HasAppEnv c => Lens' c Dispatch
Lens' e Dispatch
dispatch
if Bool
b then Sluice -> RIO e ()
forall e. HasLogFunc e => Sluice -> RIO e ()
Sl.block Sluice
sl else Sluice -> RIO e [KeyEvent]
forall e. HasLogFunc e => Sluice -> RIO e [KeyEvent]
Sl.unblock Sluice
sl RIO e [KeyEvent] -> ([KeyEvent] -> RIO e ()) -> RIO e ()
forall a b. RIO e a -> (a -> RIO e b) -> RIO e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Dispatch -> [KeyEvent] -> RIO e ()
forall e. HasLogFunc e => Dispatch -> [KeyEvent] -> RIO e ()
Dp.rerun Dispatch
di
register :: HookLocation -> Hook (RIO e) -> RIO e ()
register HookLocation
l Hook (RIO e)
h = do
Hooks
hs <- case HookLocation
l of
HookLocation
InputHook -> Getting Hooks e Hooks -> RIO e Hooks
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Hooks e Hooks
forall c. HasAppEnv c => Lens' c Hooks
Lens' e Hooks
inHooks
HookLocation
OutputHook -> Getting Hooks e Hooks -> RIO e Hooks
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Hooks e Hooks
forall c. HasAppEnv c => Lens' c Hooks
Lens' e Hooks
outHooks
Hooks -> Hook (RIO e) -> RIO e ()
forall e. HasLogFunc e => Hooks -> Hook (RIO e) -> RIO e ()
Hs.register Hooks
hs Hook (RIO e)
h
layerOp :: LayerOp -> RIO e ()
layerOp LayerOp
o = Getting Keymap e Keymap -> RIO e Keymap
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Keymap e Keymap
forall c. HasAppEnv c => Lens' c Keymap
Lens' e Keymap
keymap RIO e Keymap -> (Keymap -> RIO e ()) -> RIO e ()
forall a b. RIO e a -> (a -> RIO e b) -> RIO e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Keymap
hl -> Keymap -> LayerOp -> RIO e ()
forall e. HasLogFunc e => Keymap -> LayerOp -> RIO e ()
Km.layerOp Keymap
hl LayerOp
o
inject :: KeyEvent -> RIO e ()
inject KeyEvent
e = do
Dispatch
di <- Getting Dispatch e Dispatch -> RIO e Dispatch
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Dispatch e Dispatch
forall c. HasAppEnv c => Lens' c Dispatch
Lens' e Dispatch
dispatch
Utf8Builder -> RIO e ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logDebug (Utf8Builder -> RIO e ()) -> Utf8Builder -> RIO e ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Injecting event: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> KeyEvent -> Utf8Builder
forall a. Display a => a -> Utf8Builder
display KeyEvent
e
Dispatch -> [KeyEvent] -> RIO e ()
forall e. HasLogFunc e => Dispatch -> [KeyEvent] -> RIO e ()
Dp.rerun Dispatch
di [KeyEvent
e]
shellCmd :: LayerTag -> RIO e ()
shellCmd LayerTag
t = do
Bool
f <- Getting Bool e Bool -> RIO e Bool
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Bool e Bool
forall c. HasAppCfg c => Lens' c Bool
Lens' e Bool
allowCmd
if Bool
f then do
Utf8Builder -> RIO e ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo (Utf8Builder -> RIO e ()) -> Utf8Builder -> RIO e ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Running command: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> LayerTag -> Utf8Builder
forall a. Display a => a -> Utf8Builder
display LayerTag
t
String -> RIO e ()
forall (m :: * -> *). MonadIO m => String -> m ()
spawnCommand (String -> RIO e ())
-> (LayerTag -> String) -> LayerTag -> RIO e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LayerTag -> String
unpack (LayerTag -> RIO e ()) -> LayerTag -> RIO e ()
forall a b. (a -> b) -> a -> b
$ LayerTag
t
else
Utf8Builder -> RIO e ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Utf8Builder -> m ()
logInfo (Utf8Builder -> RIO e ()) -> Utf8Builder -> RIO e ()
forall a b. (a -> b) -> a -> b
$ Utf8Builder
"Received but not running: " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<> LayerTag -> Utf8Builder
forall a. Display a => a -> Utf8Builder
display LayerTag
t
where
spawnCommand :: MonadIO m => String -> m ()
spawnCommand :: forall (m :: * -> *). MonadIO m => String -> m ()
spawnCommand String
cmd = m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
-> m ())
-> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
-> m ()
forall a b. (a -> b) -> a -> b
$ String
-> CreateProcess
-> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
forall (m :: * -> *).
MonadIO m =>
String
-> CreateProcess
-> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
createProcess_ String
"spawnCommand"
(String -> CreateProcess
shell String
cmd){
close_fds = True
}