aboutsummaryrefslogtreecommitdiff
path: root/src/Rahm/Desktop/Keys
diff options
context:
space:
mode:
Diffstat (limited to 'src/Rahm/Desktop/Keys')
-rw-r--r--src/Rahm/Desktop/Keys/Dsl2.hs81
1 files changed, 64 insertions, 17 deletions
diff --git a/src/Rahm/Desktop/Keys/Dsl2.hs b/src/Rahm/Desktop/Keys/Dsl2.hs
index bfa8b05..16a1b89 100644
--- a/src/Rahm/Desktop/Keys/Dsl2.hs
+++ b/src/Rahm/Desktop/Keys/Dsl2.hs
@@ -17,9 +17,9 @@
-- continuous $ do
-- bind xK_plus $ doc "increase volume" increaseVolume
-- bind xK_minus $ doc "decrease volume" decreaseVolume
-
module Rahm.Desktop.Keys.Dsl2 where
+import Control.Applicative ((<|>))
import Control.Monad.Fix (fix)
import Control.Monad.RWS (MonadTrans (lift), MonadWriter, forM_, when)
import Control.Monad.Reader (Reader, ask, runReader)
@@ -55,11 +55,34 @@ instance Functor Documented where
-- indicates what type of action a keytype can be bound to.
type family Action t where
-- KeySyms are bound to contextless actions with type X ()
- Action KeySym = X ()
+ Action KeySymOrKeyCode = X ()
-- Buttons are associated with actions with type Window -> X (). In other
-- words, actions bound to a button have windows associated with it.
Action Button = Window -> X ()
+class (Bind (Super k)) => LiftBinding k where
+ type Super k :: *
+ doLift :: k -> Super k
+
+instance LiftBinding KeySymOrKeyCode where
+ type Super KeySymOrKeyCode = KeySymOrKeyCode
+ doLift = id
+
+instance LiftBinding KeySym where
+ type Super KeySym = KeySymOrKeyCode
+ doLift = Ks
+
+instance LiftBinding KeyCode where
+ type Super KeyCode = KeySymOrKeyCode
+ doLift = Kc
+
+instance LiftBinding Button where
+ type Super Button = Button
+ doLift = id
+
+data KeySymOrKeyCode = Ks KeySym | Kc KeyCode
+ deriving (Ord, Eq, Show, Read)
+
-- | An GADT for XConfig that hides the 'l' parameter. This keeps type
-- signatures clean by not having to carry around a superfluous type variable.
data XConfigH where
@@ -84,7 +107,7 @@ data Binding t
-- | Compiled bindings map. This is the type built up by the Binder monad.
data BindingsMap = BindingsMap
{ -- | Bindings for keys
- key_bindings :: Map (KeyMask, KeySym) (Documented (Binding KeySym)),
+ key_bindings :: Map (KeyMask, KeySymOrKeyCode) (Documented (Binding KeySymOrKeyCode)),
-- | Bindings for buttons.
button_bindings :: Map (KeyMask, Button) (Documented (Binding Button)),
-- | If no mapping for a key sym exists, this function is called to handle
@@ -108,7 +131,6 @@ instance Semigroup BindingsMap where
instance Monoid BindingsMap where
mempty = BindingsMap mempty mempty (\_ -> return ()) (\_ _ -> return ())
-
-- | This type is an intermediate monad in the DSL. It binds an action to a key
-- mask. This is all bound to a key or button in the Binder monad.
newtype MaskBinder k a = MaskBinder
@@ -131,17 +153,18 @@ newtype Binder a = Binder (WriterT BindingsMap (Reader XConfigH) a)
class BindingType a where
-- | What key this action belongs to.
type BoundTo a :: *
+
-- | Convert the action into a Documented binding
toBinding :: a -> Documented (Binding (BoundTo a))
--- | Bindings are trivially a BindingType.
+-- | Bindings are trivially a BindingType.
instance BindingType (Binding t) where
type BoundTo (Binding t) = t
toBinding = Documented ""
-- | An X () can be bound to a Binding KeySym
instance BindingType (X ()) where
- type BoundTo (X ()) = KeySym
+ type BoundTo (X ()) = KeySymOrKeyCode
toBinding = Documented "" . Action
-- | A Window -> X () can be bound to a Binding Button.
@@ -166,7 +189,7 @@ instance Bind Button where
rawMaskRaw mask act = tell (Map.singleton mask act)
-- | For this, it adds the bindings to the keysMap
-instance Bind KeySym where
+instance Bind KeySymOrKeyCode where
doBinding key mp = mempty {key_bindings = Map.mapKeys (,key) mp}
rawMaskRaw mask act = tell (Map.singleton mask act)
@@ -196,12 +219,12 @@ altMod = withMod mod1Mask
m1 -|- m2 = \act -> m1 act >> m2 act
-- | Bind a key to a maksBinder.
-bind :: (Bind k) => k -> MaskBinder k () -> Binder ()
+bind :: (LiftBinding k) => k -> MaskBinder (Super k) () -> Binder ()
bind k h =
- tell . doBinding k . runReader (execWriterT $ unMaskBinder h) =<< ask
+ tell . doBinding (doLift k) . runReader (execWriterT $ unMaskBinder h) =<< ask
-- | Bind multiple keys to the same mask binder.
-bindL :: (Bind k) => [k] -> MaskBinder k () -> Binder ()
+bindL :: (LiftBinding k) => [k] -> MaskBinder (Super k) () -> Binder ()
bindL ks h = mapM_ (`bind` h) ks
-- | Convenience function for Documented.
@@ -216,13 +239,23 @@ noWindow fn _ = fn
resolveBindings ::
BindingsMap ->
( XConfig l -> Map (KeyMask, KeySym) (X ()),
+ XConfig l -> Map (KeyMask, KeyCode) (X ()),
XConfig l -> Map (ButtonMask, Button) (Window -> X ())
)
-resolveBindings (BindingsMap keyBindings buttonBindings _ _) =
+resolveBindings (BindingsMap keyAndKeyCodeBindings buttonBindings _ _) =
( \c -> Map.mapWithKey (\k -> pushK k (bindingToX c) . undocument) keyBindings,
+ \c -> Map.mapWithKey (\k -> bindingToX c . undocument) keycodeBindings,
\c -> Map.mapWithKey (\k -> pushB k (bindingToWinX c) . undocument) buttonBindings
)
where
+ (keyBindings, keycodeBindings) =
+ partitionMap
+ ( \case
+ (m, Kc keyCode) -> Right (m, keyCode)
+ (m, Ks keySym) -> Left (m, keySym)
+ )
+ keyAndKeyCodeBindings
+
pushB (_, b) fn binding win =
if isRepeatOrSubmap binding
then pushPendingBuffer ("b" ++ show b ++ " ") $ fn binding win
@@ -235,7 +268,7 @@ resolveBindings (BindingsMap keyBindings buttonBindings _ _) =
pushPendingBuffer (s ++ " ") $ fn binding
else fn binding
- bindingToX :: forall l. XConfig l -> Binding KeySym -> X ()
+ bindingToX :: forall l. XConfig l -> Binding KeySymOrKeyCode -> X ()
bindingToX conf = \case
NoBinding -> return ()
Action a -> a
@@ -260,8 +293,8 @@ resolveBindings (BindingsMap keyBindings buttonBindings _ _) =
bindingToWinX conf (undocument binding) win
after
Nothing -> catb (m, b) win
- (KeyPress m k s) -> do
- case Map.lookup (m, k) kbind of
+ (KeyPress m k c s) -> do
+ case Map.lookup (m, Kc c) kbind <|> Map.lookup (m, Ks k) kbind of
(Just binding) -> do
bindingToX conf (undocument binding)
after
@@ -276,7 +309,7 @@ resolveBindings (BindingsMap keyBindings buttonBindings _ _) =
ev <- nextButtonOrKeyEvent
let str = case ev of
ButtonPress m b -> "b" ++ show b
- KeyPress _ _ s -> s
+ KeyPress _ _ _ s -> s
lift $
pushAddPendingBuffer (str ++ " ") $
fn ev
@@ -310,7 +343,7 @@ runBinder conf (Binder binder) = runReader (execWriterT binder) (XConfigH conf)
withBindings :: Binder a -> XConfig l -> XConfig l
withBindings b config =
- let (keyBinds, buttonBinds) =
+ let (keyBinds, _, buttonBinds) =
resolveBindings $ runBinder config b
in config
{ keys = keyBinds,
@@ -351,7 +384,10 @@ documentation conf binder =
tindent (lines -> (h : t)) = unlines (h : map (" " ++) t)
tindent x = x
- keyToStr (m, k) = showMask m ++ keysymToString k
+ keyToStr (m, k) = showMask m ++ keysymOrKeyCodeToString k
+ keysymOrKeyCodeToString (Kc code) = show code
+ keysymOrKeyCodeToString (Ks sym) = keysymToString sym
+
showMask mask =
let masks =
[ (shiftMask, "S"),
@@ -386,3 +422,14 @@ bindOtherKeys fn = Binder $ tell (mempty {no_match_catch_key = fn})
bindOtherButtons :: ((KeyMask, Button) -> Window -> X ()) -> Binder ()
bindOtherButtons fn = Binder $ tell (mempty {no_match_catch_button = fn})
+
+partitionMap :: (Ord k, Ord k1, Ord k2) => (k -> Either k1 k2) -> Map k a -> (Map k1 a, Map k2 a)
+partitionMap f mp =
+ foldl
+ ( \(mp1, mp2) (k, v) ->
+ case f k of
+ Left k1 -> (Map.insert k1 v mp1, mp2)
+ Right k2 -> (mp1, Map.insert k2 v mp2)
+ )
+ (mempty, mempty)
+ (Map.toList mp)