summaryrefslogtreecommitdiff
path: root/archive/bin/laptopinput
blob: e4aa8186da3edcb84a3fae5ec229d42b8da5fef6 (plain)
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"