module System.Terminal.Decoder where

import           Data.Char
import           Data.Monoid                  ((<>))

import           System.Terminal.MonadInput
import           System.Terminal.MonadScreen (Position (..))

-- | The type `Decoder` is a finite state transducer.

--

--   Intermediate state can be passed as closure.

--   See below for an example.

newtype Decoder = Decoder { Decoder -> Modifiers -> Char -> Either Decoder [Event]
feedDecoder :: Modifiers -> Char -> Either Decoder [Event] }

defaultDecoder :: (Modifiers -> Char -> Maybe Event) -> Decoder
defaultDecoder :: (Modifiers -> Char -> Maybe Event) -> Decoder
defaultDecoder Modifiers -> Char -> Maybe Event
specialChar = Decoder
defaultMode
  where
    -- The default mode is the decoder's entry point.

    defaultMode :: Decoder
    defaultMode :: Decoder
defaultMode  = (Modifiers -> Char -> Either Decoder [Event]) -> Decoder
Decoder ((Modifiers -> Char -> Either Decoder [Event]) -> Decoder)
-> (Modifiers -> Char -> Either Decoder [Event]) -> Decoder
forall a b. (a -> b) -> a -> b
$ \Modifiers
mods Char
c-> if
        -- In normal mode a NUL is interpreted as a fill character and skipped.

        | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\NUL' -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right []
        -- ESC might or might not introduce an escape sequence.

        | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\ESC' -> Decoder -> Either Decoder [Event]
forall a b. a -> Either a b
Left Decoder
escapeMode
        -- All other C0 control codes are mapped to their corresponding ASCII character + CTRL modifier.

        -- If the character is a special character, then two events are produced.

        | Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\US'  -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right ([Event] -> Either Decoder [Event])
-> [Event] -> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ [Key -> Modifiers -> Event
KeyEvent (Char -> Key
CharKey (Int -> Char
forall a. Enum a => Int -> a
toEnum (Int -> Char) -> Int -> Char
forall a b. (a -> b) -> a -> b
$ (Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
64) (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Char -> Int
forall a. Enum a => a -> Int
fromEnum Char
c)) (Modifiers
mods Modifiers -> Modifiers -> Modifiers
forall a. Semigroup a => a -> a -> a
<> Modifiers
ctrlKey)] [Event] -> [Event] -> [Event]
forall a. [a] -> [a] -> [a]
++ Modifiers -> Char -> [Event]
f Modifiers
mods Char
c
        -- All remaning characters of the Latin-1 block are returned as is.

        | Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<  Char
'\DEL' -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right ([Event] -> Either Decoder [Event])
-> [Event] -> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ [Key -> Modifiers -> Event
KeyEvent (Char -> Key
CharKey Char
c) Modifiers
mods] [Event] -> [Event] -> [Event]
forall a. [a] -> [a] -> [a]
++ Modifiers -> Char -> [Event]
f Modifiers
mods Char
c
        -- Skip all other C1 control codes and DEL unless they have special meaning configured.

        | Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<  Char
'\xA0' -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right ([Event] -> Either Decoder [Event])
-> [Event] -> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ Modifiers -> Char -> [Event]
f Modifiers
mods Char
c
        -- All other Unicode characters are returned as is.

        | Bool
otherwise   -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right [Key -> Modifiers -> Event
KeyEvent (Char -> Key
CharKey Char
c) Modifiers
mods]
        where
            f :: Modifiers -> Char -> [Event]
f Modifiers
mods Char
c = [Event] -> (Event -> [Event]) -> Maybe Event -> [Event]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] Event -> [Event]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Modifiers -> Char -> Maybe Event
specialChar Modifiers
mods Char
c)

    -- This function shall be called if an ESC has been read in default mode

    -- and it is stil unclear whether this is the beginning of an escape sequence or not.

    -- NOTE: This function is total and consumes at least one more character of input.

    escapeMode :: Decoder
    escapeMode :: Decoder
