First HID keyboard tests

This commit is contained in:
mame82 2018-05-29 20:26:30 +00:00
parent 69ee0c4769
commit 45395e761b
6 changed files with 502 additions and 302 deletions

View File

@ -1,13 +1,132 @@
package hid
import (
"encoding/json"
"log"
"errors"
"io/ioutil"
"os"
"log"
"strings"
"fmt"
"time"
"math/rand"
)
var (
KeyboardReportEmpty = NewKeyboardOutReport(0)
)
func init() {
rand.Seed(time.Now().UnixNano())
}
type HIDKeyboard struct {
DevicePath string
ActiveLanguageLayout *HIDKeyboardLanguageMap
LanguageMaps map[string]*HIDKeyboardLanguageMap //available language maps
KeyDelay int
KeyDelayJitter int
}
func (kbd *HIDKeyboard) LoadLanguageMapFromFile(filepath string) (err error) {
//if this is the first map loaded, set as active Map
kbdmap, err := LoadKeyboardLanguageMapFromFile(filepath)
if err != nil { return err }
if kbd.LanguageMaps == nil {
kbd.LanguageMaps = make(map[string]*HIDKeyboardLanguageMap)
}
kbd.LanguageMaps[strings.ToUpper(kbdmap.Name)] = kbdmap
if kbd.ActiveLanguageLayout == nil {
kbd.ActiveLanguageLayout = kbdmap
}
return nil
}
func (kbd HIDKeyboard) ListLanguageMapNames() (mapNames []string) {
mapNames = make([]string, len(kbd.LanguageMaps))
i := 0
for k := range kbd.LanguageMaps {
mapNames[i] = k
i++
}
return mapNames
}
func (kbd *HIDKeyboard) SetActiveLanguageMap(name string) (err error) {
if m, ok := kbd.LanguageMaps[strings.ToUpper(name)]; ok {
kbd.ActiveLanguageLayout = m
} else {
return errors.New(fmt.Sprintf("Language map with name '%s' isn't loaded!", name))
}
return nil
}
func (kbd *HIDKeyboard) SendString(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 string!")
}
for _,runeVal := range str {
strRune := string(runeVal)
if reports,found := kbd.ActiveLanguageLayout.Mapping[strRune]; found {
//log.Printf("Sending reports (%T): %v\n", reports, reports)
err = kbd.PressKeyCombo(reports)
if err != nil {
//Abort typing
return err
}
} else {
log.Printf("HID keyboard warning: Couldn't send charcter '%q' (0x%x) because it is not defined in language map '%s', skipping ...", strRune, strRune, kbd.ActiveLanguageLayout.Name)
}
}
return nil
}
func (kbd *HIDKeyboard) PressKeyCombo(reports []KeyboardOutReport) (err error) {
//iterate over reports and send them
for _,rep := range reports {
err = rep.WriteTo(kbd.DevicePath)
if err != nil { return err }
}
//append an empty report to release all keys
err = KeyboardReportEmpty.WriteTo(kbd.DevicePath)
if err != nil { return err }
//Delay after keypress
delay := kbd.KeyDelay
if kbd.KeyDelayJitter > 0 { delay += rand.Intn(kbd.KeyDelayJitter)}
if delay > 0 { time.Sleep(time.Millisecond * time.Duration(delay)) }
return nil
}
type HIDKeyboardLanguageMap struct {
Name string
Description string
Mapping map[string][]KeyboardOutReport
}
func (klm *HIDKeyboardLanguageMap) StoreToFile(filePath string) (err error) {
//create JSON representation
mapJson, err := json.MarshalIndent(klm, "", "\t")
if err != nil { return err }
//Write to file
return ioutil.WriteFile(filePath, mapJson, os.ModePerm)
}
func LoadKeyboardLanguageMapFromFile(filePath string) (result *HIDKeyboardLanguageMap, err error) {
result = &HIDKeyboardLanguageMap{}
mapJson, err := ioutil.ReadFile(filePath)
if err != nil { return nil,err }
err = json.Unmarshal(mapJson, result)
return
}
type KeyboardOutReport struct {
Modifiers byte
@ -15,6 +134,120 @@ type KeyboardOutReport struct {
Keys [6]byte
}
func (kr *KeyboardOutReport) UnmarshalJSON(b []byte) error {
var o interface{}
if err := json.Unmarshal(b,&o); err != nil {
return err
}
m := o.(map[string]interface{})
for k,v := range m {
//log.Printf("key: %v, val %v (%T)\n", k, v, v)
switch strings.ToLower(k) {
case "modifiers":
switch vv := v.(type) {
case []interface{}:
for _, modValIface := range vv {
//convert modifier back from string to uint8 representation
switch modVal := modValIface.(type) {
case string:
if modInt, ok := StringToUsbModKey[modVal]; ok {
kr.Modifiers |= modInt
} else {
return errors.New(fmt.Sprintf("The value '%s' couldn't be translated to a valid modifier key\n", modVal))
}
//log.Printf("Mod: %v (%T)", modVal, modVal)
case float64:
modInt := uint8(modVal)
if _,ok := UsbModKeyToString[modInt]; !ok && modInt != 0 {
return errors.New(fmt.Sprintf("The value '%v' isn't valid for a modifier key\n", modVal))
}
kr.Modifiers |= modInt
default:
return errors.New(fmt.Sprintf("The value '%v' of type '%T' isn't a valid type for a modifier key\n", modVal, modVal))
}
}
default:
return errors.New(fmt.Sprintf("Unintended type for 'Modifiers', has to be array of modifier strings, but %v was given\n", vv))
}
case "keys":
switch vv := v.(type) {
case []interface{}:
for i, keyValIface := range vv {
if i > len(kr.Keys) - 1 {
return errors.New(fmt.Sprintf("The key '%v' at index %d exceeds the maximum key count per report, which is 6!\n", keyValIface, i))
}
switch keyVal := keyValIface.(type) {
case string:
if keyInt, ok := StringToUsbKey[keyVal]; ok {
kr.Keys[i] = keyInt
} else {
return errors.New(fmt.Sprintf("The value '%s' couldn't be translated to a valid key\n", keyVal))
}
//log.Printf("Key '%s' (%T) at index %d\n", keyVal, keyVal, i)
case float64:
keyInt := uint8(keyVal)
if _,ok := UsbKeyToString[keyInt]; !ok && keyInt != 0 {
return errors.New(fmt.Sprintf("The value '%v' isn't valid for a key\n", keyVal))
}
kr.Keys[i] = keyInt
default:
return errors.New(fmt.Sprintf("The value '%v' of type '%T' at index %d isn't a valid type for a key array\n", keyVal, keyVal, i))
}
}
default:
return errors.New(fmt.Sprintf("Unintended type in for 'Keys', has to be array of key strings, but %v was given\n", vv))
}
}
}
return nil
}
func (kr *KeyboardOutReport) MarshalJSON() ([]byte, error) {
keys := []string{}
modifiers := []string{}
if kr.Modifiers & HID_MOD_KEY_LEFT_CONTROL > 0 { modifiers = append(modifiers, UsbModKeyToString[HID_MOD_KEY_LEFT_CONTROL]) }
if kr.Modifiers & HID_MOD_KEY_LEFT_SHIFT > 0 { modifiers = append(modifiers, UsbModKeyToString[HID_MOD_KEY_LEFT_SHIFT]) }
if kr.Modifiers & HID_MOD_KEY_LEFT_ALT > 0 { modifiers = append(modifiers, UsbModKeyToString[HID_MOD_KEY_LEFT_ALT]) }
if kr.Modifiers & HID_MOD_KEY_LEFT_GUI > 0 { modifiers = append(modifiers, UsbModKeyToString[HID_MOD_KEY_LEFT_GUI]) }
if kr.Modifiers & HID_MOD_KEY_RIGHT_CONTROL > 0 { modifiers = append(modifiers, UsbModKeyToString[HID_MOD_KEY_RIGHT_CONTROL]) }
if kr.Modifiers & HID_MOD_KEY_RIGHT_SHIFT > 0 { modifiers = append(modifiers, UsbModKeyToString[HID_MOD_KEY_RIGHT_SHIFT]) }
if kr.Modifiers & HID_MOD_KEY_RIGHT_ALT > 0 { modifiers = append(modifiers, UsbModKeyToString[HID_MOD_KEY_RIGHT_ALT]) }
if kr.Modifiers & HID_MOD_KEY_RIGHT_GUI > 0 { modifiers = append(modifiers, UsbModKeyToString[HID_MOD_KEY_RIGHT_GUI]) }
for _,key := range kr.Keys {
if key == 0 {break} //abort on first 0x00 key code
if keyStr, ok := UsbKeyToString[uint8(key)]; ok {
keys = append(keys, keyStr)
//log.Println(keyStr)
} else {
log.Printf("Warning: No string representation for USB key with value '%d', key ignored during JSON marshaling.\n", key)
}
}
result := struct{
Modifiers []string
Keys []string
}{
Keys:keys,
Modifiers:modifiers,
}
return json.Marshal(result)
}
func (rep KeyboardOutReport) Serialize() (out []byte) {
out = []byte {
rep.Modifiers,
@ -66,25 +299,3 @@ func NewKeyboardOutReport(modifiers byte, keys ...byte) (res KeyboardOutReport)
}
return
}
func Test() {
filepath := "/dev/hidg0"
kbdRepEmpty := NewKeyboardOutReport(0)
kbdRep_a := NewKeyboardOutReport(0, HID_KEY_A)
kbdRep_A := NewKeyboardOutReport(HID_MOD_KEY_LEFT_SHIFT, HID_KEY_A)
err := kbdRepEmpty.WriteTo(filepath)
if err != nil {log.Fatal(err)}
err = kbdRep_a.WriteTo(filepath)
if err != nil {log.Fatal(err)}
err = kbdRepEmpty.WriteTo(filepath)
if err != nil {log.Fatal(err)}
err = kbdRep_A.WriteTo(filepath)
if err != nil {log.Fatal(err)}
err = kbdRepEmpty.WriteTo(filepath)
if err != nil {log.Fatal(err)}
err = kbdRep_A.WriteTo(filepath)
if err != nil {log.Fatal(err)}
err = kbdRepEmpty.WriteTo(filepath)
if err != nil {log.Fatal(err)}
}

View File

@ -321,10 +321,10 @@ const (
)
var (
UsbKeyToString = generateKey2Str()
String2UsbKey = generateStr2Key()
UsbKeyToString = generateKey2Str()
StringToUsbKey = generateStr2Key()
UsbModKeyToString = generateMod2Str()
String2UsbModKey = generateStr2Mod()
StringToUsbModKey = generateStr2Mod()
)
func generateMod2Str() (m2s map[uint8]string) {

View File

@ -1,276 +0,0 @@
package keymaps
import (
".."
)
var (
ascii_de = map[string][]byte {
"\t": hid.NewKeyboardOutReport(0, hid.HID_KEY_TAB).Serialize(),
"\n": hid.NewKeyboardOutReport(0, hid.HID_KEY_ENTER).Serialize(),
" ": hid.NewKeyboardOutReport(0, hid.HID_KEY_SPACE).Serialize(),
"!": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_1).Serialize(),
"\"": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_2).Serialize(),
"#": hid.NewKeyboardOutReport(0, hid.HID_KEY_BACKSLASH).Serialize(),
"$": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_4).Serialize(),
"%": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_5).Serialize(),
"&": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_6).Serialize(),
"'": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_BACKSLASH).Serialize(),
"(": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_8).Serialize(),
")": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_9).Serialize(),
"*": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_RIGHTBRACE).Serialize(),
"+": hid.NewKeyboardOutReport(0, hid.HID_KEY_RIGHTBRACE).Serialize(),
",": hid.NewKeyboardOutReport(0, hid.HID_KEY_COMMA).Serialize(),
"-": hid.NewKeyboardOutReport(0, hid.HID_KEY_SLASH).Serialize(),
".": hid.NewKeyboardOutReport(0, hid.HID_KEY_DOT).Serialize(),
"/": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_7).Serialize(),
"0": hid.NewKeyboardOutReport(0, hid.HID_KEY_0).Serialize(),
"1": hid.NewKeyboardOutReport(0, hid.HID_KEY_1).Serialize(),
"2": hid.NewKeyboardOutReport(0, hid.HID_KEY_2).Serialize(),
"3": hid.NewKeyboardOutReport(0, hid.HID_KEY_3).Serialize(),
"4": hid.NewKeyboardOutReport(0, hid.HID_KEY_4).Serialize(),
"5": hid.NewKeyboardOutReport(0, hid.HID_KEY_5).Serialize(),
"6": hid.NewKeyboardOutReport(0, hid.HID_KEY_6).Serialize(),
"7": hid.NewKeyboardOutReport(0, hid.HID_KEY_7).Serialize(),
"8": hid.NewKeyboardOutReport(0, hid.HID_KEY_8).Serialize(),
"9": hid.NewKeyboardOutReport(0, hid.HID_KEY_9).Serialize(),
":": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_DOT).Serialize(),
";": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_COMMA).Serialize(),
"<": hid.NewKeyboardOutReport(0, hid.HID_KEY_102ND).Serialize(),
"=": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_0).Serialize(),
">": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_102ND).Serialize(),
"?": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_MINUS).Serialize(),
"@": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_RIGHT_ALT, hid.HID_KEY_Q).Serialize(),
"A": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_A).Serialize(),
"B": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_B).Serialize(),
"C": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_C).Serialize(),
"D": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_D).Serialize(),
"E": hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_E).Serialize(),
}
)
/*
ASCII_41 = KEY_A, MODIFIERKEY_SHIFT
// 65 A
ASCII_42 = KEY_B, MODIFIERKEY_SHIFT
// 66 B
ASCII_43 = KEY_C, MODIFIERKEY_SHIFT
// 67 C
ASCII_44 = KEY_D, MODIFIERKEY_SHIFT
// 68 D
ASCII_45 = KEY_E, MODIFIERKEY_SHIFT
// 69 E
ASCII_46 = KEY_F, MODIFIERKEY_SHIFT
// 70 F
ASCII_47 = KEY_G, MODIFIERKEY_SHIFT
// 71 G
ASCII_48 = KEY_H, MODIFIERKEY_SHIFT
// 72 H
ASCII_49 = KEY_I, MODIFIERKEY_SHIFT
// 73 I
ASCII_4A = KEY_J, MODIFIERKEY_SHIFT
// 74 J
ASCII_4B = KEY_K, MODIFIERKEY_SHIFT
// 75 K
ASCII_4C = KEY_L, MODIFIERKEY_SHIFT
// 76 L
ASCII_4D = KEY_M, MODIFIERKEY_SHIFT
// 77 M
ASCII_4E = KEY_N, MODIFIERKEY_SHIFT
// 78 N
ASCII_4F = KEY_O, MODIFIERKEY_SHIFT
// 79 O
ASCII_50 = KEY_P, MODIFIERKEY_SHIFT
// 80 P
ASCII_51 = KEY_Q, MODIFIERKEY_SHIFT
// 81 Q
ASCII_52 = KEY_R, MODIFIERKEY_SHIFT
// 82 R
ASCII_53 = KEY_S, MODIFIERKEY_SHIFT
// 83 S
ASCII_54 = KEY_T, MODIFIERKEY_SHIFT
// 84 T
ASCII_55 = KEY_U, MODIFIERKEY_SHIFT
// 85 U
ASCII_56 = KEY_V, MODIFIERKEY_SHIFT
// 86 V
ASCII_57 = KEY_W, MODIFIERKEY_SHIFT
// 87 W
ASCII_58 = KEY_X, MODIFIERKEY_SHIFT
// 88 X
ASCII_59 = KEY_Z, MODIFIERKEY_SHIFT
// 89 Y
ASCII_5A = KEY_Y, MODIFIERKEY_SHIFT
// 90 Z
ASCII_5B = KEY_8, MODIFIERKEY_RIGHT_ALT
// 91 [
ASCII_5C = KEY_MINUS, MODIFIERKEY_RIGHT_ALT
// 92
ASCII_5D = KEY_9, MODIFIERKEY_RIGHT_ALT
// 93 ]
ASCII_5E = KEY_TILDE
// 94 ^
ASCII_5F = KEY_SLASH, MODIFIERKEY_SHIFT
// 95 _
ASCII_60 = KEY_EQUAL, MODIFIERKEY_SHIFT
//GRAVE_ACCENT_BITS + KEY_SPACE
// 96 `
ASCII_61 = KEY_A
// 97 a
ASCII_62 = KEY_B
// 98 b
ASCII_63 = KEY_C
// 99 c
ASCII_64 = KEY_D
// 100 d
ASCII_65 = KEY_E
// 101 e
ASCII_66 = KEY_F
// 102 f
ASCII_67 = KEY_G
// 103 g
ASCII_68 = KEY_H
// 104 h
ASCII_69 = KEY_I
// 105 i
ASCII_6A = KEY_J
// 106 j
ASCII_6B = KEY_K
// 107 k
ASCII_6C = KEY_L
// 108 l
ASCII_6D = KEY_M
// 109 m
ASCII_6E = KEY_N
// 110 n
ASCII_6F = KEY_O
// 111 o
ASCII_70 = KEY_P
// 112 p
ASCII_71 = KEY_Q
// 113 q
ASCII_72 = KEY_R
// 114 r
ASCII_73 = KEY_S
// 115 s
ASCII_74 = KEY_T
// 116 t
ASCII_75 = KEY_U
// 117 u
ASCII_76 = KEY_V
// 118 v
ASCII_77 = KEY_W
// 119 w
ASCII_78 = KEY_X
// 120 x
ASCII_79 = KEY_Z
// 121 y
ASCII_7A = KEY_Y
// 122 z
ASCII_7B = KEY_7, MODIFIERKEY_RIGHT_ALT
// 123 {
ASCII_7C = KEY_NON_US_100, MODIFIERKEY_RIGHT_ALT
// 124 |
ASCII_7D = KEY_0, MODIFIERKEY_RIGHT_ALT
// 125 }
ASCII_7E = KEY_RIGHT_BRACE, MODIFIERKEY_RIGHT_ALT
// 126 ~
ASCII_7F = KEY_BACKSPACE
// 127
ISO_8859_1_A0 = KEY_SPACE
// 160 Nonbreakng Space
ISO_8859_1_A4 = KEY_E, MODIFIERKEY_RIGHT_ALT
// 164 ¤ Currency Sign
ISO_8859_1_A7 = KEY_3, MODIFIERKEY_SHIFT
// 167 § SECTION SIGN
ISO_8859_1_B0 = KEY_TILDE, MODIFIERKEY_SHIFT
// 176 ° DEGREE SIGN
ISO_8859_1_B2 = KEY_2, MODIFIERKEY_RIGHT_ALT
// 178 ² SUPERSCRIPT TWO
ISO_8859_1_B3 = KEY_3, MODIFIERKEY_RIGHT_ALT
// 179 ³ SUPERSCRIPT THREE
//ISO_8859_1_C0 = GRAVE_ACCENT_BITS + KEY_A, MODIFIERKEY_SHIFT
// 192 À A GRAVE
//ISO_8859_1_C1 = ACUTE_ACCENT_BITS + KEY_A, MODIFIERKEY_SHIFT
// 193 Á A ACUTE
//ISO_8859_1_C2 = CIRCUMFLEX_BITS = + KEY_A, MODIFIERKEY_SHIFT
// 194 Â A CIRCUMFLEX
ISO_8859_1_C4 = KEY_QUOTE, MODIFIERKEY_SHIFT
// 196 Ä A DIAERESIS
//ISO_8859_1_C8 = GRAVE_ACCENT_BITS + KEY_E, MODIFIERKEY_SHIFT
// 200 È E GRAVE
//ISO_8859_1_C9 = ACUTE_ACCENT_BITS + KEY_E, MODIFIERKEY_SHIFT
// 201 É E ACUTE
//ISO_8859_1_CA = CIRCUMFLEX_BITS + KEY_E, MODIFIERKEY_SHIFT
// 202 Ê E CIRCUMFLEX
//ISO_8859_1_CC = GRAVE_ACCENT_BITS + KEY_I, MODIFIERKEY_SHIFT
// 204 Ì I GRAVE
//ISO_8859_1_CD = ACUTE_ACCENT_BITS + KEY_I, MODIFIERKEY_SHIFT
// 205 Í I ACUTE
//ISO_8859_1_CE = CIRCUMFLEX_BITS + KEY_I, MODIFIERKEY_SHIFT
// 206 Î I CIRCUMFLEX
//ISO_8859_1_D2 = GRAVE_ACCENT_BITS + KEY_O, MODIFIERKEY_SHIFT
// 210 Ò O GRAVE
//ISO_8859_1_D3 = ACUTE_ACCENT_BITS + KEY_O, MODIFIERKEY_SHIFT
// 211 Ó O ACUTE
//ISO_8859_1_D4 = CIRCUMFLEX_BITS + KEY_O, MODIFIERKEY_SHIFT
// 212 Ô O CIRCUMFLEX
ISO_8859_1_D6 = KEY_SEMICOLON, MODIFIERKEY_SHIFT
// 214 Ö O DIAERESIS
//ISO_8859_1_D9 = GRAVE_ACCENT_BITS + KEY_U, MODIFIERKEY_SHIFT
// 217 Ù U GRAVE
//ISO_8859_1_DA = ACUTE_ACCENT_BITS + KEY_U, MODIFIERKEY_SHIFT
// 218 Ú U ACUTE
//ISO_8859_1_DB = CIRCUMFLEX_BITS + KEY_U, MODIFIERKEY_SHIFT
// 219 Û U CIRCUMFLEX
ISO_8859_1_DC = KEY_LEFT_BRACE, MODIFIERKEY_SHIFT
// 220 Ü U DIAERESIS
//ISO_8859_1_DD = ACUTE_ACCENT_BITS + KEY_Z, MODIFIERKEY_SHIFT
// 221 Ý Y ACUTE
ISO_8859_1_DF = KEY_MINUS
// 223 ß SHARP S
//ISO_8859_1_E0 = GRAVE_ACCENT_BITS + KEY_A
// 224 à a GRAVE
//ISO_8859_1_E1 = ACUTE_ACCENT_BITS + KEY_A
// 225 á a ACUTE
//ISO_8859_1_E2 = CIRCUMFLEX_BITS + KEY_A
// 226 â a CIRCUMFLEX
ISO_8859_1_E4 = KEY_QUOTE
// 228 ä a DIAERESIS
//ISO_8859_1_E8 = GRAVE_ACCENT_BITS + KEY_E
// 232 è e GRAVE
//ISO_8859_1_E9 = ACUTE_ACCENT_BITS + KEY_E
// 233 é e ACUTE
//ISO_8859_1_EA = CIRCUMFLEX_BITS + KEY_E
// 234 ê e CIRCUMFLEX
//ISO_8859_1_EC = GRAVE_ACCENT_BITS + KEY_I
// 236 ì i GRAVE
//ISO_8859_1_ED = ACUTE_ACCENT_BITS + KEY_I
// 237 í i ACUTE
//ISO_8859_1_EE = CIRCUMFLEX_BITS + KEY_I
// 238 î i CIRCUMFLEX
//ISO_8859_1_F2 = GRAVE_ACCENT_BITS + KEY_O
// 242 ò o GRAVE
//ISO_8859_1_F3 = ACUTE_ACCENT_BITS + KEY_O
// 243 ó o ACUTE
//ISO_8859_1_F4 = CIRCUMFLEX_BITS + KEY_O
// 244 ô o CIRCUMFLEX
ISO_8859_1_F6 = KEY_SEMICOLON
// 246 ö o DIAERESIS
//ISO_8859_1_F9 = GRAVE_ACCENT_BITS + KEY_U
// 249 ù u GRAVE
//ISO_8859_1_FA = ACUTE_ACCENT_BITS + KEY_U
// 250 ú u ACUTE
//ISO_8859_1_FB = CIRCUMFLEX_BITS + KEY_U
// 251 û u CIRCUMFLEX
ISO_8859_1_FC = KEY_LEFT_BRACE
// 252 ü u DIAERESIS
//ISO_8859_1_FD = ACUTE_ACCENT_BITS + KEY_Z
// 253 ý y ACUTE
UNICODE_20AC = KEY_E, MODIFIERKEY_RIGHT_ALT
// € Euro Sign
*/

