Allure-0.4.1: src/Keys.hs
module Keys where
import Prelude hiding (Left, Right)
import Geometry hiding (Up, Down)
import Data.Maybe
import Data.List as L
import Data.Map as M
-- | Library-independent datatype to represent keys.
data Key =
Esc
| Return
| Tab
| PgUp
| PgDn
| Left
| Right
| Up
| Down
| End
| Begin
| Home
| KP Char -- ^ a keypad key for a character (digits and operators)
| Char Char -- ^ a single printable character
| Unknown String -- ^ an unknown key, collected to warn the user later
deriving (Ord, Eq)
showKey :: Key -> String
showKey (Char ' ') = "<space>" -- warnings about "command ( )" look wrong
showKey (Char c) = [c]
showKey Esc = "ESC" -- these three are common and terse abbreviations
showKey Return = "RET"
showKey Tab = "TAB"
showKey PgUp = "<page-up>"
showKey PgDn = "<page-down>"
showKey Left = "<left>"
showKey Right = "<right>"
showKey Up = "<up>"
showKey Down = "<down>"
showKey End = "<end>"
showKey Begin = "<begin>"
showKey Home = "<home>"
showKey (KP c) = "<KeyPad " ++ [c] ++ ">"
showKey (Unknown s) = s
instance Show Key where
show = showKey
-- | Maps a keypad movement key to the canonical form.
-- Hard-coded not to bloat config files.
canonMoveKey :: Key -> Key
canonMoveKey e =
case e of
KP '8' -> Char 'K'
KP '2' -> Char 'J'
KP '4' -> Char 'H'
KP '6' -> Char 'L'
KP '7' -> Char 'Y'
KP '9' -> Char 'U'
KP '1' -> Char 'B'
KP '3' -> Char 'N'
KP '5' -> Char '.'
Up -> Char 'k'
Down -> Char 'j'
Left -> Char 'h'
Right -> Char 'l'
Home -> Char 'y'
PgUp -> Char 'u'
End -> Char 'b'
PgDn -> Char 'n'
Begin -> Char '.'
k -> k
-- | Configurable event handler for the direction keys. Is used to
-- handle player moves, but can also be used for directed commands
-- such as open/close.
handleDirection :: Key -> (Dir -> a) -> a -> a
handleDirection e h k =
case e of
Char 'k' -> h up
Char 'j' -> h down
Char 'h' -> h left
Char 'l' -> h right
Char 'y' -> h upleft
Char 'u' -> h upright
Char 'b' -> h downleft
Char 'n' -> h downright
_ -> k
-- | Configurable event handler for the upper direction keys. Is used to
-- handle player moves, but can also be used for directed commands
-- such as open/close.
handleUDirection :: Key -> (Dir -> a) -> a -> a
handleUDirection e h k =
case e of
Char 'K' -> h up
Char 'J' -> h down
Char 'H' -> h left
Char 'L' -> h right
Char 'Y' -> h upleft
Char 'U' -> h upright
Char 'B' -> h downleft
Char 'N' -> h downright
_ -> k
-- | Translate key from a GTK string description to our internal key type.
-- To be used, in particular, for the macros in the config file.
keyTranslate :: String -> Key
keyTranslate "less" = Char '<'
keyTranslate "greater" = Char '>'
keyTranslate "period" = Char '.'
keyTranslate "colon" = Char ':'
keyTranslate "comma" = Char ','
keyTranslate "space" = Char ' '
keyTranslate "question" = Char '?'
keyTranslate "dollar" = Char '$'
keyTranslate "asterisk" = Char '*'
keyTranslate "KP_Multiply" = Char '*'
keyTranslate "slash" = Char '/'
keyTranslate "KP_Divide" = Char '/'
keyTranslate "underscore" = Char '_'
keyTranslate "minus" = Char '-'
keyTranslate "KP_Subtract" = Char '-'
keyTranslate "Escape" = Esc
keyTranslate "Return" = Return
keyTranslate "Tab" = Tab
keyTranslate "KP_Up" = Up
keyTranslate "KP_Down" = Down
keyTranslate "KP_Left" = Left
keyTranslate "KP_Right" = Right
keyTranslate "KP_Home" = Home
keyTranslate "KP_End" = End
keyTranslate "KP_Page_Up" = PgUp
keyTranslate "KP_Page_Down" = PgDn
keyTranslate "KP_Begin" = Begin
keyTranslate "KP_Enter" = Return
keyTranslate ['K','P','_',c] = KP c
keyTranslate [c] = Char c
keyTranslate s = Unknown s
-- | Maps a key to the canonical key for the command it denotes.
-- Takes into account the keypad and any macros from a config file.
-- Macros cannot depend on each other, but they can on canonMoveKey.
-- This has to be fully evaluated to catch errors in macro definitions early.
macroKey :: [(String, String)] -> M.Map Key Key
macroKey section =
let trans k = case keyTranslate k of
Unknown s -> error $ "unknown macro key " ++ s
kt -> kt
trMacro (from, to) = let fromTr = trans from
!toTr = canonMoveKey $ trans to
in if fromTr == toTr
then error $ "degenerate alias for " ++ show toTr
else (fromTr, toTr)
in M.fromList $ L.map trMacro section