{-# LANGUAGE DeriveAnyClass, CPP #-}
{-|
Module      : KMonad.Keyboard.Keycode
Description : Description of all possible keycodes.
Copyright   : (c) David Janssen, 2019
License     : MIT
Maintainer  : janssen.dhj@gmail.com
Stability   : experimental
Portability : portable

'Keycode's are represented as a large enum lining up the keycodes defined in the Linux headers.

-}
module KMonad.Keyboard.Keycode
  ( -- * The core Keycode type
    -- $typ
    Keycode(..)

    -- * Naming utilities to refer to Keycodes
    -- $names
  , keyNames

  )
where

import KMonad.Prelude

import qualified Data.MultiMap     as Q
import qualified RIO.HashSet       as S
import qualified RIO.Text          as T
import qualified RIO.Text.Partial  as T (head)

--------------------------------------------------------------------------------
-- $typ
--
-- 'Keycode's are defined as a large ADT that mimics the keycodes from the Linux
-- headers:
-- https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h.
--
-- Anywhere there are missing regions in the linux headers, we've defined
-- @MissingXX@ values for the ADT.
--
-- Calling 'RIO.Partial.toEnum' on a Linux keycode value should produce the
-- corresponding 'Keycode' value and vice-versa.

-- | The 'Keycode' datatype, as an 'Enum' of all the values a 'Keycode' can take.
data Keycode
  = KeyReserved
  | KeyEsc
  | Key1
  | Key2
  | Key3
  | Key4
  | Key5
  | Key6
  | Key7
  | Key8
  | Key9
  | Key0
  | KeyMinus
  | KeyEqual
  | KeyBackspace
  | KeyTab
  | KeyQ
  | KeyW
  | KeyE
  | KeyR
  | KeyT
  | KeyY
  | KeyU
  | KeyI
  | KeyO
  | KeyP
  | KeyLeftBrace
  | KeyRightBrace
  | KeyEnter
  | KeyLeftCtrl
  | KeyA
  | KeyS
  | KeyD
  | KeyF
  | KeyG
  | KeyH
  | KeyJ
  | KeyK
  | KeyL
  | KeySemicolon
  | KeyApostrophe
  | KeyGrave
  | KeyLeftShift
  | KeyBackslash
  | KeyZ
  | KeyX
  | KeyC
  | KeyV
  | KeyB
  | KeyN
  | KeyM
  | KeyComma
  | KeyDot
  | KeySlash
  | KeyRightShift
  | KeyKpAsterisk
  | KeyLeftAlt
  | KeySpace
  | KeyCapsLock
  | KeyF1
  | KeyF2
  | KeyF3
  | KeyF4
  | KeyF5
  | KeyF6
  | KeyF7
  | KeyF8
  | KeyF9
  | KeyF10
  | KeyNumLock
  | KeyScrollLock
  | KeyKp7
  | KeyKp8
  | KeyKp9
  | KeyKpMinus
  | KeyKp4
  | KeyKp5
  | KeyKp6
  | KeyKpPlus
  | KeyKp1
  | KeyKp2
  | KeyKp3
  | KeyKp0
  | KeyKpDot
  | Missing84
  | KeyZenkakuHankaku
  | Key102nd
  | KeyF11
  | KeyF12
  | KeyRo
  | KeyKatakana
  | KeyHiragana
  | KeyHenkan
  | KeyKatakanaHiragana
  | KeyMuhenkan
  | KeyKpjpcomma
  | KeyKpEnter
  | KeyRightCtrl
  | KeyKpSlash
  | KeySysRq
  | KeyRightAlt
  | KeyLinefeed
  | KeyHome
  | KeyUp
  | KeyPageUp
  | KeyLeft
  | KeyRight
  | KeyEnd
  | KeyDown
  | KeyPageDown
  | KeyInsert
  | KeyDelete
  | KeyMacro
  | KeyMute
  | KeyVolumeDown
  | KeyVolumeUp
  | KeyPower
  | KeyKpEqual
  | KeyKpPlusMinus
  | KeyPause
  | KeyScale
  | KeyKpComma
  | KeyHangeul
  | KeyHanja
  | KeyYen
  | KeyLeftMeta
  | KeyRightMeta
  | KeyCompose
  | KeyStop
  | KeyAgain
  | KeyProps
  | KeyUndo
  | KeyFront
  | KeyCopy
  | KeyOpen
  | KeyPaste
  | KeyFind
  | KeyCut
  | KeyHelp
  | KeyMenu
  | KeyCalc
  | KeySetup
  | KeySleep
  | KeyWakeUp
  | KeyFile
  | KeySendFile
  | KeyDeleteFile
  | KeyXfer
  | KeyProg1
  | KeyProg2
  | KeyWww
  | KeyMsDos
  | KeyCoffee
  | KeyDirection
  | KeyCycleWindows
  | KeyMail
  | KeyBookmarks
  | KeyComputer
  | KeyBack
  | KeyForward
  | KeyCloseCd
  | KeyEjectCd
  | KeyEjectCloseCd
  | KeyNextSong
  | KeyPlayPause
  | KeyPreviousSong
  | KeyStopCd
  | KeyRecord
  | KeyRewind
  | KeyPhone
  | KeyIso
  | KeyConfig
  | KeyHomepage
  | KeyRefresh
  | KeyExit
  | KeyMove
  | KeyEdit
  | KeyScrollUp
  | KeyScrollDown
  | KeyKpLeftParen
  | KeyKpRightParen
  | KeyNew
  | KeyRedo
  | KeyF13
  | KeyF14
  | KeyF15
  | KeyF16
  | KeyF17
  | KeyF18
  | KeyF19
  | KeyF20
  | KeyF21
  | KeyF22
  | KeyF23
  | KeyF24
  | Missing195
  | Missing196
  | Missing197
  | Missing198
  | Missing199
  | KeyPlayCd
  | KeyPauseCd
  | KeyProg3
  | KeyProg4
  | KeyDashboard
  | KeySuspend
  | KeyClose
  | KeyPlay
  | KeyFastForward
  | KeyBassBoost
  | KeyPrint
  | KeyHp
  | KeyCamera
  | KeySound
  | KeyQuestion
  | KeyEmail
  | KeyChat
  | KeySearch
  | KeyConnect
  | KeyFinance
  | KeySport
  | KeyShop
  | KeyAlterase
  | KeyCancel
  | KeyBrightnessDown
  | KeyBrightnessUp
  | KeyMedia
  | KeySwitchVideoMode
  | KeyKbdIllumToggle
  | KeyKbdIllumDown
  | KeyKbdIllumUp
  | KeySend
  | KeyReply
  | KeyForwardMail
  | KeySave
  | KeyDocuments
  | KeyBattery
  | KeyBluetooth
  | KeyWlan
  | KeyUwb
  | KeyUnknown
  | KeyVideoNext
  | KeyVideoPrev
  | KeyBrightnessCycle
  | KeyBrightnessZero
  | KeyDisplayOff
  | KeyWimax
  | Missing247
  | Missing248
  | Missing249
  | Missing250
  | Missing251
  | Missing252
  | Missing253
  | Missing254
  | Missing255
#ifdef darwin_HOST_OS
  | KeyFn
  | KeyLaunchpad
  | KeyMissionCtrl
  | KeyBacklightDown
  | KeyBacklightUp
  | KeyError
#endif
  deriving (Keycode -> Keycode -> Bool
(Keycode -> Keycode -> Bool)
-> (Keycode -> Keycode -> Bool) -> Eq Keycode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Keycode -> Keycode -> Bool
$c/= :: Keycode -> Keycode -> Bool
== :: Keycode -> Keycode -> Bool
$c== :: Keycode -> Keycode -> Bool
Eq, Int -> Keycode -> ShowS
[Keycode] -> ShowS
Keycode -> String
(Int -> Keycode -> ShowS)
-> (Keycode -> String) -> ([Keycode] -> ShowS) -> Show Keycode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Keycode] -> ShowS
$cshowList :: [Keycode] -> ShowS
show :: Keycode -> String
$cshow :: Keycode -> String
showsPrec :: Int -> Keycode -> ShowS
$cshowsPrec :: Int -> Keycode -> ShowS
Show, Keycode
Keycode -> Keycode -> Bounded Keycode
forall a. a -> a -> Bounded a
maxBound :: Keycode
$cmaxBound :: Keycode
minBound :: Keycode
$cminBound :: Keycode
Bounded, Int -> Keycode
Keycode -> Int
Keycode -> [Keycode]
Keycode -> Keycode
Keycode -> Keycode -> [Keycode]
Keycode -> Keycode -> Keycode -> [Keycode]
(Keycode -> Keycode)
-> (Keycode -> Keycode)
-> (Int -> Keycode)
-> (Keycode -> Int)
-> (Keycode -> [Keycode])
-> (Keycode -> Keycode -> [Keycode])
-> (Keycode -> Keycode -> [Keycode])
-> (Keycode -> Keycode -> Keycode -> [Keycode])
-> Enum Keycode
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Keycode -> Keycode -> Keycode -> [Keycode]
$cenumFromThenTo :: Keycode -> Keycode -> Keycode -> [Keycode]
enumFromTo :: Keycode -> Keycode -> [Keycode]
$cenumFromTo :: Keycode -> Keycode -> [Keycode]
enumFromThen :: Keycode -> Keycode -> [Keycode]
$cenumFromThen :: Keycode -> Keycode -> [Keycode]
enumFrom :: Keycode -> [Keycode]
$cenumFrom :: Keycode -> [Keycode]
fromEnum :: Keycode -> Int
$cfromEnum :: Keycode -> Int
toEnum :: Int -> Keycode
$ctoEnum :: Int -> Keycode
pred :: Keycode -> Keycode
$cpred :: Keycode -> Keycode
succ :: Keycode -> Keycode
$csucc :: Keycode -> Keycode
Enum, Eq Keycode
Eq Keycode =>
(Keycode -> Keycode -> Ordering)
-> (Keycode -> Keycode -> Bool)
-> (Keycode -> Keycode -> Bool)
-> (Keycode -> Keycode -> Bool)
-> (Keycode -> Keycode -> Bool)
-> (Keycode -> Keycode -> Keycode)
-> (Keycode -> Keycode -> Keycode)
-> Ord Keycode
Keycode -> Keycode -> Bool
Keycode -> Keycode -> Ordering
Keycode -> Keycode -> Keycode
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Keycode -> Keycode -> Keycode
$cmin :: Keycode -> Keycode -> Keycode
max :: Keycode -> Keycode -> Keycode
$cmax :: Keycode -> Keycode -> Keycode
>= :: Keycode -> Keycode -> Bool
$c>= :: Keycode -> Keycode -> Bool
> :: Keycode -> Keycode -> Bool
$c> :: Keycode -> Keycode -> Bool
<= :: Keycode -> Keycode -> Bool
$c<= :: Keycode -> Keycode -> Bool
< :: Keycode -> Keycode -> Bool
$c< :: Keycode -> Keycode -> Bool
compare :: Keycode -> Keycode -> Ordering
$ccompare :: Keycode -> Keycode -> Ordering
$cp1Ord :: Eq Keycode
Ord, (forall x. Keycode -> Rep Keycode x)
-> (forall x. Rep Keycode x -> Keycode) -> Generic Keycode
forall x. Rep Keycode x -> Keycode
forall x. Keycode -> Rep Keycode x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Keycode x -> Keycode
$cfrom :: forall x. Keycode -> Rep Keycode x
Generic, Int -> Keycode -> Int
Keycode -> Int
(Int -> Keycode -> Int) -> (Keycode -> Int) -> Hashable Keycode
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: Keycode -> Int
$chash :: Keycode -> Int
hashWithSalt :: Int -> Keycode -> Int
$chashWithSalt :: Int -> Keycode -> Int
Hashable)


