;/* ;=========================================== ; FindText - 屏幕抓字生成字库工具与找字函数 ; https://www.autohotkey.com/boards/viewtopic.php?f=83&t=116471 ; ; 脚本作者 : FeiYue ; 最新版本 : 9.4 ; 更新时间 : 2023-12-18 ; ; 用法: (需要最新版本 AHK v2.02) ; 1. 将本脚本保存为“FindText.ahk”并复制到AHK执行程序的Lib子目录中(手动建立目录) ; 2. 抓图并生成调用FindText()的代码 ; 2.1 方式一:直接点击“抓图”按钮 ; 2.2 方式二:先设定截屏热键,使用热键截屏,再点击“截屏抓图”按钮 ; 3. 测试一下调用的代码是否成功:直接点击“测试”按钮 ; 4. 复制调用的代码到自己的脚本中 ; 4.1 方式一:打勾“附加FindText()函数”的选框,然后点击“复制”按钮(不推荐) ; 4.2 方式二:取消“附加FindText()函数”的选框,然后点击“复制”按钮, ; 然后粘贴到自己的脚本中,然后在自己的脚本开头加上一行: ; #Include ; Lib目录中必须有FindText.ahk ; 5. 多色查找模式可以一定程度上适应图像的放大缩小,常用于游戏中找图 ; 6. 这个库还可以用于快速截屏、获取颜色、写入颜色、编辑后另存图片 ; 7. 如果要调用FindTextClass类中的函数,请用无参数的FindText()获取类实例对象 ; ;=========================================== ;*/ if (!A_IsCompiled && A_LineFile=A_ScriptFullPath) FindText().Gui("Show") ;===== 复制下面的函数和类到你的代码中仅仅一次 ===== FindText(args*) { static obj:=FindTextClass() return !args.Length ? obj : obj.FindText(args*) } Class FindTextClass { ;// Class Begin Floor(i) => IsNumber(i) ? i+0 : 0 __New() { this.bits:={ Scan0: 0, hBM: 0, oldzw: 0, oldzh: 0 } this.bind:={ id: 0, mode: 0, oldStyle: 0 } this.Lib:=Map() this.Cursor:=0 } __Delete() { if (this.bits.hBM) DllCall("DeleteObject", "Ptr",this.bits.hBM) } New() { return FindTextClass() } help() { return " ( ;-------------------------------- ; FindText - 屏幕找字函数 ; 版本 : 9.4 (2023-12-18) ;-------------------------------- ; 返回变量:=FindText( ; &OutputX --> 保存返回的X坐标的变量名称 ; , &OutputY --> 保存返回的Y坐标的变量名称 ; , X1 --> 查找范围的左上角X坐标 ; , Y1 --> 查找范围的左上角Y坐标 ; , X2 --> 查找范围的右下角X坐标 ; , Y2 --> 查找范围的右下角Y坐标 ; , err1 --> 文字的黑点容错百分率(0.1=10%) ; , err0 --> 背景的白点容错百分率(0.1=10%) ; , Text --> 由工具生成的查找图像的数据,可以一次查找多个,用“|”分隔 ; , ScreenShot --> 是否截屏,为0则使用上一次的截屏数据 ; , FindAll --> 是否搜索所有位置,为0则找到一个位置就返回 ; , JoinText --> 如果想组合查找,可以为1,或者是要查找单词的数组 ; , offsetX --> 组合图像的每个字和前一个字的最大横向间隔 ; , offsetY --> 组合图像的每个字和前一个字的最大高低间隔 ; , dir --> 查找的方向,有上、下、左、右、中心9种 ; , zoomW --> 图像宽度的缩放百分率(1.0=100%) ; , zoomH --> 图像高度的缩放百分率(1.0=100%) ; ) ; ; 返回变量 --> 如果没找到结果会返回0。否则返回一个二级数组, ; 第一级是每个结果对象,第二级是结果对象的具体信息对象: ; { 1:左上角X, 2:左上角Y, 3:图像宽度W, 4:图像高度H ; , x:中心点X, y:中心点Y, id:图像识别文本 } ; 坐标都是相对于屏幕,颜色使用RGB格式 ; ; 如果 OutputX 等于 'wait' 或 'wait1' 意味着等待图像出现, ; 如果 OutputX 等于 'wait0' 意味着等待图像消失 ; 此时 OutputY 设置等待时间的秒数,如果小于0则无限等待 ; 如果超时则返回0,意味着失败,如果等待图像出现成功,则返回位置数组 ; 如果等待图像消失成功,则返回 1(注意这里的等待功能仅适用于静态图像) ; 例1: FindText(&X:='wait', &Y:=3, 0,0,0,0,0,0,Text) ; 等待3秒等图像出现 ; 例2: FindText(&X:='wait0', &Y:=-1, 0,0,0,0,0,0,Text) ; 无限等待等图像消失 ; ; : 找色 是仅有一个点的 找多色 ; Text:='|<>##DRDGDB $ 0/0/RRGGBB1-DRDGDB1/RRGGBB2/-RRGGBB3/-RRGGBB4, xn/yn/...' ; '##'之后的颜色 (0xDRDGDB) 是所有颜色的默认偏色(各个分量允许的变化值) ; 初始点 (0,0) 匹配 0xRRGGBB1(+/-0xDRDGDB1) 或者 0xRRGGBB2(+/-0xDRDGDB) ; 或者 非 0xRRGGBB3(+/-0xDRDGDB) 或者 非 0xRRGGBB4(+/-0xDRDGDB) ; 以 '-' 开头的颜色,表示除了这种颜色的其他的任何颜色都匹配 ; 每个点可以允许匹配10组颜色 (xn/yn/RRGGBB1/.../RRGGBB10) ; ; : Text 参数需要手动输入 ; Text:='|<>##DRDGDB-RRGGBB1-RRGGBB2... $ d:\a.bmp' ; 0xRRGGBB1(+/-0xDRDGDB)... 都是透明色,不参与匹配 ; ;-------------------------------- )" } FindText(OutputX:="", OutputY:="" , x1:=0, y1:=0, x2:=0, y2:=0, err1:=0, err0:=0, text:="" , ScreenShot:=1, FindAll:=1, JoinText:=0, offsetX:=20, offsetY:=10 , dir:=1, zoomW:=1, zoomH:=1) { wait:=(OutputX is VarRef) && IsSetRef(OutputX) ? %OutputX% : OutputX if !IsObject(wait) && (wait ~= "i)^\s*wait[10]?\s*$") { time:=(OutputY is VarRef) && IsSetRef(OutputY) ? %OutputY% : OutputY found:=!InStr(wait,"0"), time:=this.Floor(time) , timeout:=A_TickCount+Round(time*1000) Loop { ok:=this.FindText(,, x1, y1, x2, y2, err1, err0, text, ScreenShot , FindAll, JoinText, offsetX, offsetY, dir, zoomW, zoomH) if (found && ok) { (OutputX is VarRef) && (%OutputX%:=ok[1].x) , (OutputY is VarRef) && (%OutputY%:=ok[1].y) return ok } if (!found && !ok) return 1 if (time>=0 && A_TickCount>=timeout) Break Sleep 50 } return 0 } x1:=this.Floor(x1), y1:=this.Floor(y1), x2:=this.Floor(x2), y2:=this.Floor(y2) if (x1=0 && y1=0 && x2=0 && y2=0) n:=150000, x:=y:=-n, w:=h:=2*n else x:=Min(x1,x2), y:=Min(y1,y2), w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+1 bits:=this.GetBitsFromScreen(&x,&y,&w,&h,ScreenShot,&zx,&zy), x-=zx, y-=zy , this.ok:=0, info:=[] Loop Parse, text, "|" if IsObject(j:=this.PicInfo(A_LoopField)) info.Push(j) if (w<1 || h<1 || !(num:=info.Length) || !bits.Scan0) { return 0 } arr:=[], info2:=Map(), info2.Default:=[], k:=0, s:="" , mode:=(IsObject(JoinText) ? 2 : JoinText ? 1 : 0) For i,j in info { k:=Max(k, (j[7]=5 && j[8]=0 ? j[9] : j[2]*j[3])) if (mode) v:=(mode=2 ? j[10] : i) . "", s.="|" v , (!info2.Has(v) && info2[v]:=[]), (v!="" && info2[v].Push(j)) } sx:=x, sy:=y, sw:=w, sh:=h , JoinText:=(mode=1 ? [s] : JoinText) , s1:=Buffer(k*4), s0:=Buffer(k*4) , ss:=Buffer(sw*(sh+2)) , FindAll:=(dir=9 ? 1 : FindAll) , allpos_max:=(FindAll || JoinText ? 10240 : 1) , ini:={ sx:sx, sy:sy, sw:sw, sh:sh, zx:zx, zy:zy , mode:mode, bits:bits, ss:ss.Ptr, s1:s1.Ptr, s0:s0.Ptr , err1:err1, err0:err0, allpos_max:allpos_max , zoomW:zoomW, zoomH:zoomH } Loop 2 { if (err1=0 && err0=0) && (num>1 || A_Index>1) ini.err1:=err1:=0.05, ini.err0:=err0:=0.05 if (!JoinText) { allpos:=Buffer(allpos_max*4), allpos_ptr:=allpos.Ptr For i,j in info Loop this.PicFind(ini, j, dir, sx, sy, sw, sh, allpos_ptr) { pos:=NumGet(allpos, 4*(A_Index-1), "uint") , x:=(pos&0xFFFF)+zx, y:=(pos>>16)+zy , w:=Floor(j[2]*zoomW), h:=Floor(j[3]*zoomH), comment:=j[10] , arr.Push({1:x, 2:y, 3:w, 4:h, x:x+w//2, y:y+h//2, id:comment}) if (!FindAll) Break 3 } } else For k,v in JoinText { v:=StrSplit(Trim(RegExReplace(v, "\s*\|[|\s]*", "|"), "|") , (InStr(v,"|")?"|":""), " `t") , this.JoinText(arr, ini, info2, v, 1, offsetX, offsetY , FindAll, dir, 0, 0, 0, sx, sy, sw, sh) if (!FindAll && arr.Length) Break 2 } if (err1!=0 || err0!=0 || arr.Length || info[1][4] || info[1][7]=5) Break } if (dir=9 && arr.Length) arr:=this.Sort2(arr, (x1+x2)//2, (y1+y2)//2) if (arr.Length) { (OutputX is VarRef) && (%OutputX%:=arr[1].x) , (OutputY is VarRef) && (%OutputY%:=arr[1].y) , this.ok:=arr return arr } return 0 } ; 组合文本参数可以用数组 <==> [ "abc", "xyz", "a1|a2|a3" ] JoinText(arr, ini, info2, text, index, offsetX, offsetY , FindAll, dir, minX, minY, maxY, sx, sy, sw, sh) { if !(Len:=text.Length) return 0 allpos:=Buffer(ini.allpos_max*4), allpos_ptr:=allpos.Ptr , zoomW:=ini.zoomW, zoomH:=ini.zoomH, mode:=ini.mode For i,j in info2[text[index]] if (mode!=2 || text[index]==j[10]) Loop this.PicFind(ini, j, dir, sx, sy, (index=1 ? sw : Min(sx+offsetX+Floor(j[2]*zoomW),ini.sx+ini.sw)-sx), sh, allpos_ptr) { pos:=NumGet(allpos, 4*(A_Index-1), "uint") , x:=pos&0xFFFF, y:=pos>>16 , w:=Floor(j[2]*zoomW), h:=Floor(j[3]*zoomH) , (index=1 && (minX:=x, minY:=y, maxY:=y+h)) , minY1:=Min(y, minY), maxY1:=Max(y+h, maxY), sx1:=x+w if (index1 || !FindAll) return 1 } else { comment:="" For k,v in text comment.=(mode=2 ? v : info2[v][1][10]) x:=minX+ini.zx, y:=minY1+ini.zy, w:=sx1-minX, h:=maxY1-minY1 , arr.Push({1:x, 2:y, 3:w, 4:h, x:x+w//2, y:y+h//2, id:comment}) if (index>1 || !FindAll) return 1 } } return 0 } PicFind(ini, j, dir, sx, sy, sw, sh, allpos_ptr) { static MyFunc:="" if (!MyFunc) { x32:="VVdWU4PEgIO8JJQAAAAFi6wkzAAAAA+EoAoAAIu8JNAAAACF@w+O7RAAAMcEJAAA" . "AADHRCQQAAAAADH@x0QkHAAAAADHRCQUAAAAAIuEJMgAAACLTCQUMfYx2wHIhe2J" . "RCQMf0HplAAAAI22AAAAAA+vhCS0AAAAicGJ8Jn3@QHBi0QkDIA8GDF0TIuEJMQA" . "AACDwwEDtCTkAAAAiQy4g8cBOd10VIsEJJn3vCTQAAAAg7wklAAAAAR1tQ+vhCSo" . "AAAAicGJ8Jn3@Y0MgYtEJAyAPBgxdbSLRCQci5QkwAAAAIPDAQO0JOQAAACJDIKD" . "wAE53YlEJBx1rAFsJBSDRCQQAYuMJOgAAACLRCQQAQwkOYQk0AAAAA+FLv@@@4tM" . "JBy7rYvbaIl8JCQPr4wk1AAAAInIwfkf9+vB+gwpyouMJNgAAACJVCQYD6@PicjB" . "+R@368H6DCnKiVQkKIO8JJQAAAAED4RNCgAAi4QkqAAAAIu0JKwAAAAPr4QksAAA" . "AIuMJKgAAACNPLCLhCS0AAAA99iNBIGJRCQwi4QklAAAAIXAD4VWAwAAi4QkmAAA" . "AIusJLgAAADHRCQsAAAAAMdEJDQAAAAAwegQD7bAiUQkDIuEJJgAAAAPtsSJRCQQ" . "D7aEJJgAAACJRCQUi4QktAAAAMHgAoXtiUQkPA+OvQAAAIu0JLQAAACF9g+OlAAA" . "AIu0JKQAAACLbCQ0A6wkvAAAAAH+A3wkPIl8JDgDvCSkAAAAiTwkifaNvCcAAAAA" . "D7ZOAotcJAwPtkYBD7YWK0QkECtUJBSJzwHZKd+NmQAEAAAPr8APr9@B4AsPr98B" . "w7j+BQAAKcgPr8IPr9AB0zmcJJwAAAAPk0UAg8YEg8UBOzQkdaqLjCS0AAAAAUwk" . "NIt8JDiDRCQsAQN8JDCLRCQsOYQkuAAAAA+FQ@@@@4tEJBiJRCREi0QkKIlEJFyL" . "dCQci0wkRDHAOc6LTCRcD07wiXQkHIt0JCQ5zg9PxolEJCSLdCQki0QkHDnGD03G" . "iUQkFIuEJJQAAACD6ASD+AEPhnQHAADHRCRkAAAAAMdEJHAAAAAAi0QkcAOEJLQA" . "AAArhCTkAAAAiUQkdItEJGQDhCS4AAAAK4Qk6AAAAIlEJEyLhCSgAAAAg+gBg@gH" . "D4fpBgAAg@gDiUQkVA+O5AYAAIt0JGSLRCRwiXQkcIlEJGSLdCR0OXQkZA+P5AYA" . "AItEJHSLTCQci3QkVMdEJDwAAAAAiUQkeIuEJMAAAACNBIiJRCRgifCD4AGJRCRY" . "ifCD4AOJRCR8i0QkcIt0JEw58A+PAQEAAIN8JHwBi0wkZA9PTCR4iXQkQIlEJCyJ" . "TCRQi0QkWIXAi0QkQA9ERCQsg3wkVAOJRCQ0D49PAgAAg7wklAAAAAWLRCRQiUQk" . "OItEJDgPhFcCAACDvCSUAAAABA+EKwQAAA+vhCS0AAAAi0wkFIt0JDSFyY0sMA+E" . "4AMAAIt0JFyLXCREMcCLlCS8AAAAiWwkEItMJByLfCQkiRwkiXQkDAHqi2wkFOsL" . "g8ABOcUPhKUDAAA5yH0Xi5wkwAAAAIs0gwHWgD4AdQaDLCQBeBw5x37Wi5wkxAAA" . "AIs0gwHWgD4BdcWDbCQMAXm+g0QkLAGDbCRAAYtEJCw5RCRMD40Z@@@@g0QkZAGD" . "bCR4AYtEJGQ5RCR0D43X@v@@i0QkPIPsgFteX13CWACDvCSUAAAAAQ+EQgsAAIO8" . "JJQAAAACD4QtCQAAi4QkmAAAAA+2jCScAAAAx0QkFAAAAADHRCQsAAAAAMHoEA+2" . "wIkEJIuEJJgAAAAPtsSJRCQMD7aEJJgAAACJRCQQi4QknAAAAMHoEA+26IuEJJwA" . "AACJ7g+v9Q+2xIl0JCCJxg+v8InID6@BiXQkCIlEJASLhCS0AAAAweACiUQkNIuE" . "JLgAAACFwA+OEv3@@4uEJLQAAACFwA+OfgAAAIuUJKQAAACLXCQsA5wkvAAAAAH6" . "A3wkNIl8JDgDvCSkAAAAif0PtkICMf8PtkoBKwQkD7YyD6@AOUQkIHwiK0wkDA+v" . "yTlMJAh8FYnwD7bwK3QkEA+v9jl0JAQPncCJx4n4g8IEg8MBiEP@Oep1touMJLQA" . "AAABTCQsi3wkOINEJBQBA3wkMItEJBQ5hCS4AAAAD4VZ@@@@6Wb8@@+NtCYAAAAA" . "i0QkNIO8JJQAAAAFiUQkOItEJFCJRCQ0i0QkOA+Fqf3@@w+vhCSoAAAAi0wkNIts" . "JGiF7Y0EiIlEJDAPhQUDAACLRCRsi3wkFMdEJBgAAAAAiUQkKItEJESF@4lEJEgP" . "hBsBAACLfCQgjbQmAAAAAItMJBiLtCTAAAAAi0QkMAMEjou0JMQAAACNFImNHJGL" . "VCQoizSOi4wkpAAAAIkUJIm0JJwAAACLtCSkAAAAD7Z0BgKJdCQMi7QkpAAAAA+2" . "dAYBD7YEAYl0JBCJRCQgid7reYsEJIPGAosIi1gEiciJ38HoEMHvEA+2wCtEJAyJ" . "+g+2+g+21w+224n9iVwkBDHbD6@viVQkCA+vwDnofysPtsUrRCQQidUPr+oPr8A5" . "6H8Yi1QkBA+2wStEJCCJ0w+v2g+vwDnYD57DgwQkCIH5@@@@AA+XwDjYdRg5tCSc" . "AAAAD4d6@@@@g2wkSAEPiIICAACDRCQYAYNEJChUi0QkGDlEJBQPhfT+@@+JfCQg" . "i4Qk3AAAAINEJDwBi0wkPIXAD4TK@P@@i1QkOAOUJLAAAACLRCQ0A4QkrAAAAIu0" . "JNwAAADB4hAJ0DuMJOAAAACJRI78D4yX@P@@6cL8@@+LbCQQi1QkHIXSdKSLtCS8" . "AAAAi4QkwAAAAItcJGCNDC6LEIPABAHKOdjGAgB18ul8@@@@D6+EJKgAAACLdCQ0" . "i1wkFI0EsIu0JKQAAACJBCQDhCSYAAAAhduJ8Q+2bAYCD7Z0BgEPtgQBiXQkDIlE" . "JBAPhDj@@@+LRCRcMduJbCQYiUQkMItEJESJRCQoZpA7XCQcfWSLhCTAAAAAixQk" . "i3wkGAMUmA+2dBECD7ZEEQErRCQMD7YUEStUJBCJ9QH+Kf2NvgAEAAAPr8APr@3B" . "4AsPr@0Bx7j+BQAAKfAPr8IPr9AB1zu8JJwAAAB2C4NsJCgBD4iY+@@@OVwkJH5k" . "i4QkxAAAAIsUJIt8JBgDFJgPtnQRAg+2RBEBK0QkDA+2FBErVCQQifUB@in9jb4A" . "BAAAD6@AD6@9weALD6@9Ace4@gUAACnwD6@CD6@QAdc7vCScAAAAdwuDbCQwAQ+I" . "Lvv@@4PDATlcJBQPhR@@@@@pOv7@@4t0JBSF9g+ELv7@@4t0JESLnCSkAAAAMdKQ" . "i4QkwAAAAIt8JDADPJCLhCTEAAAAiyyQD7ZEOwKJ6cHpEA+2ySnID7ZMOwEPtjw7" . "D6@AO0QkIH8niegPtsQpwQ+vyTtMJAh@F4n4D7b4iegPtsApxw+v@zt8JAR+B2aQ" . "g+4BeBWDwgE5VCQUdZKJrCSYAAAA6ab9@@+JrCSYAAAA6Xz6@@+JfCQg6XP6@@@H" . "RCRUAAAAAIt0JHSLRCRMiXQkTIlEJHSLdCR0OXQkZA+OHPn@@8dEJDwAAAAAi0Qk" . "PIPsgFteX13CWACLhCSwAAAAx4QksAAAAAAAAACJRCRki4QkrAAAAMeEJKwAAAAA" . "AAAAiUQkcOlr+P@@i7QkmAAAADHAhfYPlcCJRCRoD4U6AQAAi5wknAAAAIXbD4R@" . "BgAAi7QknAAAAIu8JMAAAACLnCTEAAAAjQS3MfaJBCSLhCTIAAAAMdKDxwSDwwSL" . "BLCJhCSYAAAAwegE9@UPr4Qk6AAAAIlUJAyZ97wk0AAAAA+vhCSoAAAAicGLRCQM" . "D6+EJOQAAACZ9@2NBIGJR@yLhCSYAAAAg+APjQRGg8YViUP8OzwkdZeLhCScAAAA" . "i4wk1AAAALqti9toD6@IiUQkHInIwfkf9+qJ0MH4DCnIi7QkyAAAAIlEJETHRCRc" . "AAAAAMdEJCQAAAAAg8YEiXQkbOkX9@@@i4QkmAAAAMHoEA+vhCToAAAAmfe8JNAA" . "AAAPr4QkqAAAAInBD7eEJJgAAAAPr4Qk5AAAAJn3@Y0EgYmEJJgAAACLRCQYiUQk" . "RItEJCiJRCRc6cH2@@+LhCTQAAAAi7QkyAAAAA+2lCSYAAAAD6@FjQSGiUQkbIuE" . "JJgAAADB6BAPtsiLhCSYAAAAic4Pr@GLjCTQAAAAD7bEiXQkIInGD6@widAPr8KF" . "yYl0JAiJRCQED47OBAAAi3QkbI0ErQAAAACJrCTMAAAAi5wkmAAAAIu8JJwAAACL" . "bCQgiUQkNDHAx0QkLAAAAADHRCQwAAAAAMdEJBwAAAAAiTQki5QkzAAAAIXSD44a" . "AQAAi4wkyAAAAIs0JMdEJBQAAAAAiVwkKAHBA0QkNIlMJBCJRCQ4A4QkyAAAAIlE" . "JCSLRCQQhf8PtlABD7ZIAg+2AIkUJIlEJAx0RjHSZpCLHJaJ2MHoEA+2wCnID6@A" . "OcV8Iw+2xysEJA+vwDlEJAh8FA+2wytEJAwPr8A5RCQED435AAAAg8IBOfp1wolc" . "JCiLRCQcweEQweACiUQkGItEJCyZ97wk0AAAAA+vhCSoAAAAicOLRCQUmfe8JMwA" . "AACLVCQcjQSDi5wkwAAAAIkEk4sEJIPCAYucJMQAAACJVCQcweAICcELTCQMi0Qk" . "GIkMA4NEJBAEi5Qk5AAAAItEJBABVCQUO0QkJA+FIP@@@4tcJCiLRCQ4iTQkg0Qk" . "MAGLtCToAAAAi0wkMAF0JCw5jCTQAAAAD4W2@v@@i0wkHLqti9toiZwkmAAAAA+v" . "jCTUAAAAx0QkXAAAAADHRCQkAAAAAInIwfkf9+rB+gwpyolUJETplPT@@5CNdCYA" . "iVwkKOlr@@@@i4wktAAAAIuEJLwAAAAx7YuUJLgAAADHBCQAAAAAjQRIiUQkNInI" . "weAChdKJRCQMD45A9P@@i4QktAAAAIXAfleLjCSkAAAAi0QkNAH5A3wkDI0cKIl8" . "JBADvCSkAAAAD7ZRAg+2QQGDwQQPtnH8g8MBa8BLa9ImAcKJ8MHgBCnwAdDB+AeI" . "Q@85+XXTA6wktAAAAIt8JBCDBCQBA3wkMIsEJDmEJLgAAAB1iouEJLQAAACLvCSc" . "AAAAMfbHRCQMAAAAAIPoAYlEJCyLhCS4AAAAg+gBiUQkMIuEJLQAAACFwA+O7QAA" . "AItEJAyLjCS0AAAAi6wkvAAAAIXAi0QkNA+URCQUAfGJTCQ4icONFDABy4nxK4wk" . "tAAAAAHuiXQkEAHBMcCJDCTpkgAAAIB8JBQAD4WPAAAAOUQkLA+EhQAAAItMJAw5" . "TCQwdHsPtjoPtmr@vgEAAAADvCSYAAAAOe9yPA+2agE573I0iwwkD7YpOe9yKg+2" . "KznvciMPtmn@Oe9yGw+2aQE573ITD7Zr@znvcgsPtnMBOfcPksGJzotsJBCJ8YhM" . "BQCDwAGDwgGDwwGDBCQBOYQktAAAAHQShcAPhWb@@@+LdCQQxgQGAuvYi3QkOINE" . "JAwBi0QkDDmEJLgAAAAPhe7+@@+LRCQYibwknAAAAIlEJESLRCQoiUQkXOl@8v@@" . "i4QkmAAAAIucJLgAAAAx7ccEJAAAAACDwAHB4AeJhCSYAAAAi4QktAAAAMHgAoXb" . "iUQkDA+ONfL@@4uMJLQAAACFyX5mi4wkpAAAAIucJLwAAACJbCQUAfkDfCQMAeuL" . "rCSYAAAAiXwkEAO8JKQAAAAPtlECD7ZBAQ+2MWvAS2vSJgHCifDB4AQp8AHCOdUP" . "lwODwQSDwwE5+XXVi2wkFAOsJLQAAACLfCQQgwQkAQN8JDCLBCQ5hCS4AAAAD4V3" . "@@@@6afx@@@HRCQoAAAAAMdEJBgAAAAAx0QkJAAAAADHRCQcAAAAAOkg8P@@x0Qk" . "RAAAAADHRCQcAAAAAMdEJFwAAAAAx0QkJAAAAADpkfH@@zHAx0QkHAAAAADpIPr@" . "@5CQkJCQkJCQkJCQkJCQkA==" x64:="QVdBVkFVQVRVV1ZTSIHsuAAAAEiLtCQgAQAAi5wkcAEAAIP5BYmMJAABAACJ1UWJ" . "xUSJjCQYAQAARIu8JHgBAAAPhDIMAABFhf8PjlASAABEiXQkEIl8JBgxwIu8JAAB" . "AABEi6wkQAEAAEUx0kyLtCRgAQAAi6wkoAEAAEUx20SJZCQgx0QkCAAAAABBicTH" . "RCQoAAAAAImUJAgBAABEiYQkEAEAAEiJtCQgAQAASGN0JChFMclFMcBIA7QkaAEA" . "AIXbfzfrfWYPH4QAAAAAAEEPr8WJwUSJyJn3+wHBQoA8BjF0PUmDwAFJY8NBAelB" . "g8MBRDnDQYkMhn5ERInQmUH3@4P@BHXID6+EJCgBAACJwUSJyJn3+0KAPAYxjQyB" . "dcNIi5QkWAEAAEmDwAFJY8RBAelBg8QBRDnDiQyCf7wBXCQog0QkCAFEA5QkqAEA" . "AItEJAhBOccPhVD@@@9EieFBuK2L22hEi3QkEA+vjCSAAQAARIlkJFSLrCQIAQAA" . "RItkJCBEi6wkEAEAAEiLtCQgAQAAi3wkGESJXCQIicjB+R9B9+jB+gwpyouMJIgB" . "AACJVCQQQQ+vy4nIwfkfQffowfoMKcqJVCQYg7wkAAEAAAQPhIMLAACLhCQoAQAA" . "i5wkMAEAAA+vhCQ4AQAAjQSYi5wkKAEAAIlEJCiLhCRAAQAA99iNBIOLnCQAAQAA" . "iUQkLIXbD4X6AwAAiehEi5wkSAEAAMHoEA+22EiJ6A+2xEWF24nBQA+2xYnCD44X" . "BQAAi4QkQAEAAImsJAgBAABEi3wkKIusJEABAABEiXQkQESJZCRIQYnWweACx0Qk" . "IAAAAADHRCQwAAAAAIlEJDiJfCRQQYnMhe0PjooAAABIY3wkMEljx0Ux20gDvCRQ" . "AQAATI1UBgIPH4QAAAAAAEEPtlL+RQ+2CkEPtkL@RCnyRInJQYnQQo0UCynZRCng" . "RI2KAAQAAA+vwEQPr8nB4AtED6@Juf4FAAAp0YnKQQ+v0EGNBAFBD6@QAdBBOcVC" . "D5MEH0mDwwFJg8IERDndf59EA3wkOAFsJDCDRCQgAUQDfCQsi0QkIDmEJEgBAAAP" . "hVP@@@+LRCQQRIt0JECLfCRQRItkJEiLrCQIAQAAiUQkWItEJBiJhCSAAAAAi1wk" . "VItMJFgxwDnLi4wkgAAAAA9O2IlcJFSLXCQIOcsPT8OJRCQIi1wkCItEJFQ5ww9N" . "w0GJw4uEJAABAACD6ASD+AEPhpsIAADHhCSMAAAAAAAAAMeEJKAAAAAAAAAAi4Qk" . "oAAAAAOEJEABAAArhCSgAQAAiYQkpAAAAIuEJIwAAAADhCRIAQAAK4QkqAEAAIlE" . "JGCLhCQYAQAAg+gBg@gHD4f+BwAAg@gDiUQkaA+O+QcAAIucJIwAAACLhCSgAAAA" . "iZwkoAAAAImEJIwAAACLnCSkAAAAOZwkjAAAAA+P8wcAAIuEJKQAAABIi5wkWAEA" . "AImsJAgBAABEieVFidxEibQkhAAAAMdEJEAAAAAARYnuiYQkqAAAAItEJFSJvCSI" . "AAAAg+gBSI1EgwRIiUQkeEGNQ@9JifNIi7QkUAEAAEiNRIMEi1wkaEiJRCRIidiD" . "4AGJRCRsidiD4AOJhCSsAAAAi4QkoAAAAIt8JGA5+A+PBQEAAIO8JKwAAAABi5wk" . "jAAAAA9PnCSoAAAAiXwkUIlEJCCJXCRkDx+EAAAAAACLTCRsi0QkUIXJD0REJCCD" . "fCRoA4lEJCwPj1QCAACDvCQAAQAABYtEJGSJRCQwD4RcAgAAg7wkAAEAAAQPhFQE" . "AACLTCQwD6+MJEABAAADTCQsRYXkD4QJBAAARIuUJIAAAABEi0wkWDHARItEJFSL" . "fCQITIusJFgBAABMi7wkYAEAAOsNSIPAAUE5xA+O0gMAAEE5wInCfhOJy0EDXIUA" . "gDweAHUGQYPpAXgWOdd+1YnKQQMUh4A8FgF1yUGD6gF5w4NEJCABg2wkUAGLRCQg" . "OUQkYA+NJv@@@4OEJIwAAAABg6wkqAAAAAGLhCSMAAAAOYQkpAAAAA+NxP7@@4tE" . "JEBIgcS4AAAAW15fXUFcQV1BXkFfw4O8JAABAAABD4S3CwAAg7wkAAEAAAIPhIcJ" . "AABIiehEi4QkSAEAAEEPts0PtsSJ60GJzEGJw0APtsXB6xCJRCQgRInoD7bbwegQ" . "x0QkMAAAAADHRCQ4AAAAAA+20EyJ6A+2xEGJ1onHD6@4i4QkQAEAAEQPr@JEjTyF" . "AAAAAEQPr+FFhcAPjrkAAACJrCQIAQAAi6wkQAEAAESJrCQQAQAARYndhe1+b0hj" . "RCQoTGNcJDhFMcBMA5wkUAEAAEiNVAYCDx+EAAAAAAAPtgJFMdIPtkr@RA+2Sv4p" . "2A+vwEE5xnwaRCnpD6@JOc98EEQrTCQgRQ+vyUU5zEEPncJHiBQDSYPAAUiDwgRE" . "OcV@vEQBfCQoAWwkOItUJCyDRCQwAQFUJCiLRCQwOYQkSAEAAA+Fb@@@@4usJAgB" . "AABEi6wkEAEAAItEJBCJRCRYi0QkGImEJIAAAADp6@v@@4tEJCyDvCQAAQAABYlE" . "JDCLRCRkiUQkLA+FpP3@@4tEJDCLfCQsD6+EJCgBAACLlCSQAAAAhdKNBLiJRCQ4" . "D4VVAwAARYXkD4RRAQAASIu8JGABAABIi4QkWAEAAESLrCSEAAAASIm0JJgAAADH" . "RCQoAAAAAESJpCSUAAAASIl8JBBIi3wkcEiJxkiJfCQYi3wkWIl8JFyLvCSIAAAA" . "i0QkOAMGSItcJBBEi0QkKEiLVCQYjUgBRIszRI1IAkiYSGPJTWPJRQ+2JANBD7Yc" . "C0cPthQLQYnZ63QPH0QAAItKBIsaQYPAAkGJzYnYD7b9wegQQcHtEA+26UUPtu0P" . "tsAxyUQp0EWJ7w+vwEUPr@1EOfh@KA+2x0GJ@0QpyA+vwEQPr@9EOfh@Ew+2w4np" . "RCngD6@ND6@AOcgPnsFIg8IIgfv@@@8AD5fAOMh1EEU5xneMg2wkXAEPiBADAABI" . "g8YESINEJBAEg0QkKBVIg0QkGFRIO3QkSA+FIf@@@0SLpCSUAAAASIu0JJgAAABE" . "iawkhAAAAIm8JIgAAABmkINEJEABSIO8JJABAAAAi3wkQA+Emvz@@4tEJDADhCQ4" . "AQAASGPXi0wkLAOMJDABAABIi5wkkAEAAMHgEAnIO7wkmAEAAIlEk@wPjGP8@@@p" . "mvz@@4tEJFSFwHSkSIuEJFgBAABMi0QkeA8fgAAAAACJygMQSIPABEw5wMYEFgB1" . "7+l6@@@@i0QkMIt8JCwPr4QkKAEAAI0EuInBA4QkCAEAAEWF5I1QAkhj0kEPthwT" . "jVABSJhBD7YEA0hj0kEPtjwTQYn9D4Q1@@@@i7wkgAAAAIlsJBhFMcmJzUGJx0iJ" . "dCQ4iXwkEIt8JFiJfCQoi3wkVEQ5z0WJyn5uSIuEJFgBAABCixSIAeqNQgJImEEP" . "tgwDjUIBSGPSQQ+2FBNImEEPtgQDic4B2USNgQAEAAAp3kQp+kQPr8ZEKegPr8BE" . "D6@GweALQQHAuP4FAAApyA+vwg+v0EEB0EU58HYLg2wkKAEPiEcBAABEOVQkCH5w" . "SIuEJGABAABCixSIAeqNQgJImEEPtgwDjUIBSGPSQQ+2FBNImEEPtgQDQYnKAdlE" . "jYEABAAAQSnaRCn6RQ+vwkQp6A+vwEUPr8LB4AtBAcC4@gUAACnID6@CD6@QQQHQ" . "RTnwdwuDbCQQAQ+I0AAAAEmDwQFFOcwPjwb@@@+LbCQYSIt0JDjpBf7@@0WF5A+E" . "@P3@@0SJdCQoRItMJFgxyUSLrCSEAAAAi7wkiAAAAESLVCQ4TIu0JFgBAABMi7wk" . "YAEAAEGLFI5BixyPRAHSQYnYjUICQcHoEEUPtsBImEEPtgQDRCnARI1CAUhj0g+v" . "wEEPthQTTWPARw+2BANEOeh@HQ+2x0EpwEUPr8BBOfh@Dg+2wynCD6@SOep+CGaQ" . "QYPpAXgoSIPBAUE5zH+ViZwkCAEAAESLdCQo6VD9@@+LbCQYSIt0JDjp9Pn@@4mc" . "JAgBAABEi3QkKOnj+f@@RImsJIQAAACJvCSIAAAARIukJJQAAABIi7QkmAAAAOm@" . "+f@@x0QkaAAAAACLnCSkAAAAi0QkYIlcJGCJhCSkAAAAi5wkpAAAADmcJIwAAAAP" . "jg34@@@HRCRAAAAAAOm8+f@@i4QkOAEAAMeEJDgBAAAAAAAAiYQkjAAAAIuEJDAB" . "AADHhCQwAQAAAAAAAImEJKAAAADpRPf@@zHAhdIPlcCJhCSQAAAAD4UTAQAARTHJ" . "RTHbRYXATIuUJGgBAAAPhEkGAABBiyox0kmDwlSJ6MHoBPfzD6+EJKgBAACJ0ZlB" . "9@8Pr4QkKAEAAEGJwIuEJKABAAAPr8FIi4wkWAEAAJn3+0GNBIBCiQSJiehIi4wk" . "YAEAAIPgD0GNBENBg8MVQokEiUmDwQFFOc13mIuMJIABAAC6rYvbaESJbCRUQQ+v" . "zYnIwfkf9+qJ0MH4DCnISIucJGgBAACJRCRYx4QkgAAAAAAAAADHRCQIAAAAAEiD" . "wwRIiVwkcOkB9v@@iejB6BAPr4QkqAEAAJlB9@8Pr4QkKAEAAInBD7fFD6+EJKAB" . "AACZ9@uNLIGLRCQQiUQkWItEJBiJhCSAAAAA6b31@@+J2EEPr8fB4AJImEgDhCRo" . "AQAASIlEJHCJ0A+20sHoEEGJ1A+2yEiJ6A+2xEGJzonHRA+v8Q+v+EQPr+JFhf8P" . "juAEAACNQ@9Ii0wkcEGNUP@HRCQoAAAAAMdEJBAAAAAASI0EhQYAAADHRCQYAAAA" . "AESJhCQQAQAATI1UkQQx0onpSIlEJCCNBJ0AAAAAQYnVSIm0JCABAACJnCRwAQAA" . "iUQkLESJvCR4AQAAi7QkcAEAAIX2D47tAAAASGNEJBhIi7QkaAEAAEiNXAYCSANE" . "JCBIAfAx9kiJRCQIDx9AAIusJBABAABED7YDRA+2S@9ED7Zb@oXtdEBIi1QkcGaQ" . "iwqJyMHoEA+2wEQpwA+vwEE5xnwbD7bFRCnID6@AOcd8Dg+2wUQp2A+vwEE5xH1a" . "SIPCBEw50nXHi0QkKE1j@UHB4BBBweEIQYPFAUUJyJlFCdj3vCR4AQAAD6+EJCgB" . "AACJxYnwmfe8JHABAABIi5QkWAEAAI1EhQBCiQS6SIuEJGABAABGiQS4SIPDBAO0" . "JKABAABIOVwkCA+FQP@@@4t0JCwBdCQYg0QkEAGLnCSoAQAAi0QkEAFcJCg5hCR4" . "AQAAD4Xj@v@@RIlsJFSJzYtMJFQPr4wkgAEAALqti9toRIusJBABAABIi7QkIAEA" . "AMeEJIAAAAAAAAAAx0QkCAAAAACJyMH5H@fqwfoMKcqJVCRY6aTz@@+LhCRAAQAA" . "RIuMJEgBAABFMdsx2wHASJhIA4QkUAEAAEWFyUiJRCQwi4QkQAEAAESNPIUAAAAA" . "D45k9@@@iXwkIIu8JEABAACF@35PSGNEJChMY9NMA1QkMEUxwEiNTAYCD7YRD7ZB" . "@0iDwQRED7ZJ+mvAS2vSJgHCRInIweAERCnIAdDB+AdDiAQCSYPAAUQ5x3@NRAF8" . "JCgB+0GDwwGLTCQsAUwkKEQ5nCRIAQAAdZdIY4QkQAEAALoBAAAASIm0JCABAACL" . "tCRAAQAAi3wkIEUx28dEJCwAAAAASI1YAUgpwouEJEABAABIiVQkQEiJXCQ4g+gB" . "iUQkKIuEJEgBAACD6AGJRCQghfYPjt8AAABMY0wkLEiLTCQ4RYXbSItEJDBMi5Qk" . "UAEAAA+Uw06NBAlIi0wkQEqNVAgBTQHKSQHATAHJSAHBMcDpjgAAAITbD4WOAAAA" . "OUQkKA+EhAAAAEQ5XCQgdH1ED7Zq@0QPtnr+QbkBAAAAQQHtRTn9ckVED7Y6RTn9" . "cjxED7Z5@0U5@XIyRQ+2eP9FOf1yKEQPtnn+RTn9ch5ED7Y5RTn9chVFD7Z4@kU5" . "@XILRQ+2CEU5zUEPksFFiAwCSIPAAUiDwgFJg8ABSIPBATnGfg+FwA+Fav@@@0HG" . "BAIC690BdCQsQYPDAUQ5nCRIAQAAD4UH@@@@i0QkEEiLtCQgAQAAiUQkWItEJBiJ" . "hCSAAAAA6YLx@@+NRQFEi5QkSAEAAEUx2zHbweAHicWLhCRAAQAARYXSRI08hQAA" . "AAAPjlL1@@9EiXQkIESLtCRAAQAARYX2flNIY0QkKExj00wDlCRQAQAARTHASI1M" . "BgIPthEPtkH@RA+2Sf5rwEtr0iYBwkSJyMHgBEQpyAHQOcVDD5cEAkmDwAFIg8EE" . "RTnGf81EAXwkKEQB80GDwwGLTCQsAUwkKEQ5nCRIAQAAdZKLRCQQRIt0JCCJRCRY" . "i0QkGImEJIAAAADpvfD@@8dEJBgAAAAAx0QkEAAAAADHRCQIAAAAAMdEJFQAAAAA" . "6Qbv@@@HRCRYAAAAAMeEJIAAAAAAAAAAx0QkVAAAAADHRCQIAAAAAOmX8P@@McDH" . "RCRUAAAAAOkz+v@@kJCQkA==" this.MCode(&MyFunc, StrReplace((A_PtrSize=8?x64:x32),"@","/")) } text:=j[1], w:=j[2], h:=j[3] , err1:=this.Floor(j[4] ? j[5] : ini.err1) , err0:=this.Floor(j[4] ? j[6] : ini.err0) , mode:=j[7], color:=j[8], n:=j[9] return (!ini.bits.Scan0) ? 0 : DllCall(MyFunc.Ptr , "int",mode, "uint",color, "uint",n, "int",dir , "Ptr",ini.bits.Scan0, "int",ini.bits.Stride , "int",sx, "int",sy, "int",sw, "int",sh , "Ptr",ini.ss, "Ptr",ini.s1, "Ptr",ini.s0 , (mode=5 ? "Ptr":"AStr"),text, "int",w, "int",h , "int",Floor(err1*10000), "int",Floor(err0*10000) , "Ptr",allpos_ptr, "int",ini.allpos_max , "int",Floor(w*ini.zoomW), "int",Floor(h*ini.zoomH)) } code() { return " ( //***** 机器码的 C语言 源代码 ***** int __attribute__((__stdcall__)) PicFind( int mode, unsigned int c, unsigned int n, int dir , unsigned char * Bmp, int Stride , int sx, int sy, int sw, int sh , unsigned char * ss, unsigned int * s1, unsigned int * s0 , unsigned char * text, int w, int h, int err1, int err0 , unsigned int * allpos, int allpos_max , int new_w, int new_h ) { int ok, o, i, j, k, v, e1, e0, len1, len0, max; int x, y, x1, y1, x2, y2, x3, y3; int r, g, b, rr, gg, bb, dR, dG, dB; unsigned int c1, c2; unsigned char * gs; unsigned int * cors; ok=0; o=0; len1=0; len0=0; //---------------------- // 找多色、找单色、搜图模式 if (mode==5) { if (k=(c!=0)) // FindPic { cors=(unsigned int *)(text+w*h*4); r=(c>>16)&0xFF; g=(c>>8)&0xFF; b=c&0xFF; dR=r*r; dG=g*g; dB=b*b; for (y=0; y>16)&0xFF)-rr; g=((c>>8)&0xFF)-gg; b=(c&0xFF)-bb; if (r*r<=dR && g*g<=dG && b*b<=dB) goto NoMatch1; } s1[len1]=(y*new_h/h)*Stride+(x*new_w/w)*4; s0[len1++]=(rr<<16)|(gg<<8)|bb; NoMatch1:; } } } else // FindMultiColor or FindColor { cors=(unsigned int *)text; for (; len1>4)/w; x=(c>>4)%w; s1[len1]=(y*new_h/h)*Stride+(x*new_w/w)*4; s0[len1]=o+(c&0xF)*2; } cors++; } goto StartLookUp; } //---------------------- // 生成查表需要的表格 for (y=0; y>16; x=c&0xFFFF; c=(y*new_h/h)*Stride+(x*new_w/w)*4; goto StartLookUp; } //---------------------- // 生成二值化图像 o=sy*Stride+sx*4; j=Stride-sw*4; i=0; if (mode==0) // 颜色相似二值化 { rr=(c>>16)&0xFF; gg=(c>>8)&0xFF; bb=c&0xFF; for (y=0; y>7; } for (i=0, y=0; yn || gs[i+1]>n || gs[i-sw]>n || gs[i+sw]>n || gs[i-sw-1]>n || gs[i-sw+1]>n || gs[i+sw-1]>n || gs[i+sw+1]>n) ? 1:0; } } } else // (mode==3) 颜色分量二值化 { rr=(c>>16)&0xFF; gg=(c>>8)&0xFF; bb=c&0xFF; r=(n>>16)&0xFF; g=(n>>8)&0xFF; b=n&0xFF; dR=r*r; dG=g*g; dB=b*b; for (y=0; y=len1) len1=0; if (err0>=len0) len0=0; max=(len1>len0) ? len1 : len0; if (mode==5 || mode==4) { x1=sx; y1=sy; sx=0; sy=0; } else { x1=0; y1=0; } x2=x1+sw-new_w; y2=y1+sh-new_h; // 1 ==> ( Left to Right ) Top to Bottom // 2 ==> ( Right to Left ) Top to Bottom // 3 ==> ( Left to Right ) Bottom to Top // 4 ==> ( Right to Left ) Bottom to Top // 5 ==> ( Top to Bottom ) Left to Right // 6 ==> ( Bottom to Top ) Left to Right // 7 ==> ( Top to Bottom ) Right to Left // 8 ==> ( Bottom to Top ) Right to Left if (dir<1 || dir>8) dir=1; if (--dir>3) { r=y1; y1=x1; x1=r; r=y2; y2=x2; x2=r; } for (y3=y1; y3<=y2; y3++) { for (x3=x1; x3<=x2; x3++) { y=((dir&3)>1) ? y1+y2-y3 : y3; x=(dir&1) ? x1+x2-x3 : x3; if (dir>3) { r=y; y=x; x=r; } //---------------------- e1=err1; e0=err0; if (mode==5) { o=y*Stride+x*4; if (k) { for (i=0; i>16)&0xFF); g=Bmp[1+j]-((c>>8)&0xFF); b=Bmp[j]-(c&0xFF); if ((r*r>dR || g*g>dG || b*b>dB) && (--e1)<0) goto NoMatch; } } else { for (i=0; i>16)&0xFF)-rr; g=((c1>>8)&0xFF)-gg; b=(c1&0xFF)-bb; dR=(c2>>16)&0xFF; dG=(c2>>8)&0xFF; dB=c2&0xFF; if ((r*r<=dR*dR && g*g<=dG*dG && b*b<=dB*dB)^(c1>0xFFFFFF)) goto MatchOK; } if ((--e1)<0) goto NoMatch; MatchOK:; } } } else if (mode==4) { o=y*Stride+x*4; j=o+c; rr=Bmp[2+j]; gg=Bmp[1+j]; bb=Bmp[j]; for (i=0; in && (--e1)<0) goto NoMatch; } if (i=allpos_max) goto Return1; } NoMatch:; } } //---------------------- Return1: return ok; } )" } PicInfo(text) { static info:=Map(), bmp:=[] if !InStr(text, "$") return key:=(r:=StrLen(text))<10000 ? text : DllCall("ntdll\RtlComputeCrc32", "uint",0 , "Ptr",StrPtr(text), "uint",r*2, "uint") if info.Has(key) return info[key] v:=text, comment:="", seterr:=err1:=err0:=0 ; You Can Add Comment Text within The <> if RegExMatch(v, "<([^>\n]*)>", &r) v:=StrReplace(v,r[0]), comment:=Trim(r[1]) ; You can Add two fault-tolerant in the [], separated by commas if RegExMatch(v, "\[([^\]\n]*)]", &r) { v:=StrReplace(v,r[0]), r:=StrSplit(r[1] ",", ",") , seterr:=1, err1:=r[1], err0:=r[2] } color:=SubStr(v,1,InStr(v,"$")-1), v:=Trim(SubStr(v,InStr(v,"$")+1)) mode:=InStr(color,"##") ? 5 : InStr(color,"#") ? 4 : InStr(color,"-") ? 3 : InStr(color,"**") ? 2 : InStr(color,"*") ? 1 : 0 color:=RegExReplace(color, "[*#\s]") (mode=0 || mode=3 || mode=5) && color:=StrReplace(color,"0x") if (mode=5) { if !(v~="/[\s\-\w]+/[\s\-\w,/]+$") ; FindPic { ; 你可以使用 Text:="|<>##DRDGDB-RRGGBB1-RRGGBB2... $ d:\a.bmp" ; 那么 0xRRGGBB1(+/-0xDRDGDB)... 都是透明色 if !(hBM:=LoadPicture(v)) return this.GetBitmapWH(hBM, &w, &h) if (w<1 || h<1) return hBM2:=this.CreateDIBSection(w, h, 32, &Scan0) this.CopyHBM(hBM2, 0, 0, hBM, 0, 0, w, h) DllCall("DeleteObject", "Ptr",hBM) if (!Scan0) return ; 所有用于 ImageSearch 的图片都缓存了 StrReplace(color, "-",,, &n) bmp.Push(buf:=Buffer(w*h*4+n*4)), v:=buf.Ptr DllCall("RtlMoveMemory", "Ptr",v, "Ptr",Scan0, "Ptr",w*h*4) DllCall("DeleteObject", "Ptr",hBM2) p:=v+w*h*4-4, tab:=Map(), tab.CaseSense:="Off" , tab.Set("Black", "000000", "White", "FFFFFF" , "Red", "FF0000", "Green", "008000", "Blue", "0000FF" , "Yellow", "FFFF00", "Silver", "C0C0C0", "Gray", "808080" , "Teal", "008080", "Navy", "000080", "Aqua", "00FFFF" , "Olive", "808000", "Lime", "00FF00", "Fuchsia", "FF00FF" , "Purple", "800080", "Maroon", "800000") For k1,v1 in StrSplit(color, "-") if (k1>1) NumPut("uint", this.Floor("0x" (tab.Has(v1)?tab[v1]:v1)), p+=4) color:=this.Floor("0x" StrSplit(color "-", "-")[1])|0x1000000 } else ; FindMultiColor or FindColor { ; Text:='|<>##DRDGDB $ 0/0/RRGGBB1-DRDGDB1/RRGGBB2/-RRGGBB3/-RRGGBB4, xn/yn/...' ; '##'之后的颜色 (0xDRDGDB) 是所有颜色的默认偏色(各个分量允许的变化值) ; 初始点 (0,0) 匹配 0xRRGGBB1(+/-0xDRDGDB1) 或者 0xRRGGBB2(+/-0xDRDGDB) ; 或者 非 0xRRGGBB3(+/-0xDRDGDB) 或者 非 0xRRGGBB4(+/-0xDRDGDB) ; 以 '-' 开头的颜色,表示除了这种颜色的其他的任何颜色都匹配 ; 每个点可以允许匹配10组颜色 (xn/yn/RRGGBB1/.../RRGGBB10) arr:=StrSplit(Trim(RegExReplace(v, "i)\s|0x"), ","), ",") if !(n:=arr.Length) return bmp.Push(buf:=Buffer(n*(1+10+10)*4)), v:=buf.Ptr , color:=StrSplit(color "-", "-")[1] For k1,v1 in arr { r:=StrSplit(v1 "/", "/") , x:=this.Floor(r[1]), y:=this.Floor(r[2]) , (A_Index=1) ? (x1:=x2:=x, y1:=y2:=y) : (x1:=Min(x1,x), x2:=Max(x2,x) , y1:=Min(y1,y), y2:=Max(y2,y)) } w:=x2-x1+1, h:=y2-y1+1 For k1,v1 in arr { r:=StrSplit(v1 "/", "/") , x:=this.Floor(r[1])-x1, y:=this.Floor(r[2])-y1 , n1:=Min(Max(r.Length-3, 0), 10) , NumPut("uint", (y*w+x)<<4|n1, p:=v+(A_Index-1)*84) Loop n1 k1:=(InStr(v1:=r[2+A_Index], "-")=1 ? 0x1000000:0) , c:=StrSplit(Trim(v1,"-") "-" color, "-") , NumPut("uint", this.Floor("0x" c[1])&0xFFFFFF|k1, p+=4) , NumPut("uint", this.Floor("0x" c[2]), p+=4) } color:=0 } } else { r:=StrSplit(v ".", "."), w:=this.Floor(r[1]) , v:=this.base64tobit(r[2]), h:=StrLen(v)//w if (w<1 || h<1 || StrLen(v)!=w*h) return if (mode=3) { r:=StrSplit(color, "-") , color:=this.Floor("0x" r[1]), n:=this.Floor("0x" r[2]) } else { r:=StrSplit(color "@1", "@") , color:=this.Floor((mode=0?"0x":"") r[1]), n:=this.Floor(r[2]) , n:=(n<=0||n>1?1:n), n:=Floor(4606*255*255*(1-n)*(1-n)) , (mode=4) && color:=((color-1)//w)<<16|Mod(color-1,w) } } return info[key]:=[v, w, h, seterr, err1, err0, mode, color, n, comment] } GetBitsFromScreen(&x:=0, &y:=0, &w:=0, &h:=0 , ScreenShot:=1, &zx:=0, &zy:=0, &zw:=0, &zh:=0) { static CAPTUREBLT:="" (!IsObject(this.bits) && this.bits:={Scan0:0, hBM:0, oldzw:0, oldzh:0}) , bits:=this.bits if (!ScreenShot && bits.Scan0) { zx:=bits.zx, zy:=bits.zy, zw:=bits.zw, zh:=bits.zh , w:=Min(x+w,zx+zw), x:=Max(x,zx), w-=x , h:=Min(y+h,zy+zh), y:=Max(y,zy), h-=y return bits } cri:=A_IsCritical Critical if (id:=this.BindWindow(0,0,1)) { id:=WinGetID("ahk_id " id) WinGetPos &zx, &zy, &zw, &zh, id } if (!id) zx:=SysGet(76), zy:=SysGet(77), zw:=SysGet(78), zh:=SysGet(79) this.UpdateBits(bits, zx, zy, zw, zh) , w:=Min(x+w,zx+zw), x:=Max(x,zx), w-=x , h:=Min(y+h,zy+zh), y:=Max(y,zy), h-=y if (!ScreenShot || w<1 || h<1 || !bits.hBM) { Critical(cri) return bits } if IsSet(GetBitsFromScreen2) && (GetBitsFromScreen2 is Func) && GetBitsFromScreen2(bits, x-zx, y-zy, w, h) { ; Each small range of data obtained from DXGI must be ; copied to the screenshot cache using this.CopyBits() zx:=bits.zx, zy:=bits.zy, zw:=bits.zw, zh:=bits.zh Critical(cri) return bits } if (CAPTUREBLT="") ; thanks Descolada { DllCall("Dwmapi\DwmIsCompositionEnabled", "Int*", &i:=0) CAPTUREBLT:=i ? 0 : 0x40000000 } mDC:=DllCall("CreateCompatibleDC", "Ptr",0, "Ptr") oBM:=DllCall("SelectObject", "Ptr",mDC, "Ptr",bits.hBM, "Ptr") if (id) { if (mode:=this.BindWindow(0,0,0,1))<2 { hDC:=DllCall("GetDCEx", "Ptr",id, "Ptr",0, "int",3, "Ptr") DllCall("BitBlt","Ptr",mDC,"int",x-zx,"int",y-zy,"int",w,"int",h , "Ptr",hDC, "int",x-zx, "int",y-zy, "uint",0xCC0020|CAPTUREBLT) DllCall("ReleaseDC", "Ptr",id, "Ptr",hDC) } else { hBM2:=this.CreateDIBSection(zw, zh) mDC2:=DllCall("CreateCompatibleDC", "Ptr",0, "Ptr") oBM2:=DllCall("SelectObject", "Ptr",mDC2, "Ptr",hBM2, "Ptr") DllCall("PrintWindow", "Ptr",id, "Ptr",mDC2, "uint",(mode>3)*3) DllCall("BitBlt","Ptr",mDC,"int",x-zx,"int",y-zy,"int",w,"int",h , "Ptr",mDC2, "int",x-zx, "int",y-zy, "uint",0xCC0020) DllCall("SelectObject", "Ptr",mDC2, "Ptr",oBM2) DllCall("DeleteDC", "Ptr",mDC2) DllCall("DeleteObject", "Ptr",hBM2) } } else { hDC:=DllCall("GetWindowDC","Ptr",id:=DllCall("GetDesktopWindow","Ptr"),"Ptr") DllCall("BitBlt","Ptr",mDC,"int",x-zx,"int",y-zy,"int",w,"int",h , "Ptr",hDC, "int",x, "int",y, "uint",0xCC0020|CAPTUREBLT) DllCall("ReleaseDC", "Ptr",id, "Ptr",hDC) } if this.CaptureCursor(0,0,0,0,0,1) this.CaptureCursor(mDC, zx, zy, zw, zh) DllCall("SelectObject", "Ptr",mDC, "Ptr",oBM) DllCall("DeleteDC", "Ptr",mDC) Critical(cri) return bits } UpdateBits(bits, zx, zy, zw, zh) { if (zw>bits.oldzw || zh>bits.oldzh || !bits.hBM) { Try DllCall("DeleteObject", "Ptr",bits.hBM) bits.hBM:=this.CreateDIBSection(zw, zh, bpp:=32, &ppvBits) , bits.Scan0:=(!bits.hBM ? 0:ppvBits) , bits.Stride:=((zw*bpp+31)//32)*4 , bits.oldzw:=zw, bits.oldzh:=zh } bits.zx:=zx, bits.zy:=zy, bits.zw:=zw, bits.zh:=zh } CreateDIBSection(w, h, bpp:=32, &ppvBits:=0) { NumPut("int",40, "int",w, "int",-h, "short",1, "short",bpp, bi:=Buffer(40,0)) return DllCall("CreateDIBSection", "Ptr",0, "Ptr",bi , "int",0, "Ptr*",&ppvBits:=0, "Ptr",0, "int",0, "Ptr") } GetBitmapWH(hBM, &w, &h) { bm:=Buffer(size:=(A_PtrSize=8 ? 32:24)) , DllCall("GetObject", "Ptr",hBM, "int",size, "Ptr",bm) , w:=NumGet(bm,4,"int"), h:=Abs(NumGet(bm,8,"int")) } CopyHBM(hBM1, x1, y1, hBM2, x2, y2, w, h, Clear:=0, trans:=0, alpha:=255) { if (w<1 || h<1 || !hBM1 || !hBM2) return mDC1:=DllCall("CreateCompatibleDC", "Ptr",0, "Ptr") oBM1:=DllCall("SelectObject", "Ptr",mDC1, "Ptr",hBM1, "Ptr") mDC2:=DllCall("CreateCompatibleDC", "Ptr",0, "Ptr") oBM2:=DllCall("SelectObject", "Ptr",mDC2, "Ptr",hBM2, "Ptr") if (trans) DllCall("GdiAlphaBlend", "Ptr",mDC1, "int",x1, "int",y1, "int",w, "int",h , "Ptr",mDC2, "int",x2, "int",y2, "int",w, "int",h, "uint",alpha<<16) else DllCall("BitBlt", "Ptr",mDC1, "int",x1, "int",y1, "int",w, "int",h , "Ptr",mDC2, "int",x2, "int",y2, "uint",0xCC0020) if (Clear) DllCall("BitBlt", "Ptr",mDC1, "int",x1, "int",y1, "int",w, "int",h , "Ptr",mDC1, "int",x1, "int",y1, "uint",MERGECOPY:=0xC000CA) DllCall("SelectObject", "Ptr",mDC1, "Ptr",oBM1) DllCall("DeleteDC", "Ptr",mDC1) DllCall("SelectObject", "Ptr",mDC2, "Ptr",oBM2) DllCall("DeleteDC", "Ptr",mDC2) } CopyBits(Scan01,Stride1,x1,y1,Scan02,Stride2,x2,y2,w,h,Reverse:=0) { if (w<1 || h<1 || !Scan01 || !Scan02) return static init:="", MFCopyImage if (!init && init:=1) { MFCopyImage:=DllCall("GetProcAddress", "Ptr" , DllCall("LoadLibrary", "Str","Mfplat.dll", "Ptr") , "AStr","MFCopyImage", "Ptr") } if (MFCopyImage && !Reverse) ; thanks QQ:任性 { return DllCall(MFCopyImage , "Ptr",Scan01+y1*Stride1+x1*4, "int",Stride1 , "Ptr",Scan02+y2*Stride2+x2*4, "int",Stride2 , "uint",w*4, "uint",h) } ListLines (lls:=A_ListLines)?0:0 p1:=Scan01+(y1-1)*Stride1+x1*4 , p2:=Scan02+(y2-1)*Stride2+x2*4, w*=4 if (Reverse) p2+=(h+1)*Stride2, Stride2:=-Stride2 Loop h DllCall("RtlMoveMemory","Ptr",p1+=Stride1,"Ptr",p2+=Stride2,"Ptr",w) ListLines lls } DrawHBM(hBM, lines) { mDC:=DllCall("CreateCompatibleDC", "Ptr",0, "Ptr") oBM:=DllCall("SelectObject", "Ptr",mDC, "Ptr",hBM, "Ptr") oldc:="", brush:=0, rect:=Buffer(16) For k,v in lines ; [ [x, y, w, h, color] ] if IsObject(v) { if (oldc!=v[5]) { oldc:=v[5], BGR:=(oldc&0xFF)<<16|oldc&0xFF00|(oldc>>16)&0xFF DllCall("DeleteObject", "Ptr",brush) brush:=DllCall("CreateSolidBrush", "UInt",BGR, "Ptr") } DllCall("SetRect", "Ptr",rect, "int",v[1], "int",v[2] , "int",v[1]+v[3], "int",v[2]+v[4]) DllCall("FillRect", "Ptr",mDC, "Ptr",rect, "Ptr",brush) } DllCall("DeleteObject", "Ptr",brush) DllCall("SelectObject", "Ptr",mDC, "Ptr",oBM) DllCall("DeleteObject", "Ptr",mDC) } ; 绑定窗口从而可以后台查找这个窗口的图像 ; 相当于始终在前台。解绑窗口使用 FindText().BindWindow(0) BindWindow(bind_id:=0, bind_mode:=0, get_id:=0, get_mode:=0) { (!IsObject(this.bind) && this.bind:={id:0, mode:0, oldStyle:0}) , bind:=this.bind if (get_id) return bind.id if (get_mode) return bind.mode if (bind_id) { bind.id:=bind_id:=this.Floor(bind_id) , bind.mode:=bind_mode, bind.oldStyle:=0 if (bind_mode & 1) { i:=WinGetExStyle(bind_id) bind.oldStyle:=i WinSetTransparent(255, bind_id) Loop 30 { Sleep 100 i:=WinGetTransparent(bind_id) } Until (i=255) } } else { bind_id:=bind.id if (bind.mode & 1) WinSetExStyle(bind.oldStyle, bind_id) bind.id:=0, bind.mode:=0, bind.oldStyle:=0 } } ; 使用 FindText().CaptureCursor(1) 设置抓图时捕获鼠标 ; 使用 FindText().CaptureCursor(0) 取消抓图时捕获鼠标 CaptureCursor(hDC:=0, zx:=0, zy:=0, zw:=0, zh:=0, get_cursor:=0) { if (get_cursor) return this.Cursor if (hDC=1 || hDC=0) && (zw=0) { this.Cursor:=hDC return } mi:=Buffer(40, 0), NumPut("int", 16+A_PtrSize, mi) DllCall("GetCursorInfo", "Ptr",mi) bShow:=NumGet(mi, 4, "int") hCursor:=NumGet(mi, 8, "Ptr") x:=NumGet(mi, 8+A_PtrSize, "int") y:=NumGet(mi, 12+A_PtrSize, "int") if (!bShow) || (x=zx+zw || y>=zy+zh) return ni:=Buffer(40, 0) DllCall("GetIconInfo", "Ptr",hCursor, "Ptr",ni) xCenter:=NumGet(ni, 4, "int") yCenter:=NumGet(ni, 8, "int") hBMMask:=NumGet(ni, (A_PtrSize=8?16:12), "Ptr") hBMColor:=NumGet(ni, (A_PtrSize=8?24:16), "Ptr") DllCall("DrawIconEx", "Ptr",hDC , "int",x-xCenter-zx, "int",y-yCenter-zy, "Ptr",hCursor , "int",0, "int",0, "int",0, "int",0, "int",3) DllCall("DeleteObject", "Ptr",hBMMask) DllCall("DeleteObject", "Ptr",hBMColor) } MCode(&code, hex) { flag:=((hex~="[^\s\da-fA-F]")?1:4), hex:=RegExReplace(hex, "[\s=]") , code:=Buffer(len:=(flag=1 ? StrLen(hex)//4*3+3 : StrLen(hex)//2)) DllCall("crypt32\CryptStringToBinary", "Str",hex, "uint",0 , "uint",flag, "Ptr",code, "uint*",&len, "Ptr",0, "Ptr",0) DllCall("VirtualProtect", "Ptr",code, "Ptr",len, "uint",0x40, "Ptr*",0) } bin2hex(addr, size, base64:=1) { flag:=(base64 ? 1|0x40000000 : 4|0x0000000C) Loop 2 p:=(A_Index=1 ? 0 : Buffer(len*2)) , DllCall("Crypt32\CryptBinaryToString", "Ptr",addr, "uint",size , "uint",flag, "Ptr",p, "uint*",&len:=0) return RegExReplace(StrGet(p, len), "\s+") } base64tobit(s) { ListLines (lls:=A_ListLines)?0:0 static Chars:="0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" Loop Parse, Chars if InStr(s, A_LoopField, 1) s:=StrReplace(s, A_LoopField, ((i:=A_Index-1)>>5&1) . (i>>4&1) . (i>>3&1) . (i>>2&1) . (i>>1&1) . (i&1), 1) s:=RegExReplace(RegExReplace(s,"[^01]+"),"10*$") ListLines lls return s } bit2base64(s) { ListLines (lls:=A_ListLines)?0:0 s:=RegExReplace(s,"[^01]+") s.=SubStr("100000",1,6-Mod(StrLen(s),6)) s:=RegExReplace(s,".{6}","|$0") Chars:="0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" Loop Parse, Chars s:=StrReplace(s, "|" . ((i:=A_Index-1)>>5&1) . (i>>4&1) . (i>>3&1) . (i>>2&1) . (i>>1&1) . (i&1), A_LoopField) ListLines lls return s } ASCII(s) { if RegExMatch(s, "\$(\d+)\.([\w+/]+)", &r) { s:=RegExReplace(this.base64tobit(r[2]),".{" r[1] "}","$0`n") s:=StrReplace(StrReplace(s,"0","_"),"1","0") } else s:="" return s } ; 可以在脚本的开头用 FindText().PicLib(Text,1) 导入字库, ; 然后使用 FindText().PicLib("说明文字1|说明文字2|...") 获取字库中的数据 PicLib(comments, add_to_Lib:=0, index:=1) { (!IsObject(this.Lib) && this.Lib:=Map()), Lib:=this.Lib , (!Lib.Has(index) && Lib[index]:=Map()), Lib:=Lib[index] if (add_to_Lib) { re:="<([^>\n]*)>[^$\n]+\$[^`"'\r\n]+" Loop Parse, comments, "|" if RegExMatch(A_LoopField, re, &r) { s1:=Trim(r[1]), s2:="" Loop Parse, s1 s2.="_" . Format("{:d}",Ord(A_LoopField)) Lib[s2]:=r[0] } Lib[""]:="" } else { Text:="" Loop Parse, comments, "|" { s1:=Trim(A_LoopField), s2:="" Loop Parse, s1 s2.="_" . Format("{:d}",Ord(A_LoopField)) if Lib.Has(s2) Text.="|" . Lib[s2] } return Text } } ; 分割字符串为单个文字并获取数据 PicN(Number, index:=1) { return this.PicLib(RegExReplace(Number,".","|$0"), 0, index) } ; 使用 FindText().PicX(Text) 可以将文字分割成多个单字的组合,从而适应间隔变化 ; 但是不能用于“颜色位置二值化”模式, 因为位置是与整体图像相关的 PicX(Text) { if !RegExMatch(Text, "(<[^$\n]+)\$(\d+)\.([\w+/]+)", &r) return Text v:=this.base64tobit(r[3]), Text:="" c:=StrLen(StrReplace(v,"0"))<=StrLen(v)//2 ? "1":"0" txt:=RegExReplace(v,".{" r[2] "}","$0`n") While InStr(txt,c) { While !(txt~="m`n)^" c) txt:=RegExReplace(txt,"m`n)^.") i:=0 While (txt~="m`n)^.{" i "}" c) i:=Format("{:d}",i+1) v:=RegExReplace(txt,"m`n)^(.{" i "}).*","$1") txt:=RegExReplace(txt,"m`n)^.{" i "}") if (v!="") Text.="|" r[1] "$" i "." this.bit2base64(v) } return Text } ; 截屏,作为后续操作要用的“上一次的截屏” ScreenShot(x1:=0, y1:=0, x2:=0, y2:=0) { this.FindText(,, x1, y1, x2, y2) } ; 从“上一次的截屏”中快速获取指定坐标的RGB颜色 ; 如果坐标超出了屏幕范围,将返回白色 GetColor(x, y, fmt:=1) { bits:=this.GetBitsFromScreen(,,,,0,&zx,&zy,&zw,&zh) , c:=(x=zx+zw || y=zy+zh || !bits.Scan0) ? 0xFFFFFF : NumGet(bits.Scan0+(y-zy)*bits.Stride+(x-zx)*4,"uint") return (fmt ? Format("0x{:06X}",c&0xFFFFFF) : c) } ; 在“上一次的截屏”中设置点的RGB颜色 SetColor(x, y, color:=0x000000) { bits:=this.GetBitsFromScreen(,,,,0,&zx,&zy,&zw,&zh) if !(x=zx+zw || y=zy+zh || !bits.Scan0) NumPut("uint", color, bits.Scan0+(y-zy)*bits.Stride+(x-zx)*4) } ; 根据 FindText() 的结果识别一行文字或验证码 ; offsetX 为两个文字的最大间隔,超过会插入*号 ; offsetY 为两个文字的最大高度差 ; overlapW 用于设置覆盖的宽度 ; 最后返回数组:{text:识别结果, x:结果左上角X, y:结果左上角Y, w:宽, h:高} Ocr(ok, offsetX:=20, offsetY:=20, overlapW:=0) { ocr_Text:=ocr_X:=ocr_Y:=min_X:=dx:="" For k,v in ok x:=v.1 , min_X:=(A_Index=1 || xmax_X ? x : max_X) While (min_X!="" && min_X<=max_X) { LeftX:="" For k,v in ok { x:=v.1, y:=v.2 if (xoffsetY) Continue ; Get the leftmost X coordinates if (LeftX="" || xdx ? "*":"") . LeftOCR ; Update for next search min_X:=LeftX+LeftW-(overlapW>LeftW//2 ? LeftW//2:overlapW) , dx:=LeftX+LeftW+offsetX, ocr_Y:=LeftY , (LeftYmax_Y && max_Y:=LeftY+LeftH) } if (ocr_X="") ocr_X:=0, min_Y:=0, min_X:=0, max_Y:=0 return {text:ocr_Text, x:ocr_X, y:min_Y , w: min_X-ocr_X, h: max_Y-min_Y} } ; 按照从左到右、从上到下的顺序排序FindText()的结果 ; 忽略轻微的Y坐标差距,返回排序后的数组对象 Sort(ok, dy:=10) { if !IsObject(ok) return ok s:="", n:=150000, ypos:=[] For k,v in ok { x:=v.x, y:=v.y, add:=1 For k1,v1 in ypos if Abs(y-v1)<=dy { y:=v1, add:=0 Break } if (add) ypos.Push(y) s.=(y*n+x) "." k "|" } s:=Sort(Trim(s,"|"), "N D|") ok2:=[] Loop Parse, s, "|" ok2.Push( ok[StrSplit(A_LoopField,".")[2]] ) return ok2 } ; 以指定点为中心,按从近到远排序FindText()的结果,返回排序后的数组 Sort2(ok, px, py) { if !IsObject(ok) return ok s:="" For k,v in ok s.=((v.x-px)**2+(v.y-py)**2) "." k "|" s:=Sort(Trim(s,"|"), "N D|") ok2:=[] Loop Parse, s, "|" ok2.Push( ok[StrSplit(A_LoopField,".")[2]] ) return ok2 } ; 按指定的查找方向,排序FindText()的结果,返回排序后的数组 Sort3(ok, dir:=1) { if !IsObject(ok) return ok s:="", n:=150000 For k,v in ok x:=v.1, y:=v.2 , s.=(dir=1 ? y*n+x : dir=2 ? y*n-x : dir=3 ? -y*n+x : dir=4 ? -y*n-x : dir=5 ? x*n+y : dir=6 ? x*n-y : dir=7 ? -x*n+y : dir=8 ? -x*n-y : y*n+x) "." k "|" s:=Sort(Trim(s,"|"), "N D|") ok2:=[] Loop Parse, s, "|" ok2.Push( ok[StrSplit(A_LoopField,".")[2]] ) return ok2 } ; 提示某个坐标的位置,或远程控制中当前鼠标的位置 MouseTip(x:="", y:="", w:=10, h:=10, d:=3) { if (x="") { pt:=Buffer(16,0), DllCall("GetCursorPos", "Ptr",pt) x:=NumGet(pt,0,"uint"), y:=NumGet(pt,4,"uint") } Loop 4 { this.RangeTip(x-w, y-h, 2*w+1, 2*h+1, (A_Index & 1 ? "Red":"Blue"), d) Sleep 500 } this.RangeTip() } ; 显示范围的边框,类似于 ToolTip RangeTip(x:="", y:="", w:="", h:="", color:="Red", d:=3) { static Range:=Map() if (x="") { Loop 4 if (Range.Has(i:=A_Index) && Range[i]) Range[i].Destroy(), Range[i]:=0 return } if !(Range.Has(1) && Range[1]) { Loop 4 Range[A_Index]:=Gui("+AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000") } x:=(IsNumBer(x)?x:0), y:=(IsNumBer(y)?y:0) , w:=(IsNumBer(w)?w:0), h:=(IsNumBer(h)?h:0), d:=(IsNumBer(d)?d:0) Loop 4 { i:=A_Index , x1:=(i=2 ? x+w : x-d) , y1:=(i=3 ? y+h : y-d) , w1:=(i=1 || i=3 ? w+2*d : d) , h1:=(i=2 || i=4 ? h+2*d : d) Range[i].BackColor:=color Range[i].Show("NA x" x1 " y" y1 " w" w1 " h" h1) } } ; 用鼠标左右键选取屏幕范围 GetRange(ww:=25, hh:=8, key:="RButton") { static Gui_Off:="", hk, FindText_HotkeyIf:="" if (!Gui_Off) Gui_Off:=this.GetRange.Bind(this, "Off") if (ww="Off") return hk:=Trim(A_ThisHotkey, "*") ;--------------------- Try FindText_HotkeyIf.Destroy() FindText_HotkeyIf:=_Gui:=Gui() _Gui.Opt "-Caption +ToolWindow +E0x80000" _Gui.Title:="FindText_HotkeyIf" _Gui.Show "NA x0 y0 w0 h0" ;--------------------- HotIfWinExist "FindText_HotkeyIf" keys:=key "|Up|Down|Left|Right" For k,v in StrSplit(keys, "|") { KeyWait v Try Hotkey "*" v, Gui_Off, "On" } KeyWait "Ctrl" HotIfWinExist ;--------------------- Critical (cri:=A_IsCritical)?"Off":"Off" CoordMode "Mouse" tip:=this.Lang("s5") hk:="", oldx:=oldy:="", keydown:=0 Loop { Sleep 50 MouseGetPos &x, &y if (hk=key) || GetKeyState(key,"P") || GetKeyState("Ctrl","P") { keydown++ if (keydown=1) MouseGetPos &x1, &y1, &Bind_ID KeyWait key KeyWait "Ctrl" hk:="" if (keydown>1) Break } else if (hk="Up") || GetKeyState("Up","P") (hh>1 && hh--), hk:="" else if (hk="Down") || GetKeyState("Down","P") hh++, hk:="" else if (hk="Left") || GetKeyState("Left","P") (ww>1 && ww--), hk:="" else if (hk="Right") || GetKeyState("Right","P") ww++, hk:="" this.RangeTip((keydown?x1:x)-ww, (keydown?y1:y)-hh , 2*ww+1, 2*hh+1, (A_MSec<500?"Red":"Blue")) if (oldx=x && oldy=y) Continue oldx:=x, oldy:=y ToolTip "x: " (keydown?x1:x) " y: " (keydown?y1:y) "`n" tip } ToolTip this.RangeTip() HotIfWinExist "FindText_HotkeyIf" For k,v in StrSplit(keys, "|") Try Hotkey "*" v, Gui_Off, "Off" HotIfWinExist FindText_HotkeyIf.Destroy Critical(cri) return [x1-ww, y1-hh, x1+ww, y1+hh, Bind_ID] } ; 截屏到剪贴板或者文件,或者仅获取范围 SnapShot(ScreenShot:=1, key:="LButton") { static Gui_Off:="", hk, SnapShot_HotkeyIf:="", SnapShot_Box:="" if (!Gui_Off) Gui_Off:=this.SnapShot.Bind(this, "Off") if (ScreenShot="Off") return hk:=Trim(A_ThisHotkey, "*") n:=150000, x:=y:=-n, w:=h:=2*n hBM:=this.BitmapFromScreen(&x,&y,&w,&h,ScreenShot,&zx,&zy,&zw,&zh) ;--------------- Try SnapShot_HotkeyIf.Destroy() ; WS_EX_NOACTIVATE:=0x08000000 SnapShot_HotkeyIf:=_Gui:=Gui() _Gui.Opt "+AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000" _Gui.MarginX:=0, _Gui.MarginY:=0 _Gui.Add "Pic", "w" zw " h" zh, "HBITMAP:*" hBM _Gui.Title:="SnapShot_HotkeyIf" _Gui.Show "NA x" zx " y" zy " w" zw " h" zh ;--------------- Try SnapShot_Box.Destroy() SnapShot_Box:=_Gui:=Gui() _Gui.Opt "+AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000" box_id:=_Gui.Hwnd _Gui.MarginX:=0, _Gui.MarginY:=0 _Gui.SetFont "s12" For k,v in StrSplit(this.Lang("s15"), "|") id:=_Gui.Add("Button", (k=1?"":"x+0"), v) id.GetPos(&pX, &pY, &pW, &pH) box_w:=pX+pW+10, box_h:=pH+10 _Gui.Title:="SnapShot_Box" _Gui.Show "Hide" ;--------------- HotIfWinExist "SnapShot_HotkeyIf" keys:=key "|RButton|Esc|Up|Down|Left|Right" For k,v in StrSplit(keys, "|") { KeyWait v Try Hotkey "*" v, Gui_Off, "On" } HotIfWinExist ;--------------- Critical (cri:=A_IsCritical)?"Off":"Off" CoordMode "Mouse" Loop { ;// For ReTry tip:=this.Lang("s16") hk:="", oldx:=oldy:="", ok:=0, d:=10, oldt:=0, oldf:="" x:=y:=w:=h:=0 Loop { Sleep 50 if (hk="RButton") || (hk="Esc") || GetKeyState("RButton","P") || GetKeyState("Esc","P") Break 2 MouseGetPos &x1, &y1 if (oldx=x1 && oldy=y1) Continue oldx:=x1, oldy:=y1 ToolTip "x: " x1 " y: " y1 " w: 0 h: 0`n" tip } Until (hk=key) || GetKeyState(key,"P") Loop { Sleep 50 MouseGetPos &x2, &y2 x:=Min(x1,x2), y:=Min(y1,y2), w:=Abs(x1-x2)+1, h:=Abs(y1-y2)+1 this.RangeTip(x, y, w, h, (A_MSec<500 ? "Red":"Blue")) if (oldx=x2 && oldy=y2) Continue oldx:=x2, oldy:=y2 ToolTip "x: " x " y: " y " w: " w " h: " h "`n" tip } Until !GetKeyState(key,"P") hk:="" Loop { Sleep 50 MouseGetPos &x3, &y3 x1:=x, y1:=y, x2:=x+w-1, y2:=y+h-1 , d1:=Abs(x3-x1)<=d, d2:=Abs(x3-x2)<=d , d3:=Abs(y3-y1)<=d, d4:=Abs(y3-y2)<=d , d5:=x3>x1+d && x3y1+d && y3zx+zw-box_w && x1:=zx+zw-box_w) , y1:=y+h+10, (y1>zy+zh-box_h && y1:=y-box_h), (y1<10 && y1:=10) SnapShot_Box.Show "NA x" x1 " y" y1 ;------------- if (oldx=x3 && oldy=y3) Continue oldx:=x3, oldy:=y3 ToolTip "x: " x " y: " y " w: " w " h: " h "`n" tip } Break } ;// For ReTry HotIfWinExist "SnapShot_HotkeyIf" For k,v in StrSplit(keys, "|") { KeyWait v Try Hotkey "*" v, Gui_Off, "Off" } HotIfWinExist ToolTip this.RangeTip() this.SetCursor() SnapShot_Box.Destroy SnapShot_HotkeyIf.Destroy Critical(cri) ;--------------- w:=Min(x+w,zx+zw), x:=Max(x,zx), w-=x h:=Min(y+h,zy+zh), y:=Max(y,zy), h-=y if (ok=1) this.SaveBitmapToFile(0, hBM, x-zx, y-zy, w, h) else if (ok=2) { f:=FileSelect("S18", A_Desktop "\1.bmp", "SaveAs", "Image (*.bmp)") this.SaveBitmapToFile(f, hBM, x-zx, y-zy, w, h) } DllCall("DeleteObject", "Ptr",hBM) return [x, y, x+w-1, y+h-1] } SetCursor(cursor:="", *) { static init:=0, tab:=Map() if (!init && init:=1) { OnExit(this.SetCursor.Bind(this,"")), this.SetCursor() s:="ARROW,32512, SIZENWSE,32642, SIZENESW,32643" . ", SIZEWE,32644, SIZENS,32645, SIZEALL,32646" . ", IBEAM,32513, WAIT,32514, CROSS,32515, UPARROW,32516" . ", NO,32648, HAND,32649, APPSTARTING,32650, HELP,32651" For i,v in StrSplit(s, ",", " ") (i&1) ? (k:=v) : (tab[k]:=DllCall("CopyImage", "Ptr" , DllCall("LoadCursor", "Ptr",0, "Ptr",v, "Ptr") , "int",2, "int",0, "int",0, "int",0, "Ptr")) } if (cursor!="") && tab.Has(cursor) DllCall("SetSystemCursor", "Ptr", DllCall("CopyImage", "Ptr",tab[cursor] , "int",2, "int",0, "int",0, "int",0, "Ptr"), "int",32512) else DllCall("SystemParametersInfo", "int",0x57, "int",0, "Ptr",0, "int",0) } BitmapFromScreen(&x:=0, &y:=0, &w:=0, &h:=0 , ScreenShot:=1, &zx:=0, &zy:=0, &zw:=0, &zh:=0) { bits:=this.GetBitsFromScreen(&x,&y,&w,&h,ScreenShot,&zx,&zy,&zw,&zh) if (w<1 || h<1 || !bits.hBM) return hBM:=this.CreateDIBSection(w, h) this.CopyHBM(hBM, 0, 0, bits.hBM, x-zx, y-zy, w, h, 1) return hBM } ; 快速保存截图为BMP文件,可用于调试 ; 如果 file = 0 或 "" ,会保存到剪贴板 SavePic(file:=0, x1:=0, y1:=0, x2:=0, y2:=0, ScreenShot:=1) { x1:=this.Floor(x1), y1:=this.Floor(y1), x2:=this.Floor(x2), y2:=this.Floor(y2) if (x1=0 && y1=0 && x2=0 && y2=0) n:=150000, x:=y:=-n, w:=h:=2*n else x:=Min(x1,x2), y:=Min(y1,y2), w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+1 hBM:=this.BitmapFromScreen(&x, &y, &w, &h, ScreenShot) this.SaveBitmapToFile(file, hBM) DllCall("DeleteObject", "Ptr",hBM) } ; 保存图像到文件,如果 file = 0 或者 "",保存到剪贴板 ; 参数可以是位图句柄或者文件路径,例如: "c:\a.bmp" SaveBitmapToFile(file, hBM_or_file, x:=0, y:=0, w:=0, h:=0) { if IsNumber(hBM_or_file) hBM_or_file:="HBITMAP:*" hBM_or_file if !hBM:=DllCall("CopyImage", "Ptr",LoadPicture(hBM_or_file) , "int",0, "int",0, "int",0, "uint",0x2008) return if (file) || (w!=0 && h!=0) { (w=0 || h=0) && this.GetBitmapWH(hBM, &w, &h) hBM2:=this.CreateDIBSection(w, -h, bpp:=(file ? 24 : 32)) this.CopyHBM(hBM2, 0, 0, hBM, x, y, w, h) DllCall("DeleteObject", "Ptr",hBM), hBM:=hBM2 } dib:=Buffer(dib_size:=(A_PtrSize=8 ? 104:84)) , DllCall("GetObject", "Ptr",hBM, "int",dib_size, "Ptr",dib) , pbi:=dib.Ptr+(bitmap_size:=A_PtrSize=8 ? 32:24) , size:=NumGet(pbi+20, "uint"), pBits:=NumGet(pbi-A_PtrSize, "Ptr") if (!file) { hdib:=DllCall("GlobalAlloc", "uint",2, "Ptr",40+size, "Ptr") pdib:=DllCall("GlobalLock", "Ptr",hdib, "Ptr") DllCall("RtlMoveMemory", "Ptr",pdib, "Ptr",pbi, "Ptr",40) DllCall("RtlMoveMemory", "Ptr",pdib+40, "Ptr",pBits, "Ptr",size) DllCall("GlobalUnlock", "Ptr",hdib) DllCall("OpenClipboard", "Ptr",0) DllCall("EmptyClipboard") if !DllCall("SetClipboardData", "uint",8, "Ptr",hdib) DllCall("GlobalFree", "Ptr",hdib) DllCall("CloseClipboard") } else { if InStr(file,"\") && !FileExist(dir:=RegExReplace(file,"[^\\]*$")) Try DirCreate(dir) bf:=Buffer(14, 0), NumPut("short", 0x4D42, bf) NumPut("uint", 54+size, bf, 2), NumPut("uint", 54, bf, 10) f:=FileOpen(file, "w"), f.RawWrite(bf, 14) , f.RawWrite(pbi+0, 40), f.RawWrite(pBits+0, size), f.Close() } DllCall("DeleteObject", "Ptr",hBM) } ; 显示保存的图像 ShowPic(file:="", show:=1, &x:="", &y:="", &w:="", &h:="") { if (file="") { this.ShowScreenShot() return } if !(hBM:=LoadPicture(file)) return this.GetBitmapWH(hBM, &w, &h) this.GetBitsFromScreen(,,,,0,&x,&y) bits:=this.GetBitsFromScreen(&x,&y,&w,&h,0) this.CopyHBM(bits.hBM, 0, 0, hBM, 0, 0, w, h) DllCall("DeleteObject", "Ptr",hBM) if (show) this.ShowScreenShot(x, y, x+w-1, y+h-1, 0) } ; 显示内存中的屏幕截图用于调试 ShowScreenShot(x1:=0, y1:=0, x2:=0, y2:=0, ScreenShot:=1) { static hPic, oldx, oldy, oldw, oldh, FindText_Screen:="" x1:=this.Floor(x1), y1:=this.Floor(y1), x2:=this.Floor(x2), y2:=this.Floor(y2) if (x1=0 && y1=0 && x2=0 && y2=0) { if (FindText_Screen) FindText_Screen.Destroy(), FindText_Screen:="" return } x:=Min(x1,x2), y:=Min(y1,y2), w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+1 if !hBM:=this.BitmapFromScreen(&x,&y,&w,&h,ScreenShot) return ;--------------- if (!FindText_Screen) { FindText_Screen:=_Gui:=Gui() ; WS_EX_NOACTIVATE:=0x08000000 _Gui.Opt "+AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000" _Gui.Name:="FindText_Screen" _Gui.MarginX:=0, _Gui.MarginY:=0 id:=_Gui.Add("Pic", "w" w " h" h), hPic:=id.Hwnd _Gui.Title:="Show Pic" _Gui.Show "NA x" x " y" y " w" w " h" h oldx:=x, oldy:=y, oldw:=w, oldh:=h } else if (oldx!=x || oldy!=y || oldw!=w || oldh!=h) { if (oldw!=w || oldh!=h) FindText_Screen[hPic].Move(,, w, h) FindText_Screen.Show "NA x" x " y" y " w" w " h" h oldx:=x, oldy:=y, oldw:=w, oldh:=h } this.BitmapToWindow(hPic, 0, 0, hBM, 0, 0, w, h) DllCall("DeleteObject", "Ptr",hBM) } BitmapToWindow(hwnd, x1, y1, hBM, x2, y2, w, h) { mDC:=DllCall("CreateCompatibleDC", "Ptr",0, "Ptr") oBM:=DllCall("SelectObject", "Ptr",mDC, "Ptr",hBM, "Ptr") hDC:=DllCall("GetDC", "Ptr",hwnd, "Ptr") DllCall("BitBlt", "Ptr",hDC, "int",x1, "int",y1, "int",w, "int",h , "Ptr",mDC, "int",x2, "int",y2, "uint",0xCC0020) DllCall("ReleaseDC", "Ptr",hwnd, "Ptr",hDC) DllCall("SelectObject", "Ptr",mDC, "Ptr",oBM) DllCall("DeleteDC", "Ptr",mDC) } ; 快速获取屏幕图像的搜索文本数据 GetTextFromScreen(x1, y1, x2, y2, Threshold:="" , ScreenShot:=1, &rx:="", &ry:="", cut:=1) { x:=Min(x1,x2), y:=Min(y1,y2), w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+1 bits:=this.GetBitsFromScreen(&x,&y,&w,&h,ScreenShot,&zx,&zy) Scan0:=bits.Scan0, Stride:=bits.Stride if (w<1 || h<1 || !Scan0) { return } ListLines (lls:=A_ListLines)?0:0 gray:=Map(), gray.Default:=0 Loop h + 0*(j:=y-zy-1)*(k:=0) Loop w + 0*(i:=x-zx-1)*(j++) c:=NumGet(Scan0+j*Stride+(++i)*4,"uint") , gray[++k]:=(((c>>16)&0xFF)*38+((c>>8)&0xFF)*75+(c&0xFF)*15)>>7 if InStr(Threshold,"**") { Threshold:=StrReplace(Threshold,"*") if (Threshold="") Threshold:=50 s:="", sw:=w, w-=2, h-=2, x++, y++ Loop h + 0*(y1:=0) Loop w + 0*(y1++) i:=y1*sw+A_Index+1, j:=gray[i]+Threshold , s.=( gray[i-1]>j || gray[i+1]>j || gray[i-sw]>j || gray[i+sw]>j || gray[i-sw-1]>j || gray[i-sw+1]>j || gray[i+sw-1]>j || gray[i+sw+1]>j ) ? "1":"0" Threshold:="**" Threshold } else { Threshold:=StrReplace(Threshold,"*") if (Threshold="") { pp:=Map(), pp.Default:=0 Loop 256 pp[A_Index-1]:=0 Loop w*h pp[gray[A_Index]]++ IP0:=IS0:=0 Loop 256 k:=A_Index-1, IP0+=k*pp[k], IS0+=pp[k] Threshold:=Floor(IP0/IS0) Loop 20 { LastThreshold:=Threshold IP1:=IS1:=0 Loop LastThreshold+1 k:=A_Index-1, IP1+=k*pp[k], IS1+=pp[k] IP2:=IP0-IP1, IS2:=IS0-IS1 if (IS1!=0 && IS2!=0) Threshold:=Floor((IP1/IS1+IP2/IS2)/2) if (Threshold=LastThreshold) Break } } s:="" Loop w*h s.=gray[A_Index]<=Threshold ? "1":"0" Threshold:="*" Threshold } ListLines lls ;-------------------- w:=Format("{:d}",w), CutUp:=CutDown:=0 if (cut=1) { re1:="(^0{" w "}|^1{" w "})" re2:="(0{" w "}$|1{" w "}$)" While (s~=re1) s:=RegExReplace(s,re1), CutUp++ While (s~=re2) s:=RegExReplace(s,re2), CutDown++ } rx:=x+w//2, ry:=y+CutUp+(h-CutUp-CutDown)//2 s:="|<>" Threshold "$" w "." this.bit2base64(s) ;-------------------- return s } ; 等待几秒钟直到屏幕图像改变,需要先调用FindText().ScreenShot() WaitChange(time:=-1, x1:=0, y1:=0, x2:=0, y2:=0) { hash:=this.GetPicHash(x1, y1, x2, y2, 0) time:=this.Floor(time), timeout:=A_TickCount+Round(time*1000) Loop { if (hash!=this.GetPicHash(x1, y1, x2, y2, 1)) return 1 if (time>=0 && A_TickCount>=timeout) Break Sleep 10 } return 0 } ; 等待屏幕图像稳定下来 WaitNotChange(time:=1, timeout:=30, x1:=0, y1:=0, x2:=0, y2:=0) { oldhash:="", timeout:=A_TickCount+Round(this.Floor(timeout)*1000) Loop { hash:=this.GetPicHash(x1, y1, x2, y2, 1), t:=A_TickCount if (hash!=oldhash) oldhash:=hash, timeout2:=t+Round(this.Floor(time)*1000) if (t>=timeout2) return 1 if (t>=timeout) return 0 Sleep 10 } } GetPicHash(x1:=0, y1:=0, x2:=0, y2:=0, ScreenShot:=1) { static init:=DllCall("LoadLibrary", "Str","ntdll", "Ptr") x1:=this.Floor(x1), y1:=this.Floor(y1), x2:=this.Floor(x2), y2:=this.Floor(y2) if (x1=0 && y1=0 && x2=0 && y2=0) n:=150000, x:=y:=-n, w:=h:=2*n else x:=Min(x1,x2), y:=Min(y1,y2), w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+1 bits:=this.GetBitsFromScreen(&x,&y,&w,&h,ScreenShot,&zx,&zy), x-=zx, y-=zy if (w<1 || h<1 || !bits.Scan0) return 0 hash:=0, Stride:=bits.Stride, p:=bits.Scan0+(y-1)*Stride+x*4, w*=4 Loop h hash:=(hash*31+DllCall("ntdll\RtlComputeCrc32", "uint",0 , "Ptr",p+=Stride, "uint",w, "uint"))&0xFFFFFFFF return hash } WindowToScreen(&x, &y, x1, y1, id:="") { if (!id) id:=WinGetID("A") rect:=Buffer(16, 0) , DllCall("GetWindowRect", "Ptr",id, "Ptr",rect) , x:=x1+NumGet(rect,"int"), y:=y1+NumGet(rect,4,"int") } ScreenToWindow(&x, &y, x1, y1, id:="") { this.WindowToScreen(&dx, &dy, 0, 0, id), x:=x1-dx, y:=y1-dy } ClientToScreen(&x, &y, x1, y1, id:="") { if (!id) id:=WinGetID("A") pt:=Buffer(8, 0), NumPut("int64", 0, pt) , DllCall("ClientToScreen", "Ptr",id, "Ptr",pt) , x:=x1+NumGet(pt,"int"), y:=y1+NumGet(pt,4,"int") } ScreenToClient(&x, &y, x1, y1, id:="") { this.ClientToScreen(&dx, &dy, 0, 0, id), x:=x1-dx, y:=y1-dy } ; 不像 FindText 总是使用屏幕坐标,它使用与内置命令 ; ImageSearch 一样的 CoordMode 设置的坐标模式 ; 图片文件参数可以使用 "*n *TransRRGGBB-RRGGBB-White... d:\a.bmp" ImageSearch(&rx:="", &ry:="", x1:=0, y1:=0, x2:=0, y2:=0 , ImageFile:="", ScreenShot:=1, FindAll:=0) { dx:=dy:=0 if (A_CoordModePixel="Window") this.WindowToScreen(&dx, &dy, 0, 0) else if (A_CoordModePixel="Client") this.ClientToScreen(&dx, &dy, 0, 0) text:="" Loop Parse, ImageFile, "|" if (v:=Trim(A_LoopField))!="" { text.=InStr(v,"$") ? "|" v : "|##" . (RegExMatch(v, "(^|\s)\*(\d+)\s", &r) ? Format("{:06X}", r[2]<<16|r[2]<<8|r[2]) : "000000") . (RegExMatch(v, "i)(^|\s)\*Trans([\-\w]+)\s", &r) ? "-" . Trim(r[2],"-") : "") . "$" . Trim(RegExReplace(v, "(?<=^|\s)\*\S+")) } x1:=this.Floor(x1), y1:=this.Floor(y1), x2:=this.Floor(x2), y2:=this.Floor(y2) if (x1=0 && y1=0 && x2=0 && y2=0) n:=150000, x1:=y1:=-n, x2:=y2:=n if (ok:=this.FindText(,, x1+dx, y1+dy, x2+dx, y2+dy , 0, 0, text, ScreenShot, FindAll)) { For k,v in ok ; you can use ok:=FindText().ok v.1-=dx, v.2-=dy, v.x-=dx, v.y-=dy rx:=ok[1].1, ry:=ok[1].2 return ok } else { rx:=ry:="" return 0 } } ; 不像 FindText 总是使用屏幕坐标,它使用与内置命令 ; PixelSearch 一样的 CoordMode 设置的坐标模式 ; 颜色参数可以是 "RRGGBB-DRDGDB|RRGGBB-DRDGDB", Variation 取值 0-255 PixelSearch(&rx:="", &ry:="", x1:=0, y1:=0, x2:=0, y2:=0 , ColorID:="", Variation:=0, ScreenShot:=1, FindAll:=0) { n:=this.Floor(Variation), text:=Format("##{:06X}$0/0", n<<16|n<<8|n) Loop Parse, ColorID, "|" if (v:=Trim(A_LoopField))!="" text.="/" v return this.ImageSearch(&rx, &ry, x1, y1, x2, y2, text, ScreenShot, FindAll) } ; 屏幕坐标指示的范围内的某些颜色的像素计数 ; 颜色参数可以是 "RRGGBB-DRDGDB|RRGGBB-DRDGDB", Variation 取值 0-255 PixelCount(x1:=0, y1:=0, x2:=0, y2:=0, ColorID:="", Variation:=0, ScreenShot:=1) { x1:=this.Floor(x1), y1:=this.Floor(y1), x2:=this.Floor(x2), y2:=this.Floor(y2) if (x1=0 && y1=0 && x2=0 && y2=0) n:=150000, x:=y:=-n, w:=h:=2*n else x:=Min(x1,x2), y:=Min(y1,y2), w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+1 bits:=this.GetBitsFromScreen(&x,&y,&w,&h,ScreenShot,&zx,&zy), x-=zx, y-=zy sum:=0, s1:=Buffer(4), s0:=Buffer(4) , ini:={ bits:bits, ss:0, s1:s1.Ptr, s0:s0.Ptr , err1:0, err0:0, allpos_max:0, zoomW:1, zoomH:1 } , n:=this.Floor(Variation), text:=Format("##{:06X}$0/0", n<<16|n<<8|n) Loop Parse, ColorID, "|" if (v:=Trim(A_LoopField))!="" text.="/" v if (w>0 && h>0 && bits.Scan0) && IsObject(j:=this.PicInfo(text)) sum:=this.PicFind(ini, j, 1, x, y, w, h, 0) return sum } Click(x:="", y:="", other1:="", other2:="", GoBack:=0) { CoordMode "Mouse", (bak:=A_CoordModeMouse)?"Screen":"Screen" if GoBack MouseGetPos &oldx, &oldy MouseMove x, y, 0 Click x "," y "," other1 "," other2 if GoBack MouseMove oldx, oldy, 0 CoordMode "Mouse", bak } ; 使用 ControlClick 代替 Click, 使用屏幕坐标,如果用于后台请提供 hwnd ControlClick(x, y, WhichButton:="", ClickCount:=1, Opt:="", hwnd:="") { if !hwnd hwnd:=DllCall("WindowFromPoint", "int64",y<<32|x&0xFFFFFFFF, "Ptr") pt:=Buffer(8,0), ScreenX:=x, ScreenY:=y Loop { NumPut("int64",0,pt), DllCall("ClientToScreen", "Ptr",hwnd, "Ptr",pt) , x:=ScreenX-NumGet(pt,"int"), y:=ScreenY-NumGet(pt,4,"int") , id:=DllCall("ChildWindowFromPoint", "Ptr",hwnd, "int64",y<<32|x, "Ptr") if (!id || id=hwnd) Break else hwnd:=id } DetectHiddenWindows (bak:=A_DetectHiddenWindows)?1:1 PostMessage 0x200, 0, y<<16|x, hwnd ; WM_MOUSEMOVE SetControlDelay -1 ControlClick "x" x " y" y, hwnd,, WhichButton, ClickCount, "NA Pos " Opt DetectHiddenWindows bak } ; 动态运行AHK代码作为新线程 Class Thread { __New(args*) { this.pid:=this.Exec(args*) } __Delete() { ProcessClose(this.pid) } Exec(s, Ahk:="", args:="") { Ahk:=Ahk ? Ahk : A_IsCompiled ? A_ScriptFullPath : A_AhkPath add:=A_IsCompiled ? " /script " : "" s:="`nDllCall(`"SetWindowText`",`"Ptr`",A_ScriptHwnd,`"Str`",`"`")`n" . "`n`n" . s, s:=RegExReplace(s, "\R", "`r`n") Try { shell:=ComObject("WScript.Shell") oExec:=shell.Exec("`"" Ahk "`"" add " /force /CP0 * " args) oExec.StdIn.Write(s) oExec.StdIn.Close(), pid:=oExec.ProcessID } Catch { f:=A_Temp "\~ahk.tmp" s:="`r`nTry FileDelete(`"" f "`")`r`n" s Try FileDelete(f) FileAppend(s, f) r:=this.Clear.Bind(this) SetTimer(r, -3000) Run "`"" Ahk "`"" add " /force /CP0 `"" f "`" " args,,, &pid } return pid } Clear() { Try FileDelete(A_Temp "\~ahk.tmp") SetTimer(,0) } } ; FindText().QPC() 用法类似于 A_TickCount QPC() { static f:=0, c:=DllCall("QueryPerformanceFrequency", "Int*",&f)+(f/=1000) return (!DllCall("QueryPerformanceCounter", "Int64*",&c))*0+(c/f) } ; FindText().ToolTip() 用法类似于 ToolTip ToolTip(s:="", x:="", y:="", num:=1, arg:="") { static ini:=Map(), tip:=Map(), timer:=Map() f:="ToolTip_" . this.Floor(num) if (s="") { ini[f]:="" Try tip[f].Destroy() return } ;----------------- r1:=A_CoordModeToolTip r2:=A_CoordModeMouse CoordMode "Mouse", "Screen" MouseGetPos &x1, &y1 CoordMode "Mouse", r1 MouseGetPos &x2, &y2 CoordMode "Mouse", r2 (x!="" && x:="x" (this.Floor(x)+x1-x2)) , (y!="" && y:="y" (this.Floor(y)+y1-y2)) , (x="" && y="" && x:="x" (x1+16) " y" (y1+16)) ;----------------- (!IsObject(arg) && arg:={}) bgcolor:=arg.HasOwnProp("bgcolor") ? arg.bgcolor : "FAFBFC" color:=arg.HasOwnProp("color") ? arg.color : "Black" font:=arg.HasOwnProp("font") ? arg.font : "Consolas" size:=arg.HasOwnProp("size") ? arg.size : "10" bold:=arg.HasOwnProp("bold") ? arg.bold : "" trans:=arg.HasOwnProp("trans") ? arg.trans & 255 : 255 timeout:=arg.HasOwnProp("timeout") ? arg.timeout : "" ;----------------- r:=bgcolor "|" color "|" font "|" size "|" bold "|" trans "|" s if (!ini.Has(f) || ini[f]!=r) { ini[f]:=r Try tip[f].Destroy() tip[f]:=_Gui:=Gui() ; WS_EX_LAYERED:=0x80000, WS_EX_TRANSPARENT:=0x20 _Gui.Opt "+AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x80020" _Gui.MarginX:=2, _Gui.MarginY:=2 _Gui.BackColor:=bgcolor _Gui.SetFont "c" color " s" size " " bold, font _Gui.Add "Text",, s _Gui.Title:=f _Gui.Show "Hide" ;------------------ DetectHiddenWindows (bak:=A_DetectHiddenWindows)?1:1 WinSetTransparent(trans, _Gui.Hwnd) DetectHiddenWindows bak } else _Gui:=tip[f] _Gui.Opt "+AlwaysOnTop" _Gui.Show "NA " x " " y if (timeout) { (!timer.Has(f) && timer[f]:=this.ToolTip.Bind(this,"","","",num)) SetTimer(timer[f], -Round(Abs(this.Floor(timeout)*1000))-1) } } ; FindText().ObjView() 查看对象的值用于调试 ObjView(obj, keyname:="") { static Gui_DeBug:="" if IsObject(obj) { s:="" For k,v in (HasMethod(obj,"__Enum") ? obj : obj.OwnProps()) s.=this.ObjView(v, keyname "[" (k is Number ? k : "`"" k "`"") "]") } else s:=keyname ": " (obj is Number ? obj : "`"" obj "`"") "`n" if (keyname!="") return s ;------------------ Try Gui_DeBug.Destroy() Gui_DeBug:=_Gui:=Gui() _Gui.Opt "+LastFound +AlwaysOnTop" _Gui.Add("Button", "y270 w350 Default", "OK").OnEvent("Click", (*) => WinHide()) _Gui.Add "Edit", "xp y10 w350 h250 -Wrap -WantReturn" _Gui["Edit1"].Value:=s _Gui.Title:="Debug view object values" _Gui.Show DetectHiddenWindows(0) WinWaitClose "ahk_id " WinExist() _Gui.Destroy } EditScroll(hEdit, regex:="", line:=0, pos:=0) { s:=ControlGetText(hEdit) pos:=(regex!="") ? InStr(SubStr(s,1,s~=regex),"`n",0,-1) : (line>1) ? InStr(s,"`n",0,1,line-1) : pos SendMessage 0xB1, pos, pos, hEdit SendMessage 0xB7,,, hEdit } ; 从编译后的程序中获取脚本 GetScript() ; thanks TAC109 { if (!A_IsCompiled) return For i,ahk in ["#1", ">AUTOHOTKEY SCRIPT<"] if (rc:=DllCall("FindResource", "Ptr",0, "Str",ahk, "Ptr",10, "Ptr")) && (sz:=DllCall("SizeofResource", "Ptr",0, "Ptr",rc, "Uint")) && (pt:=DllCall("LoadResource", "Ptr",0, "Ptr",rc, "Ptr")) && (pt:=DllCall("LockResource", "Ptr",pt, "Ptr")) && (DllCall("VirtualProtect", "Ptr",pt, "Ptr",sz, "UInt",0x4, "UInt*",0)) && (InStr(StrGet(pt, 20, "utf-8"), "