123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741 |
- // Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
- // file at the top-level directory of this distribution and at
- // https://github.com/go-vgo/robotgo/blob/master/LICENSE
- //
- // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
- // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
- // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
- // option. This file may not be copied, modified, or distributed
- // except according to those terms.
- package robotgo
- /*
- // #include "key/keycode.h"
- #include "key/keypress_c.h"
- */
- import "C"
- import (
- "errors"
- "math/rand"
- "reflect"
- "runtime"
- "strconv"
- "strings"
- "unicode"
- "unsafe"
- "github.com/go-vgo/robotgo/clipboard"
- )
- // Defining a bunch of constants.
- const (
- // KeyA define key "a"
- KeyA = "a"
- KeyB = "b"
- KeyC = "c"
- KeyD = "d"
- KeyE = "e"
- KeyF = "f"
- KeyG = "g"
- KeyH = "h"
- KeyI = "i"
- KeyJ = "j"
- KeyK = "k"
- KeyL = "l"
- KeyM = "m"
- KeyN = "n"
- KeyO = "o"
- KeyP = "p"
- KeyQ = "q"
- KeyR = "r"
- KeyS = "s"
- KeyT = "t"
- KeyU = "u"
- KeyV = "v"
- KeyW = "w"
- KeyX = "x"
- KeyY = "y"
- KeyZ = "z"
- //
- CapA = "A"
- CapB = "B"
- CapC = "C"
- CapD = "D"
- CapE = "E"
- CapF = "F"
- CapG = "G"
- CapH = "H"
- CapI = "I"
- CapJ = "J"
- CapK = "K"
- CapL = "L"
- CapM = "M"
- CapN = "N"
- CapO = "O"
- CapP = "P"
- CapQ = "Q"
- CapR = "R"
- CapS = "S"
- CapT = "T"
- CapU = "U"
- CapV = "V"
- CapW = "W"
- CapX = "X"
- CapY = "Y"
- CapZ = "Z"
- //
- Key0 = "0"
- Key1 = "1"
- Key2 = "2"
- Key3 = "3"
- Key4 = "4"
- Key5 = "5"
- Key6 = "6"
- Key7 = "7"
- Key8 = "8"
- Key9 = "9"
- // Backspace backspace key string
- Backspace = "backspace"
- Delete = "delete"
- Enter = "enter"
- Tab = "tab"
- Esc = "esc"
- Escape = "escape"
- Up = "up" // Up arrow key
- Down = "down" // Down arrow key
- Right = "right" // Right arrow key
- Left = "left" // Left arrow key
- Home = "home"
- End = "end"
- Pageup = "pageup"
- Pagedown = "pagedown"
- F1 = "f1"
- F2 = "f2"
- F3 = "f3"
- F4 = "f4"
- F5 = "f5"
- F6 = "f6"
- F7 = "f7"
- F8 = "f8"
- F9 = "f9"
- F10 = "f10"
- F11 = "f11"
- F12 = "f12"
- F13 = "f13"
- F14 = "f14"
- F15 = "f15"
- F16 = "f16"
- F17 = "f17"
- F18 = "f18"
- F19 = "f19"
- F20 = "f20"
- F21 = "f21"
- F22 = "f22"
- F23 = "f23"
- F24 = "f24"
- Cmd = "cmd" // is the "win" key for windows
- Lcmd = "lcmd" // left command
- Rcmd = "rcmd" // right command
- // "command"
- Alt = "alt"
- Lalt = "lalt" // left alt
- Ralt = "ralt" // right alt
- Ctrl = "ctrl"
- Lctrl = "lctrl" // left ctrl
- Rctrl = "rctrl" // right ctrl
- Control = "control"
- Shift = "shift"
- Lshift = "lshift" // left shift
- Rshift = "rshift" // right shift
- // "right_shift"
- Capslock = "capslock"
- Space = "space"
- Print = "print"
- Printscreen = "printscreen" // No Mac support
- Insert = "insert"
- Menu = "menu" // Windows only
- AudioMute = "audio_mute" // Mute the volume
- AudioVolDown = "audio_vol_down" // Lower the volume
- AudioVolUp = "audio_vol_up" // Increase the volume
- AudioPlay = "audio_play"
- AudioStop = "audio_stop"
- AudioPause = "audio_pause"
- AudioPrev = "audio_prev" // Previous Track
- AudioNext = "audio_next" // Next Track
- AudioRewind = "audio_rewind" // Linux only
- AudioForward = "audio_forward" // Linux only
- AudioRepeat = "audio_repeat" // Linux only
- AudioRandom = "audio_random" // Linux only
- Num0 = "num0" // numpad 0
- Num1 = "num1"
- Num2 = "num2"
- Num3 = "num3"
- Num4 = "num4"
- Num5 = "num5"
- Num6 = "num6"
- Num7 = "num7"
- Num8 = "num8"
- Num9 = "num9"
- NumLock = "num_lock"
- NumDecimal = "num."
- NumPlus = "num+"
- NumMinus = "num-"
- NumMul = "num*"
- NumDiv = "num/"
- NumClear = "num_clear"
- NumEnter = "num_enter"
- NumEqual = "num_equal"
- LightsMonUp = "lights_mon_up" // Turn up monitor brightness No Windows support
- LightsMonDown = "lights_mon_down" // Turn down monitor brightness No Windows support
- LightsKbdToggle = "lights_kbd_toggle" // Toggle keyboard backlight on/off No Windows support
- LightsKbdUp = "lights_kbd_up" // Turn up keyboard backlight brightness No Windows support
- LightsKbdDown = "lights_kbd_down"
- )
- // keyNames define a map of key names to MMKeyCode
- var keyNames = map[string]C.MMKeyCode{
- "backspace": C.K_BACKSPACE,
- "delete": C.K_DELETE,
- "enter": C.K_RETURN,
- "tab": C.K_TAB,
- "esc": C.K_ESCAPE,
- "escape": C.K_ESCAPE,
- "up": C.K_UP,
- "down": C.K_DOWN,
- "right": C.K_RIGHT,
- "left": C.K_LEFT,
- "home": C.K_HOME,
- "end": C.K_END,
- "pageup": C.K_PAGEUP,
- "pagedown": C.K_PAGEDOWN,
- //
- "f1": C.K_F1,
- "f2": C.K_F2,
- "f3": C.K_F3,
- "f4": C.K_F4,
- "f5": C.K_F5,
- "f6": C.K_F6,
- "f7": C.K_F7,
- "f8": C.K_F8,
- "f9": C.K_F9,
- "f10": C.K_F10,
- "f11": C.K_F11,
- "f12": C.K_F12,
- "f13": C.K_F13,
- "f14": C.K_F14,
- "f15": C.K_F15,
- "f16": C.K_F16,
- "f17": C.K_F17,
- "f18": C.K_F18,
- "f19": C.K_F19,
- "f20": C.K_F20,
- "f21": C.K_F21,
- "f22": C.K_F22,
- "f23": C.K_F23,
- "f24": C.K_F24,
- //
- "cmd": C.K_META,
- "lcmd": C.K_LMETA,
- "rcmd": C.K_RMETA,
- "command": C.K_META,
- "alt": C.K_ALT,
- "lalt": C.K_LALT,
- "ralt": C.K_RALT,
- "ctrl": C.K_CONTROL,
- "lctrl": C.K_LCONTROL,
- "rctrl": C.K_RCONTROL,
- "control": C.K_CONTROL,
- "shift": C.K_SHIFT,
- "lshift": C.K_LSHIFT,
- "rshift": C.K_RSHIFT,
- "right_shift": C.K_RSHIFT,
- "capslock": C.K_CAPSLOCK,
- "space": C.K_SPACE,
- "print": C.K_PRINTSCREEN,
- "printscreen": C.K_PRINTSCREEN,
- "insert": C.K_INSERT,
- "menu": C.K_MENU,
- "audio_mute": C.K_AUDIO_VOLUME_MUTE,
- "audio_vol_down": C.K_AUDIO_VOLUME_DOWN,
- "audio_vol_up": C.K_AUDIO_VOLUME_UP,
- "audio_play": C.K_AUDIO_PLAY,
- "audio_stop": C.K_AUDIO_STOP,
- "audio_pause": C.K_AUDIO_PAUSE,
- "audio_prev": C.K_AUDIO_PREV,
- "audio_next": C.K_AUDIO_NEXT,
- "audio_rewind": C.K_AUDIO_REWIND,
- "audio_forward": C.K_AUDIO_FORWARD,
- "audio_repeat": C.K_AUDIO_REPEAT,
- "audio_random": C.K_AUDIO_RANDOM,
- "num0": C.K_NUMPAD_0,
- "num1": C.K_NUMPAD_1,
- "num2": C.K_NUMPAD_2,
- "num3": C.K_NUMPAD_3,
- "num4": C.K_NUMPAD_4,
- "num5": C.K_NUMPAD_5,
- "num6": C.K_NUMPAD_6,
- "num7": C.K_NUMPAD_7,
- "num8": C.K_NUMPAD_8,
- "num9": C.K_NUMPAD_9,
- "num_lock": C.K_NUMPAD_LOCK,
- // todo: removed
- "numpad_0": C.K_NUMPAD_0,
- "numpad_1": C.K_NUMPAD_1,
- "numpad_2": C.K_NUMPAD_2,
- "numpad_3": C.K_NUMPAD_3,
- "numpad_4": C.K_NUMPAD_4,
- "numpad_5": C.K_NUMPAD_5,
- "numpad_6": C.K_NUMPAD_6,
- "numpad_7": C.K_NUMPAD_7,
- "numpad_8": C.K_NUMPAD_8,
- "numpad_9": C.K_NUMPAD_9,
- "numpad_lock": C.K_NUMPAD_LOCK,
- "num.": C.K_NUMPAD_DECIMAL,
- "num+": C.K_NUMPAD_PLUS,
- "num-": C.K_NUMPAD_MINUS,
- "num*": C.K_NUMPAD_MUL,
- "num/": C.K_NUMPAD_DIV,
- "num_clear": C.K_NUMPAD_CLEAR,
- "num_enter": C.K_NUMPAD_ENTER,
- "num_equal": C.K_NUMPAD_EQUAL,
- "lights_mon_up": C.K_LIGHTS_MON_UP,
- "lights_mon_down": C.K_LIGHTS_MON_DOWN,
- "lights_kbd_toggle": C.K_LIGHTS_KBD_TOGGLE,
- "lights_kbd_up": C.K_LIGHTS_KBD_UP,
- "lights_kbd_down": C.K_LIGHTS_KBD_DOWN,
- // { NULL: C.K_NOT_A_KEY }
- }
- // CmdCtrl If the operating system is macOS, return the key string "cmd",
- // otherwise return the key string "ctrl
- func CmdCtrl() string {
- if runtime.GOOS == "darwin" {
- return "cmd"
- }
- return "ctrl"
- }
- // It sends a key press and release to the active application
- func tapKeyCode(code C.MMKeyCode, flags C.MMKeyFlags, pid C.uintptr) {
- C.toggleKeyCode(code, true, flags, pid)
- MilliSleep(3)
- C.toggleKeyCode(code, false, flags, pid)
- }
- var keyErr = errors.New("Invalid key flag specified.")
- func checkKeyCodes(k string) (key C.MMKeyCode, err error) {
- if k == "" {
- return
- }
- if len(k) == 1 {
- val1 := C.CString(k)
- defer C.free(unsafe.Pointer(val1))
- key = C.keyCodeForChar(*val1)
- if key == C.K_NOT_A_KEY {
- err = keyErr
- return
- }
- return
- }
- if v, ok := keyNames[k]; ok {
- key = v
- if key == C.K_NOT_A_KEY {
- err = keyErr
- return
- }
- }
- return
- }
- func checkKeyFlags(f string) (flags C.MMKeyFlags) {
- m := map[string]C.MMKeyFlags{
- "alt": C.MOD_ALT,
- "ralt": C.MOD_ALT,
- "lalt": C.MOD_ALT,
- "cmd": C.MOD_META,
- "rcmd": C.MOD_META,
- "lcmd": C.MOD_META,
- "ctrl": C.MOD_CONTROL,
- "rctrl": C.MOD_CONTROL,
- "lctrl": C.MOD_CONTROL,
- "shift": C.MOD_SHIFT,
- "rshift": C.MOD_SHIFT,
- "lshift": C.MOD_SHIFT,
- "none": C.MOD_NONE,
- }
- if v, ok := m[f]; ok {
- return v
- }
- return
- }
- func getFlagsFromValue(value []string) (flags C.MMKeyFlags) {
- if len(value) <= 0 {
- return
- }
- for i := 0; i < len(value); i++ {
- var f C.MMKeyFlags = C.MOD_NONE
- f = checkKeyFlags(value[i])
- flags = (C.MMKeyFlags)(flags | f)
- }
- return
- }
- func keyTaps(k string, keyArr []string, pid int) error {
- flags := getFlagsFromValue(keyArr)
- key, err := checkKeyCodes(k)
- if err != nil {
- return err
- }
- tapKeyCode(key, flags, C.uintptr(pid))
- MilliSleep(KeySleep)
- return nil
- }
- func keyToggles(k string, keyArr []string, pid int, args ...interface{}) error {
- if len(keyArr) <= 0 {
- keyArr = append(keyArr, "down")
- }
- down := true
- if keyArr[0] == "up" {
- down = false
- }
- if keyArr[0] == "up" || keyArr[0] == "down" {
- keyArr = keyArr[1:]
- }
- flags := getFlagsFromValue(keyArr)
- key, err := checkKeyCodes(k)
- if err != nil {
- return err
- }
- C.toggleKeyCode(key, C.bool(down), flags, C.uintptr(pid))
- if len(args) > 0 {
- MilliSleep(KeySleep)
- }
- return nil
- }
- /*
- __ ___ ___________ ____ .______ ______ ___ .______ _______
- | |/ / | ____\ \ / / | _ \ / __ \ / \ | _ \ | \
- | ' / | |__ \ \/ / | |_) | | | | | / ^ \ | |_) | | .--. |
- | < | __| \_ _/ | _ < | | | | / /_\ \ | / | | | |
- | . \ | |____ | | | |_) | | `--' | / _____ \ | |\ \----.| '--' |
- |__|\__\ |_______| |__| |______/ \______/ /__/ \__\ | _| `._____||_______/
- */
- // ToInterfaces convert []string to []interface{}
- func ToInterfaces(fields []string) []interface{} {
- res := make([]interface{}, 0, len(fields))
- for _, s := range fields {
- res = append(res, s)
- }
- return res
- }
- // ToStrings convert []interface{} to []string
- func ToStrings(fields []interface{}) []string {
- res := make([]string, 0, len(fields))
- for _, s := range fields {
- res = append(res, s.(string))
- }
- return res
- }
- // toErr it converts a C string to a Go error
- func toErr(str *C.char) error {
- gstr := C.GoString(str)
- if gstr == "" {
- return nil
- }
- return errors.New(gstr)
- }
- // KeyTap taps the keyboard code;
- //
- // See keys supported:
- //
- // https://github.com/go-vgo/robotgo/blob/master/docs/keys.md#keys
- //
- // Examples:
- //
- // robotgo.KeySleep = 100 // 100 millisecond
- // robotgo.KeyTap("a")
- // robotgo.KeyTap("i", "alt", "command")
- //
- // arr := []string{"alt", "command"}
- // robotgo.KeyTap("i", arr)
- //
- // robotgo.KeyTap("k", pid int)
- func KeyTap(key string, args ...interface{}) error {
- var keyArr []string
- if len(key) > 0 && unicode.IsUpper([]rune(key)[0]) {
- args = append(args, "shift")
- }
- key = strings.ToLower(key)
- if _, ok := Special[key]; ok {
- key = Special[key]
- if len(args) <= 0 {
- args = append(args, "shift")
- }
- }
- pid := 0
- if len(args) > 0 {
- if reflect.TypeOf(args[0]) == reflect.TypeOf(keyArr) {
- keyArr = args[0].([]string)
- } else {
- if reflect.TypeOf(args[0]) == reflect.TypeOf(pid) {
- pid = args[0].(int)
- keyArr = ToStrings(args[1:])
- } else {
- keyArr = ToStrings(args)
- }
- }
- }
- return keyTaps(key, keyArr, pid)
- }
- // KeyToggle toggles the keyboard, if there not have args default is "down"
- //
- // See keys:
- //
- // https://github.com/go-vgo/robotgo/blob/master/docs/keys.md#keys
- //
- // Examples:
- //
- // robotgo.KeyToggle("a")
- // robotgo.KeyToggle("a", "up")
- //
- // robotgo.KeyToggle("a", "up", "alt", "cmd")
- // robotgo.KeyToggle("k", pid int)
- func KeyToggle(key string, args ...interface{}) error {
- if len(key) > 0 && unicode.IsUpper([]rune(key)[0]) {
- args = append(args, "shift")
- }
- key = strings.ToLower(key)
- if _, ok := Special[key]; ok {
- key = Special[key]
- if len(args) <= 1 {
- args = append(args, "shift")
- }
- }
- pid := 0
- var keyArr []string
- if len(args) > 0 && reflect.TypeOf(args[0]) == reflect.TypeOf(pid) {
- pid = args[0].(int)
- keyArr = ToStrings(args[1:])
- } else {
- keyArr = ToStrings(args)
- }
- return keyToggles(key, keyArr, pid)
- }
- // KeyPress press key string
- func KeyPress(key string, args ...interface{}) error {
- err := KeyDown(key, args...)
- if err != nil {
- return err
- }
- MilliSleep(1 + rand.Intn(3))
- return KeyUp(key, args...)
- }
- // KeyDown press down a key
- func KeyDown(key string, args ...interface{}) error {
- return KeyToggle(key, args...)
- }
- // KeyUp press up a key
- func KeyUp(key string, args ...interface{}) error {
- arr := []interface{}{"up"}
- arr = append(arr, args...)
- return KeyToggle(key, arr...)
- }
- // ReadAll read string from clipboard
- func ReadAll() (string, error) {
- return clipboard.ReadAll()
- }
- // WriteAll write string to clipboard
- func WriteAll(text string) error {
- return clipboard.WriteAll(text)
- }
- // CharCodeAt char code at utf-8
- func CharCodeAt(s string, n int) rune {
- i := 0
- for _, r := range s {
- if i == n {
- return r
- }
- i++
- }
- return 0
- }
- // UnicodeType tap the uint32 unicode
- func UnicodeType(str uint32, args ...int) {
- cstr := C.uint(str)
- pid := 0
- if len(args) > 0 {
- pid = args[0]
- }
- isPid := 0
- if len(args) > 1 {
- isPid = args[1]
- }
- C.unicodeType(cstr, C.uintptr(pid), C.int8_t(isPid))
- }
- // ToUC trans string to unicode []string
- func ToUC(text string) []string {
- var uc []string
- for _, r := range text {
- textQ := strconv.QuoteToASCII(string(r))
- textUnQ := textQ[1 : len(textQ)-1]
- st := strings.Replace(textUnQ, "\\u", "U", -1)
- if st == "\\\\" {
- st = "\\"
- }
- if st == `\"` {
- st = `"`
- }
- uc = append(uc, st)
- }
- return uc
- }
- func inputUTF(str string) {
- cstr := C.CString(str)
- C.input_utf(cstr)
- C.free(unsafe.Pointer(cstr))
- }
- // TypeStr send a string (supported UTF-8)
- //
- // robotgo.TypeStr(string: "The string to send", int: pid, "milli_sleep time", "x11 option")
- //
- // Examples:
- //
- // robotgo.TypeStr("abc@123, Hi galaxy, こんにちは")
- // robotgo.TypeStr("To be or not to be, this is questions.", pid int)
- func TypeStr(str string, args ...int) {
- var tm, tm1 = 0, 7
- if len(args) > 1 {
- tm = args[1]
- }
- if len(args) > 2 {
- tm1 = args[2]
- }
- pid := 0
- if len(args) > 0 {
- pid = args[0]
- }
- if runtime.GOOS == "linux" {
- strUc := ToUC(str)
- for i := 0; i < len(strUc); i++ {
- ru := []rune(strUc[i])
- if len(ru) <= 1 {
- ustr := uint32(CharCodeAt(strUc[i], 0))
- UnicodeType(ustr, pid)
- } else {
- inputUTF(strUc[i])
- MilliSleep(tm1)
- }
- MilliSleep(tm)
- }
- return
- }
- for i := 0; i < len([]rune(str)); i++ {
- ustr := uint32(CharCodeAt(str, i))
- UnicodeType(ustr, pid)
- // if len(args) > 0 {
- MilliSleep(tm)
- // }
- }
- MilliSleep(KeySleep)
- }
- // PasteStr paste a string (support UTF-8),
- // write the string to clipboard and tap `cmd + v`
- func PasteStr(str string) error {
- err := clipboard.WriteAll(str)
- if err != nil {
- return err
- }
- if runtime.GOOS == "darwin" {
- return KeyTap("v", "command")
- }
- return KeyTap("v", "control")
- }
- // TypeStrDelay type string with delayed
- // And you can use robotgo.KeySleep = 100 to delayed not this function
- func TypeStrDelay(str string, delay int) {
- TypeStr(str)
- MilliSleep(delay)
- }
- // SetDelay sets the key and mouse delay
- // robotgo.SetDelay(100) option the robotgo.KeySleep and robotgo.MouseSleep = d
- func SetDelay(d ...int) {
- v := 10
- if len(d) > 0 {
- v = d[0]
- }
- KeySleep = v
- MouseSleep = v
- }
|