158
keymaps/DE_ASCII.json Executable file
View File

@ -0,0 +1,158 @@
{
"Name": "DE",
"Description": "German ASCII to USB Keyboard report mapping",
"Mapping": {
"\t": [{"Modifiers": [], "Keys": ["KEY_TAB"]}],
"\n": [{"Modifiers": [], "Keys": ["KEY_ENTER"]}],
" ": [{"Modifiers": [], "Keys": ["KEY_SPACE"]}],
"!": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_1"]}],
"\"": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_2"]}],
"#": [{"Modifiers": [], "Keys": ["KEY_BACKSLASH"]}],
"$": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_4"]}],
"%": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_5"]}],
"&": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_6"]}],
"'": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_BACKSLASH"]}],
"(": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_8"]}],
")": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_9"]}],
"*": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_RIGHTBRACE"]}],
"+": [{"Modifiers": [], "Keys": ["KEY_RIGHTBRACE"]}],
",": [{"Modifiers": [], "Keys": ["KEY_COMMA"]}],
"-": [{"Modifiers": [], "Keys": ["KEY_SLASH"]}],
".": [{"Modifiers": [], "Keys": ["KEY_DOT"]}],
"/": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_7"]}],
"0": [{"Modifiers": [], "Keys": ["KEY_0"]}],
"1": [{"Modifiers": [], "Keys": ["KEY_1"]}],
"2": [{"Modifiers": [], "Keys": ["KEY_2"]}],
"3": [{"Modifiers": [], "Keys": ["KEY_3"]}],
"4": [{"Modifiers": [], "Keys": ["KEY_4"]}],
"5": [{"Modifiers": [], "Keys": ["KEY_5"]}],
"6": [{"Modifiers": [], "Keys": ["KEY_6"]}],
"7": [{"Modifiers": [], "Keys": ["KEY_7"]}],
"8": [{"Modifiers": [], "Keys": ["KEY_8"]}],
"9": [{"Modifiers": [], "Keys": ["KEY_9"]}],
":": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_DOT"]}],
";": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_COMMA"]}],
"<": [{"Modifiers": [], "Keys": ["KEY_102ND"]}],
"=": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_0"]}],
">": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_102ND"]}],
"?": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_MINUS"]}],
"@": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_Q"]}],
"A": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_A"]}],
"B": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_B"]}],
"C": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_C"]}],
"D": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_D"]}],
"E": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_E"]}],
"F": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_F"]}],
"G": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_G"]}],
"H": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_H"]}],
"I": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_I"]}],
"J": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_J"]}],
"K": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_K"]}],
"L": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_L"]}],
"M": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_M"]}],
"N": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_N"]}],
"O": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_O"]}],
"P": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_P"]}],
"Q": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_Q"]}],
"R": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_R"]}],
"S": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_S"]}],
"T": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_T"]}],
"U": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_U"]}],
"V": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_V"]}],
"W": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_W"]}],
"X": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_X"]}],
"Y": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_Z"]}],
"Z": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_Y"]}],
"[": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_8"]}],
"\\": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_MINUS"]}],
"]": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_9"]}],
"^": [{"Modifiers": [], "Keys": ["KEY_GRAVE"]}, {"Modifiers": [], "Keys": ["KEY_SPACE"]}],
"_": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_SLASH"]}],
"`": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_EQUAL"]}, {"Modifiers": [], "Keys": ["KEY_SPACE"]}],
"a": [{"Modifiers": [], "Keys": ["KEY_A"]}],
"b": [{"Modifiers": [], "Keys": ["KEY_B"]}],
"c": [{"Modifiers": [], "Keys": ["KEY_C"]}],
"d": [{"Modifiers": [], "Keys": ["KEY_D"]}],
"e": [{"Modifiers": [], "Keys": ["KEY_E"]}],
"f": [{"Modifiers": [], "Keys": ["KEY_F"]}],
"g": [{"Modifiers": [], "Keys": ["KEY_G"]}],
"h": [{"Modifiers": [], "Keys": ["KEY_H"]}],
"i": [{"Modifiers": [], "Keys": ["KEY_I"]}],
"j": [{"Modifiers": [], "Keys": ["KEY_J"]}],
"k": [{"Modifiers": [], "Keys": ["KEY_K"]}],
"l": [{"Modifiers": [], "Keys": ["KEY_L"]}],
"m": [{"Modifiers": [], "Keys": ["KEY_M"]}],
"n": [{"Modifiers": [], "Keys": ["KEY_N"]}],
"o": [{"Modifiers": [], "Keys": ["KEY_O"]}],
"p": [{"Modifiers": [], "Keys": ["KEY_P"]}],
"q": [{"Modifiers": [], "Keys": ["KEY_Q"]}],
"r": [{"Modifiers": [], "Keys": ["KEY_R"]}],
"s": [{"Modifiers": [], "Keys": ["KEY_S"]}],
"t": [{"Modifiers": [], "Keys": ["KEY_T"]}],
"u": [{"Modifiers": [], "Keys": ["KEY_U"]}],
"v": [{"Modifiers": [], "Keys": ["KEY_V"]}],
"w": [{"Modifiers": [], "Keys": ["KEY_W"]}],
"x": [{"Modifiers": [], "Keys": ["KEY_X"]}],
"y": [{"Modifiers": [], "Keys": ["KEY_Z"]}],
"z": [{"Modifiers": [], "Keys": ["KEY_Y"]}],
"{": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_7"]}],
"|": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_102ND"]}],
"}": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_0"]}],
"~": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_RIGHTBRACE"]}],
"§": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_3"]}],
"°": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_GRAVE"]}],
"ü": [{"Modifiers": [], "Keys": ["KEY_LEFTBRACE"]}],
"Ü": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_LEFTBRACE"]}],
"ö": [{"Modifiers": [], "Keys": ["KEY_SEMICOLON"]}],
"Ö": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_SEMICOLON"]}],
"ä": [{"Modifiers": [], "Keys": ["KEY_APOSTROPHE"]}],
"Ä": [{"Modifiers": ["MOD_LEFT_SHIFT"], "Keys": ["KEY_APOSTROPHE"]}],
"µ": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_M"]}],
"€": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_E"]}],
"ß": [{"Modifiers": [], "Keys": ["KEY_MINUS"]}],
"¹": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_1"]}],
"²": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_2"]}],
"³": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_3"]}],
"¼": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_4"]}],
"½": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_5"]}],
"¬": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_6"]}],
"⁴": [{"Modifiers": [], "Keys": ["KEY_GRAVE"]}, {"Modifiers": [], "Keys": ["KEY_4"]}],
"⁵": [{"Modifiers": [], "Keys": ["KEY_GRAVE"]}, {"Modifiers": [], "Keys": ["KEY_5"]}],
"⁶": [{"Modifiers": [], "Keys": ["KEY_GRAVE"]}, {"Modifiers": [], "Keys": ["KEY_6"]}],
"⁷": [{"Modifiers": [], "Keys": ["KEY_GRAVE"]}, {"Modifiers": [], "Keys": ["KEY_7"]}],
"⁸": [{"Modifiers": [], "Keys": ["KEY_GRAVE"]}, {"Modifiers": [], "Keys": ["KEY_8"]}],
"⁹": [{"Modifiers": [], "Keys": ["KEY_GRAVE"]}, {"Modifiers": [], "Keys": ["KEY_9"]}],
"⁰": [{"Modifiers": [], "Keys": ["KEY_GRAVE"]}, {"Modifiers": [], "Keys": ["KEY_0"]}],
"„": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_V"]}],
"“": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_B"]}],
"¢": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_C"]}],
"«": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_X"]}],
"»": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_Z"]}],
"æ": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_A"]}],
"ſ": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_S"]}],
"ð": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_D"]}],
"đ": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_F"]}],
"ŋ": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_G"]}],
"ħ": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_H"]}],
"ĸ": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_K"]}],
"ł": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_L"]}],
"": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_BACKSLASH"]}],
"¶": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_R"]}],
"ŧ": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_T"]}],
"←": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_Y"]}],
"↓": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_U"]}],
"→": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_I"]}],
"ø": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_O"]}],
"þ": [{"Modifiers": ["MOD_RIGHT_ALT"], "Keys": ["KEY_P"]}]
}
}

