Initial commit.  Hard-coded.
8 files changed, 166 insertions(+), 0 deletions(-)

A => .hgignore
A => CHANGELOG.md
A => LICENSE.txt
A => README.md
A => go.mod
A => go.sum
A => main.go
A => rules.json
A => .hgignore +3 -0
@@ 0,0 1,3 @@ 
+syntax: glob
+
+.*.sw?

          
A => CHANGELOG.md +26 -0
@@ 0,0 1,26 @@ 
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+> **Types of changes**:
+>
+> - **Added**: for new features.
+> - **Changed**: for changes in existing functionality.
+> - **Deprecated**: for soon-to-be removed features.
+> - **Removed**: for now removed features.
+> - **Fixed**: for any bug fixes.
+> - **Security**: in case of vulnerabilities.
+
+## [1.1.0] - 
+
+### Added
+- Support for marks.  This allows multiple applications to be run.
+
+### Changed
+- Improved help
+
+## [1.0.0] - 2020-04-03
+
+First release.

          
A => LICENSE.txt +24 -0
@@ 0,0 1,24 @@ 
+Copyright (c) 2020, Sean E. Russell <ser@ser1.net>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the <organization> nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

          
A => README.md +0 -0

        
A => go.mod +5 -0
@@ 0,0 1,5 @@ 
+module code.ser1.net/kbplug
+
+go 1.14
+
+require github.com/pilebones/go-udev v0.0.0-20180820235104-043677e09b13

          
A => go.sum +2 -0
@@ 0,0 1,2 @@ 
+github.com/pilebones/go-udev v0.0.0-20180820235104-043677e09b13 h1:Y+ynP+0QIjUejN2tsuIlWOJG1CThJy6amRuWlBL94Vg=
+github.com/pilebones/go-udev v0.0.0-20180820235104-043677e09b13/go.mod h1:MXAPLpvZeTqLpU1eO6kFXzU0uBMooSGc1MPXAcBoy1M=

          
A => main.go +94 -0
@@ 0,0 1,94 @@ 
+package main
+
+import (
+	"flag"
+	"fmt"
+	"log"
+	"os"
+	"os/exec"
+	"os/signal"
+	"strings"
+	"syscall"
+
+	"github.com/pilebones/go-udev/netlink"
+)
+
+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")
+	flag.Parse()
+	if len(devices) < 1 || flag.NArg() < 1 {
+		flag.PrintDefaults()
+		fmt.Printf("Remaining arguments is the command to run.")
+		os.Exit(1)
+	}
+	if *help {
+		flag.PrintDefaults()
+		fmt.Printf("Remaining arguments is the command to run.")
+		os.Exit(0)
+	}
+	conn := new(netlink.UEventConn)
+	if err := conn.Connect(netlink.UdevEvent); err != nil {
+		log.Fatalln("unable to connect to udev")
+	}
+	defer conn.Close()
+
+	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.*",
+			},
+		})
+	}
+	quit := conn.Monitor(queue, errors, matcher)
+	// Signal handler to quit properly monitor mode
+	signals := make(chan os.Signal, 1)
+	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
+	go func() {
+		<-signals
+		log.Println("Exiting monitor mode...")
+		quit <- struct{}{}
+		os.Exit(0)
+	}()
+
+	// Handling message from queue
+	log.Printf("monitoring for connection events")
+	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)
+			}
+		case err := <-errors:
+			log.Printf("ERROR: %v", err)
+		}
+	}
+}
+
+type Strings []string
+
+func (s *Strings) String() string {
+	return "strings"
+}
+func (s *Strings) Set(v string) error {
+	*s = append(*s, v)
+	return nil
+}

          
A => rules.json +12 -0
@@ 0,0 1,12 @@ 
+{
+	"rules": [
+		{
+			"action": "add", 
+			"env": {
+				"ACTION": "add",
+				"SUBSYSTEM": "input",
+				"NAME": ".*Goldtouch.*Keyboard.*"
+			}
+		}
+	]
+}