mirror of
https://github.com/RoganDawes/P4wnP1_aloa.git
synced 2025-04-12 22:19:02 +02:00
Added combos for HID keyboard, added common keyboard map, added HIDscript function for combos
This commit is contained in:
parent
d580cc7627
commit
8db6b0d179
@ -217,25 +217,25 @@ func (ctl *HIDController) CancelAllVMs() error {
|
||||
}
|
||||
|
||||
//Function declarations for master VM
|
||||
//ToDo: Global mutex for VM callbacks (or better for atomar part of Keyboard.SendString)
|
||||
//ToDo: Global mutex for VM callbacks (or better for atomar part of Keyboard.StringToPressKeySequence)
|
||||
func (ctl *HIDController) jsKbdWriteString(call otto.FunctionCall) (res otto.Value) {
|
||||
arg0 := call.Argument(0)
|
||||
//fmt.Printf("JS kString called with: `%s` (%s)\n", arg0, arg0)
|
||||
//fmt.Printf("JS type() called with: `%s` (%s)\n", arg0, arg0)
|
||||
|
||||
if !arg0.IsString() {
|
||||
log.Printf("JavaScript: Wrong argument for `kString`. `kString` accepts a single String argument. Error location: %v\n", call.CallerLocation())
|
||||
log.Printf("JavaScript: Wrong argument for `type`. `type` accepts a single String argument. Error location: %v\n", call.CallerLocation())
|
||||
return
|
||||
}
|
||||
|
||||
outStr,err := arg0.ToString()
|
||||
if err != nil {
|
||||
log.Printf("kString error: couldn't convert `%s` to UTF-8 string\n", arg0)
|
||||
log.Printf("type error: couldn't convert `%s` to UTF-8 string\n", arg0)
|
||||
return
|
||||
}
|
||||
log.Printf("Typing `%s` on HID keyboard device `%s`\n", outStr, ctl.Keyboard.DevicePath)
|
||||
err = ctl.Keyboard.SendString(outStr)
|
||||
err = ctl.Keyboard.StringToPressKeySequence(outStr)
|
||||
if err != nil {
|
||||
log.Printf("kString error: Couldn't type out `%s` on %v\n", outStr, ctl.Keyboard.DevicePath)
|
||||
log.Printf("type error: Couldn't type out `%s` on %v\n", outStr, ctl.Keyboard.DevicePath)
|
||||
return
|
||||
}
|
||||
return
|
||||
@ -244,7 +244,7 @@ func (ctl *HIDController) jsKbdWriteString(call otto.FunctionCall) (res otto.Val
|
||||
func (ctl *HIDController) jsDelay(call otto.FunctionCall) (res otto.Value) {
|
||||
|
||||
arg0 := call.Argument(0)
|
||||
//fmt.Printf("JS kString called with: `%s` (%s)\n", arg0, arg0)
|
||||
//fmt.Printf("JS delay() called with: `%s` (%s)\n", arg0, arg0)
|
||||
|
||||
if !arg0.IsNumber() {
|
||||
log.Printf("JavaScript: Wrong argument for `delay`. `delay` accepts a single Number argument. Error location: %v\n", call.CallerLocation())
|
||||
@ -263,13 +263,42 @@ func (ctl *HIDController) jsDelay(call otto.FunctionCall) (res otto.Value) {
|
||||
return
|
||||
}
|
||||
|
||||
//for pressing key combos
|
||||
func (ctl *HIDController) jsPress(call otto.FunctionCall) (res otto.Value) {
|
||||
|
||||
arg0 := call.Argument(0)
|
||||
//fmt.Printf("JS delay() called with: `%s` (%s)\n", arg0, arg0)
|
||||
|
||||
if !arg0.IsString() {
|
||||
log.Printf("JavaScript: Wrong argument for 'press'. 'press' accepts a single argument of type string.\n\tError location: %v\n", call.CallerLocation())
|
||||
return
|
||||
}
|
||||
|
||||
comboStr,err := arg0.ToString()
|
||||
if err != nil {
|
||||
log.Printf("Javascript 'press' error: couldn't convert '%v' to string\n", arg0)
|
||||
return
|
||||
}
|
||||
log.Printf("Pressing combo '%s'\n", comboStr)
|
||||
err = ctl.Keyboard.StringToPressKeyCombo(comboStr)
|
||||
if err != nil {
|
||||
log.Printf("Javascript `delay` error: couldn't convert `%v` to string\n", arg0)
|
||||
oErr,vErr := otto.ToValue(err)
|
||||
if vErr == nil { return oErr}
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (ctl *HIDController) initMasterVM() (err error) {
|
||||
ctl.vmMaster = otto.New()
|
||||
err = ctl.vmMaster.Set("kString", ctl.jsKbdWriteString)
|
||||
err = ctl.vmMaster.Set("type", ctl.jsKbdWriteString)
|
||||
if err != nil { return err }
|
||||
err = ctl.vmMaster.Set("delay", ctl.jsDelay)
|
||||
if err != nil { return err }
|
||||
err = ctl.vmMaster.Set("press", ctl.jsPress)
|
||||
if err != nil { return err }
|
||||
return nil
|
||||
}
|
||||
|
264
hid/keyboard.go
264
hid/keyboard.go
@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -46,10 +47,8 @@ func NewKeyboard(devicePath string, resourcePath string) (keyboard *HIDKeyboard,
|
||||
keyboard.KeyDelay = 0
|
||||
keyboard.KeyDelayJitter = 0
|
||||
|
||||
//ToDo: Load whole language map folder, for now single layout testing
|
||||
err = keyboard.LoadLanguageMapFromFile(resourcePath + "/common.json")
|
||||
if err != nil {return nil, err}
|
||||
err = keyboard.LoadLanguageMapFromFile(resourcePath + "/DE_ASCII.json")
|
||||
//Load available language maps
|
||||
err = keyboard.LoadLanguageMapDir(resourcePath)
|
||||
if err != nil {return nil, err}
|
||||
|
||||
//Init LED sate
|
||||
@ -59,10 +58,86 @@ func NewKeyboard(devicePath string, resourcePath string) (keyboard *HIDKeyboard,
|
||||
return
|
||||
}
|
||||
|
||||
func (kbd *HIDKeyboard) LoadLanguageMapDir(dirpath string) (err error) {
|
||||
folder,err := filepath.Abs(dirpath)
|
||||
if err != nil { return err }
|
||||
var mapFiles []string
|
||||
err = filepath.Walk(string(folder), func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil { return err } // prevent panic due to access failures
|
||||
if !info.IsDir() && (strings.ToLower(filepath.Ext(info.Name())) == ".json") {
|
||||
fp := path
|
||||
abs,pErr := filepath.Abs(fp)
|
||||
if pErr == nil {
|
||||
mapFiles = append(mapFiles, abs)
|
||||
} else {
|
||||
//print warning
|
||||
log.Printf("Ignoring map file '%s', retrieving absolute path failed!\n", fp)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil { return err }
|
||||
|
||||
//mapFiles contains all absolute path of files with extension ".json"
|
||||
var commonMAP *HIDKeyboardLanguageMap
|
||||
for _,mapFile := range mapFiles {
|
||||
kbdmap, lErr := loadKeyboardLanguageMapFromFile(mapFile)
|
||||
if lErr != nil {
|
||||
//Warn on error
|
||||
log.Printf("Skipping language map file '%s' due to load error: %v\n", mapFile, lErr)
|
||||
continue
|
||||
}
|
||||
if strings.ToUpper(kbdmap.Name) == "COMMON" {
|
||||
//this is the map with common keys
|
||||
//mapping in this file will be reflected to all other maps, in case the ARE NOT ALREADY PRESENT
|
||||
commonMAP = kbdmap
|
||||
} else {
|
||||
if kbd.LanguageMaps == nil {
|
||||
kbd.LanguageMaps = make(map[string]*HIDKeyboardLanguageMap)
|
||||
}
|
||||
kbd.LanguageMaps[strings.ToUpper(kbdmap.Name)] = kbdmap
|
||||
|
||||
if kbd.ActiveLanguageLayout == nil && kbdmap.Name != "COMMON" {
|
||||
kbd.ActiveLanguageLayout = kbdmap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no language maps beside "COMMON" have been loaded, return error
|
||||
if len(kbd.LanguageMaps) == 0 {
|
||||
if commonMAP == nil {
|
||||
return errors.New("Couldn't load any language map")
|
||||
} else {
|
||||
return errors.New("Couldn't load any language map, beside 'COMMON' map")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// At this point, all map files not named "COMMON" should be added to kbd.LanguageMaps
|
||||
// In case a map with name "COMMON" was found, it should be stored in commonMap
|
||||
// If commonMap was found, the contained mappings are added to the other language maps,
|
||||
// in case the dedicated mapping doesn't exist already. F.e. the mapping for "F1" is only
|
||||
// needed in map "COMMON" and added to all other maps, except they specify the "F1" mapping
|
||||
// themselves.
|
||||
if commonMAP != nil {
|
||||
//iterate over all common mappings
|
||||
for name,reports := range commonMAP.Mapping {
|
||||
//iterate over all loaded maps
|
||||
for _,lMap := range kbd.LanguageMaps {
|
||||
//check if the mapping isn't already present and add it if needed
|
||||
if _,alreadyPresent := lMap.Mapping[name]; !alreadyPresent {
|
||||
lMap.Mapping[name] = reports
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (kbd *HIDKeyboard) LoadLanguageMapFromFile(filepath string) (err error) {
|
||||
//if this is the first map loaded, set as active Map
|
||||
kbdmap, err := LoadKeyboardLanguageMapFromFile(filepath)
|
||||
kbdmap, err := loadKeyboardLanguageMapFromFile(filepath)
|
||||
if err != nil { return err }
|
||||
|
||||
if kbd.LanguageMaps == nil {
|
||||
@ -70,10 +145,11 @@ func (kbd *HIDKeyboard) LoadLanguageMapFromFile(filepath string) (err error) {
|
||||
}
|
||||
kbd.LanguageMaps[strings.ToUpper(kbdmap.Name)] = kbdmap
|
||||
|
||||
if kbd.ActiveLanguageLayout == nil {
|
||||
if kbd.ActiveLanguageLayout == nil && kbdmap.Name != "COMMON" {
|
||||
kbd.ActiveLanguageLayout = kbdmap
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -97,10 +173,56 @@ func (kbd *HIDKeyboard) SetActiveLanguageMap(name string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kbd *HIDKeyboard) SendString(str string) (err error) {
|
||||
func (kbd *HIDKeyboard) StringToPressKeyCombo(comboStr string) (err error) {
|
||||
report,err := kbd.StringToKeyCombo(comboStr)
|
||||
if err != nil { return err }
|
||||
seq := []KeyboardOutReport{*report} //convert to single report sequence
|
||||
err = kbd.PressKeySequence(seq)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
func (kbd *HIDKeyboard) StringToKeyCombo(comboStr string) (result *KeyboardOutReport, err error) {
|
||||
//ToDo: Check if keyboard device file exists
|
||||
if kbd.ActiveLanguageLayout == nil {
|
||||
return errors.New("No language mapping active, couldn't send string!")
|
||||
return nil,errors.New("No language mapping active, couldn't send key combo!")
|
||||
}
|
||||
|
||||
//split key sequence describe by string into single key names
|
||||
keyNames := rpSplit.Split(comboStr, -1)
|
||||
if len(keyNames) == 0 {
|
||||
return nil,errors.New("No keys to press")
|
||||
}
|
||||
if len(keyNames) == 1 && len(keyNames[0]) == 0 {
|
||||
return nil,errors.New("No keys to press")
|
||||
}
|
||||
|
||||
//fmt.Printf("KeyNames %d: %+v\n", len(keyNames), keyNames)
|
||||
|
||||
//try to convert splitted keynames to reports
|
||||
comboReports := make([]*KeyboardOutReport,0)
|
||||
for _,keyname := range keyNames {
|
||||
if len(keyname) == 0 { continue } //ignore empty keynames
|
||||
report,err := kbd.mapKeyNameToReport(keyname)
|
||||
if err == nil {
|
||||
//fmt.Printf("Keyname '%s' mapped to report %+v\n", keyname, report)
|
||||
comboReports = append(comboReports, report)
|
||||
} else {
|
||||
return nil,errors.New(fmt.Sprintf("Couldn't build key combo '%s' because of mapping error in keyname '%s': %v", comboStr, keyname, err))
|
||||
}
|
||||
}
|
||||
|
||||
//fmt.Printf("Combo reports for '%s': %+v\n", comboStr, comboReports)
|
||||
|
||||
//combine reports
|
||||
result,err = combineReports(comboReports)
|
||||
return
|
||||
}
|
||||
|
||||
func (kbd *HIDKeyboard) StringToPressKeySequence(str string) (err error) {
|
||||
//ToDo: Check if keyboard device file exists
|
||||
if kbd.ActiveLanguageLayout == nil {
|
||||
return errors.New("No language mapping active, couldn't send key sequence!")
|
||||
}
|
||||
for _,runeVal := range str {
|
||||
strRune := string(runeVal)
|
||||
@ -120,55 +242,102 @@ func (kbd *HIDKeyboard) SendString(str string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// mapKeyStringToReports tries to translate a key expressed by a string description to a SINGLE
|
||||
// mapKeyNameToReport tries to translate a key expressed by a string description to a SINGLE
|
||||
// report (with respect to the chosen language map), which could be sent to a keyboard device.
|
||||
// Most printable characters like 'a' or 'A' could be represented by a single rune (f.e. `a` or `A`).
|
||||
// mapKeyStringToReports translates uppercase alphabetical keys [A-Z] to the respective lower case,
|
||||
// The parameter `keyName` is of type string (instead of rune) because there're keys which
|
||||
// couldn't be described with a single rune, for example: 'F1', 'ESCAPE' ...
|
||||
//
|
||||
// mapKeyNameToReport translates uppercase alphabetical keys [A-Z] to the respective lower case,
|
||||
// before trying to map, in order to avoid fetching reports with [SHIFT] modifiers (this assures
|
||||
// that 'A' gets mapped to the USB key KEY_A, not to the USB key KEY_A combined with the [SHIFT]
|
||||
// modifier).
|
||||
// The parameter `keyDescription` is of type string (instead of rune) because there're keys which
|
||||
// couldn't be described with a single rune, for example: 'F1', 'ESCAPE' ...
|
||||
//
|
||||
// mapKeyStringToReports could return a report, containing only modifiers (f.e. if
|
||||
// keyDescription = 'CTRL'). Such reports could be used to build KeyCombos, by mixing them together.
|
||||
// There're result reports containing only modifiers (f.e. if keyName = 'CTRL'). Such reports could be used
|
||||
// to build KeyCombos, by mixing them together.
|
||||
//
|
||||
// The language maps could contain mappings, containing multiple reports, as they sometime represent
|
||||
// printable runes consisting of a sequence of multiple keys (f.e. `^` in the German layout maps
|
||||
// to a report slice of the key for [^] followed by the key [SPACE], which is needed to print the character).
|
||||
// mapKeyStringToReports returns ONLY THE FIRST REPORT of such slices, as this is closer to the representation.
|
||||
// Additionally, single reports could be combimned into a key-combo, which wouldn't be possible with a ordered
|
||||
// sequence of reports.
|
||||
func (kbd *HIDKeyboard) TmapKeyStringToReports(keyDescription string) (report *KeyboardOutReport,err error) {
|
||||
// Assure keyDescription contains no spaces, else error
|
||||
r := rpSplit.Split(keyDescription, -1)
|
||||
// The language maps consist mappings from UTF-8 runes to reports sequences and keyNames to single reports.
|
||||
// Examples for sequences are mostly printable runes which are built from multiple sequential key presses
|
||||
// (mostly started with DEAD KEYS) like the `^` rune on a german keyboard layout, which has to be created by
|
||||
// pressing [^] followed by [SPACE].
|
||||
// The purpose of mapKeyNameToReport is to resolve the given keyname to A SINGLE REPORT, thus report sequences
|
||||
// are truncated to the first report only, before returned. This is the trade-off between assuring to return a
|
||||
// single report per keyname versus managing separated mapping files for rune-mapping and key-mapping.
|
||||
func (kbd *HIDKeyboard) mapKeyNameToReport(keyName string) (report *KeyboardOutReport,err error) {
|
||||
// Assure keyName contains no spaces, else error
|
||||
r := rpSplit.Split(keyName, -1)
|
||||
if len(r) > 1 {
|
||||
return nil, errors.New("keyDescription mustn't contain spaces")
|
||||
return nil, errors.New(fmt.Sprintf("Error mapping keyName '%s', unallowed contains spaces!", keyName))
|
||||
}
|
||||
keyDescription = strings.ToUpper(r[0]) //reassign trimmed, upper case version
|
||||
keyName = strings.ToUpper(r[0]) //reassign trimmed, upper case version
|
||||
|
||||
|
||||
// If keyDescription consists of a single upper case letter, translate to lowercase
|
||||
if rpSingleUpperLetter.MatchString(keyDescription) { keyDescription = strings.ToLower(keyDescription)}
|
||||
// If keyName consists of a single upper case letter, translate to lowercase
|
||||
if rpSingleUpperLetter.MatchString(keyName) { keyName = strings.ToLower(keyName)}
|
||||
|
||||
// Try to find a matching mapping in 1) current language map, followed by 2) common map (the latter
|
||||
// holds mappings like 'F1', 'CTRL' etc which are more or less language independent. The common
|
||||
// map is only accessed, if there was no successful mapping in the chosen language map (priority
|
||||
// as more specialized)
|
||||
c,ok := kbd.LanguageMaps["COMMON"]
|
||||
if !ok { return nil,errors.New("Keyboardmap 'common' not found")}
|
||||
common := c.Mapping
|
||||
|
||||
reports := common[keyDescription]
|
||||
if len(reports) > 1 {
|
||||
//store first report as result
|
||||
report = &reports[0]
|
||||
// Try to find a matching mapping in current language map
|
||||
if kbd.ActiveLanguageLayout == nil {
|
||||
return nil, errors.New("No language mapping selected")
|
||||
}
|
||||
if reports,found := kbd.ActiveLanguageLayout.Mapping[keyName]; found {
|
||||
//report(s) found, return only first one
|
||||
if len(reports) > 0 {
|
||||
return &reports[0], nil
|
||||
} else {
|
||||
return nil, errors.New(fmt.Sprintf("Mapping for key '%s' found in language map named '%s', but mapping is empty!", keyName, kbd.ActiveLanguageLayout.Name))
|
||||
}
|
||||
} else {
|
||||
return nil, errors.New(fmt.Sprintf("Couldn't find mapping for key '%s' in language map named '%s'!", keyName, kbd.ActiveLanguageLayout.Name))
|
||||
}
|
||||
|
||||
fmt.Printf("Descr '%s': %+v\n", keyDescription, )
|
||||
return
|
||||
}
|
||||
|
||||
// combineReports combines a slice of output reports into a single report (for key combinations).
|
||||
// The following rules apply:
|
||||
// 1) Modifiers are combined with logical or
|
||||
// 2) Unique keys are filled into the keys array, one-by-one
|
||||
// 3) Duplicated keys are ignore
|
||||
// 4) Only the first 6 keys are regarded (without duplicates), the rest is ignored
|
||||
func combineReports(reports []*KeyboardOutReport) (result *KeyboardOutReport, err error) {
|
||||
r := KeyboardOutReport{}
|
||||
keys := make(map[byte]bool)
|
||||
keyCount := 0
|
||||
maxKeys := 6
|
||||
|
||||
ADDREPORTLOOP:
|
||||
for _,report := range reports {
|
||||
//Add modifiers
|
||||
r.Modifiers |= report.Modifiers
|
||||
|
||||
// add keys to map
|
||||
// Note: This could be interrupted in the middle of a report if too many keys are contained, while the
|
||||
// modifiers of this report are already applied. This is a corner case, we don't take care of (happens f.e.
|
||||
// if the first report contains 2 keys and the second one 6 keys with modifiers)
|
||||
for _,key := range report.Keys {
|
||||
if key != 0 { //Ignore "no key"
|
||||
if !keys[key] {
|
||||
keys[key] = true
|
||||
keyCount++
|
||||
if keyCount >= maxKeys {
|
||||
break ADDREPORTLOOP
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//keys should contain maxKeys at max
|
||||
keyCount = 0
|
||||
for k,_ := range keys {
|
||||
r.Keys[keyCount] = k
|
||||
keyCount++
|
||||
if keyCount >= maxKeys { break }
|
||||
}
|
||||
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
// PressKeySequence writes the output reports given in `reports` to the keyboard device in sequential
|
||||
// order. A all empty report is automatically appended in order to release all keys after finishing
|
||||
// the sequence (press in contrast to hold).
|
||||
@ -224,7 +393,7 @@ func (klm *HIDKeyboardLanguageMap) StoreToFile(filePath string) (err error) {
|
||||
return ioutil.WriteFile(filePath, mapJson, os.ModePerm)
|
||||
}
|
||||
|
||||
func LoadKeyboardLanguageMapFromFile(filePath string) (result *HIDKeyboardLanguageMap, err error) {
|
||||
func loadKeyboardLanguageMapFromFile(filePath string) (result *HIDKeyboardLanguageMap, err error) {
|
||||
result = &HIDKeyboardLanguageMap{}
|
||||
mapJson, err := ioutil.ReadFile(filePath)
|
||||
if err != nil { return nil,err }
|
||||
@ -316,6 +485,15 @@ func (kr *KeyboardOutReport) UnmarshalJSON(b []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kr KeyboardOutReport) String() string {
|
||||
bytes,err := kr.MarshalJSON()
|
||||
if err == nil {
|
||||
return string(bytes)
|
||||
} else {
|
||||
return fmt.Sprintf("%+v", kr) //ToDo: check if this works or calls a loop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (kr *KeyboardOutReport) MarshalJSON() ([]byte, error) {
|
||||
keys := []string{}
|
||||
|
@ -68,8 +68,24 @@
|
||||
"NUM": [{"Modifiers": [], "Keys": ["KEY_NUMLOCK"]}],
|
||||
"CAPSLOCK": [{"Modifiers": [], "Keys": ["KEY_CAPSLOCK"]}],
|
||||
"CAPS": [{"Modifiers": [], "Keys": ["KEY_CAPSLOCK"]}],
|
||||
"TABULATOR": [{"Modifiers": [], "Keys": ["KEY_TAB"]}],
|
||||
"TAB": [{"Modifiers": [], "Keys": ["KEY_TAB"]}],
|
||||
|
||||
"COMPOSE": [{"Modifiers": [], "Keys": ["KEY_COMPOSE"]}],
|
||||
"102ND": [{"Modifiers": [], "Keys": ["KEY_102ND"]}]
|
||||
}
|
||||
"102ND": [{"Modifiers": [], "Keys": ["KEY_102ND"]}],
|
||||
|
||||
"F13": [{"Modifiers": [], "Keys": ["KEY_F13"]}],
|
||||
"F14": [{"Modifiers": [], "Keys": ["KEY_F14"]}],
|
||||
"F15": [{"Modifiers": [], "Keys": ["KEY_F15"]}],
|
||||
"F16": [{"Modifiers": [], "Keys": ["KEY_F16"]}],
|
||||
"F17": [{"Modifiers": [], "Keys": ["KEY_F17"]}],
|
||||
"F18": [{"Modifiers": [], "Keys": ["KEY_F18"]}],
|
||||
"F19": [{"Modifiers": [], "Keys": ["KEY_F19"]}],
|
||||
"F20": [{"Modifiers": [], "Keys": ["KEY_F20"]}],
|
||||
"F21": [{"Modifiers": [], "Keys": ["KEY_F21"]}],
|
||||
"F22": [{"Modifiers": [], "Keys": ["KEY_F22"]}],
|
||||
"F23": [{"Modifiers": [], "Keys": ["KEY_F23"]}],
|
||||
"F24": [{"Modifiers": [], "Keys": ["KEY_F24"]}]
|
||||
|
||||
}
|
||||
}
|
||||
|
46
testhid.go
46
testhid.go
@ -51,7 +51,7 @@ func main() {
|
||||
err := mapDeASCII.StoreToFile("/tmp/DE_ASCII.json")
|
||||
if err != nil { log.Fatal(err)}
|
||||
|
||||
testmap, err := hid.LoadKeyboardLanguageMapFromFile("keymaps/DE_ASCII.json")
|
||||
testmap, err := hid.loadKeyboardLanguageMapFromFile("keymaps/DE_ASCII.json")
|
||||
if err != nil { log.Fatal(err)}
|
||||
fmt.Println(testmap)
|
||||
*/
|
||||
@ -59,16 +59,25 @@ func main() {
|
||||
hidCtl, err := hid.NewHIDController("/dev/hidg0", "keymaps", "")
|
||||
if err != nil {panic(err)}
|
||||
|
||||
_,err = hidCtl.Keyboard.TmapKeyStringToReports("INS")
|
||||
if err != nil {panic(err)}
|
||||
_,err = hidCtl.Keyboard.TmapKeyStringToReports("F1")
|
||||
if err != nil {panic(err)}
|
||||
_,err = hidCtl.Keyboard.TmapKeyStringToReports("F13")
|
||||
if err != nil {panic(err)}
|
||||
_,err = hidCtl.Keyboard.TmapKeyStringToReports(" F3 ")
|
||||
if err != nil {panic(err)}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Chosen keyboard language mapping '%s'\n", hidCtl.Keyboard.ActiveLanguageLayout.Name)
|
||||
|
||||
|
||||
|
||||
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)
|
||||
|
||||
//ToDo: Test multiple waits in separate goroutines
|
||||
@ -122,17 +131,22 @@ func main() {
|
||||
|
||||
// ascii := " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
||||
// special := "§°üÜöÖäĵ€ß¹²³⁴⁵⁶⁷⁸⁹⁰¼½¬„“¢«»æſðđŋħĸł’¶ŧ←↓→øþ"
|
||||
// err = keyboard.SendString("Test:" + ascii + "\t" + special)
|
||||
// err = keyboard.StringToPressKeySequence("Test:" + ascii + "\t" + special)
|
||||
if err != nil { fmt.Println(err)}
|
||||
|
||||
script := `
|
||||
kString(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_abcdefghijklmnopqrstuvwxyz{|}~");
|
||||
kString("\n")
|
||||
kString("Waiting 500ms ...\n");
|
||||
for (i=0; i<10; i++) {
|
||||
press("CAPS")
|
||||
delay(500)
|
||||
}
|
||||
|
||||
type(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_abcdefghijklmnopqrstuvwxyz{|}~");
|
||||
type("\n")
|
||||
type("Waiting 500ms ...\n");
|
||||
delay(500)
|
||||
kString("... done\n");
|
||||
kString("§°üÜöÖäĵ€ß¹²³⁴⁵⁶⁷⁸⁹⁰¼½¬„“¢«»æſðđŋħĸł’¶ŧ←↓→øþ");
|
||||
kString("\n")
|
||||
type("... done\n");
|
||||
type("§°üÜöÖäĵ€ß¹²³⁴⁵⁶⁷⁸⁹⁰¼½¬„“¢«»æſðđŋħĸł’¶ŧ←↓→øþ");
|
||||
type("\n")
|
||||
|
||||
console.log("Log message from JS");
|
||||
`
|
||||
|
Loading…
x
Reference in New Issue
Block a user