Compare commits

..

No commits in common. "5a4c207159f0c23796362ecc74e352868051973b" and "45f9df45bb813efaff39efa988237cf5c7907734" have entirely different histories.

8 changed files with 571 additions and 1184 deletions

View File

@ -30,18 +30,8 @@ type Key struct {
// A Keymap is a json representation of the unicode rune mapped to its USB HID value // A Keymap is a json representation of the unicode rune mapped to its USB HID value
type Keymap map[string]Key type Keymap map[string]Key
type Keyboard struct { // Keyboard is a type to attach the methods to if someone wants to use it
PressDelay time.Duration // PressDelay is the time in ms to delay before sending a press event type Keyboard struct{}
ReleaseDelay time.Duration // ReleaseDelay is the time in ms to wait before sending the release event
KeymapOrder []string // Keymap Order is the order in which the specified keymaps cycle on the computer
KeymapShortcut [8]byte // KeymapShortcut is the key combo that will cycle the current keymap by one
ErrOnUnknownKey bool // ErrOnUnknownKey whether or not to fail if the unicode rune is invalid or is not in the specified keymaps
KeymapPath string // KeymapPath is the pathe to where the keymap files are stored
currentKeyMap int
keymaps map[string]Keymap
flags map[string]byte
Hidg0 io.Writer
}
// bit flag of modifier keys // bit flag of modifier keys
const ( const (
@ -57,7 +47,16 @@ const (
) )
var ( var (
Modifiers = map[string]byte{ PressDelay time.Duration // PressDelay is the time in ms to delay before sending a press event
ReleaseDelay time.Duration // ReleaseDelay is the time in ms to wait before sending the release event
KeymapOrder []string // Keymap Order is the order in which the specified keymaps cycle on the computer
KeymapShortcut [8]byte // KeymapShortcut is the key combo that will cycle the current keymap by one
ErrOnUnknownKey bool // ErrOnUnknownKey whether or not to fail if the unicode rune is invalid or is not in the specified keymaps
KeymapPath string // KeymapPath is the pathe to where the keymap files are stored
currentKeyMap int
keys = make(map[string]Keymap)
flags = map[string]byte{
"LSHIFT": LSHIFT, "LSHIFT": LSHIFT,
"LCTRL": LCTRL, "LCTRL": LCTRL,
"LALT": LALT, "LALT": LALT,
@ -68,23 +67,21 @@ var (
"RSUPER": RSUPER, "RSUPER": RSUPER,
"NONE": NONE, "NONE": NONE,
} }
Hidg0 io.Writer
) )
func NewKeyboard(Modifiers map[string]byte, kemapOrder []string, KeymapPath string, hidg0 io.Writer) *Keyboard { func (k Keyboard) Write(p []byte) (n int, err error) {
return &Keyboard{ return write(p)
flags: Modifiers, }
KeymapOrder: kemapOrder,
KeymapPath: KeymapPath, func Write(r io.Reader) error {
Hidg0: hidg0, _, err := io.Copy(Keyboard{}, r)
} return err
} }
// io.writer probably isn't the best interface to use for this // io.writer probably isn't the best interface to use for this
func (k *Keyboard) Write(p []byte) (int, error) { func write(p []byte) (n int, err error) {
var ( var index int
index int
err error
)
for index < len(p) { for index < len(p) {
var ( var (
r rune r rune
@ -101,21 +98,13 @@ func (k *Keyboard) Write(p []byte) (int, error) {
if r == utf8.RuneError { if r == utf8.RuneError {
return index, fmt.Errorf("invalid rune: 0x%X", p[index]) // This probably screws things up if the last rune in 'p' is incomplete return index, fmt.Errorf("invalid rune: 0x%X", p[index]) // This probably screws things up if the last rune in 'p' is incomplete
} }
cur, ok := k.CurrentKeymap()[string(r)] cur, ok := CurrentKeymap()[string(r)]
if !ok { if !ok {
if i == 2 { // We can change the keymap if we are on the first key if i == 2 { // can't press two keys from different keymaps
ok, err = k.changeKeymap(r) if !changeKeymap(r) && ErrOnUnknownKey {
if !ok { // rune does not have a mapping return index, fmt.Errorf("rune not in keymap: %c", r)
if k.ErrOnUnknownKey {
if err != nil {
return index, err
}
return index, fmt.Errorf("rune not in keymap: %c", r)
}
index += s
break press
} }
} else { // rune does not have a mapping in this keymaps } else {
break press break press
} }
} }
@ -123,33 +112,29 @@ func (k *Keyboard) Write(p []byte) (int, error) {
switch { switch {
case cur.PressDelayDelimiter: case cur.PressDelayDelimiter:
var n int var n int
n, k.PressDelay = parseDelay(p[index+s:]) n, PressDelay = parseDelay(p[index+s:])
index += s + n index += s + n
break press break press
case cur.ReleaseDelayDelimiter: case cur.ReleaseDelayDelimiter:
var n int var n int
n, k.ReleaseDelay = parseDelay(p[index+s:]) n, ReleaseDelay = parseDelay(p[index+s:])
index += s + n index += s + n
break press break press
case cur.Comment: case cur.Comment:
var n int var n int
n = bytes.Index(p[index+s:], []byte("\n")) + 1 n = bytes.Index(p[index+s:], []byte("\n"))
if n < 0 { if n < 0 {
n = 0 n = 0
} }
index += s + n index += s + n
break press break press
case r == '␀':
// Causes immediate key press useful for modifier keys
index += s
break press
default: default:
// Calculate next modifier byte // Calculate next modifier byte
for _, v := range cur.Modifier { for _, v := range cur.Modifier {
mod |= k.flags[v] mod = mod | flags[v]
} }
// Set the modifier if it is the first key otherwise // Set the modifier if it is the first key otherwise
@ -157,41 +142,29 @@ func (k *Keyboard) Write(p []byte) (int, error) {
if i == 2 { if i == 2 {
flag = mod flag = mod
} else if flag != mod { } else if flag != mod {
// This is the second key press if the previous one was a modifier only Decimal == 0 then take the current key as well break press
if report[i-1] != 0 {
break press
}
// Add the modifier of the current key eg 'D' adds shift; 'd' does not
flag |= mod
} }
// Check for duplicate key press. You can't press a key if it is already pressed, unless it is 0 indicating a modifier. // Check for duplicate key press. You can't press a key if it is already pressed.
for u := 2; u < i; u++ { for u := 2; u < i; u++ {
if cur.Decimal == report[u] && cur.Decimal != 0 { if cur.Decimal == report[u] {
break press break press
} }
} }
} }
report[i] = cur.Decimal report[i] = cur.Decimal
index += s index += s
if k.PressDelay > 0 { if PressDelay > 0 {
// This is the first key press if this is a modifier only Decimal == 0 then take the next key as well break press
if report[i] != 0 {
break press
}
} }
} }
report[0] = flag report[0] = flag
err = k.Press(report, k.Hidg0) r, _ = utf8.DecodeRune(p[index-1:])
if err != nil { Press(report, Hidg0)
return index, err delay(PressDelay)
}
k.delay(k.PressDelay)
}
err = k.keymapto0() // To make it reproducible
if err != nil {
return index, err
} }
keymapto0() // To make it reproducible
return index, nil return index, nil
} }
@ -221,87 +194,69 @@ func parseDelay(buffer []byte) (count int, delay time.Duration) {
return 0, 0 return 0, 0
} }
func (k *Keyboard) delay(Delay time.Duration) { func delay(Delay time.Duration) {
if Delay > 0 { if Delay > 0 {
if syncCheck, ok := k.Hidg0.(syncer); ok { if syncCheck, ok := Hidg0.(syncer); ok {
_ = syncCheck.Sync() syncCheck.Sync()
} }
time.Sleep(Delay) time.Sleep(Delay)
} }
} }
func (k *Keyboard) Press(press [8]byte, file io.Writer) error { func Press(press [8]byte, file io.Writer) {
_, err1 := file.Write(press[:]) file.Write(press[:])
k.delay(k.ReleaseDelay) delay(ReleaseDelay)
_, err2 := file.Write([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) file.Write([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
if err1 != nil {
return err1
}
if err2 != nil {
return err2
}
return nil
} }
func (k *Keyboard) Hold(press [8]byte, file io.Writer) error { func Hold(press [8]byte, file io.Writer) {
_, err := file.Write(press[:]) file.Write(press[:])
return err
} }
func (k *Keyboard) keymapto0() error { func keymapto0() {
if len(k.KeymapOrder) > 1 { if len(KeymapOrder) > 1 {
for i := 0; i < len(k.KeymapOrder)-(k.currentKeyMap); i++ { for i := 0; i < len(KeymapOrder)-(currentKeyMap); i++ {
err := k.Press([8]byte{LALT, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00}, k.Hidg0) Press([8]byte{LALT, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00}, Hidg0)
if err != nil {
return err
}
} }
k.currentKeyMap = 0 currentKeyMap = 0
} }
return nil
} }
func (k *Keyboard) changeKeymap(r rune) (bool, error) { func changeKeymap(r rune) bool {
var err error buf := bytes.NewBuffer(make([]byte, 0, 8*len(KeymapOrder))) // To batch shortcut presses
buf := bytes.NewBuffer(make([]byte, 0, 8*len(k.KeymapOrder))) // To batch shortcut presses
for i := 0; i < len(k.KeymapOrder); i++ { for i := 0; i < len(KeymapOrder); i++ {
_, ok := k.CurrentKeymap()[string(r)] _, ok := CurrentKeymap()[string(r)]
if ok { if ok {
_, err = k.Hidg0.Write(buf.Bytes()) Hidg0.Write(buf.Bytes())
return true, err return true
} }
err = k.Press(k.KeymapShortcut, buf) Press(KeymapShortcut, buf)
if err != nil { if currentKeyMap == len(KeymapOrder)-1 {
return false, err currentKeyMap = 0
}
if k.currentKeyMap == len(k.KeymapOrder)-1 {
k.currentKeyMap = 0
} else { } else {
k.currentKeyMap++ currentKeyMap++
} }
} }
return false, nil return false
} }
func (k *Keyboard) CurrentKeymap() Keymap { func CurrentKeymap() Keymap {
keymap, ok := k.keymaps[k.KeymapOrder[k.currentKeyMap]] keymap, ok := keys[KeymapOrder[currentKeyMap]]
if ok { if ok {
return keymap return keymap
} }
if k.keymaps == nil { return LoadKeymap(KeymapOrder[currentKeyMap])
k.keymaps = make(map[string]Keymap)
}
k.keymaps[k.KeymapOrder[k.currentKeyMap]] = LoadKeymap(k.KeymapOrder[k.currentKeyMap], k.KeymapPath)
return k.keymaps[k.KeymapOrder[k.currentKeyMap]]
} }
func LoadKeymap(keymapName string, KeymapPath string) Keymap { func LoadKeymap(keymapName string) Keymap {
var ( var (
err error err error
content []byte content []byte
file = path.Join(KeymapPath, keymapName+".json") file = path.Join(path.Join(KeymapPath, "hid"), keymapName+".json")
tmp = make(Keymap) tmp = make(Keymap, 0)
) )
fmt.Println(file) fmt.Println(file)
content, err = ioutil.ReadFile(file) content, err = ioutil.ReadFile(file)
@ -313,5 +268,7 @@ func LoadKeymap(keymapName string, KeymapPath string) Keymap {
if err != nil { if err != nil {
return nil return nil
} }
return tmp
keys[keymapName] = tmp
return keys[keymapName]
} }

3
go.mod
View File

@ -1,3 +0,0 @@
module github.com/lordwelch/hid
go 1.18

View File

@ -1,4 +1,8 @@
{ {
"0": {
"modifier": ["NONE"],
"decimal": 39
},
"1": { "1": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 30 "decimal": 30
@ -35,26 +39,10 @@
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 38 "decimal": 38
}, },
"0": {
"modifier": ["NONE"],
"decimal": 39
},
"[": {
"modifier": ["NONE"],
"decimal": 45
},
"]": {
"modifier": ["NONE"],
"decimal": 46
},
"!": { "!": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 30 "decimal": 30
}, },
"@": {
"modifier": ["LSHIFT"],
"decimal": 31
},
"#": { "#": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 32 "decimal": 32
@ -67,17 +55,13 @@
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 34 "decimal": 34
}, },
"^": {
"modifier": ["LSHIFT"],
"decimal": 35
},
"&": { "&": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 36 "decimal": 36
}, },
"*": { "'": {
"modifier": ["LSHIFT"], "modifier": ["NONE"],
"decimal": 37 "decimal": 20
}, },
"(": { "(": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
@ -87,81 +71,77 @@
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 39 "decimal": 39
}, },
"{": { "*": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 45 "decimal": 37
}, },
"}": { "+": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 46 "decimal": 48
},
"'": {
"modifier": ["NONE"],
"decimal": 20
}, },
",": { ",": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 26 "decimal": 26
}, },
"-": {
"modifier": ["NONE"],
"decimal": 52
},
".": { ".": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 8 "decimal": 8
}, },
"p": {
"modifier": ["NONE"],
"decimal": 21
},
"y": {
"modifier": ["NONE"],
"decimal": 23
},
"f": {
"modifier": ["NONE"],
"decimal": 28
},
"g": {
"modifier": ["NONE"],
"decimal": 24
},
"c": {
"modifier": ["NONE"],
"decimal": 12
},
"r": {
"modifier": ["NONE"],
"decimal": 18
},
"l": {
"modifier": ["NONE"],
"decimal": 19
},
"/": { "/": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 47 "decimal": 47
}, },
"=": { ":": {
"modifier": ["NONE"],
"decimal": 48
},
"\"": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 20 "decimal": 29
},
";": {
"modifier": ["NONE"],
"decimal": 29
}, },
"<": { "<": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 26 "decimal": 26
}, },
"=": {
"modifier": ["NONE"],
"decimal": 48
},
">": { ">": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 8 "decimal": 8
}, },
"P": { "?": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 21 "decimal": 47
}, },
"Y": { "@": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 23 "decimal": 31
},
"A": {
"modifier": ["LSHIFT"],
"decimal": 4
},
"B": {
"modifier": ["LSHIFT"],
"decimal": 17
},
"C": {
"modifier": ["LSHIFT"],
"decimal": 12
},
"D": {
"modifier": ["LSHIFT"],
"decimal": 11
},
"E": {
"modifier": ["LSHIFT"],
"decimal": 7
}, },
"F": { "F": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
@ -171,161 +151,13 @@
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 24 "decimal": 24
}, },
"C": {
"modifier": ["LSHIFT"],
"decimal": 12
},
"R": {
"modifier": ["LSHIFT"],
"decimal": 18
},
"L": {
"modifier": ["LSHIFT"],
"decimal": 19
},
"?": {
"modifier": ["LSHIFT"],
"decimal": 47
},
"+": {
"modifier": ["LSHIFT"],
"decimal": 48
},
"a": {
"modifier": ["NONE"],
"decimal": 4
},
"o": {
"modifier": ["NONE"],
"decimal": 22
},
"e": {
"modifier": ["NONE"],
"decimal": 7
},
"u": {
"modifier": ["NONE"],
"decimal": 9
},
"i": {
"modifier": ["NONE"],
"decimal": 10
},
"d": {
"modifier": ["NONE"],
"decimal": 11
},
"h": {
"modifier": ["NONE"],
"decimal": 13
},
"t": {
"modifier": ["NONE"],
"decimal": 14
},
"n": {
"modifier": ["NONE"],
"decimal": 15
},
"s": {
"modifier": ["NONE"],
"decimal": 51
},
"-": {
"modifier": ["NONE"],
"decimal": 52
},
"A": {
"modifier": ["LSHIFT"],
"decimal": 4
},
"O": {
"modifier": ["LSHIFT"],
"decimal": 22
},
"E": {
"modifier": ["LSHIFT"],
"decimal": 7
},
"U": {
"modifier": ["LSHIFT"],
"decimal": 9
},
"I": {
"modifier": ["LSHIFT"],
"decimal": 10
},
"D": {
"modifier": ["LSHIFT"],
"decimal": 11
},
"H": { "H": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 13 "decimal": 13
}, },
"T": { "I": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 14 "decimal": 10
},
"N": {
"modifier": ["LSHIFT"],
"decimal": 15
},
"S": {
"modifier": ["LSHIFT"],
"decimal": 51
},
"_": {
"modifier": ["LSHIFT"],
"decimal": 52
},
";": {
"modifier": ["NONE"],
"decimal": 29
},
"q": {
"modifier": ["NONE"],
"decimal": 27
},
"j": {
"modifier": ["NONE"],
"decimal": 6
},
"k": {
"modifier": ["NONE"],
"decimal": 25
},
"x": {
"modifier": ["NONE"],
"decimal": 5
},
"b": {
"modifier": ["NONE"],
"decimal": 17
},
"m": {
"modifier": ["NONE"],
"decimal": 16
},
"w": {
"modifier": ["NONE"],
"decimal": 54
},
"v": {
"modifier": ["NONE"],
"decimal": 55
},
"z": {
"modifier": ["NONE"],
"decimal": 56
},
":": {
"modifier": ["LSHIFT"],
"decimal": 29
},
"Q": {
"modifier": ["LSHIFT"],
"decimal": 27
}, },
"J": { "J": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
@ -335,42 +167,210 @@
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 25 "decimal": 25
}, },
"X": { "L": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 5 "decimal": 19
},
"B": {
"modifier": ["LSHIFT"],
"decimal": 17
}, },
"M": { "M": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 16 "decimal": 16
}, },
"W": { "N": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 54 "decimal": 15
},
"O": {
"modifier": ["LSHIFT"],
"decimal": 22
},
"P": {
"modifier": ["LSHIFT"],
"decimal": 21
},
"Q": {
"modifier": ["LSHIFT"],
"decimal": 27
},
"R": {
"modifier": ["LSHIFT"],
"decimal": 18
},
"S": {
"modifier": ["LSHIFT"],
"decimal": 51
},
"T": {
"modifier": ["LSHIFT"],
"decimal": 14
},
"U": {
"modifier": ["LSHIFT"],
"decimal": 9
}, },
"V": { "V": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 55 "decimal": 55
}, },
"W": {
"modifier": ["LSHIFT"],
"decimal": 54
},
"X": {
"modifier": ["LSHIFT"],
"decimal": 5
},
"Y": {
"modifier": ["LSHIFT"],
"decimal": 23
},
"Z": { "Z": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 56 "decimal": 56
}, },
"[": {
"modifier": ["NONE"],
"decimal": 45
},
"\"": {
"modifier": ["LSHIFT"],
"decimal": 20
},
"\\": { "\\": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 49 "decimal": 49
}, },
"|": { "]": {
"modifier": ["NONE"],
"decimal": 46
},
"^": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 49 "decimal": 35
},
"_": {
"modifier": ["LSHIFT"],
"decimal": 52
}, },
"`": { "`": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 53 "decimal": 53
}, },
"a": {
"modifier": ["NONE"],
"decimal": 4
},
"b": {
"modifier": ["NONE"],
"decimal": 17
},
"c": {
"modifier": ["NONE"],
"decimal": 12
},
"d": {
"modifier": ["NONE"],
"decimal": 11
},
"e": {
"modifier": ["NONE"],
"decimal": 7
},
"f": {
"modifier": ["NONE"],
"decimal": 28
},
"g": {
"modifier": ["NONE"],
"decimal": 24
},
"h": {
"modifier": ["NONE"],
"decimal": 13
},
"i": {
"modifier": ["NONE"],
"decimal": 10
},
"j": {
"modifier": ["NONE"],
"decimal": 6
},
"k": {
"modifier": ["NONE"],
"decimal": 25
},
"l": {
"modifier": ["NONE"],
"decimal": 19
},
"m": {
"modifier": ["NONE"],
"decimal": 16
},
"n": {
"modifier": ["NONE"],
"decimal": 15
},
"o": {
"modifier": ["NONE"],
"decimal": 22
},
"p": {
"modifier": ["NONE"],
"decimal": 21
},
"q": {
"modifier": ["NONE"],
"decimal": 27
},
"r": {
"modifier": ["NONE"],
"decimal": 18
},
"s": {
"modifier": ["NONE"],
"decimal": 51
},
"t": {
"modifier": ["NONE"],
"decimal": 14
},
"u": {
"modifier": ["NONE"],
"decimal": 9
},
"v": {
"modifier": ["NONE"],
"decimal": 55
},
"w": {
"modifier": ["NONE"],
"decimal": 54
},
"x": {
"modifier": ["NONE"],
"decimal": 5
},
"y": {
"modifier": ["NONE"],
"decimal": 23
},
"z": {
"modifier": ["NONE"],
"decimal": 56
},
"{": {
"modifier": ["LSHIFT"],
"decimal": 45
},
"|": {
"modifier": ["LSHIFT"],
"decimal": 49
},
"}": {
"modifier": ["LSHIFT"],
"decimal": 46
},
"~": { "~": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 53 "decimal": 53
@ -387,96 +387,6 @@
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 44 "decimal": 44
}, },
"⎋": {
"modifier": [""],
"decimal": 41,
"PressDelayDelimiter": false
},
"↘": {
"modifier": [""],
"decimal": 77,
"PressDelayDelimiter": false
},
"↖": {
"modifier": [""],
"decimal": 74,
"PressDelayDelimiter": false
},
"⇪": {
"modifier": [""],
"decimal": 57,
"PressDelayDelimiter": false
},
"⌃": {
"modifier": ["LCTRL"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⇧": {
"modifier": ["LSHIFT"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⌥": {
"modifier": ["LALT"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⌘": {
"modifier": ["LSUPER"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⊞": {
"modifier": ["LSUPER"],
"decimal": 0,
"PressDelayDelimiter": false
},
"→": {
"modifier": [""],
"decimal": 79,
"PressDelayDelimiter": false
},
"←": {
"modifier": [""],
"decimal": 80,
"PressDelayDelimiter": false
},
"↑": {
"modifier": [""],
"decimal": 81,
"PressDelayDelimiter": false
},
"↓": {
"modifier": [""],
"decimal": 82,
"PressDelayDelimiter": false
},
"⇞": {
"modifier": [""],
"decimal": 75,
"PressDelayDelimiter": false
},
"⇟": {
"modifier": [""],
"decimal": 78,
"PressDelayDelimiter": false
},
"⌫": {
"modifier": [""],
"decimal": 42,
"PressDelayDelimiter": false
},
"⌦": {
"modifier": [""],
"decimal": 76,
"PressDelayDelimiter": false
},
"␀": {
"modifier": [""],
"decimal": 0,
"PressDelayDelimiter": false
},
"⏲": { "⏲": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 0, "decimal": 0,

View File

@ -387,101 +387,6 @@
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 44 "decimal": 44
}, },
"␛": {
"modifier": [""],
"decimal": 41,
"PressDelayDelimiter": false
},
"⎋": {
"modifier": [""],
"decimal": 41,
"PressDelayDelimiter": false
},
"↘": {
"modifier": [""],
"decimal": 77,
"PressDelayDelimiter": false
},
"↖": {
"modifier": [""],
"decimal": 74,
"PressDelayDelimiter": false
},
"⇪": {
"modifier": [""],
"decimal": 57,
"PressDelayDelimiter": false
},
"⌃": {
"modifier": ["LCTRL"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⇧": {
"modifier": ["LSHIFT"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⌥": {
"modifier": ["LALT"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⌘": {
"modifier": ["LSUPER"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⊞": {
"modifier": ["LSUPER"],
"decimal": 0,
"PressDelayDelimiter": false
},
"→": {
"modifier": [""],
"decimal": 79,
"PressDelayDelimiter": false
},
"←": {
"modifier": [""],
"decimal": 80,
"PressDelayDelimiter": false
},
"↑": {
"modifier": [""],
"decimal": 81,
"PressDelayDelimiter": false
},
"↓": {
"modifier": [""],
"decimal": 82,
"PressDelayDelimiter": false
},
"⇞": {
"modifier": [""],
"decimal": 75,
"PressDelayDelimiter": false
},
"⇟": {
"modifier": [""],
"decimal": 78,
"PressDelayDelimiter": false
},
"⌫": {
"modifier": [""],
"decimal": 42,
"PressDelayDelimiter": false
},
"⌦": {
"modifier": [""],
"decimal": 76,
"PressDelayDelimiter": false
},
"␀": {
"modifier": [""],
"decimal": 0,
"PressDelayDelimiter": false
},
"⏲": { "⏲": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 0, "decimal": 0,

View File

@ -1,377 +1,297 @@
{ {
"": {
"modifier": ["NONE"],
"decimal": 30
},
"": {
"modifier": ["NONE"],
"decimal": 31
},
"": {
"modifier": ["NONE"],
"decimal": 32
},
"": {
"modifier": ["NONE"],
"decimal": 33
},
"": {
"modifier": ["NONE"],
"decimal": 34
},
"": {
"modifier": ["NONE"],
"decimal": 35
},
"": {
"modifier": ["NONE"],
"decimal": 36
},
"": {
"modifier": ["NONE"],
"decimal": 37
},
"": {
"modifier": ["NONE"],
"decimal": 38
},
"": {
"modifier": ["NONE"],
"decimal": 39
},
"": {
"modifier": ["NONE"],
"decimal": 45
},
"": {
"modifier": ["NONE"],
"decimal": 46
},
"": {
"modifier": ["LSHIFT"],
"decimal": 30
},
"": {
"modifier": ["LSHIFT"],
"decimal": 31
},
"": {
"modifier": ["LSHIFT"],
"decimal": 32
},
"": {
"modifier": ["LSHIFT"],
"decimal": 33
},
"": {
"modifier": ["LSHIFT"],
"decimal": 34
},
"": {
"modifier": ["LSHIFT"],
"decimal": 35
},
"": {
"modifier": ["LSHIFT"],
"decimal": 36
},
"": {
"modifier": ["LSHIFT"],
"decimal": 37
},
"": {
"modifier": ["LSHIFT"],
"decimal": 38
},
"": {
"modifier": ["LSHIFT"],
"decimal": 39
},
"": {
"modifier": ["LSHIFT"],
"decimal": 45
},
"": {
"modifier": ["LSHIFT"],
"decimal": 46
},
"": {
"modifier": ["NONE"],
"decimal": 20
},
"": {
"modifier": ["NONE"],
"decimal": 26
},
"": {
"modifier": ["NONE"],
"decimal": 8
},
"": {
"modifier": ["NONE"],
"decimal": 21
},
"": {
"modifier": ["NONE"],
"decimal": 23
},
"": {
"modifier": ["NONE"],
"decimal": 28
},
"": {
"modifier": ["NONE"],
"decimal": 24
},
"": {
"modifier": ["NONE"],
"decimal": 12
},
"": {
"modifier": ["NONE"],
"decimal": 18
},
"": {
"modifier": ["NONE"],
"decimal": 19
},
"": {
"modifier": ["NONE"],
"decimal": 47
},
"": {
"modifier": ["NONE"],
"decimal": 48
},
"": {
"modifier": ["LSHIFT"],
"decimal": 20
},
"": {
"modifier": ["LSHIFT"],
"decimal": 26
},
"": {
"modifier": ["LSHIFT"],
"decimal": 8
},
"": {
"modifier": ["LSHIFT"],
"decimal": 21
},
"": {
"modifier": ["LSHIFT"],
"decimal": 23
},
"": {
"modifier": ["LSHIFT"],
"decimal": 28
},
"": {
"modifier": ["LSHIFT"],
"decimal": 24
},
"": {
"modifier": ["LSHIFT"],
"decimal": 12
},
"": {
"modifier": ["LSHIFT"],
"decimal": 18
},
"": {
"modifier": ["LSHIFT"],
"decimal": 19
},
"": {
"modifier": ["LSHIFT"],
"decimal": 47
},
"": {
"modifier": ["LSHIFT"],
"decimal": 48
},
"": {
"modifier": ["NONE"],
"decimal": 4
},
"": {
"modifier": ["NONE"],
"decimal": 22
},
"": {
"modifier": ["NONE"],
"decimal": 7
},
"": {
"modifier": ["NONE"],
"decimal": 9
},
"": {
"modifier": ["NONE"],
"decimal": 10
},
"": {
"modifier": ["NONE"],
"decimal": 11
},
"": {
"modifier": ["NONE"],
"decimal": 13
},
"": {
"modifier": ["NONE"],
"decimal": 14
},
"": {
"modifier": ["NONE"],
"decimal": 15
},
"": {
"modifier": ["NONE"],
"decimal": 51
},
"": {
"modifier": ["NONE"],
"decimal": 52
},
"": {
"modifier": ["LSHIFT"],
"decimal": 4
},
"": {
"modifier": ["LSHIFT"],
"decimal": 22
},
"": {
"modifier": ["LSHIFT"],
"decimal": 7
},
"": {
"modifier": ["LSHIFT"],
"decimal": 9
},
"": {
"modifier": ["LSHIFT"],
"decimal": 10
},
"": {
"modifier": ["LSHIFT"],
"decimal": 11
},
"": {
"modifier": ["LSHIFT"],
"decimal": 13
},
"": {
"modifier": ["LSHIFT"],
"decimal": 14
},
"": {
"modifier": ["LSHIFT"],
"decimal": 15
},
"": {
"modifier": ["LSHIFT"],
"decimal": 51
},
"": {
"modifier": ["LSHIFT"],
"decimal": 52
},
"": { "": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 29 "decimal": 30
}, },
"": { "": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 27 "decimal": 31
}, },
"": { "": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 6 "decimal": 32
}, },
"": { "": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 25 "decimal": 33
}, },
"": { "": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 5 "decimal": 34
}, },
"": { "": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 17 "decimal": 35
}, },
"": { "": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 16 "decimal": 36
}, },
"": { "": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 54 "decimal": 37
}, },
"": { "": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 55 "decimal": 38
}, },
"": { "": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 56 "decimal": 39
},
"": {
"modifier": ["NONE"],
"decimal": 45
},
"": {
"modifier": ["NONE"],
"decimal": 46
}, },
"": { "": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 29 "decimal": 30
}, },
"": { "": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 27 "decimal": 31
},
"": {
"modifier": ["LSHIFT"],
"decimal": 6
},
"": {
"modifier": ["LSHIFT"],
"decimal": 25
},
"": {
"modifier": ["LSHIFT"],
"decimal": 5
},
"": {
"modifier": ["LSHIFT"],
"decimal": 17
},
"": {
"modifier": ["LSHIFT"],
"decimal": 16
},
"W": {
"modifier": ["LSHIFT"],
"decimal": 54
},
"": {
"modifier": ["LSHIFT"],
"decimal": 55
}, },
"": { "": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 56 "decimal": 32
},
"": {
"modifier": ["LSHIFT"],
"decimal": 33
},
"": {
"modifier": ["LSHIFT"],
"decimal": 34
},
"": {
"modifier": ["LSHIFT"],
"decimal": 35
},
"": {
"modifier": ["LSHIFT"],
"decimal": 36
},
"*": {
"modifier": ["LSHIFT"],
"decimal": 37
},
"(": {
"modifier": ["LSHIFT"],
"decimal": 38
},
")": {
"modifier": ["LSHIFT"],
"decimal": 39
},
"": {
"modifier": ["LSHIFT"],
"decimal": 45
},
"": {
"modifier": ["LSHIFT"],
"decimal": 46
},
"": {
"modifier": ["NONE"],
"decimal": 20
},
"": {
"modifier": ["NONE"],
"decimal": 26
},
"": {
"modifier": ["NONE"],
"decimal": 8
},
"": {
"modifier": ["NONE"],
"decimal": 21
},
"": {
"modifier": ["NONE"],
"decimal": 23
},
"": {
"modifier": ["NONE"],
"decimal": 28
},
"": {
"modifier": ["NONE"],
"decimal": 24
},
"": {
"modifier": ["NONE"],
"decimal": 12
},
"": {
"modifier": ["NONE"],
"decimal": 18
},
"": {
"modifier": ["NONE"],
"decimal": 19
},
"": {
"modifier": ["NONE"],
"decimal": 47
},
"": {
"modifier": ["NONE"],
"decimal": 48
},
"": {
"modifier": ["LSHIFT"],
"decimal": 20
},
"": {
"modifier": ["LSHIFT"],
"decimal": 26
},
"": {
"modifier": ["LSHIFT"],
"decimal": 8
},
"": {
"modifier": ["LSHIFT"],
"decimal": 21
},
"": {
"modifier": ["LSHIFT"],
"decimal": 23
},
"": {
"modifier": ["LSHIFT"],
"decimal": 28
},
"": {
"modifier": ["LSHIFT"],
"decimal": 24
},
"I": {
"modifier": ["LSHIFT"],
"decimal": 12
},
"": {
"modifier": ["LSHIFT"],
"decimal": 18
},
"": {
"modifier": ["NONE"],
"decimal": 4
},
"": {
"modifier": ["NONE"],
"decimal": 22
},
"": {
"modifier": ["NONE"],
"decimal": 7
},
"": {
"modifier": ["NONE"],
"decimal": 9
},
"": {
"modifier": ["NONE"],
"decimal": 10
},
"": {
"modifier": ["NONE"],
"decimal": 11
},
"": {
"modifier": ["NONE"],
"decimal": 13
},
"": {
"modifier": ["NONE"],
"decimal": 14
},
"": {
"modifier": ["NONE"],
"decimal": 15
},
"": {
"modifier": ["NONE"],
"decimal": 51
},
"": {
"modifier": ["NONE"],
"decimal": 52
},
"": {
"modifier": ["LSHIFT"],
"decimal": 4
},
"": {
"modifier": ["LSHIFT"],
"decimal": 22
},
"": {
"modifier": ["LSHIFT"],
"decimal": 15
},
"": {
"modifier": ["NONE"],
"decimal": 29
},
"": {
"modifier": ["NONE"],
"decimal": 27
},
"": {
"modifier": ["NONE"],
"decimal": 6
},
"": {
"modifier": ["NONE"],
"decimal": 25
},
"": {
"modifier": ["NONE"],
"decimal": 5
},
"": {
"modifier": ["NONE"],
"decimal": 17
},
"": {
"modifier": ["NONE"],
"decimal": 16
},
"": {
"modifier": ["NONE"],
"decimal": 54
},
"": {
"modifier": ["NONE"],
"decimal": 55
},
"": {
"modifier": ["LSHIFT"],
"decimal": 29
},
"": {
"modifier": ["LSHIFT"],
"decimal": 27
},
"": {
"modifier": ["LSHIFT"],
"decimal": 55
},
"": {
"modifier": ["NONE"],
"decimal": 49
}, },
"": { "": {
"modifier": ["NONE"],
"decimal": 49
},
"": {
"modifier": ["LSHIFT"],
"decimal": 49
},
"\\": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 53 "decimal": 53
}, },
"|": { "": {
"modifier": ["LSHIFT"], "modifier": ["LSHIFT"],
"decimal": 53 "decimal": 53
}, },
@ -387,96 +307,6 @@
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 44 "decimal": 44
}, },
"⎋": {
"modifier": [""],
"decimal": 41,
"PressDelayDelimiter": false
},
"↘": {
"modifier": [""],
"decimal": 77,
"PressDelayDelimiter": false
},
"↖": {
"modifier": [""],
"decimal": 74,
"PressDelayDelimiter": false
},
"⇪": {
"modifier": [""],
"decimal": 57,
"PressDelayDelimiter": false
},
"⌃": {
"modifier": ["LCTRL"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⇧": {
"modifier": ["LSHIFT"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⌥": {
"modifier": ["LALT"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⌘": {
"modifier": ["LSUPER"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⊞": {
"modifier": ["LSUPER"],
"decimal": 0,
"PressDelayDelimiter": false
},
"→": {
"modifier": [""],
"decimal": 79,
"PressDelayDelimiter": false
},
"←": {
"modifier": [""],
"decimal": 80,
"PressDelayDelimiter": false
},
"↑": {
"modifier": [""],
"decimal": 81,
"PressDelayDelimiter": false
},
"↓": {
"modifier": [""],
"decimal": 82,
"PressDelayDelimiter": false
},
"⇞": {
"modifier": [""],
"decimal": 75,
"PressDelayDelimiter": false
},
"⇟": {
"modifier": [""],
"decimal": 78,
"PressDelayDelimiter": false
},
"⌫": {
"modifier": [""],
"decimal": 42,
"PressDelayDelimiter": false
},
"⌦": {
"modifier": [""],
"decimal": 76,
"PressDelayDelimiter": false
},
"␀": {
"modifier": [""],
"decimal": 0,
"PressDelayDelimiter": false
},
"⏲": { "⏲": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 0, "decimal": 0,

View File

@ -375,96 +375,6 @@
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 44 "decimal": 44
}, },
"⎋": {
"modifier": [""],
"decimal": 41,
"PressDelayDelimiter": false
},
"↘": {
"modifier": [""],
"decimal": 77,
"PressDelayDelimiter": false
},
"↖": {
"modifier": [""],
"decimal": 74,
"PressDelayDelimiter": false
},
"⇪": {
"modifier": [""],
"decimal": 57,
"PressDelayDelimiter": false
},
"⌃": {
"modifier": ["LCTRL"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⇧": {
"modifier": ["LSHIFT"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⌥": {
"modifier": ["LALT"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⌘": {
"modifier": ["LSUPER"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⊞": {
"modifier": ["LSUPER"],
"decimal": 0,
"PressDelayDelimiter": false
},
"→": {
"modifier": [""],
"decimal": 79,
"PressDelayDelimiter": false
},
"←": {
"modifier": [""],
"decimal": 80,
"PressDelayDelimiter": false
},
"↑": {
"modifier": [""],
"decimal": 81,
"PressDelayDelimiter": false
},
"↓": {
"modifier": [""],
"decimal": 82,
"PressDelayDelimiter": false
},
"⇞": {
"modifier": [""],
"decimal": 75,
"PressDelayDelimiter": false
},
"⇟": {
"modifier": [""],
"decimal": 78,
"PressDelayDelimiter": false
},
"⌫": {
"modifier": [""],
"decimal": 42,
"PressDelayDelimiter": false
},
"⌦": {
"modifier": [""],
"decimal": 76,
"PressDelayDelimiter": false
},
"␀": {
"modifier": [""],
"decimal": 0,
"PressDelayDelimiter": false
},
"⏲": { "⏲": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 0, "decimal": 0,

View File

@ -559,96 +559,6 @@
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 44 "decimal": 44
}, },
"⎋": {
"modifier": [""],
"decimal": 41,
"PressDelayDelimiter": false
},
"↘": {
"modifier": [""],
"decimal": 77,
"PressDelayDelimiter": false
},
"↖": {
"modifier": [""],
"decimal": 74,
"PressDelayDelimiter": false
},
"⇪": {
"modifier": [""],
"decimal": 57,
"PressDelayDelimiter": false
},
"⌃": {
"modifier": ["LCTRL"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⇧": {
"modifier": ["LSHIFT"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⌥": {
"modifier": ["LALT"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⌘": {
"modifier": ["LSUPER"],
"decimal": 0,
"PressDelayDelimiter": false
},
"⊞": {
"modifier": ["LSUPER"],
"decimal": 0,
"PressDelayDelimiter": false
},
"→": {
"modifier": [""],
"decimal": 79,
"PressDelayDelimiter": false
},
"←": {
"modifier": [""],
"decimal": 80,
"PressDelayDelimiter": false
},
"↑": {
"modifier": [""],
"decimal": 81,
"PressDelayDelimiter": false
},
"↓": {
"modifier": [""],
"decimal": 82,
"PressDelayDelimiter": false
},
"⇞": {
"modifier": [""],
"decimal": 75,
"PressDelayDelimiter": false
},
"⇟": {
"modifier": [""],
"decimal": 78,
"PressDelayDelimiter": false
},
"⌫": {
"modifier": [""],
"decimal": 42,
"PressDelayDelimiter": false
},
"⌦": {
"modifier": [""],
"decimal": 76,
"PressDelayDelimiter": false
},
"␀": {
"modifier": [""],
"decimal": 0,
"PressDelayDelimiter": false
},
"⏲": { "⏲": {
"modifier": ["NONE"], "modifier": ["NONE"],
"decimal": 0, "decimal": 0,

60
main.go
View File

@ -3,66 +3,34 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"io"
"os" "os"
"path"
"time"
hid "github.com/lordwelch/hid/ghid" "timmy.narnian.us/hid/ghid"
) )
func main() { func main() {
var ( var (
Shortcut string SHORTCUT string
filePath string
keymapPath string
ghidPath string
pressDelay time.Duration
releaseDelay time.Duration
err error
ghid *os.File
tmp *os.File
keyboard *hid.Keyboard
) )
if _, exists := os.LookupEnv("XDG_CONFIG_HOME"); !exists {
_ = os.Setenv("XDG_CONFIG_HOME", path.Join(os.ExpandEnv("$HOME"), ".config")) flag.StringVar(&SHORTCUT, "shortcut", "", "Keymap cycle shortcut")
} flag.StringVar(&SHORTCUT, "s", "", "Keymap cycle shortcut")
flag.StringVar(&Shortcut, "shortcut", "", "Keymap cycle shortcut") flag.StringVar(&hid.KeymapPath, "path", os.ExpandEnv("$XDG_CONFIG_HOME"), "Path to config dir default: $XDG_CONFIG_HOME")
flag.StringVar(&Shortcut, "s", "", "Keymap cycle shortcut") flag.StringVar(&hid.KeymapPath, "p", os.ExpandEnv("$XDG_CONFIG_HOME"), "Path to config dir default: $XDG_CONFIG_HOME")
flag.StringVar(&keymapPath, "path", path.Join(os.ExpandEnv("$XDG_CONFIG_HOME"), "hid"), "Path to config dir default: $XDG_CONFIG_HOME")
flag.StringVar(&keymapPath, "p", path.Join(os.ExpandEnv("$XDG_CONFIG_HOME"), "hid"), "Path to config dir default: $XDG_CONFIG_HOME")
flag.StringVar(&filePath, "f", "-", "The file to read content from. Defaults to stdin")
flag.StringVar(&filePath, "file", "-", "The file to read content from. Defaults to stdin")
flag.StringVar(&ghidPath, "g", "/dev/hidg0", "The device to send key presses to. Defaults to /dev/hidg0")
flag.StringVar(&ghidPath, "ghid", "/dev/hidg0", "The device to send key presses to. Defaults to /dev/hidg0")
flag.DurationVar(&pressDelay, "press", 0, "sets the default delay between presses of individual keys")
flag.DurationVar(&releaseDelay, "release", 0, "sets the default delay between sending the press of an individual key and sending the release")
flag.Parse() flag.Parse()
if flag.NArg() < 0 {
flag.Usage()
os.Exit(1)
}
fmt.Println(keymapPath)
if filePath != "-" { hid.KeymapOrder = flag.Args()
tmp, err = os.Open(path.Clean(filePath))
if err == nil {
_ = os.Stdin.Close()
os.Stdin = tmp
}
}
ghid, err = os.OpenFile(ghidPath, os.O_APPEND|os.O_WRONLY, 0600) fmt.Println(hid.KeymapPath)
file, err := os.OpenFile("/dev/hidg0", os.O_APPEND|os.O_WRONLY, 0755)
if err != nil { if err != nil {
panic(err) panic(err)
} }
defer ghid.Close() hid.Hidg0 = file
defer file.Close()
keyboard = hid.NewKeyboard(hid.Modifiers, flag.Args(), keymapPath, ghid) hid.Write(os.Stdin)
keyboard.PressDelay = pressDelay
keyboard.ReleaseDelay = releaseDelay
_, err = io.Copy(keyboard, os.Stdin)
if err != nil { if err != nil {
panic(err) panic(err)