View File

@ -2,3 +2,38 @@
- global dhcpcd service needs to be stopped
- gloabel hostapd service needs to be stopped
- global wpa_supplicant service needs to be stopped
ToDo:
1) robust networking vs USB gadget reconfiguration / WiFi reconfiguration / Bluetooth reconfiguration
1.1) Every time the USB gadget changes, possible existing network interfaces (usbeth) are rebuild
- this should lead to automatic reconfiguration of the network interface (restore settings)
- this again means, the configuration state has to be cached and a basic network configuration for the
`usbeth` interface has to at every time (service startup configuration)
- the cached network settings and the deployed network settings (effective settings) have to be kept in sync
like done with the USB gadget state. This is, because the sate (cached settings) is user modifiable which
doesn't necessarily mean it is deployable (wrong settings, like an interface IP which is already in use).
- reconfiguration of the network interface should include killing old DHCP servers/clients and deleting
cached DHCP leases
- !!! THIS PROBLEM IS MOSTLY DEDICATED TO USB ETHERNET !! partially WiFi/BNEP interfaces are affected, too.
This involves a new problem: If every network interface is handled with a cached state, an initial state has
to be defined for every interface available. But, the intention of the network reconfiguration part of the
CLI tool (`NET` commands) is to configure interfaces, even if they aren't known before runtime. Not knowing all
interfaces before runtime, again means, ther couldn't exist a default configuration.
--> Solution: A default configuration is only defined (and deployed on service start) for known interfaces (wlan0, usbeth).
The cached state for other interfaces is created, as soon as the settings are changed the first time and updated later on.
A second problem is, that the state couldn't fully reflect the deployed configuration:
Example: An interface, let's say `wlan0` is configured in DHCP client mode. If an external DHCP server hands
out a lease to this interface, an IP address is assigned to the interface BUT NOT REFLECTED BACK TO THE CACHED STATE
(although, there's a field in the settings struct which represents an IPv4 address for the interface)
1.2) With WiFi it is the similar, every time the WiFi stack changes from Access Point to Station mode
or back, the network should be reconfigured (but would work without).
2) Cleanly kill all wpa_supplicant processes (for now dead processes)
3) IPv6 support
4) Store device path to hid devices in internal state of service and create an RPC struct to communicate !ALL! active
device paths.

