diff --git a/hid/keyboard.go b/hid/keyboard.go index f01411c..a456824 100644 --- a/hid/keyboard.go +++ b/hid/keyboard.go @@ -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)} -} diff --git a/hid/keyboard_globals.go b/hid/keyboard_globals.go index b81dfd1..6eda111 100644 --- a/hid/keyboard_globals.go +++ b/hid/keyboard_globals.go @@ -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) { diff --git a/hid/keymaps/de.go b/hid/keymaps/de.go deleted file mode 100644 index e5918b8..0000000 --- a/hid/keymaps/de.go +++ /dev/null @@ -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 - -*/ \ No newline at end of file diff --git a/keymaps/DE_ASCII.json b/keymaps/DE_ASCII.json new file mode 100755 index 0000000..b49f230 --- /dev/null +++ b/keymaps/DE_ASCII.json @@ -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"]}] + } +} diff --git a/notes.txt b/notes.txt index 1b43122..7336a11 100644 --- a/notes.txt +++ b/notes.txt @@ -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. \ No newline at end of file diff --git a/testhid.go b/testhid.go new file mode 100644 index 0000000..f0e5190 --- /dev/null +++ b/testhid.go @@ -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)} +} \ No newline at end of file