fixed mutes/pauses for long pressed rotations
[powermate.git] / powermate.hs
1 module Main where
2
3 import PowerMate
4 import System.IO
5 import System.Process
6 import Text.Regex.Posix
7 import Data.Time
8
9 data State = State {
10   stPowerMate     :: Handle,
11   stVolume        :: Int,
12   stPrevDir       :: Int,
13   stPrevAction    :: Int,
14   stPressed       :: Bool,
15   stIndeterminate :: Bool,
16   stLastPress     :: UTCTime
17 }
18
19 processEvent :: State -> Event -> IO State
20 processEvent state (Button True) = do
21   time <- getCurrentTime
22   state <- updateLastPress state (time)
23   state <- updateButton state True
24   state <- updateIndeterminate state True
25   return state
26 processEvent state (Button False) = do
27   time <- getCurrentTime
28   if (stIndeterminate state)
29     then do
30     if (diffUTCTime (time) (stLastPress state) > 0.8)
31       then do createProcess(proc "volume-toggle" []); return ()
32       else do runCommand "music-toggle"; return ()
33   else return ()
34   state <- updateButton state False
35   return state
36
37 processEvent state (Rotate dir) = do
38   state <- updateIndeterminate state False
39   state <- (if (stPressed state) == False
40               && dir < 2
41               && (stPrevDir state) == 1
42               && (stPrevAction state) == 1
43                 then volumeUp
44               else return) state
45   state <- (if (stPressed state) == False
46               && dir > 2
47               && (stPrevDir state) == 0
48               && (stPrevAction state) == 0
49                 then volumeDown
50               else return) state
51   if stPressed state
52     then do
53     if dir < 2 then do runCommand "next"; return ()
54     else do runCommand "back"; return ()
55   else return ()
56   state <- updatePrevState state (if dir < 2 then 1 else 0)
57   updateBrightness state
58   state <- updatePrevAction state (if (stPrevAction state) == 1 then 0 else 1)
59   return state
60
61 readState :: State -> IO State
62 readState state = do
63   return state
64
65 next :: a -> (a -> IO a) -> IO ()
66 next state func = do
67   newstate <- func state
68   next newstate func
69   return ()
70
71 updateBrightness :: State -> IO ()
72 updateBrightness state = do
73   let brightness = (stVolume state)
74   writeStatus (stPowerMate state) $
75     statusInit { brightness=brightness }
76
77 updateIndeterminate :: State -> Bool -> IO State
78 updateIndeterminate state value = do
79   state <- readState $ State {
80     stPowerMate=(stPowerMate state),
81     stVolume=(stVolume state),
82     stPrevAction=(stPrevAction state),
83     stPrevDir=(stPrevDir state),
84     stPressed=(stPressed state),
85     stLastPress=(stLastPress state),
86     stIndeterminate=value }
87   return state
88
89 volumeUp :: State -> IO State
90 volumeUp state = do
91   createProcess (proc "volume-up" [])
92   state <- readState $ State {
93     stPowerMate=(stPowerMate state),
94     stVolume=(max 0 $ 1+(stVolume state)),
95     stPrevAction=(stPrevAction state),
96     stPrevDir=(stPrevDir state),
97     stPressed=(stPressed state),
98     stLastPress=(stLastPress state),
99     stIndeterminate=(stIndeterminate state) }
100   state <- updatePrevAction state 1
101   return state
102
103 volumeDown :: State -> IO State
104 volumeDown state = do
105   createProcess (proc "volume-down" [])
106   state <- readState $ State {
107     stPowerMate=(stPowerMate state),
108     stVolume=(max 0 $ (stVolume state)-1),
109     stPrevAction=(stPrevAction state),
110     stPrevDir=(stPrevDir state),
111     stPressed=(stPressed state),
112     stLastPress=(stLastPress state),
113     stIndeterminate=(stIndeterminate state) }
114   state <- updatePrevAction state 0
115   return state
116
117 updatePrevState :: State -> Int -> IO State
118 updatePrevState state dir = do
119   state <- readState $ State {
120     stPowerMate=(stPowerMate state),
121     stVolume=(stVolume state),
122     stPrevAction=(stPrevAction state),
123     stPrevDir=dir,
124     stPressed=(stPressed state),
125     stLastPress=(stLastPress state),
126     stIndeterminate=(stIndeterminate state) }
127   return state
128
129 updatePrevAction :: State -> Int -> IO State
130 updatePrevAction state action = do
131   state <- readState $ State {
132     stPowerMate=(stPowerMate state),
133     stVolume=(stVolume state),
134     stPrevAction=action,
135     stPrevDir=(stPrevDir state),
136     stPressed=(stPressed state),
137     stLastPress=(stLastPress state),
138     stIndeterminate=(stIndeterminate state) }
139   return state
140
141 updateButton :: State -> Bool -> IO State
142 updateButton state button = do
143   state <- readState $ State {
144     stPowerMate=(stPowerMate state),
145     stVolume=(stVolume state),
146     stPrevAction=(stPrevAction state),
147     stPrevDir=(stPrevDir state),
148     stPressed=button,
149     stLastPress=(stLastPress state),
150     stIndeterminate=(stIndeterminate state) }
151   return state
152
153 updateLastPress :: State -> UTCTime -> IO State
154 updateLastPress state lastPress = do
155   state <- readState $ State {
156     stPowerMate=(stPowerMate state),
157     stVolume=(stVolume state),
158     stPrevAction=(stPrevAction state),
159     stPrevDir=(stPrevDir state),
160     stPressed=(stPressed state),
161     stLastPress=lastPress,
162     stIndeterminate=(stIndeterminate state) }
163   return state
164
165 loop :: FilePath -> IO ()
166 loop devname = do
167   powermate <- openDevice devname
168
169   alsaMixers <- readProcess "amixer" ["get", "Master"] []
170   let alsaMaster = (alsaMixers =~ "\\[([0-9]{1,2})%\\]" :: String)
171   let volume = read (drop 1
172                       (take
173                         (subtract 2
174                           (length alsaMaster)) alsaMaster)) :: Int
175   time <- getCurrentTime
176   state <- readState $ State {
177     stPowerMate=powermate,
178     stVolume=volume,
179     stPrevAction=0,
180     stPrevDir=0,
181     stPressed=False,
182     stLastPress=time,
183     stIndeterminate=False }
184   updateBrightness state
185
186   next state $ \call -> do
187     event <- readEventWithSkip powermate Nothing
188     case event of
189       Nothing -> return call
190       Just event -> processEvent call event
191
192 main :: IO ()
193 main = do
194   powermate <- searchForDevice
195   case powermate of
196     Nothing  -> return ()
197     Just work -> do
198       loop work