{-# LANGUAGE CPP #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ScopedTypeVariables #-}
module XMonad.Util.EZConfig (
additionalKeys, additionalKeysP,
remapKeysP,
removeKeys, removeKeysP,
additionalMouseBindings, removeMouseBindings,
mkKeymap, checkKeymap,
mkNamedKeymap,
parseKey,
parseKeyCombo,
parseKeySequence, readKeySequence,
#ifdef TESTING
parseModifier,
#endif
) where
import XMonad
import XMonad.Actions.Submap
import XMonad.Prelude
import XMonad.Util.NamedActions
import XMonad.Util.Parser
import Control.Arrow (first, (&&&))
import qualified Data.List.NonEmpty as NE
import qualified Data.Map as M
import Data.Ord (comparing)
import Data.List.NonEmpty (nonEmpty)
additionalKeys :: XConfig a -> [((KeyMask, KeySym), X ())] -> XConfig a
additionalKeys :: forall (a :: * -> *).
XConfig a -> [((KeyMask, KeySym), X ())] -> XConfig a
additionalKeys XConfig a
conf [((KeyMask, KeySym), X ())]
keyList =
XConfig a
conf { keys :: XConfig Layout -> Map (KeyMask, KeySym) (X ())
keys = forall k a. Ord k => Map k a -> Map k a -> Map k a
M.union (forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [((KeyMask, KeySym), X ())]
keyList) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (l :: * -> *).
XConfig l -> XConfig Layout -> Map (KeyMask, KeySym) (X ())
keys XConfig a
conf }
infixl 4 `additionalKeys`
additionalKeysP :: XConfig l -> [(String, X ())] -> XConfig l
additionalKeysP :: forall (l :: * -> *). XConfig l -> [(String, X ())] -> XConfig l
additionalKeysP XConfig l
conf [(String, X ())]
keyList =
XConfig l
conf { keys :: XConfig Layout -> Map (KeyMask, KeySym) (X ())
keys = \XConfig Layout
cnf -> forall k a. Ord k => Map k a -> Map k a -> Map k a
M.union (forall (l :: * -> *).
XConfig l -> [(String, X ())] -> Map (KeyMask, KeySym) (X ())
mkKeymap XConfig Layout
cnf [(String, X ())]
keyList) (forall (l :: * -> *).
XConfig l -> XConfig Layout -> Map (KeyMask, KeySym) (X ())
keys XConfig l
conf XConfig Layout
cnf) }
infixl 4 `additionalKeysP`
remapKeysP :: XConfig l -> [(String, String)] -> XConfig l
remapKeysP :: forall (l :: * -> *). XConfig l -> [(String, String)] -> XConfig l
remapKeysP XConfig l
conf [(String, String)]
keyList =
XConfig l
conf { keys :: XConfig Layout -> Map (KeyMask, KeySym) (X ())
keys = \XConfig Layout
cnf -> forall (l :: * -> *).
XConfig l -> [(String, X ())] -> Map (KeyMask, KeySym) (X ())
mkKeymap XConfig Layout
cnf (XConfig Layout -> [(String, X ())]
keyList' XConfig Layout
cnf) forall a. Semigroup a => a -> a -> a
<> forall (l :: * -> *).
XConfig l -> XConfig Layout -> Map (KeyMask, KeySym) (X ())
keys XConfig l
conf XConfig Layout
cnf }
where
keyList' :: XConfig Layout -> [(String, X ())]
keyList' :: XConfig Layout -> [(String, X ())]
keyList' XConfig Layout
cnf =
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (\String
s -> case forall (l :: * -> *).
XConfig l -> String -> Maybe (NonEmpty (KeyMask, KeySym))
readKeySequence XConfig Layout
cnf String
s of
Just ((KeyMask, KeySym)
ks :| []) -> forall (l :: * -> *).
XConfig l -> XConfig Layout -> Map (KeyMask, KeySym) (X ())
keys XConfig l
conf XConfig Layout
cnf forall k a. Ord k => Map k a -> k -> Maybe a
M.!? (KeyMask, KeySym)
ks
Maybe (NonEmpty (KeyMask, KeySym))
_ -> forall a. Maybe a
Nothing))
[(String, String)]
keyList
infixl 4 `remapKeysP`
removeKeys :: XConfig a -> [(KeyMask, KeySym)] -> XConfig a
removeKeys :: forall (a :: * -> *). XConfig a -> [(KeyMask, KeySym)] -> XConfig a
removeKeys XConfig a
conf [(KeyMask, KeySym)]
keyList =
XConfig a
conf { keys :: XConfig Layout -> Map (KeyMask, KeySym) (X ())
keys = \XConfig Layout
cnf -> forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr forall k a. Ord k => k -> Map k a -> Map k a
M.delete (forall (l :: * -> *).
XConfig l -> XConfig Layout -> Map (KeyMask, KeySym) (X ())
keys XConfig a
conf XConfig Layout
cnf) [(KeyMask, KeySym)]
keyList }
infixl 4 `removeKeys`
removeKeysP :: XConfig l -> [String] -> XConfig l
removeKeysP :: forall (l :: * -> *). XConfig l -> [String] -> XConfig l
removeKeysP XConfig l
conf [String]
keyList =
XConfig l
conf { keys :: XConfig Layout -> Map (KeyMask, KeySym) (X ())
keys = \XConfig Layout
cnf -> forall (l :: * -> *).
XConfig l -> XConfig Layout -> Map (KeyMask, KeySym) (X ())
keys XConfig l
conf XConfig Layout
cnf forall k a b. Ord k => Map k a -> Map k b -> Map k a
`M.difference` forall (l :: * -> *).
XConfig l -> [(String, X ())] -> Map (KeyMask, KeySym) (X ())
mkKeymap XConfig Layout
cnf (forall a b. (a -> b) -> [a] -> [b]
map (, forall (m :: * -> *) a. Monad m => a -> m a
return ()) [String]
keyList) }
infixl 4 `removeKeysP`
additionalMouseBindings :: XConfig a -> [((ButtonMask, Button), Window -> X ())] -> XConfig a
additionalMouseBindings :: forall (a :: * -> *).
XConfig a -> [((KeyMask, Button), KeySym -> X ())] -> XConfig a
additionalMouseBindings XConfig a
conf [((KeyMask, Button), KeySym -> X ())]
mouseBindingsList =
XConfig a
conf { mouseBindings :: XConfig Layout -> Map (KeyMask, Button) (KeySym -> X ())
mouseBindings = forall k a. Ord k => Map k a -> Map k a -> Map k a
M.union (forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [((KeyMask, Button), KeySym -> X ())]
mouseBindingsList) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (l :: * -> *).
XConfig l
-> XConfig Layout -> Map (KeyMask, Button) (KeySym -> X ())
mouseBindings XConfig a
conf }
infixl 4 `additionalMouseBindings`
removeMouseBindings :: XConfig a -> [(ButtonMask, Button)] -> XConfig a
removeMouseBindings :: forall (a :: * -> *). XConfig a -> [(KeyMask, Button)] -> XConfig a
removeMouseBindings XConfig a
conf [(KeyMask, Button)]
mouseBindingList =
XConfig a
conf { mouseBindings :: XConfig Layout -> Map (KeyMask, Button) (KeySym -> X ())
mouseBindings = \XConfig Layout
cnf -> forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr forall k a. Ord k => k -> Map k a -> Map k a
M.delete (forall (l :: * -> *).
XConfig l
-> XConfig Layout -> Map (KeyMask, Button) (KeySym -> X ())
mouseBindings XConfig a
conf XConfig Layout
cnf) [(KeyMask, Button)]
mouseBindingList }
infixl 4 `removeMouseBindings`
mkKeymap :: XConfig l -> [(String, X ())] -> M.Map (KeyMask, KeySym) (X ())
mkKeymap :: forall (l :: * -> *).
XConfig l -> [(String, X ())] -> Map (KeyMask, KeySym) (X ())
mkKeymap XConfig l
c = forall k a. Ord k => [(k, a)] -> Map k a
M.fromList forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(NonEmpty (KeyMask, KeySym), X ())] -> [((KeyMask, KeySym), X ())]
mkSubmaps forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (l :: * -> *) t.
XConfig l -> [(String, t)] -> [(NonEmpty (KeyMask, KeySym), t)]
readKeymap XConfig l
c
mkNamedKeymap :: XConfig l -> [(String, NamedAction)] -> [((KeyMask, KeySym), NamedAction)]
mkNamedKeymap :: forall (l :: * -> *).
XConfig l
-> [(String, NamedAction)] -> [((KeyMask, KeySym), NamedAction)]
mkNamedKeymap XConfig l
c = [(NonEmpty (KeyMask, KeySym), NamedAction)]
-> [((KeyMask, KeySym), NamedAction)]
mkNamedSubmaps forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (l :: * -> *) t.
XConfig l -> [(String, t)] -> [(NonEmpty (KeyMask, KeySym), t)]
readKeymap XConfig l
c
mkNamedSubmaps :: [(NonEmpty (KeyMask, KeySym), NamedAction)] -> [((KeyMask, KeySym), NamedAction)]
mkNamedSubmaps :: [(NonEmpty (KeyMask, KeySym), NamedAction)]
-> [((KeyMask, KeySym), NamedAction)]
mkNamedSubmaps = forall a b.
Ord a =>
([(a, b)] -> b) -> [(NonEmpty a, b)] -> [(a, b)]
mkSubmaps' forall a. HasName a => [((KeyMask, KeySym), a)] -> NamedAction
submapName
mkSubmaps :: [ (NonEmpty (KeyMask, KeySym), X ()) ] -> [((KeyMask, KeySym), X ())]
mkSubmaps :: [(NonEmpty (KeyMask, KeySym), X ())] -> [((KeyMask, KeySym), X ())]
mkSubmaps = forall a b.
Ord a =>
([(a, b)] -> b) -> [(NonEmpty a, b)] -> [(a, b)]
mkSubmaps' forall a b. (a -> b) -> a -> b
$ Map (KeyMask, KeySym) (X ()) -> X ()
submap forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a. Ord k => [(k, a)] -> Map k a
M.fromList
mkSubmaps' :: forall a b. (Ord a) => ([(a, b)] -> b) -> [(NonEmpty a, b)] -> [(a, b)]
mkSubmaps' :: forall a b.
Ord a =>
([(a, b)] -> b) -> [(NonEmpty a, b)] -> [(a, b)]
mkSubmaps' [(a, b)] -> b
subm [(NonEmpty a, b)]
binds = forall a b. (a -> b) -> [a] -> [b]
map [(NonEmpty a, b)] -> (a, b)
combine [[(NonEmpty a, b)]]
gathered
where
gathered :: [[(NonEmpty a, b)]]
gathered :: [[(NonEmpty a, b)]]
gathered = forall a. (a -> a -> Bool) -> [a] -> [[a]]
groupBy (NonEmpty a, b) -> (NonEmpty a, b) -> Bool
fstKey forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing forall a b. (a, b) -> a
fst) forall a b. (a -> b) -> a -> b
$ [(NonEmpty a, b)]
binds
combine :: [(NonEmpty a, b)] -> (a, b)
combine :: [(NonEmpty a, b)] -> (a, b)
combine [(a
k :| [], b
act)] = (a
k, b
act)
combine [(NonEmpty a, b)]
ks = ( forall a. NonEmpty a -> a
NE.head forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. NonEmpty a -> a
NE.head forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. HasCallStack => [a] -> NonEmpty a
notEmpty forall a b. (a -> b) -> a -> b
$ [(NonEmpty a, b)]
ks
, [(a, b)] -> b
subm forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b.
Ord a =>
([(a, b)] -> b) -> [(NonEmpty a, b)] -> [(a, b)]
mkSubmaps' [(a, b)] -> b
subm forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map (forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (forall a. HasCallStack => [a] -> NonEmpty a
notEmpty forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Int -> NonEmpty a -> [a]
NE.drop Int
1)) [(NonEmpty a, b)]
ks
)
fstKey :: (NonEmpty a, b) -> (NonEmpty a, b) -> Bool
fstKey :: (NonEmpty a, b) -> (NonEmpty a, b) -> Bool
fstKey = forall a. Eq a => a -> a -> Bool
(==) forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (forall a. NonEmpty a -> a
NE.head forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst)
readKeymap :: XConfig l -> [(String, t)] -> [(NonEmpty (KeyMask, KeySym), t)]
readKeymap :: forall (l :: * -> *) t.
XConfig l -> [(String, t)] -> [(NonEmpty (KeyMask, KeySym), t)]
readKeymap XConfig l
c = forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (forall {a} {b}. (Maybe a, b) -> Maybe (a, b)
maybeKeys forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (forall (l :: * -> *).
XConfig l -> String -> Maybe (NonEmpty (KeyMask, KeySym))
readKeySequence XConfig l
c))
where maybeKeys :: (Maybe a, b) -> Maybe (a, b)
maybeKeys (Maybe a
Nothing,b
_) = forall a. Maybe a
Nothing
maybeKeys (Just a
k, b
act) = forall a. a -> Maybe a
Just (a
k, b
act)
readKeySequence :: XConfig l -> String -> Maybe (NonEmpty (KeyMask, KeySym))
readKeySequence :: forall (l :: * -> *).
XConfig l -> String -> Maybe (NonEmpty (KeyMask, KeySym))
readKeySequence XConfig l
c = forall a. [a] -> Maybe (NonEmpty a)
nonEmpty forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< forall a. Parser a -> String -> Maybe a
runParser (forall (l :: * -> *). XConfig l -> Parser [(KeyMask, KeySym)]
parseKeySequence XConfig l
c forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ()
eof)
parseKeySequence :: XConfig l -> Parser [(KeyMask, KeySym)]
parseKeySequence :: forall (l :: * -> *). XConfig l -> Parser [(KeyMask, KeySym)]
parseKeySequence XConfig l
c = forall (l :: * -> *). XConfig l -> Parser (KeyMask, KeySym)
parseKeyCombo XConfig l
c forall a sep. Parser a -> Parser sep -> Parser [a]
`sepBy1` forall a. Parser a -> Parser [a]
many1 (Char -> Parser Char
char Char
' ')
parseKeyCombo :: XConfig l -> Parser (KeyMask, KeySym)
parseKeyCombo :: forall (l :: * -> *). XConfig l -> Parser (KeyMask, KeySym)
parseKeyCombo XConfig l
c = do [KeyMask]
mods <- forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (forall (l :: * -> *). XConfig l -> Parser KeyMask
parseModifier XConfig l
c)
KeySym
k <- Parser KeySym
parseKey
forall (m :: * -> *) a. Monad m => a -> m a
return (forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' forall a. Bits a => a -> a -> a
(.|.) KeyMask
0 [KeyMask]
mods, KeySym
k)
parseModifier :: XConfig l -> Parser KeyMask
parseModifier :: forall (l :: * -> *). XConfig l -> Parser KeyMask
parseModifier XConfig l
c = (String -> Parser String
string String
"M-" forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall (l :: * -> *). XConfig l -> KeyMask
modMask XConfig l
c)
forall a. Semigroup a => a -> a -> a
<> (String -> Parser String
string String
"C-" forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> KeyMask
controlMask)
forall a. Semigroup a => a -> a -> a
<> (String -> Parser String
string String
"S-" forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> KeyMask
shiftMask)
forall a. Semigroup a => a -> a -> a
<> do Char
_ <- Char -> Parser Char
char Char
'M'
Char
n <- (Char -> Bool) -> Parser Char
satisfy (forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char
'1'..Char
'5'])
Char
_ <- Char -> Parser Char
char Char
'-'
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Int -> KeyMask
indexMod (forall a. Read a => String -> a
read [Char
n] forall a. Num a => a -> a -> a
- Int
1)
where indexMod :: Int -> KeyMask
indexMod = forall a. [a] -> Int -> a
(!!) [KeyMask
mod1Mask,KeyMask
mod2Mask,KeyMask
mod3Mask,KeyMask
mod4Mask,KeyMask
mod5Mask]
parseKey :: Parser KeySym
parseKey :: Parser KeySym
parseKey = Parser KeySym
parseSpecial forall a. Semigroup a => a -> a -> a
<> Parser KeySym
parseRegular
parseRegular :: Parser KeySym
parseRegular :: Parser KeySym
parseRegular = forall a. [Parser a] -> Parser a
choice [ String -> Parser String
string String
s forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> KeySym
k | (String
s, KeySym
k) <- [(String, KeySym)]
regularKeys ]
parseSpecial :: Parser KeySym
parseSpecial :: Parser KeySym
parseSpecial = do Char
_ <- Char -> Parser Char
char Char
'<'
forall a. [Parser a] -> Parser a
choice [ KeySym
k forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ String -> Parser String
string String
name forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> Parser Char
char Char
'>'
| (String
name, KeySym
k) <- [(String, KeySym)]
allSpecialKeys
]
checkKeymap :: XConfig l -> [(String, a)] -> X ()
checkKeymap :: forall (l :: * -> *) a. XConfig l -> [(String, a)] -> X ()
checkKeymap XConfig l
conf [(String, a)]
km = forall {m :: * -> *}. MonadIO m => ([String], [String]) -> m ()
warn (forall (l :: * -> *) a.
XConfig l -> [(String, a)] -> ([String], [String])
doKeymapCheck XConfig l
conf [(String, a)]
km)
where warn :: ([String], [String]) -> m ()
warn ([],[]) = forall (m :: * -> *) a. Monad m => a -> m a
return ()
warn ([String]
bad,[String]
dup) = forall (m :: * -> *). MonadIO m => String -> m ()
xmessage forall a b. (a -> b) -> a -> b
$ String
"Warning:\n"
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
msg String
"bad" [String]
bad forall a. [a] -> [a] -> [a]
++ String
"\n"
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
msg String
"duplicate" [String]
dup
msg :: String -> [String] -> String
msg String
_ [] = String
""
msg String
m [String]
xs = String
m forall a. [a] -> [a] -> [a]
++ String
" keybindings detected: " forall a. [a] -> [a] -> [a]
++ [String] -> String
showBindings [String]
xs
showBindings :: [String] -> String
showBindings = [String] -> String
unwords forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map ((String
"\""forall a. [a] -> [a] -> [a]
++) forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. [a] -> [a] -> [a]
++String
"\""))
doKeymapCheck :: XConfig l -> [(String,a)] -> ([String], [String])
doKeymapCheck :: forall (l :: * -> *) a.
XConfig l -> [(String, a)] -> ([String], [String])
doKeymapCheck XConfig l
conf [(String, a)]
km = ([String]
bad,[String]
dups)
where ks :: [(Maybe (NonEmpty (KeyMask, KeySym)), String)]
ks = forall a b. (a -> b) -> [a] -> [b]
map ((forall (l :: * -> *).
XConfig l -> String -> Maybe (NonEmpty (KeyMask, KeySym))
readKeySequence XConfig l
conf forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& forall a. a -> a
id) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) [(String, a)]
km
bad :: [String]
bad = forall a. Eq a => [a] -> [a]
nub forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
filter (forall a. Maybe a -> Bool
isNothing forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) forall a b. (a -> b) -> a -> b
$ [(Maybe (NonEmpty (KeyMask, KeySym)), String)]
ks
dups :: [String]
dups = forall a b. (a -> b) -> [a] -> [b]
map (forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. NonEmpty a -> a
NE.head)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe forall a. [a] -> Maybe (NonEmpty a)
nonEmpty
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> a -> Bool) -> [a] -> [[a]]
groupBy (forall a. Eq a => a -> a -> Bool
(==) forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` forall a b. (a, b) -> a
fst)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing forall a b. (a, b) -> a
fst)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first forall a. HasCallStack => Maybe a -> a
fromJust)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
filter (forall a. Maybe a -> Bool
isJust forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst)
forall a b. (a -> b) -> a -> b
$ [(Maybe (NonEmpty (KeyMask, KeySym)), String)]
ks