instance Display Keycode where
  textDisplay :: Keycode -> Text
textDisplay c :: Keycode
c = (\t :: Text
t -> "<" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
t Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ">") (Text -> Text) -> (Maybe Text -> Text) -> Maybe Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe (Keycode -> Text
forall a. Show a => a -> Text
tshow Keycode
c)
    (Maybe Text -> Text) -> Maybe Text -> Text
forall a b. (a -> b) -> a -> b
$ Getting (Endo (Endo (Maybe Text))) (Maybe (HashSet Text)) Text
-> (Text -> Text -> Ordering) -> Maybe (HashSet Text) -> Maybe Text
forall a s.
Getting (Endo (Endo (Maybe a))) s a
-> (a -> a -> Ordering) -> s -> Maybe a
minimumByOf ((HashSet Text -> Const (Endo (Endo (Maybe Text))) (HashSet Text))
-> Maybe (HashSet Text)
-> Const (Endo (Endo (Maybe Text))) (Maybe (HashSet Text))
forall a b. Prism (Maybe a) (Maybe b) a b
_Just ((HashSet Text -> Const (Endo (Endo (Maybe Text))) (HashSet Text))
 -> Maybe (HashSet Text)
 -> Const (Endo (Endo (Maybe Text))) (Maybe (HashSet Text)))
-> ((Text -> Const (Endo (Endo (Maybe Text))) Text)
    -> HashSet Text -> Const (Endo (Endo (Maybe Text))) (HashSet Text))
-> Getting (Endo (Endo (Maybe Text))) (Maybe (HashSet Text)) Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Const (Endo (Endo (Maybe Text))) Text)
-> HashSet Text -> Const (Endo (Endo (Maybe Text))) (HashSet Text)
forall (f :: * -> *) a. Foldable f => IndexedFold Int (f a) a
folded) Text -> Text -> Ordering
cmpName (MultiMap Keycode Text
keyNames MultiMap Keycode Text
-> Getting
     (Maybe (HashSet Text))
     (MultiMap Keycode Text)
     (Maybe (HashSet Text))
-> Maybe (HashSet Text)
forall s a. s -> Getting a s a -> a
^. Index (MultiMap Keycode Text)
-> Lens'
     (MultiMap Keycode Text) (Maybe (IxValue (MultiMap Keycode Text)))
forall m. At m => Index m -> Lens' m (Maybe (IxValue m))
at Index (MultiMap Keycode Text)
Keycode
c)
    where cmpName :: Text -> Text -> Ordering
