@@ 1,31 1,38 @@
package main
import (
+ "encoding/json"
"flag"
"fmt"
+ "io/ioutil"
"log"
"os"
"os/exec"
"os/signal"
- "strings"
+ "regexp"
"syscall"
"github.com/pilebones/go-udev/netlink"
)
+var Version string
+
func main() {
- var devices Strings
- flag.Var(&devices, "d", "One (or more) regular expressions matching device names to watch for")
help := flag.Bool("h", false, "Print help and exit")
+ version := flag.Bool("v", false, "Print version and exit")
flag.Parse()
- if len(devices) < 1 || flag.NArg() < 1 {
+ if *version {
+ fmt.Println(Version)
+ os.Exit(0)
+ }
+ if flag.NArg() < 1 {
flag.PrintDefaults()
- fmt.Printf("Remaining arguments is the command to run.")
+ fmt.Printf("The only argument is the path to the rules file.")
os.Exit(1)
}
if *help {
flag.PrintDefaults()
- fmt.Printf("Remaining arguments is the command to run.")
+ fmt.Printf("The only argument is the path to the rules file.")
os.Exit(0)
}
conn := new(netlink.UEventConn)
@@ 37,17 44,12 @@ func main() {
queue := make(chan netlink.UEvent)
errors := make(chan error)
matcher := new(netlink.RuleDefinitions)
- add := "add"
- for _, d := range devices {
- log.Printf("Adding rule for %s", d)
- matcher.AddRule(netlink.RuleDefinition{
- Action: &add,
- Env: map[string]string{
- "ACTION": "add",
- "SUBSYSTEM": "input",
- "NAME": ".*Goldtouch.*Keyboard.*",
- },
- })
+ rules, err := ioutil.ReadFile(flag.Arg(0))
+ if err != nil {
+ panic(err)
+ }
+ if err := json.Unmarshal(rules, &matcher); err != nil {
+ log.Fatalf("Wrong rule syntax in \"%s\", err: %s", flag.Arg(0), err.Error())
}
quit := conn.Monitor(queue, errors, matcher)
// Signal handler to quit properly monitor mode
@@ 60,22 62,30 @@ func main() {
os.Exit(0)
}()
+ var ruleset Ruleset
+ if err := json.Unmarshal(rules, &ruleset); err != nil {
+ log.Fatalf("Wrong rule syntax in \"%s\", err: %s", flag.Arg(0), err.Error())
+ }
// Handling message from queue
- log.Printf("monitoring for connection events")
+ log.Printf("monitoring for connection events for %d rules", len(ruleset.Rules))
for {
select {
case evt := <-queue:
- var cmd *exec.Cmd
- if flag.NArg() > 1 {
- args := flag.Args()
- cmd = exec.Command(args[0], args[1:]...)
- } else {
- cmd = exec.Command(flag.Args()[0])
- }
- log.Printf("%s: %s\n", evt.Env["NAME"], strings.Join(flag.Args(), " "))
- err := cmd.Run()
- if err != nil {
- panic(err)
+ rule := ruleset.MatchRule(evt)
+ if rule != nil {
+ var cmd *exec.Cmd
+ for _, cx := range rule.Run {
+ if flag.NArg() > 1 {
+ cmd = exec.Command(cx[0], cx[1:]...)
+ } else {
+ cmd = exec.Command(cx[0])
+ }
+ log.Printf("%s: %v\n", evt.Env["NAME"], cx)
+ err := cmd.Run()
+ if err != nil {
+ panic(err)
+ }
+ }
}
case err := <-errors:
log.Printf("ERROR: %v", err)
@@ 83,12 93,31 @@ func main() {
}
}
-type Strings []string
+type Ruleset struct {
+ Rules []Rule
+}
+type Rule struct {
+ Action string
+ Env map[string]string
+ Run [][]string
+}
-func (s *Strings) String() string {
- return "strings"
-}
-func (s *Strings) Set(v string) error {
- *s = append(*s, v)
+// Return first matching rule
+func (rs Ruleset) MatchRule(e netlink.UEvent) *Rule {
+ for _, rule := range rs.Rules {
+ if rule.Action == e.Action.String() {
+ var match bool = true
+ for rk, rv := range rule.Env {
+ re := regexp.MustCompile(rv)
+ if !re.Match([]byte(e.Env[rk])) {
+ match = false
+ break
+ }
+ }
+ if match {
+ return &rule
+ }
+ }
+ }
return nil
}
@@ 5,8 5,11 @@
"env": {
"ACTION": "add",
"SUBSYSTEM": "input",
- "NAME": ".*Goldtouch.*Keyboard.*"
- }
+ "NAME": ".*Goldtouch.*Keyboard.*System Control"
+ },
+ "run": [
+ ["setxkbmap", "-layout","us","-variant","dvorak","-geometry","kinesis","-option","caps:super","-option","compose:lwin"]
+ ]
}
]
}