diff options
| author | Josh Rahm <rahm@google.com> | 2023-12-13 12:01:31 -0700 |
|---|---|---|
| committer | Josh Rahm <rahm@google.com> | 2023-12-13 12:03:16 -0700 |
| commit | 4cdab9f06cd0ecf5ad7d5ee15dd83c4dc4eb396a (patch) | |
| tree | 792b639c8b9024e0d05827df27523fac6d897c79 | |
| parent | 7c16c50990492f9e6cc2477f8284dc1a2f33d946 (diff) | |
| download | rde-4cdab9f06cd0ecf5ad7d5ee15dd83c4dc4eb396a.tar.gz rde-4cdab9f06cd0ecf5ad7d5ee15dd83c4dc4eb396a.tar.bz2 rde-4cdab9f06cd0ecf5ad7d5ee15dd83c4dc4eb396a.zip | |
Replacing existing binder DSL with a better and more expressive DSL.
This new DSL is cleaner and more powerful. This new DSL allows mixing
key and mouse bindings in submappings, which can be very useful.
| -rw-r--r-- | src/Rahm/Desktop/Keys.hs | 354 | ||||
| -rw-r--r-- | src/Rahm/Desktop/Keys/Dsl.hs | 607 | ||||
| -rw-r--r-- | src/Rahm/Desktop/Keys/Dsl2.hs | 254 | ||||
| -rw-r--r-- | src/Rahm/Desktop/Submap.hs | 78 |
4 files changed, 455 insertions, 838 deletions
diff --git a/src/Rahm/Desktop/Keys.hs b/src/Rahm/Desktop/Keys.hs index 2cc3d79..412d8f5 100644 --- a/src/Rahm/Desktop/Keys.hs +++ b/src/Rahm/Desktop/Keys.hs @@ -60,29 +60,7 @@ import Rahm.Desktop.History historyForward, jumpToLastLocation, ) -import Rahm.Desktop.Keys.Dsl - ( ButtonBinding (..), - ButtonBindings, - Documented (..), - KeyBinding (..), - KeyBindings, - altMask, - altMod, - altgrMod, - bind, - buttonDocumentation, - controlMod, - doc, - documentation, - getConfig, - justMod, - noMod, - rawMask, - runButtons, - runKeys, - shiftMod, - (-|-), - ) +import Rahm.Desktop.Keys.Dsl2 import Rahm.Desktop.Keys.Wml ( addWindowToSelection, clearWindowSelection, @@ -186,9 +164,6 @@ spawnX = spawn safeSpawnX :: String -> [String] -> X () safeSpawnX = safeSpawn -noWindow :: b -> Window -> b -noWindow = const - selectedWindowsColor = BorderColor "#00ffff" "#00ffff" decreaseVolume = spawnX "pactl set-sink-volume @DEFAULT_SINK@ -5%" @@ -249,34 +224,6 @@ button14 = 14 button15 :: Button button15 = 15 -keyBindingToKeymap :: (XConfig l -> KeyBindings) -> KeyMap l -keyBindingToKeymap bindings config = Map.mapWithKey bindingToX (bindings config) - where - bindingToX :: (KeyMask, KeySym) -> Documented KeyBinding -> X () - bindingToX key b = - case b of - Documented _ (Action x) -> x - Documented _ (Submap mapping) -> - -- This is a submap, add it to the pending buffer. - -- - -- This could potentially use the current event in the XState and - -- lookupString to potentially recover the real string typed, but - -- for now, this will do. - pushAddPendingBuffer (keysymToString $ snd key) $ do - submap (Map.mapWithKey bindingToX mapping) - Documented _ (Repeat mapping) -> do - pushAddPendingBuffer (keysymToString $ snd key) $ do - mapM_ (bindingToX key) (Map.lookup key mapping) - fix $ \recur -> do - submap - ( Map.mapWithKey - ( \k b -> do - pushAddPendingBuffer (keysymToString $ snd k) $ - bindingToX k b >> recur - ) - mapping - ) - mapWindows :: (Ord b) => (a -> b) -> W.StackSet i l a s sd -> W.StackSet i l b s sd mapWindows fn (W.StackSet cur vis hidden float) = W.StackSet @@ -290,13 +237,8 @@ mapWindows fn (W.StackSet cur vis hidden float) = data ShiftType = JustShift | ShiftAndFollow | ShiftAndSwap -keymap :: XConfig l -> KeyBindings -keymap = runKeys $ do - config <- getConfig - - let subkeys keysM = Submap (runKeys keysM config) - repeatable keysM = Repeat (runKeys keysM config) - +bindings :: Binder () +bindings = do bind xK_apostrophe $ do justMod $ doc "Jump to a window/tile currently dragging window" $ do @@ -364,33 +306,33 @@ keymap = runKeys $ do doc "Move XMobar to another screen." $ spawnX "pkill -SIGUSR1 xmobar" - bind xK_F1 $ do - justMod $ - doc - "Print this documentation" - ( safeSpawn - "gxmessage" - [ "-fn", - "Source Code Pro", - "Key Bindings\n\n" - ++ documentation (keymap config) - ++ "\n\nButton Bindings\n\n" - ++ buttonDocumentation (mouseMap config) - ] :: - X () - ) - - bind xK_F7 $ do - justMod $ - doc - "Print this documentation to stdout (at LogLevel Info)" - ( logs - Info - "KeyBindings\n\n%s\n\nButtonBindings\n\n%s" - (documentation (keymap config)) - (buttonDocumentation (mouseMap config)) :: - X () - ) + -- bind xK_F1 $ do + -- justMod $ + -- doc + -- "Print this documentation" + -- ( safeSpawn + -- "gxmessage" + -- [ "-fn", + -- "Source Code Pro", + -- "Key Bindings\n\n" + -- ++ documentation (keymap config) + -- ++ "\n\nButton Bindings\n\n" + -- ++ buttonDocumentation (mouseMap config) + -- ] :: + -- X () + -- ) + + -- bind xK_F7 $ do + -- justMod $ + -- doc + -- "Print this documentation to stdout (at LogLevel Info)" + -- ( logs + -- Info + -- "KeyBindings\n\n%s\n\nButtonBindings\n\n%s" + -- (documentation (keymap config)) + -- (buttonDocumentation (mouseMap config)) :: + -- X () + -- ) bind xK_F10 $ do justMod playPauseDoc @@ -423,9 +365,6 @@ keymap = runKeys $ do doc ("Move the current window to screen " ++ show idx) $ withScreen W.shift idx - altgrMod - (logs Info "Test altgr" :: X ()) - bind xK_bracketright $ do justMod $ doc "Increase the gaps between windows." $ @@ -500,7 +439,7 @@ keymap = runKeys $ do bind xK_d $ justMod $ doc "Record (define) macros." $ - subkeys $ do + subbind $ do bind xK_w $ noMod $ doc @@ -746,7 +685,7 @@ keymap = runKeys $ do bind xK_space $ do justMod $ doc "Layout-related bindings" $ - subkeys $ do + subbind $ do bind xK_n $ (noMod -|- justMod) $ doc "Use the next layout in the layout list." $ do @@ -833,7 +772,7 @@ keymap = runKeys $ do bind xK_t $ do justMod $ doc "Spawn a terminal." $ - spawnX (terminal config) + spawnX =<< asks (terminal . config) shiftMod $ doc "Sink the current window into the tiling." $ @@ -843,26 +782,7 @@ keymap = runKeys $ do altMod $ doc "Spawn a floating terminal" $ - spawnX (terminal config ++ " -t Floating\\ Term") - - bind xK_v - $ - -- Allows repeated strokes of M-h and M-l to reduce and increase volume - -- respectively. - justMod - $ doc - "Allows repeated strokes of M-h and M-l to decrease and\n\ - \increase volume respectively" - $ repeatable - $ do - bind xK_h $ - justMod decreaseVolumeDoc - - bind xK_l $ - justMod increaseVolumeDoc - - bind xK_v $ - justMod (return () :: X ()) + spawnX =<< asks ((++ " -t Floating\\ Term") . terminal . config) bind xK_x $ do justMod $ @@ -872,7 +792,7 @@ keymap = runKeys $ do bind xK_z $ do justMod $ doc "Less often used keybindings." $ - subkeys $ do + subbind $ do bind xK_e $ do (justMod -|- noMod) $ doc "Select an emoji" $ @@ -955,7 +875,9 @@ keymap = runKeys $ do logs next "LogLevel set to %s." (show next) bind xF86XK_Calculator $ do - noMod $ spawnX $ terminal config ++ " -t Floating\\ Term -e /usr/bin/env python3" + noMod $ + spawnX + =<< asks ((++ " -t Floating\\ Term -e /usr/bin/env python3") . terminal . config) bind xF86XK_AudioLowerVolume $ do noMod $ spawnX "pactl set-sink-volume @DEFAULT_SINK@ -1%" @@ -990,63 +912,6 @@ keymap = runKeys $ do noMod $ spawnX "set-backlight.sh -0.05" justMod $ spawnX "set-backlight.sh 0.01" rawMask shiftMask $ spawnX "set-backlight.sh 0" - -buttonBindingsToButtonMap :: (XConfig l -> ButtonBindings) -> ButtonsMap l -buttonBindingsToButtonMap bindings config = Map.mapWithKey bindingToX (bindings config) - where - bindingToX :: (ButtonMask, Button) -> Documented ButtonBinding -> (Window -> X ()) - bindingToX click@(mask, btn) = \case - Documented _ (ButtonAction action) -> action - Documented _ (ButtonSubmap sm) -> - pushAddPendingBuffer (printf "b%d " btn) - . submapButtonsWithKey (\_ _ -> return ()) (Map.mapWithKey bindingToX sm) - Documented _ (ButtonContinuous sm) -> \window -> - pushAddPendingBuffer (printf "b%d " btn) $ do - mapM_ (flip (bindingToX click) window) (Map.lookup click sm) - fix $ \recur -> do - submapButtonsWithKey - ( \_ _ -> return () - ) - ( Map.mapWithKey - ( \k b w -> - pushAddPendingBuffer (printf "b%d " (snd k)) $ - bindingToX k b w >> recur - ) - sm - ) - window - -myMouseMoveWindow = - D.mouseMoveWindowAndThen X.focus $ - mconcat - [ D.ifReleased button3 D.sinkOnRelease, - D.ifReleased' button2 $ \w _ -> X.killWindow w - ] - -myMouseResizeAction = - D.mouseResizeWindowAndThen X.focus $ - mconcat - [ D.ifReleased button1 D.sinkOnRelease - ] - -mouseMap :: forall l. XConfig l -> ButtonBindings -mouseMap = runButtons $ do - config <- getConfig - - -- let x button = Map.lookup button (mouseMap config) - - -- let defaultButtons button = - -- fromMaybe (\w -> return ()) $ - -- Map.lookup button (mouseMap config) - let subMouse = ButtonSubmap . flip runButtons config - - continuous buttons = do - let bindingMap = runButtons buttons config - in forM_ (Map.toList bindingMap) $ \((m, b), _) -> do - bind b $ - rawMask m $ - ButtonContinuous bindingMap - bind button1 $ do justMod $ doc @@ -1087,50 +952,63 @@ mouseMap = runButtons $ do doc "Media next" $ noWindow mediaNext - bind button14 $ do - noMod $ - doc "Additional Mouse Bindings" $ - subMouse $ do - bind button3 $ - noMod $ - doc "Drag a workspace to a different screen" $ - noWindow D.dragWorkspace + let button14Binder = do + bind button3 $ + noMod $ + doc "Drag a workspace to a different screen" $ + noWindow D.dragWorkspace + + bind button1 $ + noMod $ + doc "Swap a window with another window by dragging." $ + noWindow D.dragWindow + + bind button14 $ do + noMod $ + doc "Pop the window under the cursor" $ + noWindow $ + click >> sendMessage togglePop + + bind button15 $ do + noMod $ + doc "Spawn 'pavucontrol'" $ + noWindow $ + spawnX "pavucontrol" + + let mediaButtons = + [ (button4, "Increase volume", noWindow increaseVolume), + (button5, "Decrease volume", noWindow decreaseVolume), + (button2, "Play/Pause", noWindow playPause), + (button9, "History Forward", noWindow (viewAdjacentTo pointerWorkspace next)), + (button8, "History Back", noWindow (viewAdjacentTo pointerWorkspace prev)), + (button6, "Media Previous", noWindow mediaPrev), + (button7, "Media Next", noWindow mediaNext) + ] + + continuous $ do + forM_ mediaButtons $ \(b, d, a) -> + bind b $ noMod $ doc d a - bind button1 $ - noMod $ - doc "Swap a window with another window by dragging." $ - noWindow D.dragWindow + bind xK_h $ + justMod decreaseVolumeDoc - bind button14 $ do - noMod $ - doc "Pop the window under the cursor" $ - noWindow $ - click >> sendMessage togglePop + bind xK_l $ + justMod increaseVolumeDoc - bind button15 $ do - noMod $ - doc "Spawn 'pavucontrol'" $ - noWindow $ - spawnX "pavucontrol" - - let mediaButtons = - [ (button4, "Increase volume", noWindow increaseVolume), - (button5, "Decrease volume", noWindow decreaseVolume), - (button2, "Play/Pause", noWindow playPause), - (button9, "History Forward", noWindow (viewAdjacentTo pointerWorkspace next)), - (button8, "History Back", noWindow (viewAdjacentTo pointerWorkspace prev)), - (button6, "Media Previous", noWindow mediaPrev), - (button7, "Media Next", noWindow mediaNext) - ] + bind button14 $ do + noMod $ + doc "Additional Mouse Bindings" $ + subbind button14Binder - continuous $ - forM_ mediaButtons $ \(b, d, a) -> - bind b $ noMod $ doc d a + bind xK_v $ do + justMod $ + doc "Same as button14" $ + subbind button14Binder bind button13 $ noMod $ doc "General Window Management Extra Mouse Bindings" $ - subMouse $ do + subbind $ do bind button1 $ noMod $ doc @@ -1164,10 +1042,10 @@ mouseMap = runButtons $ do bind button13 $ noMod $ - subMouse $ do + subbind $ do bind button13 $ noMod $ - subMouse $ do + subbind $ do bind button13 $ noMod $ doc "Lock the screen" $ @@ -1182,7 +1060,7 @@ mouseMap = runButtons $ do bind button15 $ do noMod $ doc "General navigation extra mouse bindings" $ - subMouse $ do + subbind $ do bind button13 $ noMod $ doc "Goto the accompaning workspace to the current one." $ @@ -1220,7 +1098,7 @@ mouseMap = runButtons $ do bind button14 $ noMod $ - subMouse $ do + subbind $ do bind button1 $ noMod $ doc "Pin the selected windows" $ @@ -1273,19 +1151,42 @@ mouseMap = runButtons $ do ) in windows f >> escape --- Bindings specific to a window. These are set similarly to th ekeymap above, --- but uses a Query monad to tell which windows the keys will apply to. --- --- This is useful to create hotkeys in applications where hot keys are not --- configurable, or to remove keybindings that are irritating (looking at you, --- ctrl+w in Chrome!!). +myMouseMoveWindow = + D.mouseMoveWindowAndThen X.focus $ + mconcat + [ D.ifReleased button3 D.sinkOnRelease, + D.ifReleased' button2 $ \w _ -> X.killWindow w + ] + +myMouseResizeAction = + D.mouseResizeWindowAndThen X.focus $ + mconcat + [ D.ifReleased button1 D.sinkOnRelease + ] + +applyKeys :: XConfig l -> IO (XConfig l) +applyKeys c = + let conf' = withBindings bindings c + in return $ + windowBindings $ + conf' + { keys = + Map.insert + (modMask c .|. shiftMask, xK_q) + (spawnX "xmonad --recompile && xmonad --restart") + . keys conf' + } + windowSpecificBindings :: XConfig l -> WriterT (Map (KeyMask, KeySym) (X ())) Query () windowSpecificBindings config = do w <- lift ask + let altMask = mod1Mask let mods = permuteMods [shiftMask, controlMask, 0] - let configureIf b k = tell =<< lift (b --> return (keyBindingToKeymap (runKeys k) config)) + let configureIf b k = + let (keymap, _) = resolveBindings (runBinder config k) + in tell =<< lift (b --> return (keymap config)) emitKey = flip sendKey w configureIf (flip elem (browsers ++ spotify) <$> className) $ do @@ -1398,20 +1299,11 @@ windowBindings xconfig = map <- execWriterT $ windowSpecificBindings xconfig w <- ask - liftX $ logs Info "For Window: %s" (show w) + liftX $ logs Debug "For Window: %s" (show w) forM_ (Map.toList map) $ \(key, action) -> do - liftX $ logs Info " -- remap: %s" (show key) + liftX $ logs Debug " -- remap: %s" (show key) remapKey key action -applyKeys :: XConfig l -> IO (XConfig l) -applyKeys config = - return $ - windowBindings $ - config - { keys = keyBindingToKeymap keymap, - mouseBindings = buttonBindingsToButtonMap mouseMap - } - modifyWindowBorder :: Integer -> SpacingModifier modifyWindowBorder i = ModifyWindowBorder $ \(Border a b c d) -> Border (clip $ a + i) (clip $ b + i) (clip $ c + i) (clip $ d + i) diff --git a/src/Rahm/Desktop/Keys/Dsl.hs b/src/Rahm/Desktop/Keys/Dsl.hs deleted file mode 100644 index 1246d3b..0000000 --- a/src/Rahm/Desktop/Keys/Dsl.hs +++ /dev/null @@ -1,607 +0,0 @@ -{-# LANGUAGE FunctionalDependencies #-} - -module Rahm.Desktop.Keys.Dsl - ( doc, - (-|-), - ButtonBinding (..), - ButtonBindings, - Documented (..), - HasConfig, - KeyBinding (..), - KeyBindings, - altAltgrMod, - altHyperAltgrMod, - altHyperMod, - altMask, - altMod, - altSuperAltgrMod, - altSuperHyperAltgrMod, - altSuperHyperMod, - altSuperMod, - altgrMask, - altgrMod, - bind, - buttonDocumentation, - controlAltAltgrMod, - controlAltHyperAltgrMod, - controlAltHyperMod, - controlAltMod, - controlAltSuperAltgrMod, - controlAltSuperHyperAltgrMod, - controlAltSuperHyperMod, - controlAltSuperMod, - controlAltgrMod, - controlHyperAltgrMod, - controlHyperMod, - controlMod, - controlSuperAltgrMod, - controlSuperHyperAltgrMod, - controlSuperHyperMod, - controlSuperMod, - documentation, - getConfig, - hyperAltgrMod, - hyperMask, - hyperMod, - justMod, - maskMod, - noMod, - rawMask, - runButtons, - runKeys, - shiftAltAltgrMod, - shiftAltHyperAltgrMod, - shiftAltHyperMod, - shiftAltMod, - shiftAltSuperAltgrMod, - shiftAltSuperHyperAltgrMod, - shiftAltSuperHyperMod, - shiftAltSuperMod, - shiftAltgrMod, - shiftControlAltAltgrMod, - shiftControlAltHyperAltgrMod, - shiftControlAltHyperMod, - shiftControlAltMod, - shiftControlAltSuperAltgrMod, - shiftControlAltSuperHyperAltgrMod, - shiftControlAltSuperHyperMod, - shiftControlAltSuperMod, - shiftControlAltgrMod, - shiftControlHyperAltgrMod, - shiftControlHyperMod, - shiftControlMod, - shiftControlSuperAltgrMod, - shiftControlSuperHyperAltgrMod, - shiftControlSuperHyperMod, - shiftControlSuperMod, - shiftHyperAltgrMod, - shiftHyperMod, - shiftMod, - shiftSuperAltgrMod, - shiftSuperHyperAltgrMod, - shiftSuperHyperMod, - shiftSuperMod, - superAltgrMod, - superHyperAltgrMod, - superHyperMod, - superMask, - superMod, - ) -where - -import Control.Arrow (first, second) -import Control.Monad.State (State, execState, modify') -import Control.Monad.Writer - ( MonadWriter (tell), - execWriter, - forM_, - when, - ) -import Data.Bits ((.&.)) -import Data.List (intercalate, sortOn) -import Data.Map (Map) -import qualified Data.Map as Map - ( empty, - fromList, - fromListWith, - toList, - ) -import Text.Printf (printf) -import XMonad - ( Button, - ButtonMask, - KeyMask, - KeySym, - MonadState (get), - Window, - X, - XConfig (modMask), - controlMask, - keysymToString, - mod1Mask, - mod3Mask, - mod4Mask, - shiftMask, - (.|.), - ) - -data Documented t = Documented String t - -data KeyBinding - = Action (X ()) - | Submap KeyBindings - | Repeat KeyBindings - -type KeyBindings = Map (KeyMask, KeySym) (Documented KeyBinding) - -data ButtonBinding - = ButtonAction (Window -> X ()) - | ButtonSubmap ButtonBindings - | ButtonContinuous ButtonBindings - --- Window -> X () - -type ButtonBindings = Map (KeyMask, Button) (Documented ButtonBinding) - -{- Module that defines a DSL for binding keys. -} -newtype KeysM l a = KeysM (State (XConfig l, KeyBindings) a) - deriving (Functor, Applicative, Monad) - -newtype ButtonsM l a = ButtonsM (State (XConfig l, ButtonBindings) a) - deriving (Functor, Applicative, Monad) - -newtype BindingBuilder b a = BindingBuilder (State (KeyMask, [(KeyMask, b)]) a) - deriving (Functor, Applicative, Monad) - -class HasConfig m where - getConfig :: m l (XConfig l) - -class Bindable k where - type BindableValue k :: * - type BindableMonad k :: (* -> *) -> * -> * - - bind :: k -> BindingBuilder (BindableValue k) a -> BindableMonad k l () - --- section :: String -> BindableMonad k l () -> BindableMonad k l () - -class Binding k b where - toB :: k -> b - - rawMask :: KeyMask -> k -> BindingBuilder b () - rawMask m x = BindingBuilder $ modify' (second ((m, toB x) :)) - -instance Binding (Window -> X ()) (Documented ButtonBinding) where - toB = Documented "" . ButtonAction - -instance Binding (X ()) (Documented KeyBinding) where - toB = Documented "" . Action - -instance Binding KeyBindings (Documented KeyBinding) where - toB = Documented "" . Submap - -instance Binding a (Documented a) where - toB = Documented "" - -instance Binding a a where - toB = id - --- Relationships to witness which types can be used with the "doc" function, --- which is used to document actions in a safe and programmable way.. -class Relation k b | k -> b - -instance Relation (X ()) KeyBinding - -instance Relation KeyBinding KeyBinding - -instance Relation ButtonBinding ButtonBinding - -instance Relation (Window -> X ()) ButtonBinding - -doc :: (Relation k b, Binding k (Documented b)) => String -> k -> Documented b -doc str k = let (Documented _ t) = toB k in Documented str t - -runKeys :: KeysM l a -> XConfig l -> KeyBindings -runKeys (KeysM stateM) config = - snd $ execState stateM (config, Map.empty) - -runButtons :: ButtonsM l a -> XConfig l -> ButtonBindings -runButtons (ButtonsM stateM) config = - snd $ execState stateM (config, Map.empty) - -instance HasConfig KeysM where - getConfig = fst <$> KeysM get - -instance HasConfig ButtonsM where - getConfig = fst <$> ButtonsM get - -{- Generally it is assumed that the mod key shoud be pressed, but not always. -} -noMod :: (Binding k b) => k -> BindingBuilder b () -noMod = rawMask 0 - -maskMod :: (Binding k b) => KeyMask -> k -> BindingBuilder b () -maskMod mask action = do - modMask <- fst <$> BindingBuilder get - rawMask (modMask .|. mask) action - -altMask :: KeyMask -altMask = mod1Mask - -hyperMask :: KeyMask -hyperMask = mod3Mask - -altgrMask :: KeyMask -altgrMask = 0x80 - -superMask :: KeyMask -superMask = mod4Mask - -justMod :: (Binding k b) => k -> BindingBuilder b () -justMod = maskMod 0 - -instance Bindable KeySym where - type BindableValue KeySym = Documented KeyBinding - type BindableMonad KeySym = KeysM - - -- bind :: KeySym -> BindingBuilder (X x) a -> KeysM l () - bind key (BindingBuilder stM) = do - m <- modMask <$> getConfig - let (_, values) = execState stM (m, []) - - KeysM $ - modify' $ - second $ - flip (<>) (Map.fromList (map (\(m, v) -> ((m, key), v)) values)) - -instance Bindable Button where - type BindableValue Button = Documented ButtonBinding - type BindableMonad Button = ButtonsM - - -- bind :: KeySym -> BindingBuilder (Window -> X ()) a -> ButtonsM l () - bind button (BindingBuilder stM) = do - m <- modMask <$> getConfig - let (_, values) = execState stM (m, []) - - ButtonsM $ - modify' $ - second $ - flip (<>) (Map.fromList (map (\(m, v) -> ((m, button), v)) values)) - -shiftControlAltSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltSuperHyperAltgrMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. superMask .|. hyperMask .|. altgrMask) - -shiftControlAltSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltSuperHyperMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. superMask .|. hyperMask) - -shiftControlAltSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltSuperAltgrMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. superMask .|. altgrMask) - -shiftControlAltSuperMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltSuperMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. superMask) - -shiftControlAltHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltHyperAltgrMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. hyperMask .|. altgrMask) - -shiftControlAltHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltHyperMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. hyperMask) - -shiftControlAltAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltAltgrMod = - maskMod (shiftMask .|. controlMask .|. altMask .|. altgrMask) - -shiftControlAltMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltMod = - maskMod (shiftMask .|. controlMask .|. altMask) - -shiftControlSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlSuperHyperAltgrMod = - maskMod (shiftMask .|. controlMask .|. superMask .|. hyperMask .|. altgrMask) - -shiftControlSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlSuperHyperMod = - maskMod (shiftMask .|. controlMask .|. superMask .|. hyperMask) - -shiftControlSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlSuperAltgrMod = - maskMod (shiftMask .|. controlMask .|. superMask .|. altgrMask) - -shiftControlSuperMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlSuperMod = - maskMod (shiftMask .|. controlMask .|. superMask) - -shiftControlHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlHyperAltgrMod = - maskMod (shiftMask .|. controlMask .|. hyperMask .|. altgrMask) - -shiftControlHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlHyperMod = - maskMod (shiftMask .|. controlMask .|. hyperMask) - -shiftControlAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlAltgrMod = - maskMod (shiftMask .|. controlMask .|. altgrMask) - -shiftControlMod :: (Binding k b) => k -> BindingBuilder b () -shiftControlMod = - maskMod (shiftMask .|. controlMask) - -shiftAltSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltSuperHyperAltgrMod = - maskMod (shiftMask .|. altMask .|. superMask .|. hyperMask .|. altgrMask) - -shiftAltSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltSuperHyperMod = - maskMod (shiftMask .|. altMask .|. superMask .|. hyperMask) - -shiftAltSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltSuperAltgrMod = - maskMod (shiftMask .|. altMask .|. superMask .|. altgrMask) - -shiftAltSuperMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltSuperMod = - maskMod (shiftMask .|. altMask .|. superMask) - -shiftAltHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltHyperAltgrMod = - maskMod (shiftMask .|. altMask .|. hyperMask .|. altgrMask) - -shiftAltHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltHyperMod = - maskMod (shiftMask .|. altMask .|. hyperMask) - -shiftAltAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltAltgrMod = - maskMod (shiftMask .|. altMask .|. altgrMask) - -shiftAltMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltMod = - maskMod (shiftMask .|. altMask) - -shiftSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftSuperHyperAltgrMod = - maskMod (shiftMask .|. superMask .|. hyperMask .|. altgrMask) - -shiftSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftSuperHyperMod = - maskMod (shiftMask .|. superMask .|. hyperMask) - -shiftSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftSuperAltgrMod = - maskMod (shiftMask .|. superMask .|. altgrMask) - -shiftSuperMod :: (Binding k b) => k -> BindingBuilder b () -shiftSuperMod = - maskMod (shiftMask .|. superMask) - -shiftHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftHyperAltgrMod = - maskMod (shiftMask .|. hyperMask .|. altgrMask) - -shiftHyperMod :: (Binding k b) => k -> BindingBuilder b () -shiftHyperMod = - maskMod (shiftMask .|. hyperMask) - -shiftAltgrMod :: (Binding k b) => k -> BindingBuilder b () -shiftAltgrMod = - maskMod (shiftMask .|. altgrMask) - -shiftMod :: (Binding k b) => k -> BindingBuilder b () -shiftMod = maskMod shiftMask - -controlAltSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlAltSuperHyperAltgrMod = - maskMod (controlMask .|. altMask .|. superMask .|. hyperMask .|. altgrMask) - -controlAltSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -controlAltSuperHyperMod = - maskMod (controlMask .|. altMask .|. superMask .|. hyperMask) - -controlAltSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlAltSuperAltgrMod = - maskMod (controlMask .|. altMask .|. superMask .|. altgrMask) - -controlAltSuperMod :: (Binding k b) => k -> BindingBuilder b () -controlAltSuperMod = - maskMod (controlMask .|. altMask .|. superMask) - -controlAltHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlAltHyperAltgrMod = - maskMod (controlMask .|. altMask .|. hyperMask .|. altgrMask) - -controlAltHyperMod :: (Binding k b) => k -> BindingBuilder b () -controlAltHyperMod = - maskMod (controlMask .|. altMask .|. hyperMask) - -controlAltAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlAltAltgrMod = - maskMod (controlMask .|. altMask .|. altgrMask) - -controlAltMod :: (Binding k b) => k -> BindingBuilder b () -controlAltMod = - maskMod (controlMask .|. altMask) - -controlSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlSuperHyperAltgrMod = - maskMod (controlMask .|. superMask .|. hyperMask .|. altgrMask) - -controlSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -controlSuperHyperMod = - maskMod (controlMask .|. superMask .|. hyperMask) - -controlSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlSuperAltgrMod = - maskMod (controlMask .|. superMask .|. altgrMask) - -controlSuperMod :: (Binding k b) => k -> BindingBuilder b () -controlSuperMod = - maskMod (controlMask .|. superMask) - -controlHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlHyperAltgrMod = - maskMod (controlMask .|. hyperMask .|. altgrMask) - -controlHyperMod :: (Binding k b) => k -> BindingBuilder b () -controlHyperMod = - maskMod (controlMask .|. hyperMask) - -controlAltgrMod :: (Binding k b) => k -> BindingBuilder b () -controlAltgrMod = - maskMod (controlMask .|. altgrMask) - -controlMod :: (Binding k b) => k -> BindingBuilder b () -controlMod = maskMod controlMask - -altSuperHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -altSuperHyperAltgrMod = - maskMod (altMask .|. superMask .|. hyperMask .|. altgrMask) - -altSuperHyperMod :: (Binding k b) => k -> BindingBuilder b () -altSuperHyperMod = - maskMod (altMask .|. superMask .|. hyperMask) - -altSuperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -altSuperAltgrMod = - maskMod (altMask .|. superMask .|. altgrMask) - -altSuperMod :: (Binding k b) => k -> BindingBuilder b () -altSuperMod = - maskMod (altMask .|. superMask) - -altHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -altHyperAltgrMod = - maskMod (altMask .|. hyperMask .|. altgrMask) - -altHyperMod :: (Binding k b) => k -> BindingBuilder b () -altHyperMod = - maskMod (altMask .|. hyperMask) - -altAltgrMod :: (Binding k b) => k -> BindingBuilder b () -altAltgrMod = - maskMod (altMask .|. altgrMask) - -altMod :: (Binding k b) => k -> BindingBuilder b () -altMod = maskMod altMask - -superHyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -superHyperAltgrMod = - maskMod (superMask .|. hyperMask .|. altgrMask) - -superHyperMod :: (Binding k b) => k -> BindingBuilder b () -superHyperMod = - maskMod (superMask .|. hyperMask) - -superAltgrMod :: (Binding k b) => k -> BindingBuilder b () -superAltgrMod = - maskMod (superMask .|. altgrMask) - -superMod :: (Binding k b) => k -> BindingBuilder b () -superMod = maskMod superMask - -hyperAltgrMod :: (Binding k b) => k -> BindingBuilder b () -hyperAltgrMod = - maskMod (hyperMask .|. altgrMask) - -hyperMod :: (Binding k b) => k -> BindingBuilder b () -hyperMod = maskMod hyperMask - -altgrMod :: (Binding k b) => k -> BindingBuilder b () -altgrMod = maskMod altgrMask - -{- Can combine two or more of the functions above to apply the same action to - - multiple masks. -} -(-|-) :: - (Binding k b) => - (k -> BindingBuilder b ()) -> - (k -> BindingBuilder b ()) -> - k -> - BindingBuilder b () -(-|-) fn1 fn2 f = fn1 f >> fn2 f - -buttonDocumentation :: ButtonBindings -> String -buttonDocumentation = execWriter . document' "" - where - document' pref keybindings = - forM_ (sortOn (map (\(a, b) -> (b, a)) . snd . snd) $ Map.toList (keyBindingsToList keybindings)) $ \(doc, (thing, keys)) -> do - when (not (null doc) || hasSubmap thing) $ - tell $ printf "%s%s: %s\n" pref (intercalate " or " $ map prettyShow keys) doc - case thing of - ButtonAction _ -> return () - ButtonSubmap submap -> document' (pref ++ " ") submap - ButtonContinuous submap -> do - tell pref - tell " (repeatable):\n" - document' (pref ++ " ") submap - - keyBindingsToList :: ButtonBindings -> Map String (ButtonBinding, [(ButtonMask, Button)]) - keyBindingsToList b = - (\list -> ((\(_, Documented _ t) -> t) (head list), map fst |