escapeMode  = (Modifiers -> Char -> Either Decoder [Event]) -> Decoder
Decoder ((Modifiers -> Char -> Either Decoder [Event]) -> Decoder)
-> (Modifiers -> Char -> Either Decoder [Event]) -> Decoder
forall a b. (a -> b) -> a -> b
$ \Modifiers
mods Char
c-> if
      -- Single escape key press is always followed by a NUL fill character

      -- by design (instead of timing). This makes reasoning and testing much easier

      -- and reliable.

      | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\NUL' -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right [Key -> Modifiers -> Event
KeyEvent (Char -> Key
CharKey Char
'[') (Modifiers
mods Modifiers -> Modifiers -> Modifiers
forall a. Semigroup a => a -> a -> a
<> Modifiers
ctrlKey), Key -> Modifiers -> Event
KeyEvent Key
EscapeKey Modifiers
mods]
      | Bool
otherwise   -> Decoder -> Either Decoder [Event]
forall a b. a -> Either a b
Left (Char -> Decoder
escapeSequenceMode Char
c)

    -- This function shall be called with the escape sequence introducer.

    -- It needs to look at next character to decide whether this is

    -- a CSI sequence or an ALT-modified key or illegal state.

    escapeSequenceMode :: Char -> Decoder
    escapeSequenceMode :: Char -> Decoder
escapeSequenceMode Char
c = (Modifiers -> Char -> Either Decoder [Event]) -> Decoder
Decoder ((Modifiers -> Char -> Either Decoder [Event]) -> Decoder)
-> (Modifiers -> Char -> Either Decoder [Event]) -> Decoder
forall a b. (a -> b) -> a -> b
$ \Modifiers
mods Char
d-> if
      | Char
d Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\NUL' Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
> Char
'\SP' Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'~' -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right [Key -> Modifiers -> Event
KeyEvent (Char -> Key
CharKey Char
c) (Modifiers
mods Modifiers -> Modifiers -> Modifiers
forall a. Semigroup a => a -> a -> a
<> Modifiers
altKey)]
      | Char
d Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\NUL' Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= Char
'\xa0'           -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right [Key -> Modifiers -> Event
KeyEvent (Char -> Key
CharKey Char
c) (Modifiers
mods Modifiers -> Modifiers -> Modifiers
forall a. Semigroup a => a -> a -> a
<> Modifiers
altKey)]
      | Char
d Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\NUL'                          -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right ([Event] -> Either Decoder [Event])
-> [Event] -> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ case Modifiers -> Char -> Maybe Event
specialChar Modifiers
mods Char
c of
                                                  Maybe Event
Nothing -> []
                                                  Just Event
ev -> case Event
ev of
                                                    KeyEvent Key
key Modifiers
m -> [Key -> Modifiers -> Event
KeyEvent Key
key (Modifiers
mods Modifiers -> Modifiers -> Modifiers
forall a. Semigroup a => a -> a -> a
<> Modifiers
m Modifiers -> Modifiers -> Modifiers
forall a. Semigroup a => a -> a -> a
<> Modifiers
altKey)]
                                                    Event
_              -> [Event
ev]
      | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'O'                             -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right (Modifiers -> Char -> [Event]
ss3Mode Modifiers
mods Char
d)
      | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'['                             -> Char -> Either Decoder [Event]
csiMode Char
d
      | Bool
otherwise                            -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right []

    -- SS3 mode is another less well-known escape sequence mode.

    -- It is introduced by `\\ESCO`. Some terminal emulators use it for

    -- compatibility with veeery old terminals. SS3 mode only allows one

    -- subsequent character. Interpretation has been determined empirically

    -- and with reference to http://rtfm.etla.org/xterm/ctlseq.html

    ss3Mode :: Modifiers -> Char -> [Event]
    ss3Mode :: Modifiers -> Char -> [Event]
ss3Mode Modifiers
mods = \case
      Char
'P' -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey  Int
1) Modifiers
mods]
      Char
'Q' -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey  Int
2) Modifiers
mods]
      Char
'R' -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey  Int
3) Modifiers
mods]
      Char
'S' -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey  Int
4) Modifiers
mods]
      Char
