package encode import ( "bufio" "fmt" "io" "os" "strconv" "strings" "git.giftfish.de/ston1th/duckycode/pkg/lang" ) type Encoder struct { reader io.Reader language string defaultDelay int delayOverride bool loop int repeat bool } func NewEncoder(r io.Reader, language string) *Encoder { if language == "" { language = "de" } return &Encoder{r, language, 0, false, 0, false} } func (e *Encoder) Encode() (buf []byte, err error) { scanner := bufio.NewScanner(e.reader) for scanner.Scan() { if err = scanner.Err(); err != nil { return } s := strings.SplitN(scanner.Text(), " ", 2) switch len(s) { case 1: if b := e.instruction(s[0]); b != 0 { fmt.Fprintf(os.Stderr, "%s\n", s[0]) buf = append(buf, []byte{b, 0}...) fmt.Fprintf(os.Stderr, "%#v\n", buf) } case 2: fmt.Fprintf(os.Stderr, "%s:%s\n", s[0], s[1]) buf = append(buf, e.instructionData(s[0], s[1])...) fmt.Fprintf(os.Stderr, "%#v\n", buf) } if !e.delayOverride && e.defaultDelay > 0 { delayCounter := e.defaultDelay for delayCounter > 0 { buf = append(buf, byte(0)) if delayCounter > 255 { buf = append(buf, byte(255)) delayCounter -= 255 } else { buf = append(buf, byte(delayCounter)) delayCounter = 0 } } } } return } func (e *Encoder) instruction(in string) byte { if b, ok := lang.K["KEY_"+in]; ok { return b } switch in { case "", "REM": return 0 case "ESCAPE": return e.instruction("ESC") case "DEL": return e.instruction("DELETE") case "BREAK": return e.instruction("PAUSE") case "CONTROL": return e.instruction("CTRL") case "DOWNARROW": return e.instruction("DOWM") case "UPARROW": return e.instruction("UP") case "LEFTARROW": return e.instruction("LEFT") case "RIGHTARROW": return e.instruction("RIGHT") case "MENU": return e.instruction("APP") case "WINDOWS": return e.instruction("GUI") case "PLAY": return e.instruction("MEDIA_PLAY_PAUSE") case "MUTE": return e.instruction("MEDIA_MUTE") case "VOLUMEUP": return e.instruction("MEDIA_VOLUME_INC") case "VOLUMEDOWN": return e.instruction("MEDIAVOLUME_DEC") case "SCROLLLOCK": return e.instruction("SCROLL_LOCK") case "NUMLOCK": return e.instruction("NUM_LOCK") case "CAPSLOCK": return e.instruction("CAPS_LOCK") case "CTRL": return e.instruction("LEFT_CTRL") case "ALT": return e.instruction("LEFT_ALT") case "SHIFT": return e.instruction("LEFT_SHIFT") case "ALT-SHIFT": //TODO return 0 case "ALT-TAB": //TODO return 0 } return e.encodeRune(rune(in[0]))[0] } func (e *Encoder) instructionData(in string, data string) (b []byte) { switch in { case "DEFAULT_DELAY", "DEFAULTDELAY": delay, err := strconv.Atoi(data) if err == nil { e.defaultDelay = delay e.delayOverride = true } return nil case "DELAY": delay, err := strconv.Atoi(data) if err != nil { return nil } for delay > 0 { b = append(b, byte(0)) if delay > 255 { b = append(b, byte(255)) delay -= 255 } else { b = append(b, byte(delay)) delay = 0 } } e.delayOverride = true return case "", "REM": return nil case "STRING": for _, r := range data { enc := e.encodeRune(r) if len(enc)%2 != 0 { enc = append(enc, byte(0)) } b = append(b, enc...) } return case "CONTROL", "CTRL": return []byte{e.instruction(data), lang.K["MODIFIERKEY_CTRL"]} case "ALT": return []byte{e.instruction(data), lang.K["MODIFIERKEY_ALT"]} case "SHIFT": return []byte{e.instruction(data), lang.K["MODIFIERKEY_SHIFT"]} case "CTRL-ALT": return []byte{e.instruction(data), lang.K["MODIFIERKEY_CTRL"] | lang.K["MODIFIERKEY_ALT"]} case "CTRL-SHIFT": return []byte{e.instruction(data), lang.K["MODIFIERKEY_CTRL"] | lang.K["MODIFIERKEY_SHIFT"]} case "COMMAND-OPTION": return []byte{e.instruction(data), lang.K["MODIFIERKEY_LEFT_GUI"] | lang.K["MODIFIERKEY_ALT"]} case "ALT-SHIFT": return []byte{e.instruction(data), lang.K["MODIFIERKEY_LEFT_ALT"] | lang.K["MODIFIERKEY_SHIFT"]} case "WINDOWS", "GUI", "COMMAND": return []byte{e.instruction(data), lang.K["MODIFIERKEY_LEFT_GUI"]} } return []byte{e.instruction(data), 0} } func (e *Encoder) encodeRune(r rune) []byte { var code string hex := strings.ToUpper(strconv.FormatUint(uint64(r), 16)) switch { case r < 128: code = "ASCII_" + hex case r < 256: code = "ISO_8859_1_" + hex default: code = "UNICODE_" + hex } if b, ok := lang.K[code]; ok { return []byte{b} } else if k, ok := lang.Langs[e.language][code]; ok { if k.Mod != 0 { return []byte{k.Key, k.Mod} } return []byte{k.Key} } return nil }