aboutsummaryrefslogtreecommitdiff
path: root/montis/src/Montis/Standard/Bindings.hs
blob: fea7a03f1ab3c97deaafc18873b7a5851efe67b2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
module Montis.Standard.Bindings where

import Control.Monad (unless, when)
import Control.Monad.IO.Class (liftIO)
import Data.Data (Typeable)
import Data.Default.Class (Default (..))
import Data.Set qualified as Set
import Data.Word (Word32)
import Montis.Base.Foreign.WlRoots (seatKeyboardNotifyKey, seatPointerNotifyButton)
import Montis.Core.Events (ButtonEvent (..), ButtonState (..), KeyEvent (..), KeyState (..))
import Montis.Core.Monad (Montis, xConfigGet, xStateGet, xStateModify)
import Montis.Core.Runtime (getSeat)
import Montis.Core.State
  ( Config (startingHooks),
    ConfigModule (..),
    Hooks (keyHook, buttonHook),
    StateExtension (..),
  )

data InputEvent where
  InputEvent :: Either KeyEvent ButtonEvent -> InputEvent

-- | Configuration for the keybindings.
data InputsConfig where
  InputsConfig ::
    { startCont :: InputEvent -> Montis Bool
    } ->
    InputsConfig
  deriving (Typeable)

instance Default InputsConfig where
  def = InputsConfig $ \_ -> return False

subkeys :: (InputEvent -> Montis Bool) -> Montis Bool
subkeys fn = do
  xStateModify $ \keyState ->
    keyState
      { awaiting = Just fn
      }
  return True

-- | State of the keys right now.
data InputsState where
  InputsState ::
    { awaiting :: Maybe (InputEvent -> Montis Bool),
      ignoredKeys :: Set.Set Word32
    } ->
    InputsState

instance StateExtension InputsState where
  initialValue = InputsState Nothing Set.empty
  marshalExtension = const Nothing
  demarshalExtension = const Nothing

-- | Configurable module for keys.
instance ConfigModule Montis InputsConfig where
  alterConfig _ c =
    let oh = keyHook (startingHooks c)
        obh = buttonHook (startingHooks c)
     in c
          { startingHooks =
              (startingHooks c)
                { keyHook = \ev -> runEv (InputEvent (Left ev)) >> oh ev,
                  buttonHook = \ev -> runEv (InputEvent (Right ev)) >> obh ev
                }
          }
    where
      isKeyPress ev = keyEvent_state ev == KeyPressed
      isKeyRelease ev = keyEvent_state ev == KeyReleased
      shouldIgnoreEvent ev = do
        InputsState {ignoredKeys} <- xStateGet
        return $ Set.member (keyEvent_keycode ev) ignoredKeys
      runEv :: InputEvent -> Montis ()
      runEv iv@(InputEvent (Right ev)) = do
        handler' <- awaiting <$> xStateGet
        handler <- maybe (startCont <$> xConfigGet) return handler'
        xStateModify $ \st ->
          st {awaiting = Nothing}
        handled <- handler iv
        unless handled $
          forwardButtonToSeat ev
      runEv iv@(InputEvent (Left ev)) = do
        shouldIgnore <- shouldIgnoreEvent ev
        if isKeyRelease ev && shouldIgnore
          then xStateModify $ \ks ->
            ks {ignoredKeys = Set.delete (keyEvent_keycode ev) (ignoredKeys ks)}
          else do
            handled <-
              if isKeyPress ev
                then do
                  handler' <- awaiting <$> xStateGet
                  handler <- maybe (startCont <$> xConfigGet) return handler'
                  -- Reset the hadler.
                  xStateModify $ \st ->
                    st {awaiting = Nothing}
                  handler iv
                else return False

            if not handled
              then forwardKeyToSeat ev
              else when (isKeyPress ev) $
                xStateModify $
                  \ks ->
                    ks
                      { ignoredKeys =
                          Set.insert (keyEvent_keycode ev) (ignoredKeys ks)
                      }

forwardKeyToSeat :: KeyEvent -> Montis ()
forwardKeyToSeat ev = do
  mseat <- getSeat
  case mseat of
    Nothing -> return ()
    Just seat ->
      liftIO $
        seatKeyboardNotifyKey
          seat
          (keyEvent_timeMs ev)
          (keyEvent_keycode ev)
          (keyStateToWord32 (keyEvent_state ev))

forwardButtonToSeat :: ButtonEvent -> Montis ()
forwardButtonToSeat ev = do
  mseat <- getSeat
  case mseat of
    Nothing -> return ()
    Just seat ->
      liftIO $
        seatPointerNotifyButton
          seat
          (buttonEvent_timeMs ev)
          (buttonEvent_button ev)
          (buttonStateToWord32 (buttonEvent_state ev))

buttonStateToWord32 :: ButtonState -> Word32
buttonStateToWord32 ButtonReleased = 0
buttonStateToWord32 ButtonPressed = 1

keyStateToWord32 :: KeyState -> Word32
keyStateToWord32 KeyReleased = 0
keyStateToWord32 KeyPressed = 1