_   -> []

    -- ESC[ is followed by any number (including none) of parameter chars in the

    -- range 0–9:;<=>?, then by any number of intermediate chars

    -- in the range space and !"#$%&'()*+,-./, then finally by a single char in

    -- the range @A–Z[\]^_`a–z{|}~.

    -- For security reasons (untrusted input and denial of service) this parser

    -- only accepts a very limited number of characters for both parameter and

    -- intermediate chars.

    -- Unknown (not illegal) sequences are dropped, but it is guaranteed that

    -- they will be consumed completely and it is safe for the parser to

    -- return to normal mode afterwards. Illegal sequences cause the parser

    -- to consume the input up to the first violating character and then reject.

    -- The parser might be out of sync afterwards, but this is a protocol

    -- violation anyway. The parser's only job here is not to loop (consume

    -- and drop the illegal input!) and then to stop and fail reliably.

    csiMode :: Char -> Either Decoder [Event]
    csiMode :: Char -> Either Decoder [Event]
csiMode Char
c
      | Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= Char
'0' Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'?' = Decoder -> Either Decoder [Event]
forall a b. a -> Either a b
Left (Decoder -> Either Decoder [Event])
-> Decoder -> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ Int -> String -> Decoder
f (Int
charLimit Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) [Char
c]
      | Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= Char
'!' Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'/' = Decoder -> Either Decoder [Event]
forall a b. a -> Either a b
Left (Decoder -> Either Decoder [Event])
-> Decoder -> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ Int -> String -> String -> Decoder
g (Int
charLimit Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) [] [Char
c]
      | Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= Char
'@' Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'~' = [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right ([Event] -> Either Decoder [Event])
-> [Event] -> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ String -> String -> Char -> [Event]
interpretCSI [] [] Char
c
      | Bool
otherwise            = [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right [] -- Illegal state. Return to default mode.

      where
        charLimit :: Int
        charLimit :: Int
charLimit  = Int
16
        -- Note: The following functions use recursion, but recursion is

        -- guaranteed to terminate and maximum recursion depth is only

        -- dependant on the constant `charLimit`. In case of errors the decoder

        -- will therefore recover to default mode after at most 32 characters.

        f :: Int -> String -> Decoder
        f :: Int -> String -> Decoder
f Int
0 String
_  = Decoder
defaultMode
        f Int
i String
ps = (Modifiers -> Char -> Either Decoder [Event]) -> Decoder
Decoder ((Modifiers -> Char -> Either Decoder [Event]) -> Decoder)
-> (Modifiers -> Char -> Either Decoder [Event]) -> Decoder
forall a b. (a -> b) -> a -> b
$ (Char -> Either Decoder [Event])
-> Modifiers -> Char -> Either Decoder [Event]
forall a b. a -> b -> a
const ((Char -> Either Decoder [Event])
 -> Modifiers -> Char -> Either Decoder [Event])
-> (Char -> Either Decoder [Event])
-> Modifiers
-> Char
-> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ \Char
x-> if
          | Char
x Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= Char
'0' Bool -> Bool -> Bool
&& Char
x Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'?' -> Decoder -> Either Decoder [Event]
forall a b. a -> Either a b
Left (Decoder -> Either Decoder [Event])
-> Decoder -> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ Int -> String -> Decoder
f (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (Char
xChar -> String -> String
forall a. a -> [a] -> [a]
:String
ps)  -- More parameters.

          | Char
x Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= Char
'!' Bool -> Bool -> Bool
&& Char
x Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'/' -> Decoder -> Either Decoder [Event]
forall a b. a -> Either a b
Left (Decoder -> Either Decoder [Event])
-> Decoder -> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ Int -> String -> String -> Decoder
g Int
charLimit String
ps [] -- Start of intermediates.

          | Char
x Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= Char
'@' Bool -> Bool -> Bool
&& Char
x Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'~' -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right ([Event] -> Either Decoder [Event])
-> [Event] -> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ String -> String -> Char -> [Event]
interpretCSI (String -> String
forall a. [a] -> [a]
reverse String
ps) [] Char
x
          | Bool
otherwise            -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right [] -- Illegal state. Return to default mode.

        g :: Int -> String -> String -> Decoder
        g :: Int -> String -> String -> Decoder
g Int
0 String
_  String
_  = Decoder
defaultMode
        g Int
i String
ps String
is = (Modifiers -> Char -> Either Decoder [Event]) -> Decoder
Decoder ((Modifiers -> Char -> Either Decoder [Event]) -> Decoder)
-> (Modifiers -> Char -> Either Decoder [Event]) -> Decoder
forall a b. (a -> b) -> a -> b
$ (Char -> Either Decoder [Event])
-> Modifiers -> Char -> Either Decoder [Event]
forall a b. a -> b -> a
const ((Char -> Either Decoder [Event])
 -> Modifiers -> Char -> Either Decoder [Event])
-> (Char -> Either Decoder [Event])
-> Modifiers
-> Char
-> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ \Char
x-> if
          | Char
x Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= Char
'!' Bool -> Bool -> Bool
&& Char
x Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'/' -> Decoder -> Either Decoder [Event]
forall a b. a -> Either a b
Left (Decoder -> Either Decoder [Event])
-> Decoder -> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ Int -> String -> String -> Decoder
g (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) String
ps (Char
xChar -> String -> String
forall a. a -> [a] -> [a]
:String
is) -- More intermediates.

          | Char
x Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= Char
'@' Bool -> Bool -> Bool
&& Char
x Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'~' -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right ([Event] -> Either Decoder [Event])
-> [Event] -> Either Decoder [Event]
forall a b. (a -> b) -> a -> b
$ String -> String -> Char -> [Event]
interpretCSI (String -> String
forall a. [a] -> [a]
reverse String
ps) (String -> String
forall a. [a] -> [a]
reverse String
is) Char
x
          | Bool
otherwise            -> [Event] -> Either Decoder [Event]
forall a b. b -> Either a b
Right [] -- Illegal state. Return to default mode.


interpretCSI :: String -> String -> Char -> [Event]
interpretCSI :: String -> String -> Char -> [Event]
interpretCSI String
params String
_intermediates = \case
  Char
'$'        -> [Key -> Modifiers -> Event
KeyEvent Key
DeleteKey (Modifiers
altKey Modifiers -> Modifiers -> Modifiers
forall a. Monoid a => a -> a -> a
`mappend` Modifiers
shiftKey)]  -- urxvt, gnome-terminal

  Char
'@'        -> []
  Char
'A'        -> Key -> [Event]
modified (Key -> [Event]) -> Key -> [Event]
forall a b. (a -> b) -> a -> b
$ Direction -> Key
ArrowKey Direction
Upwards
  Char
'B'        -> Key -> [Event]
modified (Key -> [Event]) -> Key -> [Event]
forall a b. (a -> b) -> a -> b
$ Direction -> Key
ArrowKey Direction
Downwards
  Char
'C'        -> Key -> [Event]
modified (Key -> [Event]) -> Key -> [Event]
forall a b. (a -> b) -> a -> b
$ Direction -> Key
ArrowKey Direction
Rightwards
  Char
'D'        -> Key -> [Event]
modified (Key -> [Event]) -> Key -> [Event]
forall a b. (a -> b) -> a -> b
$ Direction -> Key
ArrowKey Direction
Leftwards
  Char
'E'        -> Key -> [Event]
modified   Key
BeginKey
  Char
'F'        -> Key -> [Event]
modified   Key
EndKey
  Char
'G'        -> []
  Char
'H'        -> Key -> [Event]
modified   Key
HomeKey
  Char
'I'        -> Key -> [Event]
modified   Key
TabKey
  Char
'J'        -> []
  Char
'K'        -> []
  Char
'L'        -> []
  Char
'M'        -> []
  Char
'N'        -> []
  Char
'O'        -> []
  Char
'P'        -> Key -> [Event]
modified (Int -> Key
FunctionKey  Int
1)
  Char
'Q'        -> Key -> [Event]
modified (Int -> Key
FunctionKey  Int
2)
  -- This sequence is ambiguous. xterm and derivatives use this to encode a modified F3 key as

  -- well as a cursor position report. There is no real solution to disambiguate these two

  -- other than context of expectation (cursor position report has probably been requested).

  -- This decoder shall simply emit both events and the user shall ignore unexpected events.

  Char
'R'        -> Key -> [Event]
modified (Int -> Key
FunctionKey  Int
3) [Event] -> [Event] -> [Event]
forall a. [a] -> [a] -> [a]
++ [DeviceEvent -> Event
DeviceEvent (DeviceEvent -> Event) -> DeviceEvent -> Event
forall a b. (a -> b) -> a -> b
$ Position -> DeviceEvent
CursorPositionReport (Position -> DeviceEvent) -> Position -> DeviceEvent
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Position
Position (Int -> Int
fstNumber Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (Int -> Int
sndNumber Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)]
  Char
'S'        -> Key -> [Event]
modified (Int -> Key
FunctionKey  Int
4)
  Char
'T'        -> []
  Char
'U'        -> []
  Char
'V'        -> []
  Char
'W'        -> []
  Char
'X'        -> []
  Char
'Y'        -> []
  Char
'Z'        -> [Key -> Modifiers -> Event
KeyEvent Key
TabKey Modifiers
shiftKey]
  Char
'^'        -> case String
params of
    String
"2"  -> [Key -> Modifiers -> Event
KeyEvent Key
InsertKey        Modifiers
ctrlKey]
    String
"3"  -> [Key -> Modifiers -> Event
KeyEvent Key
DeleteKey        Modifiers
ctrlKey]
    String
"4"  -> [Key -> Modifiers -> Event
KeyEvent Key
PageUpKey        Modifiers
ctrlKey]
    String
"7"  -> [Key -> Modifiers -> Event
KeyEvent Key
PageDownKey      Modifiers
ctrlKey]
    String
"5"  -> [Key -> Modifiers -> Event
KeyEvent Key
HomeKey          Modifiers
ctrlKey]
    String
"6"  -> [Key -> Modifiers -> Event
KeyEvent Key
EndKey           Modifiers
ctrlKey]
    String
"11" -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey  Int
1) Modifiers
ctrlKey]
    String
"12" -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey  Int
2) Modifiers
ctrlKey]
    String
"13" -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey  Int
3) Modifiers
ctrlKey]
    String
"14" -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey  Int
4) Modifiers
ctrlKey]
    String
"15" -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey  Int
5) Modifiers
ctrlKey]
    String
"17" -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey  Int
6) Modifiers
ctrlKey]
    String
"18" -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey  Int
7) Modifiers
ctrlKey]
    String
"19" -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey  Int
8) Modifiers
ctrlKey]
    String
"20" -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey  Int
9) Modifiers
ctrlKey]
    String
"21" -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey Int
10) Modifiers
ctrlKey]
    String
"23" -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey Int
11) Modifiers
ctrlKey]
    String
"24" -> [Key -> Modifiers -> Event
KeyEvent (Int -> Key
FunctionKey Int
12) Modifiers
ctrlKey]
    String
_    -> []
  Char
'f' -> []
  Char
'i' -> [Key -> Modifiers -> Event
KeyEvent Key
PrintKey Modifiers
forall a. Monoid a => a
mempty]
  Char
'm' -> []
  Char
'~' -> case String
fstParam of
    String
"2"  -> Key -> [Event]
modified Key
InsertKey
    String
"3"  -> Key -> [Event]
modified Key
DeleteKey
    String
"5"  -> Key -> [Event]
modified Key
PageUpKey
    String
"6"  -> Key -> [Event]
modified Key
PageDownKey
    String
"9"  -> Key -> [Event]
modified Key
HomeKey
    String
"10" -> Key -> [Event]
modified Key
EndKey
    String
"11" -> Key -> [Event]
modified (Int -> Key
FunctionKey Int
1)
    String
"12" -> Key -> [Event]
modified (Int -> Key
FunctionKey Int
2)
    String
"13" -> Key -> [Event]
modified (Int -> Key
FunctionKey Int
3)
    String
"14" -> Key -> [Event]
modified (Int -> Key
FunctionKey Int
4)
    String
"15" -> Key -> [Event]
modified (Int -> Key
FunctionKey Int
5)
    String
"17" -> Key -> [Event]
modified (Int -> Key
FunctionKey Int
6)
    String
"18" -> Key -> [Event]
modified (Int -> Key
FunctionKey Int
7)
    String
"19" -> Key -> [Event]
modified (Int -> Key
FunctionKey Int
8)
    String
"20" -> Key -> [Event]
modified (Int -> Key
FunctionKey Int
9)
    String
"21" -> Key -> [Event]
modified (Int -> Key
FunctionKey Int
10)
    String
"23" -> Key -> [Event]
modified (Int -> Key
FunctionKey Int
11)
    String
"24" -> Key -> [Event]
modified (Int -> Key
FunctionKey Int
12)
    String
_    -> []
  Char
_ -> []
  where
    fstParam :: String
    fstParam :: String
fstParam = (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
';') String
params
    sndParam :: String
    sndParam :: String
sndParam = (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
';') (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ Int -> String -> String
forall a. Int -> [a] -> [a]
drop Int
1 (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
';') String
params
    fstNumber :: Int -> Int
    fstNumber :: Int -> Int
fstNumber Int
i
      | Bool -> Bool
not (String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
fstParam) Bool -> Bool -> Bool
&& (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Char -> Bool
isDigit String
fstParam = String -> Int
forall a. Read a => String -> a
read String
fstParam
      | Bool
otherwise                                   = Int
i
    sndNumber :: Int -> Int
    sndNumber :: Int -> Int
sndNumber Int
i
      | Bool -> Bool
not (String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
sndParam) Bool -> Bool -> Bool
&& (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Char -> Bool
isDigit String
sndParam = String -> Int
forall a. Read a => String -> a
read String
sndParam
      | Bool
otherwise                                   = Int
i
    modified :: Key -> [Event]
modified Key
key = case String
sndParam of
      String
""  -> [Key -> Modifiers -> Event
KeyEvent Key
key   Modifiers
forall a. Monoid a => a
mempty                       ]
      String
"2" -> [Key -> Modifiers -> Event
KeyEvent Key
key   Modifiers
shiftKey                     ]
      String
"3" -> [Key -> Modifiers -> Event
KeyEvent Key
key               Modifiers
altKey           ]
      String
"4" -> [Key -> Modifiers -> Event
KeyEvent Key
key (Modifiers -> Event) -> Modifiers -> Event
forall a b. (a -> b) -> a -> b
$ Modifiers
shiftKey Modifiers -> Modifiers -> Modifiers
forall a. Semigroup a => a -> a -> a
<> Modifiers
altKey           ]
      String
"5" -> [Key -> Modifiers -> Event
KeyEvent Key
key                         Modifiers
ctrlKey]
      String
"6" -> [Key -> Modifiers -> Event
KeyEvent Key
key (Modifiers -> Event) -> Modifiers -> Event
forall a b. (a -> b) -> a -> b
$ Modifiers
shiftKey Modifiers -> Modifiers -> Modifiers
forall a. Semigroup a => a -> a -> a
<>           Modifiers
ctrlKey]
      String
"7" -> [Key -> Modifiers -> Event
KeyEvent Key
key (Modifiers -> Event) -> Modifiers -> Event
forall a b. (a -> b) -> a -> b
$             Modifiers
altKey Modifiers -> Modifiers -> Modifiers
forall a. Semigroup a => a -> a -> a
<> Modifiers
ctrlKey]
      String
"8" -> [Key -> Modifiers -> Event
KeyEvent Key
key (Modifiers -> Event) -> Modifiers -> Event
forall a b. (a -> b) -> a -> b
$ Modifiers
shiftKey Modifiers -> Modifiers -> Modifiers
forall a. Semigroup a => a -> a -> a
<> Modifiers
altKey Modifiers -> Modifiers -> Modifiers
forall a. Semigroup a => a -> a -> a
<> Modifiers
ctrlKey]
      String
_   -> []