72
testhid.go Normal file
View File

@ -0,0 +1,72 @@
package main
import(
"./hid"
"log"
"fmt"
)
func Test() {
filepath := "/dev/hidg0"
kbdRepEmpty := hid.NewKeyboardOutReport(0)
kbdRep_a := hid.NewKeyboardOutReport(0, hid.HID_KEY_A)
kbdRep_A := hid.NewKeyboardOutReport(hid.HID_MOD_KEY_LEFT_SHIFT, hid.HID_KEY_A)
err := kbdRepEmpty.WriteTo(filepath)
if err != nil {log.Fatal(err)}
err = kbdRep_a.WriteTo(filepath)
if err != nil {log.Fatal(err)}
err = kbdRepEmpty.WriteTo(filepath)
if err != nil {log.Fatal(err)}
err = kbdRep_A.WriteTo(filepath)
if err != nil {log.Fatal(err)}
err = kbdRepEmpty.WriteTo(filepath)
if err != nil {log.Fatal(err)}
err = kbdRep_A.WriteTo(filepath)
if err != nil {log.Fatal(err)}
err = kbdRepEmpty.WriteTo(filepath)
if err != nil {log.Fatal(err)}
}
func main() {
/*
//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)
*/
keyboard := hid.HIDKeyboard{}
keyboard.DevicePath = "/dev/hidg0"
keyboard.KeyDelay = 100
keyboard.KeyDelayJitter = 200
keyboard.LoadLanguageMapFromFile("keymaps/DE_ASCII.json")
fmt.Printf("Available language maps:\n%v\n",keyboard.ListLanguageMapNames())
err := keyboard.SetActiveLanguageMap("DE")
if err != nil { fmt.Println(err)}
ascii := " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
special := "§°üÜöÖäĵ€ß¹²³⁴⁵⁶⁷⁸⁹⁰¼½¬„“¢«»æſðđŋħĸł’¶ŧ←↓→øþ"
err = keyboard.SendString("Test:" + ascii + "\t" + special)
if err != nil { fmt.Println(err)}
}