cmpName a :: Text
a b :: Text
b =
            -- Prefer the shortest, and if equal, lowercased version
            case Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Text -> Int
T.length Text
a) (Text -> Int
T.length Text
b) of
              EQ -> Char -> Char -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Text -> Char
T.head Text
b) (Text -> Char
T.head Text
a)
              o :: Ordering
o  -> Ordering
o

--------------------------------------------------------------------------------
-- $sets

-- | The set of all existing 'Keycode'
kcAll :: S.HashSet Keycode
kcAll :: HashSet Keycode
kcAll = [Keycode] -> HashSet Keycode
forall a. (Eq a, Hashable a) => [a] -> HashSet a
S.fromList ([Keycode] -> HashSet Keycode) -> [Keycode] -> HashSet Keycode
forall a b. (a -> b) -> a -> b
$ [Keycode
forall a. Bounded a => a
minBound .. Keycode
forall a. Bounded a => a
maxBound]

-- | The set of all 'Keycode' that are not of the MissingXX pattern
kcNotMissing :: S.HashSet Keycode
kcNotMissing :: HashSet Keycode
kcNotMissing = [Keycode] -> HashSet Keycode
forall a. (Eq a, Hashable a) => [a] -> HashSet a
S.fromList ([Keycode] -> HashSet Keycode) -> [Keycode] -> HashSet Keycode
forall a b. (a -> b) -> a -> b
$ HashSet Keycode
kcAll HashSet Keycode
-> Getting (Endo [Keycode]) (HashSet Keycode) Keycode -> [Keycode]
forall s a. s -> Getting (Endo [a]) s a -> [a]
^.. Getting (Endo [Keycode]) (HashSet Keycode) Keycode
forall (f :: * -> *) a. Foldable f => IndexedFold Int (f a) a
folded Getting (Endo [Keycode]) (HashSet Keycode) Keycode
-> ((Keycode -> Const (Endo [Keycode]) Keycode)
    -> Keycode -> Const (Endo [Keycode]) Keycode)
