P4wnP1_aloa/cmd/testhid/testhid.go
2018-12-07 00:59:54 +01:00

396 lines
11 KiB
Go

// +build linux,arm
package main
import(
"github.com/mame82/P4wnP1_aloa/hid"
"log"
"fmt"
"time"
"math"
"os"
"runtime/trace"
"os/signal"
"syscall"
_ "net/http/pprof"
"net/http"
"runtime"
"context"
"io/ioutil"
)
var (
StringAscii = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
StringSpecial1 = "§°üÜöÖäĵ€ß¹²³⁴⁵⁶⁷⁸⁹⁰¼½¬„“¢«»æſðđŋħĸł’¶ŧ←↓→øþ"
)
func TestMapCreation() {
//Define test keyboard map
mapDeASCII := hid.HIDKeyboardLanguageMap{
Name: "DE",
Description: "German ASCII to USB Keyboard report mapping",
Mapping: map[string][]hid.KeyboardOutReport{},
}
mapDeASCII.Mapping["c"] = []hid.KeyboardOutReport{
hid.NewKeyboardOutReport(0, hid.HID_KEY_C),
}
mapDeASCII.Mapping["C"] = []hid.KeyboardOutReport{
hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_C),
}
//Store map to file
err := mapDeASCII.StoreToFile("/tmp/DE_ASCII.json")
if err != nil { log.Fatal(err)}
/*
testmap, err := hid.loadKeyboardLanguageMapFromFile("keymaps/DE_ASCII.json")
if err != nil { log.Fatal(err)}
fmt.Println(testmap)
*/
}
func TestComboPress(hidCtl *hid.HIDController) {
testcombos := []string {"SHIFT 1", "ENTER", "ALT TAB", "ALT TABULATOR", " WIN ", "GUI "}
for _,comboStr := range testcombos {
fmt.Printf("Pressing combo '%s'\n", comboStr)
err := hidCtl.Keyboard.StringToPressKeyCombo(comboStr)
if err == nil {
fmt.Printf("... '%s' pressed sleeping 2s\n", comboStr)
time.Sleep(2000 * time.Millisecond)
} else {
fmt.Printf("Error pressing combo '%s': %v\n", comboStr, err)
}
}
}
func TestLEDTriggers(hidCtl *hid.HIDController) {
fmt.Println("Initial sleep to test if we capture LED state changes from the past, as soon as we start waiting (needed at boot)")
time.Sleep(3 * time.Second)
ch := make(chan func(),0)
defer close(ch)
//Test repeat trigger on any LED
fmt.Println("Waiting for any repeated LED state change (5 times frequently), wait timeout after 20 seconds...")
trigger, err := hidCtl.Keyboard.WaitLEDStateChangeRepeated(ch, hid.MaskAny, 5, time.Millisecond*500, 20*time.Second)
if err != nil {
fmt.Printf("Waiting aborted with error: %v\n", err)
} else {
fmt.Printf("Triggered by %+v\n", trigger)
}
//Test single trigger on any LED
fmt.Println("Waiting for any LED single state change, timeout after 15 seconds")
trigger, err = hidCtl.Keyboard.WaitLEDStateChange(ch,hid.MaskAny, 15*time.Second)
if err != nil {
fmt.Printf("Waiting aborted with error: %v\n", err)
} else {
fmt.Printf("Triggered by %+v\n", trigger)
}
//Test single trigger on NUMLOCK LED (ignore CAPSLOCK, SCROLLLOCK etc.)
fmt.Println("Waiting for NUMLOCK LED state change, timeout after 15 seconds")
trigger, err = hidCtl.Keyboard.WaitLEDStateChange(ch,hid.MaskNumLock, 15*time.Second)
if err != nil {
fmt.Printf("Waiting aborted with error: %v\n", err)
} else {
fmt.Printf("Triggered by %+v\n", trigger)
}
//Test single trigger on NUMLOCK LED (ignore CAPSLOCK, SCROLLLOCK etc.)
fmt.Println("Waiting for CAPSLOCK LED state change for 15 seconds")
trigger, err = hidCtl.Keyboard.WaitLEDStateChange(ch, hid.MaskCapsLock, 15*time.Second)
if err != nil {
fmt.Printf("Waiting aborted with error: %v\n", err)
} else {
fmt.Printf("Triggered by %+v\n", trigger)
}
}
func TestMultiLEDTrigges(hidCtl *hid.HIDController, triggerMask byte) {
//Test repeat trigger on given LED
ch := make(chan func(),0)
defer close(ch)
fmt.Printf("Waiting for repeated LED state change (5 times frequently) of mask %v, wait timeout after 20 seconds...\n", triggerMask)
trigger, err := hidCtl.Keyboard.WaitLEDStateChangeRepeated(ch ,triggerMask, 5, time.Millisecond*500, 20*time.Second)
if err != nil {
fmt.Printf("Waiting aborted with error: %v\n", err)
} else {
fmt.Printf("Triggered by %+v\n", trigger)
}
}
func TestConcurrentLEDTriggers(hidCtl *hid.HIDController) {
go TestMultiLEDTrigges(hidCtl, hid.MaskNumLock)
go TestMultiLEDTrigges(hidCtl, hid.MaskCapsLock)
go TestMultiLEDTrigges(hidCtl, hid.MaskCapsLock | hid.MaskScrollLock)
time.Sleep(2*time.Second)
go TestMultiLEDTrigges(hidCtl, hid.MaskAny)
TestMultiLEDTrigges(hidCtl, hid.MaskKana)
}
func TestStringTyping(hidCtl *hid.HIDController) {
fmt.Println("Typing:")
fmt.Println(StringAscii)
//err := hidCtl.Keyboard.StringToPressKeySequence("Test:" + StringAscii + "\t" + StringSpecial1)
err := hidCtl.Keyboard.StringToPressKeySequence(StringAscii)
if err != nil { fmt.Println(err)}
}
func TestCombinedScript(hidCtl *hid.HIDController) (err error) {
testcript := `
console.log("HID Script test for P4wnP1 rework"); //Print to internal console
for (var i = 0; i<5; i++) {
move(128, 0);
delay(500);
move(0, -100.1);
delay(500);
move(-100, 0);
delay(500);
move(0, 100);
delay(500);
}
console.log("HID Script test for P4wnP1 rework"); //Print to internal console
for (var i = 0; i<5; i++) {
moveTo(0.0, 0.0);
delay(500);
moveTo(0.8, 0.0);
delay(500);
moveTo(0.8, 0.8);
delay(500);
moveTo(0.8, 0.8);
delay(500);
}
waitLED(ANY)
layout("US"); //Switch to US keyboard layout
type("Some ASCII test text QWERTZ\n") //Type text to target ('\n' translates to RETURN key)
delay(200); //sleep 200 milliseconds
//waitLEDRepeat test
var mask = NUM | SCROLL;
var repeatCount = 5;
var repeatIntervalMs = 800;
var timeout = 20;
//result = waitLEDRepeat(mask, repeatCount, repeatIntervalMs, timeout)
result = waitLEDRepeat(mask, repeatCount)
console.log("Result: " + JSON.stringify(result)); //Log result object as JSON to internal console
waitLED(NUM | SCROLL, 2); //Wait for NumLock or ScrollLock LED change, abort after 2 seconds
layout("DE"); //Switch to German keyboard layout
type("Non ASCII: üÜöÖäÄ"); //Type non ASCII
press("ENTER"); //Introduce linebreak by pressing RETURN directly
press("RETURN"); //Alias
counter = 4; //set a var ...
type("Pressing <ALT>+<TAB> "+ counter +" times\n"); //... and type it, along with a string
for (var i=0; i<counter; i++) {
press("ALT TAB");
delay(500)
}
//Test LED change based branching
result = waitLED(NUM | CAPS); //Wait for change on NUM or CAPS LED only, without timeout, store result
console.log("Result: " + JSON.stringify(result)); //Log result object as JSON to internal console
if (result.NUM) { //Branch depending on result of LED change
type("NUMLock LED changed\n");
} else {
type("Seems CAPSLock LED changed\n");
}
`
_,err = hidCtl.RunScript(context.Background(),testcript, true)
if err != nil {panic(err)}
return
}
func TestMouseNoScript(hidCtl *hid.HIDController) (err error) {
hidCtl.Mouse.MoveStepped(100,0)
hidCtl.Mouse.MoveStepped(0,-100)
hidCtl.Mouse.MoveStepped(0,100)
time.Sleep(2*time.Second)
hidCtl.Mouse.SetButtons(true, false, false)
for alpha := 0.0; alpha < 8*math.Pi; alpha+=(math.Pi/180) {
cos := int16(math.Cos(6.0*alpha) * 5)
sin := int16(math.Sin(alpha) * 5)
hidCtl.Mouse.MoveStepped(sin,cos)
}
hidCtl.Mouse.SetButtons(false, false, false)
return nil
}
func TestMouseCircle(hidCtl *hid.HIDController) {
scriptMouse := `
//circular mouse movement with rotating vector
turns = 2
degree = Math.PI/180.0
scale = 4
for (var alpha = 0; alpha < 2 * Math.PI * turns; alpha += degree) {
vecx = Math.cos(alpha) * scale
vecy = Math.sin(alpha) * scale
moveStepped(vecx, vecy);
}
`
_,err := hidCtl.RunScript(context.Background(),scriptMouse, true)
if err != nil { panic(err)}
}
// To profile for memory leaks and test clean cancellation of already running scripts on controller re-init
func TestControllerReInit() {
//Test for memory leaks
hidCtlTests := make([]*hid.HIDController,0)
for i:=0; i<10;i++ {
//create new controller
fmt.Printf("****Creating HIDController %d\n", i)
hidCtlTest,_ := hid.NewHIDController(context.Background(),"/dev/hidg0", "keymaps", "/dev/hidg1")
//run script which utilizes LED read
fmt.Printf("****Starting async LED reading script for HIDController %d\n", i)
//script := "waitLEDRepeat(ANY);"
script := "console.log('...started');delay(3000);console.log('...ended');"
ctx := context.Background()
for i:=0;i<4;i++ {
job,err := hidCtlTest.StartScriptAsBackgroundJob(ctx, script, true)
if err != nil {
fmt.Printf("Error starting new job: %v\n",err)
} else {
fmt.Printf("New job started: %+v\n",job)
}
}
time.Sleep(time.Second)
//add to slice
hidCtlTests = append(hidCtlTests, hidCtlTest)
}
hidCtlTests = make([]*hid.HIDController,0)
runtime.GC()
}
func main() {
f, err := os.Create("trace.out")
if err != nil {
panic(err)
}
defer f.Close()
err = trace.Start(f)
if err != nil {
panic(err)
}
defer trace.Stop()
//TestControllerReInit()
hidCtl, err := hid.NewHIDController(context.Background(),"/dev/hidg0", "keymaps", "/dev/hidg1")
if err != nil {panic(err)}
hidCtl.Keyboard.KeyDelay = 100
// hidCtl.Keyboard.KeyDelayJitter = 200
fmt.Printf("Available language maps:\n%v\n",hidCtl.Keyboard.ListLanguageMapNames())
err = hidCtl.Keyboard.SetActiveLanguageMap("DE") //first loaded language map is set by default
if err != nil { fmt.Println(err)}
fmt.Printf("Chosen keyboard language mapping '%s'\n", hidCtl.Keyboard.ActiveLanguageLayout.Name)
// tests
//TestComboPress(hidCtl)
//TestLEDTriggers(hidCtl)
//TestStringTyping(hidCtl)
//TestConcurrentLEDTriggers(hidCtl)
//TestMouseNoScript(hidCtl)
//TestCombinedScript(hidCtl)
//TestMouseCircle(hidCtl)
//add bg jobs waiting for LED
jobList := make([]int,0)
fmt.Println("Adding sleeping jobs with 5 seconds timeout context")
ctxT,_ := context.WithTimeout(context.Background(), time.Second * 2)
//script := "console.log('START ' + JID + ' on VM ' + VMID);delay(5000);console.log(JID + ' returned from 5s blocking delay');"
script := "console.log('START ' + JID + ' on VM ' + VMID);waitLEDRepeat(ANY,5000);console.log(JID + ' returned from 5s blocking delay');"
startTime := time.Now()
for i:=1; i<4; i++ {
job,err := hidCtl.StartScriptAsBackgroundJob(ctxT,script,true)
if err != nil {
fmt.Printf("Failed adding background job: %v\n", err)
} else {
// ad job to slice
jobList = append(jobList, job.Id)
}
}
//Wait for all jobs to finish
fmt.Printf("Waiting for Job results for IDs: %+v\n", jobList)
for _,jid := range jobList {
job,err := hidCtl.GetBackgroundJobByID(jid)
if err != nil {
fmt.Printf("Job with ID %d not found, skipping...\n", jid)
continue
} else {
fmt.Printf("Waiting for finish of job with ID %d \n", jid)
jRes,jErr := hidCtl.WaitBackgroundJobResult(context.Background(),job)
fmt.Printf("JID: %d, Result: %+v, Err: %v\n", jid, jRes, jErr)
}
}
fmt.Printf("All results received after %v\n", time.Since(startTime))
//try to load script file
filepath := "./hidtest1.js"
if scriptFile, err := ioutil.ReadFile(filepath); err != nil {
log.Printf("Couldn't load HIDScript testfile: %s\n", filepath)
} else {
_,err = hidCtl.RunScript(context.Background(),string(scriptFile), true)
if err != nil { panic(err)}
}
go http.ListenAndServe(":8080", nil)
//use a channel to wait for SIGTERM or SIGINT
fmt.Println("Waiting for keyboard interrupt")
sig := make(chan os.Signal)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
s := <-sig
log.Printf("Signal (%v) received, closing ...\n", s)
return
//log.Fatalf("Signal (%v) received, closing \"Let Me In\" rebind DNS server\n", s)
}