{-# LANGUAGE RankNTypes #-} module Internal.Keys (applyKeys) where import Graphics.X11.ExtraTypes.XF86; import Internal.KeysM import Internal.SwapMaster (swapMaster) import XMonad.Hooks.ManageDocks import XMonad.Layout.MosaicAlt import Graphics.X11.ExtraTypes.XorgDefault import System.Process import XMonad.Util.Ungrab import XMonad.Layout.Spacing import Data.Maybe (isJust) import Debug.Trace import Control.Applicative import Prelude hiding ((!!)) import Control.Monad import Data.Char import Data.List hiding ((!!)) import Data.List.Safe ((!!)) import Data.Map (Map) import Internal.Layout import Internal.Marking import Internal.PromptConfig import System.IO import Text.Printf import XMonad import Internal.Submap import XMonad.Actions.WindowNavigation import XMonad.Prompt import XMonad.Prompt.Input import XMonad.Prompt.Shell import XMonad.Util.CustomKeys import XMonad.Util.Scratchpad import XMonad.Actions.RotSlaves import XMonad.Actions.CopyWindow as CopyWindow import XMonad.Actions.SpawnOn as SpawnOn import qualified Data.Map as Map import qualified XMonad.StackSet as W import Internal.Lib import Internal.DMenu import Internal.PassMenu type KeyMap l = XConfig l -> Map (KeyMask, KeySym) (X ()) type ButtonsMap l = XConfig l -> Map (KeyMask, Button) (Window -> X ()) keymap :: KeyMap l keymap = runKeys $ do config <- getConfig let subkeys = submap . flip runKeys config bind xK_apostrophe $ do justMod $ subkeys $ do bind xK_apostrophe $ (noMod -|- justMod) jumpToLast mapAlpha 0 jumpToMark shiftMod $ subkeys $ do bind xK_apostrophe $ (noMod -|- shiftMod -|- rawMask shiftMask) swapWithLastMark mapAlpha shiftMask swapWithMark bind xK_BackSpace $ do -- The only raw keybinding. Meant to get a terminal to unbrick XMonad if -- something goes wrong with the keyboard layout and for first-time boots -- where dmenu/alacritty may not be installed. rawMask mod4Mask $ spawn "xterm" justMod $ spawn "pkill -SIGUSR 1 xmobar" bind xK_F1 $ do -- Button programmed on mouse rawMask shiftMask $ click >> withFocused (windows . W.sink) shiftMod $ spawn "spotify-control play" bind xK_F2 $ -- Button programmed on mouse rawMask shiftMask $ click >> sendMessage ToggleZoom bind xK_F3 $ -- Button programmed on mouse rawMask shiftMask $ subkeys $ do bind xK_F1 $ -- Make it harder to close so I don't accidentally git it. rawMask shiftMask $ click >> CopyWindow.kill1 -- I Don't really use these, but they could be bound to something cool! bind xK_F2 $ rawMask shiftMask $ spawn "spotify-control next" bind xK_F3 $ rawMask shiftMask $ spawn "spotify-control prev" bind xK_F10 $ do justMod $ spawn "spotify-control play" bind xK_F11 $ do justMod $ spawn "spotify-control prev" bind xK_F12 $ do justMod $ spawn "spotify-control next" bind xK_Return $ do justMod swapMaster bind xK_Tab $ do justMod $ windows W.focusDown shiftMod $ windows W.focusUp -- Switch between different screens. These are the leftmost keys on the home -- row in a Dvorak layout. One might want to switch these to ASD for QWERTY. forM_ (zip [xK_a, xK_o, xK_e] [0..]) $ \(key, idx) -> bind key $ do -- Move focus to that screen. justMod $ withScreen W.view idx -- Swap the current screen with the one given altMod $ withScreen W.greedyView idx -- Move the current window to the select screen. shiftMod $ withScreen W.shift idx bind xK_bracketright $ do justMod $ sendMessage $ modifyWindowBorder 5 bind xK_bracketleft $ do justMod $ sendMessage $ modifyWindowBorder (-5) bind xK_b $ do justMod $ spawn "bluetooth-select.sh" bind xK_c $ do justMod runPassMenu shiftMod CopyWindow.kill1 bind xK_f $ do justMod $ sendMessage FlipLayout shiftMod $ sendMessage HFlipLayout bind xK_g $ do justMod $ mapNextString $ \_ str -> case str of [ch] | isAlphaNum ch -> gotoWorkspace ch [' '] -> gotoAccompaningWorkspace _ -> return () shiftMod $ mapNextString $ \_ str -> case str of [ch] | isAlphaNum ch -> shiftToWorkspace ch _ -> return () shiftAltMod $ mapNextString $ \_ str -> case str of [ch] | isAlphaNum ch -> swapWorkspace ch _ -> return () bind xK_h $ do justMod $ windows W.focusDown shiftMod $ windows W.swapDown controlMod rotAllDown bind xK_j $ do justMod $ sendMessage ShrinkZoom bind xK_k $ do justMod $ sendMessage ExpandZoom bind xK_l $ do justMod $ windows W.focusUp shiftMod $ windows W.swapUp controlMod rotAllUp altMod $ spawn "xsecurelock" bind xK_minus $ do justMod $ sendMessage (IncMasterN (-1)) shiftMod $ withFocused $ sendMessage . expandWindowAlt bind xK_m $ do justMod $ subkeys $ mapAlpha 0 markCurrentWindow bind xK_n $ do justMod $ relativeWorkspaceShift next bind xK_p $ do justMod $ relativeWorkspaceShift prev bind xK_plus $ do justMod $ sendMessage (IncMasterN 1) shiftMod $ withFocused $ sendMessage . expandWindowAlt bind xK_q $ do shiftMod $ spawn "xmonad --recompile && xmonad --restart" bind xK_r $ do justMod runDMenu shiftMod $ sendMessage DoRotate bind xK_s $ do altMod $ spawn "sudo -A systemctl suspend && xsecurelock" bind xK_space $ do justMod $ sendMessage NextLayout shiftMod $ sendMessage NextLayout bind xK_t $ do justMod $ spawn (terminal config) shiftMod $ withFocused $ windows . W.sink altMod $ spawn (terminal config ++ " -t Floating\\ Term") bind xK_w $ do justMod windowJump bind xK_x $ do justMod $ sendMessage ToggleStruts bind xK_z $ do justMod $ subkeys $ do bind xK_g $ do (justMod -|- noMod) $ mapNextString $ \_ s -> case s of [ch] | isAlphaNum ch -> windows (CopyWindow.copy s) _ -> return () bind xK_p $ do (justMod -|- noMod) $ mapNextString $ \_ str -> spawn $ printf "gxmessage 'typed: \"%s\"\ncodes: \"%s\"\nunicode: รก\n'" str (show (map ord str)) bind xK_c $ do shiftMod CopyWindow.killAllOtherCopies bind xK_e $ (justMod -|- noMod) $ spawn "emoji-select.sh" -- Double-tap Z to toggle zoom. bind xK_z $ do noMod -|- justMod $ sendMessage ToggleZoom -- Z is reserved to create sub keybindings to do various things. -- I don't really use these at the moment. bind xK_h $ do noMod $ spawn "spotify-control prev" bind xK_l $ do noMod $ spawn "spotify-control next" -- Centers the current focused window. i.e. toggles the Zoom layout -- modifier. shiftMod $ sendMessage ToggleZoom bind xF86XK_AudioLowerVolume $ do noMod $ spawn "pactl set-sink-volume @DEFAULT_SINK@ -1%" justMod $ spawn "spotify-control prev" bind xF86XK_AudioRaiseVolume $ do noMod $ spawn "pactl set-sink-volume @DEFAULT_SINK@ +1%" justMod $ spawn "spotify-control next" bind xF86XK_AudioMute $ do noMod $ spawn "pactl set-sink-mute @DEFAULT_SINK@ toggle" bind xF86XK_AudioPlay $ do noMod $ spawn "spotify-control play" bind xF86XK_AudioNext $ do noMod $ spawn "spotify-control next" bind xF86XK_AudioPrev $ do noMod $ spawn "spotify-control prev" bind xF86XK_AudioPrev $ do noMod $ spawn "spotify-control prev" mouseMap :: ButtonsMap l mouseMap = runButtons $ do bind button1 $ do justMod $ \w -> focus w >> mouseMoveWindow w >> windows W.shiftMaster bind button2 $ do justMod $ windows . (W.shiftMaster .) . W.focusWindow bind button3 $ do justMod $ \w -> focus w >> mouseResizeWindow w >> windows W.shiftMaster bind (6 :: Button) $ justMod $ const (relativeWorkspaceShift prev) bind (7 :: Button) $ justMod $ const (relativeWorkspaceShift next) bind (8 :: Button) $ justMod $ const $ spawn "spotify-control prev" bind (9 :: Button) $ justMod $ const $ spawn "spotify-control next" applyKeys :: XConfig l -> IO (XConfig l) applyKeys config = return $ config { keys = keymap, mouseBindings = mouseMap } click :: X () click = do (dpy, root) <- asks $ (,) <$> display <*> theRoot (_, _, window, _, _, _, _, _) <- io $ queryPointer dpy root focus window modifyWindowBorder :: Integer -> SpacingModifier modifyWindowBorder i = ModifyWindowBorder $ \(Border a b c d) -> Border (a + i) (b + i) (c + i) (d + i)