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
|
#!/usr/bin/env runhaskell
import Control.Applicative ((<$>))
import Control.Monad (when)
import Data.List (isInfixOf, isPrefixOf, isSuffixOf)
import System.Environment (getArgs)
import System.Process (readProcessWithExitCode, runCommand)
-- constants
-- | Keyboards in the output of lsusb(8) that are to be used instead
-- of the laptops's built-in keyboard. If none are present, the
-- laptop keyboard will not be disabled.
pluggedKBs = ["04f2:0833 Chicony Electronics Co., Ltd "]
-- | Pointing devices in the output of lsusb(8) that are to be used instead
-- of the laptops's built-in pointing devices. If none are present,
-- the laptop pointing devices will not be disabled.
pluggedMice = ["045e:0053 Microsoft Corp. Optical Mouse"]
-- | The laptop's built-in keyboard as listed by xinput(1).
laptopKB = "AT Translated Set 2 keyboard"
-- | The laptop's built-in pointing devices as listed by xinput(1).
laptopMice = ["DualPoint Stick", "AlpsPS/2 ALPS DualPoint TouchPad"]
-- string processing
-- | Find a device's ID in the output of `xinput --list`
findXInputID :: String -> String -> Maybe Int
findXInputID device xinput = do
(line:[]) <- Just $ filter (device `isInfixOf`) $ lines xinput
(idW:[]) <- Just $ filter ("id=" `isPrefixOf`) $ words line
((id, _):[]) <- Just $ reads $ drop 3 idW
return id
-- | Determines whether a device is plugged in using lsusb(8) output.
checkPlugged :: String -> String -> Bool
checkPlugged device lsusb = length ls == 1
where
ls = filter (device `isSuffixOf`) $ lines lsusb
-- | xinput(1) command to disable an input with a given id
disableCommand :: Int -> String
disableCommand id = "xinput set-int-prop " ++ show id ++ " \"Device Enabled\" 8 0"
-- | xinput(1) command to enable an input with a given id
enableCommand :: Int -> String
enableCommand id = init (disableCommand id) ++ "1"
-- IO actions to do the work
enable :: IO ()
enable = sequence_ $ enableInput <$> laptopKB : laptopMice
-- disable :: IO ()
-- disable = undefined
disable :: IO ()
disable = do
mousePlugged <- any (== True) <$> (sequence $ checkInput <$> pluggedMice)
when mousePlugged $ sequence_ $ disableInput <$> laptopMice
kbPlugged <- any (== True) <$> (sequence $ checkInput <$> pluggedKBs)
when kbPlugged $ disableInput laptopKB
enableInput :: String -> IO ()
enableInput device = do
xinput <- getXInputList
let id = findXInputID device xinput
case id of
Just i -> runCommand (enableCommand i) >> return ()
Nothing -> putStrLn $ "cannot enable input with xinput"
disableInput :: String -> IO ()
disableInput device = do
xinput <- getXInputList
let id = findXInputID device xinput
case id of
Just i -> runCommand (disableCommand i) >> return ()
Nothing -> putStrLn $ "cannot disable input with xinput"
checkInput :: String -> IO Bool
checkInput device = getUSBList >>= \lsusb ->
return $ checkPlugged device lsusb
getXInputList :: IO String
getXInputList = do
(_, output, _) <- readProcessWithExitCode "xinput" ["--list"] ""
return output
getUSBList :: IO String
getUSBList = do
(_, output, _) <- readProcessWithExitCode "lsusb" [] ""
return output
-- handle command line arguments
processArgs :: [String] -> IO ()
processArgs [] = usage
processArgs (o:_) =
case o of
"--enable" -> enable
"--maybe-disable" -> disable
_ -> usage
main = getArgs >>= processArgs
usage :: IO ()
usage = putStrLn "usage: laptopinput --enable|--maybe-disable"
|