├── .gitignore ├── LICENSE ├── README.md ├── config.file ├── README.md └── ini │ └── config.go ├── gaode.congestion ├── README.md ├── config.ini ├── gaode │ ├── app.go │ ├── config │ │ └── ini │ │ │ └── config.go │ ├── datetime │ │ └── datetime.go │ ├── gaode.go │ └── model │ │ └── congestion_city_rank.go ├── main.exe └── main.go ├── snake.game ├── app │ └── app.go ├── format │ └── format.go ├── log │ └── log.go ├── main.exe └── main.go └── win.control.simulate ├── README.md ├── clicks ├── README.md ├── app │ └── app.go ├── click.ini ├── clicks.exe └── clicks.go └── example.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe~ 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 wxbool 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go语言学习小项目 2 | 3 | 4 | 项目目录: 5 | * snake.game 命令行贪吃蛇小游戏 6 | * win.control.simulate Windows系统模拟控制相关练习 7 | * config.file 配置文件读取封装 8 | * gaode.congestion 高德地图 `主要城市拥堵排名` 数据采集工具 9 | 10 | 11 | 使用方式: 12 | * 尝试编译项目文件夹中的 main.go 文件 或 直接找到项目中 .exe文件 运行 -------------------------------------------------------------------------------- /config.file/README.md: -------------------------------------------------------------------------------- 1 | # 配置文件读取封装 2 | 3 | 已完成: 4 | * .ini 配置文件读取 -------------------------------------------------------------------------------- /config.file/ini/config.go: -------------------------------------------------------------------------------- 1 | package ini 2 | 3 | import ( 4 | "github.com/Unknwon/goconfig" 5 | "strings" 6 | ) 7 | 8 | //获取值类型 9 | const ( 10 | CFG_BOOL = iota 11 | CFG_FLOAT64 12 | CFG_INT 13 | CFG_INT64 14 | CFG_STRING 15 | ) 16 | 17 | type Cfg struct { 18 | filename string //.ini 配置文件 19 | sep string //key.value连接符 20 | 21 | instance goconfig.ConfigFile //配置文件实例 22 | } 23 | 24 | 25 | //加载配置文件 26 | func LoadConfigFile(file string , sep string) (Cfg , error) { 27 | cfg := Cfg{} 28 | config , err := goconfig.LoadConfigFile(file) 29 | if err != nil { 30 | return cfg , err 31 | } 32 | cfg.filename = file 33 | cfg.sep = sep 34 | cfg.instance = *config 35 | return cfg , nil 36 | } 37 | 38 | //根据键名获取值[返回string][失败返回nil] 39 | func (c Cfg) Get(key string) interface{} { 40 | return c.GetValue(key , CFG_STRING , nil) 41 | } 42 | 43 | //根据键名获取值[必须] 44 | func (c Cfg) GetMust(key string , def string) string { 45 | val := c.GetValue(key , CFG_STRING , def) 46 | 47 | if val , ok := val.(string); !ok { 48 | return def 49 | } else { 50 | return val 51 | } 52 | } 53 | 54 | //根据键名获取值[返回bool][失败返回nil] 55 | func (c Cfg) GetBool(key string) interface{} { 56 | return c.GetValue(key , CFG_BOOL , nil) 57 | } 58 | 59 | //根据键名获取值[必须] 60 | func (c Cfg) GetBoolMust(key string , def bool) bool { 61 | val := c.GetValue(key , CFG_BOOL , def) 62 | 63 | if val , ok := val.(bool); !ok { 64 | return def 65 | } else { 66 | return val 67 | } 68 | } 69 | 70 | //根据键名获取值[返回float64][失败返回nil] 71 | func (c Cfg) GetFloat64(key string) interface{} { 72 | return c.GetValue(key , CFG_FLOAT64 , nil) 73 | } 74 | 75 | //根据键名获取值[必须] 76 | func (c Cfg) GetFloat64Must(key string , def float64) float64 { 77 | val := c.GetValue(key , CFG_FLOAT64 , def) 78 | 79 | if val , ok := val.(float64); !ok { 80 | return def 81 | } else { 82 | return val 83 | } 84 | } 85 | 86 | //根据键名获取值[返回int][失败返回nil] 87 | func (c Cfg) GetInt(key string) interface{} { 88 | return c.GetValue(key , CFG_INT , nil) 89 | } 90 | 91 | //根据键名获取值[必须] 92 | func (c Cfg) GetIntMust(key string , def int) int { 93 | val := c.GetValue(key , CFG_INT , def) 94 | 95 | if val , ok := val.(int); !ok { 96 | return def 97 | } else { 98 | return val 99 | } 100 | } 101 | 102 | //根据键名获取值[返回int64][失败返回nil] 103 | func (c Cfg) GetInt64(key string) interface{} { 104 | return c.GetValue(key , CFG_INT64 , nil) 105 | } 106 | 107 | //根据键名获取值[必须] 108 | func (c Cfg) GetInt64Must(key string , def int64) int64 { 109 | val := c.GetValue(key , CFG_INT64 , def) 110 | 111 | if val , ok := val.(int64); !ok { 112 | return def 113 | } else { 114 | return val 115 | } 116 | } 117 | 118 | //获取配置值 119 | func (c Cfg) GetValue(key string , flag int , def interface{}) interface{} { 120 | keysplit := strings.Split(key , c.sep) 121 | if len(keysplit) < 2 { 122 | return def 123 | } 124 | switch flag { 125 | case CFG_BOOL: 126 | if value , err := c.instance.Bool(keysplit[0] , keysplit[1]);err != nil { 127 | return def 128 | } else { 129 | return value 130 | } 131 | case CFG_FLOAT64: 132 | if value , err := c.instance.Float64(keysplit[0] , keysplit[1]);err != nil { 133 | return def 134 | } else { 135 | return value 136 | } 137 | case CFG_INT: 138 | if value , err := c.instance.Int(keysplit[0] , keysplit[1]);err != nil { 139 | return def 140 | } else { 141 | return value 142 | } 143 | case CFG_INT64: 144 | if value , err := c.instance.Int64(keysplit[0] , keysplit[1]);err != nil { 145 | return def 146 | } else { 147 | return value 148 | } 149 | case CFG_STRING: 150 | if value , err := c.instance.GetValue(keysplit[0] , keysplit[1]);err != nil { 151 | return def 152 | } else { 153 | return value 154 | } 155 | } 156 | return def 157 | } -------------------------------------------------------------------------------- /gaode.congestion/README.md: -------------------------------------------------------------------------------- 1 | 高德地图 `主要城市拥堵排名` 数据采集工具 2 | 3 | 目标页面:https://report.amap.com/index.do 4 | 5 | 配置预览: 6 | 7 | ![](http://pan.viggo.site/?/images/2019/10/11/E119ujOAlB/QQ%E6%88%AA%E5%9B%BE20191011173400.jpg) 8 | 9 | -------------------------------------------------------------------------------- /gaode.congestion/config.ini: -------------------------------------------------------------------------------- 1 | [database] 2 | hostname=127.0.0.1 3 | database=gaode 4 | username=root 5 | password=root 6 | port=3306 7 | charset=utf8 8 | prefix=gaode_ 9 | 10 | 11 | [task] 12 | # 仅获取前 n 名城市排名的数据 13 | ranks=30 14 | # 运行开始时间,格式 2019-10-01 15:00:00 15 | startdate=2019-10-11 17:10:00 16 | # 运行截止时间,格式 2019-10-01 15:00:00 17 | stopdate=2019-10-11 17:11:00 18 | # 获取间隔时间(s)秒 19 | intervals=20 -------------------------------------------------------------------------------- /gaode.congestion/gaode/app.go: -------------------------------------------------------------------------------- 1 | package gaode 2 | 3 | import ( 4 | "./config/ini" 5 | "./model" 6 | "./datetime" 7 | "fmt" 8 | "github.com/jinzhu/gorm" 9 | _ "github.com/jinzhu/gorm/dialects/mysql" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | //主应用 15 | type AppGaode struct { 16 | //数据库连接配置 17 | DbConfig struct { 18 | Hostname string 19 | Database string 20 | Username string 21 | Password string 22 | Charset string 23 | Port string 24 | Prefix string 25 | } 26 | //数据库连接 27 | Db *gorm.DB 28 | 29 | Startdate string //运行开始时间 30 | Stopdate string //运行截止时间 31 | Ranks int //仅获取前 n 名城市排名的数据 32 | Intervals int //获取间隔时间(s)秒 33 | } 34 | 35 | 36 | //获取应用 37 | func NewApp(cfg string) *AppGaode { 38 | app := ReadConfig(cfg) 39 | 40 | return app 41 | } 42 | 43 | 44 | //读取配置 45 | func ReadConfig (cfg string) *AppGaode { 46 | if file, e := ini.LoadConfigFile(cfg , ".");e != nil { 47 | panic(e); 48 | } else { 49 | appconfig := &AppGaode{} 50 | appconfig.DbConfig.Hostname = file.GetMust("database.hostname" , "") 51 | appconfig.DbConfig.Database = file.GetMust("database.database" , "") 52 | appconfig.DbConfig.Username = file.GetMust("database.username" , "") 53 | appconfig.DbConfig.Password = file.GetMust("database.password" , "") 54 | appconfig.DbConfig.Charset = file.GetMust("database.charset" , "") 55 | appconfig.DbConfig.Prefix = file.GetMust("database.prefix" , "") 56 | appconfig.DbConfig.Port = file.GetMust("database.port" , "") 57 | 58 | appconfig.Startdate = file.GetMust("task.startdate" , "") 59 | appconfig.Stopdate = file.GetMust("task.stopdate" , "") 60 | appconfig.Ranks = file.GetIntMust("task.ranks" , 100) 61 | appconfig.Intervals = file.GetIntMust("task.intervals" , 300) 62 | 63 | return appconfig 64 | } 65 | } 66 | 67 | 68 | //日志输出 69 | func Log(agrs ...interface{}) { 70 | fmt.Println(agrs ...) 71 | } 72 | 73 | 74 | //初始化应用 75 | func (app *AppGaode) Init() { 76 | //初始化数据库 77 | app.Db = app.dbConnect() 78 | //校验数据表 79 | app.vailDbTables() 80 | } 81 | 82 | 83 | //数据库连接 84 | func (app *AppGaode) dbConnect() (*gorm.DB) { 85 | conn := strings.Join([] string{ 86 | app.DbConfig.Username , ":" , 87 | app.DbConfig.Password , "@(" , 88 | app.DbConfig.Hostname , ":" , 89 | app.DbConfig.Port , ")/" , 90 | app.DbConfig.Database , "?charset=" , 91 | app.DbConfig.Charset , "&parseTime=True&loc=Local" , 92 | } , "") 93 | //连接数据库 94 | db, err := gorm.Open("mysql", conn) 95 | if err != nil { 96 | panic(err) 97 | } 98 | 99 | Log("db connect success .") 100 | 101 | db.LogMode(false) 102 | 103 | // 全局禁用表名复数 104 | db.SingularTable(true) // 如果设置为true,`User`的默认表名为`user`,使用`TableName`设置的表名不受影响 105 | 106 | //设置数据表名规则 107 | gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string { 108 | return app.DbConfig.Prefix + defaultTableName; 109 | } 110 | 111 | return db 112 | } 113 | 114 | 115 | //校验数据表 116 | func (app *AppGaode) vailDbTables() { 117 | if !app.Db.HasTable(&model.CongestionCitysRank{}) { 118 | if e := app.Db.CreateTable(&model.CongestionCitysRank{}).Error; e != nil { 119 | panic(e) 120 | } 121 | } 122 | 123 | Log("verification db tables .") 124 | } 125 | 126 | 127 | //运行任务 128 | func (app *AppGaode) Run() { 129 | 130 | if app.Stopdate == "" { 131 | Log("stopdate empty .") 132 | return 133 | } 134 | 135 | //解析开始时间 136 | starttime, e := datetime.DateStringToTime(app.Startdate , datetime.DATETIME) 137 | if e != nil { 138 | Log("starttime wrong format ."); 139 | return 140 | } 141 | if starttime.Unix() <= 0 { 142 | Log("starttime wrong format ."); 143 | return 144 | } 145 | 146 | //解析终止时间 147 | endtime, e := datetime.DateStringToTime(app.Stopdate , datetime.DATETIME) 148 | if e != nil { 149 | Log("stopdate wrong format ."); 150 | return 151 | } 152 | if endtime.Unix() <= 0 { 153 | Log("stopdate wrong format ."); 154 | return 155 | } 156 | 157 | //校验日期范围 158 | if starttime.Unix() >= endtime.Unix() { 159 | Log("date configuration error ."); 160 | return 161 | } 162 | 163 | tips := false 164 | 165 | for { 166 | //当前日期 167 | nowtime := time.Now() 168 | //未到开始时间 169 | if starttime.Unix() > nowtime.Unix() { 170 | 171 | if tips == false { 172 | //提示等待中 173 | Log("waiting the task to begin .") 174 | tips = true; 175 | } 176 | 177 | continue; 178 | } 179 | //已到截止时间 180 | if endtime.Unix() <= nowtime.Unix() { 181 | Log("end of task ."); 182 | break; 183 | } 184 | 185 | //执行获取 186 | Log("start gets ...") 187 | 188 | gaodeData := Gets(app.Ranks) 189 | 190 | Log("gets finish ...") 191 | 192 | //数据入库 193 | app.putStorage(gaodeData) 194 | 195 | Log("puts finish ...") 196 | 197 | Log("waiting " , app.Intervals , " seconds .") 198 | 199 | time.Sleep(time.Duration(app.Intervals) * time.Second) //等待间隔(s) 200 | } 201 | } 202 | 203 | 204 | 205 | //采集结果入库 206 | func (app *AppGaode) putStorage(data [] *GaodeGetsData) { 207 | lens := len(data) 208 | if lens == 0 { 209 | return 210 | } 211 | 212 | version := time.Now().Unix(); 213 | 214 | for _ , gaode := range data { 215 | //创建文章列表 216 | rows := &model.CongestionCitysRank{ 217 | City:gaode.City, 218 | Idx:gaode.Idx, 219 | RealSpeed:gaode.RealSpeed, 220 | FreeFlowSpeed:gaode.FreeFlowSpeed, 221 | Value:gaode.Value, 222 | Version:version, 223 | } 224 | 225 | if app.Db.NewRecord(rows) { 226 | app.Db.Create(&rows) 227 | Log("insert rows : " , rows.City , rows.ID) 228 | } 229 | } 230 | } -------------------------------------------------------------------------------- /gaode.congestion/gaode/config/ini/config.go: -------------------------------------------------------------------------------- 1 | package ini 2 | 3 | import ( 4 | "github.com/Unknwon/goconfig" 5 | "strings" 6 | ) 7 | 8 | //获取值类型 9 | const ( 10 | CFG_BOOL = iota 11 | CFG_FLOAT64 12 | CFG_INT 13 | CFG_INT64 14 | CFG_STRING 15 | ) 16 | 17 | type Cfg struct { 18 | filename string //.ini 配置文件 19 | sep string //key.value连接符 20 | 21 | instance goconfig.ConfigFile //配置文件实例 22 | } 23 | 24 | 25 | //加载配置文件 26 | func LoadConfigFile(file string , sep string) (Cfg , error) { 27 | cfg := Cfg{} 28 | config , err := goconfig.LoadConfigFile(file) 29 | if err != nil { 30 | return cfg , err 31 | } 32 | cfg.filename = file 33 | cfg.sep = sep 34 | cfg.instance = *config 35 | return cfg , nil 36 | } 37 | 38 | //根据键名获取值[返回string][失败返回nil] 39 | func (c Cfg) Get(key string) interface{} { 40 | return c.GetValue(key , CFG_STRING , nil) 41 | } 42 | 43 | //根据键名获取值[必须] 44 | func (c Cfg) GetMust(key string , def string) string { 45 | val := c.GetValue(key , CFG_STRING , def) 46 | 47 | if val , ok := val.(string); !ok { 48 | return def 49 | } else { 50 | return val 51 | } 52 | } 53 | 54 | //根据键名获取值[返回bool][失败返回nil] 55 | func (c Cfg) GetBool(key string) interface{} { 56 | return c.GetValue(key , CFG_BOOL , nil) 57 | } 58 | 59 | //根据键名获取值[必须] 60 | func (c Cfg) GetBoolMust(key string , def bool) bool { 61 | val := c.GetValue(key , CFG_BOOL , def) 62 | 63 | if val , ok := val.(bool); !ok { 64 | return def 65 | } else { 66 | return val 67 | } 68 | } 69 | 70 | //根据键名获取值[返回float64][失败返回nil] 71 | func (c Cfg) GetFloat64(key string) interface{} { 72 | return c.GetValue(key , CFG_FLOAT64 , nil) 73 | } 74 | 75 | //根据键名获取值[必须] 76 | func (c Cfg) GetFloat64Must(key string , def float64) float64 { 77 | val := c.GetValue(key , CFG_FLOAT64 , def) 78 | 79 | if val , ok := val.(float64); !ok { 80 | return def 81 | } else { 82 | return val 83 | } 84 | } 85 | 86 | //根据键名获取值[返回int][失败返回nil] 87 | func (c Cfg) GetInt(key string) interface{} { 88 | return c.GetValue(key , CFG_INT , nil) 89 | } 90 | 91 | //根据键名获取值[必须] 92 | func (c Cfg) GetIntMust(key string , def int) int { 93 | val := c.GetValue(key , CFG_INT , def) 94 | 95 | if val , ok := val.(int); !ok { 96 | return def 97 | } else { 98 | return val 99 | } 100 | } 101 | 102 | //根据键名获取值[返回int64][失败返回nil] 103 | func (c Cfg) GetInt64(key string) interface{} { 104 | return c.GetValue(key , CFG_INT64 , nil) 105 | } 106 | 107 | //根据键名获取值[必须] 108 | func (c Cfg) GetInt64Must(key string , def int64) int64 { 109 | val := c.GetValue(key , CFG_INT64 , def) 110 | 111 | if val , ok := val.(int64); !ok { 112 | return def 113 | } else { 114 | return val 115 | } 116 | } 117 | 118 | //获取配置值 119 | func (c Cfg) GetValue(key string , flag int , def interface{}) interface{} { 120 | keysplit := strings.Split(key , c.sep) 121 | if len(keysplit) < 2 { 122 | return def 123 | } 124 | switch flag { 125 | case CFG_BOOL: 126 | if value , err := c.instance.Bool(keysplit[0] , keysplit[1]);err != nil { 127 | return def 128 | } else { 129 | return value 130 | } 131 | case CFG_FLOAT64: 132 | if value , err := c.instance.Float64(keysplit[0] , keysplit[1]);err != nil { 133 | return def 134 | } else { 135 | return value 136 | } 137 | case CFG_INT: 138 | if value , err := c.instance.Int(keysplit[0] , keysplit[1]);err != nil { 139 | return def 140 | } else { 141 | return value 142 | } 143 | case CFG_INT64: 144 | if value , err := c.instance.Int64(keysplit[0] , keysplit[1]);err != nil { 145 | return def 146 | } else { 147 | return value 148 | } 149 | case CFG_STRING: 150 | if value , err := c.instance.GetValue(keysplit[0] , keysplit[1]);err != nil { 151 | return def 152 | } else { 153 | return value 154 | } 155 | } 156 | return def 157 | } -------------------------------------------------------------------------------- /gaode.congestion/gaode/datetime/datetime.go: -------------------------------------------------------------------------------- 1 | package datetime 2 | 3 | import "time" 4 | 5 | const ( 6 | DATE = 1 //字符串日期类型:2008-06-01 7 | DATETIME = 2 //字符串日期类型:2008-06-01 12:01:01 8 | ) 9 | 10 | 11 | func DateStringToTime (value string , valueType int) (time.Time , error) { 12 | timeLayout := "" 13 | switch valueType { 14 | case DATE: 15 | timeLayout = "2006-01-02" 16 | case DATETIME: 17 | timeLayout = "2006-01-02 15:04:05" 18 | } 19 | 20 | loc , e := time.LoadLocation("Local") //本地时区 21 | if e != nil { 22 | return time.Now() , e 23 | } 24 | time , e := time.ParseInLocation(timeLayout , value , loc) 25 | if e != nil { 26 | return time , e 27 | } 28 | 29 | return time , nil 30 | } -------------------------------------------------------------------------------- /gaode.congestion/gaode/gaode.go: -------------------------------------------------------------------------------- 1 | package gaode 2 | 3 | import ( 4 | "github.com/buger/jsonparser" 5 | "io/ioutil" 6 | "net/http" 7 | "strconv" 8 | ) 9 | 10 | type GaodeGetsData struct { 11 | City string //城市名称 12 | Idx string //拥堵指数 13 | RealSpeed string //平均行车速度(km/h) 14 | FreeFlowSpeed string //畅通行车速度(km/h) 15 | Value int //城市排名 16 | } 17 | 18 | 19 | func CheckError (e error) { 20 | if e != nil { 21 | panic(e) 22 | } 23 | } 24 | 25 | 26 | //执行一次获取 27 | func Gets(ranks int) ([] *GaodeGetsData) { 28 | 29 | targetApi := "https://report.amap.com/ajax/getCityRank.do" 30 | 31 | request, e := http.NewRequest(http.MethodGet, targetApi , nil) 32 | CheckError(e) 33 | 34 | request.Header.Set("Host" , "report.amap.com") 35 | request.Header.Set("Referer" , "https://report.amap.com/index.do") 36 | request.Header.Set("User-Agent" , "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.204 Safari/537.36") 37 | 38 | response, e := http.DefaultClient.Do(request) 39 | CheckError(e) 40 | 41 | content, e := ioutil.ReadAll(response.Body) 42 | CheckError(e) 43 | 44 | if string(content) == "" { 45 | panic("gets error .") 46 | } 47 | 48 | //声明结果队列 49 | result := make([] *GaodeGetsData , 0) 50 | index := 0 //获取计数 51 | //遍历 52 | jsonparser.ArrayEach(content , func(value []byte, dataType jsonparser.ValueType, offset int, err error) { 53 | index++ 54 | 55 | if index > ranks { 56 | return //跳过获取 57 | } 58 | 59 | gaode := &GaodeGetsData{} 60 | 61 | city , _ := jsonparser.GetString(value, "label") 62 | idx , _ := jsonparser.GetFloat(value, "idx") 63 | realSpeed , _ := jsonparser.GetFloat(value, "realSpeed") 64 | freeFlowSpeed , _ := jsonparser.GetFloat(value, "freeFlowSpeed") 65 | valueint , _ := jsonparser.GetInt(value, "value") 66 | 67 | gaode.City = city 68 | gaode.Idx = strconv.FormatFloat(idx, 'f', 2, 64) 69 | gaode.RealSpeed = strconv.FormatFloat(realSpeed, 'f', 2, 64) 70 | gaode.FreeFlowSpeed = strconv.FormatFloat(freeFlowSpeed, 'f', 2, 64) 71 | gaode.Value = int(valueint) 72 | 73 | result = append(result , gaode) 74 | }) 75 | 76 | return result 77 | } 78 | 79 | -------------------------------------------------------------------------------- /gaode.congestion/gaode/model/congestion_city_rank.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | //拥堵城市排行榜 8 | type CongestionCitysRank struct { 9 | ID uint `gorm:"primary_key"` 10 | CreatedAt time.Time `gorm:"type:datetime;"` 11 | UpdatedAt time.Time `gorm:"type:datetime;"` 12 | DeletedAt *time.Time `gorm:"type:datetime"` 13 | 14 | City string `gorm:"type:varchar(25);default:''"` //城市名称 15 | Idx string `gorm:"type:char(8);"` //拥堵指数 16 | RealSpeed string `gorm:"type:char(8);"` //平均行车速度(km/h) 17 | FreeFlowSpeed string `gorm:"type:char(8);"` //畅通行车速度(km/h) 18 | Value int `gorm:"type:int(8);"` //城市排名 19 | Version int64 `gorm:"type:int(11);default:0"` //入库版本 20 | } -------------------------------------------------------------------------------- /gaode.congestion/main.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxbool/Go-LearnProject/8f6bda24cba2bf9a0fbb7e238bd1277b30a70cf5/gaode.congestion/main.exe -------------------------------------------------------------------------------- /gaode.congestion/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./gaode" 5 | "log" 6 | "time" 7 | ) 8 | 9 | //定义配置文件 10 | const CONFIG = "config.ini" 11 | 12 | func main() { 13 | 14 | //致命错误捕获 15 | defer func() { 16 | if err := recover(); err != nil { 17 | log.Printf("Error : %v", err) 18 | 19 | time.Sleep(time.Second * 8) 20 | } 21 | }() 22 | 23 | //获取应用 24 | app := gaode.NewApp(CONFIG) 25 | 26 | //初始化应用 27 | app.Init() 28 | 29 | //运行任务 30 | app.Run() 31 | 32 | //延迟退出 33 | time.Sleep(time.Second * 10) 34 | } 35 | -------------------------------------------------------------------------------- /snake.game/app/app.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import "github.com/nsf/termbox-go" 4 | 5 | type AppRun struct { 6 | UpEvent func() 7 | DownEvent func() 8 | LeftEvent func() 9 | RightEvent func() 10 | EnterEvent func() 11 | EscEvent func() 12 | } 13 | 14 | //开始运行 15 | func (app AppRun) Run() { 16 | 17 | //注册监听 18 | //初始化 19 | err := termbox.Init() 20 | if err != nil { 21 | panic(err) 22 | } 23 | //结束的时候,记得关闭 24 | defer termbox.Close() 25 | 26 | //阻塞监听键盘事件 27 | Loop: 28 | for { 29 | //termbox.PollEvent() 这个监控事件输入,保存到ev 30 | //ev.Type 事件类型 31 | //ev.Key 一些特殊按键,比如 key+c F1 F2 Esc Enter等 32 | //ev.Ch 正常的字符健. abcd 1234 33 | //termbox.EventKey 判断是否键盘事件 34 | //termbox.EventResize 判断是否调整窗口大小 35 | //termbox.EventMouse 判断是否鼠标事件 36 | //termbox.EventError 判断错误事件 37 | //termbox.EventInterrupt 判断终止事件. 38 | 39 | switch ev := termbox.PollEvent(); ev.Type { 40 | case termbox.EventKey: 41 | switch ev.Key { 42 | case 27: //Esc 43 | app.EscEvent() //退出事件 44 | break Loop 45 | case 65517: //Up 46 | app.UpEvent() 47 | case 65516: //Down 48 | app.DownEvent() 49 | case 65515: //Left 50 | app.LeftEvent() 51 | case 65514: //Right 52 | app.RightEvent() 53 | case 13: //Enter 54 | app.EnterEvent() 55 | } 56 | 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /snake.game/format/format.go: -------------------------------------------------------------------------------- 1 | package format 2 | 3 | import ( 4 | "math/rand" 5 | "strconv" 6 | "time" 7 | ) 8 | 9 | //行进方向 10 | const ( 11 | PATH_UP = 1 12 | PATH_DOWN = 2 13 | PATH_LEFT = 3 14 | PATH_RIGHT = 4 15 | ) 16 | 17 | type Food struct { 18 | x int //x坐标 19 | y int //y坐标 20 | } 21 | 22 | type GameCanvas struct { 23 | Width int 24 | Height int 25 | 26 | GameFood Food //食物坐标 27 | FoodSymbol string //食物符号 28 | Grade int //分数 29 | ReduceSpeed time.Duration //蛇移动速度递减量 30 | } 31 | 32 | type Snake struct { //一条蛇 33 | len int //总长度 34 | maxX int //最大x坐标 35 | maxY int //最大y坐标 36 | body [][]int //蛇坐标 37 | path int //行进方向 38 | speed time.Duration //速度 39 | symbol string //蛇体符号 40 | fail string //失败信息 41 | } 42 | 43 | 44 | //创建新面板 45 | func (canvas *GameCanvas) NewGameCanvas(snake Snake) string { 46 | //随机生成一个食物 47 | fx , fy := RandomFood(snake.maxX , snake.maxY) 48 | canvas.GameFood.x = fx 49 | canvas.GameFood.y = fy 50 | canvas.Grade = 0 51 | 52 | return drawCanvas(*canvas , snake) 53 | } 54 | 55 | //创建一条蛇 56 | func (canvas GameCanvas) NewSnake(len int , body [][]int , symbol string , speed time.Duration) Snake { 57 | snake := Snake{ 58 | len:len, 59 | body:body, 60 | maxX:canvas.Width-3, 61 | maxY:canvas.Height-3, 62 | speed:speed, 63 | symbol:symbol, 64 | } 65 | return snake 66 | } 67 | 68 | //改变蛇的方向 69 | func (canvas GameCanvas) ChangeSnakePath(snake *Snake , path int) { 70 | switch snake.path { 71 | case PATH_UP: 72 | if path == PATH_DOWN { 73 | return 74 | } 75 | case PATH_DOWN: 76 | if path == PATH_UP { 77 | return 78 | } 79 | case PATH_LEFT: 80 | if path == PATH_RIGHT { 81 | return 82 | } 83 | case PATH_RIGHT: 84 | if path == PATH_LEFT { 85 | return 86 | } 87 | } 88 | snake.path = path 89 | } 90 | 91 | //将蛇往下移 92 | func (canvas *GameCanvas) MoveDownSnake(snake *Snake) string { 93 | newhead := []int{snake.body[0][0] , snake.body[0][1]+1} //设置头部坐标 94 | replaceSnake(newhead , snake , canvas) 95 | return drawCanvas(*canvas , *snake) 96 | } 97 | 98 | //将蛇往上移 99 | func (canvas *GameCanvas) MoveUpSnake(snake *Snake) string { 100 | newhead := []int{snake.body[0][0] , snake.body[0][1]-1} //设置头部坐标 101 | replaceSnake(newhead , snake , canvas) 102 | return drawCanvas(*canvas , *snake) 103 | } 104 | 105 | //将蛇向右移动 106 | func (canvas *GameCanvas) MoveRightSnake(snake *Snake) string { 107 | newhead := []int{snake.body[0][0]+1 , snake.body[0][1]} 108 | replaceSnake(newhead , snake , canvas) 109 | return drawCanvas(*canvas , *snake) 110 | } 111 | 112 | //将蛇向左移动 113 | func (canvas *GameCanvas) MoveLeftSnake(snake *Snake) string { 114 | newhead := []int{snake.body[0][0]-1 , snake.body[0][1]} //设置头部坐标 115 | replaceSnake(newhead , snake , canvas) 116 | return drawCanvas(*canvas , *snake) 117 | } 118 | 119 | //随机获取一个食物坐标 120 | func RandomFood(maxX int , maxY int) (x int , y int) { 121 | rand.Seed(time.Now().UnixNano()) 122 | x = rand.Intn(maxX) 123 | rand.Seed(time.Now().UnixNano()) 124 | y = rand.Intn(maxY) 125 | return 126 | } 127 | 128 | //替换蛇身体 129 | func replaceSnake(newhead []int , snake *Snake , canvas *GameCanvas) { 130 | len := len(snake.body) 131 | newbody := make([][]int , 0 , len) 132 | 133 | //吃到食物 134 | if (newhead[0] == canvas.GameFood.x) && (newhead[1] == canvas.GameFood.y) { 135 | //吃到果子,追加蛇节点 136 | newbody = append(newbody , []int{newhead[0] , newhead[1]}) 137 | for index , _ := range snake.body { 138 | newbody = append(newbody , []int{snake.body[index][0] , snake.body[index][1]}) 139 | } 140 | //重新生成食物 141 | fx , fy := RandomFood(snake.maxX , snake.maxY) 142 | canvas.GameFood.x = fx 143 | canvas.GameFood.y = fy 144 | //速度递减 145 | snake.speed -= canvas.ReduceSpeed 146 | //加分数 147 | canvas.Grade++ 148 | } else { 149 | //移动蛇节点 150 | for index , _ := range snake.body { 151 | if index == 0 { 152 | newbody = append(newbody , []int{newhead[0] , newhead[1]}) 153 | } else { 154 | newbody = append(newbody , []int{snake.body[index - 1][0] , snake.body[index - 1][1]}) 155 | } 156 | } 157 | } 158 | 159 | //检测蛇身冲突 160 | //检测蛇是否撞墙 161 | for index , _ := range newbody { 162 | if index != 0 { 163 | if (newhead[0] == newbody[index][0]) && (newhead[1] == newbody[index][1]) { 164 | //冲突 165 | snake.fail = "You lose"; 166 | } 167 | } 168 | 169 | if newbody[index][0] > snake.maxX || newbody[index][0] < 0 { 170 | //撞墙 171 | snake.fail = "You lose"; 172 | } 173 | if newbody[index][1] > snake.maxY || newbody[index][1] < 0 { 174 | //撞墙 175 | snake.fail = "You lose"; 176 | } 177 | } 178 | 179 | snake.body = newbody 180 | } 181 | 182 | 183 | //蛇自动行进 184 | func (canvas GameCanvas) Watch(snake *Snake , callback func (string)) { 185 | var box string 186 | 187 | for { 188 | 189 | time.Sleep(time.Millisecond * snake.speed) 190 | if snake.path == 0 { 191 | continue 192 | } 193 | 194 | //蛇行进失败 195 | if snake.fail != "" { 196 | box := drawCanvas(canvas , *snake) 197 | box += "\n" + snake.fail 198 | callback(box) 199 | break 200 | } 201 | 202 | switch snake.path { 203 | case PATH_UP: 204 | box = canvas.MoveUpSnake(snake) 205 | case PATH_DOWN: 206 | box = canvas.MoveDownSnake(snake) 207 | case PATH_LEFT: 208 | box = canvas.MoveLeftSnake(snake) 209 | case PATH_RIGHT: 210 | box = canvas.MoveRightSnake(snake) 211 | } 212 | 213 | callback(box) 214 | } 215 | } 216 | 217 | 218 | //输出游戏面板 219 | func drawCanvas(canvas GameCanvas , snake Snake) string { 220 | fmtout := "" 221 | fmtout += "\n\n\n\n\n" 222 | 223 | for h:=0;h 蛇x坐标 282 | func getX(canvas GameCanvas , x int) int { 283 | if x == 0 || x == canvas.Width-1 { 284 | return -1 285 | } 286 | return x-1 287 | } 288 | 289 | //画布y坐标 -> 蛇y坐标 290 | func getY(canvas GameCanvas , y int) int { 291 | if y == 0 || y == canvas.Height-1 { 292 | return -1 293 | } 294 | return y-1 295 | } -------------------------------------------------------------------------------- /snake.game/log/log.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | //日志存储文件 9 | const LOGFILE = "log.txt" 10 | 11 | 12 | //写入日志 13 | func WriteLog(text ...interface{}) { 14 | if err := checkLogFile(LOGFILE); err != nil { 15 | panic(err.Error()) 16 | return 17 | } 18 | logfile , err := os.OpenFile(LOGFILE , os.O_APPEND , os.ModePerm) 19 | if err != nil { 20 | panic(err.Error()) 21 | return 22 | } 23 | 24 | defer logfile.Close() //关闭 25 | 26 | debugLog := log.New(logfile , "[info]" , log.Llongfile) 27 | debugLog.Println(text) 28 | } 29 | 30 | 31 | //检测日志文件 32 | func checkLogFile (path string) (error) { 33 | file , err := os.Open(path) 34 | if err != nil { 35 | if os.IsNotExist(err) { 36 | newfile , err := os.Create(path) 37 | if err != nil { 38 | return err 39 | } 40 | newfile.Close() 41 | } 42 | } 43 | file.Close() 44 | return nil 45 | } 46 | 47 | -------------------------------------------------------------------------------- /snake.game/main.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxbool/Go-LearnProject/8f6bda24cba2bf9a0fbb7e238bd1277b30a70cf5/snake.game/main.exe -------------------------------------------------------------------------------- /snake.game/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gosuri/uilive" 6 | appGame "snake.game/app" 7 | "snake.game/format" 8 | "time" 9 | ) 10 | 11 | func main() { 12 | 13 | var app = appGame.AppRun{} 14 | var game = format.GameCanvas{Width:50,Height:25,FoodSymbol:"$",ReduceSpeed:5} //创建实例 15 | var snake = game.NewSnake(5 , [][]int{{3,3} , {3,4} , {3,5}} , "O" , 180) //初始化蛇 16 | var init = false //游戏初始化 17 | 18 | //缓冲区 19 | writer := uilive.New() 20 | writer.Start() 21 | 22 | //注册事件 23 | app.EnterEvent = func() { 24 | if !init { 25 | box := game.NewGameCanvas(snake) 26 | fmt.Fprintln(writer, box) 27 | 28 | //自动行进注册 29 | go func() { 30 | game.Watch(&snake , func(box string) { 31 | fmt.Fprintln(writer, box) 32 | }) 33 | }() 34 | } 35 | init = true 36 | } 37 | //上移 38 | app.UpEvent = func() { 39 | game.ChangeSnakePath(&snake , format.PATH_UP) 40 | } 41 | //下移 42 | app.DownEvent = func() { 43 | game.ChangeSnakePath(&snake , format.PATH_DOWN) 44 | } 45 | //右移 46 | app.RightEvent = func() { 47 | game.ChangeSnakePath(&snake , format.PATH_RIGHT) 48 | } 49 | //左移 50 | app.LeftEvent = func() { 51 | game.ChangeSnakePath(&snake , format.PATH_LEFT) 52 | } 53 | 54 | //退出 55 | app.EscEvent = func() { 56 | fmt.Fprintln(writer, "游戏已退出") 57 | } 58 | 59 | fmt.Fprintln(writer, "按 Enter 键开始游戏") 60 | fmt.Fprintln(writer, "按 Esc 退出游戏") 61 | fmt.Fprintln(writer, "使用 上下左右键 来控制游戏") 62 | 63 | time.Sleep(time.Millisecond * 1500) 64 | 65 | app.Run() 66 | 67 | writer.Stop() 68 | } 69 | 70 | -------------------------------------------------------------------------------- /win.control.simulate/README.md: -------------------------------------------------------------------------------- 1 | # Windows 模拟控制 2 | 3 | 主要使用了 Robotgo库,完成客户端模拟控制 4 | 5 | 6 | 7 | 小项目: 8 | * 鼠标模拟点击器 -------------------------------------------------------------------------------- /win.control.simulate/clicks/README.md: -------------------------------------------------------------------------------- 1 | # Windows 鼠标模拟点击器 2 | 3 | 使用方法: 4 | * 打开 click.ini 进行坐标配置,运行 clicks.exe 即可 5 | -------------------------------------------------------------------------------- /win.control.simulate/clicks/app/app.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "github.com.wxbool/go.learn.project/config.file/ini" 5 | "github.com/go-vgo/robotgo" 6 | "strconv" 7 | "strings" 8 | "time" 9 | ) 10 | 11 | type Coordinate struct { 12 | X int //X坐标点 13 | Y int //Y坐标点 14 | Click string //点击鼠标按键 => left/center/right 15 | Dbclick bool //是否双击 16 | Nums int //点击次数 17 | } 18 | 19 | //点击器配置 20 | type ClickCfg struct { 21 | Coordinate []*Coordinate //点击坐标点切片 22 | StartWait int //任务开始前等待时间(秒s) 23 | ClickWait int //多个坐标点点击间隔时间(毫秒ms),1000ms = 1s 24 | Loops int //任务执行循环次数 25 | Mouse bool //是否模拟鼠标移动过程(true/false) 26 | } 27 | 28 | 29 | //根据配置文件实例应用 30 | func NewApp(cfg string) (app *ClickCfg) { 31 | //读取配置 32 | app = readConfig(cfg) 33 | return 34 | } 35 | 36 | 37 | //运行 38 | func (app *ClickCfg) Run() { 39 | //开始运行等待(s) 40 | time.Sleep(time.Second * time.Duration(app.StartWait)) 41 | 42 | //遍历点击 43 | for _ , item := range app.Coordinate { 44 | if item.Nums <= 0 { 45 | continue 46 | } 47 | //执行次数 48 | index := 0 49 | for index < item.Nums { 50 | if app.Mouse { //模拟鼠标移动 51 | //移动到目标坐标 52 | robotgo.MoveMouseSmooth(item.X , item.Y) 53 | //鼠标点击 54 | robotgo.MouseClick(item.Click , item.Dbclick) 55 | } else { 56 | //移动到目标位置,并点击 57 | robotgo.MoveClick(item.X , item.Y , item.Click , item.Dbclick) 58 | } 59 | 60 | //执行后间隔等待 61 | time.Sleep(time.Millisecond * time.Duration(app.ClickWait)) 62 | 63 | index++ 64 | } 65 | } 66 | } 67 | 68 | 69 | //获取配置 70 | func readConfig(cfg string) *ClickCfg { 71 | if c , err := ini.LoadConfigFile(cfg , ".");err != nil { 72 | panic(err) 73 | } else { 74 | clickCfg := &ClickCfg{} 75 | clickCfg.StartWait = c.GetIntMust("task.startwait" , 0) 76 | clickCfg.ClickWait = c.GetIntMust("task.clickwait" , 0) 77 | clickCfg.Loops = c.GetIntMust("task.loops" , 1) 78 | clickCfg.Mouse = c.GetBoolMust("task.mouse" , true) 79 | 80 | //获取坐标列表 81 | coordinate := c.GetMust("task.coordinate" , "") 82 | //解析坐标列表 83 | clickCfg.Coordinate = readCoordinate(coordinate) 84 | 85 | return clickCfg 86 | } 87 | } 88 | 89 | //解析坐标列表 90 | func readCoordinate(coord string) []*Coordinate { 91 | if coord == "" { 92 | panic("Task coordinate points is empty .") 93 | } 94 | 95 | taskSlice := make([]*Coordinate , 0 , 20) 96 | //分隔 97 | coordSlice := strings.Split(coord , "|") 98 | 99 | for _ , co := range coordSlice { 100 | thisCoord := strings.Split(co , ",") 101 | //检测格式 102 | if len(thisCoord) != 5 { 103 | panic("Task coordinate point input format error .") 104 | } 105 | 106 | x := thisCoord[0] 107 | y := thisCoord[1] 108 | click := thisCoord[2] 109 | dbclick := thisCoord[3] 110 | nums := thisCoord[4] 111 | 112 | xVal , err := strconv.Atoi(x) 113 | if err != nil { 114 | panic("X coordinate error .") 115 | } 116 | yVal , err := strconv.Atoi(y) 117 | if err != nil { 118 | panic("X coordinate error .") 119 | } 120 | //left/center/right 121 | if click != "left" && click != "center" && click != "right" { 122 | panic("coordinate error : "+ click) 123 | } 124 | dbVal , err := strconv.ParseBool(dbclick) 125 | if err != nil { 126 | panic("coordinate error : " + dbclick) 127 | } 128 | numsVal , err := strconv.Atoi(nums) 129 | if err != nil { 130 | panic("coordinate error : " + nums) 131 | } 132 | 133 | taskSlice = append(taskSlice , &Coordinate{X:xVal , Y:yVal , Click:click , Dbclick:dbVal , Nums:numsVal}) 134 | } 135 | return taskSlice 136 | } -------------------------------------------------------------------------------- /win.control.simulate/clicks/click.ini: -------------------------------------------------------------------------------- 1 | [task] 2 | ;任务坐标点,支持多个,使用 | 隔开 3 | ;单个坐标点格式:x,y,left/center/right,true/false,1 => (x坐标,y坐标,鼠标点击按键[左键/中键/右键],是否双击,点击次数) 4 | coordinate=1072,10,left,false,1|1308,12,left,false,1|1550,12,left,false,1|1550,12,right,false,1 5 | ;任务开始前等待时间(秒s) 6 | startwait=1 7 | ;多个坐标点点击间隔时间(毫秒ms),1000ms = 1s 8 | clickwait=1000 9 | ;任务执行循环次数 10 | loops=1 11 | ;是否模拟鼠标移动过程(true/false) 12 | mouse=true -------------------------------------------------------------------------------- /win.control.simulate/clicks/clicks.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxbool/Go-LearnProject/8f6bda24cba2bf9a0fbb7e238bd1277b30a70cf5/win.control.simulate/clicks/clicks.exe -------------------------------------------------------------------------------- /win.control.simulate/clicks/clicks.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | appclick "github.com.wxbool/go.learn.project/win.control.simulate/clicks/app" 6 | "log" 7 | "time" 8 | ) 9 | 10 | //配置文件 11 | const CONFIG = "click.ini" 12 | 13 | //模拟点击小程序 14 | func main() { 15 | 16 | //致命错误捕获 17 | defer func() { 18 | if err := recover(); err != nil { 19 | log.Printf("Error : %v", err) 20 | 21 | time.Sleep(time.Second * 8) 22 | } 23 | }() 24 | 25 | app := appclick.NewApp(CONFIG) 26 | 27 | loop := 0 //任务执行次数 28 | for loop < app.Loops { 29 | app.Run() 30 | 31 | loop++ 32 | } 33 | 34 | fmt.Println("finish .") 35 | 36 | time.Sleep(time.Millisecond * 500) 37 | 38 | } -------------------------------------------------------------------------------- /win.control.simulate/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | 4 | func main() { 5 | 6 | 7 | //模拟热键WIN+R 8 | //robotgo.KeyTap("R", "command") //模拟热键WIN+R 9 | 10 | //KeyToggle的使用,按下或抬起按键 11 | //.KeyToggle(按键,按下或抬起,按键,按键...) 12 | //.KeyToggle(按键,"down"/"up",按键,按键...) 13 | //robotgo.KeyToggle("r", "down" , "command") 14 | //robotgo.KeyToggle("a" , "down", "alt", "control") //长按ctrl+alt+a,如果打开了QQ,按下A可以截图 15 | 16 | 17 | 18 | 19 | //TypeStr的使用,在输入框中输入字符串 20 | //这个有缺陷,Hello真的打印出来可能是Helo,少字母 21 | //TypeStr(要打印的字符) 22 | //robotgo.TypeStr("Hello") 23 | 24 | //TypeStrDelay的使用,在输入框中输入字符串 25 | //TypeStrDelay(要打印的字符,每分钟输出的字符数) 26 | //robotgo.TypeStrDelay("Hello",500) 27 | 28 | 29 | 30 | 31 | //MoveMouse,移动鼠标到目标位置 32 | //MoveMouse(横向坐标,纵向坐标) 33 | //robotgo.MoveMouse(600,400) 34 | 35 | //MoveMouseSmooth,平滑移动到目标位置,模仿人类操作 36 | //MoveMouseSmooth(横向坐标,纵向坐标) 37 | //robotgo.MoveMouseSmooth(600,400) 38 | //robotgo.MoveMouseSmooth(600,400,1.0 , 20.0)//后面两个参数文档上看lowspeed, highspeed,与速度相关,是能改变移动速度,但是没搞清究竟是怎么个改变的 39 | 40 | //MouseClick,鼠标点击事件 41 | //MouseClick(哪一个键,是否双击) 42 | //MouseClick("left/center/right",true/false) 43 | //robotgo.MouseClick("left" , false) 44 | 45 | //MoveClick,移动到目标位置,并点击 46 | //MoveClick(横向坐标,纵向坐标,"right",false) 47 | //robotgo.MoveClick(1085,15,"left" , false) 48 | 49 | //MouseToggle,长按 50 | //MouseToggle("down/up","left/center/right") 51 | //robotgo.MouseToggle("down","left") 52 | 53 | //DragMouse名,拖动鼠标 54 | //实例里面与MouseToggle合用,没发现与MoveMouse的区别,使用方法相同 55 | //robotgo.MouseToggle("down") 56 | //robotgo.DragMouse(600, 400) 57 | 58 | //GetMousePos,获取鼠标当前位置 59 | //fmt.Println(robotgo.GetMousePos()) 60 | 61 | //ScrollMouse,滚动鼠标滚轮 62 | //ScrollMouse(滚动大小,向上或向下滚动) 63 | //ScrollMouse(10,"up/down") 64 | //robotgo.ScrollMouse(1, "up") 65 | 66 | 67 | 68 | 69 | 70 | 71 | //GetPixelColor,获取目标位置颜色 72 | //fmt.Println(robotgo.GetPixelColor(600,400))//结果:2b2b2b 73 | 74 | //GetScreenSize,获取屏幕大小 75 | //fmt.Println(robotgo.GetScreenSize())//结果:1920 1080,宽度 高度 76 | 77 | 78 | 79 | 80 | 81 | //位图操作********************************************** 82 | 83 | //CaptureScreen,截图操作 84 | //返回值为位图的对象 85 | //CaptureScreen(横向坐标x,纵向坐标y,图片高度,图片宽度) 86 | //截图的时候是在x,y点的基础分别加上高度与宽度的点,两点形成的矩形框 87 | //bitmap := robotgo.CaptureScreen(10, 20, 30, 40) 88 | 89 | //SaveBitmap,保存位图为文件 90 | //截了图,当然要保存才有用,这里的bitmap就是上面得到的bitmap 91 | //SaveBitmap(位图的对象, 保存路径与文件名,图片类型(可忽略,我也没搞清楚)) 92 | //robotgo.SaveBitmap(bitmap, "test.png") 93 | 94 | //OpenBitmap,把png图片转为bitmap对象 95 | //bitmap := robotgo.OpenBitmap("test.png") 96 | 97 | //FindBitmap,找到bitmap对象的坐标 98 | //fx, fy := robotgo.FindBitmap(bitmap) 99 | //fmt.Println("FindBitmap------", fx, fy) 100 | 101 | //TostringBitmap,把位图对象转为字符串 102 | //fmt.Println(robotgo.TostringBitmap(bitmap)) 103 | 104 | //GetPortion,截取位图对象的一部分 105 | //GetPortion(位图对象,起始横向坐标,起始纵向坐标,宽度,高度) 106 | /** 107 | bm := robotgo.OpenBitmap("test.png") 108 | cutBm := robotgo.GetPortion(bm,0,0,100,100) 109 | robotgo.SaveBitmap(cutBm,"cutBm.png") 110 | */ 111 | 112 | //Convert,图片格式转换 113 | //Convert(文件源路径,新文件目标路径,文件格式),文件格式文档没写,代码里也没看出对应的判断代码,不知道有什么意义,为0时大小不变,为2时文件大小变大很多,其他无作用,文件格式设置可省略 114 | //robotgo.Convert("test.png", "test.jpg",2) 115 | 116 | 117 | //FreeBitmap,释放位图 118 | //把位图释放掉,下面代码在保存时会报错 119 | /** 120 | bm := robotgo.OpenBitmap("test.png") 121 | robotgo.FreeBitmap(bm) 122 | robotgo.SaveBitmap(bm,"freeBm.png") 123 | */ 124 | 125 | 126 | //ReadBitmap,判断位图是否为空 127 | //如果为空,返回false,否则true 128 | /* 129 | bm := robotgo.OpenBitmap("test.png") 130 | bm=nil 131 | fmt.Println(robotgo.ReadBitmap(bm)) 132 | */ 133 | 134 | 135 | //CopyBitpb,将位图复制到剪贴板 136 | //在word文件中ctrl+v,图片就会拷贝到文件中了 137 | /* 138 | bm := robotgo.OpenBitmap("test.png") 139 | robotgo.CopyBitpb(bm) 140 | */ 141 | 142 | //DeepCopyBit,复制位图对象 143 | /* 144 | bm := robotgo.OpenBitmap("test.png") 145 | cyBm := robotgo.DeepCopyBit(bm) 146 | robotgo.SaveBitmap(cyBm,"cyBm.png") 147 | */ 148 | 149 | 150 | 151 | 152 | 153 | //事件操作********************************************** 154 | 155 | //AddEvent,添加全局事件监听 156 | //AddEvent(按键或者鼠标操作) 157 | //支持的按键有数字字母等按键,支持的功能键从代码中可以看到有截图中的按键 158 | //鼠标(鼠标参数: mleft, mright, wheelDown, wheelUp, wheelLeft, wheelRight),目前测试中只有前面两个对应代码有效 159 | /* 160 | lEvent := robotgo.AddEvent("mleft") 161 | if lEvent == 0 { 162 | fmt.Println("mleft") 163 | } 164 | */ 165 | 166 | //StopEvent(),停止事件监听 167 | //暂时没想到用到的地方,测试时要把监听也停止监听跑两个线程才能看到效果,AddEvent运行时是阻塞的 168 | //robotgo.StopEvent() 169 | 170 | 171 | 172 | 173 | 174 | //窗口操作********************************************** 175 | //几个文档中的函数测试中无法有效使用(可能是我win10系统),或者没找到合适用法的,没有写入下方文档 176 | 177 | //ShowAlert,消息提示框 178 | //ShowAlert("标题", "消息", "Success","Close"),后面两个参数无效,可省略,中文存在乱码问题 179 | /* 180 | btMsg := robotgo.ShowAlert("Title", "This Message!", "Success","Close") 181 | fmt.Println(btMsg)//确定0,取消1 182 | */ 183 | 184 | 185 | //GetActive,SetActive获取当前窗口和跳转到某窗口 186 | //下面代码测试流程:程序正式执行后,5S类切换到另外一个窗口,过会又会跳到开始的窗口 187 | /* 188 | cw := robotgo.GetActive()//获取当前选择的窗口 189 | time.Sleep(5*time.Second) 190 | robotgo.SetActive(cw)//跳转到目标窗口 191 | */ 192 | 193 | 194 | //GetTitle,获取窗口标题 195 | //fmt.Println(robotgo.GetTitle()) 196 | 197 | 198 | //GetHandle,SetHandle,获取窗口句柄和设置句柄 199 | //获取没问题,但设置发现无效 200 | /* 201 | fmt.Println(robotgo.GetHandle()) 202 | robotgo.SetHandle(3272727) 203 | */ 204 | 205 | 206 | //Pids,获取进程PID 207 | //返回两个参数,第一个是pid的数组,第二个是错误信息 208 | //fmt.Println(robotgo.Pids()) 209 | 210 | 211 | //PidExists,判断进程是否存在 212 | //根据PID判断,返回两个参数,第一个bool值存在true,第二个是错误信息 213 | //fmt.Println(robotgo.PidExists(928)) 214 | 215 | 216 | //Process,获取进程信息 217 | //返回两个参数:进程信息的数组,错误信息 218 | //fmt.Println(robotgo.Process()) 219 | 220 | 221 | //FindName,根据PID查询进程名 222 | //返回参数:进程名,错误信息 223 | //fmt.Println(robotgo.FindName(928)) 224 | 225 | 226 | //FindNames,查询所有进程名 227 | //不知道是不是系统原因,无效 228 | //返回参数:进程名数组,错误信息 229 | //fmt.Println(robotgo.FindNames()) 230 | 231 | 232 | //FindIds,根据进程名找PID 233 | //返回参数:进程PID,错误信息 234 | //fmt.Println(robotgo.FindIds("lsass.exe")) 235 | 236 | 237 | //ActivePID,根据PID激活窗口 238 | //不知道是不是系统原因,无效 239 | //返回参数:错误信息 240 | //fmt.Println(robotgo.ActivePID(9792)) 241 | } 242 | --------------------------------------------------------------------------------