-> Getting (Endo [Keycode]) (HashSet Keycode) Keycode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Keycode -> Bool)
-> (Keycode -> Const (Endo [Keycode]) Keycode)
-> Keycode
-> Const (Endo [Keycode]) Keycode
forall (p :: * -> * -> *) (f :: * -> *) a.
(Choice p, Applicative f) =>
(a -> Bool) -> Optic' p f a a
filtered (Text -> Text -> Bool
T.isPrefixOf "Key" (Text -> Bool) -> (Keycode -> Text) -> Keycode -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Keycode -> Text
forall a. Show a => a -> Text
tshow)

--------------------------------------------------------------------------------
-- $names

-- | Helper function to generate easy name maps
nameKC :: Foldable t
  => (Keycode -> Text)
  -> t Keycode
  -> Q.MultiMap Keycode Text
nameKC :: (Keycode -> Text) -> t Keycode -> MultiMap Keycode Text
nameKC f :: Keycode -> Text
f = [(Keycode, [Text])] -> MultiMap Keycode Text
forall (t1 :: * -> *) (t2 :: * -> *) k v.
(Foldable t1, Foldable t2, CanMM k v) =>
t1 (k, t2 v) -> MultiMap k v
Q.mkMultiMap ([(Keycode, [Text])] -> MultiMap Keycode Text)
-> (t Keycode -> [(Keycode, [Text])])
-> t Keycode
-> MultiMap Keycode Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Keycode -> (Keycode, [Text])) -> [Keycode] -> [(Keycode, [Text])]
forall a b. (a -> b) -> [a] -> [b]
map Keycode -> (Keycode, [Text])
go ([Keycode] -> [(Keycode, [Text])])
-> (t Keycode -> [Keycode]) -> t Keycode -> [(Keycode, [Text])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t Keycode -> [Keycode]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList
  where go :: Keycode -> (Keycode, [Text])
go k :: Keycode
k = (Keycode
k, [Keycode -> Text
f Keycode
k, Text -> Text
T.toLower (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Keycode -> Text
f Keycode
k])

-- | A collection of 'Keycode' to 'Text' mappings
keyNames :: Q.MultiMap Keycode Text
keyNames :: MultiMap Keycode Text
keyNames = [MultiMap Keycode Text] -> MultiMap Keycode Text
forall a. Monoid a => [a] -> a
mconcat
  [ (Keycode -> Text) -> HashSet Keycode -> MultiMap Keycode Text
forall (t :: * -> *).
Foldable t =>
(Keycode -> Text) -> t Keycode -> MultiMap Keycode Text
nameKC Keycode -> Text
forall a. Show a => a -> Text
tshow               HashSet Keycode
kcAll
  , (Keycode -> Text) -> HashSet Keycode -> MultiMap Keycode Text
forall (t :: * -> *).
Foldable t =>
(Keycode -> Text) -> t Keycode -> MultiMap Keycode Text
nameKC (Int -> Text -> Text
T.drop 3 (Text -> Text) -> (Keycode -> Text) -> Keycode -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Keycode -> Text
forall a. Show a => a -> Text
tshow)  HashSet Keycode
kcNotMissing
  , MultiMap Keycode Text
aliases
  ]

-- | A collection of useful aliases to refer to keycode names
aliases :: Q.MultiMap Keycode Text
aliases :: MultiMap Keycode Text
aliases = [(Keycode, [Text])] -> MultiMap Keycode Text
forall (t1 :: * -> *) (t2 :: * -> *) k v.
(Foldable t1, Foldable t2, CanMM k v) =>
t1 (k, t2 v) -> MultiMap k v
Q.mkMultiMap
  [ (Keycode
KeyEnter,          ["ret", "return", "ent"])
  , (Keycode
KeyMinus,          ["min", "-"])
  , (Keycode
KeyEqual,          ["eql", "="])
  , (Keycode
KeySleep,          ["zzz"])
  , (Keycode
KeySpace,          ["spc"])
  , (Keycode
KeyPageUp,         ["pgup"])
  , (Keycode
KeyPageDown,       ["pgdn"])
  , (Keycode
KeyInsert,         ["ins"])
  , (Keycode
KeyDelete,         ["del"])
  , (Keycode
KeyVolumeUp,       ["volu"])
  , (Keycode
KeyVolumeDown,     ["voldwn", "vold"])
  , (Keycode
KeyBrightnessUp,   ["brup", "bru"])
  , (Keycode
KeyBrightnessDown, ["brdown", "brdwn", "brdn"])
  , (Keycode
KeyLeftAlt,        ["lalt", "alt"])
  , (Keycode
KeyRightAlt,       ["ralt"])
  , (Keycode
KeyCompose,        ["comp", "cmps", "cmp"])
  , (Keycode
KeyLeftShift,      ["lshift", "lshft", "lsft", "shft", "sft"])
  , (Keycode
KeyRightShift,     ["rshift", "rshft", "rsft"])
  , (Keycode
KeyLeftCtrl,       ["lctrl", "lctl", "ctl"])
  , (Keycode
KeyRightCtrl,      ["rctrl", "rctl"])
  , (Keycode
KeyLeftMeta,       ["lmeta", "lmet", "met"])
  , (Keycode
KeyRightMeta,      ["rmeta", "rmet"])
  , (Keycode
KeyBackspace,      ["bks", "bspc"])
  , (Keycode
KeyCapsLock,       ["caps"])
  , (Keycode
KeyGrave,          ["grv"])
  , (Keycode
Key102nd,          ["102d"])
  , (Keycode
KeyForward,        ["fwd"])
  , (Keycode
KeyScrollLock,     ["scrlck", "slck"])
  , (Keycode
KeyPrint,          ["prnt"])
  , (Keycode
KeyWakeUp,         ["wkup"])
  , (Keycode
KeyLeft,           ["lft"])
  , (Keycode
KeyRight,          ["rght"])
  , (Keycode
KeyLeftBrace,      ["lbrc", "["])
  , (Keycode
KeyRightBrace,     ["rbrc", "]"])
  , (Keycode
KeySemicolon,      ["scln", ";"])
  , (Keycode
KeyApostrophe,     ["apos", "'"])
  , (Keycode
KeyGrave,          ["grv", "`"])
  , (Keycode
KeyBackslash,      ["bksl", "\\"]) -- NOTE: "\\" here is a 1char string, the first \ is consumed by Haskell as an escape character
  , (Keycode
KeyComma,          ["comm", ","])
  , (Keycode
KeyDot,            ["."])
  , (Keycode
KeySlash,          ["/"])
  , (Keycode
KeyNumLock,        ["nlck"])
  , (Keycode
KeyKpSlash,        ["kp/"])
  , (Keycode
KeyKpEnter,        ["kprt"])
  , (Keycode
KeyKpPlus,         ["kp+"])
  , (Keycode
KeyKpAsterisk,     ["kp*"])
  , (Keycode
KeyKpMinus,        ["kp-"])
  , (Keycode
KeyKpDot,          ["kp."])
  , (Keycode
KeySysRq,          ["ssrq", "sys"])
#ifdef darwin_HOST_OS
  , (KeyLaunchpad,      ["lp"])
  , (KeyMissionCtrl,    ["mctl"])
  , (KeyBacklightDown,  ["bldn"])
  , (KeyBacklightUp,    ["blup"])
#endif
  ]