595076941@qq.com

某网页单据打印辅助AutoHotkey v1.0脚本,本来打印单据需要用鼠标点击多次,

 

  某网页单据打印辅助AutoHotkey v1.0脚本,本来打印单据需要用鼠标点击多次

 

,

 

 

 

; 某网页单据打印辅助AutoHotkey v1.0脚本,本来打印单据需要用鼠标点击多次,
; 运行此脚本之后只需在输入完毕后按快捷键热键<F4>
; 为了便于寻找快捷键位置,我在F4键的键帽上贴了黄色贴纸
; 可用 AHKInfo 1.3.5 或者 AhkSpy 等窗口信息探测工具来获取鼠标光标的当前位置
; 2025-03-31

; 由于"【函数】FindText中文版- 屏幕抓字生成字库工具与找字函数"比较复杂,创建和使用脚本麻烦
; 所以我使用 MouseMove、Click和Sleep这3个AHK原生语句来制作此脚本,
; 这3个内置函数语句的优点是性能速度快,效率高,稳定可靠(有时候FindText在不同电脑上会找不到位图),
; 这3个内置函数语句的缺点是环境适应性差,不同显示器,不同显卡,不同电脑,不同分辨率下的全局坐标可能会不同,需要重写代码.
; 这3个内置函数语句的缺点是需要窗口最大化,窗口位置固定,否则有可能点击不到网页中的按钮.
; 我这边网页平台系统只要多次鼠标点击写到1个快捷键热键就可以了,只要能够长期稳定使用就可以了,要求不高.
; 所以我也不想再根据屏幕分辨率 DPI 缩放修正通用全局坐标了,不折腾了,只要一个电脑上能用就好了,
; 并且我这个Windows 10 企业版 LTSC 电脑用Acronis True Image 2021 在USM v5下备份了系统分区,
; 并且正确安装设置了Deep Freeze Standard冰点还原精灵保护电脑第1分区系统分区C盘.

; xx=% "x" 397*A_ScreenDPI//96
; yy=" y" 63*A_ScreenDPI//96
; MouseMove,xx,yy

;;;;;;;点击窗口内指定坐标 【DPI缩放通用坐标修正】
; ControlClick, % "x" 397*A_ScreenDPI//96 " y" 63*A_ScreenDPI//96, D:\APP\F4\F4.ahk * SciTE4AutoHotkey ahk_class SciTEWindow

; FindText 深度教程 v1.2
; https://www.autoahk.com/archives/41636
; https://www.autoahk.com/archives/47248
; https://www.autoahk.com/archives/39249
; https://www.autoahk.com/archives/28493

; 设置每次鼠标移动或点击后自动的延时.
SetMouseDelay,0
SetKeyDelay,0
SetControlDelay,0
SetWinDelay,0
; 把 Click, MouseMove, MouseClick 放置在绝对的屏幕坐标上.
CoordMode, Mouse, Screen
; 设置脚本可以 "看见" 隐藏的窗口.
DetectHiddenWindows, On
; 按快捷键 Ctrl + F4 立即退出此脚本
Hotkey,^F4,ExitPrintHMF
Hotkey,F4,PrintHMF
return
ExitPrintHMF()
{
	ExitApp
}
PrintHMF()
{
  
  
		;第1步:点击 提交保存网页按钮
	;第2步:点击 打印预览网页按钮
	;第3步:点击 打印网页按钮
	;第4步:点击 确定对话框按钮
	;第5步:点击 关闭网页按钮
	;第6步:点击 取消网页按钮
	;第7步:点击 收费方式网页下拉列表单选框
	;第8步:点击 微信
	;第9步:点击 位置/姓名 搜索框网页控件
	;第10步:发送 Ctrl + A 全选搜索框中原有的内容,为下一次筛选搜索过滤记录行做好输入准备。

; #Include <FindText>

; t1:=A_TickCount, Text:=X:=Y:=""

Text:=X:=Y:=""

; 第1步:点击"提交保存"网页中的按钮
Loop,9
{

Text:="|<>*178$56.r0Tnzc1yzxrbyzmyTDw0100AjY00rSTSzPtxzwE7bba0S06DzlsFgbDl409AoTDntxyztDo0803NUz7xsQDjqPzVzQ3nvx0zX7qGQyw707yAQnADU"

if (ok:=FindText(X, Y, 1030-150000, 1008-150000, 1030+150000, 1008+150000, 0, 0, Text))
{
  FindText().Click(X, Y, "R")
  Break
}
}
; 第2步:点击"打印预览"成功提示对话框按钮
Text:="|<>*182$57.vzz00004bzM03CSQwY10Qttm7bY3zTbDCMU4U7vws1k0wzyT3bDCM4a07lwttn0YnwsTbDCNYaNbvwtVnAYn4zTb10tsTkwvwttzC9sbAQ7zDV7UQ1U"

if (ok:=FindText(X, Y, 1068-150000, 688-150000, 1068+150000, 688+150000, 0, 0, Text))
{
  ; FindText().Click(X, Y, "R")
}

; 第3步:点击"打印"预览网页中的图标按钮
Text:="|<>*133$16.1zk810jc40ULrW0JTyi05TztU0e03jzuE1Ezy000000067vX28+8UUXu28+8UUW+2/88kUU2C0+"

if (ok:=FindText(X, Y, 457-150000, 41-150000, 457+150000, 41+150000, 0, 0, Text))
{
  ; FindText().Click(X, Y, "R")
}

; 第4步:点击"确定"打印对话框按钮
Text:="|<>*149$70.Dzzzzzzzzzzl00000000000c00000000001U000104000060007bU80000M0004WTz0001U000EF0400060002Dk00000M000CdTz0001U001fw2000060002eF80000M000+z4y0001U000uYG000060002eGc0000M00013Fz0001U0000000000600000000000I00000000002Dzzzzzzzzzzm"

if (ok:=FindText(X, Y, 1091-150000, 537-150000, 1091+150000, 537+150000, 0, 0, Text))
{
  ; FindText().Click(X, Y, "R")
}

; 第5步:点击"关闭"预览网页中的图标按钮
Text:="|<>*143$23.0y002200Dzy0E040V08170E2T0U48108E20EzY0U08100E3zzU000000000002240284z0002zsV4412882zTzY8UU8l2UGW8Ud4UV6C0m1s"

if (ok:=FindText(X, Y, 496-150000, 41-150000, 496+150000, 41+150000, 0, 0, Text))
{
  FindText().Click(X, Y, "R")
}

; 第6步:点击"取消"成功提示对话框按钮
Text:="|<>*183$27.zU8aGTsqmHF2KXu97zHFAUPvMo3H+0zuNkY3LY4zzNlY33nAUMQB4SU"

if (ok:=FindText(X, Y, 1152-150000, 688-150000, 1152+150000, 688+150000, 0, 0, Text))
{
  ; FindText().Click(X, Y, "R")
}

; 第7步:点击"现金"收费方式下拉列表单选框
Text:="|<>*154$28.zzU40W21c298AM8YX0FuGrym98108gU40WkDzWX410AIH4n6F6K0ktzzU"

if (ok:=FindText(X, Y, 415-150000, 522-150000, 415+150000, 522+150000, 0, 0, Text))
{
  ; FindText().Click(X, Y, "R")
}

; 第8步:点击"微信"收费方式下拉列表单选框选项
Text:="|<>*189$28.4W120ec7zoywU0Q6aTsjuM061ebyPnW03hA9zWYEY2+P2E8dO9zX14Y2U"

if (ok:=FindText(X, Y, 415-150000, 604-150000, 415+150000, 604+150000, 0, 0, Text))
{
  ; FindText().Click(X, Y, "R")
}

; 第9步:点击"位置"搜索输入框
Text:="|<>*230$54.zy8K3zk0gU08K30E0acAzrnznzzgM8K30E0UXk8K001yaVUDrjzxaaXkQK1U1awaMsK101ysgA/rlzlaNs48K00E2tU08K00HxfzzsK0TU36U"

if (ok:=FindText(X, Y, 430-150000, 238-150000, 430+150000, 238+150000, 0, 0, Text))
{
  ; FindText().Click(X, Y, "R")
}

; 第10步:点击"位置"搜索输入框
	;Sleep,5
; Send,^a
; Sleep,5
}
return

;/*
;===========================================
;  FindText - 屏幕抓字生成字库工具与找字函数
;  https://www.autohotkey.com/boards/viewtopic.php?f=6&t=17834
;
;  脚本作者 : FeiYue
;  最新版本 : 10.0
;  更新时间 : 2024-10-06
;
;  用法:  (需要最新版本 AHK v1.1.34+)
;  1. 将本脚本保存为“FindText.ahk”并复制到AHK执行程序的Lib子目录中(手动建立目录)
;  2. 抓图并生成调用FindText()的代码
;     2.1 方式一:直接点击“抓图”按钮
;     2.2 方式二:先设定截屏热键,使用热键截屏,再点击“截屏抓图”按钮
;  3. 测试一下调用的代码是否成功:直接点击“测试”按钮
;  4. 复制调用的代码到自己的脚本中
;     4.1 方式一:打勾“附加FindText()函数”的选框,然后点击“复制”按钮(不推荐)
;     4.2 方式二:取消“附加FindText()函数”的选框,然后点击“复制”按钮,
;         然后粘贴到自己的脚本中,然后在自己的脚本开头加上一行:
;         #Include <FindText>  ; Lib目录中必须有FindText.ahk
;  5. 多色查找模式可以一定程度上适应图像的放大缩小,常用于游戏中找图
;  6. 这个库还可以用于快速截屏、获取颜色、写入颜色、编辑后另存图片
;  7. 如果要调用FindTextClass类中的函数,请用无参数的FindText()获取类实例对象
;
;===========================================
;*/


if (!A_IsCompiled && A_LineFile=A_ScriptFullPath)
  FindText().Gui("Show")


;===== 复制下面的函数和类到你的代码中仅仅一次 =====


FindText(ByRef x:="FindTextClass", ByRef y:="", args*)
{
  static init, obj
  if !VarSetCapacity(init) && (init:="1")
    obj:=new FindTextClass()
  return (x=="FindTextClass" && !args.Length()) ? obj : obj.FindText(x, y, args*)
}

Class FindTextClass
{  ;// Class Begin

Floor(i)
{
  if i is number
    return i+0
  else return 0
}

__New()
{
  this.bits:={ Scan0: 0, hBM: 0, oldzw: 0, oldzh: 0 }
  this.bind:={ id: 0, mode: 0, oldStyle: 0 }
  this.Lib:=[]
  this.Cursor:=0
}

__Delete()
{
  if (this.bits.hBM)
    Try DllCall("DeleteObject", "Ptr",this.bits.hBM)
}

New()
{
  return new FindTextClass()
}

help()
{
return "
(
;--------------------------------
;  FindText - 屏幕找字函数
;  版本 : 10.0  (2024-10-06)
;--------------------------------
;  返回变量:=FindText(
;      OutputX --> 保存返回的X坐标的变量名称
;    , OutputY --> 保存返回的Y坐标的变量名称
;    , X1 --> 查找范围的左上角X坐标
;    , Y1 --> 查找范围的左上角Y坐标
;    , X2 --> 查找范围的右下角X坐标
;    , Y2 --> 查找范围的右下角Y坐标
;    , err1 --> 文字的黑点容错百分率(0.1=10%)
;    , err0 --> 背景的白点容错百分率(0.1=10%)
;      设置 err1<0 或 err0<0 可以打开左右膨胀算法
;      忽略文字线条的轻微错位,此时容错值应该非常小
;      在找图模式中,err0 可以设置要跳过的行列数,加快速度
;    , Text --> 由工具生成的查找图像的数据,可以一次查找多个,用“|”分隔
;    , ScreenShot --> 是否截屏,为0则使用上一次的截屏数据
;    , FindAll --> 是否搜索所有位置,为0则找到一个位置就返回
;    , JoinText --> 如果想组合查找,可以为1,或者是要查找单词的数组
;    , offsetX --> 组合图像的每个字和前一个字的最大横向间隔
;    , offsetY --> 组合图像的每个字和前一个字的最大高低间隔
;    , dir --> 查找的方向,有上、下、左、右、中心9种
;      默认 dir=0,这种返回的结果将按最小误差排序,
;      即使设置了较大的容错,第一个结果也是误差最小的
;    , zoomW --> 图像宽度的缩放百分率(1.0=100%)
;    , zoomH --> 图像高度的缩放百分率(1.0=100%)
;  )
;
;  返回变量 --> 如果没找到结果会返回0。否则返回一个二级数组,
;      第一级是每个结果对象,第二级是结果对象的具体信息对象:
;      { 1:左上角X, 2:左上角Y, 3:图像宽度W, 4:图像高度H
;        , x:中心点X, y:中心点Y, id:图像识别文本 }
;  所有坐标都是相对于屏幕,颜色使用RGB格式
;  所有 RRGGBB 可以使用 Black、White、Red、Green、Blue 代替,
;  所有 DRDGDB 可以使用相似度 1.0(100%) 代替,它是浮点数
;
;  如果 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) ; 无限等待等图像消失
;
;  <FindMultiColor> 或 <FindColor> : 找色 是仅有一个点的 多点找色
;  Text:='|<>##DRDGDB $ 0/0/RRGGBB1-DRDGDB1/RRGGBB2, xn/yn/-RRGGBB3/RRGGBB4, ...'
;  '##'之后的颜色 (0xDRDGDB) 是所有颜色的默认偏色(各个分量允许的变化值)
;  初始点 (0,0) 匹配 0xRRGGBB1(+/-0xDRDGDB1) 或者 0xRRGGBB2(+/-0xDRDGDB),
;  点 (xn,yn) 匹配 排除 0xRRGGBB3(+/-0xDRDGDB) 和排除 0xRRGGBB4(+/-0xDRDGDB)
;  点坐标后面以 '-' 开头表示要排除后面的所有颜色,其他颜色都匹配
;  每个点最多允许匹配10组颜色 (xn/yn/RRGGBB1/.../RRGGBB10)
;
;  <FindShape> : 类似于 FindMultiColor,仅是把具体颜色替换为
;  这一点的颜色是否与第一点的颜色是否相似
;  Text:='|<>##DRDGDB $ 0/0/1, x1/y1/0, x2/y2/1, xn/yn/0, ...'
;
;  <FindPic> : Text 参数需要手动输入
;  Text:='|<>##DRDGDB/RRGGBB1-DRDGDB1/RRGGBB2... $ d:\a.bmp'
;  '##'之后的颜色 (0xDRDGDB) 是所有颜色的默认偏色(各个分量允许的变化值)
;  这个 0xRRGGBB1(+/-0xDRDGDB1) 和 0xRRGGBB2(+/-0xDRDGDB)... 都是透明色
;
;--------------------------------
)"
}

FindText(ByRef OutputX:="", ByRef 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:=0, zoomW:=1, zoomH:=1)
{
  local
  if (OutputX ~= "i)^\s*wait[10]?\s*$")
  {
    found:=!InStr(OutputX,"0"), time:=this.Floor(OutputY)
    , timeout:=A_TickCount+Round(time*1000), OutputX:=""
    Loop
    {
      ok:=this.FindText(,, x1, y1, x2, y2, err1, err0, text, ScreenShot
        , FindAll, JoinText, offsetX, offsetY, dir, zoomW, zoomH)
      if (found && ok)
      {
        OutputX:=ok[1].x, OutputY:=ok[1].y
        return ok
      }
      if (!found && !ok)
        return 1
      if (time>=0 && A_TickCount>=timeout)
        Break
      Sleep 50
    }
    return 0
  }
  SetBatchLines % (bch:=A_BatchLines)?"-1":"-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
  , 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)
  {
    SetBatchLines % bch
    return 0
  }
  arr:=[], info2:=[], k:=0, s:=""
  , mode:=(IsObject(JoinText) ? 2 : JoinText ? 1 : 0)
  For i,j in info
  {
    k:=Max(k, (j[7]=5 && j[8]!=2 ? j[9] : j[2]*j[3]))
    if (mode)
      v:=(mode=1 ? i : j[10]) . "", s.="|" v
      , (v!="") && ((!info2.HasKey(v) && info2[v]:=[]), info2[v].Push(j))
  }
  sx:=x, sy:=y, sw:=w, sh:=h, (mode=1 && JoinText:=[s])
  , allpos_max:=(FindAll || JoinText ? 10000:1)
  , VarSetCapacity(s1,k*4), VarSetCapacity(s0,k*4)
  , VarSetCapacity(ss,sw*(sh+3)), VarSetCapacity(allpos,allpos_max*8)
  , ini:={ sx:sx, sy:sy, sw:sw, sh:sh, zx:zx, zy:zy
  , mode:mode, bits:bits, ss:&ss, s1:&s1, s0:&s0
  , allpos:&allpos, allpos_max:allpos_max
  , err1:err1, err0:err0, 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)
    {
      For i,j in info
      Loop % this.PicFind(ini, j, dir, sx, sy, sw, sh)
      {
        v:=NumGet(allpos,4*A_Index-4,"uint"), x:=(v&0xFFFF)+zx, y:=(v>>16)+zy
        , w:=Floor(j[2]*zoomW), h:=Floor(j[3]*zoomH)
        , arr.Push({1:x, 2:y, 3:w, 4:h, x:x+w//2, y:y+h//2, id:j[10]})
        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
  }
  SetBatchLines % bch
  if (arr.Length())
  {
    OutputX:=arr[1].x, OutputY:=arr[1].y, this.ok:=arr
    return arr
  }
  return 0
}

; the join text object use [ "abc", "xyz", "a1|a2|a3" ]

JoinText(arr, ini, info2, text, index, offsetX, offsetY
  , FindAll, dir, minX, minY, maxY, sx, sy, sw, sh)
{
  local
  if !(Len:=text.Length()) || !info2.HasKey(key:=text[index])
    return 0
  zoomW:=ini.zoomW, zoomH:=ini.zoomH, mode:=ini.mode
  For i,j in info2[key]
  if (mode!=2 || key==j[10])
  Loop % ok:=this.PicFind(ini, j, dir, sx, sy, (index=1 ? sw
  : Min(sx+offsetX+Floor(j[2]*zoomW),ini.sx+ini.sw)-sx), sh)
  {
    if (A_Index=1)
    {
      pos:=[], p:=ini.allpos-4
      Loop % ok
        pos.Push(NumGet(0|p+=4,"uint"))
    }
    v:=pos[A_Index], x:=v&0xFFFF, y:=v>>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 (index<Len)
    {
      sy1:=Max(minY1-offsetY, ini.sy)
      , sh1:=Min(maxY1+offsetY, ini.sy+ini.sh)-sy1
      if this.JoinText(arr, ini, info2, text, index+1, offsetX, offsetY
      , FindAll, 5, minX, minY1, maxY1, sx1, sy1, 0, sh1)
      && (index>1 || !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)
{
  local
  static init, MyFunc
  if !VarSetCapacity(init) && (init:="1")
  {
    x32:="VVdWU4HsmAAAAIuEJNQAAAADhCTMAAAAi5wk@AAAAIO8JKwAAAAFiUQkIIuEJPgA"
    . "AACNBJiJRCQ0D4RKBgAAi4Qk6AAAAIXAD45ADwAAiXwkEIu8JOQAAAAx7ccEJAAA"
    . "AADHRCQIAAAAAMdEJBQAAAAAx0QkDAAAAACNtgAAAACLhCTgAAAAi0wkDDH2MdsB"
    . "yIX@iUQkBH896ZAAAABmkA+vhCTMAAAAicGJ8Jn3@wHBi0QkBIA8GDF0TIuEJNwA"
    . "AACDwwEDtCQAAQAAiQyog8UBOd90VIsEJJn3vCToAAAAg7wkrAAAAAR1tQ+vhCTA"
    . "AAAAicGJ8Jn3@40MgYtEJASAPBgxdbSLRCQUi5Qk2AAAAIPDAQO0JAABAACJDIKD"
    . "wAE534lEJBR1rAF8JAyDRCQIAYu0JAQBAACLRCQIATQkOYQk6AAAAA+FMv@@@4tE"
    . "JBSLfCQQD6+EJOwAAACJbCQwwfgKiUQkKIuEJPAAAAAPr8XB+AqJRCRAg7wkrAAA"
    . "AAQPhCIGAACLhCTAAAAAi5wkxAAAAA+vhCTIAAAAjSyYi4QkzAAAAIucJMAAAAD3"
    . "2IO8JKwAAAABjQSDiUQkLA+ELwYAAIO8JKwAAAACD4Q4CAAAg7wkrAAAAAMPhLkL"
    . "AACLjCTQAAAAhckPjicBAACLhCTMAAAAi6wkzAAAAMdEJAwAAAAAx0QkEAAAAACJ"
    . "fCQYg+gBiUQkCI22AAAAAIt8JBCLtCTUAAAAMcCLXCQgAfsB94Xtif6J738X6bwA"
    . "AADGBAYEg8ABg8MBOccPhKQAAACDvCSsAAAAA3@khcAPtgsPhLoPAAAPtlP@iVQk"
    . "BDlEJAgPhMIPAAAPtlMBiRQki5Qk9AAAAIXSD4SfAQAAD7bpugYAAACD7QGD@QF2"
    . "G4N8JAQBD5TCgzwkAYnVD5TCCeoPttIB0oPKBIHh@QAAAL0BAAAAdByLTCQEiywk"
    . "hckPlEQkBIXtD5TBic0PtkwkBAnNCeqDwwGIFAaDwAE5xw+FXP@@@wF8JBCJ@YNE"
    . "JAwBi0QkDDmEJNAAAAAPjwz@@@+LfCQYg7wkrAAAAAN@FouEJPQAAACFwA+VwDwB"
    . "g5wkxAAAAP+LXCQUi3QkKDHAOfOLdCRAD07YiVwkFItcJDA58w9Pw4lEJDCLhCTM"
    . "AAAAK4QkAAEAAIlEJASLhCTQAAAAK4QkBAEAAIO8JLgAAAAJiUQkCA+ExgAAAIuE"
    . "JLgAAACD6AGD+AcPh7wCAACD+AOJRCQkD463AgAAi0QkBMdEJEQAAAAAx0QkDAAA"
    . "AACJBCSLRCQIiUQkHItcJEQ5HCTHRCRMAAAAAA+MCwEAAItcJEw5XCQcD4zCDQAA"
    . "i3QkRItcJCSLBCQp8PbDAg9Exot0JEyJwotEJBwp8PbDAQ9ExoP7A4nWD0@wD0@C"
    . "iXQkGIlEJBDp3gsAAI12AA+20YPqAYP6AhnSg+ICg8IEgeH9AAAAD5TBCcqIFAbp"
    . "8v3@@4tcJASLdCQIx0QkZAAAAADHRCRgAQAAAMdEJFQAAAAAx0QkWAAAAACJ2I1W"
    . "AYk0JMHoH4lcJBzHRCQMAAAAAAHY0fiJRCQQifDB6B8B8NH4iUQkGInYg8ABicEP"
    . "r8o50A9MwoPACIlMJHyJwQ+vyImMJIAAAACLXCR8OVwkZH0Zi5wkgAAAADlcJFjH"
    . "RCRcAAAAAA+M9QQAAIuMJLgAAACFyQ+FnQIAAIuUJPgAAACF0g+EjgIAAIuEJAQB"
    . "AAAPr4QkAAEAAIP4AQ+EdgIAAIN8JAwBD46lCgAAi0QkNIucJPgAAAAx7cdEJAQA"
    . "AAAAiSwkjXgEi0QkDIPoAYlEJBCLRCQEiwwkizeLRAMEhcmJRCQIich4NotP@DnO"
    . "D4N1BQAAifqNa@zrDY12AIPqBItK@DnOcxeJCotMhQSJTIMEg+gBg@j@deS4@@@@"
    . "@4tMJDSDwAGDBCQBg8cEg0QkBASJNIGLdCQIiTSDiwQkO0QkEHWNi4QkBAEAAIus"
    . "JAABAAAPr8APr+2JRCQEi7Qk+AAAAMdEJAgAAAAAMduLRCQIiwSGiUQkEA+3+MHo"
    . "EIXbiQQkdC0xyY22AAAAAIsUjg+3win4D6@AOeh9D8HqECsUJA+v0jtUJAR8EYPB"
    . "ATnZdduLRCQQiQSeg8MBg0QkCAGLRCQIOUQkDHWiidiBxJgAAABbXl9dwlwAx0Qk"
    . "JAAAAACLRCQIx0QkRAAAAADHRCQMAAAAAIkEJItEJASJRCQc6UT9@@8xwIO8JLAA"
    . "AAACD5TAiYQkhAAAAA+EUAQAADHAg7wksAAAAAGLrCS0AAAAD5TAhe2JRCR4D4SG"
    . "CwAAi7Qk2AAAAIuUJLQAAAAx7YucJOAAAACLjCTcAAAAiXwkCI0ElolEJASNdCYA"
    . "izuDxgSDw1iDwQSJ+MHoEA+vhCQEAQAAmfe8JOgAAAAPr4QkwAAAAIkEJA+3xw+v"
    . "hCQAAQAAmfe8JOQAAACLFCSNBIKJRvyLQ6yNREUAg8UWiUH8O3QkBHWmi4QktAAA"
    . "AIm8JLAAAACLfCQIiUQkFIuEJOwAAAAPr4QktAAAAMH4ColEJCiLhCTgAAAAx0Qk"
    . "QAAAAADHRCQwAAAAAIPACIlEJFDpSfr@@4tEJAyBxJgAAABbXl9dwlwAi4QksAAA"
    . "AMHoEA+vhCQEAQAAmfe8JOgAAAAPr4QkwAAAAInBD7eEJLAAAAAPr4QkAAEAAJn3"
    . "vCTkAAAAjQSBiYQksAAAAOnt+f@@i4Qk6AAAAIu0JNAAAAAPr4Qk5AAAANGkJLQA"
    . "AAADhCTgAAAAhfaJRCRQD47z+v@@i4QkzAAAAInqi2wkUMdEJCQAAAAAx0QkOAAA"
    . "AADB4AKJRCRIMcCLnCTMAAAAhdsPjisBAACLnCS8AAAAAdMDVCRIiVwkEItcJCAD"
    . "XCQ4iVQkPAOUJLwAAACJXCQYiVQkHI12AI28JwAAAACLdCQQMds5nCS0AAAAD7ZO"
    . "AolMJAQPtk4BD7Y2iUwkCIl0JAx2W412AI28JwAAAACLRJ0Ag8MCi3yd@InCD7bM"
    . "D7bAK0QkDMHqECtMJAgPttIrVCQEgf@@@@8AiQQkdyUPr9IPr8mNFFIPr8CNFIqN"
    . "BEI5x3NGMcA5nCS0AAAAd6+JwutBif7B7hCJ8A+28A+v0g+v9jnyd92J+A+21A+v"
    . "yQ+v0jnRd86LNCSJ+A+20A+v0onwD6@GOdB3uroBAAAAuAEAAACLXCQYg0QkEASL"
    . "TCQQiBODwwE7TCQciVwkGA+FGv@@@4u0JMwAAAABdCQ4i1QkPINEJCQBA1QkLItc"
    . "JCQ5nCTQAAAAD4Ws@v@@6U34@@+LRCQQhcB4G4tcJBw52H8Ti0QkGIXAeAuLHCQ5"
    . "2A+ONwYAAItsJFSF7Q+F4AUAAINsJBgBg0QkXAGDRCRYAYt0JGA5dCRcfLiLXCRU"
    . "idiD4AEBxonYg8ABiXQkYIPgA4lEJFTpvvr@@4uEJLAAAACLjCTQAAAAxwQkAAAA"
    . "AMdEJAQAAAAAg8ABweAHiYQksAAAAIuEJMwAAADB4AKFyYlEJAwPjsz4@@+J6Ius"
    . "JLAAAACJfCQQi5QkzAAAAIXSfmaLjCS8AAAAi1wkIIu8JLwAAAADXCQEAcEDRCQM"
    . "iUQkCAHHjXYAjbwnAAAAAA+2UQIPtkEBD7Yxa8BLa9ImAcKJ8MHgBCnwAdA5xQ+X"
    . "A4PBBIPDATn5ddWLnCTMAAAAAVwkBItEJAiDBCQBA0QkLIs8JDm8JNAAAAAPhXf@"
    . "@@+LfCQQ6Qb3@@+LBCTprvr@@4uEJOgAAACLvCTgAAAAD6+EJOQAAADRpCS0AAAA"
    . "jQSHiUQkUIuEJPAAAADB+AqDwAGJRCQki4Qk6AAAAIXAD45ECgAAi3wkJIuEJAQB"
    . "AACLdCRQx0QkMAAAAADHRCQUAAAAAA+vx4lEJECLhCTkAAAAD6@HweACiUQkSIuE"
    . "JOAAAACDwAKJRCQ4ifiNPL0AAAAAiXwkLInHD6+EJAABAACJfCQ8iUQkKIuEJOQA"
    . "AACFwA+OaQEAAItEJDjHRCQcAAAAAIlEJBCLRCQkiUQkGItEJBC7AgAAAA+2OIk8"
    . "JA+2eP8PtkD+iXwkBIlEJAg5nCS0AAAAD4bCAAAAiwSeg8MCi3ye@InCD7bMD7bA"
    . "K0QkCMHqECtMJAQPttIrFCSB@@@@@wCJRCQMd0YPr9IPr8mNFFIPr8CNFIqNBEI5"
    . "x3Kui3wkGItEJCSLTCQsAUwkEItMJCgBTCQcAfg5vCTkAAAAD465AAAAiUQkGOlf"
    . "@@@@if3B7RCJ6A+26A+v0g+v7TnqD4dm@@@@ifgPttQPr8kPr9I50Q+HU@@@@4tM"
    . "JAyJ+A+2+A+v@4nID6@BOfh2kDmcJLQAAAAPhz7@@@+LRCQwi3wkFJmNHL0AAAAA"
    . "97wk6AAAAA+vhCTAAAAAicGLRCQcmfe8JOQAAACLFCTB4hCNBIGLjCTYAAAAiQS5"
    . "i0QkBIPHAYl8JBSLvCTcAAAAweAICdALRCQIiQQf6SD@@@+LfCQ8i0QkJItMJEAB"
    . "TCQwi0wkSAFMJDgB+Dm8JOgAAAB+CYlEJDzpXP7@@4tEJBQPr4Qk7AAAAMH4ColE"
    . "JCiLRCRQx0QkQAAAAADHRCQwAAAAAIt4BIn4ifvB6BAPtteJ+w+2wA+2y4nDD6@Y"
    . "idAPr8KJXCRwiUQkdInID6@BiUQkbOlH9P@@i4Qk0AAAAIXAD45u9f@@i5wkzAAA"
    . "AItEJCDHBCQAAAAAx0QkBAAAAACJfCQMjQRYiUQkGInYweACiUQkCIu0JMwAAACF"
    . "9n5Xi4wkvAAAAItcJBiLvCS8AAAAA1wkBAHpA2wkCAHvD7ZRAoPBBIPDAWvyJg+2"
    . "Uf1rwkuNFAYPtnH8ifDB4AQp8AHQwfgHiEP@Ofl10ou8JMwAAAABfCQEgwQkAQNs"
    . "JCyLBCQ5hCTQAAAAdYqLhCTMAAAAi3wkDDHti5QktAAAADH2g+gBiXwkJIlEJAyL"
    . "hCTQAAAAg+gBiUQkEIucJMwAAACF2w+O4gAAAIu8JMwAAACLRCQYAfeNDDCJ+4l8"
    . "JByJxwHfifMrnCTMAAAAiXwkBIt8JCABwwH3McCJfCQIiRwkhcAPhGQDAAA5RCQM"
    . "D4RaAwAAhe0PhFIDAAA5bCQQD4RIAwAAD7YRD7Z5@74BAAAAA5QksAAAADn6ckYP"
    . "tnkBOfpyPos8JA+2Pzn6cjSLXCQED7Y7OfpyKYs8JA+2f@85+nIeizwkD7Z@ATn6"
    . "chMPtnv@OfpyCw+2cwE58g+Sw4nei3wkCInziBwHg8ABg8EBg0QkBAGDBCQBOYQk"
    . "zAAAAA+FWv@@@4t0JByDxQE5rCTQAAAAD4X@@v@@i3wkJImUJLQAAADpY@L@@8dE"
    . "JEAAAAAAx0QkKAAAAADHRCQwAAAAAMdEJBQAAAAA6cfx@@+DfCRUAQ+E6gEAAIN8"
    . "JFQCD4SVAgAAg2wkEAHpBfr@@4uEJAQBAACLrCQAAQAAD6@AD6@tiUQkBItEJAyF"
    . "wA+P6PX@@zHA6VL2@@+DRCRkAcdEJCQJAAAAi0QkGIucJNQAAAAPr4QkzAAAAANE"
    . "JBCAPAMDD4ZnAQAAi3QkFItcJDA53g9N3oO8JKwAAAADiVwkIA+OdQEAAItEJBgD"
    . "hCTIAAAAD6+EJMAAAACLVCQQA5QkxAAAAIO8JKwAAAAFD4RsAgAAjTSQi4QksAAA"
    . "AIucJLwAAAAB8A+2XAMCiVwkOIucJLwAAAAPtlwDAYlcJDyLnCS8AAAAD7YEA4lE"
    . "JEiLRCQghcAPhKoBAACLRCRAiXwkLDHbi2wkKIu8JLwAAACJRCRo62KNtCYAAAAA"
    . "OVwkMH5Ii4Qk3AAAAIsUmAHyD7ZEFwIPtkwXAStEJDgrTCQ8D7YUFytUJEgPr8AP"
    . "r8mNBEAPr9KNBIiNBFA5hCS0AAAAcgeDbCRoAXhhg8MBOVwkIA+EogEAADlcJBR+"
    . "n4uEJNgAAACLFJgB8g+2RBcCD7ZMFwErRCQ4K0wkPA+2FBcrVCRID6@AD6@JjQRA"
    . "D6@SjQSIjQRQOYQktAAAAA+DWv@@@4PtAQ+JUf@@@4t8JCyDfCQkCQ+EKfj@@4NE"
    . "JEwB6Try@@+DRCQQAekm+P@@g0QkRAHpEfL@@410JgCF2w+EoAAAAAOEJNQAAACL"
    . "XCRAMdKLbCQoicHrJTlUJDB+Fou0JNwAAACLBJYByPYAAXUFg+sBeJqDwgE5VCQg"
    . "dGo5VCQUftWLtCTYAAAAiwSWAcj2AAJ1xIPtAXm@6XD@@@@HRCQEAwAAAOlB8P@@"
    . "i3wkCMYEBwLpEf3@@8cEJAMAAADpOfD@@8dEJCgAAAAAx0QkFAAAAADpGPX@@4NE"
    . "JBgB6XD3@@+LbCQoi4Qk+AAAAINEJAwBhcAPhMoDAACLVCQYA5QkyAAAAItcJAyL"
    . "RCQQA4QkxAAAAIu0JPgAAADB4hCNi@@@@z8J0IkEjou0JLgAAACF9g+F0gIAAItE"
    . "JCiLdCQ0Keg5nCT8AAAAiQSOD44z8v@@6bb+@@+LfCQs64mLtCSEAAAAjQSQiUQk"
    . "PIX2D4WuAQAAi1wkIItEJFAx9otsJCiF24lEJGgPhFn@@@+LhCTYAAAAi1wkaItU"
    . "JDwDFLCJXCRIa8YWgTv@@@8AiUQkOA+XwA+2wIlEJCyLhCTcAAAAiwSwiYQktAAA"
    . "AIuEJLwAAAAPtkQQAomEJIwAAADB4BCJwYuEJLwAAAAPtkQQAYmEJJAAAADB4AgJ"
    . "yIuMJLwAAAAPtgwRCciJjCSUAAAAiYQkiAAAAOsfD6@SD6@JjRRSD6@AjRSKjQRC"
    . "OccPg70AAACDRCRICItEJDg7hCS0AAAAD4PPAAAAi1QkeIt8JEiDRCQ4AoXSiweL"
    . "fwR0JoX2i5wkiAAAAA9FnCSwAAAAhcAPlMAPtsCJRCQsiZwksAAAAInYicIPtswP"
    . "tsDB6hArjCSQAAAAK4QklAAAAA+20iuUJIwAAACB@@@@@wAPhmX@@@+J+8HrEA+2"
    . "2w+v0g+v2znaD4dp@@@@ifsPttcPr8kPr9I50Q+HVv@@@4n7D7bTD6@AD6@SOdAP"
    . "h0P@@@+LRCQshcB0CYPtAQ+IDf3@@4PGAYNEJGhYOXQkIA+Fe@7@@+nP@f@@i0Qk"
    . "LIXAdeHr1otMJCCLbCQohckPhLX9@@8x9usuOUQkcHwSD6@JOUwkdHwJD6@SOVQk"
    . "bH0Jg+0BD4i3@P@@g8YBOXQkIA+Eg@3@@4uEJNgAAACLVCQ8i5wkvAAAAAMUsIuE"
    . "JNwAAACLBLCJhCSwAAAAi4QkvAAAAIuMJLAAAAAPtkQQAsHpEA+2ySnID7ZMEwGL"
    . "nCSwAAAAD6@AD7bfKdmLnCS8AAAAD7YUEw+2nCSwAAAAKdqB@@@@@wAPh1z@@@8P"
    . "r8mNBEAPr9KNBIiNBFA5xw+CXf@@@+lh@@@@x0QkKAAAAADHRCQUAAAAAOnC9@@@"
    . "i1wkDDmcJPwAAACJ2A+OrfD@@4tcJBgxyYnOidgrhCQEAQAAg8ABD0jBicKJ2Iuc"
    . "JAQBAACNRBj@i1wkCDnDD07Di1wkEInFidgrhCQAAQAAg8ABD0nwidiLnCQAAQAA"
    . "jUQY@4tcJAQ5ww9OwznVicMPjIz7@@+LhCTMAAAAg8UBD6@CA4Qk1AAAAInBjUMB"
    . "iUQkIDnefw+J8IAkAQODwAE7RCQgdfODwgEDjCTMAAAAOep13+lJ+@@@i6wkuAAA"
    . "AIXtD4VK@@@@6TX7@@+QkA=="
    x64:="QVdBVkFVQVRVV1ZTSIHsyAAAAEhjhCRQAQAASIu8JKgBAACJjCQQAQAAiVQkMESJ"
    . "jCQoAQAAi7QkgAEAAIusJIgBAABJicRIiUQkWEgDhCRgAQAAg@kFSIlEJChIY4Qk"
    . "sAEAAEiNBIdIiUQkYA+E3AUAAIXtD44BDAAARTH2iVwkEIu8JLgBAABEiXQkCIuc"
    . "JBABAABFMe1Mi7QkcAEAAEUx20Ux@0SJbCQYRImEJCABAABMY1QkCEUxyUUxwEwD"
    . "lCR4AQAAhfZ@Mut3Dx9AAEEPr8SJwUSJyJn3@gHBQ4A8AjF0PEmDwAFJY8dBAflB"
    . "g8cBRDnGQYkMhn5DRInYmff9g@sEdckPr4QkOAEAAInBRInImff+Q4A8AjGNDIF1"
    . "xEiLlCRoAQAASYPAAUljxUEB+UGDxQFEOcaJDIJ@vQF0JAiDRCQYAUQDnCTAAQAA"
    . "i0QkGDnFD4VX@@@@RInoi1wkEESLhCQgAQAAD6+EJJABAABEiWwkGMH4ColEJByL"
    . "hCSYAQAAQQ+vx8H4ColEJECDvCQQAQAABA+EtwUAAIuEJDgBAACLvCRAAQAAD6+E"
    . "JEgBAACNBLiLvCQ4AQAAiUQkCESJ4PfYg7wkEAEAAAGNBIeJRCQgD4SxBQAAg7wk"
    . "EAEAAAIPhIQHAACDvCQQAQAAAw+EowoAAIuEJFgBAACFwA+OHwEAAESJfCQQRIuc"
    . "JBABAABBjWwk@0yLfCQoi7wkoAEAAEUx9kUx7YlcJAhEiYQkIAEAAA8fhAAAAAAA"
    . "RYXkD467AAAASWPFMclJicFNjUQHAUwDjCRgAQAA6xhBxgEEg8EBSYPBAUmDwAFB"
    . "OcwPhIkAAABBg@sDf+KFyUEPtlD@D4S1DgAAQQ+2WP45zQ+Euw4AAEUPthCF@w+E"
    . "fAEAAA+28rgGAAAAg+4Bg@4BdhiD+wFAD5TGQYP6AQ+UwAnwD7bAAcCDyASB4v0A"
    . "AAC+AQAAAHQOhdtAD5TGRYXSD5TCCdYJ8IPBAUmDwQFBiEH@SYPAAUE5zA+Fd@@@"
    . "@0UB5UGDxgFEObQkWAEAAA+PKv@@@4tcJAhEi3wkEESLhCQgAQAAg7wkEAEAAAN@"
    . "FouEJKABAACFwA+VwDwBg5wkQAEAAP+LfCQYi3QkHDHARInlRIucJFgBAAA59w9O"
    . "+EQ7fCRAiXwkGEQPTvgrrCS4AQAARCucJMABAACDvCQoAQAACQ+EuQAAAIuEJCgB"
    . "AACD6AGD+AcPh5ACAACD+AOJRCRID46LAgAAiWwkCESJXCQQRTH2x0QkTAAAAACL"
    . "fCRMOXwkCMdEJGgAAAAAD4wNAQAAi3wkaDl8JBAPjNIMAACLfCRIi3QkTItEJAgp"
    . "8ED2xwIPRMaLdCRoicKLRCQQKfBA9scBD0TGg@8DidcPT@gPT8JBicXptgoAAGaQ"
    . "D7bCg+gBg@gCGcCD4AKDwASB4v0AAAAPlMIJ0EGIAekg@v@@iehBjVMBRIlcJAjB"
    . "6B+JbCQQx4QkiAAAAAAAAAAB6MeEJIQAAAABAAAAx0QkbAAAAADR+MdEJHwAAAAA"
    . "QYnFRInYwegfRAHY0fiJx41FAYnGD6@yOdAPTMJFMfaDwAiJtCSkAAAAicYPr@CJ"
    . "tCSoAAAAi7QkpAAAADm0JIgAAAB9HIu0JKgAAAA5dCR8x4QkgAAAAAAAAAAPjEYE"
    . "AACLhCQoAQAAhcAPhV0CAABIg7wkqAEAAAAPhE4CAACLhCTAAQAAD6+EJLgBAACD"
    . "+AEPhDYCAABBg@4BD45dCQAAQY1G@kyLRCRgTIucJKgBAABFMclFMdJIjRyFBAAA"
    . "AEOLdAgEQ4sUCESJ0UOLfAsETInQOdZyE+kJBAAAZpBIg+gBQYsUgDnWcx1BiVSA"
    . "BEGLFIOD6QGD+f9BiVSDBHXeSMfA@@@@@0mDwQRIg8ABSYPCAUk52UGJNIBBiTyD"
    . "dZ9Ei5QkuAEAAIucJMABAABFD6@SD6@bTIuMJKgBAAAx9jHAQYsssYnvRA+33cHv"
    . "EIXAdDJFMcAPH4QAAAAAAEOLDIEPt9FEKdoPr9JEOdJ9DMHpECn5D6@JOdl8E0mD"
    . "wAFEOcB@2Uhj0IPAAUGJLJFIg8YBQTn2f6pIgcTIAAAAW15fXUFcQV1BXkFfw8dE"
    . "JEgAAAAARIlcJAiJbCQQRTH2x0QkTAAAAADpcP3@@4tEJDAx@4P4AkAPlMeJvCSs"
    . "AAAAD4SpAwAAMcCDfCQwAQ+UwEWFwImEJKAAAAAPhNsKAABEiaQkUAEAAEyLlCR4"
    . "AQAARTHJi7wkOAEAAEyLpCRoAQAARTHbTIusJHABAABEi7QkuAEAAESLvCTAAQAA"
    . "iVwkGEGLGkmDwliJ2MHoEEEPr8eZ9@0Pr8eJwQ+3w0EPr8aZ9@6NBIFDiQSMQYtC"
    . "rEGNBENBg8MWQ4lEjQBJg8EBRTnId72LhCSQAQAARIukJFABAACJXCQwi1wkGESJ"
    . "RCQYQQ+vwMH4ColEJBxIi4QkeAEAAMdEJEAAAAAARTH@SIPACEiJBCTpq@r@@0SJ"
    . "8OnE@v@@i3wkMIn4wegQD6+EJMABAACZ9@0Pr4QkOAEAAInBD7fHD6+EJLgBAACZ"
    . "9@6NBIGJRCQw6Wv6@@+J6ESLjCRYAQAARQHAD6@GSJhIA4QkeAEAAEWFyUiJBCQP"
    . "jnL7@@9CjTylAAAAAMdEJBAAAAAAMcDHRCRIAAAAAESJfCR4iXwkUEWF5A+O6QAA"
    . "AEhjVCQISIu8JDABAABFMe1MY3QkSEwDdCQoSI1sFwJMiwwkRTHSD7Z9AA+2df9E"
    . "D7Zd@usmZi4PH4QAAAAAAA+vyQ+v0o0MSQ+vwI0UkY0EQjnDc2hJg8EIMcBFOcIP"
    . "gxsBAABBiwFBi1kEQYPCAonBD7bUD7bAwekQKfJEKdgPtskp+YH7@@@@AHazQYnf"
    . "QcHvEEUPtv8Pr8lFD6@@RDn5d7IPts8Pr9IPr8k5ynelD7bTD6@AD6@SOdB3mLoB"
    . "AAAAuAEAAABDiBQuSYPFAUiDxQRFOewPj0P@@@+LdCRQRAFkJEgBdCQIg0QkEAGL"
    . "VCQgi3wkEAFUJAg5vCRYAQAAD4Xw@v@@RIt8JHjpFvn@@0WF7XgVRDtsJBB@DoX@"
    . "eAo7fCQID464BQAAi0QkbIXAD4WNBQAAg+8Bg4QkgAAAAAGDRCR8AYuUJIQAAAA5"
    . "lCSAAAAAfLqLdCRsifCD4AEBwonwg8ABiZQkhAAAAIPgA4lEJGzpW@v@@w8fRAAA"
    . "icLpQf@@@0yJ0Oka@P@@i0QkMIuMJFgBAAAx9jH@Qo0spQAAAACDwAHB4AeFyYlE"
    . "JDAPjo@5@@9Ei3QkCESLbCQwRYXkflVIi5QkMAEAAExj30wDXCQoSWPGRTHJSI1M"
    . "AgIPthEPtkH@RA+2Uf5rwEtr0iYBwkSJ0MHgBEQp0AHQQTnFQw+XBAtJg8EBSIPB"
    . "BEU5zH@MQQHuRAHng8YBRAN0JCA5tCRYAQAAdZXp9vf@@4noRQHAD6@GweACSJhI"
    . "A4QkeAEAAEiJBCSLhCSYAQAAwfgKg8ABhe2JRCQID46VCgAAi3wkCIuEJMABAADH"
    . "RCRIAAAAAMdEJBgAAAAARImkJFABAACJrCSIAQAAD6@HiXwkUIlEJHiJ+A+vxsHg"
    . "AkiYSIlEJHBIi4QkeAEAAEiJRCRAifjB4AJImEiJRCQQi4QkuAEAAA+vx4lEJBxI"
    . "iwQkSIPACEiJRCQghfYPjiYBAABIi3wkQESLZCQIMe0Ptl8CTItMJCBBvgIAAABE"
    . "D7ZXAUQPth9Bid3rHQ8fAA+v2w+v0o0cWw+vwI0Uk40EQjnBc2pJg8EIRTnwD4Z9"
    . "AAAAQYsBQYtJBEGDxgKJww+21A+2wMHrEEQp0kQp2A+220Qp64H5@@@@AHazQYnP"
    . "QcHvEEUPtv8Pr9tFD6@@RDn7d7IPtt0Pr9IPr9s52nelD7bJD6@AD6@JOch3mGaQ"
    . "i0QkCEgDfCQQA2wkHEQB4EQ55n5lQYnE6UP@@@8PHwCLRCRIRIt0JBhEievB4xBB"
    . "weIIQQnamU1jzkUJ2ve8JIgBAAAPr4QkOAEAAInBieiZ9@5Ii5QkaAEAAI0EgUKJ"
    . "BIpEifCDwAGJRCQYSIuEJHABAABGiRSI64aLfCRQi0QkCItUJHgBVCRISItUJHBI"
    . "AVQkQAH4ObwkiAEAAH4JiUQkUOmk@v@@i0QkGESLpCRQAQAAD6+EJJABAADB+AqJ"
    . "RCQcSIsEJMdEJEAAAAAARTH@i1gEidgPts8PttPB6BAPtsCJxw+v+InID6@Bibwk"
    . "mAAAAImEJJwAAACJ0A+vwomEJJQAAADpffX@@8dEJEAAAAAAx0QkHAAAAABFMf@H"
    . "RCQYAAAAAOn19P@@i5QkWAEAAIXSD4589v@@Q40EZESLdCQIQo0spQAAAAAx9jH@"
    . "SJhIA4QkYAEAAEmJxUWF5H5aSIuUJDABAABJY8ZMY99FMclNAetIjUwCAg8fRAAA"
    . "D7YRSIPBBERr0iYPtlH7a8JLQY0UAkQPtlH6RInQweAERCnQAdDB+AdDiAQLSYPB"
    . "AUU5zH@KQQHuRAHng8YBRAN0JCA5tCRYAQAAdZBIi3wkWDHSQY1sJP9EiXwkSEUx"
    . "0olcJCBBiddIifhIg8ABSIlEJAi4AQAAAEiJxouEJFgBAABIKf6LfCQwSIl0JBBE"
    . "jXD@RYXkD47TAAAASItEJAhNY99Ii3QkKEuNVB0BTo0MGEiLRCQQTAHeTQHpSo0M"
    . "GDHATAHpZi4PH4QAAAAAAEiFwA+EgQMAADnFD4R5AwAARYXSD4RwAwAARTnWD4Rn"
    . "AwAARA+2Qv9ED7Za@rsBAAAAQQH4RTnYckZED7YaRTnYcj1ED7ZZ@0U52HIzRQ+2"
    . "Wf9FOdhyKUQPtln+RTnYch9ED7YZRTnYchZFD7ZZ@kU52HIMRQ+2GUU52A+Sw2aQ"
    . "iBwGSIPAAUiDwgFJg8EBSIPBAUE5xA+PZP@@@0UB50GDwgFEOZQkWAEAAA+FEv@@"
    . "@4tcJCBEi3wkSOmJ8@@@RIuUJLgBAACLnCTAAQAAMcBFD6@SD6@bRYX2D4569@@@"
    . "6RP3@@+DfCRsAQ+E@AEAAIN8JGwCD4S4AgAAQYPtAelX+v@@g4QkiAAAAAHHRCRI"
    . "CQAAAIn4SIu0JGABAABBD6@ERo0MKEljwYA8BgMPhqQBAACLRCQYRDn4QQ9Mx4O8"
    . "JBABAAADiUQkIA+OsAEAAIuEJEgBAACLlCRAAQAAAfhEAeoPr4QkOAEAAIO8JBAB"
    . "AAAFD4TAAgAARI0MkItEJDBIi7QkMAEAAESLVCQgRAHIjVACRYXSSGPSD7Y0Fo1Q"
    . "AUiYSGPSiXQkUEiLtCQwAQAAD7Y0Fol0JHhIi7QkMAEAAA+2BAaJRCRwD4TrAQAA"
    . "i0QkQESJXCQoRTHSi3QkHEyLnCQwAQAAiYQkjAAAAOtyRDu8JJAAAAB+WUiLhCRw"
    . "AQAAQosUkEQByo1CAo1KAUhj0kEPthQTSJhIY8krVCRwQQ+2BANBD7YMCytEJFAr"
    . "TCR4D6@SD6@AD6@JjQRAjQSIjQRQQTnAcgqDrCSMAAAAAXh+SYPCAUQ5VCQgD47P"
    . "AQAARDlUJBhEiZQkkAAAAA+Oe@@@@0iLhCRoAQAAQosUkEQByo1CAo1KAUhj0kEP"
    . "thQTSJhIY8krVCRwQQ+2BANBD7YMCytEJFArTCR4D6@SD6@AD6@JjQRAjQSIjQRQ"
    . "QTnAD4Mo@@@@g+4BD4kf@@@@RItcJCiDfCRICQ+Eavj@@4NEJGgB6Snz@@9Bg8UB"
    . "6Wb4@@+DRCRMAekA8@@@kIXAD4SzAAAARItUJECLdCQcMcnrM0Q7fCQofiJIi5Qk"
    . "cAEAAESJyAMEikiLlCRgAQAA9gQCAXUGQYPqAXiZSIPBATlMJCB+dzlMJBiJTCQo"
    . "fsNIi4QkaAEAAESJygMUiEiLhCRgAQAA9gQQAnWng+4BeaLpX@@@@w8fhAAAAAAA"
    . "uwMAAADpRvH@@8YEBgLp8Pz@@0G6AwAAAOk+8f@@x0QkHAAAAADHRCQYAAAAAOm7"
    . "9f@@g8cB6aD3@@+LdCQcQYPGAUiDvCSoAQAAAA+EHQQAAEljxouUJEgBAABIjQyF"
    . "AAAAAIuEJEABAAAB+sHiEEQB6AnQSIuUJKgBAACJRAr8i5QkKAEAAIXSD4UeAwAA"
    . "i0QkHCnwRDm0JLABAABIi3QkYIlEDvwPjhPz@@@ppf7@@0SLXCQo64aNBJCJRCQo"
    . "i4QkrAAAAIXAD4XjAQAAi0QkIIXAD4Rg@@@@SIsEJIt0JBxFMcnHRCR4AAAAAESJ"
    . "dCRwRIm8JIwAAABEiZwkkAAAAEiJRCRQSIuEJGgBAACLTCQoTIu8JDABAABMi1Qk"
    . "UEyLhCRwAQAARItcJHhCAwyIQYE6@@@@AEeLBIiNUQKNQQFIY8lBD5fGSGPSSJhF"
    . "D7b2QQ+2FBdBD7YEB4mUJLQAAACJhCS4AAAAweIQweAICdBBD7YUDwnQiZQkvAAA"
    . "AImEJLAAAADrHg+v0g+vyY0UUg+vwI0Uio0EQjnDD4OvAAAASYPCCEU5ww+D4AAA"
    . "AESLvCSgAAAAQYPDAkGLAkGLWgRFhf90Hk2FyYtUJDAPRJQksAAAAEUx9oXAQQ+U"
    . "xolUJDCJ0InCD7bMD7bAweoQK4wkuAAAACuEJLwAAAAPttIrlCS0AAAAgfv@@@8A"
    . "D4Z0@@@@QYnfQcHvEEUPtv8Pr9JFD6@@RDn6D4dz@@@@D7bXD6@JD6@SOdEPh2L@"
    . "@@8PttMPr8APr9I50A+HUf@@@0WF9nQFg+4BeDtJg8EBSINEJFBYg0QkeBZEOUwk"
    . "IA+Pkf7@@0SLdCRwRIu8JIwAAABEi5wkkAAAAOmu@f@@RYX2dcfrwESLdCRwRIu8"
    . "JIwAAABEi5wkkAAAAOml@P@@i0QkIIt0JByFwA+Eff3@@0Ux0us5OYQkmAAAAHwY"
    . "D6@JOYwknAAAAHwMD6@SOZQklAAAAH0Jg+4BD4hm@P@@SYPCAUQ5VCQgD44@@f@@"
    . "SIuEJGgBAACLVCQoTIuMJDABAABCAxSQSIuEJHABAABCiwSQicGNQgKJTCQwwekQ"
    . "SJgPtslBD7YEASnIjUoBSGPSD6@ASGPJRQ+2DAlIi0wkMA+2zUEpyUSJyUyLjCQw"
    . "AQAAQQ+2FBFED7ZMJDBEKcqB+@@@@wAPh0r@@@8Pr8mNBEAPr9KNBIiNBFA5ww+C"
    . "VP@@@+lY@@@@x0QkHAAAAADHRCQYAAAAAOlF9@@@RDm0JLABAABEifAPjhvx@@+J"
    . "+CuEJMABAABFMdKDwAFBD0jCicGLhCTAAQAAjUQH@0E5w0EPTsOJxkSJ6CuEJLgB"
    . "AACDwAFED0nQi4QkuAEAAEGNRAX@OcUPTsU5zolEJCAPjEH7@@9EieJJY8IPr9FI"
    . "Y9JIAdBIA4QkYAEAAEmJwY1GAYlEJCiLRCQgRCnQSI1wAUQ7VCQgfxNKjRQOTInI"
    . "gCADSIPAAUg50HX0g8EBTANMJFg7TCQoddjp6Pr@@4uMJCgBAACFyQ+FQf@@@+nU"
    . "+v@@kJCQkJCQkJCQkJCQkA=="
    MyFunc:=this.MCode(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]
  ok:=(!ini.bits.Scan0 || mode<1 || mode>5) ? 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
    , "Ptr",text, "int",w, "int",h
    , "int",Floor(Abs(err1)*1024), "int",Floor(Abs(err0)*1024)
    , "int",(err1<0||err0<0), "Ptr",ini.allpos, "int",ini.allpos_max
    , "int",Floor(w*ini.zoomW), "int",Floor(h*ini.zoomH))
  return ok
}

code()
{
return "
(

//***** C source code of machine code *****
// gcc.exe -m32/-m64 -O2

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, int more_err
  , unsigned int * allpos, int allpos_max
  , int new_w, int new_h )
{
  int ok, o, i, j, k, v, e1, e0, len1, len0, max, pic, shape, sort;
  int x, y, x1, y1, x2, y2, x3, y3, r, g, b, rr, gg, bb, dR, dG, dB;
  int ii, jj, RunDir, DirCount, RunCount, AllCount1, AllCount2;
  unsigned int c1, c2, *cors, *arr;
  unsigned char *ts, *gs;
  ok=0; o=0; v=0; len1=0; len0=0; ts=ss+sw; gs=ss+sw*3;
  arr=allpos+allpos_max; sort=(dir==0);
  //----------------------
  if (mode==5)
  {
    if (pic=(c==2))  // FindPic
    {
      cors=(unsigned int *)(text+w*h*4); j=(err0>>10)+1; n*=2;
      for (y=0; y<h; y+=j)
      {
        for (x=0; x<w; x+=j)
        {
          o=(y*w+x)*4; rr=text[2+o]; gg=text[1+o]; bb=text[o];
          for (i=2; i<n;)
          {
            c1=cors[i++]; c2=cors[i++];
            r=((c1>>16)&0xFF)-rr; g=((c1>>8)&0xFF)-gg; b=(c1&0xFF)-bb;
            v=(c2<0x1000000) ? (3*r*r+4*g*g+2*b*b<=c2)
            : (r*r<=((c2>>16)&0xFF)*((c2>>16)&0xFF)
            && g*g<=((c2>>8)&0xFF)*((c2>>8)&0xFF) && b*b<=(c2&0xFF)*(c2&0xFF));
            if (v) goto NoMatch1;
          }
          s1[len1]=(y*new_h/h)*Stride+(x*new_w/w)*4;
          s0[len1++]=rr<<16|gg<<8|bb;
          NoMatch1:;
        }
      }
      c2=cors[1]; r=(c2>>16)&0xFF; g=(c2>>8)&0xFF; b=c2&0xFF; dR=r*r; dG=g*g; dB=b*b;
    }
    else  // FindMultiColor or FindColor
    {
      shape=(c==1);  // FindShape
      cors=(unsigned int *)text;
      for (i=0; i<n; i++, o+=22)
      {
        c=cors[o]; y=c>>16; x=c&0xFFFF;
        s1[len1]=(y*new_h/h)*Stride+(x*new_w/w)*4;
        s0[len1++]=o+cors[o+1]*2;
      }
      cors+=2;
    }
    goto StartLookUp;
  }
  //----------------------
  // Generate Lookup Table
  for (y=0; y<h; y++)
  {
    for (x=0; x<w; x++)
    {
      i=(mode==4) ? (y*new_h/h)*Stride+(x*new_w/w)*4 : (y*new_h/h)*sw+(x*new_w/w);
      if (text[o++]=='1')
        s1[len1++]=i;
      else
        s0[len0++]=i;
    }
  }
  //----------------------
  // Color Position Mode
  // only used to recognize multicolored Verification Code
  if (mode==4)
  {
    y=c>>16; x=c&0xFFFF;
    c=(y*new_h/h)*Stride+(x*new_w/w)*4;
    goto StartLookUp;
  }
  //----------------------
  // Generate Two Value Image
  o=sy*Stride+sx*4; j=Stride-sw*4; i=0;
  if (mode==1)  // Color Mode
  {
    cors=(unsigned int *)(text+w*h); n*=2;
    for (y=0; y<sh; y++, o+=j)
    {
      for (x=0; x<sw; x++, o+=4, i++)
      {
        rr=Bmp[2+o]; gg=Bmp[1+o]; bb=Bmp[o];
        for (k=0; k<n;)
        {
          c1=cors[k++]; c2=cors[k++];
          r=((c1>>16)&0xFF)-rr; g=((c1>>8)&0xFF)-gg; b=(c1&0xFF)-bb;
          v=(c2<0x1000000) ? (3*r*r+4*g*g+2*b*b<=c2)
          : (r*r<=((c2>>16)&0xFF)*((c2>>16)&0xFF)
          && g*g<=((c2>>8)&0xFF)*((c2>>8)&0xFF) && b*b<=(c2&0xFF)*(c2&0xFF));
          if (v) break;
        }
        ts[i]=(v) ? 1:0;
      }
    }
  }
  else if (mode==2)  // Gray Threshold Mode
  {
    c=(c+1)<<7;
    for (y=0; y<sh; y++, o+=j)
      for (x=0; x<sw; x++, o+=4, i++)
        ts[i]=(Bmp[2+o]*38+Bmp[1+o]*75+Bmp[o]*15<c) ? 1:0;
  }
  else if (mode==3)  // Gray Difference Mode
  {
    for (y=0; y<sh; y++, o+=j)
    {
      for (x=0; x<sw; x++, o+=4, i++)
        gs[i]=(Bmp[2+o]*38+Bmp[1+o]*75+Bmp[o]*15)>>7;
    }
    for (i=0, y=0; y<sh; y++)
    for (x=0; x<sw; x++, i++)
    if (x==0 || x==sw-1 || y==0 || y==sh-1)
      ts[i]=2;
    else
    {
      n=gs[i]+c;
      ts[i]=(gs[i-1]>n || 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;
    }
  }
  //----------------------
  StartLookUp:
  for (i=0, y=0; y<sh; y++)
  {
    for (x=0; x<sw; x++, i++)
    {
      if (mode>=4) { ss[i]=4; continue; }
      r=ts[i]; g=(x==0 ? 3 : ts[i-1]); b=(x==sw-1 ? 3 : ts[i+1]);
      if (more_err)
        ss[i]=4|(r==2||r==1||g==1||b==1)<<1|(r==2||r==0||g==0||b==0);
      else
        ss[i]=4|(r==2||r==1)<<1|(r==2||r==0);
    }
  }
  if (mode<4 && more_err) sx++;
  err1=(len1*err1)>>10;
  err0=(len0*err0)>>10;
  if (err1>=len1) len1=0;
  if (err0>=len0) len0=0;
  max=(len1>len0) ? len1 : len0;
  w=new_w; h=new_h; x1=0; y1=0; x2=sw-w; y2=sh-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
  // 9 ==> Center to Four Sides
  if (dir==9)
  {
    x=(x1+x2)/2; y=(y1+y2)/2; i=x2-x1+1; j=y2-y1+1;
    AllCount1=i*j; i=(i>j?i:j)+8;
    AllCount2=i*i; RunCount=0; DirCount=1; RunDir=0;
    for (ii=0; RunCount<AllCount1 && ii<AllCount2;)
    {
      for(jj=0; jj<DirCount; jj++, ii++)
      {
        if(x>=x1 && x<=x2 && y>=y1 && y<=y2)
        {
          RunCount++;
          goto FindPos;
          FindPos_GoBak:;
        }
        if (RunDir==0) y--;
        else if (RunDir==1) x++;
        else if (RunDir==2) y++;
        else x--;
      }
      if (RunDir & 1) DirCount++;
      RunDir = (++RunDir) & 3;
    }
    goto Return1;
  }
  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 & 2) ? y1+y2-y3 : y3;
      x=(dir & 1) ? x1+x2-x3 : x3;
      if (dir>3) { r=y; y=x; x=r; }
      //----------------------
      FindPos:
      e1=err1; e0=err0; o=y*sw+x;
      if (ss[o]<4) goto NoMatch;
      if (mode<4)
      {
        for (i=0; i<max; i++)
        {
          if (i<len1 && (ss[o+s1[i]]&2)==0 && (--e1)<0) goto NoMatch;
          if (i<len0 && (ss[o+s0[i]]&1)==0 && (--e0)<0) goto NoMatch;
        }
      }
      else if (mode==5)
      {
        o=(sy+y)*Stride+(sx+x)*4;
        if (pic)
        {
          for (i=0; i<max; i++)
          {
            j=o+s1[i]; c=s0[i]; r=Bmp[2+j]-((c>>16)&0xFF);
            g=Bmp[1+j]-((c>>8)&0xFF); b=Bmp[j]-(c&0xFF);
            v=(c2<0x1000000)?(3*r*r+4*g*g+2*b*b>c2):(r*r>dR||g*g>dG||b*b>dB);
            if (v && (--e1)<0) goto NoMatch;
          }
        }
        else
        {
          for (i=0; i<max; i++)
          {
            j=o+s1[i]; rr=Bmp[2+j]; gg=Bmp[1+j]; bb=Bmp[j];
            for (j=i*22, k=cors[j]>0xFFFFFF, n=s0[i]; j<n;)
            {
              c1=cors[j++]; c2=cors[j++];
              if (shape) { if (i==0) c=rr<<16|gg<<8|bb; k=!c1; c1=c; }
              r=((c1>>16)&0xFF)-rr; g=((c1>>8)&0xFF)-gg; b=(c1&0xFF)-bb;
              v=(c2<0x1000000) ? (3*r*r+4*g*g+2*b*b<=c2)
              : (r*r<=((c2>>16)&0xFF)*((c2>>16)&0xFF)
              && g*g<=((c2>>8)&0xFF)*((c2>>8)&0xFF) && b*b<=(c2&0xFF)*(c2&0xFF));
              if (v) { if (k) goto NoMatch2; goto MatchOK; }
            }
            if (k) goto MatchOK;
            NoMatch2:
            if ((--e1)<0) goto NoMatch;
            MatchOK:;
          }
        }
      }
      else  // mode==4
      {
        o=(sy+y)*Stride+(sx+x)*4; j=o+c; rr=Bmp[2+j]; gg=Bmp[1+j]; bb=Bmp[j];
        for (i=0; i<max; i++)
        {
          if (i<len1)
          {
            j=o+s1[i]; r=Bmp[2+j]-rr; g=Bmp[1+j]-gg; b=Bmp[j]-bb;
            if (3*r*r+4*g*g+2*b*b>n && (--e1)<0) goto NoMatch;
          }
          if (i<len0)
          {
            j=o+s0[i]; r=Bmp[2+j]-rr; g=Bmp[1+j]-gg; b=Bmp[j]-bb;
            if (3*r*r+4*g*g+2*b*b<=n && (--e0)<0) goto NoMatch;
          }
        }
      }
      ok++;
      if (allpos)
      {
        allpos[ok-1]=(sy+y)<<16|(sx+x); if (sort) arr[ok-1]=err1-e1;
        if (ok>=allpos_max) goto Return1;
      }
      // Skip areas that may overlap
      if (!sort)
      {
        r=y-h+1; if (r<0) r=0; rr=y+h-1; if (rr>sh-h) rr=sh-h;
        g=x-w+1; if (g<0) g=0; gg=x+w-1; if (gg>sw-w) gg=sw-w;
        for (i=r; i<=rr; i++)
          for (j=g; j<=gg; j++)
            ss[i*sw+j] &= 3;
      }
      NoMatch:
      if (dir==9) goto FindPos_GoBak;
    }
  }
  //----------------------
  Return1:
  if (!sort || !allpos || w*h==1)
    return ok;
  // Sort by smallest error
  for (i=1; i<ok; i++)
  {
    k=arr[i]; v=allpos[i];
    for (j=i-1; j>=0 && arr[j]>k; j--)
    {
      arr[j+1]=arr[j]; allpos[j+1]=allpos[j];
    }
    arr[j+1]=k; allpos[j+1]=v;
  }
  // Clean up overlapping results
  w*=w; h*=h; k=ok; ok=0;
  for (i=0; i<k; i++)
  {
    c1=allpos[i]; x1=c1&0xFFFF; y1=c1>>16;
    for (j=0; j<ok; j++)
    {
      c2=allpos[j]; x=(c2&0xFFFF)-x1; y=(c2>>16)-y1;
      if (x*x<w && y*y<h) goto NoMatch3;
    }
    allpos[ok++]=c1;
    NoMatch3:;
  }
  return ok;
}

)"
}

PicInfo(text)
{
  local
  if !InStr(text, "$")
    return
  static init, info, bmp
  if !VarSetCapacity(init) && (init:="1")
    info:=[], bmp:=[]
  key:=(r:=StrLen(v:=Trim(text,"|")))<10000 ? v
    : DllCall("ntdll\RtlComputeCrc32", "uint",0
    , "Ptr",&v, "uint",r*(1+!!A_IsUnicode), "uint")
  if info.HasKey(key)
    return info[key]
  comment:="", seterr:=err1:=err0:=0
  ; You Can Add Comment Text within The <>
  if RegExMatch(v, "O)<([^>\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, "O)\[([^\]\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 : 1
  color:=RegExReplace(StrReplace(color,"@","-"), "[*#\s]")
  (mode=1 || mode=5) && color:=StrReplace(color,"0x")
  if (mode=5)
  {
    if !(v~="^[\s\-\w.]+/[\s\-\w.]+/[\s\-\w./,]+$")  ; <FindPic>
    {
      if !(hBM:=LoadPicture(v))
      {
        MsgBox, 4096, Tip, Can't Load Picture ! %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
      arr:=StrSplit(color "/", "/"), arr.Pop(), n:=arr.Length()
      bmp.Push(buf:=this.Buffer(w*h*4 + n*2*4)), v:=buf.Ptr, p:=v+w*h*4-4
      DllCall("RtlMoveMemory", "Ptr",v, "Ptr",Scan0, "Ptr",w*h*4)
      DllCall("DeleteObject", "Ptr",hBM2), color:=Trim(arr[1],"-")
      For k1,v1 in arr
        c:=StrSplit(Trim(v1,"-") "-" color, "-")
        , x:=this.Floor(c[2]), x:=(x<=0||x>1?0:Floor(9*255*255*(1-x)*(1-x)))
        , NumPut(this.ToRGB(c[1]), 0|p+=4, "uint")
        , NumPut((InStr(c[2],".")?x:this.Floor("0x" c[2])|0x1000000), 0|p+=4, "uint")
      color:=2
    }
    else  ; <FindMultiColor> or <FindColor> or <FindShape>
    {
      color:=Trim(StrSplit(color "/", "/")[1], "-")
      arr:=StrSplit(Trim(RegExReplace(v, "i)\s|0x"), ","), ",")
      if !(n:=arr.Length())
        return
      bmp.Push(buf:=this.Buffer(n*22*4)), v:=buf.Ptr
      shape:=(n>1 && StrLen(StrSplit(arr[1] "//","/")[3])=1 ? 1:0)
      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))
      }
      For k1,v1 in arr
      {
        r:=StrSplit(v1 "/","/"), x:=this.Floor(r[1])-x1, y:=this.Floor(r[2])-y1
        , NumPut(y<<16|x, 0|p:=v+(A_Index-1)*22*4, "uint")
        , NumPut(n1:=Min(Max(r.Length()-3,0),(shape?1:10)), 0|p+=4, "uint")
        Loop % n1
          c:=StrSplit(Trim(v1:=r[2+A_Index],"-") "-" color, "-")
          , x:=this.Floor(c[2]), x:=(x<=0||x>1?0:Floor(9*255*255*(1-x)*(1-x)))
          , NumPut(this.ToRGB(c[1])&0xFFFFFF|(!shape&&InStr(v1,"-")=1?0x1000000:0), 0|p+=4, "uint")
          , NumPut((InStr(c[2],".")?x:this.Floor("0x" c[2])|0x1000000), 0|p+=4, "uint")
      }
      color:=shape, w:=x2-x1+1, h:=y2-y1+1
    }
  }
  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
    arr:=StrSplit(color "/", "/"), arr.Pop(), n:=arr.Length()
    , bmp.Push(buf:=this.Buffer(StrPut(v, "CP0") + n*2*4))
    , StrPut(v, buf.Ptr, "CP0"), v:=buf.Ptr, p:=v+w*h-4
    , color:=this.Floor(color)
    if (mode=1)
    {
      For k1,v1 in arr
        c:=StrSplit(Trim(v1,"-") "-", "-")
        , x:=this.Floor(c[2]), x:=(x<=0||x>1?0:Floor(9*255*255*(1-x)*(1-x)))
        , NumPut(this.ToRGB(c[1]), 0|p+=4, "uint")
        , NumPut((InStr(c[2],".")?x:this.Floor("0x" c[2])|0x1000000), 0|p+=4, "uint")
    }
    else if (mode=4)
    {
      r:=StrSplit(Trim(arr[1],"-") "-", "-")
      , n:=this.Floor(r[2]), n:=(n<=0||n>1?0:Floor(9*255*255*(1-n)*(1-n)))
      , c:=this.Floor(r[1]), color:=(c<1||c>w*h?0:((c-1)//w)<<16|Mod(c-1,w))
    }
  }
  return info[key]:=[v, w, h, seterr, err1, err0, mode, color, n, comment]
}

ToRGB(color)  ; color can use: RRGGBB, Red, Yellow, Black, White
{
  static init, tab
  if !VarSetCapacity(init) && (init:="1")
    tab:=Object("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")
  return this.Floor("0x" (tab.HasKey(color)?tab[color]:color))
}

Buffer(size, FillByte:="")
{
  local
  buf:={}, buf.SetCapacity("_key", size), p:=buf.GetAddress("_key")
  , (FillByte!="" && DllCall("RtlFillMemory","Ptr",p,"Ptr",size,"uchar",FillByte))
  , buf.Ptr:=p, buf.Size:=size
  return buf
}

GetBitsFromScreen(ByRef x:=0, ByRef y:=0, ByRef w:=0, ByRef h:=0
  , ScreenShot:=1, ByRef zx:=0, ByRef zy:=0, ByRef zw:=0, ByRef zh:=0)
{
  local
  static init, CAPTUREBLT
  if !VarSetCapacity(init) && (init:="1")  ; thanks Descolada
  {
    DllCall("Dwmapi\DwmIsCompositionEnabled", "Int*",i:=0)
    CAPTUREBLT:=i ? 0 : 0x40000000
  }
  if InStr(A_OSVersion, ".")  ; thanks QQ:349029755
    DllCall("SetThreadDpiAwarenessContext", "Ptr",-3, "Ptr")
  (!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
  }
  bch:=A_BatchLines, cri:=A_IsCritical
  Critical
  bits.BindWindow:=id:=this.BindWindow(0,0,1)
  if (id)
  {
    WinGet, id, ID, ahk_id %id%
    WinGetPos, zx, zy, zw, zh, ahk_id %id%
  }
  if (!id)
  {
    SysGet, zx, 76
    SysGet, zy, 77
    SysGet, zw, 78
    SysGet, zh, 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
    SetBatchLines % bch
    return bits
  }
  if IsFunc(k:="GetBitsFromScreen2")
    && %k%(bits, x-zx, y-zy, w, h)
  {
    ; Get the bind window use bits.BindWindow
    ; Each small range of data obtained from DXGI must be
    ; copied to the screenshot cache using FindText().CopyBits()
    zx:=bits.zx, zy:=bits.zy, zw:=bits.zw, zh:=bits.zh
    Critical % cri
    SetBatchLines % bch
    return bits
  }
  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("UpdateWindow", "Ptr",id)
      ; RDW_INVALIDATE=0x1|RDW_ERASE=0x4|RDW_ALLCHILDREN=0x80|RDW_FRAME=0x400
      ; DllCall("RedrawWindow", "Ptr",id, "Ptr",0, "Ptr",0, "uint", 0x485)
      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
  SetBatchLines % bch
  return bits
}

UpdateBits(bits, zx, zy, zw, zh)
{
  local
  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, ByRef ppvBits:=0)
{
  local
  VarSetCapacity(bi, 40, 0), NumPut(40, bi, 0, "int")
  , NumPut(w, bi, 4, "int"), NumPut(-h, bi, 8, "int")
  , NumPut(1, bi, 12, "short"), NumPut(bpp, bi, 14, "short")
  return DllCall("CreateDIBSection", "Ptr",0, "Ptr",&bi
    , "int",0, "Ptr*",ppvBits:=0, "Ptr",0, "int",0, "Ptr")
}

GetBitmapWH(hBM, ByRef w, ByRef h)
{
  local
  VarSetCapacity(bm, size:=(A_PtrSize=8 ? 32:24), 0)
  , 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)
{
  local
  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")
  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)
{
  local
  if (w<1 || h<1 || !Scan01 || !Scan02)
    return
  static init, MFCopyImage
  if !VarSetCapacity(init) && (init:="1")
  {
    MFCopyImage:=DllCall("GetProcAddress", "Ptr"
    , DllCall("LoadLibrary", "Str","Mfplat.dll", "Ptr")
    , "AStr","MFCopyImage", "Ptr")
  }
  if (MFCopyImage && !Reverse)  ; thanks QQ:121507989
  {
    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
  SetBatchLines % (bch:=A_BatchLines)?"-1":"-1"
  p1:=Scan01+(y1-1)*Stride1+x1*4
  , p2:=Scan02+(y2-1)*Stride2+x2*4, w*=4
  , (Reverse) && (p2+=(h+1)*Stride2, Stride2:=-Stride2)
  Loop % h
    DllCall("RtlMoveMemory","Ptr",p1+=Stride1,"Ptr",p2+=Stride2,"Ptr",w)
  SetBatchLines % bch
  ListLines % lls
}

DrawHBM(hBM, lines)
{
  local
  mDC:=DllCall("CreateCompatibleDC", "Ptr",0, "Ptr")
  oBM:=DllCall("SelectObject", "Ptr",mDC, "Ptr",hBM, "Ptr")
  oldc:="", brush:=0, VarSetCapacity(rect, 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)
{
  local
  (!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)
    {
      WinGet, i, ExStyle, ahk_id %bind_id%
      bind.oldStyle:=i
      WinSet, Transparent, 255, ahk_id %bind_id%
      Loop 30
      {
        Sleep 100
        WinGet, i, Transparent, ahk_id %bind_id%
      }
      Until (i=255)
    }
  }
  else
  {
    bind_id:=bind.id
    if (bind.mode & 1)
      WinSet, ExStyle, % bind.oldStyle, ahk_id %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)
{
  local
  if (get_cursor)
    return this.Cursor
  if (hDC=1 || hDC=0) && (zw=0)
  {
    this.Cursor:=hDC
    return
  }
  VarSetCapacity(mi, 40, 0), NumPut(16+A_PtrSize, mi, "int")
  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 || y<zy || x>=zx+zw || y>=zy+zh)
    return
  VarSetCapacity(ni, 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(hex)
{
  local
  flag:=((hex~="[^A-Fa-f\d\s]") ? 1:4), len:=0
  Loop 2
    if !DllCall("crypt32\CryptStringToBinary", "Str",hex, "uint",0, "uint",flag
    , "Ptr",(A_Index=1?0:(p:=this.Buffer(len)).Ptr), "uint*",len, "Ptr",0, "Ptr",0)
      return
  if DllCall("VirtualProtect", "Ptr",p.Ptr, "Ptr",len, "uint",0x40, "uint*",0)
    return p
}

bin2hex(addr, size, base64:=0)
{
  local
  flag:=(base64 ? 1:4)|0x40000000, len:=0
  Loop 2
    DllCall("crypt32\CryptBinaryToString", "Ptr",addr, "uint",size, "uint",flag
    , "Ptr",(A_Index=1?0:(p:=this.Buffer(len*2)).Ptr), "uint*",len)
  return RegExReplace(StrGet(p.Ptr, len), "\s+")
}

base64tobit(s)
{
  local
  ListLines % (lls:=A_ListLines)?0:0
  Chars:="0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  SetFormat, IntegerFast, d
  Loop Parse, Chars
    if InStr(s, A_LoopField, 1)
      s:=RegExReplace(s, "[" A_LoopField "]", ((i:=A_Index-1)>>5&1)
      . (i>>4&1) . (i>>3&1) . (i>>2&1) . (i>>1&1) . (i&1))
  s:=RegExReplace(RegExReplace(s,"[^01]+"),"10*$")
  ListLines % lls
  return s
}

bit2base64(s)
{
  local
  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"
  SetFormat, IntegerFast, d
  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)
{
  local
  if RegExMatch(s, "O)\$(\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)
{
  local
  (!IsObject(this.Lib) && this.Lib:=[]), Lib:=this.Lib
  , (!Lib.HasKey(index) && Lib[index]:=[]), Lib:=Lib[index]
  if (add_to_Lib)
  {
    re:="O)<([^>\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))
        (s2!="") && Lib[s2]:=r[0]
      }
  }
  else
  {
    Text:=""
    Loop Parse, comments, |
    {
      s1:=Trim(A_LoopField), s2:=""
      Loop Parse, s1
        s2.=Format("_{:d}", Ord(A_LoopField))
      (Lib.HasKey(s2)) && Text.="|" Lib[s2]
    }
    return Text
  }
}

; 分割字符串为单个文字并获取数据

PicN(Number, index:=1)
{
  return this.PicLib(RegExReplace(Number,".","|$0"), 0, index)
}

; 使用 FindText().PicX(Text) 可以将文字分割成多个单字的组合,从而适应间隔变化
; 但是不能用于“颜色位置二值化”模式, 因为位置是与整体图像相关的

PicX(Text)
{
  local
  if !RegExMatch(Text, "O)(<[^$\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)
{
  local
  bits:=this.GetBitsFromScreen(,,,,0,zx,zy,zw,zh), x-=zx, y-=zy
  , c:=(x>=0 && x<zw && y>=0 && y<zh && bits.Scan0)
  ? NumGet(bits.Scan0+y*bits.Stride+x*4,"uint") : 0xFFFFFF
  return (fmt ? Format("0x{:06X}",c&0xFFFFFF) : c)
}

; 在“上一次的截屏”中设置点的RGB颜色

SetColor(x, y, color:=0x000000)
{
  local
  bits:=this.GetBitsFromScreen(,,,,0,zx,zy,zw,zh), x-=zx, y-=zy
  if (x>=0 && x<zw && y>=0 && y<zh && bits.Scan0)
    NumPut(color, bits.Scan0+y*bits.Stride+x*4, "uint")
}

; 根据 FindText() 的结果识别一行文字或验证码
; offsetX 为两个文字的最大间隔,超过会插入*号
; offsetY 为两个文字的最大高度差
; overlapW 用于设置覆盖的宽度
; 最后返回数组:{text:识别结果, x:结果左上角X, y:结果左上角Y, w:宽, h:高}

Ocr(ok, offsetX:=20, offsetY:=20, overlapW:=0)
{
  local
  ocr_Text:=ocr_X:=ocr_Y:=min_X:=dx:=""
  For k,v in ok
    x:=v.1
    , min_X:=(A_Index=1 || x<min_X ? x : min_X)
    , max_X:=(A_Index=1 || x>max_X ? x : max_X)
  While (min_X!="" && min_X<=max_X)
  {
    LeftX:=""
    For k,v in ok
    {
      x:=v.1, y:=v.2
      if (x<min_X) || (ocr_Y!="" && Abs(y-ocr_Y)>offsetY)
        Continue
      ; Get the leftmost X coordinates
      if (LeftX="" || x<LeftX)
        LeftX:=x, LeftY:=y, LeftW:=v.3, LeftH:=v.4, LeftOCR:=v.id
    }
    if (LeftX="")
      Break
    if (ocr_X="")
      ocr_X:=LeftX, min_Y:=LeftY, max_Y:=LeftY+LeftH
    ; If the interval exceeds the set value, add "*" to the result
    ocr_Text.=(ocr_Text!="" && LeftX>dx ? "*":"") . LeftOCR
    ; Update for next search
    min_X:=LeftX+LeftW-(overlapW>LeftW//2 ? LeftW//2:overlapW)
    , dx:=LeftX+LeftW+offsetX, ocr_Y:=LeftY
    , (LeftY<min_Y && min_Y:=LeftY)
    , (LeftY+LeftH>max_Y && max_Y:=LeftY+LeftH)
  }
  (ocr_X="") && ocr_X:=min_Y:=min_X:=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)
{
  local
  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:=Trim(s,"|")
  Sort, s, N D|
  ok2:=[]
  For k,v in StrSplit(s,"|")
    ok2.Push(ok[SubStr(v,InStr(v,".")+1)])
  return ok2
}

; 以指定点为中心,按从近到远排序FindText()的结果,返回排序后的数组

Sort2(ok, px, py)
{
  local
  if !IsObject(ok)
    return ok
  s:=""
  For k,v in ok
    s.=((v.x-px)**2+(v.y-py)**2) "." k "|"
  s:=Trim(s,"|")
  Sort, s, N D|
  ok2:=[]
  For k,v in StrSplit(s,"|")
    ok2.Push(ok[SubStr(v,InStr(v,".")+1)])
  return ok2
}

; 按指定的查找方向,排序FindText()的结果,返回排序后的数组

Sort3(ok, dir:=1)
{
  local
  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:=Trim(s,"|")
  Sort, s, N D|
  ok2:=[]
  For k,v in StrSplit(s,"|")
    ok2.Push(ok[SubStr(v,InStr(v,".")+1)])
  return ok2
}

; 提示某个坐标的位置,或远程控制中当前鼠标的位置

MouseTip(x:="", y:="", w:=10, h:=10, d:=3)
{
  local
  if (x="")
  {
    VarSetCapacity(pt,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, num:=1)
{
  local
  ListLines % (lls:=A_ListLines)?0:0
  static init, tab
  if !VarSetCapacity(init) && (init:="1")
    tab:=[]
  (!tab.HasKey(num) && tab[num]:=[0,0,0,0]), Range:=tab[num]
  if (x="")
  {
    if (Range[1])
    Loop 4
    {
      Gui, % Range[A_Index] ":Destroy"
      Range[A_Index]:=0
    }
    ListLines % lls
    return
  }
  if !(Range[1])
  {
    Loop 4
    {
      Gui, New, +Hwndid +AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000
      Range[A_Index]:=id
    }
  }
  x:=Floor(x), y:=Floor(y), w:=Floor(w), h:=Floor(h), d:=Floor(d)
  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)
    Gui, % Range[i] ":Color", %color%
    Gui, % Range[i] ":Show", NA x%x1% y%y1% w%w1% h%h1%
  }
  ListLines % lls
}

State(key)
{
  return GetKeyState(key,"P") || GetKeyState(key)
}

; 用鼠标左右键选取屏幕范围

GetRange(ww:=25, hh:=8, key:="RButton")
{
  local
  static init, KeyOff, hk
  if !VarSetCapacity(init) && (init:="1")
    KeyOff:=this.GetRange.Bind(this, "Off")
  if (ww=="Off")
    return hk:=Trim(A_ThisHotkey, "*")
  ;---------------------
  GetRange_HotkeyIf:=_Gui:=this.GuiNew()
  _Gui.Opt("-Caption +ToolWindow +E0x80000")
  _Gui.Title:="GetRange_HotkeyIf"
  _Gui.Show("NA x0 y0 w0 h0")
  ;---------------------
  if GetKeyState("Ctrl")
    Send {Ctrl Up}
  Hotkey, IfWinExist, GetRange_HotkeyIf
  keys:=key "|Up|Down|Left|Right"
  For k,v in StrSplit(keys, "|")
  {
    if GetKeyState(v)
      Send {%v% Up}
    Hotkey, *%v%, %KeyOff%, On UseErrorLevel
  }
  Hotkey, IfWinExist
  ;---------------------
  Critical % (cri:=A_IsCritical)?"Off":"Off"
  CoordMode, Mouse
  tip:=this.Lang("s5")
  hk:="", oldx:=oldy:="", keydown:=0
  Loop
  {
    Sleep 50
    MouseGetPos, x2, y2
    if (hk=key) || this.State(key) || this.State("Ctrl")
    {
      keydown++
      if (keydown=1)
        MouseGetPos, x1, y1, Bind_ID
      timeout:=A_TickCount+3000
      While (A_TickCount<timeout) && (this.State(key) || this.State("Ctrl"))
        Sleep 50
      hk:=""
      if (keydown>=2)
        Break
    }
    else if (hk="Up") || this.State("Up")
      (hh>1 && hh--), hk:=""
    else if (hk="Down") || this.State("Down")
      hh++, hk:=""
    else if (hk="Left") || this.State("Left")
      (ww>1 && ww--), hk:=""
    else if (hk="Right") || this.State("Right")
      ww++, hk:=""
    x:=(keydown?x1:x2), y:=(keydown?y1:y2)
    this.RangeTip(x-ww, y-hh, 2*ww+1, 2*hh+1, (A_MSec<500?"Red":"Blue"))
    if (oldx=x2 && oldy=y2)
      Continue
    oldx:=x2, oldy:=y2
    ToolTip % "x: " x " y: " y "`n" tip
  }
  ToolTip
  this.RangeTip()
  Hotkey, IfWinExist, GetRange_HotkeyIf
  For k,v in StrSplit(keys, "|")
    Hotkey, *%v%, %KeyOff%, Off UseErrorLevel
  Hotkey, IfWinExist
  GetRange_HotkeyIf.Destroy()
  Critical % cri
  return [x-ww, y-hh, x+ww, y+hh, Bind_ID]
}

GetRange2(key:="LButton")
{
  local
  FindText_GetRange:=_Gui:=this.GuiNew()
  _Gui.Opt("+LastFound +AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000")
  _Gui.BackColor:="White"
  WinSet, Transparent, 10
  this.GetBitsFromScreen(,,,,0,x,y,w,h)
  _Gui.Title:="FindText_GetRange"
  _Gui.Show("NA x" x " y" y " w" w " h" h)
  CoordMode, Mouse
  tip:=this.Lang("s7"), oldx:=oldy:=""
  Loop
  {
    Sleep 50
    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 this.State(key) || this.State("Ctrl")
  Loop
  {
    Sleep 50
    MouseGetPos, x2, y2
    x:=Min(x1,x2), y:=Min(y1,y2), w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+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 !(this.State(key) || this.State("Ctrl"))
  ToolTip
  this.RangeTip()
  FindText_GetRange.Destroy()
  Clipboard:=x "," y "," (x+w-1) "," (y+h-1)
  return [x, y, x+w-1, y+h-1]
}

BitmapFromScreen(ByRef x:=0, ByRef y:=0, ByRef w:=0, ByRef h:=0
  , ScreenShot:=1, ByRef zx:=0, ByRef zy:=0, ByRef zw:=0, ByRef zh:=0)
{
  local
  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)
{
  local
  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)
{
  local
  if hBM_or_file is number
    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
  }
  VarSetCapacity(dib, dib_size:=(A_PtrSize=8 ? 104:84), 0)
  , DllCall("GetObject", "Ptr",hBM, "int",dib_size, "Ptr",&dib)
  , pbi:=&dib+(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")
    DllCall("SetClipboardData", "uint",8, "Ptr",hdib)
    DllCall("CloseClipboard")
  }
  else
  {
    if InStr(file,"\") && !FileExist(dir:=RegExReplace(file,"[^\\]*$"))
      Try FileCreateDir, % dir
    VarSetCapacity(bf, 14, 0), NumPut(0x4D42, bf, "short")
    NumPut(54+size, bf, 2, "uint"), NumPut(54, bf, 10, "uint")
    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, ByRef x:="", ByRef y:="", ByRef w:="", ByRef h:="")
{
  local
  if (file="")
  {
    this.ShowScreenShot()
    return
  }
  if !(hBM:=LoadPicture(file))
    return
  this.GetBitmapWH(hBM, w, h)
  bits:=this.GetBitsFromScreen(,,,,0,x,y,zw,zh)
  this.UpdateBits(bits, x, y, Max(w,zw), Max(h,zh))
  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)
  return 1
}

; 显示内存中的屏幕截图用于调试

ShowScreenShot(x1:=0, y1:=0, x2:=0, y2:=0, ScreenShot:=1)
{
  local
  static init, hPic, oldx, oldy, oldw, oldh, FindText_Screen
  if !VarSetCapacity(init) && (init:="1")
    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:=this.GuiNew()  ; WS_EX_NOACTIVATE:=0x08000000
    _Gui.Opt("+AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000")
    _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)
{
  local
  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:=0, y1:=0, x2:=0, y2:=0, Threshold:=""
  , ScreenShot:=1, ByRef rx:="", ByRef ry:="", cut:=1)
{
  local
  if (x1=0 && y1=0 && x2=0 && y2=0)
    return this.Gui("CaptureS", ScreenShot)
  SetBatchLines % (bch:=A_BatchLines)?"-1":"-1"
  x1:=this.Floor(x1), y1:=this.Floor(y1), x2:=this.Floor(x2), y2:=this.Floor(y2)
  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)
  if (w<1 || h<1 || !bits.Scan0)
  {
    SetBatchLines % bch
    return
  }
  ListLines % (lls:=A_ListLines)?0:0
  gs:=[]
  j:=bits.Stride-w*4, p:=bits.Scan0+(y-zy)*bits.Stride+(x-zx)*4-j-4
  Loop % h + 0*(k:=0)
  Loop % w + 0*(p+=j)
    c:=NumGet(0|p+=4,"uint")
    , gs[++k]:=(((c>>16)&0xFF)*38+((c>>8)&0xFF)*75+(c&0xFF)*15)>>7
  if InStr(Threshold,"**")
  {
    Threshold:=Trim(Threshold,"* "), (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:=gs[i]+Threshold
      , s.=( gs[i-1]>j || gs[i+1]>j
      || gs[i-sw]>j || gs[i+sw]>j
      || gs[i-sw-1]>j || gs[i-sw+1]>j
      || gs[i+sw-1]>j || gs[i+sw+1]>j ) ? "1":"0"
    Threshold:="**" Threshold
  }
  else
  {
    Threshold:=Trim(Threshold,"* ")
    if (Threshold="")
    {
      pp:=[]
      Loop 256
        pp[A_Index-1]:=0
      Loop % w*h
        pp[gs[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.=gs[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)
  ;--------------------
  SetBatchLines % bch
  return s
}

; 等待几秒钟直到屏幕图像改变,需要先调用FindText().ScreenShot()

WaitChange(time:=-1, x1:=0, y1:=0, x2:=0, y2:=0)
{
  local
  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)
{
  local
  oldhash:="", time:=this.Floor(time)
  , 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(time*1000)
    if (t>=timeout2)
      return 1
    if (t>=timeout)
      return 0
    Sleep 100
  }
}

GetPicHash(x1:=0, y1:=0, x2:=0, y2:=0, ScreenShot:=1)
{
  local
  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
  ListLines % (lls:=A_ListLines)?0:0
  Loop % h
    hash:=(hash*31+DllCall("ntdll\RtlComputeCrc32", "uint",0
      , "Ptr",p+=Stride, "uint",w, "uint"))&0xFFFFFFFF
  ListLines % lls
  return hash
}

WindowToScreen(ByRef x, ByRef y, x1, y1, id:="")
{
  local
  if (!id)
    WinGet, id, ID, A
  VarSetCapacity(rect, 16, 0)
  , DllCall("GetWindowRect", "Ptr",id, "Ptr",&rect)
  , x:=x1+NumGet(rect,"int"), y:=y1+NumGet(rect,4,"int")
}

ScreenToWindow(ByRef x, ByRef y, x1, y1, id:="")
{
  local
  this.WindowToScreen(dx, dy, 0, 0, id), x:=x1-dx, y:=y1-dy
}

ClientToScreen(ByRef x, ByRef y, x1, y1, id:="")
{
  local
  if (!id)
    WinGet, id, ID, A
  VarSetCapacity(pt, 8, 0), NumPut(0, pt, "int64")
  , DllCall("ClientToScreen", "Ptr",id, "Ptr",&pt)
  , x:=x1+NumGet(pt,"int"), y:=y1+NumGet(pt,4,"int")
}

ScreenToClient(ByRef x, ByRef y, x1, y1, id:="")
{
  local
  this.ClientToScreen(dx, dy, 0, 0, id), x:=x1-dx, y:=y1-dy
}

; 不像 FindText 总是使用屏幕坐标,它使用与内置命令
; PixelGetColor 一样的 CoordMode 设置的坐标模式

PixelGetColor(x, y, ScreenShot:=1, id:="")
{
  if (A_CoordModePixel="Window")
    this.WindowToScreen(x, y, x, y, id)
  else if (A_CoordModePixel="Client")
    this.ClientToScreen(x, y, x, y, id)
  if (ScreenShot)
    this.ScreenShot(x, y, x, y)
  return this.GetColor(x, y)
}

; 不像 FindText 总是使用屏幕坐标,它使用与内置命令
; ImageSearch 一样的 CoordMode 设置的坐标模式
; 图片文件参数可以使用 "*n *TransBlack/White/RRGGBB-DRDGDB... d:\a.bmp"

ImageSearch(ByRef rx:="", ByRef ry:="", x1:=0, y1:=0, x2:=0, y2:=0
  , ImageFile:="", ScreenShot:=1, FindAll:=0, dir:=1)
{
  local
  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, "O)(^|\s)\*(\d+)\s", r)
    ? Format("{:06X}", r[2]<<16|r[2]<<8|r[2]) : "000000")
    . (RegExMatch(v, "Oi)(^|\s)\*Trans(\S+)\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,,,, dir))
  {
    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, ErrorLevel:=0
    return ok
  }
  else
  {
    rx:=ry:="", ErrorLevel:=1
    return 0
  }
}

; 不像 FindText 总是使用屏幕坐标,它使用与内置命令
; PixelSearch 一样的 CoordMode 设置的坐标模式
; 颜色参数可以是 "RRGGBB-DRDGDB|RRGGBB-DRDGDB", Variation 取值 0-255

PixelSearch(ByRef rx:="", ByRef ry:="", x1:=0, y1:=0, x2:=0, y2:=0
  , ColorID:="", Variation:=0, ScreenShot:=1, FindAll:=0, dir:=1)
{
  local
  n:=this.Floor(Variation), text:=Format("##{:06X}$0/0/", n<<16|n<<8|n)
  . Trim(StrReplace(ColorID, "|", "/"), "- /")
  return this.ImageSearch(rx, ry, x1, y1, x2, y2, text, ScreenShot, FindAll, dir)
}

; 屏幕坐标指示的范围内的某些颜色的像素计数
; 颜色参数可以是 "RRGGBB-DRDGDB|RRGGBB-DRDGDB", Variation 取值 0-255

PixelCount(x1:=0, y1:=0, x2:=0, y2:=0, ColorID:="", Variation:=0, ScreenShot:=1)
{
  local
  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, VarSetCapacity(s1,4), VarSetCapacity(s0,4), VarSetCapacity(ss,w*(h+3))
  ini:={ bits:bits, ss:&ss, s1:&s1, s0:&s0, allpos:0, allpos_max:0
    , err1:0, err0:0, zoomW:1, zoomH:1 }
  n:=this.Floor(Variation), text:=Format("##{:06X}$0/0/", n<<16|n<<8|n)
  . Trim(StrReplace(ColorID, "|", "/"), "- /")
  if IsObject(j:=this.PicInfo(text))
    sum:=this.PicFind(ini, j, 1, x, y, w, h)
  return sum
}

; 创建包含特定颜色的色块,可以限定这个色块中符合颜色的数量
; ColorID 可以使用 "RRGGBB-DRDGDB|RRGGBB-DRDGDB", "*128", "**50"
; Count1, Count0 是这个色块二值化后黑点和白点的数量最小值

ColorBlock(ColorID, w, h, Count1:=0, Count0:=0)
{
  local
  (Count0>0 && Count1:=0)
  Text:="|<>[" (1-Count1/(w*h)) "," (1-Count0/(w*h)) "]"
  . Trim(StrReplace(ColorID,"|","/"),"- /") . Format("${:d}.",w)
  . this.bit2base64(StrReplace(Format(Format("{{}:0{:d}d{}}",w*h),0),"0"
  , (Count0>0 ? "0":"1")))
  return Text
}

Click(x:="", y:="", other1:="", other2:="", GoBack:=0)
{
  local
  CoordMode, Mouse, % (bak:=A_CoordModeMouse)?"Screen":"Screen"
  if GoBack
    MouseGetPos, oldx, oldy
  MouseMove, x, y, 0
  Sleep 30
  Click % x "," y "," other1 "," other2
  if GoBack
    MouseMove, oldx, oldy, 0
  CoordMode, Mouse, %bak%
  return 1
}

; 动态运行AHK代码作为新线程

Class Thread
{
  __New(args*)
  {
    this.pid:=this.Exec(args*)
  }
  __Delete()
  {
    Process, Close, % this.pid
  }
  Exec(s, Ahk:="", args:="")    ; required AHK v1.1.34+ and Ahk2Exe Use .exe
  {
    local
    Ahk:=Ahk ? Ahk : A_IsCompiled ? A_ScriptFullPath : A_AhkPath
    s:="`nDllCall(""SetWindowText"",""Ptr"",A_ScriptHwnd,""Str"",""<AHK>"")`n"
      . "`nSetBatchLines,-1`n" . s, s:=RegExReplace(s, "\R", "`r`n")
    Try
    {
      shell:=ComObjCreate("WScript.Shell")
      oExec:=shell.Exec("""" Ahk """ /script /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%" /script /force /CP0 "%f%" %args%,, UseErrorLevel, pid
    }
    return pid
  }
  Clear()
  {
    Try FileDelete % A_Temp "\~ahk.tmp"
    SetTimer,, Off
  }
}

; FindText().QPC() 用法类似于 A_TickCount

QPC()
{
  static init, f, c
  if !VarSetCapacity(init) && (init:="1")
    f:=0, c:=DllCall("QueryPerformanceFrequency", "Int64*",f)+(f/=1000)
  return (!DllCall("QueryPerformanceCounter","Int64*",c))*0+(c/f)
}

; FindText().ToolTip() 用法类似于 ToolTip

ToolTip(s:="", x:="", y:="", num:=1, arg:="")
{
  local
  static init, ini, tip, timer
  if !VarSetCapacity(init) && (init:="1")
    ini:=[], tip:=[], timer:=[]
  f:="ToolTip_" . this.Floor(num)
  if (s="")
  {
    Try tip[f].Destroy()
    ini[f]:="", tip[f]:=""
    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))
  ;-----------------
  bgcolor:=arg.bgcolor!="" ? arg.bgcolor : "FAFBFC"
  color:=arg.color!="" ? arg.color : "Black"
  font:=arg.font ? arg.font : "Consolas"
  size:=arg.size ? arg.size : "10"
  bold:=arg.bold ? arg.bold : ""
  trans:=arg.trans!="" ? arg.trans & 255 : 255
  timeout:=arg.timeout!="" ? arg.timeout : ""
  ;-----------------
  r:=bgcolor "|" color "|" font "|" size "|" bold "|" trans "|" s
  if (!ini.HasKey(f) || ini[f]!=r)
  {
    ini[f]:=r
    Try tip[f].Destroy()
    tip[f]:=_Gui:=this.GuiNew()  ; WS_EX_LAYERED:=0x80000, WS_EX_TRANSPARENT:=0x20
    _Gui.Opt("+LastFound +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")
    WinSet, Transparent, % trans
  }
  tip[f].Opt("+AlwaysOnTop")
  tip[f].Show("NA " x " " y)
  if (timeout)
  {
    (!timer.HasKey(f) && timer[f]:=this.ToolTip.Bind(this,"","","",num))
    , r:=timer[f]
    SetTimer % r, % -Round(Abs(this.Floor(timeout)*1000))-1
  }
}

; FindText().ObjView() 查看对象的值用于调试

ObjView(obj, keyname:="")
{
  local
  if IsObject(obj)  ; thanks lexikos's type(v)
  {
    s:=""
    For k,v in obj
      s.=this.ObjView(v, keyname "[" (StrLen(k)>1000
      || [k].GetCapacity(1) ? """" k """":k) "]")
  }
  else
    s:=keyname ": " (StrLen(obj)>1000
    || [obj].GetCapacity(1) ? """" obj """":obj) "`n"
  if (keyname!="")
    return s
  ;------------------
  _Gui:=this.GuiNew("+AlwaysOnTop")
  _Gui.Add("Button", "y270 w350 gCancel Default", "OK")
  _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 " _Gui.Hwnd
  _Gui.Destroy()
}

EditScroll(hEdit, regex:="", line:=0, pos:=0)
{
  local
  ControlGetText, s,, ahk_id %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,, ahk_id %hEdit%
  SendMessage, 0xB7,,,, ahk_id %hEdit%
}

LastCtrl()
{
  local
  return (G:=this.GuiFromHwnd(WinExist()))[G.LastHwnd]
}

Hide(args*)
{
  WinMinimize
  WinHide
  ToolTip
  DetectHiddenWindows 0
  WinWaitClose % "ahk_id " WinExist()
}

SC(RGB, hwnd)
{
  SendMessage,0x2001,0,(RGB&0xFF)<<16|RGB&0xFF00|(RGB>>16)&0xFF,,% "ahk_id " hwnd
}


;==== Optional GUI interface ====


Gui(cmd, arg1:="", args*)
{
  local
  static
  local bch, cri, lls, _Gui
  ListLines % InStr("MouseMove|ToolTipOff",cmd)?0:A_ListLines
  static init
  if !VarSetCapacity(init) && (init:="1")
  {
    SavePicDir:=A_Temp "\Ahk_ScreenShot\"
    G_ := this.Gui.Bind(this)
    G_G := this.Gui.Bind(this, "G")
    G_Run := this.Gui.Bind(this, "Run")
    G_Show := this.Gui.Bind(this, "Show")
    G_KeyDown := this.Gui.Bind(this, "KeyDown")
    G_LButtonDown := this.Gui.Bind(this, "LButtonDown")
    G_RButtonDown := this.Gui.Bind(this, "RButtonDown")
    G_MouseMove := this.Gui.Bind(this, "MouseMove")
    G_ScreenShot := this.Gui.Bind(this, "ScreenShot")
    G_ShowPic := this.Gui.Bind(this, "ShowPic")
    G_Slider := this.Gui.Bind(this, "Slider")
    G_ToolTip := this.Gui.Bind(this, "ToolTip")
    G_ToolTipOff := this.Gui.Bind(this, "ToolTipOff")
    G_SaveScr := this.Gui.Bind(this, "SaveScr")
    G_PicShowOK := this.Gui.Bind(this, "PicShowOK")
    G_Drag := this.Gui.Bind(this, "Drag")
    FindText_Capture:=FindText_Main:=""
    PrevControl:=x:=y:=oldx:=oldy:=""
    Pics:=[], hBM_old:=dx:=dy:=0
    bch:=A_BatchLines, cri:=A_IsCritical
    Critical
    #NoEnv
    Lang:=this.Lang(,1), Tip_Text:=this.Lang(,2)
    G_.Call("MakeCaptureWindow")
    G_.Call("MakeMainWindow")
    OnMessage(0x100, G_KeyDown)
    OnMessage(0x201, G_LButtonDown)
    OnMessage(0x204, G_RButtonDown)
    OnMessage(0x200, G_MouseMove)
    Menu, Tray, Add
    Menu, Tray, Add, % Lang["s1"], % G_Show
    if (!A_IsCompiled && A_LineFile=A_ScriptFullPath)
    {
      Menu, Tray, Default, % Lang["s1"]
      Menu, Tray, Click, 1
      Menu, Tray, Icon, Shell32.dll, 23
    }
    Critical % cri
    SetBatchLines % bch
    this.GuiNew("+LastFound").Destroy()
  }
  Switch cmd
  {
  Case "G":
    id:=this.LastCtrl()
    Try id.OnEvent("Click", G_Run)
    Catch
      Try id.OnEvent("Change", G_Run)
    return
  Case "Run":
    Critical
    G_.Call(arg1.Name)
    return
  Case "Show":
    FindText_Main.Show(arg1 ? "Center" : "")
    ControlFocus,, % "ahk_id " hscr
    return
  Case "Cancel", "Cancel2":
    WinHide
    return
  Case "MakeCaptureWindow":
    WindowColor:="0xDDEEFF"
    Try FindText_Capture.Destroy()
    FindText_Capture:=_Gui:=this.GuiNew()
    _Gui.Opt("+LastFound +AlwaysOnTop -DPIScale")
    _Gui.MarginX:=15, _Gui.MarginY:=10
    _Gui.BackColor:=WindowColor
    _Gui.SetFont("s12", "Verdana")
    Tab:=_Gui.Add("Tab3", "vMyTab1 -Wrap", StrSplit(Lang["s18"],"|"))
    Tab.UseTab(1)
    C_:=[], Cid_:=[]
    , nW:=71, nH:=25, w:=h:=12, pW:=nW*(w+1)-1, pH:=(nH+1)*(h+1)-1
    id:=_Gui.Add("Text", "w" pW " h" pH), Cid_[id.Hwnd]:=-1
    _Gui.Opt("-Theme")
    ListLines % (lls:=A_ListLines)?0:0
    Loop % nW*(nH+1)
    {
      i:=A_Index, j:=i=1 ? "xp yp Section" : Mod(i,nW)=1 ? "xs y+1":"x+1"
      id:=_Gui.Add("Progress", j " w" w " h" h " -E0x20000 Smooth")
      C_[i]:=id.Hwnd, Cid_[id.Hwnd]:=i
    }
    ListLines % lls
    _Gui.Opt("+Theme")
    _Gui.Add("Slider", "xs w" pW " vMySlider1 +Center Page20 Line10 NoTicks AltSubmit")
    G_G.Call()
    _Gui.Add("Slider", "ys h" pH " vMySlider2 +Center Page20 Line10 NoTicks AltSubmit +Vertical")
    G_G.Call()
    Tab.UseTab(2)
    id:=_Gui.Add("Pic", "w" (pW-135) " h" pH " +Border -Background Section"), hPic:=id.Hwnd
    Pic_hBM:=this.CreateDIBSection(Pic_w:=(pW-135), Pic_h:=pH)
    _Gui.Add("Slider", "xs wp vMySlider3 +Center Page20 Line10 NoTicks AltSubmit")
    G_G.Call()
    _Gui.Add("Slider", "ys h" pH " vMySlider4 +Center Page20 Line10 NoTicks AltSubmit +Vertical")
    G_G.Call()
    _Gui.Add("ListBox", "ys w120 h200 vSelectBox AltSubmit 0x100")
    G_G.Call()
    _Gui.Add("Button", "y+0 wp vClearAll", Lang["ClearAll"])
    G_G.Call()
    _Gui.Add("Button", "y+0 wp vOpenDir", Lang["OpenDir"])
    G_G.Call()
    _Gui.Add("Button", "y+0 wp vLoadPic", Lang["LoadPic"])
    G_G.Call()
    _Gui.Add("Button", "y+0 wp vSavePic", Lang["SavePic"])
    G_G.Call()
    Tab.UseTab()
    ;--------------
    _Gui.Add("Text", "xm Section", Lang["SelGray"])
    _Gui.Add("Edit", "x+5 yp-3 w80 vSelGray ReadOnly")
    _Gui.Add("Text", "x+15 ys", Lang["SelColor"])
    _Gui.Add("Edit", "x+5 yp-3 w150 vSelColor ReadOnly")
    _Gui.Add("Text", "x+15 ys", Lang["SelR"])
    _Gui.Add("Edit", "x+5 yp-3 w80 vSelR ReadOnly")
    _Gui.Add("Text", "x+5 ys", Lang["SelG"])
    _Gui.Add("Edit", "x+5 yp-3 w80 vSelG ReadOnly")
    _Gui.Add("Text", "x+5 ys", Lang["SelB"])
    _Gui.Add("Edit", "x+5 yp-3 w80 vSelB ReadOnly")
    ;--------------
    id:=_Gui.Add("Button", "xm Hidden Section", Lang["Auto"])
    id.GetPos(pX, pY, pW, pH)
    w:=Round(pW*0.75), i:=Round(w*3+15+pW*0.5-w*1.5)
    _Gui.Add("Button", "xm+" i " yp w" w " hp -Wrap vRepU", Lang["RepU"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutU", Lang["CutU"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutU3", Lang["CutU3"])
    G_G.Call()
    _Gui.Add("Button", "xm wp hp -Wrap vRepL", Lang["RepL"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutL", Lang["CutL"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutL3", Lang["CutL3"])
    G_G.Call()
    _Gui.Add("Button", "x+15 w" pW " hp -Wrap vAuto", Lang["Auto"])
    G_G.Call()
    _Gui.Add("Button", "x+15 w" w " hp -Wrap vRepR", Lang["RepR"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutR", Lang["CutR"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutR3", Lang["CutR3"])
    G_G.Call()
    _Gui.Add("Button", "xm+" i " wp hp -Wrap vRepD", Lang["RepD"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutD", Lang["CutD"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutD3", Lang["CutD3"])
    G_G.Call()
    ;--------------
    Tab:=_Gui.Add("Tab3", "ys -Wrap", StrSplit(Lang["s2"],"|"))
    Tab.UseTab(1)
    _Gui.Add("Text", "x+30 y+35", Lang["Threshold"])
    _Gui.Add("Edit", "x+15 w100 vThreshold")
    _Gui.Add("Button", "x+15 yp-3 vGray2Two", Lang["Gray2Two"])
    G_G.Call()
    Tab.UseTab(2)
    _Gui.Add("Text", "x+30 y+35", Lang["GrayDiff"])
    _Gui.Add("Edit", "x+15 w100 vGrayDiff", "50")
    _Gui.Add("Button", "x+15 yp-3 vGrayDiff2Two", Lang["GrayDiff2Two"])
    G_G.Call()
    Tab.UseTab(3)
    _Gui.Add("Text", "x+10 y+15 Section", Lang["Similar1"] " 0")
    _Gui.Add("Slider", "x+0 w100 vSimilar1 +Center Page1 NoTicks ToolTip")
    G_G.Call()
    _Gui.Add("Text", "x+0", "100")
    _Gui.Add("Button", "x+10 ys-2 vAddColorSim", Lang["AddColorSim"])
    G_G.Call()
    _Gui.Add("Text", "x+25 ys+4", Lang["DiffRGB2"])
    _Gui.Add("Edit", "x+5 ys w80 vDiffRGB2 Limit3")
    _Gui.Add("UpDown", "vdRGB2 Range0-255 Wrap", 50)
    _Gui.Add("Button", "x+10 ys-2 vAddColorDiff", Lang["AddColorDiff"])
    G_G.Call()
    _Gui.Add("Button", "xs vUndo2", Lang["Undo2"])
    G_G.Call()
    _Gui.Add("Edit", "x+10 yp+2 w340 vColorList")
    _Gui.Add("Button", "x+10 yp-2 vColor2Two", Lang["Color2Two"])
    G_G.Call()
    Tab.UseTab(4)
    _Gui.Add("Text", "x+30 y+35", Lang["Similar2"] " 0")
    _Gui.Add("Slider", "x+0 w120 vSimilar2 +Center Page1 NoTicks ToolTip")
    G_G.Call()
    _Gui.Add("Text", "x+0", "100")
    _Gui.Add("Button", "x+15 yp-3 vColorPos2Two", Lang["ColorPos2Two"])
    G_G.Call()
    Tab.UseTab(5)
    _Gui.Add("Text", "x+30 y+15 Section", Lang["Similar3"] " 0")
    _Gui.Add("Slider", "x+0 w120 vSimilar3 +Center Page1 NoTicks ToolTip")
    G_G.Call()
    _Gui.Add("Text", "x+0", "100")
    _Gui.Add("Button", "x+15 ys-2 vUndo", Lang["Undo"])
    G_G.Call()
    _Gui.Add("Checkbox", "xs vMultiColor", Lang["MultiColor"])
    G_G.Call()
    _Gui.Add("Checkbox", "x+50 vFindShape", Lang["FindShape"])
    G_G.Call()
    Tab.UseTab()
    ;--------------
    _Gui.Add("Button", "xm vReset", Lang["Reset"])
    G_G.Call()
    _Gui.Add("Checkbox", "x+15 yp+5 vModify", Lang["Modify"])
    G_G.Call()
    _Gui.Add("Text", "x+30", Lang["Comment"])
    _Gui.Add("Edit", "x+5 yp-2 w250 vComment")
    _Gui.Add("Button", "x+10 yp-3 vSplitAdd", Lang["SplitAdd"])
    G_G.Call()
    _Gui.Add("Button", "x+10 vAllAdd", Lang["AllAdd"])
    G_G.Call()
    _Gui.Add("Button", "x+30 wp vOK", Lang["OK"])
    G_G.Call()
    _Gui.Add("Button", "x+15 wp vCancel", Lang["Cancel"])
    G_G.Call()
    _Gui.Add("Button", "xm vBind0", Lang["Bind0"])
    G_G.Call()
    _Gui.Add("Button", "x+10 vBind1", Lang["Bind1"])
    G_G.Call()
    _Gui.Add("Button", "x+10 vBind2", Lang["Bind2"])
    G_G.Call()
    _Gui.Add("Button", "x+10 vBind3", Lang["Bind3"])
    G_G.Call()
    _Gui.Add("Button", "x+10 vBind4", Lang["Bind4"])
    G_G.Call()
    _Gui.Add("Button", "x+30 vSavePic2", Lang["SavePic2"])
    G_G.Call()
    _Gui.Title:=Lang["s3"]
    _Gui.Show("Hide")
    _Gui.OnEvent("DropFiles", G_Drag)
    return
  Case "Drag":
    Try G_.Call("LoadPic", args[2][1])
    return
  Case "MakeMainWindow":
    Try FindText_Main.Destroy()
    FindText_Main:=_Gui:=this.GuiNew()
    _Gui.Opt("+LastFound +AlwaysOnTop -DPIScale")
    _Gui.MarginX:=15, _Gui.MarginY:=10
    _Gui.BackColor:=WindowColor
    _Gui.SetFont("s12", "Verdana")
    _Gui.Add("Text", "xm", Lang["NowHotkey"])
    _Gui.Add("Edit", "x+5 w160 vNowHotkey ReadOnly")
    _Gui.Add("Hotkey", "x+5 w160 vSetHotkey1")
    s:="F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|LWin|Ctrl|Shift|Space|MButton"
      . "|ScrollLock|CapsLock|Ins|Esc|BS|Del|Tab|Home|End|PgUp|PgDn"
      . "|NumpadDot|NumpadSub|NumpadAdd|NumpadDiv|NumpadMult"
    _Gui.Add("DDL", "x+5 w160 vSetHotkey2", StrSplit(s,"|"))
    _Gui.Add("Button", "x+15 vApply", Lang["Apply"])
    G_G.Call()
    _Gui.Add("GroupBox", "xm y+0 w280 h55 vMyGroup cBlack")
    _Gui.Add("Text", "xp+15 yp+20 Section", Lang["Myww"] ": ")
    _Gui.Add("Text", "x+0 w80", nW//2)
    _Gui.Add("UpDown", "vMyww Range1-100", nW//2)
    _Gui.Add("Text", "x+15 ys", Lang["Myhh"] ": ")
    _Gui.Add("Text", "x+0 w80", nH//2)
    id:=_Gui.Add("UpDown", "vMyhh Range1-100", nH//2)
    id.GetPos(pX, pY, pW, pH)
    _Gui["MyGroup"].Move(,, pX+pW, pH+30)
    id:=_Gui.Add("Checkbox", "x+100 ys vAddFunc", Lang["AddFunc"] " FindText()")
    id.GetPos(pX, pY, pW, pH)
    pW:=pX+pW-15, pW:=(pW<720?720:pW), w:=pW//5
    _Gui.Add("Button", "xm y+18 w" w " vCutL2", Lang["CutL2"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vCutR2", Lang["CutR2"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vCutU2", Lang["CutU2"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vCutD2", Lang["CutD2"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vUpdate", Lang["Update"])
    G_G.Call()
    _Gui.SetFont("s6 bold", "Verdana")
    _Gui.Add("Edit", "xm y+10 w" pW " h260 vMyPic -Wrap HScroll")
    _Gui.SetFont("s12 norm", "Verdana")
    w:=pW//3
    _Gui.Add("Button", "xm w" w " vCapture", Lang["Capture"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vTest", Lang["Test"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vCopy", Lang["Copy"])
    G_G.Call()
    _Gui.Add("Button", "xm y+0 wp vCaptureS", Lang["CaptureS"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vGetRange", Lang["GetRange"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vGetOffset", Lang["GetOffset"])
    G_G.Call()
    _Gui.Add("Edit", "xm y+10 w130 hp vClipText")
    _Gui.Add("Button", "x+0 vPaste", Lang["Paste"])
    G_G.Call()
    _Gui.Add("Button", "x+0 vTestClip", Lang["TestClip"])
    G_G.Call()
    id:=_Gui.Add("Button", "x+0 vGetClipOffset", Lang["GetClipOffset"])
    G_G.Call()
    id.GetPos(x,, w)
    w:=((pW+15)-(x+w))//2
    _Gui.Add("Edit", "x+0 w" w " hp vOffset")
    _Gui.Add("Button", "x+0 wp vCopyOffset", Lang["CopyOffset"])
    G_G.Call()
    _Gui.SetFont("cBlue")
    id:=_Gui.Add("Edit", "xm w" pW " h250 vscr -Wrap HScroll"), hscr:=id.Hwnd
    _Gui.Title:=Lang["s4"]
    _Gui.Show("Hide")
    G_.Call("LoadScr")
    OnExit(G_SaveScr)
    return
  Case "LoadScr":
    f:=A_Temp "\~scr1.tmp"
    FileRead, s, % f
    FindText_Main["scr"].Value:=s
    return
  Case "SaveScr":
    f:=A_Temp "\~scr1.tmp"
    s:=FindText_Main["scr"].Value
    Try FileDelete % f
    FileAppend % s, % f
    return
  Case "Capture", "CaptureS":
    _Gui:=FindText_Main
    if show_gui:=WinExist("ahk_id " _Gui.Hwnd)
      this.Hide()
    if (cmd="Capture")
    {
      w:=_Gui["Myww"].Value
      h:=_Gui["Myhh"].Value
      p:=this.GetRange(w, h)
      sx:=p[1], sy:=p[2], sw:=p[3]-p[1]+1, sh:=p[4]-p[2]+1
      , Bind_ID:=p[5], bind_mode:=""
      _Gui:=FindText_Capture
      _Gui["MyTab1"].Choose(1)
    }
    else
    {
      sx:=0, sy:=0, sw:=1, sh:=1, Bind_ID:=WinExist("A"), bind_mode:=""
      _Gui:=FindText_Capture
      _Gui["MyTab1"].Choose(2)
    }
    n:=150000, x:=y:=-n, w:=h:=2*n
    hBM:=this.BitmapFromScreen(x,y,w,h,(arg1=0?0:1))
    Pics:=[], Pics[hBM]:=1, hBM_x:=hBM_y:=0
    G_.Call("CaptureUpdate")
    G_.Call("PicUpdate")
    Names:=["HBITMAP:*" hBM], s:="<New>"
    Loop Files, % SavePicDir "*.bmp"
      Names.Push(v:=A_LoopFileFullPath), s.="|" RegExReplace(v,"i)^.*\\|\.bmp$")
    _Gui["SelectBox"].Delete()
    _Gui["SelectBox"].Add(StrSplit(Trim(s,"|"),"|"))
    ;------------------------
    s:="SelGray|SelColor|SelR|SelG|SelB|Threshold|Comment|ColorList"
    Loop Parse, s, |
      _Gui[A_LoopField].Value:=""
    For k,v in ["Similar1","Similar2","Similar3"]
      _Gui[v].Value:=90
    _Gui["Modify"].Value:=Modify:=0
    _Gui["MultiColor"].Value:=MultiColor:=0
    _Gui["FindShape"].Value:=FindShape:=0
    _Gui["GrayDiff"].Value:=50
    _Gui["Gray2Two"].Focus()
    _Gui["Gray2Two"].Opt("+Default")
    _Gui.Show("Center")
    Event:=Result:=""
    DetectHiddenWindows 0
    Critical, Off
    WinWaitClose % "ahk_id " _Gui.Hwnd
    Critical
    ToolTip
    Pics[hBM]:=1, hBM_old:=0
    For k,v in Pics
      Try DllCall("DeleteObject", "Ptr",k)
    Text:=RegExMatch(Result,"O)\|<[^>\n]*>[^$\n]+\$[^""\r\n]+",r)?r[0]:""
    ;------------------------
    _Gui:=FindText_Main
    if (bind_mode!="")
    {
      WinGetTitle, tt, ahk_id %Bind_ID%
      WinGetClass, tc, ahk_id %Bind_ID%
      tt:=Trim(SubStr(tt,1,30) (tc ? " ahk_class " tc:""))
      tt:=StrReplace(RegExReplace(tt,"[;``]","``$0"),"""","""""")
      Result:="`nSetTitleMatchMode 2`nid:=WinExist(""" tt """)"
        . "`nFindText().BindWindow(id" (bind_mode=0 ? "":"," bind_mode)
        . ")  `; " Lang["s6"] " FindText().BindWindow(0)`n`n" Result
    }
    if (Event="OK")
    {
      s:=""
      if (!A_IsCompiled)
        Try FileRead, s, %A_LineFile%
      re:="Oi)\n\s*FindText[^\n]+args\*[\s\S]*?Script_End[(){}\s]+}"
      s:=RegExMatch(s, re, r) ? "`n;==========`n" r[0] "`n" : ""
      _Gui["scr"].Value:=Result "`n" s
      _Gui["MyPic"].Value:=Trim(this.ASCII(Result),"`n")
    }
    else if (Event="SplitAdd" || Event="AllAdd")
    {
      s:=_Gui["scr"].Value
      r:=SubStr(s, 1, InStr(s,"=FindText("))
      i:=j:=0, re:="<[^>\n]*>[^$\n]+\$[^""\r\n]+"
      While j:=RegExMatch(r, re,, j+1)
        i:=InStr(r, "`n", 0, j)
      _Gui["scr"].Value:=SubStr(s,1,i) . Result . SubStr(s,i+1)
      _Gui["MyPic"].Value:=Trim(this.ASCII(Result),"`n")
    }
    if (Event) && RegExMatch(Result, "O)\$\d+\.[\w+/]{1,100}", r)
      this.EditScroll(hscr, "\Q" r[0] "\E")
    Event:=Result:=s:=""
    ;----------------------
    if (show_gui && arg1="")
      G_Show.Call()
    else Clipboard:=Text
    return Text
  Case "CaptureUpdate":
    nX:=sx, nY:=sy, nW:=sw, nH:=sh
    bits:=this.GetBitsFromScreen(nX,nY,nW,nH,0,zx,zy)
    cors:=[], show:=[], ascii:=[]
    , SelPos:=bg:=color:=Result:=""
    , dx:=dy:=CutLeft:=CutRight:=CutUp:=CutDown:=0
    ListLines % (lls:=A_ListLines)?0:0
    if (nW>0 && nH>0 && bits.Scan0)
    {
      j:=bits.Stride-nW*4, p:=bits.Scan0+(nY-zy)*bits.Stride+(nX-zx)*4-j-4
      Loop % nH + 0*(k:=0)
      Loop % nW + 0*(p+=j)
        show[++k]:=1, cors[k]:=NumGet(0|p+=4,"uint")
    }
    Loop % 25 + 0*(ty:=dy-1)*(k:=0)
    Loop % 71 + 0*(tx:=dx-1)*(ty++)
      this.SC(((++tx)<nW && ty<nH ? cors[ty*nW+tx+1]:WindowColor), C_[++k])
    Loop % 71 + 0*(k:=71*25)
      this.SC(0xFFFFAA, C_[++k])
    ListLines % lls
    _Gui:=FindText_Capture
    _Gui["MySlider1"].Enabled:=nW>71
    _Gui["MySlider2"].Enabled:=nH>25
    _Gui["MySlider1"].Value:=0
    _Gui["MySlider2"].Value:=0
    return
  Case "PicUpdate":
    Try i:=0, i:=Pics.HasKey(hBM_old)
    Try (!i) && DllCall("DeleteObject", "Ptr",hBM_old)
    this.GetBitmapWH(hBM, hBM_w, hBM_h), hBM_old:=hBM
    G_.Call("PicShow", 1)
    return
  Case "MySlider3", "MySlider4":
    hBM_x:=Round(FindText_Capture["MySlider3"].Value*(hBM_w-Pic_w)/100)
    hBM_y:=Round(FindText_Capture["MySlider4"].Value*(hBM_h-Pic_h)/100)
    G_.Call("PicShow")
    return
  Case "PicShow":
    w:=hBM_w-Pic_w, h:=hBM_h-Pic_h
    , hBM_x:=Max(Min(hBM_x,w),0), hBM_y:=Max(Min(hBM_y,h),0)
    if (w<0 || h<0)
      this.DrawHBM(Pic_hBM, [[0, 0, Pic_w, Pic_h, WindowColor]])
    this.CopyHBM(Pic_hBM,0,0,hBM,hBM_x,hBM_y,Min(Pic_w,hBM_w),Min(Pic_h,hBM_h))
    if (arg1)
      G_PicShowOK.Call()
    else
    {
      this.BitmapToWindow(hPic,0,0,Pic_hBM,0,0,Pic_w,Pic_h)
      SetTimer % G_PicShowOK, -1000
    }
    FindText_Capture["MySlider3"].Value:=w>0?Round(hBM_x/w*100):0
    FindText_Capture["MySlider4"].Value:=h>0?Round(hBM_y/h*100):0
    return
  Case "PicShowOK":
    FindText_Capture[hPic].Value:="*w0 *h0 HBITMAP:*" Pic_hBM
    return
  Case "Reset":
    G_.Call("CaptureUpdate")
    return
  Case "LoadPic":
    FindText_Capture.Opt("+OwnDialogs")
    f:=arg1
    if (f="")
    {
      if !FileExist(SavePicDir)
        FileCreateDir % SavePicDir
      f:=SavePicDir "*.bmp"
      Loop Files, % f
        f:=A_LoopFileFullPath
      FileSelectFile, f,, %f%, Select Picture
    }
    if !InStr(f,"HBITMAP:") && !FileExist(f)
    {
      MsgBox, 4096, Tip, % Lang["s17"]
      return
    }
    if !this.ShowPic(f, 0, sx, sy, sw, sh)
      return
    hBM:=this.BitmapFromScreen(sx, sy, sw, sh, 0)
    sw:=Min(sw,71), sh:=Min(sh,25)
    G_.Call("CaptureUpdate")
    G_.Call("PicUpdate")
    return
  Case "SavePic":
    FindText_Capture.Hide()
    this.ScreenShot(), this.ShowPic("HBITMAP:*" hBM)
    Try this.GuiFromHwnd(WinExist("Show Pic")).Opt("+OwnDialogs")
    Loop
    {
      p:=this.GetRange2()
      MsgBox, 4099, Tip, % Lang["s15"]
      IfMsgBox, No
        Continue
      Break
    }
    IfMsgBox, Yes
      G_.Call("ScreenShot", p[1] "|" p[2] "|" p[3] "|" p[4] "|0")
    this.ShowPic()
    return
  Case "SelectBox":
    SelectBox:=FindText_Capture["SelectBox"].Value
    Try f:="", f:=Names[SelectBox]
    if (f!="")
      G_.Call("LoadPic", f)
    return
  Case "ClearAll":
    FindText_Capture.Opt("+OwnDialogs")
    MsgBox, 4100, Tip, % Lang["s19"]
    IfMsgBox, Yes
    {
      FindText_Capture.Hide()
      FileDelete % SavePicDir "*.bmp"
    }
    return
  Case "OpenDir":
    if !FileExist(SavePicDir)
      FileCreateDir % SavePicDir
    Run % SavePicDir
    return
  Case "GetRange":
    _Gui:=FindText_Main
    _Gui.Opt("+LastFound")
    this.Hide()
    p:=this.GetRange2(), v:=p[1] ", " p[2] ", " p[3] ", " p[4]
    s:=_Gui["scr"].Value
    re:="i)(=FindText\([^\n]*?)([^(,\n]*,){4}([^,\n]*,[^,\n]*,[^,\n]*Text)"
    if SubStr(s,1,s~="i)\n\s*FindText[^\n]+args\*")~=re
    {
      s:=RegExReplace(s, re, "$1 " v ",$3",, 1)
      _Gui["scr"].Value:=s
    }
    _Gui["Offset"].Value:=v
    G_Show.Call()
    return
  Case "Test", "TestClip":
    _Gui:=FindText_Main
    _Gui.Opt("+LastFound")
    this.Hide()
    ;----------------------
    if (cmd="Test")
      s:=_Gui["scr"].Value
    else
      s:=_Gui["ClipText"].Value
    if (cmd="Test") && InStr(s, "MCode(")
    {
      s:="`n#NoEnv`nMenu, Tray, Click, 1`n" s "`nExitApp`n"
      Thread1:=new this.Thread(s)
      DetectHiddenWindows, 1
      WinWait % "ahk_class AutoHotkey ahk_pid " Thread1.pid,, 3
      if (!ErrorLevel)
        WinWaitClose,,, 30
      ; Thread1:=""  ; kill the Thread
    }
    else
    {
      t:=A_TickCount, v:=X:=Y:=""
      if RegExMatch(s, "O)<[^>\n]*>[^$\n]+\$[^""\r\n]+", r)
        v:=this.FindText(X, Y, 0,0,0,0, 0,0, r[0])
      r:=StrSplit(Lang["s8"] "||||", "|")
      MsgBox, 4096, Tip, % r[1] ":`t" (IsObject(v)?v.Length():v) "`n`n"
        . r[2] ":`t" (A_TickCount-t) " " r[3] "`n`n"
        . r[4] ":`t" X ", " Y "`n`n"
        . r[5] ":`t<" (IsObject(v)?v[1].id:"") ">", 3
      Try For i,j in v
        if (i<=2)
          this.MouseTip(j.x, j.y)
      v:="", Clipboard:=X "," Y
    }
    ;----------------------
    G_Show.Call()
    return
  Case "GetOffset", "GetClipOffset":
    FindText_Main.Hide()
    p:=this.GetRange()
    _Gui:=FindText_Main
    if (cmd="GetOffset")
      s:=_Gui["scr"].Value
    else
      s:=_Gui["ClipText"].Value
    if RegExMatch(s, "O)<[^>\n]*>[^$\n]+\$[^""\r\n]+", r)
    && this.FindText(X, Y, 0,0,0,0, 0,0, r[0])
    {
      r:=StrReplace("X+" ((p[1]+p[3])//2-X)
        . ", Y+" ((p[2]+p[4])//2-Y), "+-", "-")
      if (cmd="GetOffset")
      {
        re:="i)(\(\)\.\w*Click\w*\()[^,\n]*,[^,)\n]*"
        if SubStr(s,1,s~="i)\n\s*FindText[^\n]+args\*")~=re
          s:=RegExReplace(s, re, "$1" r,, 1)
        _Gui["scr"].Value:=s
      }
      _Gui["Offset"].Value:=r
    }
    s:="", G_Show.Call()
    return
  Case "Paste":
    if RegExMatch(Clipboard, "O)\|?<[^>\n]*>[^$\n]+\$[^""\r\n]+", r)
    {
      FindText_Main["ClipText"].Value:=r[0]
      FindText_Main["MyPic"].Value:=Trim(this.ASCII(r[0]),"`n")
    }
    return
  Case "CopyOffset":
    Clipboard:=FindText_Main["Offset"].Value
    return
  Case "Copy":
    ControlGet, s, Selected,,, ahk_id %hscr%
    if (s="")
    {
      s:=FindText_Main["scr"].Value
      r:=FindText_Main["AddFunc"].Value
      if (r != 1)
        s:=RegExReplace(s, "i)\n\s*FindText[^\n]+args\*[\s\S]*")
        , s:=RegExReplace(s, "i)\n; ok:=FindText[\s\S]*")
        , s:=SubStr(s, (s~="i)\n[ \t]*Text"))
    }
    Clipboard:=RegExReplace(s, "\R", "`r`n")
    ControlFocus,, % "ahk_id " hscr
    return
  Case "Apply":
    _Gui:=FindText_Main
    NowHotkey:=_Gui["NowHotkey"].Value
    SetHotkey1:=_Gui["SetHotkey1"].Value
    SetHotkey2:=_Gui["SetHotkey2"].Text
    if (NowHotkey!="")
      Hotkey, *%NowHotkey%,, Off UseErrorLevel
    k:=SetHotkey1!="" ? SetHotkey1 : SetHotkey2
    if (k!="")
      Hotkey, *%k%, %G_ScreenShot%, On UseErrorLevel
    _Gui["NowHotkey"].Value:=k
    _Gui["SetHotkey1"].Value:=""
    _Gui["SetHotkey2"].Choose(0)
    return
  Case "ScreenShot":
    Critical
    if !FileExist(SavePicDir)
      FileCreateDir % SavePicDir
    Loop
      f:=SavePicDir . Format("{:03d}.bmp",A_Index)
    Until !FileExist(f)
    this.SavePic(f, StrSplit(arg1,"|")*)
    CoordMode, ToolTip
    this.ToolTip(Lang["s9"],, 0,, { bgcolor:"Yellow", color:"Red"
      , size:48, bold:"bold", trans:200, timeout:0.2 })
    return
  Case "Bind0", "Bind1", "Bind2", "Bind3", "Bind4":
    this.BindWindow(Bind_ID, bind_mode:=SubStr(cmd,5))
    n:=150000, x:=y:=-n, w:=h:=2*n
    hBM:=this.BitmapFromScreen(x,y,w,h,1)
    G_.Call("PicUpdate")
    FindText_Capture["MyTab1"].Choose(2)
    this.BindWindow(0)
    return
  Case "MySlider1", "MySlider2":
    SetTimer % G_Slider, -10
    return
  Case "Slider":
    Critical
    dx:=nW>71 ? Round(FindText_Capture["MySlider1"].Value*(nW-71)/100):0
    dy:=nH>25 ? Round(FindText_Capture["MySlider2"].Value*(nH-25)/100):0
    if (oldx=dx && oldy=dy)
      return
    ListLines % (lls:=A_ListLines)?0:0
    Loop % 25 + 0*(ty:=dy-1)*(k:=0)
    Loop % 71 + 0*(tx:=dx-1)*(ty++)
      this.SC(((++tx)>=nW || ty>=nH || !show[i:=ty*nW+tx+1]
      ? WindowColor : bg="" ? cors[i] : ascii[i] ? 0:0xFFFFFF), C_[++k])
    Loop % 71*(oldx!=dx) + 0*(i:=nW*nH+dx)*(k:=71*25)
      this.SC((show[++i]?0xFF0000:0xFFFFAA), C_[++k])
    ListLines % lls
    oldx:=dx, oldy:=dy
    return
  Case "RepColor", "CutColor":
    if (cmd="RepColor")
      show[k]:=1, c:=(bg="" ? cors[k] : ascii[k] ? 0:0xFFFFFF)
    else
      show[k]:=0, c:=WindowColor
    if (tx:=Mod(k-1,nW)-dx)>=0 && tx<71 && (ty:=(k-1)//nW-dy)>=0 && ty<25
      this.SC(c, C_[ty*71+tx+1])
    return
  Case "RepL":
    if (CutLeft<=0) || (bg!="" && InStr(color,"**") && CutLeft=1)
      return
    k:=CutLeft-nW, CutLeft--
    Loop % nH
      k+=nW, (A_Index>CutUp && A_Index<nH+1-CutDown && G_.Call("RepColor"))
    return
  Case "CutL":
    if (CutLeft+CutRight>=nW)
      return
    CutLeft++, k:=CutLeft-nW
    Loop % nH
      k+=nW, (A_Index>CutUp && A_Index<nH+1-CutDown && G_.Call("CutColor"))
    return
  Case "CutL3":
    Loop 3
      G_.Call("CutL")
    return
  Case "RepR":
    if (CutRight<=0) || (bg!="" && InStr(color,"**") && CutRight=1)
      return
    k:=1-CutRight, CutRight--
    Loop % nH
      k+=nW, (A_Index>CutUp && A_Index<nH+1-CutDown && G_.Call("RepColor"))
    return
  Case "CutR":
    if (CutLeft+CutRight>=nW)
      return
    CutRight++, k:=1-CutRight
    Loop % nH
      k+=nW, (A_Index>CutUp && A_Index<nH+1-CutDown && G_.Call("CutColor"))
    return
  Case "CutR3":
    Loop 3
      G_.Call("CutR")
    return
  Case "RepU":
    if (CutUp<=0) || (bg!="" && InStr(color,"**") && CutUp=1)
      return
    k:=(CutUp-1)*nW, CutUp--
    Loop % nW
      k++, (A_Index>CutLeft && A_Index<nW+1-CutRight && G_.Call("RepColor"))
    return
  Case "CutU":
    if (CutUp+CutDown>=nH)
      return
    CutUp++, k:=(CutUp-1)*nW
    Loop % nW
      k++, (A_Index>CutLeft && A_Index<nW+1-CutRight && G_.Call("CutColor"))
    return
  Case "CutU3":
    Loop 3
      G_.Call("CutU")
    return
  Case "RepD":
    if (CutDown<=0) || (bg!="" && InStr(color,"**") && CutDown=1)
      return
    k:=(nH-CutDown)*nW, CutDown--
    Loop % nW
      k++, (A_Index>CutLeft && A_Index<nW+1-CutRight && G_.Call("RepColor"))
    return
  Case "CutD":
    if (CutUp+CutDown>=nH)
      return
    CutDown++, k:=(nH-CutDown)*nW
    Loop % nW
      k++, (A_Index>CutLeft && A_Index<nW+1-CutRight && G_.Call("CutColor"))
    return
  Case "CutD3":
    Loop 3
      G_.Call("CutD")
    return
  Case "Gray2Two":
    ListLines % (lls:=A_ListLines)?0:0
    gs:=[], k:=0
    Loop % nW*nH
      gs[++k]:=((((c:=cors[k])>>16)&0xFF)*38+((c>>8)&0xFF)*75+(c&0xFF)*15)>>7
    _Gui:=FindText_Capture
    _Gui["Threshold"].Focus()
    Threshold:=_Gui["Threshold"].Value
    if (Threshold="")
    {
      pp:=[]
      Loop 256
        pp[A_Index-1]:=0
      Loop % nW*nH
        if (show[A_Index])
          pp[gs[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
      }
      _Gui["Threshold"].Value:=Threshold
    }
    Threshold:=Round(Threshold)
    color:="*" Threshold, k:=i:=0
    Loop % nW*nH
      ascii[++k]:=v:=(gs[k]<=Threshold)
      , (show[k] && i:=(v?i+1:i-1))
    bg:=(i>0 ? "1":"0"), G_.Call("BlackWhite")
    ListLines % lls
    return
  Case "GrayDiff2Two":
    _Gui:=FindText_Capture
    GrayDiff:=_Gui["GrayDiff"].Value
    if (GrayDiff="")
    {
      _Gui.Opt("+OwnDialogs")
      MsgBox, 4096, Tip, % Lang["s11"], 1
      return
    }
    ListLines % (lls:=A_ListLines)?0:0
    gs:=[], k:=0
    Loop % nW*nH
      gs[++k]:=((((c:=cors[k])>>16)&0xFF)*38+((c>>8)&0xFF)*75+(c&0xFF)*15)>>7
    if (CutLeft=0)
      G_.Call("CutL")
    if (CutRight=0)
      G_.Call("CutR")
    if (CutUp=0)
      G_.Call("CutU")
    if (CutDown=0)
      G_.Call("CutD")
    GrayDiff:=Round(GrayDiff)
    color:="**" GrayDiff, k:=i:=0
    Loop % nW*nH
      j:=gs[++k]+GrayDiff
      , ascii[k]:=v:=( gs[k-1]>j || gs[k+1]>j
      || gs[k-nW]>j || gs[k+nW]>j
      || gs[k-nW-1]>j || gs[k-nW+1]>j
      || gs[k+nW-1]>j || gs[k+nW+1]>j )
      , (show[k] && i:=(v?i+1:i-1))
    bg:=(i>0 ? "1":"0"), G_.Call("BlackWhite")
    ListLines % lls
    return
  Case "AddColorSim", "AddColorDiff":
    _Gui:=FindText_Capture
    c:=StrReplace(_Gui["SelColor"].Value, "0x")
    if (c="")
    {
      _Gui.Opt("+OwnDialogs")
      MsgBox, 4096, Tip, % Lang["s12"], 1
      return
    }
    s:=_Gui["ColorList"].Value
    if InStr(cmd, "Sim")
      v:=_Gui["Similar1"].Value, v:=c "-" Round(v/100,2)
    else
      v:=_Gui["dRGB2"].Value, v:=c "-" Format("{:06X}",v<<16|v<<8|v)
    s:=RegExReplace("/" s, "/" c "-[^/]*") . "/" v
    _Gui["ColorList"].Value:=Trim(s,"/")
    ControlSend,, {End}, % "ahk_id " _Gui["ColorList"].Hwnd
    G_.Call("Color2Two")
    return
  Case "Undo2":
    _Gui:=FindText_Capture
    s:=_Gui["ColorList"].Value
    s:=RegExReplace("/" s, "/[^/]+$")
    _Gui["ColorList"].Value:=Trim(s,"/")
    ControlSend,, {End}, % "ahk_id " _Gui["ColorList"].Hwnd
    return
  Case "Color2Two":
    _Gui:=FindText_Capture
    color:=RegExReplace(_Gui["ColorList"].Value, "i)\s|0x")
    if (color="")
    {
      _Gui.Opt("+OwnDialogs")
      MsgBox, 4096, Tip, % Lang["s16"], 1
      return
    }
    ListLines % (lls:=A_ListLines)?0:0
    k:=i:=v:=0, arr:=StrSplit(Trim(StrReplace(color,"@","-"), "/"), "/")
    Loop % nW*nH
    {
      c:=cors[++k], rr:=(c>>16)&0xFF, gg:=(c>>8)&0xFF, bb:=c&0xFF
      For k1,v1 in arr
      {
        r:=StrSplit(Trim(v1,"-") "-", "-"), c:=this.ToRGB(r[1]), n:=r[2]
        , r:=((c>>16)&0xFF)-rr, g:=((c>>8)&0xFF)-gg, b:=(c&0xFF)-bb
        if InStr(n, ".")
        {
          n:=this.Floor(n), n:=(n<=0||n>1?0:Floor(9*255*255*(1-n)*(1-n)))
          if v:=(3*r*r+4*g*g+2*b*b<=n)
            Break
        }
        else
        {
          c:=this.Floor("0x" n), dR:=(c>>16)&0xFF, dG:=(c>>8)&0xFF, dB:=c&0xFF
          if v:=(Abs(r)<=dR && Abs(g)<=dG && Abs(b)<=dB)
            Break
        }
      }
      ascii[k]:=v, (show[k] && i:=(v?i+1:i-1))
    }
    bg:=(i>0 ? "1":"0"), G_.Call("BlackWhite")
    ListLines % lls
    return
  Case "ColorPos2Two":
    _Gui:=FindText_Capture
    c:=_Gui["SelColor"].Value
    if (c="")
    {
      _Gui.Opt("+OwnDialogs")
      MsgBox, 4096, Tip, % Lang["s12"], 1
      return
    }
    n:=_Gui["Similar2"].Value, n:=Round(n/100,2), color:="#" c "-" n
    , n:=(n<=0||n>1?0:Floor(9*255*255*(1-n)*(1-n)))
    , rr:=(c>>16)&0xFF, gg:=(c>>8)&0xFF, bb:=c&0xFF, k:=i:=0
    ListLines % (lls:=A_ListLines)?0:0
    Loop % nW*nH
      c:=cors[++k], r:=((c>>16)&0xFF)-rr, g:=((c>>8)&0xFF)-gg, b:=(c&0xFF)-bb
      , ascii[k]:=v:=3*r*r+4*g*g+2*b*b<=n, (show[k] && i:=(v?i+1:i-1))
    bg:=(i>0 ? "1":"0"), G_.Call("BlackWhite")
    ListLines % lls
    return
  Case "BlackWhite":
    Loop % 25 + 0*(ty:=dy-1)*(k:=0)
    Loop % 71 + 0*(tx:=dx-1)*(ty++)
    if (k++)*0 + (++tx)<nW && ty<nH && show[i:=ty*nW+tx+1]
      this.SC((ascii[i]?0:0xFFFFFF), C_[k])
    return
  Case "Modify":
    Modify:=FindText_Capture["Modify"].Value
    return
  Case "MultiColor":
    MultiColor:=FindText_Capture["MultiColor"].Value
    Result:=""
    ToolTip
    return
  Case "FindShape":
    FindShape:=FindText_Capture["FindShape"].Value
    (FindShape && !MultiColor) && FindText_Capture["MultiColor"].Value:=MultiColor:=1
    return
  Case "Undo":
    Result:=RegExReplace(Result, ",[^/]+/[^/]+/[^/]+$")
    ToolTip % Trim(Result, ",")
    return
  Case "Similar1", "Similar2", "Similar3":
    i:=FindText_Capture[cmd].Value
    For k,v in ["Similar1","Similar2","Similar3"]
      (v!=cmd) && FindText_Capture[v].Value:=i
    return
  Case "GetTxt":
    txt:=""
    if (bg="")
      return
    k:=0
    ListLines % (lls:=A_ListLines)?0:0
    Loop % nH
    {
      v:=""
      Loop % nW
        v.=!show[++k] ? "" : ascii[k] ? "1":"0"
      txt.=v="" ? "" : v "`n"
    }
    ListLines % lls
    return
  Case "Auto":
    G_.Call("GetTxt")
    if (txt="")
    {
      FindText_Capture.Opt("+OwnDialogs")
      MsgBox, 4096, Tip, % Lang["s13"], 1
      return
    }
    While InStr(txt,bg)
    {
      if (txt~="^" bg "+\n")
        txt:=RegExReplace(txt, "^" bg "+\n"), G_.Call("CutU")
      else if !(txt~="m`n)[^\n" bg "]$")
        txt:=RegExReplace(txt, "m`n)" bg "$"), G_.Call("CutR")
      else if (txt~="\n" bg "+\n$")
        txt:=RegExReplace(txt, "\n\K" bg "+\n$"), G_.Call("CutD")
      else if !(txt~="m`n)^[^\n" bg "]")
        txt:=RegExReplace(txt, "m`n)^" bg), G_.Call("CutL")
      else Break
    }
    txt:=""
    return
  Case "OK", "SplitAdd", "AllAdd":
    _Gui:=FindText_Capture
    _Gui.Opt("+OwnDialogs")
    G_.Call("GetTxt")
    if (txt="") && (!MultiColor)
    {
      MsgBox, 4096, Tip, % Lang["s13"], 1
      return
    }
    if InStr(color,"#") && (!MultiColor)
    {
      k:=i:=j:=0
      ListLines % (lls:=A_ListLines)?0:0
      Loop % nW*nH
      {
        if (!show[++k])
          Continue
        i++
        if (k=SelPos)
        {
          j:=i
          Break
        }
      }
      ListLines % lls
      if (j=0)
      {
        MsgBox, 4096, Tip, % Lang["s12"], 1
        return
      }
      color:="#" j "-" StrSplit(color "-","-")[2]
    }
    Comment:=_Gui["Comment"].Value
    if (cmd="SplitAdd") && (!MultiColor)
    {
      if InStr(color,"#")
      {
        MsgBox, 4096, Tip, % Lang["s14"], 3
        return
      }
      bg:=StrLen(StrReplace(txt,"0"))
        > StrLen(StrReplace(txt,"1")) ? "1":"0"
      s:="", i:=0, k:=nW*nH+1+CutLeft
      Loop % w:=nW-CutLeft-CutRight
      {
        i++
        if (!show[k++] && A_Index<w)
          Continue
        i:=Format("{:d}",i)
        v:=RegExReplace(txt,"m`n)^(.{" i "}).*","$1")
        txt:=RegExReplace(txt,"m`n)^.{" i "}"), i:=0
        While InStr(v,bg)
        {
          if (v~="^" bg "+\n")
            v:=RegExReplace(v,"^" bg "+\n")
          else if !(v~="m`n)[^\n" bg "]$")
            v:=RegExReplace(v,"m`n)" bg "$")
          else if (v~="\n" bg "+\n$")
            v:=RegExReplace(v,"\n\K" bg "+\n$")
          else if !(v~="m`n)^[^\n" bg "]")
            v:=RegExReplace(v,"m`n)^" bg)
          else Break
        }
        if (v!="")
        {
          v:=Format("{:d}.",InStr(v,"`n")-1) . this.bit2base64(v)
          s.="`nText.=""|<" SubStr(Comment,1,1) ">" color "$" v """`n"
          Comment:=SubStr(Comment, 2)
        }
      }
      Event:=cmd, Result:=s
      _Gui.Hide()
      return
    }
    if (!MultiColor)
      txt:=Format("{:d}.",InStr(txt,"`n")-1) . this.bit2base64(txt)
    else
    {
      n:=_Gui["Similar3"].Value, n:=Round(n/100,2), color:="##" n
      , n:=(n<=0||n>1?0:Floor(9*255*255*(1-n)*(1-n)))
      , arr:=StrSplit(Trim(StrReplace(Result,",","/"),"/"),"/"), s:="", i:=1
      SetFormat, IntegerFast, d
      Loop % arr.Length()//3
        x1:=arr[i++], y1:=arr[i++], c1:=arr[i++], c:="0x" c1
        , (A_Index=1 && (x:=x1, y:=y1, rr:=(c>>16)&0xFF, gg:=(c>>8)&0xFF, bb:=c&0xFF))
        , r:=((c>>16)&0xFF)-rr, g:=((c>>8)&0xFF)-gg, b:=(c&0xFF)-bb
        , s.="," (x1-x) "/" (y1-y) "/" (FindShape?3*r*r+4*g*g+2*b*b<=n:c1)
      txt:=SubStr(s,2)
    }
    s:="`nText.=""|<" Comment ">" color "$" txt """`n"
    if (cmd="SplitAdd" || cmd="AllAdd")
    {
      Event:=cmd, Result:=s
      _Gui.Hide()
      return
    }
    x:=nX+CutLeft+(nW-CutLeft-CutRight)//2
    y:=nY+CutUp+(nH-CutUp-CutDown)//2
    s:=StrReplace(s, "Text.=", "Text:="), r:=StrSplit(Lang["s8"] "|||||||", "|")
    s:="`; #Include <FindText>`n"
    . "`nt1:=A_TickCount, Text:=X:=Y:=""""`n" s
    . "`nif (ok:=FindText(X, Y, " x "-150000, "
    . y "-150000, " x "+150000, " y "+150000, 0, 0, Text))"
    . "`n{"
    . "`n  `; FindText()." . "Click(" . "X, Y, ""L"")"
    . "`n}`n"
    . "`n`; ok:=FindText(X:=""wait"", Y:=3, 0,0,0,0,0,0,Text)    `; " r[7]
    . "`n`; ok:=FindText(X:=""wait0"", Y:=-1, 0,0,0,0,0,0,Text)  `; " r[8]
    . "`n`nMsgBox, 4096, Tip, `% """ r[1] ":``t"" (IsObject(ok)?ok.Length():ok)"
    . "`n  . ""``n``n" r[2] ":``t"" (A_TickCount-t1) "" " r[3] """"
    . "`n  . ""``n``n" r[4] ":``t"" X "", "" Y"
    . "`n  . ""``n``n" r[5] ":``t<"" (IsObject(ok)?ok[1].id:"""") "">""`n"
    . "`nTry For i,v in ok  `; ok " r[6] " ok:=FindText().ok"
    . "`n  if (i<=2)"
    . "`n    FindText().MouseTip(ok[i].x, ok[i].y)`n"
    Event:=cmd, Result:=s
    _Gui.Hide()
    return
  Case "SavePic2":
    x:=nX+CutLeft, w:=nW-CutLeft-CutRight
    y:=nY+CutUp, h:=nH-CutUp-CutDown
    G_.Call("ScreenShot", x "|" y "|" (x+w-1) "|" (y+h-1) "|0")
    return
  Case "ShowPic":
    ControlGet, i, CurrentLine,,, ahk_id %hscr%
    ControlGet, s, Line, %i%,, ahk_id %hscr%
    FindText_Main["MyPic"].Value:=Trim(this.ASCII(s),"`n")
    return
  Case "KeyDown":
    Critical
    _Gui:=FindText_Main
    if (WinExist()!=_Gui.Hwnd)
      return
    Try ctrl:="", ctrl:=args[3]
    if (ctrl=hscr)
      SetTimer % G_ShowPic, -150
    else if (ctrl=_Gui["ClipText"].Hwnd)
    {
      s:=_Gui["ClipText"].Value
      _Gui["MyPic"].Value:=Trim(this.ASCII(s),"`n")
    }
    return
  Case "LButtonDown":
    Critical
    if (WinExist()!=FindText_Capture.Hwnd)
      return G_.Call("KeyDown", arg1, args*)
    CoordMode, Mouse
    MouseGetPos, k1, k2,, k6, 2
    if (k6=hPic)
    {
      ListLines % (lls:=A_ListLines)?0:0
      Loop
      {
        Sleep 50
        MouseGetPos, k3, k4
        this.RangeTip(Min(k1,k3), Min(k2,k4)
        , Abs(k1-k3)+1, Abs(k2-k4)+1, (A_MSec<500 ? "Red":"Blue"))
      }
      Until !this.State("LButton")
      ListLines % lls
      this.RangeTip()
      this.GetBitsFromScreen(,,,,0,zx,zy)
      this.ClientToScreen(sx, sy, 0, 0, hPic)
      sx:=Min(k1,k3)-sx+hBM_x+zx, sy:=Min(k2,k4)-sy+hBM_y+zy
      , sw:=Abs(k1-k3)+1, sh:=Abs(k2-k4)+1
      if (sw+sh)<5
        sx-=71//2, sy-=25//2, sw:=71, sh:=25
      G_.Call("CaptureUpdate")
      FindText_Capture["MyTab1"].Choose(1)
      return
    }
    if !(Cid_.HasKey(k6) && k5:=Cid_[k6])
      return
    if (k5=-1)
    {
      MouseMove, k1+2, k2+2, 0
      MouseGetPos,,,, k6, 2
      MouseMove, k1, k2, 0
      if !(Cid_.HasKey(k6) && k5:=Cid_[k6]) || (k5=-1)
        return
    }
    if (k5>71*25)
    {
      k1:=nW*nH+dx+(k5-71*25)
      this.SC(((show[k1]:=!show[k1])?0xFF0000:0xFFFFAA), k6)
      return
    }
    k3:=Mod(k5-1,71)+dx, k4:=(k5-1)//71+dy
    if (k3>=nW || k4>=nH)
      return
    k1:=k4*nW+k3+1
    if (Modify && bg!="" && show[k1])
      this.SC(((ascii[k1]:=!ascii[k1])?0:0xFFFFFF), k6)
    else
    {
      k2:=cors[k1], SelPos:=k1
      _Gui:=FindText_Capture
      _Gui["SelGray"].Value:=(((k2>>16)&0xFF)*38+((k2>>8)&0xFF)*75+(k2&0xFF)*15)>>7
      _Gui["SelColor"].Value:=Format("0x{:06X}",k2&0xFFFFFF)
      _Gui["SelR"].Value:=(k2>>16)&0xFF
      _Gui["SelG"].Value:=(k2>>8)&0xFF
      _Gui["SelB"].Value:=k2&0xFF
    }
    if (MultiColor && show[k1])
    {
      (FindShape && Result="") && G_.Call("ColorPos2Two")
      k2:=Format(",{:d}/{:d}/{:06X}", nX+k3, nY+k4, cors[k1]&0xFFFFFF)
      , Result.=InStr(Result,k2) ? "":k2
      ToolTip % Trim(Result, ",")
    }
    return
  Case "RButtonDown":
    Critical
    MouseGetPos,,,, k2, 2
    if (k2!=hPic)
      return
    CoordMode, Mouse
    MouseGetPos, k1, k2
    k5:=hBM_x, k6:=hBM_y
    ListLines % (lls:=A_ListLines)?0:0
    Loop
    {
      Sleep 10
      MouseGetPos, k3, k4
      hBM_x:=k5+k1-k3, hBM_y:=k6+k2-k4
      G_.Call("PicShow")
    }
    Until !this.State("RButton")
    ListLines % lls
    return
  Case "MouseMove":
    Try ctrl_name:="", ctrl_name:=this.GuiCtrlFromHwnd(args[3]).Name
    if (PrevControl != ctrl_name)
    {
      ToolTip
      PrevControl:=ctrl_name
      Try SetTimer % G_ToolTip, % (PrevControl ? -500:"Off")
      Try SetTimer % G_ToolTipOff, % (PrevControl ? -5500:"Off")
    }
    return
  Case "ToolTip":
    MouseGetPos,,, _TT
    if WinExist("ahk_id " _TT " ahk_class AutoHotkeyGUI")
      Try ToolTip % Tip_Text[PrevControl]
    return
  Case "ToolTipOff":
    ToolTip
    return
  Case "CutL2", "CutR2", "CutU2", "CutD2":
    s:=FindText_Main["MyPic"].Value
    s:=Trim(s,"`n") . "`n", v:=SubStr(cmd,4,1)
    if (v="U")
      s:=RegExReplace(s,"^[^\n]+\n")
    else if (v="D")
      s:=RegExReplace(s,"[^\n]+\n$")
    else if (v="L")
      s:=RegExReplace(s,"m`n)^[^\n]")
    else if (v="R")
      s:=RegExReplace(s,"m`n)[^\n]$")
    FindText_Main["MyPic"].Value:=Trim(s,"`n")
    return
  Case "Update":
    ControlFocus,, % "ahk_id " hscr
    ControlGet, i, CurrentLine,,, ahk_id %hscr%
    ControlGet, s, Line, %i%,, ahk_id %hscr%
    if !RegExMatch(s, "O)(<[^>\n]*>[^$\n]+\$)\d+\.[\w+/]+", r)
      return
    v:=FindText_Main["MyPic"].Value
    v:=Trim(v,"`n") . "`n", w:=Format("{:d}",InStr(v,"`n")-1)
    v:=StrReplace(StrReplace(v,"0","1"),"_","0")
    s:=StrReplace(s, r[0], r[1] . w "." this.bit2base64(v))
    v:="{End}{Shift Down}{Home}{Shift Up}{Del}"
    ControlSend,, %v%, ahk_id %hscr%
    Control, EditPaste, %s%,, ahk_id %hscr%
    ControlSend,, {Home}, ahk_id %hscr%
    return
  }
}

Lang(text:="", getLang:=0)
{
  local
  static init, Lang1, Lang2
  if !VarSetCapacity(init) && (init:="1")
  {
    s:="
    (
Myww       = 宽度 = 调整抓图范围的宽度
Myhh       = 高度 = 调整抓图范围的高度
AddFunc    = 附加 = 复制时带 FindText() 函数
NowHotkey  = 截屏热键 = 当前的截屏热键
SetHotkey1 = = 第一优先级的截屏热键
SetHotkey2 = = 第二优先级的截屏热键
Apply      = 应用 = 应用新的截屏热键
CutU2      = 上删 = 裁剪下面编辑框中文字的上边缘
CutL2      = 左删 = 裁剪下面编辑框中文字的左边缘
CutR2      = 右删 = 裁剪下面编辑框中文字的右边缘
CutD2      = 下删 = 裁剪下面编辑框中文字的下边缘
Update     = 更新 = 更新下面编辑框中文字到代码行中
GetRange   = 获取屏幕范围 = 获取屏幕范围到剪贴板并替换代码中的范围参数
GetOffset  = 获取相对坐标 = 获取相对图像位置的偏移坐标并替换代码中的点击坐标
GetClipOffset  = 获取相对坐标2 = 获取相对左边编辑框的图像的偏移坐标
Capture    = 抓图 = 开始屏幕抓图
CaptureS   = 截屏抓图 = 先截屏,然后显示截屏图像,再手动选择图像内的范围抓图
Test       = 测试 = 测试生成的代码是否可以查找成功
TestClip   = 测试2 = 测试左边文本框中的文字是否可以查找成功,结果复制到剪贴板
Paste      = 粘贴 = 粘贴剪贴板的文字数据
CopyOffset = 复制2 = 复制左边的偏移坐标到剪贴板
Copy       = 复制 = 复制代码到剪贴板
Reset      = 重读 = 重新读取原来的彩色图像
SplitAdd   = 分割添加 = 点击黄色的标签来分割图像为多个图像数据,添加到旧代码中
AllAdd     = 整体添加 = 将文字数据整体添加到旧代码中
Gray2Two      = 灰度阈值二值化 = 灰度小于阈值的为黑色其余白色
GrayDiff2Two  = 灰度差值二值化 = 某点与周围灰度之差大于差值的为黑色其余白色
Color2Two     = 颜色二值化 = 通过颜色列表来转换图像为黑白图
ColorPos2Two  = 颜色位置二值化 = 指定颜色及相似色为黑色其余白色,但是记录该色的位置
SelGray    = 灰度 = 选定颜色的灰度值 (0-255)
SelColor   = 颜色 = 选定颜色的RGB颜色值
SelR       = 红 = 选定颜色的红色分量
SelG       = 绿 = 选定颜色的绿色分量
SelB       = 蓝 = 选定颜色的蓝色分量
RepU       = -上 = 撤销裁剪上边缘1个像素
CutU       = 上 = 裁剪上边缘1个像素
CutU3      = 上3 = 裁剪上边缘3个像素
RepL       = -左 = 撤销裁剪左边缘1个像素
CutL       = 左 = 裁剪左边缘1个像素
CutL3      = 左3 = 裁剪左边缘3个像素
Auto       = 自动 = 二值化之后自动裁剪空白边缘
RepR       = -右 = 撤销裁剪右边缘1个像素
CutR       = 右 = 裁剪右边缘1个像素
CutR3      = 右3 = 裁剪右边缘3个像素
RepD       = -下 = 撤销裁剪下边缘1个像素
CutD       = 下 = 裁剪下边缘1个像素
CutD3      = 下3 = 裁剪下边缘3个像素
Modify     = 修改 = 二值化后可以用鼠标在预览区点击手动修改黑白点
MultiColor = 多点找色 = 鼠标选择多种颜色,之后点击“确定”按钮
FindShape  = 找形状 = 鼠标选择多种颜色,会基于第一点的颜色二值化
Undo       = 撤销 = 撤销上一次选择的颜色
Undo2      = 撤销 = 撤销上一次添加到颜色列表的颜色
Comment    = 识别文字 = 识别文本 (包含在<>中),分割添加时也会分解成单个文字
Threshold  = 灰度阈值 = 灰度阈值 (0-255)
GrayDiff   = 灰度差值 = 灰度差值 (0-255)
Similar1   = 相似度 = 与选定颜色的相似度
Similar2   = 相似度 = 与选定颜色的相似度
Similar3   = 相似度 = 与选定颜色的相似度
AddColorSim  = 添加 = 颜色相似模式添加到颜色列表中再运行颜色二值化
AddColorDiff = 添加 = 颜色偏色模式添加到颜色列表中再运行颜色二值化
ColorList  = = 颜色列表用于转换图像为二值图
DiffRGB    = 红/绿/蓝 = 多色查找时各分量允许的偏差 (0-255)
DiffRGB2   = 红/绿/蓝 = 多色查找时各分量允许的偏差 (0-255)
Bind0      = 绑定窗口1 = 绑定窗口使用GetDCEx()获取后台窗口图像
Bind1      = 绑定窗口1+ = 绑定窗口使用GetDCEx()并修改窗口透明度
Bind2      = 绑定窗口2 = 绑定窗口使用PrintWindow()获取后台窗口图像
Bind3      = 绑定窗口2+ = 绑定窗口使用PrintWindow()并修改窗口透明度
Bind4      = 绑定窗口3 = 绑定窗口使用PrintWindow(,,3)获取后台窗口图像
OK         = 确定 = 生成全新的代码替换旧代码
OK2        = 确定 = 恢复截屏到屏幕然后再抓图
Cancel     = 取消 = 关闭窗口不做任何事
Cancel2    = 取消 = 关闭窗口不做任何事
ClearAll   = 清空 = 清空所有保存的截图
OpenDir    = 打开目录 = 打开保存屏幕截图的目录
SavePic    = 保存图片 = 选择一个范围保存为图片
SavePic2   = 保存图片 = 将修剪后的原始图像保存为图片
LoadPic    = 载入图片 = 载入一张图片作为抓取的图像
ClipText   = = 显示粘贴的文字数据
Offset     = = 显示“获取相对坐标2”或者“获取屏幕范围”的结果
SelectBox  = = 选择截图显示到屏幕左上角
s1  = FindText找字工具
s2  = 灰度阈值|灰度差值|颜色|颜色位置|多色查找
s3  = 图像二值化及分割
s4  = 抓图生成字库及找字代码
s5  = 方向键微调选框\n先点击右键(Ctrl)一次\n把鼠标移开\n再点击右键(Ctrl)一次
s6  = 解绑窗口使用
s7  = 左键(Ctrl)拖动选择范围\n坐标复制到剪贴板
s8  = 找到|时间|毫秒|位置|结果|值可以这样获取|等待3秒等图像出现|无限等待等图像消失
s9  = 截屏成功
s10 = 鼠标位置|穿透显示绑定窗口\n点击右键完成抓图
s11 = 请先设定灰度差值!
s12 = 请先选择核心颜色!
s13 = 请先将图像二值化!
s14 = 不能用于颜色位置二值化模式, 因为分割后会导致位置错误
s15 = 你确定选择的范围吗?\n\n如果不确定,可以重新选择
s16 = 请先添加颜色到颜色列表!
s17 = 你想打开的图片没有找到!
s18 = 捕获|截图
s19 = 你确定要删除所有的截图吗?
    )"
    Lang1:=[], Lang2:=[]
    Loop Parse, s, `n, `r
      if InStr(v:=A_LoopField, "=")
        r:=StrSplit(StrReplace(v "==","\n","`n"), "=", "`t ")
        , Lang1[r[1]]:=r[2], Lang2[r[1]]:=r[3]
  }
  return getLang=1 ? Lang1 : getLang=2 ? Lang2 : Lang1[text]
}

;---------------------------------
; Gui-V1-V2 Compatibility Library  By FeiYue
;---------------------------------

GuiNew(args*) {
  return new this.GuiCreate(args*)
}

GuiFromHwnd(hwnd:="AllGuiObj", RecurseParent:=0) {
  static init, AllGuiObj
  if !VarSetCapacity(init) && (init:="1")
    AllGuiObj:=[]
  if (hwnd=="AllGuiObj")
    return AllGuiObj
  if (RecurseParent)
    While hwnd && !AllGuiObj.HasKey(hwnd)
      hwnd:=DllCall("GetParent", "Ptr",hwnd, "Ptr")
  return AllGuiObj[hwnd]
}

GuiCtrlFromHwnd(hwnd) {
  return this.GuiFromHwnd(hwnd,1)[hwnd]
}

GuiOnEvent(EventName, args*) {
  return this.GuiFromHwnd(WinExist())["_" EventName].Call(0,args*)
}

GuiClose(args*) {
  return FindText().GuiOnEvent("Close",args*)
}

GuiEscape(args*) {
  return FindText().GuiOnEvent("Escape",args*)
}

GuiSize(args*) {
  return FindText().GuiOnEvent("Size",args*)
}

GuiContextMenu(args*) {
  return FindText().GuiOnEvent("ContextMenu",args*)
}

GuiDropFiles(args*) {
  return FindText().GuiOnEvent("DropFiles",0,args*)
}

Class GuiCreate
{  ;// GuiCreate Class Begin

__New(opts:="", title:="", args*) {
  local
  Gui, New, % opts " +Hwndhwnd +LabelFindTextClass.Gui", % title
  this.Hwnd:=hwnd, this.ClassNN:=[]
  FindText().GuiFromHwnd()[hwnd]:=this
}

__Delete() {
  this.Destroy()
}

Destroy() {
  local
  if !(hwnd:=this.Hwnd)
    return
  this.Hwnd:="", FindText().GuiFromHwnd().Delete(hwnd)
  Try Gui, % hwnd ":Destroy"
  For k,v in this
    (v.Hwnd && v.Hwnd:=""), this[k]:=""
}

OnEvent(EventName, Callback, AddRemove:=1) {
  if IsObject(Callback)
    this["_" EventName]:=Callback
}

Opt(opts) {
  Gui, % this.Hwnd ":" RegExReplace(opts,"i)[+\-\s]Label\S*")
}

Add(type, opts:="", text:="") {
  local
  static init, type2class
  if !VarSetCapacity(init) && (init:="1")
    type2class:=[]
  type:=(type="DropDownList"?"DDL":type="Picture"?"Pic":type)
  name:=RegExMatch(opts,"i)(^|[+\-\s])V(?!Scroll\b|ertical\b)\K\S*",r)?r:""
  opts:=RegExReplace(opts,"i)(^|[+\-\s])V(?!Scroll\b|ertical\b)\S*")
  if IsObject(text)
  {
    s:=""
    For k,v in text
      s.="|" v
    text:=Trim(s, "|")
  }
  Gui, % this.Hwnd ":Add", % type, % opts " +Hwndhwnd", % text
  this.LastHwnd:=hwnd
  if type2class.HasKey(type)
    s:=type2class[type]
  else
  {
    WinGetClass, s, ahk_id %hwnd%
    type2class[type]:=s
  }
  this.ClassNN[s]:=n:=Floor(this.ClassNN[s])+1, classnn:=s . n
  obj:= new this.Control(this.Hwnd, hwnd, type, classnn, name)
  this[hwnd]:=obj, this[classnn]:=obj
  if (name) && !(name~="i)^(Destroy|OnEvent|Opt|Add"
  . "|SetFont|Show|Hide|Move|GetClientPos|GetPos|Maximize"
  . "|Minimize|Restore|Flash|Submit|Hwnd|Name|Title"
  . "|BackColor|MarginX|MarginY|MenuBar|FocusedCtrl)$")
    this[name]:=obj
  return obj
}

SetFont(opts:="", FontName:="") {
  Gui, % this.Hwnd ":Font", % opts, % FontName
}

Show(opts:="", args*) {
  Gui, % this.Hwnd ":Show", % opts
}

Hide() {
  Gui, % this.Hwnd ":Hide"
}

Move(x:="", y:="", w:="", h:="") {
  local
  this.GetPos(pX, pY, pW, pH)
  x:=(x=""?pX:x), y:=(y=""?pY:y), w:=(w=""?pW:w), h:=(h=""?pH:h)
  DllCall("MoveWindow", "Ptr",this.Hwnd, "int",x, "int",y, "int",w, "int",h, "int",1)
}

GetClientPos(ByRef x:="", ByRef y:="", ByRef w:="", ByRef h:="") {
  local
  VarSetCapacity(rect, 16, 0)
  , DllCall("GetClientRect",  "Ptr",this.Hwnd, "Ptr",&rect)
  , DllCall("ClientToScreen", "Ptr",this.Hwnd, "Ptr",&rect)
  , x:=NumGet(rect, 0, "int"), y:=NumGet(rect, 4, "int")
  , w:=NumGet(rect, 8, "int")-x, h:=NumGet(rect, 12, "int")-y
}

GetPos(ByRef x:="", ByRef y:="", ByRef w:="", ByRef h:="") {
  local
  VarSetCapacity(rect, 16, 0)
  , DllCall("GetWindowRect",  "Ptr",this.Hwnd, "Ptr",&rect)
  , x:=NumGet(rect, 0, "int"), y:=NumGet(rect, 4, "int")
  , w:=NumGet(rect, 8, "int")-x, h:=NumGet(rect, 12, "int")-y
}

Maximize() {
  Gui, % this.Hwnd ":Maximize"
}

Minimize() {
  Gui, % this.Hwnd ":Minimize"
}

Restore() {
  Gui, % this.Hwnd ":Restore"
}

Flash(k:=1) {
  Gui, % this.Hwnd ":Flash", % k ? "":"Off"
}

Submit(hide:=1) {
  local
  (hide && this.Hide()), arr:=[]
  For k,v in this
    if k is number
      if (v.Name!="")
        arr[v.Name]:=v.Value
  return arr
}

BackColor {
  get {
    return this._BackColor
  }
  set {
    this._BackColor:=value
    Gui, % this.Hwnd ":Color", % value
    return value
  }
}

MarginX {
  get {
    return this._MarginX
  }
  set {
    this._MarginX:=value
    Gui, % this.Hwnd ":Margin", % value
    return value
  }
}

MarginY {
  get {
    return this._MarginY
  }
  set {
    this._MarginY:=value
    Gui, % this.Hwnd ":Margin",, % value
    return value
  }
}

MenuBar {
  get {
    return this._MenuBar
  }
  set {
    this._MenuBar:=value
    Gui, % this.Hwnd ":Menu", % value
    return value
  }
}

Title {
  get {
    local
    VarSetCapacity(v, 260*2)
    DllCall("GetWindowText", "Ptr",this.Hwnd, "Str",v, "Int",260)
    return v
  }
  set {
    DllCall("SetWindowText", "Ptr",this.Hwnd, "Str",value)
    return value
  }
}

FocusedCtrl {
  get {
    local
    GuiControlGet, v, % this.Hwnd ":Focus"
    return this[v]
  }
}

Class Control
{  ;// Control Class Begin

__New(GuiHwnd, hwnd, type, classnn, name) {
  this.GuiHwnd:=GuiHwnd, this.Hwnd:=hwnd
  this.Type:=type, this.ClassNN:=classnn, this.Name:=name
}

Opt(opts) {
  GuiControl, % opts, % this.Hwnd
}

OnEvent(EventName, Callback, AddRemove:=1) {
  local
  r:=this.OnEvent_G.Bind(this, Callback)
  GuiControl, +g, % this.Hwnd, % r
}

OnEvent_G(Callback, args*) {
  if IsObject(Callback)
    return %Callback%(this, args*)
}

GetPos(ByRef x:="", ByRef y:="", ByRef w:="", ByRef h:="") {
  local
  GuiControlGet, p, Pos, % this.Hwnd
  x:=Floor(pX), y:=Floor(pY), w:=Floor(pW), h:=Floor(pH)
}

Move(x:="", y:="", w:="", h:="") {
  local
  s:=(x=""?"":" x" x) (y=""?"":" y" y) (w=""?"":" w" w) (h=""?"":" h" h)
  GuiControl, Move, % this.Hwnd, % s
}

Redraw() {
  GuiControl, MoveDraw, % this.Hwnd
}

Focus() {
  Try GuiControl, Focus, % this.Hwnd
}

UseTab(Name:="", Exact:="", index:="") {
  Gui, % this.GuiHwnd ":Tab", % Name, % index, % Exact?"Exact":""
}

SetFont(opts:="", FontName:="") {
  Gui, % this.GuiHwnd ":Font", % opts, % FontName
  GuiControl, Font, % this.Hwnd
}

Add(text) {
  local
  if IsObject(text)
  {
    s:=""
    For k,v in text
      s.="|" v
    text:=Trim(s, "|")
  }
  GuiControl,, % this.Hwnd, % text
}

Delete(N:="") {
  if (N="")
    GuiControl,, % this.Hwnd, |
  else
    this.Choose(N), this.Choose(0)
}

Choose(N) {
  if N is number
    GuiControl, Choose, % this.Hwnd, % N
  else
    GuiControl, ChooseString, % this.Hwnd, % N
}

Gui {
  get {
    return FindText().GuiFromHwnd(this.GuiHwnd)
  }
}

Enabled {
  get {
    local
    GuiControlGet, v, Enabled, % this.Hwnd
    return v
  }
  set {
    GuiControl, % "Enable" (!!value), % this.Hwnd
    return value
  }
}

Visible {
  get {
    local
    GuiControlGet, v, Visible, % this.Hwnd
    return v
  }
  set {
    GuiControl, % "Show" (!!value), % this.Hwnd
    return value
  }
}

Focused {
  get {
    local
    GuiControlGet, v, % this.GuiHwnd ":Focus"
    return (v=this.ClassNN)
  }
}

Value {
  get {
    local
    if (this.Type~="i)^(ListBox|DDL|ComboBox|Tab)$")
      this.Opt("+AltSubmit")
    GuiControlGet, v,, % this.Hwnd
    return v
  }
  set {
    if (this.Type~="i)^(ListBox|DDL|ComboBox|Tab)$")
      GuiControl, Choose, % this.Hwnd, % value
    else
      GuiControl,, % this.Hwnd, % value
    return value
  }
}

Text {
  get {
    local
    if (this.Type~="i)^(ListBox|DDL|ComboBox|Tab)$")
      this.Opt("-AltSubmit")
    GuiControlGet, v,, % this.Hwnd
    return v
  }
  set {
    if (this.Type~="i)^(ListBox|DDL|ComboBox|Tab)$")
      GuiControl, ChooseString, % this.Hwnd, % value
    else
      GuiControl,, % this.Hwnd, % value
    return value
  }
}

}  ;// Control Class End

}  ;// GuiCreate Class End

Script_End() {
}

}  ;// Class End

;================= The End =================

;

 

  

 

 

 

; 某网页单据打印辅助AutoHotkey v1.0脚本,本来打印单据需要用鼠标点击多次,
; 运行此脚本之后只需在输入完毕后按快捷键热键<F4>
; 为了便于寻找快捷键位置,我在F4键的键帽上贴了黄色贴纸
; 可用 AHKInfo 1.3.5 或者 AhkSpy 等窗口信息探测工具来获取鼠标光标的当前位置
; 2025-03-31

; 由于"【函数】FindText中文版- 屏幕抓字生成字库工具与找字函数"比较复杂,创建和使用脚本麻烦
; 所以我使用 MouseMove、Click和Sleep这3个AHK原生语句来制作此脚本,
; 这3个内置函数语句的优点是性能速度快,效率高,稳定可靠(有时候FindText在不同电脑上会找不到位图),
; 这3个内置函数语句的缺点是环境适应性差,不同显示器,不同显卡,不同电脑,不同分辨率下的全局坐标可能会不同,需要重写代码.
; 这3个内置函数语句的缺点是需要窗口最大化,窗口位置固定,否则有可能点击不到网页中的按钮.
; 我这边网页平台系统只要多次鼠标点击写到1个快捷键热键就可以了,只要能够长期稳定使用就可以了,要求不高.
; 所以我也不想再根据屏幕分辨率 DPI 缩放修正通用全局坐标了,不折腾了,只要一个电脑上能用就好了,
; 并且我这个Windows 10 企业版 LTSC 电脑用Acronis True Image 2021 在USM v5下备份了系统分区,
; 并且正确安装设置了Deep Freeze Standard冰点还原精灵保护电脑第1分区系统分区C盘.

; xx=% "x" 397*A_ScreenDPI//96
; yy=" y" 63*A_ScreenDPI//96
; MouseMove,xx,yy

;;;;;;;点击窗口内指定坐标 【DPI缩放通用坐标修正】
; ControlClick, % "x" 397*A_ScreenDPI//96 " y" 63*A_ScreenDPI//96, D:\APP\F4\F4.ahk * SciTE4AutoHotkey ahk_class SciTEWindow

; FindText 深度教程 v1.2
; https://www.autoahk.com/archives/41636
; https://www.autoahk.com/archives/47248
; https://www.autoahk.com/archives/39249
; https://www.autoahk.com/archives/28493

; 设置每次鼠标移动或点击后自动的延时.
SetMouseDelay,0
SetKeyDelay,0
SetControlDelay,0
SetWinDelay,0
; 把 Click, MouseMove, MouseClick 放置在绝对的屏幕坐标上.
CoordMode, Mouse, Screen
; 设置脚本可以 "看见" 隐藏的窗口.
DetectHiddenWindows, On
; 按快捷键 Ctrl + F4 立即退出此脚本
Hotkey,^F4,ExitPrintHMF
Hotkey,F4,PrintHMF
return
ExitPrintHMF()
{
	ExitApp
}
PrintHMF()
{

;第1步:点击 提交保存网页按钮
;第2步:点击 打印预览网页按钮
;第3步:点击 打印网页按钮
;第4步:点击 确定对话框按钮
;第5步:点击 关闭网页按钮
;第6步:点击 取消网页按钮
;第7步:点击 收费方式网页下拉列表单选框
;第8步:点击 微信
;第9步:点击 位置/姓名 搜索框网页控件
;第10步:发送 Ctrl + A 全选搜索框中原有的内容,为下一次筛选搜索过滤记录行做好输入准备。


; MsgBox ;第1步:点击 提交保存网页按钮 Sleep,55 MouseMove,1030,1007 Sleep,55 MouseMove,1030,1007 Sleep,333 Sleep,55 Click Sleep,55 Sleep,333 ;第2步:点击 打印预览网页按钮 Sleep,55 MouseMove,1064,666 Sleep,55 MouseMove,1064,666 Sleep,333 Sleep,55 Click Sleep,55 ;第3步:点击 打印网页按钮 ; 等待"打印预览"窗口创建并显示,"打印预览"窗口不是对话框,是新的窗口,显示比较慢。 ; 先移动鼠标光标到目标坐标位置,然后再等待 Sleep,55 MouseMove,455,37 Sleep,55 MouseMove,455,37 Sleep,333 Sleep,333 Sleep,333 Sleep,333 Sleep,333 Sleep,55 Click Sleep,55 Sleep,333 ;第4步:点击 确定对话框按钮 Sleep,55 MouseMove,1090,538 Sleep,55 MouseMove,1090,538 Sleep,333 Sleep,55 Click Sleep,55 Sleep,333 ;第5步:点击 关闭网页按钮 Sleep,55 MouseMove,495,37 Sleep,55 MouseMove,495,37 Sleep,333 Sleep,55 Click Sleep,55 Sleep,333 ;第6步:点击 取消网页按钮 Sleep,55 MouseMove,1152,665 Sleep,55 MouseMove,1152,665 Sleep,333 Sleep,333 Sleep,55 Click Sleep,55 ;第7步:点击 收费方式网页下拉列表单选框 Sleep,55 MouseMove,507,478 Sleep,55 MouseMove,507,478 Sleep,333 Sleep,333 Sleep,55 Click Sleep,55 Sleep,333 ;第8步:点击 微信 Sleep,55 MouseMove,496,559 Sleep,55 MouseMove,496,559 Sleep,333 Sleep,55 Click Sleep,55 Sleep,333 ;第9步:点击 位置/姓名 搜索框网页控件 Sleep,55 MouseMove,484,237 Sleep,55 MouseMove,484,237 Sleep,333 Sleep,55 Click Sleep,55 Sleep,333 ;第10步:发送 Ctrl + A 全选搜索框中原有的内容,为下一次筛选搜索过滤记录行做好输入准备。 Sleep,55 Send,^a Sleep,55 }

 

; 以下是一些常用的 辅助AutoHotkey脚本工具

 

 

;/*
;===========================================
;  FindText - 屏幕抓字生成字库工具与找字函数
;  https://www.autohotkey.com/boards/viewtopic.php?f=6&t=17834
;
;  脚本作者 : FeiYue
;  最新版本 : 10.0
;  更新时间 : 2024-10-06
;
;  用法:  (需要最新版本 AHK v1.1.34+)
;  1. 将本脚本保存为“FindText.ahk”并复制到AHK执行程序的Lib子目录中(手动建立目录)
;  2. 抓图并生成调用FindText()的代码
;     2.1 方式一:直接点击“抓图”按钮
;     2.2 方式二:先设定截屏热键,使用热键截屏,再点击“截屏抓图”按钮
;  3. 测试一下调用的代码是否成功:直接点击“测试”按钮
;  4. 复制调用的代码到自己的脚本中
;     4.1 方式一:打勾“附加FindText()函数”的选框,然后点击“复制”按钮(不推荐)
;     4.2 方式二:取消“附加FindText()函数”的选框,然后点击“复制”按钮,
;         然后粘贴到自己的脚本中,然后在自己的脚本开头加上一行:
;         #Include <FindText>  ; Lib目录中必须有FindText.ahk
;  5. 多色查找模式可以一定程度上适应图像的放大缩小,常用于游戏中找图
;  6. 这个库还可以用于快速截屏、获取颜色、写入颜色、编辑后另存图片
;  7. 如果要调用FindTextClass类中的函数,请用无参数的FindText()获取类实例对象
;
;===========================================
;*/


if (!A_IsCompiled && A_LineFile=A_ScriptFullPath)
  FindText().Gui("Show")


;===== 复制下面的函数和类到你的代码中仅仅一次 =====


FindText(ByRef x:="FindTextClass", ByRef y:="", args*)
{
  static init, obj
  if !VarSetCapacity(init) && (init:="1")
    obj:=new FindTextClass()
  return (x=="FindTextClass" && !args.Length()) ? obj : obj.FindText(x, y, args*)
}

Class FindTextClass
{  ;// Class Begin

Floor(i)
{
  if i is number
    return i+0
  else return 0
}

__New()
{
  this.bits:={ Scan0: 0, hBM: 0, oldzw: 0, oldzh: 0 }
  this.bind:={ id: 0, mode: 0, oldStyle: 0 }
  this.Lib:=[]
  this.Cursor:=0
}

__Delete()
{
  if (this.bits.hBM)
    Try DllCall("DeleteObject", "Ptr",this.bits.hBM)
}

New()
{
  return new FindTextClass()
}

help()
{
return "
(
;--------------------------------
;  FindText - 屏幕找字函数
;  版本 : 10.0  (2024-10-06)
;--------------------------------
;  返回变量:=FindText(
;      OutputX --> 保存返回的X坐标的变量名称
;    , OutputY --> 保存返回的Y坐标的变量名称
;    , X1 --> 查找范围的左上角X坐标
;    , Y1 --> 查找范围的左上角Y坐标
;    , X2 --> 查找范围的右下角X坐标
;    , Y2 --> 查找范围的右下角Y坐标
;    , err1 --> 文字的黑点容错百分率(0.1=10%)
;    , err0 --> 背景的白点容错百分率(0.1=10%)
;      设置 err1<0 或 err0<0 可以打开左右膨胀算法
;      忽略文字线条的轻微错位,此时容错值应该非常小
;      在找图模式中,err0 可以设置要跳过的行列数,加快速度
;    , Text --> 由工具生成的查找图像的数据,可以一次查找多个,用“|”分隔
;    , ScreenShot --> 是否截屏,为0则使用上一次的截屏数据
;    , FindAll --> 是否搜索所有位置,为0则找到一个位置就返回
;    , JoinText --> 如果想组合查找,可以为1,或者是要查找单词的数组
;    , offsetX --> 组合图像的每个字和前一个字的最大横向间隔
;    , offsetY --> 组合图像的每个字和前一个字的最大高低间隔
;    , dir --> 查找的方向,有上、下、左、右、中心9种
;      默认 dir=0,这种返回的结果将按最小误差排序,
;      即使设置了较大的容错,第一个结果也是误差最小的
;    , zoomW --> 图像宽度的缩放百分率(1.0=100%)
;    , zoomH --> 图像高度的缩放百分率(1.0=100%)
;  )
;
;  返回变量 --> 如果没找到结果会返回0。否则返回一个二级数组,
;      第一级是每个结果对象,第二级是结果对象的具体信息对象:
;      { 1:左上角X, 2:左上角Y, 3:图像宽度W, 4:图像高度H
;        , x:中心点X, y:中心点Y, id:图像识别文本 }
;  所有坐标都是相对于屏幕,颜色使用RGB格式
;  所有 RRGGBB 可以使用 Black、White、Red、Green、Blue 代替,
;  所有 DRDGDB 可以使用相似度 1.0(100%) 代替,它是浮点数
;
;  如果 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) ; 无限等待等图像消失
;
;  <FindMultiColor> 或 <FindColor> : 找色 是仅有一个点的 多点找色
;  Text:='|<>##DRDGDB $ 0/0/RRGGBB1-DRDGDB1/RRGGBB2, xn/yn/-RRGGBB3/RRGGBB4, ...'
;  '##'之后的颜色 (0xDRDGDB) 是所有颜色的默认偏色(各个分量允许的变化值)
;  初始点 (0,0) 匹配 0xRRGGBB1(+/-0xDRDGDB1) 或者 0xRRGGBB2(+/-0xDRDGDB),
;  点 (xn,yn) 匹配 排除 0xRRGGBB3(+/-0xDRDGDB) 和排除 0xRRGGBB4(+/-0xDRDGDB)
;  点坐标后面以 '-' 开头表示要排除后面的所有颜色,其他颜色都匹配
;  每个点最多允许匹配10组颜色 (xn/yn/RRGGBB1/.../RRGGBB10)
;
;  <FindShape> : 类似于 FindMultiColor,仅是把具体颜色替换为
;  这一点的颜色是否与第一点的颜色是否相似
;  Text:='|<>##DRDGDB $ 0/0/1, x1/y1/0, x2/y2/1, xn/yn/0, ...'
;
;  <FindPic> : Text 参数需要手动输入
;  Text:='|<>##DRDGDB/RRGGBB1-DRDGDB1/RRGGBB2... $ d:\a.bmp'
;  '##'之后的颜色 (0xDRDGDB) 是所有颜色的默认偏色(各个分量允许的变化值)
;  这个 0xRRGGBB1(+/-0xDRDGDB1) 和 0xRRGGBB2(+/-0xDRDGDB)... 都是透明色
;
;--------------------------------
)"
}

FindText(ByRef OutputX:="", ByRef 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:=0, zoomW:=1, zoomH:=1)
{
  local
  if (OutputX ~= "i)^\s*wait[10]?\s*$")
  {
    found:=!InStr(OutputX,"0"), time:=this.Floor(OutputY)
    , timeout:=A_TickCount+Round(time*1000), OutputX:=""
    Loop
    {
      ok:=this.FindText(,, x1, y1, x2, y2, err1, err0, text, ScreenShot
        , FindAll, JoinText, offsetX, offsetY, dir, zoomW, zoomH)
      if (found && ok)
      {
        OutputX:=ok[1].x, OutputY:=ok[1].y
        return ok
      }
      if (!found && !ok)
        return 1
      if (time>=0 && A_TickCount>=timeout)
        Break
      Sleep 50
    }
    return 0
  }
  SetBatchLines % (bch:=A_BatchLines)?"-1":"-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
  , 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)
  {
    SetBatchLines % bch
    return 0
  }
  arr:=[], info2:=[], k:=0, s:=""
  , mode:=(IsObject(JoinText) ? 2 : JoinText ? 1 : 0)
  For i,j in info
  {
    k:=Max(k, (j[7]=5 && j[8]!=2 ? j[9] : j[2]*j[3]))
    if (mode)
      v:=(mode=1 ? i : j[10]) . "", s.="|" v
      , (v!="") && ((!info2.HasKey(v) && info2[v]:=[]), info2[v].Push(j))
  }
  sx:=x, sy:=y, sw:=w, sh:=h, (mode=1 && JoinText:=[s])
  , allpos_max:=(FindAll || JoinText ? 10000:1)
  , VarSetCapacity(s1,k*4), VarSetCapacity(s0,k*4)
  , VarSetCapacity(ss,sw*(sh+3)), VarSetCapacity(allpos,allpos_max*8)
  , ini:={ sx:sx, sy:sy, sw:sw, sh:sh, zx:zx, zy:zy
  , mode:mode, bits:bits, ss:&ss, s1:&s1, s0:&s0
  , allpos:&allpos, allpos_max:allpos_max
  , err1:err1, err0:err0, 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)
    {
      For i,j in info
      Loop % this.PicFind(ini, j, dir, sx, sy, sw, sh)
      {
        v:=NumGet(allpos,4*A_Index-4,"uint"), x:=(v&0xFFFF)+zx, y:=(v>>16)+zy
        , w:=Floor(j[2]*zoomW), h:=Floor(j[3]*zoomH)
        , arr.Push({1:x, 2:y, 3:w, 4:h, x:x+w//2, y:y+h//2, id:j[10]})
        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
  }
  SetBatchLines % bch
  if (arr.Length())
  {
    OutputX:=arr[1].x, OutputY:=arr[1].y, this.ok:=arr
    return arr
  }
  return 0
}

; the join text object use [ "abc", "xyz", "a1|a2|a3" ]

JoinText(arr, ini, info2, text, index, offsetX, offsetY
  , FindAll, dir, minX, minY, maxY, sx, sy, sw, sh)
{
  local
  if !(Len:=text.Length()) || !info2.HasKey(key:=text[index])
    return 0
  zoomW:=ini.zoomW, zoomH:=ini.zoomH, mode:=ini.mode
  For i,j in info2[key]
  if (mode!=2 || key==j[10])
  Loop % ok:=this.PicFind(ini, j, dir, sx, sy, (index=1 ? sw
  : Min(sx+offsetX+Floor(j[2]*zoomW),ini.sx+ini.sw)-sx), sh)
  {
    if (A_Index=1)
    {
      pos:=[], p:=ini.allpos-4
      Loop % ok
        pos.Push(NumGet(0|p+=4,"uint"))
    }
    v:=pos[A_Index], x:=v&0xFFFF, y:=v>>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 (index<Len)
    {
      sy1:=Max(minY1-offsetY, ini.sy)
      , sh1:=Min(maxY1+offsetY, ini.sy+ini.sh)-sy1
      if this.JoinText(arr, ini, info2, text, index+1, offsetX, offsetY
      , FindAll, 5, minX, minY1, maxY1, sx1, sy1, 0, sh1)
      && (index>1 || !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)
{
  local
  static init, MyFunc
  if !VarSetCapacity(init) && (init:="1")
  {
    x32:="VVdWU4HsmAAAAIuEJNQAAAADhCTMAAAAi5wk@AAAAIO8JKwAAAAFiUQkIIuEJPgA"
    . "AACNBJiJRCQ0D4RKBgAAi4Qk6AAAAIXAD45ADwAAiXwkEIu8JOQAAAAx7ccEJAAA"
    . "AADHRCQIAAAAAMdEJBQAAAAAx0QkDAAAAACNtgAAAACLhCTgAAAAi0wkDDH2MdsB"
    . "yIX@iUQkBH896ZAAAABmkA+vhCTMAAAAicGJ8Jn3@wHBi0QkBIA8GDF0TIuEJNwA"
    . "AACDwwEDtCQAAQAAiQyog8UBOd90VIsEJJn3vCToAAAAg7wkrAAAAAR1tQ+vhCTA"
    . "AAAAicGJ8Jn3@40MgYtEJASAPBgxdbSLRCQUi5Qk2AAAAIPDAQO0JAABAACJDIKD"
    . "wAE534lEJBR1rAF8JAyDRCQIAYu0JAQBAACLRCQIATQkOYQk6AAAAA+FMv@@@4tE"
    . "JBSLfCQQD6+EJOwAAACJbCQwwfgKiUQkKIuEJPAAAAAPr8XB+AqJRCRAg7wkrAAA"
    . "AAQPhCIGAACLhCTAAAAAi5wkxAAAAA+vhCTIAAAAjSyYi4QkzAAAAIucJMAAAAD3"
    . "2IO8JKwAAAABjQSDiUQkLA+ELwYAAIO8JKwAAAACD4Q4CAAAg7wkrAAAAAMPhLkL"
    . "AACLjCTQAAAAhckPjicBAACLhCTMAAAAi6wkzAAAAMdEJAwAAAAAx0QkEAAAAACJ"
    . "fCQYg+gBiUQkCI22AAAAAIt8JBCLtCTUAAAAMcCLXCQgAfsB94Xtif6J738X6bwA"
    . "AADGBAYEg8ABg8MBOccPhKQAAACDvCSsAAAAA3@khcAPtgsPhLoPAAAPtlP@iVQk"
    . "BDlEJAgPhMIPAAAPtlMBiRQki5Qk9AAAAIXSD4SfAQAAD7bpugYAAACD7QGD@QF2"
    . "G4N8JAQBD5TCgzwkAYnVD5TCCeoPttIB0oPKBIHh@QAAAL0BAAAAdByLTCQEiywk"
    . "hckPlEQkBIXtD5TBic0PtkwkBAnNCeqDwwGIFAaDwAE5xw+FXP@@@wF8JBCJ@YNE"
    . "JAwBi0QkDDmEJNAAAAAPjwz@@@+LfCQYg7wkrAAAAAN@FouEJPQAAACFwA+VwDwB"
    . "g5wkxAAAAP+LXCQUi3QkKDHAOfOLdCRAD07YiVwkFItcJDA58w9Pw4lEJDCLhCTM"
    . "AAAAK4QkAAEAAIlEJASLhCTQAAAAK4QkBAEAAIO8JLgAAAAJiUQkCA+ExgAAAIuE"
    . "JLgAAACD6AGD+AcPh7wCAACD+AOJRCQkD463AgAAi0QkBMdEJEQAAAAAx0QkDAAA"
    . "AACJBCSLRCQIiUQkHItcJEQ5HCTHRCRMAAAAAA+MCwEAAItcJEw5XCQcD4zCDQAA"
    . "i3QkRItcJCSLBCQp8PbDAg9Exot0JEyJwotEJBwp8PbDAQ9ExoP7A4nWD0@wD0@C"
    . "iXQkGIlEJBDp3gsAAI12AA+20YPqAYP6AhnSg+ICg8IEgeH9AAAAD5TBCcqIFAbp"
    . "8v3@@4tcJASLdCQIx0QkZAAAAADHRCRgAQAAAMdEJFQAAAAAx0QkWAAAAACJ2I1W"
    . "AYk0JMHoH4lcJBzHRCQMAAAAAAHY0fiJRCQQifDB6B8B8NH4iUQkGInYg8ABicEP"
    . "r8o50A9MwoPACIlMJHyJwQ+vyImMJIAAAACLXCR8OVwkZH0Zi5wkgAAAADlcJFjH"
    . "RCRcAAAAAA+M9QQAAIuMJLgAAACFyQ+FnQIAAIuUJPgAAACF0g+EjgIAAIuEJAQB"
    . "AAAPr4QkAAEAAIP4AQ+EdgIAAIN8JAwBD46lCgAAi0QkNIucJPgAAAAx7cdEJAQA"
    . "AAAAiSwkjXgEi0QkDIPoAYlEJBCLRCQEiwwkizeLRAMEhcmJRCQIich4NotP@DnO"
    . "D4N1BQAAifqNa@zrDY12AIPqBItK@DnOcxeJCotMhQSJTIMEg+gBg@j@deS4@@@@"
    . "@4tMJDSDwAGDBCQBg8cEg0QkBASJNIGLdCQIiTSDiwQkO0QkEHWNi4QkBAEAAIus"
    . "JAABAAAPr8APr+2JRCQEi7Qk+AAAAMdEJAgAAAAAMduLRCQIiwSGiUQkEA+3+MHo"
    . "EIXbiQQkdC0xyY22AAAAAIsUjg+3win4D6@AOeh9D8HqECsUJA+v0jtUJAR8EYPB"
    . "ATnZdduLRCQQiQSeg8MBg0QkCAGLRCQIOUQkDHWiidiBxJgAAABbXl9dwlwAx0Qk"
    . "JAAAAACLRCQIx0QkRAAAAADHRCQMAAAAAIkEJItEJASJRCQc6UT9@@8xwIO8JLAA"
    . "AAACD5TAiYQkhAAAAA+EUAQAADHAg7wksAAAAAGLrCS0AAAAD5TAhe2JRCR4D4SG"
    . "CwAAi7Qk2AAAAIuUJLQAAAAx7YucJOAAAACLjCTcAAAAiXwkCI0ElolEJASNdCYA"
    . "izuDxgSDw1iDwQSJ+MHoEA+vhCQEAQAAmfe8JOgAAAAPr4QkwAAAAIkEJA+3xw+v"
    . "hCQAAQAAmfe8JOQAAACLFCSNBIKJRvyLQ6yNREUAg8UWiUH8O3QkBHWmi4QktAAA"
    . "AIm8JLAAAACLfCQIiUQkFIuEJOwAAAAPr4QktAAAAMH4ColEJCiLhCTgAAAAx0Qk"
    . "QAAAAADHRCQwAAAAAIPACIlEJFDpSfr@@4tEJAyBxJgAAABbXl9dwlwAi4QksAAA"
    . "AMHoEA+vhCQEAQAAmfe8JOgAAAAPr4QkwAAAAInBD7eEJLAAAAAPr4QkAAEAAJn3"
    . "vCTkAAAAjQSBiYQksAAAAOnt+f@@i4Qk6AAAAIu0JNAAAAAPr4Qk5AAAANGkJLQA"
    . "AAADhCTgAAAAhfaJRCRQD47z+v@@i4QkzAAAAInqi2wkUMdEJCQAAAAAx0QkOAAA"
    . "AADB4AKJRCRIMcCLnCTMAAAAhdsPjisBAACLnCS8AAAAAdMDVCRIiVwkEItcJCAD"
    . "XCQ4iVQkPAOUJLwAAACJXCQYiVQkHI12AI28JwAAAACLdCQQMds5nCS0AAAAD7ZO"
    . "AolMJAQPtk4BD7Y2iUwkCIl0JAx2W412AI28JwAAAACLRJ0Ag8MCi3yd@InCD7bM"
    . "D7bAK0QkDMHqECtMJAgPttIrVCQEgf@@@@8AiQQkdyUPr9IPr8mNFFIPr8CNFIqN"
    . "BEI5x3NGMcA5nCS0AAAAd6+JwutBif7B7hCJ8A+28A+v0g+v9jnyd92J+A+21A+v"
    . "yQ+v0jnRd86LNCSJ+A+20A+v0onwD6@GOdB3uroBAAAAuAEAAACLXCQYg0QkEASL"
    . "TCQQiBODwwE7TCQciVwkGA+FGv@@@4u0JMwAAAABdCQ4i1QkPINEJCQBA1QkLItc"
    . "JCQ5nCTQAAAAD4Ws@v@@6U34@@+LRCQQhcB4G4tcJBw52H8Ti0QkGIXAeAuLHCQ5"
    . "2A+ONwYAAItsJFSF7Q+F4AUAAINsJBgBg0QkXAGDRCRYAYt0JGA5dCRcfLiLXCRU"
    . "idiD4AEBxonYg8ABiXQkYIPgA4lEJFTpvvr@@4uEJLAAAACLjCTQAAAAxwQkAAAA"
    . "AMdEJAQAAAAAg8ABweAHiYQksAAAAIuEJMwAAADB4AKFyYlEJAwPjsz4@@+J6Ius"
    . "JLAAAACJfCQQi5QkzAAAAIXSfmaLjCS8AAAAi1wkIIu8JLwAAAADXCQEAcEDRCQM"
    . "iUQkCAHHjXYAjbwnAAAAAA+2UQIPtkEBD7Yxa8BLa9ImAcKJ8MHgBCnwAdA5xQ+X"
    . "A4PBBIPDATn5ddWLnCTMAAAAAVwkBItEJAiDBCQBA0QkLIs8JDm8JNAAAAAPhXf@"
    . "@@+LfCQQ6Qb3@@+LBCTprvr@@4uEJOgAAACLvCTgAAAAD6+EJOQAAADRpCS0AAAA"
    . "jQSHiUQkUIuEJPAAAADB+AqDwAGJRCQki4Qk6AAAAIXAD45ECgAAi3wkJIuEJAQB"
    . "AACLdCRQx0QkMAAAAADHRCQUAAAAAA+vx4lEJECLhCTkAAAAD6@HweACiUQkSIuE"
    . "JOAAAACDwAKJRCQ4ifiNPL0AAAAAiXwkLInHD6+EJAABAACJfCQ8iUQkKIuEJOQA"
    . "AACFwA+OaQEAAItEJDjHRCQcAAAAAIlEJBCLRCQkiUQkGItEJBC7AgAAAA+2OIk8"
    . "JA+2eP8PtkD+iXwkBIlEJAg5nCS0AAAAD4bCAAAAiwSeg8MCi3ye@InCD7bMD7bA"
    . "K0QkCMHqECtMJAQPttIrFCSB@@@@@wCJRCQMd0YPr9IPr8mNFFIPr8CNFIqNBEI5"
    . "x3Kui3wkGItEJCSLTCQsAUwkEItMJCgBTCQcAfg5vCTkAAAAD465AAAAiUQkGOlf"
    . "@@@@if3B7RCJ6A+26A+v0g+v7TnqD4dm@@@@ifgPttQPr8kPr9I50Q+HU@@@@4tM"
    . "JAyJ+A+2+A+v@4nID6@BOfh2kDmcJLQAAAAPhz7@@@+LRCQwi3wkFJmNHL0AAAAA"
    . "97wk6AAAAA+vhCTAAAAAicGLRCQcmfe8JOQAAACLFCTB4hCNBIGLjCTYAAAAiQS5"
    . "i0QkBIPHAYl8JBSLvCTcAAAAweAICdALRCQIiQQf6SD@@@+LfCQ8i0QkJItMJEAB"
    . "TCQwi0wkSAFMJDgB+Dm8JOgAAAB+CYlEJDzpXP7@@4tEJBQPr4Qk7AAAAMH4ColE"
    . "JCiLRCRQx0QkQAAAAADHRCQwAAAAAIt4BIn4ifvB6BAPtteJ+w+2wA+2y4nDD6@Y"
    . "idAPr8KJXCRwiUQkdInID6@BiUQkbOlH9P@@i4Qk0AAAAIXAD45u9f@@i5wkzAAA"
    . "AItEJCDHBCQAAAAAx0QkBAAAAACJfCQMjQRYiUQkGInYweACiUQkCIu0JMwAAACF"
    . "9n5Xi4wkvAAAAItcJBiLvCS8AAAAA1wkBAHpA2wkCAHvD7ZRAoPBBIPDAWvyJg+2"
    . "Uf1rwkuNFAYPtnH8ifDB4AQp8AHQwfgHiEP@Ofl10ou8JMwAAAABfCQEgwQkAQNs"
    . "JCyLBCQ5hCTQAAAAdYqLhCTMAAAAi3wkDDHti5QktAAAADH2g+gBiXwkJIlEJAyL"
    . "hCTQAAAAg+gBiUQkEIucJMwAAACF2w+O4gAAAIu8JMwAAACLRCQYAfeNDDCJ+4l8"
    . "JByJxwHfifMrnCTMAAAAiXwkBIt8JCABwwH3McCJfCQIiRwkhcAPhGQDAAA5RCQM"
    . "D4RaAwAAhe0PhFIDAAA5bCQQD4RIAwAAD7YRD7Z5@74BAAAAA5QksAAAADn6ckYP"
    . "tnkBOfpyPos8JA+2Pzn6cjSLXCQED7Y7OfpyKYs8JA+2f@85+nIeizwkD7Z@ATn6"
    . "chMPtnv@OfpyCw+2cwE58g+Sw4nei3wkCInziBwHg8ABg8EBg0QkBAGDBCQBOYQk"
    . "zAAAAA+FWv@@@4t0JByDxQE5rCTQAAAAD4X@@v@@i3wkJImUJLQAAADpY@L@@8dE"
    . "JEAAAAAAx0QkKAAAAADHRCQwAAAAAMdEJBQAAAAA6cfx@@+DfCRUAQ+E6gEAAIN8"
    . "JFQCD4SVAgAAg2wkEAHpBfr@@4uEJAQBAACLrCQAAQAAD6@AD6@tiUQkBItEJAyF"
    . "wA+P6PX@@zHA6VL2@@+DRCRkAcdEJCQJAAAAi0QkGIucJNQAAAAPr4QkzAAAAANE"
    . "JBCAPAMDD4ZnAQAAi3QkFItcJDA53g9N3oO8JKwAAAADiVwkIA+OdQEAAItEJBgD"
    . "hCTIAAAAD6+EJMAAAACLVCQQA5QkxAAAAIO8JKwAAAAFD4RsAgAAjTSQi4QksAAA"
    . "AIucJLwAAAAB8A+2XAMCiVwkOIucJLwAAAAPtlwDAYlcJDyLnCS8AAAAD7YEA4lE"
    . "JEiLRCQghcAPhKoBAACLRCRAiXwkLDHbi2wkKIu8JLwAAACJRCRo62KNtCYAAAAA"
    . "OVwkMH5Ii4Qk3AAAAIsUmAHyD7ZEFwIPtkwXAStEJDgrTCQ8D7YUFytUJEgPr8AP"
    . "r8mNBEAPr9KNBIiNBFA5hCS0AAAAcgeDbCRoAXhhg8MBOVwkIA+EogEAADlcJBR+"
    . "n4uEJNgAAACLFJgB8g+2RBcCD7ZMFwErRCQ4K0wkPA+2FBcrVCRID6@AD6@JjQRA"
    . "D6@SjQSIjQRQOYQktAAAAA+DWv@@@4PtAQ+JUf@@@4t8JCyDfCQkCQ+EKfj@@4NE"
    . "JEwB6Try@@+DRCQQAekm+P@@g0QkRAHpEfL@@410JgCF2w+EoAAAAAOEJNQAAACL"
    . "XCRAMdKLbCQoicHrJTlUJDB+Fou0JNwAAACLBJYByPYAAXUFg+sBeJqDwgE5VCQg"
    . "dGo5VCQUftWLtCTYAAAAiwSWAcj2AAJ1xIPtAXm@6XD@@@@HRCQEAwAAAOlB8P@@"
    . "i3wkCMYEBwLpEf3@@8cEJAMAAADpOfD@@8dEJCgAAAAAx0QkFAAAAADpGPX@@4NE"
    . "JBgB6XD3@@+LbCQoi4Qk+AAAAINEJAwBhcAPhMoDAACLVCQYA5QkyAAAAItcJAyL"
    . "RCQQA4QkxAAAAIu0JPgAAADB4hCNi@@@@z8J0IkEjou0JLgAAACF9g+F0gIAAItE"
    . "JCiLdCQ0Keg5nCT8AAAAiQSOD44z8v@@6bb+@@+LfCQs64mLtCSEAAAAjQSQiUQk"
    . "PIX2D4WuAQAAi1wkIItEJFAx9otsJCiF24lEJGgPhFn@@@+LhCTYAAAAi1wkaItU"
    . "JDwDFLCJXCRIa8YWgTv@@@8AiUQkOA+XwA+2wIlEJCyLhCTcAAAAiwSwiYQktAAA"
    . "AIuEJLwAAAAPtkQQAomEJIwAAADB4BCJwYuEJLwAAAAPtkQQAYmEJJAAAADB4AgJ"
    . "yIuMJLwAAAAPtgwRCciJjCSUAAAAiYQkiAAAAOsfD6@SD6@JjRRSD6@AjRSKjQRC"
    . "OccPg70AAACDRCRICItEJDg7hCS0AAAAD4PPAAAAi1QkeIt8JEiDRCQ4AoXSiweL"
    . "fwR0JoX2i5wkiAAAAA9FnCSwAAAAhcAPlMAPtsCJRCQsiZwksAAAAInYicIPtswP"
    . "tsDB6hArjCSQAAAAK4QklAAAAA+20iuUJIwAAACB@@@@@wAPhmX@@@+J+8HrEA+2"
    . "2w+v0g+v2znaD4dp@@@@ifsPttcPr8kPr9I50Q+HVv@@@4n7D7bTD6@AD6@SOdAP"
    . "h0P@@@+LRCQshcB0CYPtAQ+IDf3@@4PGAYNEJGhYOXQkIA+Fe@7@@+nP@f@@i0Qk"
    . "LIXAdeHr1otMJCCLbCQohckPhLX9@@8x9usuOUQkcHwSD6@JOUwkdHwJD6@SOVQk"
    . "bH0Jg+0BD4i3@P@@g8YBOXQkIA+Eg@3@@4uEJNgAAACLVCQ8i5wkvAAAAAMUsIuE"
    . "JNwAAACLBLCJhCSwAAAAi4QkvAAAAIuMJLAAAAAPtkQQAsHpEA+2ySnID7ZMEwGL"
    . "nCSwAAAAD6@AD7bfKdmLnCS8AAAAD7YUEw+2nCSwAAAAKdqB@@@@@wAPh1z@@@8P"
    . "r8mNBEAPr9KNBIiNBFA5xw+CXf@@@+lh@@@@x0QkKAAAAADHRCQUAAAAAOnC9@@@"
    . "i1wkDDmcJPwAAACJ2A+OrfD@@4tcJBgxyYnOidgrhCQEAQAAg8ABD0jBicKJ2Iuc"
    . "JAQBAACNRBj@i1wkCDnDD07Di1wkEInFidgrhCQAAQAAg8ABD0nwidiLnCQAAQAA"
    . "jUQY@4tcJAQ5ww9OwznVicMPjIz7@@+LhCTMAAAAg8UBD6@CA4Qk1AAAAInBjUMB"
    . "iUQkIDnefw+J8IAkAQODwAE7RCQgdfODwgEDjCTMAAAAOep13+lJ+@@@i6wkuAAA"
    . "AIXtD4VK@@@@6TX7@@+QkA=="
    x64:="QVdBVkFVQVRVV1ZTSIHsyAAAAEhjhCRQAQAASIu8JKgBAACJjCQQAQAAiVQkMESJ"
    . "jCQoAQAAi7QkgAEAAIusJIgBAABJicRIiUQkWEgDhCRgAQAAg@kFSIlEJChIY4Qk"
    . "sAEAAEiNBIdIiUQkYA+E3AUAAIXtD44BDAAARTH2iVwkEIu8JLgBAABEiXQkCIuc"
    . "JBABAABFMe1Mi7QkcAEAAEUx20Ux@0SJbCQYRImEJCABAABMY1QkCEUxyUUxwEwD"
    . "lCR4AQAAhfZ@Mut3Dx9AAEEPr8SJwUSJyJn3@gHBQ4A8AjF0PEmDwAFJY8dBAflB"
    . "g8cBRDnGQYkMhn5DRInYmff9g@sEdckPr4QkOAEAAInBRInImff+Q4A8AjGNDIF1"
    . "xEiLlCRoAQAASYPAAUljxUEB+UGDxQFEOcaJDIJ@vQF0JAiDRCQYAUQDnCTAAQAA"
    . "i0QkGDnFD4VX@@@@RInoi1wkEESLhCQgAQAAD6+EJJABAABEiWwkGMH4ColEJByL"
    . "hCSYAQAAQQ+vx8H4ColEJECDvCQQAQAABA+EtwUAAIuEJDgBAACLvCRAAQAAD6+E"
    . "JEgBAACNBLiLvCQ4AQAAiUQkCESJ4PfYg7wkEAEAAAGNBIeJRCQgD4SxBQAAg7wk"
    . "EAEAAAIPhIQHAACDvCQQAQAAAw+EowoAAIuEJFgBAACFwA+OHwEAAESJfCQQRIuc"
    . "JBABAABBjWwk@0yLfCQoi7wkoAEAAEUx9kUx7YlcJAhEiYQkIAEAAA8fhAAAAAAA"
    . "RYXkD467AAAASWPFMclJicFNjUQHAUwDjCRgAQAA6xhBxgEEg8EBSYPBAUmDwAFB"
    . "OcwPhIkAAABBg@sDf+KFyUEPtlD@D4S1DgAAQQ+2WP45zQ+Euw4AAEUPthCF@w+E"
    . "fAEAAA+28rgGAAAAg+4Bg@4BdhiD+wFAD5TGQYP6AQ+UwAnwD7bAAcCDyASB4v0A"
    . "AAC+AQAAAHQOhdtAD5TGRYXSD5TCCdYJ8IPBAUmDwQFBiEH@SYPAAUE5zA+Fd@@@"
    . "@0UB5UGDxgFEObQkWAEAAA+PKv@@@4tcJAhEi3wkEESLhCQgAQAAg7wkEAEAAAN@"
    . "FouEJKABAACFwA+VwDwBg5wkQAEAAP+LfCQYi3QkHDHARInlRIucJFgBAAA59w9O"
    . "+EQ7fCRAiXwkGEQPTvgrrCS4AQAARCucJMABAACDvCQoAQAACQ+EuQAAAIuEJCgB"
    . "AACD6AGD+AcPh5ACAACD+AOJRCRID46LAgAAiWwkCESJXCQQRTH2x0QkTAAAAACL"
    . "fCRMOXwkCMdEJGgAAAAAD4wNAQAAi3wkaDl8JBAPjNIMAACLfCRIi3QkTItEJAgp"
    . "8ED2xwIPRMaLdCRoicKLRCQQKfBA9scBD0TGg@8DidcPT@gPT8JBicXptgoAAGaQ"
    . "D7bCg+gBg@gCGcCD4AKDwASB4v0AAAAPlMIJ0EGIAekg@v@@iehBjVMBRIlcJAjB"
    . "6B+JbCQQx4QkiAAAAAAAAAAB6MeEJIQAAAABAAAAx0QkbAAAAADR+MdEJHwAAAAA"
    . "QYnFRInYwegfRAHY0fiJx41FAYnGD6@yOdAPTMJFMfaDwAiJtCSkAAAAicYPr@CJ"
    . "tCSoAAAAi7QkpAAAADm0JIgAAAB9HIu0JKgAAAA5dCR8x4QkgAAAAAAAAAAPjEYE"
    . "AACLhCQoAQAAhcAPhV0CAABIg7wkqAEAAAAPhE4CAACLhCTAAQAAD6+EJLgBAACD"
    . "+AEPhDYCAABBg@4BD45dCQAAQY1G@kyLRCRgTIucJKgBAABFMclFMdJIjRyFBAAA"
    . "AEOLdAgEQ4sUCESJ0UOLfAsETInQOdZyE+kJBAAAZpBIg+gBQYsUgDnWcx1BiVSA"
    . "BEGLFIOD6QGD+f9BiVSDBHXeSMfA@@@@@0mDwQRIg8ABSYPCAUk52UGJNIBBiTyD"
    . "dZ9Ei5QkuAEAAIucJMABAABFD6@SD6@bTIuMJKgBAAAx9jHAQYsssYnvRA+33cHv"
    . "EIXAdDJFMcAPH4QAAAAAAEOLDIEPt9FEKdoPr9JEOdJ9DMHpECn5D6@JOdl8E0mD"
    . "wAFEOcB@2Uhj0IPAAUGJLJFIg8YBQTn2f6pIgcTIAAAAW15fXUFcQV1BXkFfw8dE"
    . "JEgAAAAARIlcJAiJbCQQRTH2x0QkTAAAAADpcP3@@4tEJDAx@4P4AkAPlMeJvCSs"
    . "AAAAD4SpAwAAMcCDfCQwAQ+UwEWFwImEJKAAAAAPhNsKAABEiaQkUAEAAEyLlCR4"
    . "AQAARTHJi7wkOAEAAEyLpCRoAQAARTHbTIusJHABAABEi7QkuAEAAESLvCTAAQAA"
    . "iVwkGEGLGkmDwliJ2MHoEEEPr8eZ9@0Pr8eJwQ+3w0EPr8aZ9@6NBIFDiQSMQYtC"
    . "rEGNBENBg8MWQ4lEjQBJg8EBRTnId72LhCSQAQAARIukJFABAACJXCQwi1wkGESJ"
    . "RCQYQQ+vwMH4ColEJBxIi4QkeAEAAMdEJEAAAAAARTH@SIPACEiJBCTpq@r@@0SJ"
    . "8OnE@v@@i3wkMIn4wegQD6+EJMABAACZ9@0Pr4QkOAEAAInBD7fHD6+EJLgBAACZ"
    . "9@6NBIGJRCQw6Wv6@@+J6ESLjCRYAQAARQHAD6@GSJhIA4QkeAEAAEWFyUiJBCQP"
    . "jnL7@@9CjTylAAAAAMdEJBAAAAAAMcDHRCRIAAAAAESJfCR4iXwkUEWF5A+O6QAA"
    . "AEhjVCQISIu8JDABAABFMe1MY3QkSEwDdCQoSI1sFwJMiwwkRTHSD7Z9AA+2df9E"
    . "D7Zd@usmZi4PH4QAAAAAAA+vyQ+v0o0MSQ+vwI0UkY0EQjnDc2hJg8EIMcBFOcIP"
    . "gxsBAABBiwFBi1kEQYPCAonBD7bUD7bAwekQKfJEKdgPtskp+YH7@@@@AHazQYnf"
    . "QcHvEEUPtv8Pr8lFD6@@RDn5d7IPts8Pr9IPr8k5ynelD7bTD6@AD6@SOdB3mLoB"
    . "AAAAuAEAAABDiBQuSYPFAUiDxQRFOewPj0P@@@+LdCRQRAFkJEgBdCQIg0QkEAGL"
    . "VCQgi3wkEAFUJAg5vCRYAQAAD4Xw@v@@RIt8JHjpFvn@@0WF7XgVRDtsJBB@DoX@"
    . "eAo7fCQID464BQAAi0QkbIXAD4WNBQAAg+8Bg4QkgAAAAAGDRCR8AYuUJIQAAAA5"
    . "lCSAAAAAfLqLdCRsifCD4AEBwonwg8ABiZQkhAAAAIPgA4lEJGzpW@v@@w8fRAAA"
    . "icLpQf@@@0yJ0Oka@P@@i0QkMIuMJFgBAAAx9jH@Qo0spQAAAACDwAHB4AeFyYlE"
    . "JDAPjo@5@@9Ei3QkCESLbCQwRYXkflVIi5QkMAEAAExj30wDXCQoSWPGRTHJSI1M"
    . "AgIPthEPtkH@RA+2Uf5rwEtr0iYBwkSJ0MHgBEQp0AHQQTnFQw+XBAtJg8EBSIPB"
    . "BEU5zH@MQQHuRAHng8YBRAN0JCA5tCRYAQAAdZXp9vf@@4noRQHAD6@GweACSJhI"
    . "A4QkeAEAAEiJBCSLhCSYAQAAwfgKg8ABhe2JRCQID46VCgAAi3wkCIuEJMABAADH"
    . "RCRIAAAAAMdEJBgAAAAARImkJFABAACJrCSIAQAAD6@HiXwkUIlEJHiJ+A+vxsHg"
    . "AkiYSIlEJHBIi4QkeAEAAEiJRCRAifjB4AJImEiJRCQQi4QkuAEAAA+vx4lEJBxI"
    . "iwQkSIPACEiJRCQghfYPjiYBAABIi3wkQESLZCQIMe0Ptl8CTItMJCBBvgIAAABE"
    . "D7ZXAUQPth9Bid3rHQ8fAA+v2w+v0o0cWw+vwI0Uk40EQjnBc2pJg8EIRTnwD4Z9"
    . "AAAAQYsBQYtJBEGDxgKJww+21A+2wMHrEEQp0kQp2A+220Qp64H5@@@@AHazQYnP"
    . "QcHvEEUPtv8Pr9tFD6@@RDn7d7IPtt0Pr9IPr9s52nelD7bJD6@AD6@JOch3mGaQ"
    . "i0QkCEgDfCQQA2wkHEQB4EQ55n5lQYnE6UP@@@8PHwCLRCRIRIt0JBhEievB4xBB"
    . "weIIQQnamU1jzkUJ2ve8JIgBAAAPr4QkOAEAAInBieiZ9@5Ii5QkaAEAAI0EgUKJ"
    . "BIpEifCDwAGJRCQYSIuEJHABAABGiRSI64aLfCRQi0QkCItUJHgBVCRISItUJHBI"
    . "AVQkQAH4ObwkiAEAAH4JiUQkUOmk@v@@i0QkGESLpCRQAQAAD6+EJJABAADB+AqJ"
    . "RCQcSIsEJMdEJEAAAAAARTH@i1gEidgPts8PttPB6BAPtsCJxw+v+InID6@Bibwk"
    . "mAAAAImEJJwAAACJ0A+vwomEJJQAAADpffX@@8dEJEAAAAAAx0QkHAAAAABFMf@H"
    . "RCQYAAAAAOn19P@@i5QkWAEAAIXSD4589v@@Q40EZESLdCQIQo0spQAAAAAx9jH@"
    . "SJhIA4QkYAEAAEmJxUWF5H5aSIuUJDABAABJY8ZMY99FMclNAetIjUwCAg8fRAAA"
    . "D7YRSIPBBERr0iYPtlH7a8JLQY0UAkQPtlH6RInQweAERCnQAdDB+AdDiAQLSYPB"
    . "AUU5zH@KQQHuRAHng8YBRAN0JCA5tCRYAQAAdZBIi3wkWDHSQY1sJP9EiXwkSEUx"
    . "0olcJCBBiddIifhIg8ABSIlEJAi4AQAAAEiJxouEJFgBAABIKf6LfCQwSIl0JBBE"
    . "jXD@RYXkD47TAAAASItEJAhNY99Ii3QkKEuNVB0BTo0MGEiLRCQQTAHeTQHpSo0M"
    . "GDHATAHpZi4PH4QAAAAAAEiFwA+EgQMAADnFD4R5AwAARYXSD4RwAwAARTnWD4Rn"
    . "AwAARA+2Qv9ED7Za@rsBAAAAQQH4RTnYckZED7YaRTnYcj1ED7ZZ@0U52HIzRQ+2"
    . "Wf9FOdhyKUQPtln+RTnYch9ED7YZRTnYchZFD7ZZ@kU52HIMRQ+2GUU52A+Sw2aQ"
    . "iBwGSIPAAUiDwgFJg8EBSIPBAUE5xA+PZP@@@0UB50GDwgFEOZQkWAEAAA+FEv@@"
    . "@4tcJCBEi3wkSOmJ8@@@RIuUJLgBAACLnCTAAQAAMcBFD6@SD6@bRYX2D4569@@@"
    . "6RP3@@+DfCRsAQ+E@AEAAIN8JGwCD4S4AgAAQYPtAelX+v@@g4QkiAAAAAHHRCRI"
    . "CQAAAIn4SIu0JGABAABBD6@ERo0MKEljwYA8BgMPhqQBAACLRCQYRDn4QQ9Mx4O8"
    . "JBABAAADiUQkIA+OsAEAAIuEJEgBAACLlCRAAQAAAfhEAeoPr4QkOAEAAIO8JBAB"
    . "AAAFD4TAAgAARI0MkItEJDBIi7QkMAEAAESLVCQgRAHIjVACRYXSSGPSD7Y0Fo1Q"
    . "AUiYSGPSiXQkUEiLtCQwAQAAD7Y0Fol0JHhIi7QkMAEAAA+2BAaJRCRwD4TrAQAA"
    . "i0QkQESJXCQoRTHSi3QkHEyLnCQwAQAAiYQkjAAAAOtyRDu8JJAAAAB+WUiLhCRw"
    . "AQAAQosUkEQByo1CAo1KAUhj0kEPthQTSJhIY8krVCRwQQ+2BANBD7YMCytEJFAr"
    . "TCR4D6@SD6@AD6@JjQRAjQSIjQRQQTnAcgqDrCSMAAAAAXh+SYPCAUQ5VCQgD47P"
    . "AQAARDlUJBhEiZQkkAAAAA+Oe@@@@0iLhCRoAQAAQosUkEQByo1CAo1KAUhj0kEP"
    . "thQTSJhIY8krVCRwQQ+2BANBD7YMCytEJFArTCR4D6@SD6@AD6@JjQRAjQSIjQRQ"
    . "QTnAD4Mo@@@@g+4BD4kf@@@@RItcJCiDfCRICQ+Eavj@@4NEJGgB6Snz@@9Bg8UB"
    . "6Wb4@@+DRCRMAekA8@@@kIXAD4SzAAAARItUJECLdCQcMcnrM0Q7fCQofiJIi5Qk"
    . "cAEAAESJyAMEikiLlCRgAQAA9gQCAXUGQYPqAXiZSIPBATlMJCB+dzlMJBiJTCQo"
    . "fsNIi4QkaAEAAESJygMUiEiLhCRgAQAA9gQQAnWng+4BeaLpX@@@@w8fhAAAAAAA"
    . "uwMAAADpRvH@@8YEBgLp8Pz@@0G6AwAAAOk+8f@@x0QkHAAAAADHRCQYAAAAAOm7"
    . "9f@@g8cB6aD3@@+LdCQcQYPGAUiDvCSoAQAAAA+EHQQAAEljxouUJEgBAABIjQyF"
    . "AAAAAIuEJEABAAAB+sHiEEQB6AnQSIuUJKgBAACJRAr8i5QkKAEAAIXSD4UeAwAA"
    . "i0QkHCnwRDm0JLABAABIi3QkYIlEDvwPjhPz@@@ppf7@@0SLXCQo64aNBJCJRCQo"
    . "i4QkrAAAAIXAD4XjAQAAi0QkIIXAD4Rg@@@@SIsEJIt0JBxFMcnHRCR4AAAAAESJ"
    . "dCRwRIm8JIwAAABEiZwkkAAAAEiJRCRQSIuEJGgBAACLTCQoTIu8JDABAABMi1Qk"
    . "UEyLhCRwAQAARItcJHhCAwyIQYE6@@@@AEeLBIiNUQKNQQFIY8lBD5fGSGPSSJhF"
    . "D7b2QQ+2FBdBD7YEB4mUJLQAAACJhCS4AAAAweIQweAICdBBD7YUDwnQiZQkvAAA"
    . "AImEJLAAAADrHg+v0g+vyY0UUg+vwI0Uio0EQjnDD4OvAAAASYPCCEU5ww+D4AAA"
    . "AESLvCSgAAAAQYPDAkGLAkGLWgRFhf90Hk2FyYtUJDAPRJQksAAAAEUx9oXAQQ+U"
    . "xolUJDCJ0InCD7bMD7bAweoQK4wkuAAAACuEJLwAAAAPttIrlCS0AAAAgfv@@@8A"
    . "D4Z0@@@@QYnfQcHvEEUPtv8Pr9JFD6@@RDn6D4dz@@@@D7bXD6@JD6@SOdEPh2L@"
    . "@@8PttMPr8APr9I50A+HUf@@@0WF9nQFg+4BeDtJg8EBSINEJFBYg0QkeBZEOUwk"
    . "IA+Pkf7@@0SLdCRwRIu8JIwAAABEi5wkkAAAAOmu@f@@RYX2dcfrwESLdCRwRIu8"
    . "JIwAAABEi5wkkAAAAOml@P@@i0QkIIt0JByFwA+Eff3@@0Ux0us5OYQkmAAAAHwY"
    . "D6@JOYwknAAAAHwMD6@SOZQklAAAAH0Jg+4BD4hm@P@@SYPCAUQ5VCQgD44@@f@@"
    . "SIuEJGgBAACLVCQoTIuMJDABAABCAxSQSIuEJHABAABCiwSQicGNQgKJTCQwwekQ"
    . "SJgPtslBD7YEASnIjUoBSGPSD6@ASGPJRQ+2DAlIi0wkMA+2zUEpyUSJyUyLjCQw"
    . "AQAAQQ+2FBFED7ZMJDBEKcqB+@@@@wAPh0r@@@8Pr8mNBEAPr9KNBIiNBFA5ww+C"
    . "VP@@@+lY@@@@x0QkHAAAAADHRCQYAAAAAOlF9@@@RDm0JLABAABEifAPjhvx@@+J"
    . "+CuEJMABAABFMdKDwAFBD0jCicGLhCTAAQAAjUQH@0E5w0EPTsOJxkSJ6CuEJLgB"
    . "AACDwAFED0nQi4QkuAEAAEGNRAX@OcUPTsU5zolEJCAPjEH7@@9EieJJY8IPr9FI"
    . "Y9JIAdBIA4QkYAEAAEmJwY1GAYlEJCiLRCQgRCnQSI1wAUQ7VCQgfxNKjRQOTInI"
    . "gCADSIPAAUg50HX0g8EBTANMJFg7TCQoddjp6Pr@@4uMJCgBAACFyQ+FQf@@@+nU"
    . "+v@@kJCQkJCQkJCQkJCQkA=="
    MyFunc:=this.MCode(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]
  ok:=(!ini.bits.Scan0 || mode<1 || mode>5) ? 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
    , "Ptr",text, "int",w, "int",h
    , "int",Floor(Abs(err1)*1024), "int",Floor(Abs(err0)*1024)
    , "int",(err1<0||err0<0), "Ptr",ini.allpos, "int",ini.allpos_max
    , "int",Floor(w*ini.zoomW), "int",Floor(h*ini.zoomH))
  return ok
}

code()
{
return "
(

//***** C source code of machine code *****
// gcc.exe -m32/-m64 -O2

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, int more_err
  , unsigned int * allpos, int allpos_max
  , int new_w, int new_h )
{
  int ok, o, i, j, k, v, e1, e0, len1, len0, max, pic, shape, sort;
  int x, y, x1, y1, x2, y2, x3, y3, r, g, b, rr, gg, bb, dR, dG, dB;
  int ii, jj, RunDir, DirCount, RunCount, AllCount1, AllCount2;
  unsigned int c1, c2, *cors, *arr;
  unsigned char *ts, *gs;
  ok=0; o=0; v=0; len1=0; len0=0; ts=ss+sw; gs=ss+sw*3;
  arr=allpos+allpos_max; sort=(dir==0);
  //----------------------
  if (mode==5)
  {
    if (pic=(c==2))  // FindPic
    {
      cors=(unsigned int *)(text+w*h*4); j=(err0>>10)+1; n*=2;
      for (y=0; y<h; y+=j)
      {
        for (x=0; x<w; x+=j)
        {
          o=(y*w+x)*4; rr=text[2+o]; gg=text[1+o]; bb=text[o];
          for (i=2; i<n;)
          {
            c1=cors[i++]; c2=cors[i++];
            r=((c1>>16)&0xFF)-rr; g=((c1>>8)&0xFF)-gg; b=(c1&0xFF)-bb;
            v=(c2<0x1000000) ? (3*r*r+4*g*g+2*b*b<=c2)
            : (r*r<=((c2>>16)&0xFF)*((c2>>16)&0xFF)
            && g*g<=((c2>>8)&0xFF)*((c2>>8)&0xFF) && b*b<=(c2&0xFF)*(c2&0xFF));
            if (v) goto NoMatch1;
          }
          s1[len1]=(y*new_h/h)*Stride+(x*new_w/w)*4;
          s0[len1++]=rr<<16|gg<<8|bb;
          NoMatch1:;
        }
      }
      c2=cors[1]; r=(c2>>16)&0xFF; g=(c2>>8)&0xFF; b=c2&0xFF; dR=r*r; dG=g*g; dB=b*b;
    }
    else  // FindMultiColor or FindColor
    {
      shape=(c==1);  // FindShape
      cors=(unsigned int *)text;
      for (i=0; i<n; i++, o+=22)
      {
        c=cors[o]; y=c>>16; x=c&0xFFFF;
        s1[len1]=(y*new_h/h)*Stride+(x*new_w/w)*4;
        s0[len1++]=o+cors[o+1]*2;
      }
      cors+=2;
    }
    goto StartLookUp;
  }
  //----------------------
  // Generate Lookup Table
  for (y=0; y<h; y++)
  {
    for (x=0; x<w; x++)
    {
      i=(mode==4) ? (y*new_h/h)*Stride+(x*new_w/w)*4 : (y*new_h/h)*sw+(x*new_w/w);
      if (text[o++]=='1')
        s1[len1++]=i;
      else
        s0[len0++]=i;
    }
  }
  //----------------------
  // Color Position Mode
  // only used to recognize multicolored Verification Code
  if (mode==4)
  {
    y=c>>16; x=c&0xFFFF;
    c=(y*new_h/h)*Stride+(x*new_w/w)*4;
    goto StartLookUp;
  }
  //----------------------
  // Generate Two Value Image
  o=sy*Stride+sx*4; j=Stride-sw*4; i=0;
  if (mode==1)  // Color Mode
  {
    cors=(unsigned int *)(text+w*h); n*=2;
    for (y=0; y<sh; y++, o+=j)
    {
      for (x=0; x<sw; x++, o+=4, i++)
      {
        rr=Bmp[2+o]; gg=Bmp[1+o]; bb=Bmp[o];
        for (k=0; k<n;)
        {
          c1=cors[k++]; c2=cors[k++];
          r=((c1>>16)&0xFF)-rr; g=((c1>>8)&0xFF)-gg; b=(c1&0xFF)-bb;
          v=(c2<0x1000000) ? (3*r*r+4*g*g+2*b*b<=c2)
          : (r*r<=((c2>>16)&0xFF)*((c2>>16)&0xFF)
          && g*g<=((c2>>8)&0xFF)*((c2>>8)&0xFF) && b*b<=(c2&0xFF)*(c2&0xFF));
          if (v) break;
        }
        ts[i]=(v) ? 1:0;
      }
    }
  }
  else if (mode==2)  // Gray Threshold Mode
  {
    c=(c+1)<<7;
    for (y=0; y<sh; y++, o+=j)
      for (x=0; x<sw; x++, o+=4, i++)
        ts[i]=(Bmp[2+o]*38+Bmp[1+o]*75+Bmp[o]*15<c) ? 1:0;
  }
  else if (mode==3)  // Gray Difference Mode
  {
    for (y=0; y<sh; y++, o+=j)
    {
      for (x=0; x<sw; x++, o+=4, i++)
        gs[i]=(Bmp[2+o]*38+Bmp[1+o]*75+Bmp[o]*15)>>7;
    }
    for (i=0, y=0; y<sh; y++)
    for (x=0; x<sw; x++, i++)
    if (x==0 || x==sw-1 || y==0 || y==sh-1)
      ts[i]=2;
    else
    {
      n=gs[i]+c;
      ts[i]=(gs[i-1]>n || 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;
    }
  }
  //----------------------
  StartLookUp:
  for (i=0, y=0; y<sh; y++)
  {
    for (x=0; x<sw; x++, i++)
    {
      if (mode>=4) { ss[i]=4; continue; }
      r=ts[i]; g=(x==0 ? 3 : ts[i-1]); b=(x==sw-1 ? 3 : ts[i+1]);
      if (more_err)
        ss[i]=4|(r==2||r==1||g==1||b==1)<<1|(r==2||r==0||g==0||b==0);
      else
        ss[i]=4|(r==2||r==1)<<1|(r==2||r==0);
    }
  }
  if (mode<4 && more_err) sx++;
  err1=(len1*err1)>>10;
  err0=(len0*err0)>>10;
  if (err1>=len1) len1=0;
  if (err0>=len0) len0=0;
  max=(len1>len0) ? len1 : len0;
  w=new_w; h=new_h; x1=0; y1=0; x2=sw-w; y2=sh-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
  // 9 ==> Center to Four Sides
  if (dir==9)
  {
    x=(x1+x2)/2; y=(y1+y2)/2; i=x2-x1+1; j=y2-y1+1;
    AllCount1=i*j; i=(i>j?i:j)+8;
    AllCount2=i*i; RunCount=0; DirCount=1; RunDir=0;
    for (ii=0; RunCount<AllCount1 && ii<AllCount2;)
    {
      for(jj=0; jj<DirCount; jj++, ii++)
      {
        if(x>=x1 && x<=x2 && y>=y1 && y<=y2)
        {
          RunCount++;
          goto FindPos;
          FindPos_GoBak:;
        }
        if (RunDir==0) y--;
        else if (RunDir==1) x++;
        else if (RunDir==2) y++;
        else x--;
      }
      if (RunDir & 1) DirCount++;
      RunDir = (++RunDir) & 3;
    }
    goto Return1;
  }
  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 & 2) ? y1+y2-y3 : y3;
      x=(dir & 1) ? x1+x2-x3 : x3;
      if (dir>3) { r=y; y=x; x=r; }
      //----------------------
      FindPos:
      e1=err1; e0=err0; o=y*sw+x;
      if (ss[o]<4) goto NoMatch;
      if (mode<4)
      {
        for (i=0; i<max; i++)
        {
          if (i<len1 && (ss[o+s1[i]]&2)==0 && (--e1)<0) goto NoMatch;
          if (i<len0 && (ss[o+s0[i]]&1)==0 && (--e0)<0) goto NoMatch;
        }
      }
      else if (mode==5)
      {
        o=(sy+y)*Stride+(sx+x)*4;
        if (pic)
        {
          for (i=0; i<max; i++)
          {
            j=o+s1[i]; c=s0[i]; r=Bmp[2+j]-((c>>16)&0xFF);
            g=Bmp[1+j]-((c>>8)&0xFF); b=Bmp[j]-(c&0xFF);
            v=(c2<0x1000000)?(3*r*r+4*g*g+2*b*b>c2):(r*r>dR||g*g>dG||b*b>dB);
            if (v && (--e1)<0) goto NoMatch;
          }
        }
        else
        {
          for (i=0; i<max; i++)
          {
            j=o+s1[i]; rr=Bmp[2+j]; gg=Bmp[1+j]; bb=Bmp[j];
            for (j=i*22, k=cors[j]>0xFFFFFF, n=s0[i]; j<n;)
            {
              c1=cors[j++]; c2=cors[j++];
              if (shape) { if (i==0) c=rr<<16|gg<<8|bb; k=!c1; c1=c; }
              r=((c1>>16)&0xFF)-rr; g=((c1>>8)&0xFF)-gg; b=(c1&0xFF)-bb;
              v=(c2<0x1000000) ? (3*r*r+4*g*g+2*b*b<=c2)
              : (r*r<=((c2>>16)&0xFF)*((c2>>16)&0xFF)
              && g*g<=((c2>>8)&0xFF)*((c2>>8)&0xFF) && b*b<=(c2&0xFF)*(c2&0xFF));
              if (v) { if (k) goto NoMatch2; goto MatchOK; }
            }
            if (k) goto MatchOK;
            NoMatch2:
            if ((--e1)<0) goto NoMatch;
            MatchOK:;
          }
        }
      }
      else  // mode==4
      {
        o=(sy+y)*Stride+(sx+x)*4; j=o+c; rr=Bmp[2+j]; gg=Bmp[1+j]; bb=Bmp[j];
        for (i=0; i<max; i++)
        {
          if (i<len1)
          {
            j=o+s1[i]; r=Bmp[2+j]-rr; g=Bmp[1+j]-gg; b=Bmp[j]-bb;
            if (3*r*r+4*g*g+2*b*b>n && (--e1)<0) goto NoMatch;
          }
          if (i<len0)
          {
            j=o+s0[i]; r=Bmp[2+j]-rr; g=Bmp[1+j]-gg; b=Bmp[j]-bb;
            if (3*r*r+4*g*g+2*b*b<=n && (--e0)<0) goto NoMatch;
          }
        }
      }
      ok++;
      if (allpos)
      {
        allpos[ok-1]=(sy+y)<<16|(sx+x); if (sort) arr[ok-1]=err1-e1;
        if (ok>=allpos_max) goto Return1;
      }
      // Skip areas that may overlap
      if (!sort)
      {
        r=y-h+1; if (r<0) r=0; rr=y+h-1; if (rr>sh-h) rr=sh-h;
        g=x-w+1; if (g<0) g=0; gg=x+w-1; if (gg>sw-w) gg=sw-w;
        for (i=r; i<=rr; i++)
          for (j=g; j<=gg; j++)
            ss[i*sw+j] &= 3;
      }
      NoMatch:
      if (dir==9) goto FindPos_GoBak;
    }
  }
  //----------------------
  Return1:
  if (!sort || !allpos || w*h==1)
    return ok;
  // Sort by smallest error
  for (i=1; i<ok; i++)
  {
    k=arr[i]; v=allpos[i];
    for (j=i-1; j>=0 && arr[j]>k; j--)
    {
      arr[j+1]=arr[j]; allpos[j+1]=allpos[j];
    }
    arr[j+1]=k; allpos[j+1]=v;
  }
  // Clean up overlapping results
  w*=w; h*=h; k=ok; ok=0;
  for (i=0; i<k; i++)
  {
    c1=allpos[i]; x1=c1&0xFFFF; y1=c1>>16;
    for (j=0; j<ok; j++)
    {
      c2=allpos[j]; x=(c2&0xFFFF)-x1; y=(c2>>16)-y1;
      if (x*x<w && y*y<h) goto NoMatch3;
    }
    allpos[ok++]=c1;
    NoMatch3:;
  }
  return ok;
}

)"
}

PicInfo(text)
{
  local
  if !InStr(text, "$")
    return
  static init, info, bmp
  if !VarSetCapacity(init) && (init:="1")
    info:=[], bmp:=[]
  key:=(r:=StrLen(v:=Trim(text,"|")))<10000 ? v
    : DllCall("ntdll\RtlComputeCrc32", "uint",0
    , "Ptr",&v, "uint",r*(1+!!A_IsUnicode), "uint")
  if info.HasKey(key)
    return info[key]
  comment:="", seterr:=err1:=err0:=0
  ; You Can Add Comment Text within The <>
  if RegExMatch(v, "O)<([^>\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, "O)\[([^\]\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 : 1
  color:=RegExReplace(StrReplace(color,"@","-"), "[*#\s]")
  (mode=1 || mode=5) && color:=StrReplace(color,"0x")
  if (mode=5)
  {
    if !(v~="^[\s\-\w.]+/[\s\-\w.]+/[\s\-\w./,]+$")  ; <FindPic>
    {
      if !(hBM:=LoadPicture(v))
      {
        MsgBox, 4096, Tip, Can't Load Picture ! %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
      arr:=StrSplit(color "/", "/"), arr.Pop(), n:=arr.Length()
      bmp.Push(buf:=this.Buffer(w*h*4 + n*2*4)), v:=buf.Ptr, p:=v+w*h*4-4
      DllCall("RtlMoveMemory", "Ptr",v, "Ptr",Scan0, "Ptr",w*h*4)
      DllCall("DeleteObject", "Ptr",hBM2), color:=Trim(arr[1],"-")
      For k1,v1 in arr
        c:=StrSplit(Trim(v1,"-") "-" color, "-")
        , x:=this.Floor(c[2]), x:=(x<=0||x>1?0:Floor(9*255*255*(1-x)*(1-x)))
        , NumPut(this.ToRGB(c[1]), 0|p+=4, "uint")
        , NumPut((InStr(c[2],".")?x:this.Floor("0x" c[2])|0x1000000), 0|p+=4, "uint")
      color:=2
    }
    else  ; <FindMultiColor> or <FindColor> or <FindShape>
    {
      color:=Trim(StrSplit(color "/", "/")[1], "-")
      arr:=StrSplit(Trim(RegExReplace(v, "i)\s|0x"), ","), ",")
      if !(n:=arr.Length())
        return
      bmp.Push(buf:=this.Buffer(n*22*4)), v:=buf.Ptr
      shape:=(n>1 && StrLen(StrSplit(arr[1] "//","/")[3])=1 ? 1:0)
      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))
      }
      For k1,v1 in arr
      {
        r:=StrSplit(v1 "/","/"), x:=this.Floor(r[1])-x1, y:=this.Floor(r[2])-y1
        , NumPut(y<<16|x, 0|p:=v+(A_Index-1)*22*4, "uint")
        , NumPut(n1:=Min(Max(r.Length()-3,0),(shape?1:10)), 0|p+=4, "uint")
        Loop % n1
          c:=StrSplit(Trim(v1:=r[2+A_Index],"-") "-" color, "-")
          , x:=this.Floor(c[2]), x:=(x<=0||x>1?0:Floor(9*255*255*(1-x)*(1-x)))
          , NumPut(this.ToRGB(c[1])&0xFFFFFF|(!shape&&InStr(v1,"-")=1?0x1000000:0), 0|p+=4, "uint")
          , NumPut((InStr(c[2],".")?x:this.Floor("0x" c[2])|0x1000000), 0|p+=4, "uint")
      }
      color:=shape, w:=x2-x1+1, h:=y2-y1+1
    }
  }
  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
    arr:=StrSplit(color "/", "/"), arr.Pop(), n:=arr.Length()
    , bmp.Push(buf:=this.Buffer(StrPut(v, "CP0") + n*2*4))
    , StrPut(v, buf.Ptr, "CP0"), v:=buf.Ptr, p:=v+w*h-4
    , color:=this.Floor(color)
    if (mode=1)
    {
      For k1,v1 in arr
        c:=StrSplit(Trim(v1,"-") "-", "-")
        , x:=this.Floor(c[2]), x:=(x<=0||x>1?0:Floor(9*255*255*(1-x)*(1-x)))
        , NumPut(this.ToRGB(c[1]), 0|p+=4, "uint")
        , NumPut((InStr(c[2],".")?x:this.Floor("0x" c[2])|0x1000000), 0|p+=4, "uint")
    }
    else if (mode=4)
    {
      r:=StrSplit(Trim(arr[1],"-") "-", "-")
      , n:=this.Floor(r[2]), n:=(n<=0||n>1?0:Floor(9*255*255*(1-n)*(1-n)))
      , c:=this.Floor(r[1]), color:=(c<1||c>w*h?0:((c-1)//w)<<16|Mod(c-1,w))
    }
  }
  return info[key]:=[v, w, h, seterr, err1, err0, mode, color, n, comment]
}

ToRGB(color)  ; color can use: RRGGBB, Red, Yellow, Black, White
{
  static init, tab
  if !VarSetCapacity(init) && (init:="1")
    tab:=Object("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")
  return this.Floor("0x" (tab.HasKey(color)?tab[color]:color))
}

Buffer(size, FillByte:="")
{
  local
  buf:={}, buf.SetCapacity("_key", size), p:=buf.GetAddress("_key")
  , (FillByte!="" && DllCall("RtlFillMemory","Ptr",p,"Ptr",size,"uchar",FillByte))
  , buf.Ptr:=p, buf.Size:=size
  return buf
}

GetBitsFromScreen(ByRef x:=0, ByRef y:=0, ByRef w:=0, ByRef h:=0
  , ScreenShot:=1, ByRef zx:=0, ByRef zy:=0, ByRef zw:=0, ByRef zh:=0)
{
  local
  static init, CAPTUREBLT
  if !VarSetCapacity(init) && (init:="1")  ; thanks Descolada
  {
    DllCall("Dwmapi\DwmIsCompositionEnabled", "Int*",i:=0)
    CAPTUREBLT:=i ? 0 : 0x40000000
  }
  if InStr(A_OSVersion, ".")  ; thanks QQ:349029755
    DllCall("SetThreadDpiAwarenessContext", "Ptr",-3, "Ptr")
  (!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
  }
  bch:=A_BatchLines, cri:=A_IsCritical
  Critical
  bits.BindWindow:=id:=this.BindWindow(0,0,1)
  if (id)
  {
    WinGet, id, ID, ahk_id %id%
    WinGetPos, zx, zy, zw, zh, ahk_id %id%
  }
  if (!id)
  {
    SysGet, zx, 76
    SysGet, zy, 77
    SysGet, zw, 78
    SysGet, zh, 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
    SetBatchLines % bch
    return bits
  }
  if IsFunc(k:="GetBitsFromScreen2")
    && %k%(bits, x-zx, y-zy, w, h)
  {
    ; Get the bind window use bits.BindWindow
    ; Each small range of data obtained from DXGI must be
    ; copied to the screenshot cache using FindText().CopyBits()
    zx:=bits.zx, zy:=bits.zy, zw:=bits.zw, zh:=bits.zh
    Critical % cri
    SetBatchLines % bch
    return bits
  }
  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("UpdateWindow", "Ptr",id)
      ; RDW_INVALIDATE=0x1|RDW_ERASE=0x4|RDW_ALLCHILDREN=0x80|RDW_FRAME=0x400
      ; DllCall("RedrawWindow", "Ptr",id, "Ptr",0, "Ptr",0, "uint", 0x485)
      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
  SetBatchLines % bch
  return bits
}

UpdateBits(bits, zx, zy, zw, zh)
{
  local
  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, ByRef ppvBits:=0)
{
  local
  VarSetCapacity(bi, 40, 0), NumPut(40, bi, 0, "int")
  , NumPut(w, bi, 4, "int"), NumPut(-h, bi, 8, "int")
  , NumPut(1, bi, 12, "short"), NumPut(bpp, bi, 14, "short")
  return DllCall("CreateDIBSection", "Ptr",0, "Ptr",&bi
    , "int",0, "Ptr*",ppvBits:=0, "Ptr",0, "int",0, "Ptr")
}

GetBitmapWH(hBM, ByRef w, ByRef h)
{
  local
  VarSetCapacity(bm, size:=(A_PtrSize=8 ? 32:24), 0)
  , 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)
{
  local
  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")
  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)
{
  local
  if (w<1 || h<1 || !Scan01 || !Scan02)
    return
  static init, MFCopyImage
  if !VarSetCapacity(init) && (init:="1")
  {
    MFCopyImage:=DllCall("GetProcAddress", "Ptr"
    , DllCall("LoadLibrary", "Str","Mfplat.dll", "Ptr")
    , "AStr","MFCopyImage", "Ptr")
  }
  if (MFCopyImage && !Reverse)  ; thanks QQ:121507989
  {
    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
  SetBatchLines % (bch:=A_BatchLines)?"-1":"-1"
  p1:=Scan01+(y1-1)*Stride1+x1*4
  , p2:=Scan02+(y2-1)*Stride2+x2*4, w*=4
  , (Reverse) && (p2+=(h+1)*Stride2, Stride2:=-Stride2)
  Loop % h
    DllCall("RtlMoveMemory","Ptr",p1+=Stride1,"Ptr",p2+=Stride2,"Ptr",w)
  SetBatchLines % bch
  ListLines % lls
}

DrawHBM(hBM, lines)
{
  local
  mDC:=DllCall("CreateCompatibleDC", "Ptr",0, "Ptr")
  oBM:=DllCall("SelectObject", "Ptr",mDC, "Ptr",hBM, "Ptr")
  oldc:="", brush:=0, VarSetCapacity(rect, 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)
{
  local
  (!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)
    {
      WinGet, i, ExStyle, ahk_id %bind_id%
      bind.oldStyle:=i
      WinSet, Transparent, 255, ahk_id %bind_id%
      Loop 30
      {
        Sleep 100
        WinGet, i, Transparent, ahk_id %bind_id%
      }
      Until (i=255)
    }
  }
  else
  {
    bind_id:=bind.id
    if (bind.mode & 1)
      WinSet, ExStyle, % bind.oldStyle, ahk_id %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)
{
  local
  if (get_cursor)
    return this.Cursor
  if (hDC=1 || hDC=0) && (zw=0)
  {
    this.Cursor:=hDC
    return
  }
  VarSetCapacity(mi, 40, 0), NumPut(16+A_PtrSize, mi, "int")
  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 || y<zy || x>=zx+zw || y>=zy+zh)
    return
  VarSetCapacity(ni, 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(hex)
{
  local
  flag:=((hex~="[^A-Fa-f\d\s]") ? 1:4), len:=0
  Loop 2
    if !DllCall("crypt32\CryptStringToBinary", "Str",hex, "uint",0, "uint",flag
    , "Ptr",(A_Index=1?0:(p:=this.Buffer(len)).Ptr), "uint*",len, "Ptr",0, "Ptr",0)
      return
  if DllCall("VirtualProtect", "Ptr",p.Ptr, "Ptr",len, "uint",0x40, "uint*",0)
    return p
}

bin2hex(addr, size, base64:=0)
{
  local
  flag:=(base64 ? 1:4)|0x40000000, len:=0
  Loop 2
    DllCall("crypt32\CryptBinaryToString", "Ptr",addr, "uint",size, "uint",flag
    , "Ptr",(A_Index=1?0:(p:=this.Buffer(len*2)).Ptr), "uint*",len)
  return RegExReplace(StrGet(p.Ptr, len), "\s+")
}

base64tobit(s)
{
  local
  ListLines % (lls:=A_ListLines)?0:0
  Chars:="0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  SetFormat, IntegerFast, d
  Loop Parse, Chars
    if InStr(s, A_LoopField, 1)
      s:=RegExReplace(s, "[" A_LoopField "]", ((i:=A_Index-1)>>5&1)
      . (i>>4&1) . (i>>3&1) . (i>>2&1) . (i>>1&1) . (i&1))
  s:=RegExReplace(RegExReplace(s,"[^01]+"),"10*$")
  ListLines % lls
  return s
}

bit2base64(s)
{
  local
  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"
  SetFormat, IntegerFast, d
  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)
{
  local
  if RegExMatch(s, "O)\$(\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)
{
  local
  (!IsObject(this.Lib) && this.Lib:=[]), Lib:=this.Lib
  , (!Lib.HasKey(index) && Lib[index]:=[]), Lib:=Lib[index]
  if (add_to_Lib)
  {
    re:="O)<([^>\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))
        (s2!="") && Lib[s2]:=r[0]
      }
  }
  else
  {
    Text:=""
    Loop Parse, comments, |
    {
      s1:=Trim(A_LoopField), s2:=""
      Loop Parse, s1
        s2.=Format("_{:d}", Ord(A_LoopField))
      (Lib.HasKey(s2)) && Text.="|" Lib[s2]
    }
    return Text
  }
}

; 分割字符串为单个文字并获取数据

PicN(Number, index:=1)
{
  return this.PicLib(RegExReplace(Number,".","|$0"), 0, index)
}

; 使用 FindText().PicX(Text) 可以将文字分割成多个单字的组合,从而适应间隔变化
; 但是不能用于“颜色位置二值化”模式, 因为位置是与整体图像相关的

PicX(Text)
{
  local
  if !RegExMatch(Text, "O)(<[^$\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)
{
  local
  bits:=this.GetBitsFromScreen(,,,,0,zx,zy,zw,zh), x-=zx, y-=zy
  , c:=(x>=0 && x<zw && y>=0 && y<zh && bits.Scan0)
  ? NumGet(bits.Scan0+y*bits.Stride+x*4,"uint") : 0xFFFFFF
  return (fmt ? Format("0x{:06X}",c&0xFFFFFF) : c)
}

; 在“上一次的截屏”中设置点的RGB颜色

SetColor(x, y, color:=0x000000)
{
  local
  bits:=this.GetBitsFromScreen(,,,,0,zx,zy,zw,zh), x-=zx, y-=zy
  if (x>=0 && x<zw && y>=0 && y<zh && bits.Scan0)
    NumPut(color, bits.Scan0+y*bits.Stride+x*4, "uint")
}

; 根据 FindText() 的结果识别一行文字或验证码
; offsetX 为两个文字的最大间隔,超过会插入*号
; offsetY 为两个文字的最大高度差
; overlapW 用于设置覆盖的宽度
; 最后返回数组:{text:识别结果, x:结果左上角X, y:结果左上角Y, w:宽, h:高}

Ocr(ok, offsetX:=20, offsetY:=20, overlapW:=0)
{
  local
  ocr_Text:=ocr_X:=ocr_Y:=min_X:=dx:=""
  For k,v in ok
    x:=v.1
    , min_X:=(A_Index=1 || x<min_X ? x : min_X)
    , max_X:=(A_Index=1 || x>max_X ? x : max_X)
  While (min_X!="" && min_X<=max_X)
  {
    LeftX:=""
    For k,v in ok
    {
      x:=v.1, y:=v.2
      if (x<min_X) || (ocr_Y!="" && Abs(y-ocr_Y)>offsetY)
        Continue
      ; Get the leftmost X coordinates
      if (LeftX="" || x<LeftX)
        LeftX:=x, LeftY:=y, LeftW:=v.3, LeftH:=v.4, LeftOCR:=v.id
    }
    if (LeftX="")
      Break
    if (ocr_X="")
      ocr_X:=LeftX, min_Y:=LeftY, max_Y:=LeftY+LeftH
    ; If the interval exceeds the set value, add "*" to the result
    ocr_Text.=(ocr_Text!="" && LeftX>dx ? "*":"") . LeftOCR
    ; Update for next search
    min_X:=LeftX+LeftW-(overlapW>LeftW//2 ? LeftW//2:overlapW)
    , dx:=LeftX+LeftW+offsetX, ocr_Y:=LeftY
    , (LeftY<min_Y && min_Y:=LeftY)
    , (LeftY+LeftH>max_Y && max_Y:=LeftY+LeftH)
  }
  (ocr_X="") && ocr_X:=min_Y:=min_X:=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)
{
  local
  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:=Trim(s,"|")
  Sort, s, N D|
  ok2:=[]
  For k,v in StrSplit(s,"|")
    ok2.Push(ok[SubStr(v,InStr(v,".")+1)])
  return ok2
}

; 以指定点为中心,按从近到远排序FindText()的结果,返回排序后的数组

Sort2(ok, px, py)
{
  local
  if !IsObject(ok)
    return ok
  s:=""
  For k,v in ok
    s.=((v.x-px)**2+(v.y-py)**2) "." k "|"
  s:=Trim(s,"|")
  Sort, s, N D|
  ok2:=[]
  For k,v in StrSplit(s,"|")
    ok2.Push(ok[SubStr(v,InStr(v,".")+1)])
  return ok2
}

; 按指定的查找方向,排序FindText()的结果,返回排序后的数组

Sort3(ok, dir:=1)
{
  local
  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:=Trim(s,"|")
  Sort, s, N D|
  ok2:=[]
  For k,v in StrSplit(s,"|")
    ok2.Push(ok[SubStr(v,InStr(v,".")+1)])
  return ok2
}

; 提示某个坐标的位置,或远程控制中当前鼠标的位置

MouseTip(x:="", y:="", w:=10, h:=10, d:=3)
{
  local
  if (x="")
  {
    VarSetCapacity(pt,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, num:=1)
{
  local
  ListLines % (lls:=A_ListLines)?0:0
  static init, tab
  if !VarSetCapacity(init) && (init:="1")
    tab:=[]
  (!tab.HasKey(num) && tab[num]:=[0,0,0,0]), Range:=tab[num]
  if (x="")
  {
    if (Range[1])
    Loop 4
    {
      Gui, % Range[A_Index] ":Destroy"
      Range[A_Index]:=0
    }
    ListLines % lls
    return
  }
  if !(Range[1])
  {
    Loop 4
    {
      Gui, New, +Hwndid +AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000
      Range[A_Index]:=id
    }
  }
  x:=Floor(x), y:=Floor(y), w:=Floor(w), h:=Floor(h), d:=Floor(d)
  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)
    Gui, % Range[i] ":Color", %color%
    Gui, % Range[i] ":Show", NA x%x1% y%y1% w%w1% h%h1%
  }
  ListLines % lls
}

State(key)
{
  return GetKeyState(key,"P") || GetKeyState(key)
}

; 用鼠标左右键选取屏幕范围

GetRange(ww:=25, hh:=8, key:="RButton")
{
  local
  static init, KeyOff, hk
  if !VarSetCapacity(init) && (init:="1")
    KeyOff:=this.GetRange.Bind(this, "Off")
  if (ww=="Off")
    return hk:=Trim(A_ThisHotkey, "*")
  ;---------------------
  GetRange_HotkeyIf:=_Gui:=this.GuiNew()
  _Gui.Opt("-Caption +ToolWindow +E0x80000")
  _Gui.Title:="GetRange_HotkeyIf"
  _Gui.Show("NA x0 y0 w0 h0")
  ;---------------------
  if GetKeyState("Ctrl")
    Send {Ctrl Up}
  Hotkey, IfWinExist, GetRange_HotkeyIf
  keys:=key "|Up|Down|Left|Right"
  For k,v in StrSplit(keys, "|")
  {
    if GetKeyState(v)
      Send {%v% Up}
    Hotkey, *%v%, %KeyOff%, On UseErrorLevel
  }
  Hotkey, IfWinExist
  ;---------------------
  Critical % (cri:=A_IsCritical)?"Off":"Off"
  CoordMode, Mouse
  tip:=this.Lang("s5")
  hk:="", oldx:=oldy:="", keydown:=0
  Loop
  {
    Sleep 50
    MouseGetPos, x2, y2
    if (hk=key) || this.State(key) || this.State("Ctrl")
    {
      keydown++
      if (keydown=1)
        MouseGetPos, x1, y1, Bind_ID
      timeout:=A_TickCount+3000
      While (A_TickCount<timeout) && (this.State(key) || this.State("Ctrl"))
        Sleep 50
      hk:=""
      if (keydown>=2)
        Break
    }
    else if (hk="Up") || this.State("Up")
      (hh>1 && hh--), hk:=""
    else if (hk="Down") || this.State("Down")
      hh++, hk:=""
    else if (hk="Left") || this.State("Left")
      (ww>1 && ww--), hk:=""
    else if (hk="Right") || this.State("Right")
      ww++, hk:=""
    x:=(keydown?x1:x2), y:=(keydown?y1:y2)
    this.RangeTip(x-ww, y-hh, 2*ww+1, 2*hh+1, (A_MSec<500?"Red":"Blue"))
    if (oldx=x2 && oldy=y2)
      Continue
    oldx:=x2, oldy:=y2
    ToolTip % "x: " x " y: " y "`n" tip
  }
  ToolTip
  this.RangeTip()
  Hotkey, IfWinExist, GetRange_HotkeyIf
  For k,v in StrSplit(keys, "|")
    Hotkey, *%v%, %KeyOff%, Off UseErrorLevel
  Hotkey, IfWinExist
  GetRange_HotkeyIf.Destroy()
  Critical % cri
  return [x-ww, y-hh, x+ww, y+hh, Bind_ID]
}

GetRange2(key:="LButton")
{
  local
  FindText_GetRange:=_Gui:=this.GuiNew()
  _Gui.Opt("+LastFound +AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000")
  _Gui.BackColor:="White"
  WinSet, Transparent, 10
  this.GetBitsFromScreen(,,,,0,x,y,w,h)
  _Gui.Title:="FindText_GetRange"
  _Gui.Show("NA x" x " y" y " w" w " h" h)
  CoordMode, Mouse
  tip:=this.Lang("s7"), oldx:=oldy:=""
  Loop
  {
    Sleep 50
    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 this.State(key) || this.State("Ctrl")
  Loop
  {
    Sleep 50
    MouseGetPos, x2, y2
    x:=Min(x1,x2), y:=Min(y1,y2), w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+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 !(this.State(key) || this.State("Ctrl"))
  ToolTip
  this.RangeTip()
  FindText_GetRange.Destroy()
  Clipboard:=x "," y "," (x+w-1) "," (y+h-1)
  return [x, y, x+w-1, y+h-1]
}

BitmapFromScreen(ByRef x:=0, ByRef y:=0, ByRef w:=0, ByRef h:=0
  , ScreenShot:=1, ByRef zx:=0, ByRef zy:=0, ByRef zw:=0, ByRef zh:=0)
{
  local
  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)
{
  local
  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)
{
  local
  if hBM_or_file is number
    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
  }
  VarSetCapacity(dib, dib_size:=(A_PtrSize=8 ? 104:84), 0)
  , DllCall("GetObject", "Ptr",hBM, "int",dib_size, "Ptr",&dib)
  , pbi:=&dib+(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")
    DllCall("SetClipboardData", "uint",8, "Ptr",hdib)
    DllCall("CloseClipboard")
  }
  else
  {
    if InStr(file,"\") && !FileExist(dir:=RegExReplace(file,"[^\\]*$"))
      Try FileCreateDir, % dir
    VarSetCapacity(bf, 14, 0), NumPut(0x4D42, bf, "short")
    NumPut(54+size, bf, 2, "uint"), NumPut(54, bf, 10, "uint")
    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, ByRef x:="", ByRef y:="", ByRef w:="", ByRef h:="")
{
  local
  if (file="")
  {
    this.ShowScreenShot()
    return
  }
  if !(hBM:=LoadPicture(file))
    return
  this.GetBitmapWH(hBM, w, h)
  bits:=this.GetBitsFromScreen(,,,,0,x,y,zw,zh)
  this.UpdateBits(bits, x, y, Max(w,zw), Max(h,zh))
  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)
  return 1
}

; 显示内存中的屏幕截图用于调试

ShowScreenShot(x1:=0, y1:=0, x2:=0, y2:=0, ScreenShot:=1)
{
  local
  static init, hPic, oldx, oldy, oldw, oldh, FindText_Screen
  if !VarSetCapacity(init) && (init:="1")
    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:=this.GuiNew()  ; WS_EX_NOACTIVATE:=0x08000000
    _Gui.Opt("+AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000")
    _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)
{
  local
  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:=0, y1:=0, x2:=0, y2:=0, Threshold:=""
  , ScreenShot:=1, ByRef rx:="", ByRef ry:="", cut:=1)
{
  local
  if (x1=0 && y1=0 && x2=0 && y2=0)
    return this.Gui("CaptureS", ScreenShot)
  SetBatchLines % (bch:=A_BatchLines)?"-1":"-1"
  x1:=this.Floor(x1), y1:=this.Floor(y1), x2:=this.Floor(x2), y2:=this.Floor(y2)
  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)
  if (w<1 || h<1 || !bits.Scan0)
  {
    SetBatchLines % bch
    return
  }
  ListLines % (lls:=A_ListLines)?0:0
  gs:=[]
  j:=bits.Stride-w*4, p:=bits.Scan0+(y-zy)*bits.Stride+(x-zx)*4-j-4
  Loop % h + 0*(k:=0)
  Loop % w + 0*(p+=j)
    c:=NumGet(0|p+=4,"uint")
    , gs[++k]:=(((c>>16)&0xFF)*38+((c>>8)&0xFF)*75+(c&0xFF)*15)>>7
  if InStr(Threshold,"**")
  {
    Threshold:=Trim(Threshold,"* "), (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:=gs[i]+Threshold
      , s.=( gs[i-1]>j || gs[i+1]>j
      || gs[i-sw]>j || gs[i+sw]>j
      || gs[i-sw-1]>j || gs[i-sw+1]>j
      || gs[i+sw-1]>j || gs[i+sw+1]>j ) ? "1":"0"
    Threshold:="**" Threshold
  }
  else
  {
    Threshold:=Trim(Threshold,"* ")
    if (Threshold="")
    {
      pp:=[]
      Loop 256
        pp[A_Index-1]:=0
      Loop % w*h
        pp[gs[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.=gs[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)
  ;--------------------
  SetBatchLines % bch
  return s
}

; 等待几秒钟直到屏幕图像改变,需要先调用FindText().ScreenShot()

WaitChange(time:=-1, x1:=0, y1:=0, x2:=0, y2:=0)
{
  local
  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)
{
  local
  oldhash:="", time:=this.Floor(time)
  , 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(time*1000)
    if (t>=timeout2)
      return 1
    if (t>=timeout)
      return 0
    Sleep 100
  }
}

GetPicHash(x1:=0, y1:=0, x2:=0, y2:=0, ScreenShot:=1)
{
  local
  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
  ListLines % (lls:=A_ListLines)?0:0
  Loop % h
    hash:=(hash*31+DllCall("ntdll\RtlComputeCrc32", "uint",0
      , "Ptr",p+=Stride, "uint",w, "uint"))&0xFFFFFFFF
  ListLines % lls
  return hash
}

WindowToScreen(ByRef x, ByRef y, x1, y1, id:="")
{
  local
  if (!id)
    WinGet, id, ID, A
  VarSetCapacity(rect, 16, 0)
  , DllCall("GetWindowRect", "Ptr",id, "Ptr",&rect)
  , x:=x1+NumGet(rect,"int"), y:=y1+NumGet(rect,4,"int")
}

ScreenToWindow(ByRef x, ByRef y, x1, y1, id:="")
{
  local
  this.WindowToScreen(dx, dy, 0, 0, id), x:=x1-dx, y:=y1-dy
}

ClientToScreen(ByRef x, ByRef y, x1, y1, id:="")
{
  local
  if (!id)
    WinGet, id, ID, A
  VarSetCapacity(pt, 8, 0), NumPut(0, pt, "int64")
  , DllCall("ClientToScreen", "Ptr",id, "Ptr",&pt)
  , x:=x1+NumGet(pt,"int"), y:=y1+NumGet(pt,4,"int")
}

ScreenToClient(ByRef x, ByRef y, x1, y1, id:="")
{
  local
  this.ClientToScreen(dx, dy, 0, 0, id), x:=x1-dx, y:=y1-dy
}

; 不像 FindText 总是使用屏幕坐标,它使用与内置命令
; PixelGetColor 一样的 CoordMode 设置的坐标模式

PixelGetColor(x, y, ScreenShot:=1, id:="")
{
  if (A_CoordModePixel="Window")
    this.WindowToScreen(x, y, x, y, id)
  else if (A_CoordModePixel="Client")
    this.ClientToScreen(x, y, x, y, id)
  if (ScreenShot)
    this.ScreenShot(x, y, x, y)
  return this.GetColor(x, y)
}

; 不像 FindText 总是使用屏幕坐标,它使用与内置命令
; ImageSearch 一样的 CoordMode 设置的坐标模式
; 图片文件参数可以使用 "*n *TransBlack/White/RRGGBB-DRDGDB... d:\a.bmp"

ImageSearch(ByRef rx:="", ByRef ry:="", x1:=0, y1:=0, x2:=0, y2:=0
  , ImageFile:="", ScreenShot:=1, FindAll:=0, dir:=1)
{
  local
  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, "O)(^|\s)\*(\d+)\s", r)
    ? Format("{:06X}", r[2]<<16|r[2]<<8|r[2]) : "000000")
    . (RegExMatch(v, "Oi)(^|\s)\*Trans(\S+)\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,,,, dir))
  {
    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, ErrorLevel:=0
    return ok
  }
  else
  {
    rx:=ry:="", ErrorLevel:=1
    return 0
  }
}

; 不像 FindText 总是使用屏幕坐标,它使用与内置命令
; PixelSearch 一样的 CoordMode 设置的坐标模式
; 颜色参数可以是 "RRGGBB-DRDGDB|RRGGBB-DRDGDB", Variation 取值 0-255

PixelSearch(ByRef rx:="", ByRef ry:="", x1:=0, y1:=0, x2:=0, y2:=0
  , ColorID:="", Variation:=0, ScreenShot:=1, FindAll:=0, dir:=1)
{
  local
  n:=this.Floor(Variation), text:=Format("##{:06X}$0/0/", n<<16|n<<8|n)
  . Trim(StrReplace(ColorID, "|", "/"), "- /")
  return this.ImageSearch(rx, ry, x1, y1, x2, y2, text, ScreenShot, FindAll, dir)
}

; 屏幕坐标指示的范围内的某些颜色的像素计数
; 颜色参数可以是 "RRGGBB-DRDGDB|RRGGBB-DRDGDB", Variation 取值 0-255

PixelCount(x1:=0, y1:=0, x2:=0, y2:=0, ColorID:="", Variation:=0, ScreenShot:=1)
{
  local
  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, VarSetCapacity(s1,4), VarSetCapacity(s0,4), VarSetCapacity(ss,w*(h+3))
  ini:={ bits:bits, ss:&ss, s1:&s1, s0:&s0, allpos:0, allpos_max:0
    , err1:0, err0:0, zoomW:1, zoomH:1 }
  n:=this.Floor(Variation), text:=Format("##{:06X}$0/0/", n<<16|n<<8|n)
  . Trim(StrReplace(ColorID, "|", "/"), "- /")
  if IsObject(j:=this.PicInfo(text))
    sum:=this.PicFind(ini, j, 1, x, y, w, h)
  return sum
}

; 创建包含特定颜色的色块,可以限定这个色块中符合颜色的数量
; ColorID 可以使用 "RRGGBB-DRDGDB|RRGGBB-DRDGDB", "*128", "**50"
; Count1, Count0 是这个色块二值化后黑点和白点的数量最小值

ColorBlock(ColorID, w, h, Count1:=0, Count0:=0)
{
  local
  (Count0>0 && Count1:=0)
  Text:="|<>[" (1-Count1/(w*h)) "," (1-Count0/(w*h)) "]"
  . Trim(StrReplace(ColorID,"|","/"),"- /") . Format("${:d}.",w)
  . this.bit2base64(StrReplace(Format(Format("{{}:0{:d}d{}}",w*h),0),"0"
  , (Count0>0 ? "0":"1")))
  return Text
}

Click(x:="", y:="", other1:="", other2:="", GoBack:=0)
{
  local
  CoordMode, Mouse, % (bak:=A_CoordModeMouse)?"Screen":"Screen"
  if GoBack
    MouseGetPos, oldx, oldy
  MouseMove, x, y, 0
  Sleep 30
  Click % x "," y "," other1 "," other2
  if GoBack
    MouseMove, oldx, oldy, 0
  CoordMode, Mouse, %bak%
  return 1
}

; 动态运行AHK代码作为新线程

Class Thread
{
  __New(args*)
  {
    this.pid:=this.Exec(args*)
  }
  __Delete()
  {
    Process, Close, % this.pid
  }
  Exec(s, Ahk:="", args:="")    ; required AHK v1.1.34+ and Ahk2Exe Use .exe
  {
    local
    Ahk:=Ahk ? Ahk : A_IsCompiled ? A_ScriptFullPath : A_AhkPath
    s:="`nDllCall(""SetWindowText"",""Ptr"",A_ScriptHwnd,""Str"",""<AHK>"")`n"
      . "`nSetBatchLines,-1`n" . s, s:=RegExReplace(s, "\R", "`r`n")
    Try
    {
      shell:=ComObjCreate("WScript.Shell")
      oExec:=shell.Exec("""" Ahk """ /script /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%" /script /force /CP0 "%f%" %args%,, UseErrorLevel, pid
    }
    return pid
  }
  Clear()
  {
    Try FileDelete % A_Temp "\~ahk.tmp"
    SetTimer,, Off
  }
}

; FindText().QPC() 用法类似于 A_TickCount

QPC()
{
  static init, f, c
  if !VarSetCapacity(init) && (init:="1")
    f:=0, c:=DllCall("QueryPerformanceFrequency", "Int64*",f)+(f/=1000)
  return (!DllCall("QueryPerformanceCounter","Int64*",c))*0+(c/f)
}

; FindText().ToolTip() 用法类似于 ToolTip

ToolTip(s:="", x:="", y:="", num:=1, arg:="")
{
  local
  static init, ini, tip, timer
  if !VarSetCapacity(init) && (init:="1")
    ini:=[], tip:=[], timer:=[]
  f:="ToolTip_" . this.Floor(num)
  if (s="")
  {
    Try tip[f].Destroy()
    ini[f]:="", tip[f]:=""
    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))
  ;-----------------
  bgcolor:=arg.bgcolor!="" ? arg.bgcolor : "FAFBFC"
  color:=arg.color!="" ? arg.color : "Black"
  font:=arg.font ? arg.font : "Consolas"
  size:=arg.size ? arg.size : "10"
  bold:=arg.bold ? arg.bold : ""
  trans:=arg.trans!="" ? arg.trans & 255 : 255
  timeout:=arg.timeout!="" ? arg.timeout : ""
  ;-----------------
  r:=bgcolor "|" color "|" font "|" size "|" bold "|" trans "|" s
  if (!ini.HasKey(f) || ini[f]!=r)
  {
    ini[f]:=r
    Try tip[f].Destroy()
    tip[f]:=_Gui:=this.GuiNew()  ; WS_EX_LAYERED:=0x80000, WS_EX_TRANSPARENT:=0x20
    _Gui.Opt("+LastFound +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")
    WinSet, Transparent, % trans
  }
  tip[f].Opt("+AlwaysOnTop")
  tip[f].Show("NA " x " " y)
  if (timeout)
  {
    (!timer.HasKey(f) && timer[f]:=this.ToolTip.Bind(this,"","","",num))
    , r:=timer[f]
    SetTimer % r, % -Round(Abs(this.Floor(timeout)*1000))-1
  }
}

; FindText().ObjView() 查看对象的值用于调试

ObjView(obj, keyname:="")
{
  local
  if IsObject(obj)  ; thanks lexikos's type(v)
  {
    s:=""
    For k,v in obj
      s.=this.ObjView(v, keyname "[" (StrLen(k)>1000
      || [k].GetCapacity(1) ? """" k """":k) "]")
  }
  else
    s:=keyname ": " (StrLen(obj)>1000
    || [obj].GetCapacity(1) ? """" obj """":obj) "`n"
  if (keyname!="")
    return s
  ;------------------
  _Gui:=this.GuiNew("+AlwaysOnTop")
  _Gui.Add("Button", "y270 w350 gCancel Default", "OK")
  _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 " _Gui.Hwnd
  _Gui.Destroy()
}

EditScroll(hEdit, regex:="", line:=0, pos:=0)
{
  local
  ControlGetText, s,, ahk_id %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,, ahk_id %hEdit%
  SendMessage, 0xB7,,,, ahk_id %hEdit%
}

LastCtrl()
{
  local
  return (G:=this.GuiFromHwnd(WinExist()))[G.LastHwnd]
}

Hide(args*)
{
  WinMinimize
  WinHide
  ToolTip
  DetectHiddenWindows 0
  WinWaitClose % "ahk_id " WinExist()
}

SC(RGB, hwnd)
{
  SendMessage,0x2001,0,(RGB&0xFF)<<16|RGB&0xFF00|(RGB>>16)&0xFF,,% "ahk_id " hwnd
}


;==== Optional GUI interface ====


Gui(cmd, arg1:="", args*)
{
  local
  static
  local bch, cri, lls, _Gui
  ListLines % InStr("MouseMove|ToolTipOff",cmd)?0:A_ListLines
  static init
  if !VarSetCapacity(init) && (init:="1")
  {
    SavePicDir:=A_Temp "\Ahk_ScreenShot\"
    G_ := this.Gui.Bind(this)
    G_G := this.Gui.Bind(this, "G")
    G_Run := this.Gui.Bind(this, "Run")
    G_Show := this.Gui.Bind(this, "Show")
    G_KeyDown := this.Gui.Bind(this, "KeyDown")
    G_LButtonDown := this.Gui.Bind(this, "LButtonDown")
    G_RButtonDown := this.Gui.Bind(this, "RButtonDown")
    G_MouseMove := this.Gui.Bind(this, "MouseMove")
    G_ScreenShot := this.Gui.Bind(this, "ScreenShot")
    G_ShowPic := this.Gui.Bind(this, "ShowPic")
    G_Slider := this.Gui.Bind(this, "Slider")
    G_ToolTip := this.Gui.Bind(this, "ToolTip")
    G_ToolTipOff := this.Gui.Bind(this, "ToolTipOff")
    G_SaveScr := this.Gui.Bind(this, "SaveScr")
    G_PicShowOK := this.Gui.Bind(this, "PicShowOK")
    G_Drag := this.Gui.Bind(this, "Drag")
    FindText_Capture:=FindText_Main:=""
    PrevControl:=x:=y:=oldx:=oldy:=""
    Pics:=[], hBM_old:=dx:=dy:=0
    bch:=A_BatchLines, cri:=A_IsCritical
    Critical
    #NoEnv
    Lang:=this.Lang(,1), Tip_Text:=this.Lang(,2)
    G_.Call("MakeCaptureWindow")
    G_.Call("MakeMainWindow")
    OnMessage(0x100, G_KeyDown)
    OnMessage(0x201, G_LButtonDown)
    OnMessage(0x204, G_RButtonDown)
    OnMessage(0x200, G_MouseMove)
    Menu, Tray, Add
    Menu, Tray, Add, % Lang["s1"], % G_Show
    if (!A_IsCompiled && A_LineFile=A_ScriptFullPath)
    {
      Menu, Tray, Default, % Lang["s1"]
      Menu, Tray, Click, 1
      Menu, Tray, Icon, Shell32.dll, 23
    }
    Critical % cri
    SetBatchLines % bch
    this.GuiNew("+LastFound").Destroy()
  }
  Switch cmd
  {
  Case "G":
    id:=this.LastCtrl()
    Try id.OnEvent("Click", G_Run)
    Catch
      Try id.OnEvent("Change", G_Run)
    return
  Case "Run":
    Critical
    G_.Call(arg1.Name)
    return
  Case "Show":
    FindText_Main.Show(arg1 ? "Center" : "")
    ControlFocus,, % "ahk_id " hscr
    return
  Case "Cancel", "Cancel2":
    WinHide
    return
  Case "MakeCaptureWindow":
    WindowColor:="0xDDEEFF"
    Try FindText_Capture.Destroy()
    FindText_Capture:=_Gui:=this.GuiNew()
    _Gui.Opt("+LastFound +AlwaysOnTop -DPIScale")
    _Gui.MarginX:=15, _Gui.MarginY:=10
    _Gui.BackColor:=WindowColor
    _Gui.SetFont("s12", "Verdana")
    Tab:=_Gui.Add("Tab3", "vMyTab1 -Wrap", StrSplit(Lang["s18"],"|"))
    Tab.UseTab(1)
    C_:=[], Cid_:=[]
    , nW:=71, nH:=25, w:=h:=12, pW:=nW*(w+1)-1, pH:=(nH+1)*(h+1)-1
    id:=_Gui.Add("Text", "w" pW " h" pH), Cid_[id.Hwnd]:=-1
    _Gui.Opt("-Theme")
    ListLines % (lls:=A_ListLines)?0:0
    Loop % nW*(nH+1)
    {
      i:=A_Index, j:=i=1 ? "xp yp Section" : Mod(i,nW)=1 ? "xs y+1":"x+1"
      id:=_Gui.Add("Progress", j " w" w " h" h " -E0x20000 Smooth")
      C_[i]:=id.Hwnd, Cid_[id.Hwnd]:=i
    }
    ListLines % lls
    _Gui.Opt("+Theme")
    _Gui.Add("Slider", "xs w" pW " vMySlider1 +Center Page20 Line10 NoTicks AltSubmit")
    G_G.Call()
    _Gui.Add("Slider", "ys h" pH " vMySlider2 +Center Page20 Line10 NoTicks AltSubmit +Vertical")
    G_G.Call()
    Tab.UseTab(2)
    id:=_Gui.Add("Pic", "w" (pW-135) " h" pH " +Border -Background Section"), hPic:=id.Hwnd
    Pic_hBM:=this.CreateDIBSection(Pic_w:=(pW-135), Pic_h:=pH)
    _Gui.Add("Slider", "xs wp vMySlider3 +Center Page20 Line10 NoTicks AltSubmit")
    G_G.Call()
    _Gui.Add("Slider", "ys h" pH " vMySlider4 +Center Page20 Line10 NoTicks AltSubmit +Vertical")
    G_G.Call()
    _Gui.Add("ListBox", "ys w120 h200 vSelectBox AltSubmit 0x100")
    G_G.Call()
    _Gui.Add("Button", "y+0 wp vClearAll", Lang["ClearAll"])
    G_G.Call()
    _Gui.Add("Button", "y+0 wp vOpenDir", Lang["OpenDir"])
    G_G.Call()
    _Gui.Add("Button", "y+0 wp vLoadPic", Lang["LoadPic"])
    G_G.Call()
    _Gui.Add("Button", "y+0 wp vSavePic", Lang["SavePic"])
    G_G.Call()
    Tab.UseTab()
    ;--------------
    _Gui.Add("Text", "xm Section", Lang["SelGray"])
    _Gui.Add("Edit", "x+5 yp-3 w80 vSelGray ReadOnly")
    _Gui.Add("Text", "x+15 ys", Lang["SelColor"])
    _Gui.Add("Edit", "x+5 yp-3 w150 vSelColor ReadOnly")
    _Gui.Add("Text", "x+15 ys", Lang["SelR"])
    _Gui.Add("Edit", "x+5 yp-3 w80 vSelR ReadOnly")
    _Gui.Add("Text", "x+5 ys", Lang["SelG"])
    _Gui.Add("Edit", "x+5 yp-3 w80 vSelG ReadOnly")
    _Gui.Add("Text", "x+5 ys", Lang["SelB"])
    _Gui.Add("Edit", "x+5 yp-3 w80 vSelB ReadOnly")
    ;--------------
    id:=_Gui.Add("Button", "xm Hidden Section", Lang["Auto"])
    id.GetPos(pX, pY, pW, pH)
    w:=Round(pW*0.75), i:=Round(w*3+15+pW*0.5-w*1.5)
    _Gui.Add("Button", "xm+" i " yp w" w " hp -Wrap vRepU", Lang["RepU"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutU", Lang["CutU"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutU3", Lang["CutU3"])
    G_G.Call()
    _Gui.Add("Button", "xm wp hp -Wrap vRepL", Lang["RepL"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutL", Lang["CutL"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutL3", Lang["CutL3"])
    G_G.Call()
    _Gui.Add("Button", "x+15 w" pW " hp -Wrap vAuto", Lang["Auto"])
    G_G.Call()
    _Gui.Add("Button", "x+15 w" w " hp -Wrap vRepR", Lang["RepR"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutR", Lang["CutR"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutR3", Lang["CutR3"])
    G_G.Call()
    _Gui.Add("Button", "xm+" i " wp hp -Wrap vRepD", Lang["RepD"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutD", Lang["CutD"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp hp -Wrap vCutD3", Lang["CutD3"])
    G_G.Call()
    ;--------------
    Tab:=_Gui.Add("Tab3", "ys -Wrap", StrSplit(Lang["s2"],"|"))
    Tab.UseTab(1)
    _Gui.Add("Text", "x+30 y+35", Lang["Threshold"])
    _Gui.Add("Edit", "x+15 w100 vThreshold")
    _Gui.Add("Button", "x+15 yp-3 vGray2Two", Lang["Gray2Two"])
    G_G.Call()
    Tab.UseTab(2)
    _Gui.Add("Text", "x+30 y+35", Lang["GrayDiff"])
    _Gui.Add("Edit", "x+15 w100 vGrayDiff", "50")
    _Gui.Add("Button", "x+15 yp-3 vGrayDiff2Two", Lang["GrayDiff2Two"])
    G_G.Call()
    Tab.UseTab(3)
    _Gui.Add("Text", "x+10 y+15 Section", Lang["Similar1"] " 0")
    _Gui.Add("Slider", "x+0 w100 vSimilar1 +Center Page1 NoTicks ToolTip")
    G_G.Call()
    _Gui.Add("Text", "x+0", "100")
    _Gui.Add("Button", "x+10 ys-2 vAddColorSim", Lang["AddColorSim"])
    G_G.Call()
    _Gui.Add("Text", "x+25 ys+4", Lang["DiffRGB2"])
    _Gui.Add("Edit", "x+5 ys w80 vDiffRGB2 Limit3")
    _Gui.Add("UpDown", "vdRGB2 Range0-255 Wrap", 50)
    _Gui.Add("Button", "x+10 ys-2 vAddColorDiff", Lang["AddColorDiff"])
    G_G.Call()
    _Gui.Add("Button", "xs vUndo2", Lang["Undo2"])
    G_G.Call()
    _Gui.Add("Edit", "x+10 yp+2 w340 vColorList")
    _Gui.Add("Button", "x+10 yp-2 vColor2Two", Lang["Color2Two"])
    G_G.Call()
    Tab.UseTab(4)
    _Gui.Add("Text", "x+30 y+35", Lang["Similar2"] " 0")
    _Gui.Add("Slider", "x+0 w120 vSimilar2 +Center Page1 NoTicks ToolTip")
    G_G.Call()
    _Gui.Add("Text", "x+0", "100")
    _Gui.Add("Button", "x+15 yp-3 vColorPos2Two", Lang["ColorPos2Two"])
    G_G.Call()
    Tab.UseTab(5)
    _Gui.Add("Text", "x+30 y+15 Section", Lang["Similar3"] " 0")
    _Gui.Add("Slider", "x+0 w120 vSimilar3 +Center Page1 NoTicks ToolTip")
    G_G.Call()
    _Gui.Add("Text", "x+0", "100")
    _Gui.Add("Button", "x+15 ys-2 vUndo", Lang["Undo"])
    G_G.Call()
    _Gui.Add("Checkbox", "xs vMultiColor", Lang["MultiColor"])
    G_G.Call()
    _Gui.Add("Checkbox", "x+50 vFindShape", Lang["FindShape"])
    G_G.Call()
    Tab.UseTab()
    ;--------------
    _Gui.Add("Button", "xm vReset", Lang["Reset"])
    G_G.Call()
    _Gui.Add("Checkbox", "x+15 yp+5 vModify", Lang["Modify"])
    G_G.Call()
    _Gui.Add("Text", "x+30", Lang["Comment"])
    _Gui.Add("Edit", "x+5 yp-2 w250 vComment")
    _Gui.Add("Button", "x+10 yp-3 vSplitAdd", Lang["SplitAdd"])
    G_G.Call()
    _Gui.Add("Button", "x+10 vAllAdd", Lang["AllAdd"])
    G_G.Call()
    _Gui.Add("Button", "x+30 wp vOK", Lang["OK"])
    G_G.Call()
    _Gui.Add("Button", "x+15 wp vCancel", Lang["Cancel"])
    G_G.Call()
    _Gui.Add("Button", "xm vBind0", Lang["Bind0"])
    G_G.Call()
    _Gui.Add("Button", "x+10 vBind1", Lang["Bind1"])
    G_G.Call()
    _Gui.Add("Button", "x+10 vBind2", Lang["Bind2"])
    G_G.Call()
    _Gui.Add("Button", "x+10 vBind3", Lang["Bind3"])
    G_G.Call()
    _Gui.Add("Button", "x+10 vBind4", Lang["Bind4"])
    G_G.Call()
    _Gui.Add("Button", "x+30 vSavePic2", Lang["SavePic2"])
    G_G.Call()
    _Gui.Title:=Lang["s3"]
    _Gui.Show("Hide")
    _Gui.OnEvent("DropFiles", G_Drag)
    return
  Case "Drag":
    Try G_.Call("LoadPic", args[2][1])
    return
  Case "MakeMainWindow":
    Try FindText_Main.Destroy()
    FindText_Main:=_Gui:=this.GuiNew()
    _Gui.Opt("+LastFound +AlwaysOnTop -DPIScale")
    _Gui.MarginX:=15, _Gui.MarginY:=10
    _Gui.BackColor:=WindowColor
    _Gui.SetFont("s12", "Verdana")
    _Gui.Add("Text", "xm", Lang["NowHotkey"])
    _Gui.Add("Edit", "x+5 w160 vNowHotkey ReadOnly")
    _Gui.Add("Hotkey", "x+5 w160 vSetHotkey1")
    s:="F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|LWin|Ctrl|Shift|Space|MButton"
      . "|ScrollLock|CapsLock|Ins|Esc|BS|Del|Tab|Home|End|PgUp|PgDn"
      . "|NumpadDot|NumpadSub|NumpadAdd|NumpadDiv|NumpadMult"
    _Gui.Add("DDL", "x+5 w160 vSetHotkey2", StrSplit(s,"|"))
    _Gui.Add("Button", "x+15 vApply", Lang["Apply"])
    G_G.Call()
    _Gui.Add("GroupBox", "xm y+0 w280 h55 vMyGroup cBlack")
    _Gui.Add("Text", "xp+15 yp+20 Section", Lang["Myww"] ": ")
    _Gui.Add("Text", "x+0 w80", nW//2)
    _Gui.Add("UpDown", "vMyww Range1-100", nW//2)
    _Gui.Add("Text", "x+15 ys", Lang["Myhh"] ": ")
    _Gui.Add("Text", "x+0 w80", nH//2)
    id:=_Gui.Add("UpDown", "vMyhh Range1-100", nH//2)
    id.GetPos(pX, pY, pW, pH)
    _Gui["MyGroup"].Move(,, pX+pW, pH+30)
    id:=_Gui.Add("Checkbox", "x+100 ys vAddFunc", Lang["AddFunc"] " FindText()")
    id.GetPos(pX, pY, pW, pH)
    pW:=pX+pW-15, pW:=(pW<720?720:pW), w:=pW//5
    _Gui.Add("Button", "xm y+18 w" w " vCutL2", Lang["CutL2"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vCutR2", Lang["CutR2"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vCutU2", Lang["CutU2"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vCutD2", Lang["CutD2"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vUpdate", Lang["Update"])
    G_G.Call()
    _Gui.SetFont("s6 bold", "Verdana")
    _Gui.Add("Edit", "xm y+10 w" pW " h260 vMyPic -Wrap HScroll")
    _Gui.SetFont("s12 norm", "Verdana")
    w:=pW//3
    _Gui.Add("Button", "xm w" w " vCapture", Lang["Capture"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vTest", Lang["Test"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vCopy", Lang["Copy"])
    G_G.Call()
    _Gui.Add("Button", "xm y+0 wp vCaptureS", Lang["CaptureS"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vGetRange", Lang["GetRange"])
    G_G.Call()
    _Gui.Add("Button", "x+0 wp vGetOffset", Lang["GetOffset"])
    G_G.Call()
    _Gui.Add("Edit", "xm y+10 w130 hp vClipText")
    _Gui.Add("Button", "x+0 vPaste", Lang["Paste"])
    G_G.Call()
    _Gui.Add("Button", "x+0 vTestClip", Lang["TestClip"])
    G_G.Call()
    id:=_Gui.Add("Button", "x+0 vGetClipOffset", Lang["GetClipOffset"])
    G_G.Call()
    id.GetPos(x,, w)
    w:=((pW+15)-(x+w))//2
    _Gui.Add("Edit", "x+0 w" w " hp vOffset")
    _Gui.Add("Button", "x+0 wp vCopyOffset", Lang["CopyOffset"])
    G_G.Call()
    _Gui.SetFont("cBlue")
    id:=_Gui.Add("Edit", "xm w" pW " h250 vscr -Wrap HScroll"), hscr:=id.Hwnd
    _Gui.Title:=Lang["s4"]
    _Gui.Show("Hide")
    G_.Call("LoadScr")
    OnExit(G_SaveScr)
    return
  Case "LoadScr":
    f:=A_Temp "\~scr1.tmp"
    FileRead, s, % f
    FindText_Main["scr"].Value:=s
    return
  Case "SaveScr":
    f:=A_Temp "\~scr1.tmp"
    s:=FindText_Main["scr"].Value
    Try FileDelete % f
    FileAppend % s, % f
    return
  Case "Capture", "CaptureS":
    _Gui:=FindText_Main
    if show_gui:=WinExist("ahk_id " _Gui.Hwnd)
      this.Hide()
    if (cmd="Capture")
    {
      w:=_Gui["Myww"].Value
      h:=_Gui["Myhh"].Value
      p:=this.GetRange(w, h)
      sx:=p[1], sy:=p[2], sw:=p[3]-p[1]+1, sh:=p[4]-p[2]+1
      , Bind_ID:=p[5], bind_mode:=""
      _Gui:=FindText_Capture
      _Gui["MyTab1"].Choose(1)
    }
    else
    {
      sx:=0, sy:=0, sw:=1, sh:=1, Bind_ID:=WinExist("A"), bind_mode:=""
      _Gui:=FindText_Capture
      _Gui["MyTab1"].Choose(2)
    }
    n:=150000, x:=y:=-n, w:=h:=2*n
    hBM:=this.BitmapFromScreen(x,y,w,h,(arg1=0?0:1))
    Pics:=[], Pics[hBM]:=1, hBM_x:=hBM_y:=0
    G_.Call("CaptureUpdate")
    G_.Call("PicUpdate")
    Names:=["HBITMAP:*" hBM], s:="<New>"
    Loop Files, % SavePicDir "*.bmp"
      Names.Push(v:=A_LoopFileFullPath), s.="|" RegExReplace(v,"i)^.*\\|\.bmp$")
    _Gui["SelectBox"].Delete()
    _Gui["SelectBox"].Add(StrSplit(Trim(s,"|"),"|"))
    ;------------------------
    s:="SelGray|SelColor|SelR|SelG|SelB|Threshold|Comment|ColorList"
    Loop Parse, s, |
      _Gui[A_LoopField].Value:=""
    For k,v in ["Similar1","Similar2","Similar3"]
      _Gui[v].Value:=90
    _Gui["Modify"].Value:=Modify:=0
    _Gui["MultiColor"].Value:=MultiColor:=0
    _Gui["FindShape"].Value:=FindShape:=0
    _Gui["GrayDiff"].Value:=50
    _Gui["Gray2Two"].Focus()
    _Gui["Gray2Two"].Opt("+Default")
    _Gui.Show("Center")
    Event:=Result:=""
    DetectHiddenWindows 0
    Critical, Off
    WinWaitClose % "ahk_id " _Gui.Hwnd
    Critical
    ToolTip
    Pics[hBM]:=1, hBM_old:=0
    For k,v in Pics
      Try DllCall("DeleteObject", "Ptr",k)
    Text:=RegExMatch(Result,"O)\|<[^>\n]*>[^$\n]+\$[^""\r\n]+",r)?r[0]:""
    ;------------------------
    _Gui:=FindText_Main
    if (bind_mode!="")
    {
      WinGetTitle, tt, ahk_id %Bind_ID%
      WinGetClass, tc, ahk_id %Bind_ID%
      tt:=Trim(SubStr(tt,1,30) (tc ? " ahk_class " tc:""))
      tt:=StrReplace(RegExReplace(tt,"[;``]","``$0"),"""","""""")
      Result:="`nSetTitleMatchMode 2`nid:=WinExist(""" tt """)"
        . "`nFindText().BindWindow(id" (bind_mode=0 ? "":"," bind_mode)
        . ")  `; " Lang["s6"] " FindText().BindWindow(0)`n`n" Result
    }
    if (Event="OK")
    {
      s:=""
      if (!A_IsCompiled)
        Try FileRead, s, %A_LineFile%
      re:="Oi)\n\s*FindText[^\n]+args\*[\s\S]*?Script_End[(){}\s]+}"
      s:=RegExMatch(s, re, r) ? "`n;==========`n" r[0] "`n" : ""
      _Gui["scr"].Value:=Result "`n" s
      _Gui["MyPic"].Value:=Trim(this.ASCII(Result),"`n")
    }
    else if (Event="SplitAdd" || Event="AllAdd")
    {
      s:=_Gui["scr"].Value
      r:=SubStr(s, 1, InStr(s,"=FindText("))
      i:=j:=0, re:="<[^>\n]*>[^$\n]+\$[^""\r\n]+"
      While j:=RegExMatch(r, re,, j+1)
        i:=InStr(r, "`n", 0, j)
      _Gui["scr"].Value:=SubStr(s,1,i) . Result . SubStr(s,i+1)
      _Gui["MyPic"].Value:=Trim(this.ASCII(Result),"`n")
    }
    if (Event) && RegExMatch(Result, "O)\$\d+\.[\w+/]{1,100}", r)
      this.EditScroll(hscr, "\Q" r[0] "\E")
    Event:=Result:=s:=""
    ;----------------------
    if (show_gui && arg1="")
      G_Show.Call()
    else Clipboard:=Text
    return Text
  Case "CaptureUpdate":
    nX:=sx, nY:=sy, nW:=sw, nH:=sh
    bits:=this.GetBitsFromScreen(nX,nY,nW,nH,0,zx,zy)
    cors:=[], show:=[], ascii:=[]
    , SelPos:=bg:=color:=Result:=""
    , dx:=dy:=CutLeft:=CutRight:=CutUp:=CutDown:=0
    ListLines % (lls:=A_ListLines)?0:0
    if (nW>0 && nH>0 && bits.Scan0)
    {
      j:=bits.Stride-nW*4, p:=bits.Scan0+(nY-zy)*bits.Stride+(nX-zx)*4-j-4
      Loop % nH + 0*(k:=0)
      Loop % nW + 0*(p+=j)
        show[++k]:=1, cors[k]:=NumGet(0|p+=4,"uint")
    }
    Loop % 25 + 0*(ty:=dy-1)*(k:=0)
    Loop % 71 + 0*(tx:=dx-1)*(ty++)
      this.SC(((++tx)<nW && ty<nH ? cors[ty*nW+tx+1]:WindowColor), C_[++k])
    Loop % 71 + 0*(k:=71*25)
      this.SC(0xFFFFAA, C_[++k])
    ListLines % lls
    _Gui:=FindText_Capture
    _Gui["MySlider1"].Enabled:=nW>71
    _Gui["MySlider2"].Enabled:=nH>25
    _Gui["MySlider1"].Value:=0
    _Gui["MySlider2"].Value:=0
    return
  Case "PicUpdate":
    Try i:=0, i:=Pics.HasKey(hBM_old)
    Try (!i) && DllCall("DeleteObject", "Ptr",hBM_old)
    this.GetBitmapWH(hBM, hBM_w, hBM_h), hBM_old:=hBM
    G_.Call("PicShow", 1)
    return
  Case "MySlider3", "MySlider4":
    hBM_x:=Round(FindText_Capture["MySlider3"].Value*(hBM_w-Pic_w)/100)
    hBM_y:=Round(FindText_Capture["MySlider4"].Value*(hBM_h-Pic_h)/100)
    G_.Call("PicShow")
    return
  Case "PicShow":
    w:=hBM_w-Pic_w, h:=hBM_h-Pic_h
    , hBM_x:=Max(Min(hBM_x,w),0), hBM_y:=Max(Min(hBM_y,h),0)
    if (w<0 || h<0)
      this.DrawHBM(Pic_hBM, [[0, 0, Pic_w, Pic_h, WindowColor]])
    this.CopyHBM(Pic_hBM,0,0,hBM,hBM_x,hBM_y,Min(Pic_w,hBM_w),Min(Pic_h,hBM_h))
    if (arg1)
      G_PicShowOK.Call()
    else
    {
      this.BitmapToWindow(hPic,0,0,Pic_hBM,0,0,Pic_w,Pic_h)
      SetTimer % G_PicShowOK, -1000
    }
    FindText_Capture["MySlider3"].Value:=w>0?Round(hBM_x/w*100):0
    FindText_Capture["MySlider4"].Value:=h>0?Round(hBM_y/h*100):0
    return
  Case "PicShowOK":
    FindText_Capture[hPic].Value:="*w0 *h0 HBITMAP:*" Pic_hBM
    return
  Case "Reset":
    G_.Call("CaptureUpdate")
    return
  Case "LoadPic":
    FindText_Capture.Opt("+OwnDialogs")
    f:=arg1
    if (f="")
    {
      if !FileExist(SavePicDir)
        FileCreateDir % SavePicDir
      f:=SavePicDir "*.bmp"
      Loop Files, % f
        f:=A_LoopFileFullPath
      FileSelectFile, f,, %f%, Select Picture
    }
    if !InStr(f,"HBITMAP:") && !FileExist(f)
    {
      MsgBox, 4096, Tip, % Lang["s17"]
      return
    }
    if !this.ShowPic(f, 0, sx, sy, sw, sh)
      return
    hBM:=this.BitmapFromScreen(sx, sy, sw, sh, 0)
    sw:=Min(sw,71), sh:=Min(sh,25)
    G_.Call("CaptureUpdate")
    G_.Call("PicUpdate")
    return
  Case "SavePic":
    FindText_Capture.Hide()
    this.ScreenShot(), this.ShowPic("HBITMAP:*" hBM)
    Try this.GuiFromHwnd(WinExist("Show Pic")).Opt("+OwnDialogs")
    Loop
    {
      p:=this.GetRange2()
      MsgBox, 4099, Tip, % Lang["s15"]
      IfMsgBox, No
        Continue
      Break
    }
    IfMsgBox, Yes
      G_.Call("ScreenShot", p[1] "|" p[2] "|" p[3] "|" p[4] "|0")
    this.ShowPic()
    return
  Case "SelectBox":
    SelectBox:=FindText_Capture["SelectBox"].Value
    Try f:="", f:=Names[SelectBox]
    if (f!="")
      G_.Call("LoadPic", f)
    return
  Case "ClearAll":
    FindText_Capture.Opt("+OwnDialogs")
    MsgBox, 4100, Tip, % Lang["s19"]
    IfMsgBox, Yes
    {
      FindText_Capture.Hide()
      FileDelete % SavePicDir "*.bmp"
    }
    return
  Case "OpenDir":
    if !FileExist(SavePicDir)
      FileCreateDir % SavePicDir
    Run % SavePicDir
    return
  Case "GetRange":
    _Gui:=FindText_Main
    _Gui.Opt("+LastFound")
    this.Hide()
    p:=this.GetRange2(), v:=p[1] ", " p[2] ", " p[3] ", " p[4]
    s:=_Gui["scr"].Value
    re:="i)(=FindText\([^\n]*?)([^(,\n]*,){4}([^,\n]*,[^,\n]*,[^,\n]*Text)"
    if SubStr(s,1,s~="i)\n\s*FindText[^\n]+args\*")~=re
    {
      s:=RegExReplace(s, re, "$1 " v ",$3",, 1)
      _Gui["scr"].Value:=s
    }
    _Gui["Offset"].Value:=v
    G_Show.Call()
    return
  Case "Test", "TestClip":
    _Gui:=FindText_Main
    _Gui.Opt("+LastFound")
    this.Hide()
    ;----------------------
    if (cmd="Test")
      s:=_Gui["scr"].Value
    else
      s:=_Gui["ClipText"].Value
    if (cmd="Test") && InStr(s, "MCode(")
    {
      s:="`n#NoEnv`nMenu, Tray, Click, 1`n" s "`nExitApp`n"
      Thread1:=new this.Thread(s)
      DetectHiddenWindows, 1
      WinWait % "ahk_class AutoHotkey ahk_pid " Thread1.pid,, 3
      if (!ErrorLevel)
        WinWaitClose,,, 30
      ; Thread1:=""  ; kill the Thread
    }
    else
    {
      t:=A_TickCount, v:=X:=Y:=""
      if RegExMatch(s, "O)<[^>\n]*>[^$\n]+\$[^""\r\n]+", r)
        v:=this.FindText(X, Y, 0,0,0,0, 0,0, r[0])
      r:=StrSplit(Lang["s8"] "||||", "|")
      MsgBox, 4096, Tip, % r[1] ":`t" (IsObject(v)?v.Length():v) "`n`n"
        . r[2] ":`t" (A_TickCount-t) " " r[3] "`n`n"
        . r[4] ":`t" X ", " Y "`n`n"
        . r[5] ":`t<" (IsObject(v)?v[1].id:"") ">", 3
      Try For i,j in v
        if (i<=2)
          this.MouseTip(j.x, j.y)
      v:="", Clipboard:=X "," Y
    }
    ;----------------------
    G_Show.Call()
    return
  Case "GetOffset", "GetClipOffset":
    FindText_Main.Hide()
    p:=this.GetRange()
    _Gui:=FindText_Main
    if (cmd="GetOffset")
      s:=_Gui["scr"].Value
    else
      s:=_Gui["ClipText"].Value
    if RegExMatch(s, "O)<[^>\n]*>[^$\n]+\$[^""\r\n]+", r)
    && this.FindText(X, Y, 0,0,0,0, 0,0, r[0])
    {
      r:=StrReplace("X+" ((p[1]+p[3])//2-X)
        . ", Y+" ((p[2]+p[4])//2-Y), "+-", "-")
      if (cmd="GetOffset")
      {
        re:="i)(\(\)\.\w*Click\w*\()[^,\n]*,[^,)\n]*"
        if SubStr(s,1,s~="i)\n\s*FindText[^\n]+args\*")~=re
          s:=RegExReplace(s, re, "$1" r,, 1)
        _Gui["scr"].Value:=s
      }
      _Gui["Offset"].Value:=r
    }
    s:="", G_Show.Call()
    return
  Case "Paste":
    if RegExMatch(Clipboard, "O)\|?<[^>\n]*>[^$\n]+\$[^""\r\n]+", r)
    {
      FindText_Main["ClipText"].Value:=r[0]
      FindText_Main["MyPic"].Value:=Trim(this.ASCII(r[0]),"`n")
    }
    return
  Case "CopyOffset":
    Clipboard:=FindText_Main["Offset"].Value
    return
  Case "Copy":
    ControlGet, s, Selected,,, ahk_id %hscr%
    if (s="")
    {
      s:=FindText_Main["scr"].Value
      r:=FindText_Main["AddFunc"].Value
      if (r != 1)
        s:=RegExReplace(s, "i)\n\s*FindText[^\n]+args\*[\s\S]*")
        , s:=RegExReplace(s, "i)\n; ok:=FindText[\s\S]*")
        , s:=SubStr(s, (s~="i)\n[ \t]*Text"))
    }
    Clipboard:=RegExReplace(s, "\R", "`r`n")
    ControlFocus,, % "ahk_id " hscr
    return
  Case "Apply":
    _Gui:=FindText_Main
    NowHotkey:=_Gui["NowHotkey"].Value
    SetHotkey1:=_Gui["SetHotkey1"].Value
    SetHotkey2:=_Gui["SetHotkey2"].Text
    if (NowHotkey!="")
      Hotkey, *%NowHotkey%,, Off UseErrorLevel
    k:=SetHotkey1!="" ? SetHotkey1 : SetHotkey2
    if (k!="")
      Hotkey, *%k%, %G_ScreenShot%, On UseErrorLevel
    _Gui["NowHotkey"].Value:=k
    _Gui["SetHotkey1"].Value:=""
    _Gui["SetHotkey2"].Choose(0)
    return
  Case "ScreenShot":
    Critical
    if !FileExist(SavePicDir)
      FileCreateDir % SavePicDir
    Loop
      f:=SavePicDir . Format("{:03d}.bmp",A_Index)
    Until !FileExist(f)
    this.SavePic(f, StrSplit(arg1,"|")*)
    CoordMode, ToolTip
    this.ToolTip(Lang["s9"],, 0,, { bgcolor:"Yellow", color:"Red"
      , size:48, bold:"bold", trans:200, timeout:0.2 })
    return
  Case "Bind0", "Bind1", "Bind2", "Bind3", "Bind4":
    this.BindWindow(Bind_ID, bind_mode:=SubStr(cmd,5))
    n:=150000, x:=y:=-n, w:=h:=2*n
    hBM:=this.BitmapFromScreen(x,y,w,h,1)
    G_.Call("PicUpdate")
    FindText_Capture["MyTab1"].Choose(2)
    this.BindWindow(0)
    return
  Case "MySlider1", "MySlider2":
    SetTimer % G_Slider, -10
    return
  Case "Slider":
    Critical
    dx:=nW>71 ? Round(FindText_Capture["MySlider1"].Value*(nW-71)/100):0
    dy:=nH>25 ? Round(FindText_Capture["MySlider2"].Value*(nH-25)/100):0
    if (oldx=dx && oldy=dy)
      return
    ListLines % (lls:=A_ListLines)?0:0
    Loop % 25 + 0*(ty:=dy-1)*(k:=0)
    Loop % 71 + 0*(tx:=dx-1)*(ty++)
      this.SC(((++tx)>=nW || ty>=nH || !show[i:=ty*nW+tx+1]
      ? WindowColor : bg="" ? cors[i] : ascii[i] ? 0:0xFFFFFF), C_[++k])
    Loop % 71*(oldx!=dx) + 0*(i:=nW*nH+dx)*(k:=71*25)
      this.SC((show[++i]?0xFF0000:0xFFFFAA), C_[++k])
    ListLines % lls
    oldx:=dx, oldy:=dy
    return
  Case "RepColor", "CutColor":
    if (cmd="RepColor")
      show[k]:=1, c:=(bg="" ? cors[k] : ascii[k] ? 0:0xFFFFFF)
    else
      show[k]:=0, c:=WindowColor
    if (tx:=Mod(k-1,nW)-dx)>=0 && tx<71 && (ty:=(k-1)//nW-dy)>=0 && ty<25
      this.SC(c, C_[ty*71+tx+1])
    return
  Case "RepL":
    if (CutLeft<=0) || (bg!="" && InStr(color,"**") && CutLeft=1)
      return
    k:=CutLeft-nW, CutLeft--
    Loop % nH
      k+=nW, (A_Index>CutUp && A_Index<nH+1-CutDown && G_.Call("RepColor"))
    return
  Case "CutL":
    if (CutLeft+CutRight>=nW)
      return
    CutLeft++, k:=CutLeft-nW
    Loop % nH
      k+=nW, (A_Index>CutUp && A_Index<nH+1-CutDown && G_.Call("CutColor"))
    return
  Case "CutL3":
    Loop 3
      G_.Call("CutL")
    return
  Case "RepR":
    if (CutRight<=0) || (bg!="" && InStr(color,"**") && CutRight=1)
      return
    k:=1-CutRight, CutRight--
    Loop % nH
      k+=nW, (A_Index>CutUp && A_Index<nH+1-CutDown && G_.Call("RepColor"))
    return
  Case "CutR":
    if (CutLeft+CutRight>=nW)
      return
    CutRight++, k:=1-CutRight
    Loop % nH
      k+=nW, (A_Index>CutUp && A_Index<nH+1-CutDown && G_.Call("CutColor"))
    return
  Case "CutR3":
    Loop 3
      G_.Call("CutR")
    return
  Case "RepU":
    if (CutUp<=0) || (bg!="" && InStr(color,"**") && CutUp=1)
      return
    k:=(CutUp-1)*nW, CutUp--
    Loop % nW
      k++, (A_Index>CutLeft && A_Index<nW+1-CutRight && G_.Call("RepColor"))
    return
  Case "CutU":
    if (CutUp+CutDown>=nH)
      return
    CutUp++, k:=(CutUp-1)*nW
    Loop % nW
      k++, (A_Index>CutLeft && A_Index<nW+1-CutRight && G_.Call("CutColor"))
    return
  Case "CutU3":
    Loop 3
      G_.Call("CutU")
    return
  Case "RepD":
    if (CutDown<=0) || (bg!="" && InStr(color,"**") && CutDown=1)
      return
    k:=(nH-CutDown)*nW, CutDown--
    Loop % nW
      k++, (A_Index>CutLeft && A_Index<nW+1-CutRight && G_.Call("RepColor"))
    return
  Case "CutD":
    if (CutUp+CutDown>=nH)
      return
    CutDown++, k:=(nH-CutDown)*nW
    Loop % nW
      k++, (A_Index>CutLeft && A_Index<nW+1-CutRight && G_.Call("CutColor"))
    return
  Case "CutD3":
    Loop 3
      G_.Call("CutD")
    return
  Case "Gray2Two":
    ListLines % (lls:=A_ListLines)?0:0
    gs:=[], k:=0
    Loop % nW*nH
      gs[++k]:=((((c:=cors[k])>>16)&0xFF)*38+((c>>8)&0xFF)*75+(c&0xFF)*15)>>7
    _Gui:=FindText_Capture
    _Gui["Threshold"].Focus()
    Threshold:=_Gui["Threshold"].Value
    if (Threshold="")
    {
      pp:=[]
      Loop 256
        pp[A_Index-1]:=0
      Loop % nW*nH
        if (show[A_Index])
          pp[gs[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
      }
      _Gui["Threshold"].Value:=Threshold
    }
    Threshold:=Round(Threshold)
    color:="*" Threshold, k:=i:=0
    Loop % nW*nH
      ascii[++k]:=v:=(gs[k]<=Threshold)
      , (show[k] && i:=(v?i+1:i-1))
    bg:=(i>0 ? "1":"0"), G_.Call("BlackWhite")
    ListLines % lls
    return
  Case "GrayDiff2Two":
    _Gui:=FindText_Capture
    GrayDiff:=_Gui["GrayDiff"].Value
    if (GrayDiff="")
    {
      _Gui.Opt("+OwnDialogs")
      MsgBox, 4096, Tip, % Lang["s11"], 1
      return
    }
    ListLines % (lls:=A_ListLines)?0:0
    gs:=[], k:=0
    Loop % nW*nH
      gs[++k]:=((((c:=cors[k])>>16)&0xFF)*38+((c>>8)&0xFF)*75+(c&0xFF)*15)>>7
    if (CutLeft=0)
      G_.Call("CutL")
    if (CutRight=0)
      G_.Call("CutR")
    if (CutUp=0)
      G_.Call("CutU")
    if (CutDown=0)
      G_.Call("CutD")
    GrayDiff:=Round(GrayDiff)
    color:="**" GrayDiff, k:=i:=0
    Loop % nW*nH
      j:=gs[++k]+GrayDiff
      , ascii[k]:=v:=( gs[k-1]>j || gs[k+1]>j
      || gs[k-nW]>j || gs[k+nW]>j
      || gs[k-nW-1]>j || gs[k-nW+1]>j
      || gs[k+nW-1]>j || gs[k+nW+1]>j )
      , (show[k] && i:=(v?i+1:i-1))
    bg:=(i>0 ? "1":"0"), G_.Call("BlackWhite")
    ListLines % lls
    return
  Case "AddColorSim", "AddColorDiff":
    _Gui:=FindText_Capture
    c:=StrReplace(_Gui["SelColor"].Value, "0x")
    if (c="")
    {
      _Gui.Opt("+OwnDialogs")
      MsgBox, 4096, Tip, % Lang["s12"], 1
      return
    }
    s:=_Gui["ColorList"].Value
    if InStr(cmd, "Sim")
      v:=_Gui["Similar1"].Value, v:=c "-" Round(v/100,2)
    else
      v:=_Gui["dRGB2"].Value, v:=c "-" Format("{:06X}",v<<16|v<<8|v)
    s:=RegExReplace("/" s, "/" c "-[^/]*") . "/" v
    _Gui["ColorList"].Value:=Trim(s,"/")
    ControlSend,, {End}, % "ahk_id " _Gui["ColorList"].Hwnd
    G_.Call("Color2Two")
    return
  Case "Undo2":
    _Gui:=FindText_Capture
    s:=_Gui["ColorList"].Value
    s:=RegExReplace("/" s, "/[^/]+$")
    _Gui["ColorList"].Value:=Trim(s,"/")
    ControlSend,, {End}, % "ahk_id " _Gui["ColorList"].Hwnd
    return
  Case "Color2Two":
    _Gui:=FindText_Capture
    color:=RegExReplace(_Gui["ColorList"].Value, "i)\s|0x")
    if (color="")
    {
      _Gui.Opt("+OwnDialogs")
      MsgBox, 4096, Tip, % Lang["s16"], 1
      return
    }
    ListLines % (lls:=A_ListLines)?0:0
    k:=i:=v:=0, arr:=StrSplit(Trim(StrReplace(color,"@","-"), "/"), "/")
    Loop % nW*nH
    {
      c:=cors[++k], rr:=(c>>16)&0xFF, gg:=(c>>8)&0xFF, bb:=c&0xFF
      For k1,v1 in arr
      {
        r:=StrSplit(Trim(v1,"-") "-", "-"), c:=this.ToRGB(r[1]), n:=r[2]
        , r:=((c>>16)&0xFF)-rr, g:=((c>>8)&0xFF)-gg, b:=(c&0xFF)-bb
        if InStr(n, ".")
        {
          n:=this.Floor(n), n:=(n<=0||n>1?0:Floor(9*255*255*(1-n)*(1-n)))
          if v:=(3*r*r+4*g*g+2*b*b<=n)
            Break
        }
        else
        {
          c:=this.Floor("0x" n), dR:=(c>>16)&0xFF, dG:=(c>>8)&0xFF, dB:=c&0xFF
          if v:=(Abs(r)<=dR && Abs(g)<=dG && Abs(b)<=dB)
            Break
        }
      }
      ascii[k]:=v, (show[k] && i:=(v?i+1:i-1))
    }
    bg:=(i>0 ? "1":"0"), G_.Call("BlackWhite")
    ListLines % lls
    return
  Case "ColorPos2Two":
    _Gui:=FindText_Capture
    c:=_Gui["SelColor"].Value
    if (c="")
    {
      _Gui.Opt("+OwnDialogs")
      MsgBox, 4096, Tip, % Lang["s12"], 1
      return
    }
    n:=_Gui["Similar2"].Value, n:=Round(n/100,2), color:="#" c "-" n
    , n:=(n<=0||n>1?0:Floor(9*255*255*(1-n)*(1-n)))
    , rr:=(c>>16)&0xFF, gg:=(c>>8)&0xFF, bb:=c&0xFF, k:=i:=0
    ListLines % (lls:=A_ListLines)?0:0
    Loop % nW*nH
      c:=cors[++k], r:=((c>>16)&0xFF)-rr, g:=((c>>8)&0xFF)-gg, b:=(c&0xFF)-bb
      , ascii[k]:=v:=3*r*r+4*g*g+2*b*b<=n, (show[k] && i:=(v?i+1:i-1))
    bg:=(i>0 ? "1":"0"), G_.Call("BlackWhite")
    ListLines % lls
    return
  Case "BlackWhite":
    Loop % 25 + 0*(ty:=dy-1)*(k:=0)
    Loop % 71 + 0*(tx:=dx-1)*(ty++)
    if (k++)*0 + (++tx)<nW && ty<nH && show[i:=ty*nW+tx+1]
      this.SC((ascii[i]?0:0xFFFFFF), C_[k])
    return
  Case "Modify":
    Modify:=FindText_Capture["Modify"].Value
    return
  Case "MultiColor":
    MultiColor:=FindText_Capture["MultiColor"].Value
    Result:=""
    ToolTip
    return
  Case "FindShape":
    FindShape:=FindText_Capture["FindShape"].Value
    (FindShape && !MultiColor) && FindText_Capture["MultiColor"].Value:=MultiColor:=1
    return
  Case "Undo":
    Result:=RegExReplace(Result, ",[^/]+/[^/]+/[^/]+$")
    ToolTip % Trim(Result, ",")
    return
  Case "Similar1", "Similar2", "Similar3":
    i:=FindText_Capture[cmd].Value
    For k,v in ["Similar1","Similar2","Similar3"]
      (v!=cmd) && FindText_Capture[v].Value:=i
    return
  Case "GetTxt":
    txt:=""
    if (bg="")
      return
    k:=0
    ListLines % (lls:=A_ListLines)?0:0
    Loop % nH
    {
      v:=""
      Loop % nW
        v.=!show[++k] ? "" : ascii[k] ? "1":"0"
      txt.=v="" ? "" : v "`n"
    }
    ListLines % lls
    return
  Case "Auto":
    G_.Call("GetTxt")
    if (txt="")
    {
      FindText_Capture.Opt("+OwnDialogs")
      MsgBox, 4096, Tip, % Lang["s13"], 1
      return
    }
    While InStr(txt,bg)
    {
      if (txt~="^" bg "+\n")
        txt:=RegExReplace(txt, "^" bg "+\n"), G_.Call("CutU")
      else if !(txt~="m`n)[^\n" bg "]$")
        txt:=RegExReplace(txt, "m`n)" bg "$"), G_.Call("CutR")
      else if (txt~="\n" bg "+\n$")
        txt:=RegExReplace(txt, "\n\K" bg "+\n$"), G_.Call("CutD")
      else if !(txt~="m`n)^[^\n" bg "]")
        txt:=RegExReplace(txt, "m`n)^" bg), G_.Call("CutL")
      else Break
    }
    txt:=""
    return
  Case "OK", "SplitAdd", "AllAdd":
    _Gui:=FindText_Capture
    _Gui.Opt("+OwnDialogs")
    G_.Call("GetTxt")
    if (txt="") && (!MultiColor)
    {
      MsgBox, 4096, Tip, % Lang["s13"], 1
      return
    }
    if InStr(color,"#") && (!MultiColor)
    {
      k:=i:=j:=0
      ListLines % (lls:=A_ListLines)?0:0
      Loop % nW*nH
      {
        if (!show[++k])
          Continue
        i++
        if (k=SelPos)
        {
          j:=i
          Break
        }
      }
      ListLines % lls
      if (j=0)
      {
        MsgBox, 4096, Tip, % Lang["s12"], 1
        return
      }
      color:="#" j "-" StrSplit(color "-","-")[2]
    }
    Comment:=_Gui["Comment"].Value
    if (cmd="SplitAdd") && (!MultiColor)
    {
      if InStr(color,"#")
      {
        MsgBox, 4096, Tip, % Lang["s14"], 3
        return
      }
      bg:=StrLen(StrReplace(txt,"0"))
        > StrLen(StrReplace(txt,"1")) ? "1":"0"
      s:="", i:=0, k:=nW*nH+1+CutLeft
      Loop % w:=nW-CutLeft-CutRight
      {
        i++
        if (!show[k++] && A_Index<w)
          Continue
        i:=Format("{:d}",i)
        v:=RegExReplace(txt,"m`n)^(.{" i "}).*","$1")
        txt:=RegExReplace(txt,"m`n)^.{" i "}"), i:=0
        While InStr(v,bg)
        {
          if (v~="^" bg "+\n")
            v:=RegExReplace(v,"^" bg "+\n")
          else if !(v~="m`n)[^\n" bg "]$")
            v:=RegExReplace(v,"m`n)" bg "$")
          else if (v~="\n" bg "+\n$")
            v:=RegExReplace(v,"\n\K" bg "+\n$")
          else if !(v~="m`n)^[^\n" bg "]")
            v:=RegExReplace(v,"m`n)^" bg)
          else Break
        }
        if (v!="")
        {
          v:=Format("{:d}.",InStr(v,"`n")-1) . this.bit2base64(v)
          s.="`nText.=""|<" SubStr(Comment,1,1) ">" color "$" v """`n"
          Comment:=SubStr(Comment, 2)
        }
      }
      Event:=cmd, Result:=s
      _Gui.Hide()
      return
    }
    if (!MultiColor)
      txt:=Format("{:d}.",InStr(txt,"`n")-1) . this.bit2base64(txt)
    else
    {
      n:=_Gui["Similar3"].Value, n:=Round(n/100,2), color:="##" n
      , n:=(n<=0||n>1?0:Floor(9*255*255*(1-n)*(1-n)))
      , arr:=StrSplit(Trim(StrReplace(Result,",","/"),"/"),"/"), s:="", i:=1
      SetFormat, IntegerFast, d
      Loop % arr.Length()//3
        x1:=arr[i++], y1:=arr[i++], c1:=arr[i++], c:="0x" c1
        , (A_Index=1 && (x:=x1, y:=y1, rr:=(c>>16)&0xFF, gg:=(c>>8)&0xFF, bb:=c&0xFF))
        , r:=((c>>16)&0xFF)-rr, g:=((c>>8)&0xFF)-gg, b:=(c&0xFF)-bb
        , s.="," (x1-x) "/" (y1-y) "/" (FindShape?3*r*r+4*g*g+2*b*b<=n:c1)
      txt:=SubStr(s,2)
    }
    s:="`nText.=""|<" Comment ">" color "$" txt """`n"
    if (cmd="SplitAdd" || cmd="AllAdd")
    {
      Event:=cmd, Result:=s
      _Gui.Hide()
      return
    }
    x:=nX+CutLeft+(nW-CutLeft-CutRight)//2
    y:=nY+CutUp+(nH-CutUp-CutDown)//2
    s:=StrReplace(s, "Text.=", "Text:="), r:=StrSplit(Lang["s8"] "|||||||", "|")
    s:="`; #Include <FindText>`n"
    . "`nt1:=A_TickCount, Text:=X:=Y:=""""`n" s
    . "`nif (ok:=FindText(X, Y, " x "-150000, "
    . y "-150000, " x "+150000, " y "+150000, 0, 0, Text))"
    . "`n{"
    . "`n  `; FindText()." . "Click(" . "X, Y, ""L"")"
    . "`n}`n"
    . "`n`; ok:=FindText(X:=""wait"", Y:=3, 0,0,0,0,0,0,Text)    `; " r[7]
    . "`n`; ok:=FindText(X:=""wait0"", Y:=-1, 0,0,0,0,0,0,Text)  `; " r[8]
    . "`n`nMsgBox, 4096, Tip, `% """ r[1] ":``t"" (IsObject(ok)?ok.Length():ok)"
    . "`n  . ""``n``n" r[2] ":``t"" (A_TickCount-t1) "" " r[3] """"
    . "`n  . ""``n``n" r[4] ":``t"" X "", "" Y"
    . "`n  . ""``n``n" r[5] ":``t<"" (IsObject(ok)?ok[1].id:"""") "">""`n"
    . "`nTry For i,v in ok  `; ok " r[6] " ok:=FindText().ok"
    . "`n  if (i<=2)"
    . "`n    FindText().MouseTip(ok[i].x, ok[i].y)`n"
    Event:=cmd, Result:=s
    _Gui.Hide()
    return
  Case "SavePic2":
    x:=nX+CutLeft, w:=nW-CutLeft-CutRight
    y:=nY+CutUp, h:=nH-CutUp-CutDown
    G_.Call("ScreenShot", x "|" y "|" (x+w-1) "|" (y+h-1) "|0")
    return
  Case "ShowPic":
    ControlGet, i, CurrentLine,,, ahk_id %hscr%
    ControlGet, s, Line, %i%,, ahk_id %hscr%
    FindText_Main["MyPic"].Value:=Trim(this.ASCII(s),"`n")
    return
  Case "KeyDown":
    Critical
    _Gui:=FindText_Main
    if (WinExist()!=_Gui.Hwnd)
      return
    Try ctrl:="", ctrl:=args[3]
    if (ctrl=hscr)
      SetTimer % G_ShowPic, -150
    else if (ctrl=_Gui["ClipText"].Hwnd)
    {
      s:=_Gui["ClipText"].Value
      _Gui["MyPic"].Value:=Trim(this.ASCII(s),"`n")
    }
    return
  Case "LButtonDown":
    Critical
    if (WinExist()!=FindText_Capture.Hwnd)
      return G_.Call("KeyDown", arg1, args*)
    CoordMode, Mouse
    MouseGetPos, k1, k2,, k6, 2
    if (k6=hPic)
    {
      ListLines % (lls:=A_ListLines)?0:0
      Loop
      {
        Sleep 50
        MouseGetPos, k3, k4
        this.RangeTip(Min(k1,k3), Min(k2,k4)
        , Abs(k1-k3)+1, Abs(k2-k4)+1, (A_MSec<500 ? "Red":"Blue"))
      }
      Until !this.State("LButton")
      ListLines % lls
      this.RangeTip()
      this.GetBitsFromScreen(,,,,0,zx,zy)
      this.ClientToScreen(sx, sy, 0, 0, hPic)
      sx:=Min(k1,k3)-sx+hBM_x+zx, sy:=Min(k2,k4)-sy+hBM_y+zy
      , sw:=Abs(k1-k3)+1, sh:=Abs(k2-k4)+1
      if (sw+sh)<5
        sx-=71//2, sy-=25//2, sw:=71, sh:=25
      G_.Call("CaptureUpdate")
      FindText_Capture["MyTab1"].Choose(1)
      return
    }
    if !(Cid_.HasKey(k6) && k5:=Cid_[k6])
      return
    if (k5=-1)
    {
      MouseMove, k1+2, k2+2, 0
      MouseGetPos,,,, k6, 2
      MouseMove, k1, k2, 0
      if !(Cid_.HasKey(k6) && k5:=Cid_[k6]) || (k5=-1)
        return
    }
    if (k5>71*25)
    {
      k1:=nW*nH+dx+(k5-71*25)
      this.SC(((show[k1]:=!show[k1])?0xFF0000:0xFFFFAA), k6)
      return
    }
    k3:=Mod(k5-1,71)+dx, k4:=(k5-1)//71+dy
    if (k3>=nW || k4>=nH)
      return
    k1:=k4*nW+k3+1
    if (Modify && bg!="" && show[k1])
      this.SC(((ascii[k1]:=!ascii[k1])?0:0xFFFFFF), k6)
    else
    {
      k2:=cors[k1], SelPos:=k1
      _Gui:=FindText_Capture
      _Gui["SelGray"].Value:=(((k2>>16)&0xFF)*38+((k2>>8)&0xFF)*75+(k2&0xFF)*15)>>7
      _Gui["SelColor"].Value:=Format("0x{:06X}",k2&0xFFFFFF)
      _Gui["SelR"].Value:=(k2>>16)&0xFF
      _Gui["SelG"].Value:=(k2>>8)&0xFF
      _Gui["SelB"].Value:=k2&0xFF
    }
    if (MultiColor && show[k1])
    {
      (FindShape && Result="") && G_.Call("ColorPos2Two")
      k2:=Format(",{:d}/{:d}/{:06X}", nX+k3, nY+k4, cors[k1]&0xFFFFFF)
      , Result.=InStr(Result,k2) ? "":k2
      ToolTip % Trim(Result, ",")
    }
    return
  Case "RButtonDown":
    Critical
    MouseGetPos,,,, k2, 2
    if (k2!=hPic)
      return
    CoordMode, Mouse
    MouseGetPos, k1, k2
    k5:=hBM_x, k6:=hBM_y
    ListLines % (lls:=A_ListLines)?0:0
    Loop
    {
      Sleep 10
      MouseGetPos, k3, k4
      hBM_x:=k5+k1-k3, hBM_y:=k6+k2-k4
      G_.Call("PicShow")
    }
    Until !this.State("RButton")
    ListLines % lls
    return
  Case "MouseMove":
    Try ctrl_name:="", ctrl_name:=this.GuiCtrlFromHwnd(args[3]).Name
    if (PrevControl != ctrl_name)
    {
      ToolTip
      PrevControl:=ctrl_name
      Try SetTimer % G_ToolTip, % (PrevControl ? -500:"Off")
      Try SetTimer % G_ToolTipOff, % (PrevControl ? -5500:"Off")
    }
    return
  Case "ToolTip":
    MouseGetPos,,, _TT
    if WinExist("ahk_id " _TT " ahk_class AutoHotkeyGUI")
      Try ToolTip % Tip_Text[PrevControl]
    return
  Case "ToolTipOff":
    ToolTip
    return
  Case "CutL2", "CutR2", "CutU2", "CutD2":
    s:=FindText_Main["MyPic"].Value
    s:=Trim(s,"`n") . "`n", v:=SubStr(cmd,4,1)
    if (v="U")
      s:=RegExReplace(s,"^[^\n]+\n")
    else if (v="D")
      s:=RegExReplace(s,"[^\n]+\n$")
    else if (v="L")
      s:=RegExReplace(s,"m`n)^[^\n]")
    else if (v="R")
      s:=RegExReplace(s,"m`n)[^\n]$")
    FindText_Main["MyPic"].Value:=Trim(s,"`n")
    return
  Case "Update":
    ControlFocus,, % "ahk_id " hscr
    ControlGet, i, CurrentLine,,, ahk_id %hscr%
    ControlGet, s, Line, %i%,, ahk_id %hscr%
    if !RegExMatch(s, "O)(<[^>\n]*>[^$\n]+\$)\d+\.[\w+/]+", r)
      return
    v:=FindText_Main["MyPic"].Value
    v:=Trim(v,"`n") . "`n", w:=Format("{:d}",InStr(v,"`n")-1)
    v:=StrReplace(StrReplace(v,"0","1"),"_","0")
    s:=StrReplace(s, r[0], r[1] . w "." this.bit2base64(v))
    v:="{End}{Shift Down}{Home}{Shift Up}{Del}"
    ControlSend,, %v%, ahk_id %hscr%
    Control, EditPaste, %s%,, ahk_id %hscr%
    ControlSend,, {Home}, ahk_id %hscr%
    return
  }
}

Lang(text:="", getLang:=0)
{
  local
  static init, Lang1, Lang2
  if !VarSetCapacity(init) && (init:="1")
  {
    s:="
    (
Myww       = 宽度 = 调整抓图范围的宽度
Myhh       = 高度 = 调整抓图范围的高度
AddFunc    = 附加 = 复制时带 FindText() 函数
NowHotkey  = 截屏热键 = 当前的截屏热键
SetHotkey1 = = 第一优先级的截屏热键
SetHotkey2 = = 第二优先级的截屏热键
Apply      = 应用 = 应用新的截屏热键
CutU2      = 上删 = 裁剪下面编辑框中文字的上边缘
CutL2      = 左删 = 裁剪下面编辑框中文字的左边缘
CutR2      = 右删 = 裁剪下面编辑框中文字的右边缘
CutD2      = 下删 = 裁剪下面编辑框中文字的下边缘
Update     = 更新 = 更新下面编辑框中文字到代码行中
GetRange   = 获取屏幕范围 = 获取屏幕范围到剪贴板并替换代码中的范围参数
GetOffset  = 获取相对坐标 = 获取相对图像位置的偏移坐标并替换代码中的点击坐标
GetClipOffset  = 获取相对坐标2 = 获取相对左边编辑框的图像的偏移坐标
Capture    = 抓图 = 开始屏幕抓图
CaptureS   = 截屏抓图 = 先截屏,然后显示截屏图像,再手动选择图像内的范围抓图
Test       = 测试 = 测试生成的代码是否可以查找成功
TestClip   = 测试2 = 测试左边文本框中的文字是否可以查找成功,结果复制到剪贴板
Paste      = 粘贴 = 粘贴剪贴板的文字数据
CopyOffset = 复制2 = 复制左边的偏移坐标到剪贴板
Copy       = 复制 = 复制代码到剪贴板
Reset      = 重读 = 重新读取原来的彩色图像
SplitAdd   = 分割添加 = 点击黄色的标签来分割图像为多个图像数据,添加到旧代码中
AllAdd     = 整体添加 = 将文字数据整体添加到旧代码中
Gray2Two      = 灰度阈值二值化 = 灰度小于阈值的为黑色其余白色
GrayDiff2Two  = 灰度差值二值化 = 某点与周围灰度之差大于差值的为黑色其余白色
Color2Two     = 颜色二值化 = 通过颜色列表来转换图像为黑白图
ColorPos2Two  = 颜色位置二值化 = 指定颜色及相似色为黑色其余白色,但是记录该色的位置
SelGray    = 灰度 = 选定颜色的灰度值 (0-255)
SelColor   = 颜色 = 选定颜色的RGB颜色值
SelR       = 红 = 选定颜色的红色分量
SelG       = 绿 = 选定颜色的绿色分量
SelB       = 蓝 = 选定颜色的蓝色分量
RepU       = -上 = 撤销裁剪上边缘1个像素
CutU       = 上 = 裁剪上边缘1个像素
CutU3      = 上3 = 裁剪上边缘3个像素
RepL       = -左 = 撤销裁剪左边缘1个像素
CutL       = 左 = 裁剪左边缘1个像素
CutL3      = 左3 = 裁剪左边缘3个像素
Auto       = 自动 = 二值化之后自动裁剪空白边缘
RepR       = -右 = 撤销裁剪右边缘1个像素
CutR       = 右 = 裁剪右边缘1个像素
CutR3      = 右3 = 裁剪右边缘3个像素
RepD       = -下 = 撤销裁剪下边缘1个像素
CutD       = 下 = 裁剪下边缘1个像素
CutD3      = 下3 = 裁剪下边缘3个像素
Modify     = 修改 = 二值化后可以用鼠标在预览区点击手动修改黑白点
MultiColor = 多点找色 = 鼠标选择多种颜色,之后点击“确定”按钮
FindShape  = 找形状 = 鼠标选择多种颜色,会基于第一点的颜色二值化
Undo       = 撤销 = 撤销上一次选择的颜色
Undo2      = 撤销 = 撤销上一次添加到颜色列表的颜色
Comment    = 识别文字 = 识别文本 (包含在<>中),分割添加时也会分解成单个文字
Threshold  = 灰度阈值 = 灰度阈值 (0-255)
GrayDiff   = 灰度差值 = 灰度差值 (0-255)
Similar1   = 相似度 = 与选定颜色的相似度
Similar2   = 相似度 = 与选定颜色的相似度
Similar3   = 相似度 = 与选定颜色的相似度
AddColorSim  = 添加 = 颜色相似模式添加到颜色列表中再运行颜色二值化
AddColorDiff = 添加 = 颜色偏色模式添加到颜色列表中再运行颜色二值化
ColorList  = = 颜色列表用于转换图像为二值图
DiffRGB    = 红/绿/蓝 = 多色查找时各分量允许的偏差 (0-255)
DiffRGB2   = 红/绿/蓝 = 多色查找时各分量允许的偏差 (0-255)
Bind0      = 绑定窗口1 = 绑定窗口使用GetDCEx()获取后台窗口图像
Bind1      = 绑定窗口1+ = 绑定窗口使用GetDCEx()并修改窗口透明度
Bind2      = 绑定窗口2 = 绑定窗口使用PrintWindow()获取后台窗口图像
Bind3      = 绑定窗口2+ = 绑定窗口使用PrintWindow()并修改窗口透明度
Bind4      = 绑定窗口3 = 绑定窗口使用PrintWindow(,,3)获取后台窗口图像
OK         = 确定 = 生成全新的代码替换旧代码
OK2        = 确定 = 恢复截屏到屏幕然后再抓图
Cancel     = 取消 = 关闭窗口不做任何事
Cancel2    = 取消 = 关闭窗口不做任何事
ClearAll   = 清空 = 清空所有保存的截图
OpenDir    = 打开目录 = 打开保存屏幕截图的目录
SavePic    = 保存图片 = 选择一个范围保存为图片
SavePic2   = 保存图片 = 将修剪后的原始图像保存为图片
LoadPic    = 载入图片 = 载入一张图片作为抓取的图像
ClipText   = = 显示粘贴的文字数据
Offset     = = 显示“获取相对坐标2”或者“获取屏幕范围”的结果
SelectBox  = = 选择截图显示到屏幕左上角
s1  = FindText找字工具
s2  = 灰度阈值|灰度差值|颜色|颜色位置|多色查找
s3  = 图像二值化及分割
s4  = 抓图生成字库及找字代码
s5  = 方向键微调选框\n先点击右键(Ctrl)一次\n把鼠标移开\n再点击右键(Ctrl)一次
s6  = 解绑窗口使用
s7  = 左键(Ctrl)拖动选择范围\n坐标复制到剪贴板
s8  = 找到|时间|毫秒|位置|结果|值可以这样获取|等待3秒等图像出现|无限等待等图像消失
s9  = 截屏成功
s10 = 鼠标位置|穿透显示绑定窗口\n点击右键完成抓图
s11 = 请先设定灰度差值!
s12 = 请先选择核心颜色!
s13 = 请先将图像二值化!
s14 = 不能用于颜色位置二值化模式, 因为分割后会导致位置错误
s15 = 你确定选择的范围吗?\n\n如果不确定,可以重新选择
s16 = 请先添加颜色到颜色列表!
s17 = 你想打开的图片没有找到!
s18 = 捕获|截图
s19 = 你确定要删除所有的截图吗?
    )"
    Lang1:=[], Lang2:=[]
    Loop Parse, s, `n, `r
      if InStr(v:=A_LoopField, "=")
        r:=StrSplit(StrReplace(v "==","\n","`n"), "=", "`t ")
        , Lang1[r[1]]:=r[2], Lang2[r[1]]:=r[3]
  }
  return getLang=1 ? Lang1 : getLang=2 ? Lang2 : Lang1[text]
}

;---------------------------------
; Gui-V1-V2 Compatibility Library  By FeiYue
;---------------------------------

GuiNew(args*) {
  return new this.GuiCreate(args*)
}

GuiFromHwnd(hwnd:="AllGuiObj", RecurseParent:=0) {
  static init, AllGuiObj
  if !VarSetCapacity(init) && (init:="1")
    AllGuiObj:=[]
  if (hwnd=="AllGuiObj")
    return AllGuiObj
  if (RecurseParent)
    While hwnd && !AllGuiObj.HasKey(hwnd)
      hwnd:=DllCall("GetParent", "Ptr",hwnd, "Ptr")
  return AllGuiObj[hwnd]
}

GuiCtrlFromHwnd(hwnd) {
  return this.GuiFromHwnd(hwnd,1)[hwnd]
}

GuiOnEvent(EventName, args*) {
  return this.GuiFromHwnd(WinExist())["_" EventName].Call(0,args*)
}

GuiClose(args*) {
  return FindText().GuiOnEvent("Close",args*)
}

GuiEscape(args*) {
  return FindText().GuiOnEvent("Escape",args*)
}

GuiSize(args*) {
  return FindText().GuiOnEvent("Size",args*)
}

GuiContextMenu(args*) {
  return FindText().GuiOnEvent("ContextMenu",args*)
}

GuiDropFiles(args*) {
  return FindText().GuiOnEvent("DropFiles",0,args*)
}

Class GuiCreate
{  ;// GuiCreate Class Begin

__New(opts:="", title:="", args*) {
  local
  Gui, New, % opts " +Hwndhwnd +LabelFindTextClass.Gui", % title
  this.Hwnd:=hwnd, this.ClassNN:=[]
  FindText().GuiFromHwnd()[hwnd]:=this
}

__Delete() {
  this.Destroy()
}

Destroy() {
  local
  if !(hwnd:=this.Hwnd)
    return
  this.Hwnd:="", FindText().GuiFromHwnd().Delete(hwnd)
  Try Gui, % hwnd ":Destroy"
  For k,v in this
    (v.Hwnd && v.Hwnd:=""), this[k]:=""
}

OnEvent(EventName, Callback, AddRemove:=1) {
  if IsObject(Callback)
    this["_" EventName]:=Callback
}

Opt(opts) {
  Gui, % this.Hwnd ":" RegExReplace(opts,"i)[+\-\s]Label\S*")
}

Add(type, opts:="", text:="") {
  local
  static init, type2class
  if !VarSetCapacity(init) && (init:="1")
    type2class:=[]
  type:=(type="DropDownList"?"DDL":type="Picture"?"Pic":type)
  name:=RegExMatch(opts,"i)(^|[+\-\s])V(?!Scroll\b|ertical\b)\K\S*",r)?r:""
  opts:=RegExReplace(opts,"i)(^|[+\-\s])V(?!Scroll\b|ertical\b)\S*")
  if IsObject(text)
  {
    s:=""
    For k,v in text
      s.="|" v
    text:=Trim(s, "|")
  }
  Gui, % this.Hwnd ":Add", % type, % opts " +Hwndhwnd", % text
  this.LastHwnd:=hwnd
  if type2class.HasKey(type)
    s:=type2class[type]
  else
  {
    WinGetClass, s, ahk_id %hwnd%
    type2class[type]:=s
  }
  this.ClassNN[s]:=n:=Floor(this.ClassNN[s])+1, classnn:=s . n
  obj:= new this.Control(this.Hwnd, hwnd, type, classnn, name)
  this[hwnd]:=obj, this[classnn]:=obj
  if (name) && !(name~="i)^(Destroy|OnEvent|Opt|Add"
  . "|SetFont|Show|Hide|Move|GetClientPos|GetPos|Maximize"
  . "|Minimize|Restore|Flash|Submit|Hwnd|Name|Title"
  . "|BackColor|MarginX|MarginY|MenuBar|FocusedCtrl)$")
    this[name]:=obj
  return obj
}

SetFont(opts:="", FontName:="") {
  Gui, % this.Hwnd ":Font", % opts, % FontName
}

Show(opts:="", args*) {
  Gui, % this.Hwnd ":Show", % opts
}

Hide() {
  Gui, % this.Hwnd ":Hide"
}

Move(x:="", y:="", w:="", h:="") {
  local
  this.GetPos(pX, pY, pW, pH)
  x:=(x=""?pX:x), y:=(y=""?pY:y), w:=(w=""?pW:w), h:=(h=""?pH:h)
  DllCall("MoveWindow", "Ptr",this.Hwnd, "int",x, "int",y, "int",w, "int",h, "int",1)
}

GetClientPos(ByRef x:="", ByRef y:="", ByRef w:="", ByRef h:="") {
  local
  VarSetCapacity(rect, 16, 0)
  , DllCall("GetClientRect",  "Ptr",this.Hwnd, "Ptr",&rect)
  , DllCall("ClientToScreen", "Ptr",this.Hwnd, "Ptr",&rect)
  , x:=NumGet(rect, 0, "int"), y:=NumGet(rect, 4, "int")
  , w:=NumGet(rect, 8, "int")-x, h:=NumGet(rect, 12, "int")-y
}

GetPos(ByRef x:="", ByRef y:="", ByRef w:="", ByRef h:="") {
  local
  VarSetCapacity(rect, 16, 0)
  , DllCall("GetWindowRect",  "Ptr",this.Hwnd, "Ptr",&rect)
  , x:=NumGet(rect, 0, "int"), y:=NumGet(rect, 4, "int")
  , w:=NumGet(rect, 8, "int")-x, h:=NumGet(rect, 12, "int")-y
}

Maximize() {
  Gui, % this.Hwnd ":Maximize"
}

Minimize() {
  Gui, % this.Hwnd ":Minimize"
}

Restore() {
  Gui, % this.Hwnd ":Restore"
}

Flash(k:=1) {
  Gui, % this.Hwnd ":Flash", % k ? "":"Off"
}

Submit(hide:=1) {
  local
  (hide && this.Hide()), arr:=[]
  For k,v in this
    if k is number
      if (v.Name!="")
        arr[v.Name]:=v.Value
  return arr
}

BackColor {
  get {
    return this._BackColor
  }
  set {
    this._BackColor:=value
    Gui, % this.Hwnd ":Color", % value
    return value
  }
}

MarginX {
  get {
    return this._MarginX
  }
  set {
    this._MarginX:=value
    Gui, % this.Hwnd ":Margin", % value
    return value
  }
}

MarginY {
  get {
    return this._MarginY
  }
  set {
    this._MarginY:=value
    Gui, % this.Hwnd ":Margin",, % value
    return value
  }
}

MenuBar {
  get {
    return this._MenuBar
  }
  set {
    this._MenuBar:=value
    Gui, % this.Hwnd ":Menu", % value
    return value
  }
}

Title {
  get {
    local
    VarSetCapacity(v, 260*2)
    DllCall("GetWindowText", "Ptr",this.Hwnd, "Str",v, "Int",260)
    return v
  }
  set {
    DllCall("SetWindowText", "Ptr",this.Hwnd, "Str",value)
    return value
  }
}

FocusedCtrl {
  get {
    local
    GuiControlGet, v, % this.Hwnd ":Focus"
    return this[v]
  }
}

Class Control
{  ;// Control Class Begin

__New(GuiHwnd, hwnd, type, classnn, name) {
  this.GuiHwnd:=GuiHwnd, this.Hwnd:=hwnd
  this.Type:=type, this.ClassNN:=classnn, this.Name:=name
}

Opt(opts) {
  GuiControl, % opts, % this.Hwnd
}

OnEvent(EventName, Callback, AddRemove:=1) {
  local
  r:=this.OnEvent_G.Bind(this, Callback)
  GuiControl, +g, % this.Hwnd, % r
}

OnEvent_G(Callback, args*) {
  if IsObject(Callback)
    return %Callback%(this, args*)
}

GetPos(ByRef x:="", ByRef y:="", ByRef w:="", ByRef h:="") {
  local
  GuiControlGet, p, Pos, % this.Hwnd
  x:=Floor(pX), y:=Floor(pY), w:=Floor(pW), h:=Floor(pH)
}

Move(x:="", y:="", w:="", h:="") {
  local
  s:=(x=""?"":" x" x) (y=""?"":" y" y) (w=""?"":" w" w) (h=""?"":" h" h)
  GuiControl, Move, % this.Hwnd, % s
}

Redraw() {
  GuiControl, MoveDraw, % this.Hwnd
}

Focus() {
  Try GuiControl, Focus, % this.Hwnd
}

UseTab(Name:="", Exact:="", index:="") {
  Gui, % this.GuiHwnd ":Tab", % Name, % index, % Exact?"Exact":""
}

SetFont(opts:="", FontName:="") {
  Gui, % this.GuiHwnd ":Font", % opts, % FontName
  GuiControl, Font, % this.Hwnd
}

Add(text) {
  local
  if IsObject(text)
  {
    s:=""
    For k,v in text
      s.="|" v
    text:=Trim(s, "|")
  }
  GuiControl,, % this.Hwnd, % text
}

Delete(N:="") {
  if (N="")
    GuiControl,, % this.Hwnd, |
  else
    this.Choose(N), this.Choose(0)
}

Choose(N) {
  if N is number
    GuiControl, Choose, % this.Hwnd, % N
  else
    GuiControl, ChooseString, % this.Hwnd, % N
}

Gui {
  get {
    return FindText().GuiFromHwnd(this.GuiHwnd)
  }
}

Enabled {
  get {
    local
    GuiControlGet, v, Enabled, % this.Hwnd
    return v
  }
  set {
    GuiControl, % "Enable" (!!value), % this.Hwnd
    return value
  }
}

Visible {
  get {
    local
    GuiControlGet, v, Visible, % this.Hwnd
    return v
  }
  set {
    GuiControl, % "Show" (!!value), % this.Hwnd
    return value
  }
}

Focused {
  get {
    local
    GuiControlGet, v, % this.GuiHwnd ":Focus"
    return (v=this.ClassNN)
  }
}

Value {
  get {
    local
    if (this.Type~="i)^(ListBox|DDL|ComboBox|Tab)$")
      this.Opt("+AltSubmit")
    GuiControlGet, v,, % this.Hwnd
    return v
  }
  set {
    if (this.Type~="i)^(ListBox|DDL|ComboBox|Tab)$")
      GuiControl, Choose, % this.Hwnd, % value
    else
      GuiControl,, % this.Hwnd, % value
    return value
  }
}

Text {
  get {
    local
    if (this.Type~="i)^(ListBox|DDL|ComboBox|Tab)$")
      this.Opt("-AltSubmit")
    GuiControlGet, v,, % this.Hwnd
    return v
  }
  set {
    if (this.Type~="i)^(ListBox|DDL|ComboBox|Tab)$")
      GuiControl, ChooseString, % this.Hwnd, % value
    else
      GuiControl,, % this.Hwnd, % value
    return value
  }
}

}  ;// Control Class End

}  ;// GuiCreate Class End

Script_End() {
}

}  ;// Class End

;================= The End =================

;

 

  

;Reveal information on windows, controls, etc. 
;by toralf
;requires AHK 1.0.44.04
;www.autohotkey.com/forum/topic8976.html

ScriptName = AHK Window Info 1.7

; License: Attribution-NonCommercial-ShareAlike 2.5 licence from Creative Commons 
; for details see: http://creativecommons.org/licenses/by-nc-sa/2.5/legalcode
;
; export code by sosaited www.autohotkey.com/forum/viewtopic.php?t=8732&p=53372#53372
; idea and lot of code of frame drawing by shimanov
; several ideas from Chris and other users of the AHK forum

; initial ideas taken from these scripts: 
; Ahk Window Spy 1.3.3 by Decarlo www.autohotkey.com/forum/viewtopic.php?t=4679 
; WinInfo Menu by Jon www.autohotkey.com/forum/viewtopic.php?t=8617

;changes since 1.6
; - added a small gap in the mouse picker grid to identify the center (thanks fade2gray)
; - adjusted groupbox size and tab size
; - added reset of picker to default color on dimensional change

;changes since 1.5
; - Groupboxes with bold text have been set -wrap, to fix line breaks on some windows themes
; - BGR is made default for color picker
; - update is stopped when mouse moves over its own gui, allowing easier graping of data, since no Pause key needs to be pressed. 

;changes since 1.4
; - "H" replaced with Hwnd; "P" and "S" with "Pos" and "Size" on advanced tab for Control
; - GroupBox names have bold font
; - Mouse color picker is only updated when mouse tab is visible. Otherwise set to gray
; - set default for color picker to 15x15, since it only influences CPU load when the mouse tab is visible
; - controls list items are only updated when advanced tab is visible. Otherwise set to ">>>not updated<<<""
; - windows statusbar text is only updated when advanced tab is visible. Otherwise set to ">>>not updated<<<""
; - fast/slow visible/hidden window text are only updated when advanced tab is visible. Otherwise set to ">>>not updated<<<""
;todo
; - Window Info should be tested on Windows 9x

;changes since 1.3
; - last tab gets remembered between starts
; - large list hides automatically when tab is not "Advanced"
; - by default not rectangle is drawn around controls
; - gui starts NoActivate
; - fixed a problem with hidden gui and pause key
; - reduced impact in hidden mode on CPU load to nearly 0
; - to support 800x600 screen resolutions the advanced tab initial height is 600 
; - instead of auto-update, update of data can be done on mouse click (button can be L/M/R, default M)
; - when started with "HideGui" turned on: GUI starts hidden, after 500 ms data is collected and GUI shown 
; - changed licence to Attribution-NonCommercial-ShareAlike 2.5 licence from Creative Commons

;changes since 1.2
; - added: Control handle to advanced and list view
; - improved: fixed some spelling mistakes
; - fixed: option "Show tooltip at cursor" had no effect
; - fixed: option "Show tooltip at cursor" wasn't remembered between sessions
; - improved: For all DllCall's the types are put in quotes  
; - changed: coordinates and sizes will have a space after the comma when put on clipboard 
; - changed: the number of characters in the GUI for the list items is limited to 200. Clipboard will receive all 
; - changed: "Introduction - Please Read" button moved to new info tab
; - changed: Renamed "active control in window" to "focused control in window".
; - fixed: Window Info refused to minimize while the right-side list was displayed.
; - changed: While Window Info is minimized, updating of data is turned off
; - fixed: Coordinates of GUI got stored when GUI got closed minimized

;changes since 1.1
; - added: OnExit routine that cleans up frame gui if script exits unexpectedly
; - changed: Tooltip of control frame disappears when mouse gets moved onto it.
; - changed: font size of GUI is now 6pt

;changes since 1.0
; - improved: specified the font for the GUI, MS Sans Serif, 8 point
; - changed: for some OS (WIN_2000,WIN_NT4,WIN_95,WIN_98,WIN_ME) the icon is changed to ID 57
; - improved: small features that simplify maintenance
;        + combine update routines
;        + simplify options actions
;        + simplify Pause Key actions
;        + reorder code
; - improved: new method to capture fast/slow visible/hidden window text (Thanks Chris)
; - changed: Gui (advanced) now holds fields for fast/slow visible/hidden window text
; - added: option to switch color picker between RGB and BGR
; - improved: color picker only updates when mouse moves or color below mouse changes. This reduces jittery update.
; - changed: Color picker now has a 15x15 color matrix
; - changed: checkbox "Show right List" changed to button that alternates between "More Info >>" and "<< Less Info".
; - added: check for minium required AHK version 
; - added: new option to turn auto-update automatically ON when Gui gets inactive (if it had been turned off (by pause or by the large list))

/*
Requests:
[quote="Chris"]Sometimes pressing Window Info's minimize button fails to work.[/quote]I still can't reproduce it. I tried it 20 times any each time the window minimized 

[quote="Chris"]I've made a note to test it on Win9x prior to distribution.[/quote]Please do. Or is there someone else out there to do the testing. Would be very much appreaciated. 

[quote="Chris"]Minor typos in source code comments: "or less or" should be "or else" in 2 places.[/quote]The two cases where "or less or" is written are actually correct. 
*/

AHK_version = 1.0.44.04 
If not A_IsCompiled      ;if it is a script
    CheckAHKVersion(AHK_version)   ;check if minimum AHK Version is installed 

InformationText =
  (LTrim
    This Gui will reveal information on windows, controls, etc.
    This software is under the GNU General Public License for details see: www.autohotkey.com/docs/license.htm
    
    Move your mouse over the area of interest and see the data in this GUI changing accordingly (auto-update). The auto-update stops when this GUI becomes the active one. To achieve this without moving the mouse you can use Alt+Tab to change to %ScriptName%. Or you can use a hotkey to turn the auto-update off. The default hotkey is the Pause key.
    
    When the data for the large list is collected (advanced tab), the auto-update of the data is stopped automatically to allow you to work with the data. Use the toggle hotkey (see below) to create a new snapshot of data. Or turn on the option, to start updating again when the GUI gets deactivated. 
    
    These shortcuts exist:
    =================
    
    => Toggle Auto-Update Hotkey (default: Pause):
    ---------------------------------------------------------------------------
    Toggles (start/stop) auto-updating data in GUI OR creates a new snapshot of data when auto-update has been stopped automatically. 
    
    => Left-Mouse Button:
    ---------------------------------------
    Copies the content of a control to the clipboard. This is achieved in the code with OnMessage(), thus it should not interfere with any of your own hotkeys.
    
    => Middle-Mouse Button:
    ---------------------------------------
    Toggles AlwaysOnTop status of this window. Click inside the window, it will not work on the titlebar. This is achieved in the code with OnMessage(), thus it should not interfere with any of your own hotkeys.
    
    => Win+s hotkey combination:
    ------------------------------------------------
    Exports data to file. It will only work, when auto-update has been stopped. 
    
    Remarks:
    =======
    - You can change the toggle auto-update hotkey in the advanced options (you will not see keys that do not produces visible characters, e.g. the default Pause key). A key has to be specified. A single Ctrl, Shift, Alt, Win key or their combinations are not allowed.
    - The advanced option "Hide/Show Gui" allows you to create snapshots of data while the GUI is hidden. The toggle auto-update hotkey will toggle the visibility of the GUI. Just before the GUI is shown again the data gets collected and the GUI updated.
    - Log to file only works when auto-update has been stopped.
    - Specify a file name you want to save the data too. Insert #'s into the filename, if you want %ScriptName% to number the files automatically. 
  )  

#SingleInstance force
;set working dir, in case this script is called from some other script in a different dir 
SetWorkingDir, %A_ScriptDir%

GoSub, ReadIni
GoSub, CreateTrayMenu
GoSub, BuildGui

WindowControlTextSize = 32767  ; Must be 32767 or less or it won't work on Windows 95.
VarSetCapacity(WindowControlText, WindowControlTextSize)
ControlTextSize = 512          ; Must be 32767 or less or it won't work on Windows 95.
VarSetCapacity(ControlText, ControlTextSize)

;activate auto-update toggle hotkey
HotKey, %HtkPauseAction%, PauseAction, On

;toggle AOT attribute of GUI with middle mouse click
WM_MBUTTONDOWN = 0x207
OnMessage(WM_MBUTTONDOWN, "ToggleOnTopGui1")

;initialize Save hotkey, so it can be easily turned on/off 
HotKey, #s, BtnSaveExport, Off
;initialize update on click hotkey, so it can be easily turned on/off 
Hotkey, IfWinNotActive, ahk_id %Gui1UniqueID%
Hotkey, ~%CbbHtkUpdate%, UpdateOnClick, Off
Hotkey, IfWinNotActive

;activate update on click
If RadUpdateOnClick {
      Hotkey, IfWinNotActive, ahk_id %Gui1UniqueID%
      Hotkey, ~%CbbHtkUpdate%, On
      Hotkey, IfWinNotActive
}Else{
    ;activate auto-start updating at Gui inactivity
    WM_ACTIVATE = 0x6
    If ChkAutoStartUpdate
        OnMessage(WM_ACTIVATE, "WM_ACTIVATE")

    ;set timer once, so that it knows its interval and can be easily turned on/off
    UpdateIsStopped := True
    SetTimer, UpdateInfo, %CbbUpdateInterval%
    If ChkHideGui {
        Sleep, 500
        Gosub, PauseAction
        ToolTip("Press Pause to hide GUI again", 2000)
    }Else
        UpdateIsStopped := False
  }
    
;activate copy-on-click for left mouse click
WM_LBUTTONDOWN = 0x201
If ChkCopyToCB
    OnMessage(WM_LBUTTONDOWN, "WM_LBUTTONDOWN")

;set static parameters to draw frames around control and window
Sysget, ScreenWidth, 78   ; get screen size from virtual screen 
Sysget, ScreenHeight, 79 
frame_cc = 0x0000FF       ;set color for frame, 0x00BBGGRR
frame_cw = 0x00FF00       ;set color for frame, 0x00BBGGRR
frame_t  = 2              ;set line thickness for frame, 1-10

GoSub, ToogleExportActions
GoSub, PrepareFrameDraw  ;create or destroy frame drawing objects

OnExit, ExitSub
Return
;######## End of Auto-Exec-Section

ExitSub:
  GoSub, CleanUpFrameGui
  Sleep,50
  ExitApp
Return

ReadIni:
  SplitPath, A_ScriptName, , , , OutNameNoExt
  IniFile = %OutNameNoExt%.ini
  
  IniRead, Gui1Pos                 , %IniFile%, Settings, Gui1Pos                , x0 y0
  IniRead, Gui1AOTState            , %IniFile%, Settings, Gui1AOTState           , 1
  IniRead, Tab1                    , %IniFile%, Settings, Tab1                   , 1
  IniRead, RadWindow               , %IniFile%, Settings, RadWindow              , 2
  IniRead, RadControl              , %IniFile%, Settings, RadControl             , 2
  IniRead, SelectedRadList         , %IniFile%, Settings, SelectedRadList        , 1
  IniRead, ChkShowList             , %IniFile%, Settings, ChkShowList            , 0
  IniRead, HtkPauseAction          , %IniFile%, Settings, HtkPauseAction         , Pause
  IniRead, ChkCopyToCB             , %IniFile%, Settings, ChkCopyToCB            , 1
  IniRead, ChkHideGui              , %IniFile%, Settings, ChkHideGui             , 0
  IniRead, ChkUseSaveHotkey        , %IniFile%, Settings, ChkUseSaveHotkey       , 0
  IniRead, ChkExportMousePosScreen , %IniFile%, Export  , ChkExportMousePosScreen, 1
  IniRead, ChkExportMousePosAWin   , %IniFile%, Export  , ChkExportMousePosAWin  , 0
  IniRead, ChkExportMousePosWin    , %IniFile%, Export  , ChkExportMousePosWin   , 1
  IniRead, ChkExportMousePointer   , %IniFile%, Export  , ChkExportMousePointer  , 0
  IniRead, ChkExportMouseColorRGB  , %IniFile%, Export  , ChkExportMouseColorRGB , 0
  IniRead, ChkExportMouseColorHex  , %IniFile%, Export  , ChkExportMouseColorHex , 0
  IniRead, ChkExportCtrlText       , %IniFile%, Export  , ChkExportCtrlText      , 1
  IniRead, ChkExportCtrlClass      , %IniFile%, Export  , ChkExportCtrlClass     , 1
  IniRead, ChkExportCtrlPos        , %IniFile%, Export  , ChkExportCtrlPos       , 0
  IniRead, ChkExportCtrlSize       , %IniFile%, Export  , ChkExportCtrlSize      , 0
  IniRead, ChkExportCtrlListItems  , %IniFile%, Export  , ChkExportCtrlListItems , 0
  IniRead, ChkExportWinTitle       , %IniFile%, Export  , ChkExportWinTitle      , 1
  IniRead, ChkExportWinPos         , %IniFile%, Export  , ChkExportWinPos        , 0
  IniRead, ChkExportWinSize        , %IniFile%, Export  , ChkExportWinSize       , 0
  IniRead, ChkExportWinClass       , %IniFile%, Export  , ChkExportWinClass      , 1
  IniRead, ChkExportWinProcess     , %IniFile%, Export  , ChkExportWinProcess    , 1
  IniRead, ChkExportWinUID         , %IniFile%, Export  , ChkExportWinUID        , 0
  IniRead, ChkExportWinPID         , %IniFile%, Export  , ChkExportWinPID        , 0
  IniRead, ChkExportWinStatusText  , %IniFile%, Export  , ChkExportWinStatusText , 1
  IniRead, ChkExportWinText        , %IniFile%, Export  , ChkExportWinText       , 1
  IniRead, ChkExportLargeList      , %IniFile%, Export  , ChkExportLargeList     , 1
  IniRead, EdtExportFile           , %IniFile%, Export  , EdtExportFile          , AHK_Window_Info_Data_###.txt
  IniRead, ChkExportAutoNumber     , %IniFile%, Export  , ChkExportAutoNumber    , 1
  IniRead, ChkExportAppend         , %IniFile%, Export  , ChkExportAppend        , 0
  IniRead, ChkShowInfoToolTip      , %IniFile%, Advanced, ChkShowInfoToolTip     , 1
  IniRead, ChkDrawRectCtrl         , %IniFile%, Advanced, ChkDrawRectCtrl        , 0
  IniRead, ChkDrawRectWin          , %IniFile%, Advanced, ChkDrawRectWin         , 0
  IniRead, ChkTtpMaster            , %IniFile%, Advanced, ChkTtpMaster           , 0
  IniRead, ChkTtpMSPos             , %IniFile%, Advanced, ChkTtpMSPos            , 0
  IniRead, ChkTtpMWPos             , %IniFile%, Advanced, ChkTtpMWPos            , 1
  IniRead, ChkTtpMColor            , %IniFile%, Advanced, ChkTtpMColor           , 1
  IniRead, ChkTtpCClass            , %IniFile%, Advanced, ChkTtpCClass           , 1
  IniRead, ChkTtpCPos              , %IniFile%, Advanced, ChkTtpCPos             , 0
  IniRead, ChkTtpCSize             , %IniFile%, Advanced, ChkTtpCSize            , 0
  IniRead, ChkTtpWClass            , %IniFile%, Advanced, ChkTtpWClass           , 1
  IniRead, ChkTtpWTitle            , %IniFile%, Advanced, ChkTtpWTitle           , 1
  IniRead, CbbUpdateInterval       , %IniFile%, Advanced, CbbUpdateInterval      , 100
  IniRead, CbbColorPickDim         , %IniFile%, Advanced, CbbColorPickDim        , 15x15
  IniRead, RadColorPick            , %IniFile%, Advanced, RadColorPick           , 2
  IniRead, ChkAutoStartUpdate      , %IniFile%, Advanced, ChkAutoStartUpdate     , 1
  IniRead, CbbHtkUpdate            , %IniFile%, Advanced, CbbHtkUpdate           , MButton
  IniRead, RadUpdateOnClick        , %IniFile%, Advanced, RadUpdateOnClick       , 0
  IniRead, RadUpdateAuto           , %IniFile%, Advanced, RadUpdateAuto          , 1
Return

CreateTrayMenu:
  ;location of icon file
  IconFile := A_WinDir "\system" iif(A_OSType = "WIN32_WINDOWS","","32") "\shell32.dll"
  ;create traybar menu
  ;icon for taskbar and for proces in task manager
  If A_OSVersion in WIN_2000,WIN_NT4,WIN_95,WIN_98,WIN_ME
      Menu, Tray, Icon, %IconFile%, 57    
  Else
      Menu, Tray, Icon, %IconFile%, 172
  Menu, Tray, NoStandard
  Menu, Tray, Tip, %ScriptName%
  Menu, Tray, Add, Show, GuiShow
  Menu, Tray, Default, Show 
  Menu, Tray, Add, Exit, GuiClose
  Menu, Tray, Click, 1
Return

GuiShow:
  Gui, 1:Show                   ;show window again if it has been hidden
Return

BuildGui:
  GuiIsVisible := False
  Gui, 1: +LastFound
  Gui1UniqueID := WinExist() 
  Gui, 1:Font, s6, MS Sans Serif
  Gui, 1:Margin, 0, 0
  Gui, 1:Add, Tab, w287 h145 vTab1 gTab1 AltSubmit -Wrap , Simple|Advanced|Mouse|Options|Info
    Gui, 1:Tab, Simple
      Gui, 1:Add, Text, x5 y28 , Window Title
      Gui, 1:Add, Edit, x+2 yp-3 w211 vEdtEasyWindowTitle, 
    
      Gui, 1:Add, Text, x5 y+5, Window Class
      Gui, 1:Add, Edit, x+2 yp-3 w206 vEdtEasyWindowClass, 

      Gui, 1:Add, Text, x5 y+5, Control ClassNN
      Gui, 1:Add, Edit, x+2 yp-3 w196 vEdtEasyControlClass, 

      Gui, 1:Add, Text, x5 y+5, Control Text
      Gui, 1:Add, Edit, x+2 yp-3 w216 vEdtEasyControlText, 

      Gui, 1:Add, Text, x5 y+5, Mouse Position relative to Window
      Gui, 1:Add, Edit, x+2 yp-3 w110 vEdtEasyMousePosWin,

    Gui, 1:Tab, Advanced
      Gui, 1:Add, Text, x5 y28 Section, Pos. rel. to Window
      Gui, 1:Add, Edit, x+2 yp-3 w80 vEdtDataMousePosWin,

      Gui, 1:Add, Button, x+28 yp-1 vBtnShowList gBtnShowList -Wrap, % iif(ChkShowList,"<< Less Info","More Info >>")
      
      Gui, 1:Font, bold 
      Gui, 1:Add, GroupBox, xs w274 h114 -wrap, Control      
      Gui, 1:Font, normal 
        Gui, 1:Add, Text, xs+4 yp+18, Text
        Gui, 1:Add, Edit, x+2 yp-3 w104 vEdtControlText, 
      
        Gui, 1:Add, Text, x+5 yp+3, ClassNN
        Gui, 1:Add, Edit, x+2 yp-3 w91 vEdtControlClass, 
      
        Gui, 1:Add, Text, xs+4 y+5, Pos
        Gui, 1:Add, Edit, x+2 yp-3 w60 vEdtControlPos, 
      
        Gui, 1:Add, Text, x+5 yp+3, Size
        Gui, 1:Add, Edit, x+2 yp-3 w65 vEdtControlSize, 

        Gui, 1:Add, Text, x+5 yp+3, Hwnd
        Gui, 1:Add, Edit, x+2 yp-3 w59 vEdtControlHwnd, 
    
        Gui, 1:Add, Text, xs+4 y+3, List`nItems  
        Gui, 1:Add, Edit, x+4 r3 w237 vEdtListItems, 
        
      Gui, 1:Font, bold 
      Gui, 1:Add, GroupBox, xs w274 h492 -wrap vGrbAdvancedWindow, Window
      Gui, 1:Font, normal 
        Gui, 1:Add, Text, xs+4 yp+18 , Title
        Gui, 1:Add, Edit, x+2 yp-3 w244 vEdtWindowTitle, 
      
        Gui, 1:Add, Text, xs+4 y+5, Position
        Gui, 1:Add, Edit, x+2 yp-3 w88 vEdtWindowPos, 
      
        Gui, 1:Add, Text, x+5 yp+3, Size
        Gui, 1:Add, Edit, x+2 yp-3 w112 vEdtWindowSize,
      
        Gui, 1:Add, Text, xs+4 y+5, Class
        Gui, 1:Add, Edit, x+2 yp-3 w100 vEdtWindowClass, 
      
        Gui, 1:Add, Text, x+5 yp+3, Process
        Gui, 1:Add, Edit, x+2 yp-3 w94 vEdtWindowProcess, 
      
        Gui, 1:Add, Text, xs+4 y+5, Unique ID
        Gui, 1:Add, Edit, x+2 yp-3 w77 vEdtWindowUID, 
      
        Gui, 1:Add, Text, x+5 yp+3, Process ID
        Gui, 1:Add, Edit, x+2 yp-3 w80 vEdtWindowPID, 
    
        Gui, 1:Add, Text, xs+4 y+3, StatusbarText (Part# - Text)  
        Gui, 1:Add, ListBox, xs+4 y+2 r4 w266 vLsbStatusbarText, 
        
        Gui, 1:Add, Text, xs+4 y+3 Section, Fast Visible Text  
        Gui, 1:Add, Edit, y+2 r10 w132 vEdtWindowTextFastVisible, 

        Gui, 1:Add, Text, x+2 ys, Fast Hidden Text  
        Gui, 1:Add, Edit, y+2 r10 w132 vEdtWindowTextFastHidden, 

        Gui, 1:Add, Text, xs Section vTxtWindowTextSlowVisible, Slow Visible Text  
        Gui, 1:Add, Edit, y+2 r10 w132 vEdtWindowTextSlowVisible, 

        Gui, 1:Add, Text, x+2 ys vTxtWindowTextSlowHidden, Slow Hidden Text  
        Gui, 1:Add, Edit, y+2 r10 w132 vEdtWindowTextSlowHidden, 
      
    Gui, 1:Tab, Mouse
      Gui, 1:Add, Text, x5 y28, Data of/under mouse cursor and Positions relative to
      Gui, 1:Add, Text, x5 y+5, Window
      Gui, 1:Add, Edit, x+2 yp-3 w106 vEdtMousePosWin,
      
      Gui, 1:Add, Text, x+5 yp+3, Screen
      Gui, 1:Add, Edit, x+2 yp-3 w88 vEdtMousePosScreen,
    
      Gui, 1:Add, Text, x5 y+5, Active Window
      Gui, 1:Add, Edit, x+2 yp-3 w73 vEdtMousePosAWin,
    
      Gui, 1:Add, Text, x+5 yp+3, Cursor
      Gui, 1:Add, Edit, x+2 yp-3 w92 vEdtMousePointer,
    
      Gui, 1:Add, Text, x5 y+5, RGB Color
      Gui, 1:Add, Edit, x+2 yp-3 w95 vEdtMouseColorRGB,
    
      Gui, 1:Add, Text, x+5 yp+3, RGB Color
      Gui, 1:Add, Edit, x+2 yp-3 w72 vEdtMouseColorHex,
        
      Gui, 1:Font, bold 
      Gui, 1:Add, GroupBox, x5 y+10 Section w274 h305 -wrap, Color Picker
      Gui, 1:Font, normal 
        Gui, 1:Add, Text, xs+4 yp+18, Dimension:
        Gui, 1:Add, ComboBox, x+5 yp-3 w55 vCbbColorPickDim gRefreshControlStates, 1x1|3x3||5x5|7x7|9x9|15x15
        Gui, 1:Add, Radio, x+5 yp+3 vRadColorPick gRefreshControlStates, RGB
        Gui, 1:Add, Radio, x+5 Checked gRefreshControlStates, BGR

        Gui, 1:Add, Text, xs+4 y+5 w10 h5 Section,        ;only to create a gap to the color matix
        
        Loop, 15 {
            Row = %A_Index%
            dy := (Row = 8 OR Row = 9) ? "y+2" : ""
            Gui, 1:Add, Progress, xs+5 %dy% w17 h17 vPgbColorPicker%Row%_1,
            Loop, 14 {
                Column := A_Index + 1
                dx := (A_Index = 7 OR A_Index = 8) ? 2 : 0
                Gui, 1:Add, Progress, x+%dx% w17 h17 vPgbColorPicker%Row%_%Column%,
              }
          }

    Gui, 1:Tab, Options

      Gui, 1:Add, Text, x5 y25 Section , Show window and control data for
      Gui, 1:Add, Radio, xs y+5 vRadWindow gRefreshControlStates, Active Window
      Gui, 1:Add, Radio, xs y+5 Checked gRefreshControlStates, Window under Mouse Cursor

      Gui, 1:Add, Button, x+55 y25 gBtnShowOptions1, Advanced`nOptions

      Gui, 1:Add, Text, xs y+25, Show control data for
      Gui, 1:Add, Radio, xs y+5 vRadControl gRefreshControlStates, Focused Control in Window
      Gui, 1:Add, Radio, xs y+5 Checked gRefreshControlStates, Control under Mouse Cursor

      Gui, 1:Add, Checkbox, xs y+15 vChkTtpMaster gRefreshControlStates Checked%ChkTtpMaster%, Show tooltip at cursor
      Gui, 1:Add, Button, x+3 yp-5 gBtnShowOptions2, Data Filter Options

      Gui, 1:Add, Text, xs y+12 , Draw a rectangle around
      Gui, 1:Add, Checkbox, x+5 vChkDrawRectCtrl gChkDrawRectCtrl Checked%ChkDrawRectCtrl%, control (red)
      Gui, 1:Add, Checkbox, y+5 vChkDrawRectWin gChkDrawRectWin Checked%ChkDrawRectWin%, window (green)
      
      ExportOptions =           ;collect all checkboxes, so they can be parsed in a loop
        (LTrim Join,
          ChkExportMousePosScreen,ChkExportMousePosAWin,ChkExportMousePosWin
          ChkExportMousePointer,ChkExportMouseColorRGB,ChkExportMouseColorHex
          ChkExportCtrlText,ChkExportCtrlClass,ChkExportCtrlPos
          ChkExportCtrlSize,ChkExportCtrlListItems,ChkExportWinTitle,ChkExportWinPos
          ChkExportWinSize,ChkExportWinClass,ChkExportWinProcess
          ChkExportWinUID,ChkExportWinPID,ChkExportWinStatusText
          ChkExportWinText,ChkExportLargeList
        )
       
      Gui, 1:Add, Text, xs y+17 ,Log Data to File  
      Gui, 1:Add, Button, x+5 yp-5 gBtnShowOptions3, Log Options
      Gui, 1:Add, Button, x+5 vBtnSaveExport gBtnSaveExport, Save to file 
      Gui, 1:Add, Edit, xs w255 vEdtExportFile, %EdtExportFile%
      Gui, 1:Add, Button, x+2 yp-1 gBtnBrowseExportFile,... 
    Gui, 1:Tab, Info
      Gui, 1:Add, Text, x5 y25 Section ,
        (
This GUI will reveal information on windows, controls, etc.,
but only when this GUI is not the active window.

- To start/stop updating data press the Auto-Update
  toggle Hotkey (default: Pause).
- To put the content of a field on the clipboard click with
  the left mouse button into the field.
- To toggle the always-on-top state of this GUI use the
  middle mouse button.
        )  
      Gui, 1:Add, Button, x70 y+5 vBtnShowInfo gBtnShowInfo, More Information - Please read
      
  Gui, 1:Tab
  GuiControl, Choose, Tab1, %Tab1%   

  Gui, 1:Add, Radio, x290 y2 Section vRadList1 gRadList, Info on all Controls of one window
  Gui, 1:Add, Radio, x+5 vRadList2 gRadList, Info on all Windows    (Click radio buttons again to refresh list)
  Gui, 1:Add, ListView, xs y+5 w370 h339 vLV1 Count200
    , Z or Stack Order|Unique ID or Handle|Window PID|Class(NN)|Process Name|Hidden|Title or Text|X|Y|Width|Height|Style|ExStyle|Selected|CurrentCol|CurrentLine|LineCount|Choice|Tab|Enabled|Checked

  ;Apply settings
  If RadWindow = 1
      GuiControl, 1:, RadWindow, 1
  If RadControl = 1
      GuiControl, 1:, RadControl, 1
  If RadColorPick = 1
      GuiControl, 1:, RadColorPick, 1
  GuiControl, 1:, RadList%SelectedRadList%, 1
  GuiControl, 1:ChooseString, CbbColorPickDim, %CbbColorPickDim%
  StringSplit, Dim, CbbColorPickDim, x    ;prepare color picker dimensions
  Dim = %Dim1%
  HalfDim := Dim // 2 + 1

  GoSub, ShowHideList 

  If Gui1AOTState {
      Gui, 1:+AlwaysOnTop
      TitleExtension = - *AOT*
    }
  
  If ChkHideGui
      ShowOption = Hide
  Else        
      ShowOption = NoActivate
  Gui, 1:Show, %Gui1Pos% %ShowOption% AutoSize , %ScriptName% %TitleExtension%
  If !ChkHideGui
      GuiIsVisible := True
Return

;###############################################################################
;###   prepare hotkey or mouse interaction with GUI   ##########################
;###############################################################################

WM_LBUTTONDOWN(wParam, lParam, msg, hwnd){       ;Copy-On-Click for controls
    global 
    local Content 

    If A_GuiControl is space                     ;Control is not known
        Return
    If A_GuiControl not contains Edt,Lsb,Pgb     ;Control is something else then edit, listbox or progressbar control
        Return
    
    ;Check for full text vars
    Fulltext = %A_GuiControl%Full
    If (%Fulltext% <> "")
        Content := %Fulltext%
    Else {
        If A_GuiControl contains Pgb                 ;get value from color pickers (progressbar)
            Content := %A_GuiControl%
        Else
            GuiControlGet, Content, , %A_GuiControl% ;get controls content
      }
    
    If Content is space                          ;content is empty or couldn't be retrieved
        Return
  
    If A_GuiControl contains Class               ;change data for specific fields
        Content = %Content%
    Else If A_GuiControl contains UID
        Content = ahk_id %Content%
    Else If A_GuiControl contains PID
        Content = ahk_pid %Content%
    Else If A_GuiControl contains Process
        Content = ahk_exe %Content%
    Else If A_GuiControl contains Pos,Size
      {
        StringReplace, Content, Content, x
        StringReplace, Content, Content, y
        StringReplace, Content, Content, w
        StringReplace, Content, Content, h
        StringReplace, Content, Content, %A_Space%, `,%A_Space%
      }
    Else If A_GuiControl contains Pgb
        Content = 0x%Content%
    ClipBoard = %Content%                   ;put content in clipboard 
  
    If ChkShowInfoToolTip {
        If (StrLen(Content) > 200){             ;give feedback (limit size to 200 characters)
            StringLeft, Content, Content, 200 
            Content = %Content% ...
          }
          ToolTip("ClipBoard = " Content)
      }
  }

WM_ACTIVATE(wParam, lParam, msg, hwnd){
    Global UpdateIsStopped, ChkHideGui
    If (wParam  AND !ChkHideGui) 
        UpdateIsStopped := False 
  }

UpdateOnClick:
  UpdateIsStopped := False    ;needs to be set if large list had set it to true
  GoSub, UpdateInfo           ;collect data
Return

PauseAction:                      ;user has pressed toogle auto-update hotkey
  If ChkHideGui {                 ;user wants hide/show toggle
      UpdateIsStopped := False    ;needs to be set if large list had set it to true
      If GuiIsVisible {
          Gui, 1:Hide 
      }Else{
          SetTimer, UpdateInfo, Off ;turn timer off, to collect only once data
          UpdateIsStopped := False  ;turn update on
          UpdateAfterPause := True  ;set flag to update all
          GoSub, UpdateInfo         ;collect data
          UpdateAfterPause := False ;turn off flag to update all
          UpdateIsStopped := True   ;turn update off
          SetTimer, UpdateInfo, %CbbUpdateInterval% ;turn timer back on
          GoSub, GuiShow            ;bring GUI to front
        }
      GuiIsVisible := not GuiIsVisible
      If ChkShowInfoToolTip
          ToolTip(iif(UpdateIsStopped,"Press " HtkPauseAction " to hide GUI","Wait for " HtkPauseAction " key to`nupdate data and show GUI"),2000)
  }Else {
      UpdateIsStopped := not UpdateIsStopped  ;toggle update status and show feedback
      If UpdateIsStopped                      ;when stopped, bring GUI to front
          GoSub, GuiShow
      If ChkShowInfoToolTip                   ;give feedback
          ToolTip(Scriptname "`n----------------------------`nUpdate data : " iif(UpdateIsStopped,"Off","On"))
    }

  GoSub, ToogleExportActions
  GoSub, PrepareFrameDraw  ;create or destroy frame drawing objects
Return

ToogleExportActions:
  ;Disable Export Save button during update 
  GuiControl, 1:Enable%UpdateIsStopped%, BtnSaveExport

  ;Enable Export Save hotkey when update is stopped and hotkey wanted 
  If (ChkUseSaveHotkey AND UpdateIsStopped)
      HotKey, #s, , On
  Else                 ; ... otherwise de-activate Export Save hotkey
      HotKey, #s, , Off UseErrorLevel
Return

PrepareFrameDraw:           ;create or destroy frame drawing objects
  If (UpdateIsStopped OR (ChkDrawRectCtrl = 0 AND ChkDrawRectWin = 0)){
      GoSub, CleanUpFrameGui
  ;create GUI Only if Gui doesn't exist yet and is needed.
  }Else If ( (ChkDrawRectCtrl OR ChkDrawRectWin) And not FrameGUIExists ){
      FrameGUIExists := True
      ;create transparent GUI covering the whole screen 
      Gui, 2:+Lastfound +AlwaysOnTop
      Gui, 2:Color, Black 
      WinSet, TransColor, Black
      Gui, 2: -Caption +ToolWindow
      Gui, 2:Show, x0 y0 w%ScreenWidth% h%ScreenHeight%, FrameDrawGUI2
      UniqueIDGui2 := WinExist()

      ;create draw objects for that window 
      CreateDrawHandles(UniqueIDGui2, ScreenWidth, ScreenHeight, frame_cc, frame_cw) 
    }
  ;set previous control/window to nothing, so that the frames start to draw immediatly
  PreviousControlID = 
  PreviousWindowID =
Return

CleanUpFrameGui:
  DeleteObject( h_brushC )       ;destroy objects 
  DeleteObject( h_brushW ) 
  DeleteObject( h_region ) 
  DeleteObject( hbm_buffer ) 
    
  DeleteDC( hdc_frame ) 
  DeleteDC( hdc_buffer ) 
  Gui, 2:Destroy                 ;destroy gui
  FrameGUIExists := False
  ToolTip, , , , 2               ;remove control frame tooltip
  ToolTip, , , , 3               ;remove window frame tooltip
Return

;###############################################################################
;###   Interactions with GUI controls   ########################################
;###############################################################################

Tab1:
  GuiControlGet, Tab1, 1:                ;get current value
  GoSub, ClearNotUsedControls
  If (Tab1 = 1){                            ;adjust tab height based on visible tab
      GuiControl, 1:Move, Tab1, h145
  }Else If (Tab1 = 2) {  
      GuiControl, 1:Move, Tab1, h570
  }Else If (Tab1 = 3) {  
      GuiControl, 1:Move, Tab1, h430
  }Else If (Tab1 = 4) {
      GuiControl, 1:Move, Tab1, h274
  }Else If (Tab1 = 5) {  
      GuiControl, 1:Move, Tab1, h174
    }
  ChkShowList := False
  GoSub, ShowHideList
  Gui, 1:Show, AutoSize                         ;autosize GUI
return

ClearNotUsedControls:
  If (Tab1 <> 2) {  
      GuiControl, 1:, EdtListItems, >>>not updated<<<
      GuiControl, 1:, LsbStatusbarText, |>>>not updated<<<
      GuiControl, 1:, EdtWindowTextFastVisible, >>>not updated<<<
      GuiControl, 1:, EdtWindowTextSlowVisible, >>>not updated<<<
      GuiControl, 1:, EdtWindowTextFastHidden, >>>not updated<<<
      GuiControl, 1:, EdtWindowTextSlowHidden, >>>not updated<<<
    }
  If (Tab1 <> 3) {  
      Loop, %Dim% {
          Row := A_Index + 8 - HalfDim
          Loop, %Dim% {
              y++
              Control := "PgbColorPicker" (A_Index + 8 - HalfDim) "_" Row 
              GuiControl, 1:+BackgroundECE9D8,%Control% 
            }
        }
      
    }
Return

ShowHideList:
  GuiControl, 1:, BtnShowList, % iif(ChkShowList,"<< Less Info","More Info >>") 
  GuiControl, 1:Show%ChkShowList%, RadList1      ;show/hide controls
  GuiControl, 1:Show%ChkShowList%, RadList2
  GuiControl, 1:Show%ChkShowList%, LV1          ;show/hide large list
Return

BtnShowList:
  ChkShowList := not ChkShowList
  GoSub, ShowHideList
  Gui, 1:Show, AutoSize                         ;autosize GUI
  If ChkShowList                                    
      GoSub, GetDataForLargeList      ;get data 
Return

RadList:
  LV_Delete()                                      ;clear controls
  StringRight, SelectedRadList, A_GuiControl, 1    ;get which got pressed
  Loop, 2                                          ;deactivate the other
      If (A_Index <> SelectedRadList)
          GuiControl, 1:, RadList%A_Index%, 0
  Gui, 1:Submit, NoHide
  GoSub, GetDataForLargeList                       ;get data 
Return

GetDataForLargeList:
  If (RadList1 = 1){                   ;get data depending on choice
      WindowUniqueID = %EdtWindowUID%
      If EdtWindowUID is not space
          GoSub, GetControlListInfo
    }
  Else
      GoSub, GetAllWindowsInfo   
Return

RefreshControlStates:
  Gui, 1:Submit, NoHide                   ;get current values of all controls
  StringSplit, Dim, CbbColorPickDim, x    ;prepare color picker dimensions
  Dim = %Dim1%
  HalfDim := Dim // 2 + 1
  Loop, 15 {
      Row = %A_Index%
      Loop, 15
          GuiControl, 1:+BackgroundDefault ,PgbColorPicker%Row%_%A_Index%
    }
Return

ChkDrawRectCtrl:
  GuiControlGet, ChkDrawRectCtrl, 1:      ;get current value
  GoSub, PrepareFrameDraw
  ToolTip, , , , 2
Return

ChkDrawRectWin:
  GuiControlGet, ChkDrawRectWin, 1:       ;get current value
  GoSub, PrepareFrameDraw
  ToolTip, , , , 3
Return

;###############################################################################
;###   GUI actions   ###########################################################
;###############################################################################

GuiSize:
  If (A_EventInfo = 0) {   ;restored, or resized
      GuiControl, 1:Move, Tab1, h%A_GuiHeight% 
      w := A_GuiWidth - 290
      h := A_GuiHeight - 22
      GuiControl, 1:Move, LV1, w%w% h%h%
      h -= 143
      GuiControl, 1:Move, GrbAdvancedWindow, h%h%
      h := (h - 218) / 2
      GuiControl, 1:Move, EdtWindowTextFastVisible, h%h%
      GuiControl, 1:Move, EdtWindowTextFastHidden, h%h%
      y := A_GuiHeight - h - 24
      GuiControl, 1:Move, TxtWindowTextSlowVisible, y%y%
      GuiControl, 1:Move, TxtWindowTextSlowHidden, y%y%
      y += 15
      GuiControl, 1:Move, EdtWindowTextSlowVisible, y%y% h%h%
      GuiControl, 1:Move, EdtWindowTextSlowHidden, y%y% h%h%
      If (LastEventInfo = 1){    ;Gui got restored
          ;start updating again
          UpdateIsStopped := False
          ;reactivate frame
          GoSub, PrepareFrameDraw
        }
  }Else If (A_EventInfo = 1) {   ;minimized
      ;stop updating
      UpdateIsStopped := True
      ;remove frames
      GoSub, PrepareFrameDraw
    }
  LastEventInfo = %A_EventInfo%
Return

WriteIni:
  Gui, 1:Submit, NoHide
  WinGetPos, PosX, PosY, SizeW, SizeH, %WinNameGui1%
  Loop, 2
      If (RadList%A_Index% = 1)
          IniWrite, %A_Index%    , %IniFile%, Settings, SelectedRadList
  If (PosX > -4 and PosY > -4)
      IniWrite, x%PosX% y%PosY%      , %IniFile%, Settings, Gui1Pos
  IniWrite, %Gui1AOTState%       , %IniFile%, Settings, Gui1AOTState
  IniWrite, %Tab1%               , %IniFile%, Settings, Tab1
  IniWrite, %RadWindow%          , %IniFile%, Settings, RadWindow
  IniWrite, %RadControl%         , %IniFile%, Settings, RadControl
  IniWrite, %ChkShowList%        , %IniFile%, Settings, ChkShowList
  IniWrite, %HtkPauseAction%     , %IniFile%, Settings, HtkPauseAction
  IniWrite, %ChkCopyToCB%        , %IniFile%, Settings, ChkCopyToCB
  IniWrite, %ChkHideGui%         , %IniFile%, Settings, ChkHideGui
  IniWrite, %ChkUseSaveHotkey%   , %IniFile%, Settings, ChkUseSaveHotkey
  
  Loop, Parse, ExportOptions, `,
      IniWrite, % %A_LoopField%  , %IniFile%, Export  , %A_LoopField%
  IniWrite, %EdtExportFile%      , %IniFile%, Export  , EdtExportFile          
  IniWrite, %ChkExportAutoNumber%, %IniFile%, Export  , ChkExportAutoNumber
  IniWrite, %ChkExportAppend%    , %IniFile%, Export  , ChkExportAppend
  IniWrite, %ChkShowInfoToolTip% , %IniFile%, Advanced, ChkShowInfoToolTip  
  IniWrite, %ChkDrawRectCtrl%    , %IniFile%, Advanced, ChkDrawRectCtrl
  IniWrite, %ChkDrawRectWin%     , %IniFile%, Advanced, ChkDrawRectWin
  IniWrite, %ChkTtpMaster%       , %IniFile%, Advanced, ChkTtpMaster         
  IniWrite, %ChkTtpMSPos%        , %IniFile%, Advanced, ChkTtpMSPos         
  IniWrite, %ChkTtpMWPos%        , %IniFile%, Advanced, ChkTtpMWPos         
  IniWrite, %ChkTtpMColor%       , %IniFile%, Advanced, ChkTtpMColor        
  IniWrite, %ChkTtpCClass%       , %IniFile%, Advanced, ChkTtpCClass        
  IniWrite, %ChkTtpCPos%         , %IniFile%, Advanced, ChkTtpCPos          
  IniWrite, %ChkTtpCSize%        , %IniFile%, Advanced, ChkTtpCSize         
  IniWrite, %ChkTtpWClass%       , %IniFile%, Advanced, ChkTtpWClass        
  IniWrite, %ChkTtpWTitle%       , %IniFile%, Advanced, ChkTtpWTitle        
  IniWrite, %CbbUpdateInterval%  , %IniFile%, Advanced, CbbUpdateInterval   
  IniWrite, %CbbColorPickDim%    , %IniFile%, Advanced, CbbColorPickDim
  IniWrite, %RadColorPick%       , %IniFile%, Advanced, RadColorPick
  IniWrite, %ChkAutoStartUpdate% , %IniFile%, Advanced, ChkAutoStartUpdate
  IniWrite, %CbbHtkUpdate%       , %IniFile%, Advanced, CbbHtkUpdate
  IniWrite, %RadUpdateOnClick%   , %IniFile%, Advanced, RadUpdateOnClick
  IniWrite, %RadUpdateAuto%      , %IniFile%, Advanced, RadUpdateAuto
Return

GuiClose:
GuiEscape:
  GoSub, WriteIni
  ExitApp
Return

;###############################################################################
;###   GUI for information text   ##############################################
;###############################################################################

BtnShowInfo:
  GuiControl, 1:Disable, BtnShowInfo 
  Gui, 3:+Owner1 +AlwaysOnTop +ToolWindow +Resize
  Gui, 3:Font, s8, MS Sans Serif
  Gui, 3:Add, Button, gCloseInfoGui, Close
  Gui, 3:Add, Edit, w600 h400 vEdtInfoText, %InformationText%
  Gui, 3:Show,, Info - %ScriptName%
Return

3GuiClose:
3GuiEscape:
CloseInfoGui:
  GuiControl, 1:Enable, BtnShowInfo 
  Gui, 3:Destroy
Return

3GuiSize:
  w := A_GuiWidth - 20
  h := A_GuiHeight - 45
  GuiControl, 3:Move, EdtInfoText, w%w% h%h%
Return

;###############################################################################
;###   GUI for options   #######################################################
;###############################################################################

BtnShowOptions1:
  ChangeToTab = 1
  GoSub, BtnShowOptions
Return
BtnShowOptions2:
  ChangeToTab = 2
  GoSub, BtnShowOptions
Return
BtnShowOptions3:
  ChangeToTab = 3
  GoSub, BtnShowOptions
Return
BtnShowOptions:
  UpdateIsStopped := True
  Hotkey, IfWinNotActive, ahk_id %Gui1UniqueID%
  Hotkey, ~%CbbHtkUpdate%, Off
  Hotkey, IfWinNotActive
  
  Gui, 1:+Disabled
  Gui, 4:+Owner1 +AlwaysOnTop +ToolWindow
  Gui, 4:Font, s8, MS Sans Serif

  Gui, 4:Add, Tab, Section w300 h390 vTab2 AltSubmit -Wrap, Advanced|ToolTip|Log to File 
    Gui, 4:Tab, Advanced
      Gui, 4:Add, GroupBox, w275 h73, Update data
      Gui, 4:Add, Radio, xp+10 yp+22 Checked%RadUpdateOnClick% vRadUpdateOnClick gRadUpdate, on click with
      Gui, 4:Add, ComboBox, x+5 yp-3 w80 vCbbHtkUpdate, LButton|MButton||RButton
      Gui, 4:Add, Radio, x32 y+8 Checked%RadUpdateAuto% vRadUpdateAuto gRadUpdate, automatically every milliseconds:
      Gui, 4:Add, ComboBox, x+5 yp-3 w50 vCbbUpdateInterval, 100||200|300|400|500|1000|2000

      Gui, 4:Add, Checkbox, x22 y+20 vChkChangePauseHotkey gChkChangePauseHotkey, Change hotkey to toogle auto-update (default: Pause)
      Gui, 4:Add, Hotkey, xp+15 y+5 w150 vHtkPauseAction gHtkPauseAction Disabled, %HtkPauseAction%
    
      Gui, 4:Add, Checkbox, xp-15 y+5 vChkHideGui Checked%ChkHideGui%, Hide/Show GUI with above hotkey`;`nbefore the GUI is shown data will be collected  
      Gui, 4:Add, Checkbox, y+5 vChkAutoStartUpdate Checked%ChkAutoStartUpdate%, Start updating of data again when Gui gets inactive`nafter auto-update has been turned off. 
      Gui, 4:Add, Checkbox, y+5 vChkCopyToCB Checked%ChkCopyToCB%, Copy data to clipboard with left click on data field  

      Gui, 4:Add, Text, y+20, When update is turned off:
      Gui, 4:Add, Checkbox, vChkUseSaveHotkey Checked%ChkUseSaveHotkey%, Use Win+S as hotkey to log data to file
                                                         
      Gui, 4:Add, Checkbox, y+20 Section vChkShowInfoToolTip Checked%ChkShowInfoToolTip%, Show info-tooltips
    Gui, 4:Tab, ToolTip
      Gui, 4:Add, Text, , Check which data you want to see next to the mouse cursor
      Gui, 4:Add, Checkbox, vChkTtpMSPos Checked%ChkTtpMSPos%, Mouse position on screen *
      Gui, 4:Add, Checkbox, vChkTtpMWPos Checked%ChkTtpMWPos%, Mouse position on window
      Gui, 4:Add, Checkbox, vChkTtpMColor Checked%ChkTtpMColor%, Color under mouse pointer
      Gui, 4:Add, Checkbox, vChkTtpCClass Checked%ChkTtpCClass%, Control class under mouse pointer *
      Gui, 4:Add, Checkbox, vChkTtpCPos Checked%ChkTtpCPos%, Control position
      Gui, 4:Add, Checkbox, vChkTtpCSize Checked%ChkTtpCSize%, Control size
      Gui, 4:Add, Checkbox, vChkTtpWClass Checked%ChkTtpWClass%, Window class *                
      Gui, 4:Add, Checkbox, vChkTtpWTitle Checked%ChkTtpWTitle%, Window title *                         
      Gui, 4:Add, Text, , (* = available when Gui is hidden)
    Gui, 4:Tab, Log to File
      Gui, 4:Add, GroupBox, Section w274 h70 , Log this Mouse Data
        Gui, 4:Add, Checkbox, vChkExportMousePosScreen Checked%ChkExportMousePosScreen% xs+4 yp+18, Position on Screen 
        Gui, 4:Add, Checkbox, vChkExportMousePosAWin   Checked%ChkExportMousePosAWin%   xs+125 yp, Pos. rel. to active Window 
        Gui, 4:Add, Checkbox, vChkExportMousePosWin    Checked%ChkExportMousePosWin%    xs+4 y+5, Pos. rel. to Window 
        Gui, 4:Add, Checkbox, vChkExportMousePointer   Checked%ChkExportMousePointer%   xs+125 yp, Cursor Style 
        Gui, 4:Add, Checkbox, vChkExportMouseColorRGB  Checked%ChkExportMouseColorRGB%  xs+4 y+5, RGB Color 
        Gui, 4:Add, Checkbox, vChkExportMouseColorHex  Checked%ChkExportMouseColorHex%  xs+125 yp, Hex Color 
      Gui, 4:Add, GroupBox, xs w274 h75 , Log this Control Data 
        Gui, 4:Add, Checkbox, vChkExportCtrlText  Checked%ChkExportCtrlText%            xs+4 yp+18, Control Text 
        Gui, 4:Add, Checkbox, vChkExportCtrlClass Checked%ChkExportCtrlClass%           xs+125 yp, Control ClassNN 
        Gui, 4:Add, Checkbox, vChkExportCtrlPos   Checked%ChkExportCtrlPos%             xs+4 y+5, Control Position 
        Gui, 4:Add, Checkbox, vChkExportCtrlSize  Checked%ChkExportCtrlSize%            xs+125 yp, Control Size 
        Gui, 4:Add, Checkbox, vChkExportCtrlListItems  Checked%ChkExportCtrlListItems%  xs+4 y+5, Control List Items 
      Gui, 4:Add, GroupBox, xs w274 h110 , Log this Window Data 
        Gui, 4:Add, Checkbox, vChkExportWinTitle       Checked%ChkExportWinTitle%       xs+4 yp+18, Window Title 
        Gui, 4:Add, Checkbox, vChkExportWinPos         Checked%ChkExportWinPos%         xs+4 y+5, Window Position 
        Gui, 4:Add, Checkbox, vChkExportWinSize        Checked%ChkExportWinSize%        xs+125 yp, Window Size 
        Gui, 4:Add, Checkbox, vChkExportWinClass       Checked%ChkExportWinClass%       xs+4 y+5, Window Class 
        Gui, 4:Add, Checkbox, vChkExportWinProcess     Checked%ChkExportWinProcess%     xs+125 yp, Window Process 
        Gui, 4:Add, Checkbox, vChkExportWinUID         Checked%ChkExportWinUID%         xs+4 y+5, Window Unique ID 
        Gui, 4:Add, Checkbox, vChkExportWinPID         Checked%ChkExportWinPID%         xs+125 yp, Win Process ID 
        Gui, 4:Add, Checkbox, vChkExportWinStatusText  Checked%ChkExportWinStatusText%  xs+4 y+5, Statusbar Text 
        Gui, 4:Add, Checkbox, vChkExportWinText        Checked%ChkExportWinText%        xs+125 yp, Window Text 
    
      Gui, 4:Add, Checkbox, xs y+16 vChkExportLargeList  Checked%ChkExportLargeList%, Log Large List         Check:
    
      Gui, 4:Add, Button, x+2 yp-5 gBtnExportCheckAll, All 
      Gui, 4:Add, Button, x+2 gBtnExportCheckNone , None 
      Gui, 4:Add, Button, x+2 gBtnExportCheckReverse , Rev
    
      Gui, 4:Add, Text, xs y+5, Additional log options:
      Gui, 4:Add, Checkbox, y+5 Section vChkExportAutoNumber gChkExportAutoNumber Checked%ChkExportAutoNumber%, Replace "#" in filename with Numbers
      Gui, 4:Add, Checkbox, y+5 vChkExportAppend gChkExportAppend Checked%ChkExportAppend%, Append data to file
  Gui, 4:Tab

  Gui, 4:Add, Button, xm gApplyOptions, Apply Options
  Gui, 4:Add, Button, x+5 g4GuiClose, Cancel

  If RadUpdateOnClick {
      GuiControl, 4:Disable, ChkChangePauseHotkey
      GuiControl, 4:Disable, ChkHideGui
      GuiControl, 4:Disable, ChkAutoStartUpdate
    }
  GuiControl, 4:ChooseString, CbbHtkUpdate, %CbbHtkUpdate%
  GuiControl, 4:ChooseString, CbbUpdateInterval, %CbbUpdateInterval%
  GoSub, ChkExportAutoNumber
  GoSub, ChkExportAppend
  GuiControl, 4:Choose, Tab2, %ChangeToTab%

  Gui, 4:Show,, Options - %ScriptName%
Return

RadUpdate:
  If (A_GuiControl = "RadUpdateOnClick"){
      GuiControl, 4:, RadUpdateAuto, 0
      GuiControl, 4:, ChkChangePauseHotkey, 0
      GuiControl, 4:Disable, ChkChangePauseHotkey
      GuiControl, 4:Disable, HtkPauseAction
      GuiControl, 4:, ChkHideGui, 0
      GuiControl, 4:Disable, ChkHideGui
      GuiControl, 4:, ChkAutoStartUpdate, 0
      GuiControl, 4:Disable, ChkAutoStartUpdate
  }Else{
      GuiControl, 4:, RadUpdateOnClick, 0
      GuiControl, 4:Enable, ChkChangePauseHotkey
      GuiControl, 4:Enable, ChkHideGui
      GuiControl, 4:Enable, ChkAutoStartUpdate
      GuiControl, 4:, ChkAutoStartUpdate, 1
    }
Return

ApplyOptions:
  Gui, 4:Submit
  If ChkCopyToCB
      OnMessage( WM_LBUTTONDOWN, "WM_LBUTTONDOWN" )   ;activate copy-on-click
  Else
      OnMessage( WM_LBUTTONDOWN, "" )                 ;deactivate copy-on-click
  If ChkAutoStartUpdate
      OnMessage(WM_ACTIVATE, "WM_ACTIVATE")       ;activate auto-start updating at Gui inactivity
  Else
      OnMessage(WM_ACTIVATE, "" )                 ;deactivate auto-start updating
  If RadUpdateAuto {
      SetTimer, UpdateInfo, %CbbUpdateInterval%
  }Else{
      SetTimer, UpdateInfo, Off
      Hotkey, IfWinNotActive, ahk_id %Gui1UniqueID%
      Hotkey, ~%CbbHtkUpdate%, UpdateOnClick, On
      Hotkey, IfWinNotActive
    }
  GoSub, PauseAction  
4GuiClose:
4GuiEscape:
  UpdateIsStopped := False
  Gui, 1:-Disabled
  Gui, 4:Destroy
Return

ChkChangePauseHotkey:
  GuiControlGet, ChkChangePauseHotkey, 4:      ;get current value
  If ChkChangePauseHotkey {
      ;de-activate current auto-update toggle hotkey
      HotKey, %HtkPauseAction%, Off
      GuiControl, 4:Enable, HtkPauseAction
  }Else
      GoSub, HtkPauseAction
Return

HtkPauseAction:
  GuiControlGet, HtkPauseAction, 4:      ;get current value
  If HtkPauseAction {
      If HtkPauseAction in ^,+,!         ;don't react on simple modifiers
          return
      ;activate new auto-update toggle hotkey
      HotKey, %HtkPauseAction%, PauseAction, On
      GuiControl, 4:Disable, HtkPauseAction
      GuiControl, 4:, ChkChangePauseHotkey, 0
  }Else{
      GuiControl, 4:, ChkChangePauseHotkey, 1
      GuiControl, 4:Enable, HtkPauseAction
      ToolTip("You need to specify a hotkey", 2000)          
    }
Return

BtnExportCheckAll:
  Loop, Parse, ExportOptions, `,
      GuiControl, 4:, %A_LoopField%, 1
Return
BtnExportCheckNone:
  Loop, Parse, ExportOptions, `,
      GuiControl, 4:, %A_LoopField%, 0
Return
BtnExportCheckReverse:
  Gui, 1:Submit, NoHide
  Loop, Parse, ExportOptions, `,
      GuiControl, 4:, %A_LoopField%, % not %A_LoopField%
Return
ChkExportAutoNumber:
  Gui, 4:Submit, NoHide
  If ChkExportAutoNumber
      GuiControl, 4:Disable, ChkExportAppend
  Else
      GuiControl, 4:Enable, ChkExportAppend   
Return
ChkExportAppend:
  Gui, 4:Submit, NoHide
  If ChkExportAppend
      GuiControl, 4:Disable, ChkExportAutoNumber
  Else
      GuiControl, 4:Enable, ChkExportAutoNumber   
Return

;###############################################################################
;###   getting the data    #####################################################
;###############################################################################

UpdateInfo:
  If UpdateIsStopped
      Return
  
  If (WinActive("A") = Gui1UniqueID )    ;don't update when window becomes the active one
      Return
 
  If (Tab1 > 3 )    ;don't update when tab 4 or tab 5 are visible
      Return
      
  SetBatchLines, -1
  
  ;get mouse pos and make sure mouse is not on frames or tooltips or on it's own gui
  MouseIsOnFrameGUI := False
  GoSub, CheckForFramesAndTipsAndGetMousePos
  If MouseIsOnFrameGUI
      Return
  
  GoSub, SetWhichWindow
  GoSub, SetWhichControl

  If (ChkHideGui And ChkTtpMaster And !GuiIsVisible)   ;update only small info when gui is hidden if tool tips are wanted
      GoSub, UpdateMinimumInfo
  Else If (!ChkHideGui Or UpdateAfterPause) ;update only when gui not set to HideGui or if Pause is release and one update is needed
      GoSub, UpdateAllInfo

  ;draw frames if wanted
  If ( ( ChkDrawRectCtrl OR ChkDrawRectWin )                           ;user wants to see at least one of the frames
     AND PreviousControlID <> ControlID                                ;the control has changed
     AND StatusDrawFrame ){                                             ;AND the Mouse is not on the active window which should be drawn 
      If not FrameGUIExists         ;create frame gui if it had been destroyed, e.g. by viewing the large list
          GoSub, PrepareFrameDraw
      DrawFrameAroundControl(ControlID, WindowUniqueID, frame_t)
     } 
  ;memorize IDs
  PreviousControlID = %ControlID%
  PreviousWindowID = %WindowID%

  If UpdateIsStopped {         ;when update stopped within this run, behave as if toggle hotkey was pressed 
      GoSub, ToogleExportActions      
      GoSub, PrepareFrameDraw  ;create or destroy frame drawing objects
      GoSub, GuiShow
    }
Return

;check if frames or tool tips are under mouse pointer
CheckForFramesAndTipsAndGetMousePos:
  ;get mouse positions relative to screen
  CoordMode, Mouse, Screen  
  MouseGetPos, MouseScreenX, MouseScreenY, MouseWindowUID, MouseControlID  
  WinGetClass, WindowClass, ahk_id %MouseWindowUID%
  WinGetTitle, WindowTitle, ahk_id %MouseWindowUID% 
  If ( MouseWindowUID = UniqueIDGui2                    ;if window is frame gui
       OR  MouseWindowUID = Gui1UniqueID                ;or real gui
       OR (WindowClass = "tooltips_class32"                ;or window is tooltip
           AND ( WindowTitle = PreviousControlID               ;and has the title of the last control
                 OR WindowTitle = PreviousWindowID                 ;or has the title of the last window
                 OR InStr(WindowTitle,Scriptname)) ) ) ;{          ;or has a title that contains the script name, then it might be one of the info tooltips   
      MouseIsOnFrameGUI := True
  If (MouseIsOnFrameGUI AND WindowTitle = PreviousControlID) ;remove control frame tooltip if mouse is on it, to be able to see screen below
      ToolTip, , , , 2               
Return

;set UID of window for which the following data should be retrieved
SetWhichWindow:
  StatusDrawFrame := True
  If (RadWindow = 1){                      ;for active window
      WinGet, WindowUniqueID, ID, A
      If (WindowUniqueID <> MouseWindowUID)  ;mouse is not in active window, don't redraw frames
          StatusDrawFrame := False
  }Else                                    ;for window under mouse pointer
      WindowUniqueID = %MouseWindowUID%
Return
 
;set control ID for which the data should be retrieved 
SetWhichControl:
  If (RadControl = 1)        ;for active control
      ControlGetFocus, ControlID, ahk_id %WindowUniqueID%
  Else                       ;for control under mouse pointer
      ControlID = %MouseControlID%
Return

UpdateMinimumInfo:
  ;optional tooltip
  If ChkTtpMaster {
      InfoString := iif(ChkTtpMSPos,"MScreen: " MouseScreenX "," MouseScreenY "`n")
                  . iif(ChkTtpCClass,"Control ClassNN: " MouseControlID "`n")
                  . iif(ChkTtpWClass,"Window Class: " WindowClass "`n")
                  . iif(ChkTtpWTitle,"Window Title: " WindowTitle "`n")
      StringTrimRight, InfoString, InfoString, 1    ;remove last `n
      If InfoString
          ToolTip(Scriptname "`n----------------------------`n" InfoString)
    }
Return

UpdateAllInfo:
  ;ToolTip, UpdateAllInfo - %A_Now%   ;??? for debug
  
  GoSub, GetMouseInfo
  GoSub, GetControlInfo

  ;optional tooltip
  If ChkTtpMaster {
      InfoString := iif(ChkTtpMSPos,"MScreen: " MouseScreenX "," MouseScreenY "`n")
                    . iif(ChkTtpMWPos,"MWindow: " MouseWindowX "," MouseWindowY "`n")
                    . iif(ChkTtpMColor,"MColor: " MouseColorRGB "`n")
                    . iif(ChkTtpCClass,"Control ClassNN: " MouseControlID "`n")
                    . iif(ChkTtpCPos,"Control Pos: " ControlX "," ControlY "`n")
                    . iif(ChkTtpCSize,"Control Size: " ControlWidth "," ControlHeight "`n")
                    . iif(ChkTtpWClass,"Window Class: " WindowClass "`n")
                    . iif(ChkTtpWTitle,"Window Title: " WindowTitle "`n")
        StringTrimRight, InfoString, InfoString, 1    ;remove last `n
        If InfoString
            ToolTip(Scriptname "`n----------------------------`n" InfoString)
    }
    
  GoSub, GetWindowInfo
  If (Tab1 = 2) ;get window text only when advanced tab is active
      GoSub, GetWindowText
  
  If ChkShowList {                        ;if large list is shown
      If RadList1 = 1               ;get data depending on choice
          GoSub, GetControlListInfo
      Else
          GoSub, GetAllWindowsInfo

      UpdateIsStopped := True                  ;give feedback and stop updating
      If ChkShowInfoToolTip
          ToolTip("Stopped to update data to allow working with "
                  . iif(SelectedRadList = 1,"list of controls")
                  . iif(SelectedRadList = 2,"list of windows")
                  . "`nPress Pause key to create a new snapshot", 2000)
    }
Return

GetMouseInfo:
  ;get mouse pos relative to windows
  WinGetPos, WindowActiveX, WindowActiveY,,, A
  WinGetPos, WindowX, WindowY,,, ahk_id %MouseWindowUID%
  MouseWindowActiveX := MouseScreenX - WindowActiveX
  MouseWindowActiveY := MouseScreenY - WindowActiveY
  MouseWindowX := MouseScreenX - WindowX
  MouseWindowY := MouseScreenY - WindowY
  GuiControl, 1:, EdtMousePosScreen, x%MouseScreenX% y%MouseScreenY%
  GuiControl, 1:, EdtMousePosWin, x%MouseWindowX% y%MouseWindowY%
  GuiControl, 1:, EdtEasyMousePosWin, x%MouseWindowX% y%MouseWindowY%
  GuiControl, 1:, EdtDataMousePosWin, x%MouseWindowX% y%MouseWindowY%
  GuiControl, 1:, EdtMousePosAWin, x%MouseWindowActiveX% y%MouseWindowActiveY%

  ;get pointer shape
  GuiControl, 1:, EdtMousePointer, %A_Cursor%
  
  ;get color below mouse pointer
  CoordMode, Pixel, Screen 
  PixelGetColor, MouseColorRGB, %MouseScreenX%, %MouseScreenY%, RGB
  StringMid, MouseColorR, MouseColorRGB, 3, 2
  StringMid, MouseColorG, MouseColorRGB, 5, 2
  StringMid, MouseColorB, MouseColorRGB, 7, 2
  GuiControl, 1:, EdtMouseColorRGB, % "R" HEXtoDEC(MouseColorR) " G" HEXtoDEC(MouseColorG)" B" HEXtoDEC(MouseColorB)
  GuiControl, 1:, EdtMouseColorHex, %MouseColorRGB%

  If (Tab1 = 3) {      ;Only update color picker when mouse tab is active 
      If ( MouseScreenX MouseScreenY <> OldPosition or MouseColorRGB <> OldMouseColorRGB){    ;only update color picker when mouse moves or color changes
          x := MouseScreenX - HalfDim
          Loop, %Dim% {
              x++
              Row := A_Index + 8 - HalfDim
              y := MouseScreenY - HalfDim
              Loop, %Dim% {
                  y++
                  PixelGetColor, ColorRGB, %x%, %y%, % iif(RadColorPick = 1, "RGB")
                  StringTrimLeft, ColorRGB, ColorRGB, 2
                  Control := "PgbColorPicker" (A_Index + 8 - HalfDim) "_" Row 
                  %Control% = %ColorRGB%  
                  If RadColorPick = 2
                      PixelGetColor, ColorRGB, %x%, %y%, RGB
                  GuiControl, 1:+Background%ColorRGB%,%Control% 
                }
            }
        }
      OldPosition = %MouseScreenX%%MouseScreenY%
      OldMouseColorRGB = %MouseColorRGB%
    }
Return

GetControlInfo:
  GuiControl, 1:, EdtControlClass, %ControlID%
  GuiControl, 1:, EdtEasyControlClass, %ControlID%

  ;get Pos, Size, Text
  ControlGetPos, ControlX, ControlY, ControlWidth, ControlHeight, %ControlID%, ahk_id %WindowUniqueID%
  GuiControl, 1:, EdtControlPos, x%ControlX% y%ControlY%
  GuiControl, 1:, EdtControlSize, w%ControlWidth% h%ControlHeight%

  ControlGet, ControlHwnd, Hwnd,, %ControlID%, ahk_id %WindowUniqueID%
  GuiControl, 1:, EdtControlHwnd, %ControlHwnd%

;Chris suggests to avoid any call to ControlGetText or WinGetText because they force the OS to copy an
; unlimited amount of text across process boundaries. This text could be several megabytes or more if
; someone has a big text file or Word document open. Instead use WM_GETTEXT.
;   ControlGetText, ControlText, %ControlID%, ahk_id %WindowUniqueID%
  MouseGetPos,,,,ControlHWND, 2
  SendMessage, 0xD, ControlTextSize, &ControlText,, ahk_id %ControlHWND%  ; 0xD is WM_GETTEXT.
  EdtControlTextFull := ShowOnlyAPartInGui("EdtControlText", ControlText, 100)
  EdtEasyControlTextFull := ShowOnlyAPartInGui("EdtEasyControlText", ControlText, 100)

  If (Tab1 = 2) { ;get control list data only when advanced tab is active
      ControlGet, ControlListItems, List, , %ControlID%, ahk_id %WindowUniqueID%
      EdtListItemsFull := ShowOnlyAPartInGui("EdtListItems", ControlListItems, 200)
    }
Return

GetWindowInfo:
  ;get Title, Pos, Size, PID, Process, Class
  WinGetTitle, WindowTitle, ahk_id %WindowUniqueID% 
  WinGetPos, WindowX, WindowY, WindowWidth, WindowHeight, ahk_id %WindowUniqueID%
  WinGet, WindowPID, PID, ahk_id %WindowUniqueID% 
  WinGet, WindowProcessName, ProcessName, ahk_pid %WindowPID%
  WinGetClass, WindowClass, ahk_id %WindowUniqueID%
  GuiControl, 1:, EdtWindowTitle, %WindowTitle%
  GuiControl, 1:, EdtEasyWindowTitle, %WindowTitle%
  GuiControl, 1:, EdtWindowPos, x%WindowX% y%WindowY%
  GuiControl, 1:, EdtWindowSize, w%WindowWidth% h%WindowHeight%
  GuiControl, 1:, EdtWindowClass, %WindowClass%
  GuiControl, 1:, EdtEasyWindowClass, %WindowClass%
  GuiControl, 1:, EdtWindowProcess, %WindowProcessName%
  GuiControl, 1:, EdtWindowUID, %WindowUniqueID%
  GuiControl, 1:, EdtWindowPID, %WindowPID%

  If (Tab1 = 2) { ;get advanced window data only when advanced tab is active
      ;get and set statusbartext (maximum 10)
      ListOfStatusbarText = 
      Loop, 10 { 
          StatusBarGetText, StatusBarText, %A_Index%, ahk_id %WindowUniqueID%
          If StatusBarText
              ListOfStatusbarText = %ListOfStatusbarText%%A_Index% - %StatusBarText%|
        }
      If ListOfStatusbarText is space
          ListOfStatusbarText = No text found in statusbar
      GuiControl, 1:, LsbStatusbarText, |%ListOfStatusbarText%
    }
Return

GetWindowText:
  EdtWindowTextFastVisible =
  EdtWindowTextSlowVisible =
  EdtWindowTextFastHidden =
  EdtWindowTextSlowHidden =
  
  ;Suggested by Chris
  WinGet, ListOfControlHandles, ControlListHwnd, ahk_id %WindowUniqueID%  ; Requires v1.0.43.06+.
  Loop, Parse, ListOfControlHandles, `n
    {
    	text_is_fast := true
      If not DllCall("GetWindowText", "uint", A_LoopField, "str", WindowControlText, "int", WindowControlTextSize){
      		text_is_fast := false
       		SendMessage, 0xD, WindowControlTextSize, &WindowControlText,, ahk_id %A_LoopField%  ; 0xD is WM_GETTEXT
      	}
    	If (WindowControlText <> ""){
      		ControlGet, WindowControlStyle, Style,,, ahk_id %A_LoopField%
      		If (WindowControlStyle & 0x10000000){  ; Control is visible vs. hidden (WS_VISIBLE).
        			If text_is_fast
        				EdtWindowTextFastVisible = %EdtWindowTextFastVisible%%WindowControlText%`r`n
        			Else
        				EdtWindowTextSlowVisible = %EdtWindowTextSlowVisible%%WindowControlText%`r`n
      		}Else{  ; Hidden text.
        			If text_is_fast
        				EdtWindowTextFastHidden = %EdtWindowTextFastHidden%%WindowControlText%`r`n
        			Else
        				EdtWindowTextSlowHidden = %EdtWindowTextSlowHidden%%WindowControlText%`r`n
        		}
      	}
  }

  EdtWindowTextFastVisibleFull := ShowOnlyAPartInGui("EdtWindowTextFastVisible", EdtWindowTextFastVisible, 400)
  EdtWindowTextSlowVisibleFull := ShowOnlyAPartInGui("EdtWindowTextSlowVisible", EdtWindowTextSlowVisible, 400)
  EdtWindowTextFastHiddenFull := ShowOnlyAPartInGui("EdtWindowTextFastHidden", EdtWindowTextFastHidden, 400)
  EdtWindowTextSlowHiddenFull := ShowOnlyAPartInGui("EdtWindowTextSlowHidden", EdtWindowTextSlowHidden, 400)
Return

ShowOnlyAPartInGui(Control, FullContent, Limit=200){
    Content = %FullContent%
    If (StrLen(Content) > Limit){         ;limits the control text in the GUI. An unlimited length caused on some PCs 100% CPU load
        StringLeft, Content, Content, %Limit%
        Content = %Content% ...
      }
    GuiControl, 1:, %Control%, %Content%
    Return FullContent
  }

GetControlListInfo:
  ;get list of controls in z order
  WinGet, ControlList, ControlList, ahk_id %WindowUniqueID%
  
  ;get all data for these controls
  Loop, Parse, ControlList, `n
    {
      ControlID0 = %A_Index%
      ControlID = %A_LoopField%
      ControlID%A_Index% = %ControlID%
      ControlGetPos, ControlX%A_Index%, ControlY%A_Index%, ControlWidth%A_Index%, ControlHeight%A_Index%, %ControlID%, ahk_id %WindowUniqueID%
      ControlGet, ControlHwnd%A_Index%, Hwnd,, %ControlID%, ahk_id %WindowUniqueID%
      ControlGetText, ControlText%A_Index%, %ControlID%, ahk_id %WindowUniqueID%
      ControlGet, ControlChecked%A_Index%, Checked, , %ControlID%, ahk_id %WindowUniqueID%
      ControlGet, ControlEnabled%A_Index%, Enabled, , %ControlID%, ahk_id %WindowUniqueID%
      ControlGet, ControlVisible%A_Index%, Visible, , %ControlID%, ahk_id %WindowUniqueID%
      ControlGet, ControlTab%A_Index%, Tab, , %ControlID%, ahk_id %WindowUniqueID%
      ControlGet, ControlChoice%A_Index%, Choice, , %ControlID%, ahk_id %WindowUniqueID%
      ControlGet, ControlLineCount%A_Index%, LineCount, , %ControlID%, ahk_id %WindowUniqueID%
      ControlGet, ControlCurrentLine%A_Index%, CurrentLine, , %ControlID%, ahk_id %WindowUniqueID%
      ControlGet, ControlCurrentCol%A_Index%, CurrentCol, , %ControlID%, ahk_id %WindowUniqueID%
      ControlGet, ControlSelected%A_Index%, Selected, , %ControlID%, ahk_id %WindowUniqueID%
      ControlGet, ControlStyle%A_Index%, Style, , %ControlID%, ahk_id %WindowUniqueID%
      ControlGet, ControlExStyle%A_Index%, ExStyle, , %ControlID%, ahk_id %WindowUniqueID%
    }

  ;add all data to listview
  GuiControl, -Redraw, LV1          ; speed up adding data
  LV_Delete()                       ; remove old data
  Loop, %ControlID0% {
      LV_Add(""
        , A_Index                     ; Z or Stack Order
        , ControlHwnd%A_Index%          ; Unique ID
        , ""                          ; Window PID
        , ControlID%A_Index%          ; Window Class
        , ""                          ; Window Process Name
        , ControlVisible%A_Index%     ; Visible or Hidden?
        , ControlText%A_Index%        ; Title or Text
        , ControlX%A_Index%           ; X
        , ControlY%A_Index%           ; Y
        , ControlWidth%A_Index%       ; Width
        , ControlHeight%A_Index%      ; Height
        , ControlStyle%A_Index%       ; Style
        , ControlExStyle%A_Index%     ; ExStyle
        , ControlSelected%A_Index%    ; Selected
        , ControlCurrentCol%A_Index%  ; CurrentCol
        , ControlCurrentLine%A_Index% ; CurrentLine
        , ControlLineCount%A_Index%   ; LineCount
        , ControlChoice%A_Index%      ; Choice
        , ControlTab%A_Index%         ; Tab
        , ControlEnabled%A_Index%     ; Enabled
        , ControlChecked%A_Index%)    ; Checked
    }   
  LV_ModifyCol()                    ; Auto-size all columns 
  LV_ModifyCol(1, "Integer Left")   ; column Z Order 
  LV_ModifyCol(3, 0)                ; hide column Window PID 
  LV_ModifyCol(5, 0)                ; hide column Window Process Name 
  LV_ModifyCol(7, "150")            ; column Text 
  GuiControl, +Redraw, LV1
Return

GetAllWindowsInfo:
  ;get list of all visible windows in stack order
  DetectHiddenWindows, Off 
  WinGet, WinIDs, List 
  Loop, %WinIDs% 
      winListIDsVisible := winListIDsVisible WinIDs%A_Index% "`n" 
  
  ;get list of all windows in stack order
  DetectHiddenWindows, On 
  WinGet, WinIDs, List 

  ;get all data for all windows
  Loop, %WinIDs% {
      UniqueID := "ahk_id " WinIDs%A_Index% 
      WinGetPos, WindowX%A_Index%, WindowY%A_Index%, WindowWidth%A_Index%, WindowHeight%A_Index%, %UniqueID%
      WinGet, winPID%A_Index%, PID, %UniqueID% 
      WinGet, processName%A_Index%, ProcessName, % "ahk_pid " winPID%A_Index%
      WinGetTitle, winTitle%A_Index%, %UniqueID%   
      WinGetClass, winClass%A_Index%, %UniqueID%
    } 
  DetectHiddenWindows, off
  
  ;add all data to listview
  GuiControl, -Redraw, LV1          ; speed up adding data
  LV_Delete()                       ; remove old data
  Loop, %WinIDs% {
      LV_Add(""
        , A_Index                   ; Z or Stack Order
        , WinIDs%A_Index%           ; Unique ID
        , winPID%A_Index%           ; Window PID
        , winClass%A_Index%         ; Window Class
        , processName%A_Index%      ; Process Name
        , iif(InStr(winListIDsVisible,WinIDs%A_Index%),"","Hidden")  ; Visible or Hidden?
        , winTitle%A_Index%         ; Title or Text
        , WindowX%A_Index%          ; X
        , WindowY%A_Index%          ; Y
        , WindowWidth%A_Index%      ; Width
        , WindowHeight%A_Index%)    ; Height
    }   
  LV_ModifyCol()                    ; Auto-size all columns 
  LV_ModifyCol(1, "Integer Left")   ; column Stack Order 
  LV_ModifyCol(4, "100")            ; column Class
  LV_ModifyCol(7, "150")            ; column Title
  GuiControl, +Redraw, LV1
Return

;draw frames around controls and/or windows
DrawFrameAroundControl(ControlID, WindowUniqueID, frame_t){
    global h_brushC, h_brushW, ChkDrawRectCtrl, ChkDrawRectWin
    
    ;get coordinates of Window and control again
    ;(could have been past into the function but it seemed too much parameters)
    WinGetPos, WindowX, WindowY, WindowWidth, WindowHeight, ahk_id %WindowUniqueID%
    ControlGetPos, ControlX, ControlY, ControlWidth, ControlHeight, %ControlID%, ahk_id %WindowUniqueID%
    
    ;find upper left corner relative to screen
    StartX := WindowX + ControlX 
    StartY := WindowY + ControlY 
      
    ;show ID in upper left corner
    CoordMode, ToolTip, Screen
    
    ;show frame gui above AOT apps
    Gui, 2: +AlwaysOnTop
    
    If ChkDrawRectWin {
        ;if windows upper left corner is outside the screen
        ; it is assumed that the window is maximized and the frame is made smaller
        If ( WindowX < 0 AND WindowY < 0 ){
            WindowX += 4
            WindowY += 4
            WindowWidth -= 8
            WindowHeight -= 8
          }

        ;remove old rectangle from screen and save/buffer screen below new rectangle
        BufferAndRestoreRegion( WindowX, WindowY, WindowWidth, WindowHeight ) 

        ;draw rectangle frame around window
        DrawFrame( WindowX, WindowY, WindowWidth, WindowHeight, frame_t, h_brushW )

        ;show tooltip above window frame when enough space
        If ( WindowY > 22)
            WindowY -= 22

        ;Show tooltip with windows unique ID 
        ToolTip, %WindowUniqueID%, WindowX, WindowY, 3
      }
    Else
        ;remove old rectangle from screen and save/buffer screen below new rectangle
        BufferAndRestoreRegion( StartX, StartY, ControlWidth, ControlHeight )             

    If ChkDrawRectCtrl {
        ;draw rectangle frame around control
        DrawFrame( StartX, StartY, ControlWidth, ControlHeight, frame_t, h_brushC )

        ;show tooltip above control frame when enough space, or below
        If ( StartY > 22)
            StartY -= 22
        Else 
            StartY += ControlHeight
        
        ;show control tooltip left of window tooltip if position identical (e.g. Windows Start Button on Taskbar) 
        If (StartY = WindowY
            AND StartX < WindowX + 50)
            StartX += 50
                        
        ;Show tooltip with controls unique ID 
        ToolTip, %ControlID%, StartX, StartY, 2
      }
    ;set back ToolTip position to default
    CoordMode, ToolTip, Relative
  }

;###############################################################################
;###   export the data    ######################################################
;###############################################################################

BtnBrowseExportFile:
  Gui, 1:Submit, NoHide
  SelectFile("EdtExportFile", EdtExportFile, "email")
Return

BtnSaveExport:
  Gui, 1:Submit, NoHide

  ;return if no filename is given
  If EdtExportFile is space
    {
      ToolTip("No filename for export specified.", 3000)
      MsgBox, 48, Problem , No export filename is given.
      Return
    }

  ;return if no data is selected for export
  NumberOfExports = 0
  Loop, Parse, ExportOptions, `,
      NumberOfExports := NumberOfExports + %A_LoopField%
  If (NumberOfExports = 0){
      ToolTip("No data selected for export.", 3000)
      Return
    }

  ;get filename
  If (ChkExportAutoNumber){
      FileNameForExport := GetAvailableFileName(EdtExportFile)
      If not FileNameForExport {
          ToolTip("Could get filename for export.`n" ErrorLevel, 3000)
          Return
        }
  }Else
      FileNameForExport = %EdtExportFile%
       
  GuiControl, 1:Disable, BtnSaveExport
  GoSub, ExportDataToFile
  GuiControl, 1:Enable, BtnSaveExport
  If ChkShowInfoToolTip
      ToolTip("Data exported to file: " FileNameForExport, 3000) 
Return

ExportDataToFile: 
  If ChkExportAppend
      FileAppend, `n===========next snapshot===========`n, %FileNameForExport% 
  Else 
      FileDelete, %FileNameForExport%
      
  ExportString := "Data exported from " ScriptName " at " A_Now "`n`nMouse Data`n" 
               . iif(ChkExportMousePosScreen,"Mouse position relative to Screen :`n" EdtMousePosScreen "`n`n")
               . iif(ChkExportMousePosWin,"Mouse position relative to window under mouse pointer :`n" EdtMousePosWin "`n`n")
               . iif(ChkExportMousePosAWin,"Mouse position relative to active window :`n" EdtMousePosAWin "`n`n")
               . iif(ChkExportMousePointer,"Mouse cursor style :`n" EdtMousepointer "`n`n")
               . iif(ChkExportMouseColorRGB,"Pixel Color in RGB format under mouse pointer :`n" EdtMouseColorRGB "`n`n")
               . iif(ChkExportMouseColorHex,"Pixel Color in Hex format (RGB) mouse pointer :`n" EdtMouseColorHex "`n`n")
               . "`nControl data for "
               . iif(RadControl = 1,"active control of " iif(RadWindow = 1,"active window","window under mouse pointer") ,"control under mouse pointer")
               . "`n"
               . iif(ChkExportCtrlText,"Control text :`n" EdtControlText "`n`n")
               . iif(ChkExportCtrlClass,"Control classNN :`n" EdtControlClass "`n`n")
               . iif(ChkExportCtrlPos,"Control position :`n" EdtControlPos "`n`n")
               . iif(ChkExportCtrlSize,"Control size :`n" EdtControlSize "`n`n")
               . iif(ChkExportCtrlListItems,"Control list items :`n" EdtListItems "`n`n")
               . "`nWindow data for "
               . iif(RadWindow = 1,"active window","window under mouse pointer")
               . "`n"
               . iif(ChkExportWinTitle,"Window title :`n" EdtWindowTitle "`n`n")
               . iif(ChkExportWinPos,"Window position :`n" EdtWindowPos "`n`n")
               . iif(ChkExportWinSize,"Window size :`n" EdtWindowSize "`n`n")
               . iif(ChkExportWinClass,"Window class :`n" EdtWindowClass "`n`n")
               . iif(ChkExportWinProcess,"Window process name:`n" EdtWindowprocess "`n`n")
               . iif(ChkExportWinUID,"Window unique ID :`n" EdtWindowUID "`n`n")
               . iif(ChkExportWinPID,"Window PID :`n" EdtWindowPID "`n`n")
  FileAppend, %ExportString%, %FileNameForExport% 

  ExportString =
  If ChkExportWinStatusText {
      StringReplace, StatusbarText, ListOfStatusbarText, |, `n, All
      ExportString = `n######## Window Statusbar Text (Part# - Text) :`n%StatusbarText%`n`n
    } 
  If ChkExportWinText
      ExportString := ExportString 
               . iif(EdtWindowTextFastVisible,"`n######## Fast Visible Window Text :`n" EdtWindowTextFastVisible "`n`n")
               . iif(EdtWindowTextSlowVisible,"`n######## Slow Visible Window Text :`n" EdtWindowTextSlowVisible "`n`n")
               . iif(EdtWindowTextFastHidden,"`n######## Fast Hidden Window Text :`n" EdtWindowTextFastHidden "`n`n")
               . iif(EdtWindowTextSlowHidden,"`n######## Slow Hidden Window Text :`n" EdtWindowTextSlowHidden "`n`n")
  FileAppend, %ExportString%, %FileNameForExport% 

  If ChkExportLargeList {
      If LV_GetCount() {
          ExportString := "`n########"
                          . iif(RadList3,"Data of all controls of the " iif(RadWindow = 1,"active window","window under the mousepointer") ,"Data of all windows")
          ExportString = %ExportString% :`n
             (LTrim Join`s
                ######## Z or Stack Order, Unique ID, Window PID, Window Class,
                Process Name, Hidden, Title or Text, X, Y, Width, Height, Style,
                ExStyle, Selected, CurrentCol, CurrentLine, LineCount, Choice,
                Tab, Enabled, Checked
                
             )
          Columns := LV_GetCount("Col")
          Loop, % LV_GetCount() {
              Row = %A_Index%
              Loop %Columns% {
                  LV_GetText(Text, Row , A_Index)
                  ExportString = %ExportString%%Text%, 
                } 
              StringTrimRight,ExportString,ExportString,1  ;remove last comma 
              ExportString = %ExportString%`n              ;start new line
            } 
        }  
      If ExportString
          FileAppend, %ExportString%, %FileNameForExport% 
    } 
Return

;###############################################################################
;###   small helper functions   ################################################
;###############################################################################

iif(expr, a, b=""){
    If expr
        Return a
    Return b
  }

ToggleOnTopGui1(wParam, lParam, msg, hwnd) {
    Global Gui1UniqueID, Gui1AOTState

    WinGetTitle, CurrentTitle , ahk_id %Gui1UniqueID%
    If (Gui1AOTState){
        Gui, 1: -AlwaysOnTop
        StringTrimRight, CurrentTitle, CurrentTitle, 8
        WinSetTitle, ahk_id %Gui1UniqueID%, , %CurrentTitle%
    }Else { 
        Gui, 1: +AlwaysOnTop
        WinSetTitle, ahk_id %Gui1UniqueID%, , %CurrentTitle% - *AOT* 
      }
    Gui1AOTState := not Gui1AOTState
  }

ToolTip(Text, TimeOut=1000){
    ToolTip, %Text%
    SetTimer, RemoveToolTip, %TimeOut%
    Return
  }
RemoveToolTip:
   ToolTip
Return

HEXtoDEC(HEX){ 
    StringUpper, HEX, HEX 
    Loop, % StrLen(HEX) { 
        StringMid, Col, HEX, % (StrLen(HEX) + 1) - A_Index, 1 
        If Col is integer 
            DEC1 := Col * 16 ** (A_Index - 1) 
        Else 
            DEC1 := (Asc(Col) - 55) * 16 ** (A_Index - 1) 
        DEC += %DEC1% 
      } 
    return DEC 
  }

SelectFile(Control, OldFile, Text){
    Gui, 1:+OwnDialogs
    StringReplace, OutputVar, OldFile, #, *, All
    IfExist %A_ScriptDir%\%OutputVar%
        StartFolder = %A_ScriptDir%
    Else IfExist %OldFile%
        SplitPath, OldFile, , StartFolder
    Else 
        StartFolder = 
    FileSelectFile, SelectedFile, S18, %StartFolder%, Select file for %Text%, Text file (*.txt)
    If SelectedFile {
        StringReplace, SelectedFile, SelectedFile, %A_ScriptDir%\
        GuiControl, 1: ,%Control%, %SelectedFile%
      }
  }

CheckAHKVersion(AHK_version){
    StringSplit, A, A_AHKVERSION, . 
    StringSplit, B, AHK_version, .
    Ax = 0
    Bx = 0
    Loop, %A0%{      ; create unique number for both versions, max. verion 999.999.999.999 leads to 999999999999 
        Ax := Ax + A%A_Index% * 1000 ** ( A0 - A_Index ) 
        Bx := Bx + B%A_Index% * 1000 ** ( A0 - A_Index ) 
      } 
    If ( Bx > Ax ) { 
        msgbox, 16, Old AHK version,
          (LTrim
            This script requires a newer version of AHK.
            Installed version = %A_AHKVERSION%
            Required version = %AHK_version%
            
            Please download latest version and install it.
            This Program will exit and open the webpage
            where you can download the latest AHK version.
          )
        run, http://www.autohotkey.com/download
        ExitApp 
      } 
  }

;#############   Get next free/available File Name   ##########################
GetAvailableFileName(ExportFileName){ 
    ;separate FileName and FileDir
    SplitPath, ExportFileName, FileName, FileDir
  
    ;return ExportFileName if FileName doesn't contain "#"
    If (InStr(FileName, "#") = 0)
        Return, ExportFileName
  
    ;add "\" to FileDir again
    If FileDir
        FileDir = %FileDir%\
  
    ;split FileName with #
    StringSplit, NameArray, FileName, #
    
    ;Search from StartID = 1
    StartID = 1
    Loop { 
        Number := A_Index + StartID - 1
               
        ;untill number is too large ...
        If ( StrLen(Number) > NameArray0 - 1 ) {
            ErrorLevel =
              (LTrim
                All files exist for >%ExportFileName%<
                with all "#" between %StartID% and %Number%.
              )
            Return 0
          }
  
        ;otherwise fill number with leading zeros
        Loop, % NameArray0 - 1 - StrLen(Number)
            Number = 0%Number% 
        
        ;split number in an array
        StringSplit, NumberArray, Number
        
        ;mix and concatenate the names array with the numbers array
        FileName =
        Loop, %NameArray0%
            FileName := FileName . NameArray%A_Index% . NumberArray%A_Index%
        
        ;check if GivenFileName doesn't exist
        If not FileExist(FileDir . FileName)
            Return FileDir . FileName
      } 
  }

;#############   destroy draw objects   ####################################### 
DeleteObject( p_object ) { 
    ;deletes a logical pen, brush, font, bitmap, region, or palette, freeing all system resources 
    DllCall( "gdi32.dll\DeleteObject", "uint", p_object ) 
  } 

DeleteDC( p_dc ) { 
    ;deletes the specified device context (DC). 
    DllCall( "gdi32.dll\DeleteDC", "uint", p_dc ) 
  } 

;#############   create draw objects   ######################################## 
CreateDrawHandles(UniqueID, ScreenWidth, ScreenHeight, frame_cc, frame_cw){ 
    global   hdc_frame, hdc_buffer, h_region, h_brushC, h_brushW 
  
    ;Get handle to display device context (DC) for the client area of a specified window 
    hdc_frame := DllCall( "GetDC" 
                        , "uint", UniqueID ) 
                        
    ;create buffer to store old color data to remove drawn rectangles 
    hdc_buffer := DllCall( "gdi32.dll\CreateCompatibleDC" 
                         , "uint", hdc_frame ) 
    
    ;Create Bitmap buffer to remove drawn rectangles 
    hbm_buffer := DllCall( "gdi32.dll\CreateCompatibleBitmap" 
                         , "uint", hdc_frame 
                         , "int", ScreenWidth 
                         , "int", ScreenHeight ) 
    
    ;Select Bitmap buffer in buffer to remove drawn rectangles 
    DllCall( "gdi32.dll\SelectObject" 
           , "uint", hdc_buffer 
           , "uint", hbm_buffer ) 
  
    ;create a dummy rectangular region. 
    h_region := DllCall( "gdi32.dll\CreateRectRgn" 
                       , "int", 0 
                       , "int", 0 
                       , "int", 0 
                       , "int", 0 ) 
  
    ;specify the color of the control frame. 
    h_brushC := DllCall( "gdi32.dll\CreateSolidBrush" 
                       , "uint", frame_cc ) 
    ;specify the color of the window frame. 
    h_brushW := DllCall( "gdi32.dll\CreateSolidBrush" 
                       , "uint", frame_cw ) 
  }
  
;#############   remove old rectangle and save screen below new rectangle   ### 
BufferAndRestoreRegion( p_x, p_y, p_w, p_h ) { 
    global   hdc_frame, hdc_buffer 
    static   buffer_state, old_x, old_y, old_w, old_h 
      
    ;Copies the source rectangle directly to the destination rectangle. 
    SRCCOPY   = 0x00CC0020 
        
    ;remove previously drawn rectangle (restore previoulsy buffered color data) 
    if ( buffer_state = "full") 
       ;perform transfer of color data of rectangle from source DC into destination DC 
       ; from buffer to screen, erasing the previously darwn reactangle 
       DllCall( "gdi32.dll\BitBlt" 
              , "uint", hdc_frame 
              , "int", old_x 
              , "int", old_y 
              , "int", old_w 
              , "int", old_h 
              , "uint", hdc_buffer 
              , "int", 0 
              , "int", 0 
              , "uint", SRCCOPY ) 
    else 
       buffer_state = full 
  
    ;remember new rectangle for next loop (to be removed) 
    old_x := p_x 
    old_y := p_y 
    old_w := p_w 
    old_h := p_h 
  
    ; Store current color data of new rectangle in buffer 
    DllCall( "gdi32.dll\BitBlt" 
           , "uint", hdc_buffer 
           , "int", 0 
           , "int", 0 
           , "int", p_w 
           , "int", p_h 
           , "uint", hdc_frame 
           , "int", p_x 
           , "int", p_y 
           , "uint", SRCCOPY ) 
  } 
  
;#############   draw frame   ################################################# 
DrawFrame( p_x, p_y, p_w, p_h, p_t, h_brush ) { 
    global   hdc_frame, h_region
      
    ; modify dummy rectangular region to desired reactangle 
    DllCall( "gdi32.dll\SetRectRgn" 
           , "uint", h_region 
           , "int", p_x 
           , "int", p_y 
           , "int", p_x+p_w 
           , "int", p_y+p_h ) 
    
    ; draw region frame with thickness (width and hight are the same) 
    DllCall( "gdi32.dll\FrameRgn" 
           , "uint", hdc_frame 
           , "uint", h_region 
           , "uint", h_brush 
           , "int", p_t 
           , "int", p_t ) 
  } 

  

 

; AHKInfo-1.3.5-是一个相当好用的AutoHotkey窗口信息获取工具,
; 还能生成后台发送按键或鼠标操作控件的代码。是一个AutoHotkey必备工具。

SetBatchLines -1
; AHK脚本以管理员权限自启
if !(A_IsAdmin || InStr(DllCall("GetCommandLine", "str"), ".exe"" /r"))
	RunWait % "*RunAs " (s:=A_IsCompiled ? "" : A_AhkPath " /r ") """" A_ScriptFullPath """" (s ? "" : " /r")
;AHK版本:    AutoHotkey_L 1.1.09.02
;~ #NoTrayIcon
;定义标题,在多处用到的!还是定义个变量比较好!后期修改时只改这里就行了
AHKInfo_Title=AHKInfo 1.3.5
;********************************************
;图标数据
Cross_CUR:="000002000100202002000F00100034010000160000002800000020000000400000000100010000000000800000000000000000000000020000000200000000000000FFFFFF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83FFFFFE6CFFFFFD837FFFFBEFBFFFF783DFFFF7EFDFFFEAC6AFFFEABAAFFFE0280FFFEABAAFFFEAC6AFFFF7EFDFFFF783DFFFFBEFBFFFFD837FFFFE6CFFFFFF83FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF28000000"
Full_ico:="0000010001002020100000000000E8020000160000002800000020000000400000000100040000000000000200000000000000000000100000001000000000000000000080000080000000808000800000008000800080800000C0C0C000808080000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFF00000FFFFFFFFFFFF000FFFFFFFFFF00FF0FF00FFFFFFFFFF000FFFFFFFFF0FF00000FF0FFFFFFFFF000FFFFFFFF0FFFFF0FFFFF0FFFFFFFF000FFFFFFF0FFFF00000FFFF0FFFFFFF000FFFFFFF0FFFFFF0FFFFFF0FFFFFFF000FFFFFF0F0F0FF000FF0F0F0FFFFFF000FFFFFF0F0F0F0FFF0F0F0F0FFFFFF000FFFFFF0000000F0F0000000FFFFFF000FFFFFF0F0F0F0FFF0F0F0F0FFFFFF000FFFFFF0F0F0FF000FF0F0F0FFFFFF000FFFFFFF0FFFFFF0FFFFFF0FFFFFFF000FFFFFFF0FFFF00000FFFF0FFFFFFF000FFFFFFFF0FFFFF0FFFFF0FFFFFFFF000FFFFFFFFF0FF00000FF0FFFFFFFFF000FFFFFFFFFF00FF0FF00FFFFFFFFFF000FFFFFFFFFFFF00000FFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000007770CCCCCCCCCCCCCCCCCCCCC07770007070CCCCCCCCCCCCCCCCCCCCC07070007770CCCCCCCCCCCCCCCCCCCCC0777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFF80000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000FFFFFFFFFFFFFFFFFFFFFFFF"
Null_ico:="0000010001002020100000000000E8020000160000002800000020000000400000000100040000000000000200000000000000000000100000001000000000000000000080000080000000808000800000008000800080800000C0C0C000808080000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000007770CCCCCCCCCCCCCCCCCCCCC07770007070CCCCCCCCCCCCCCCCCCCCC07070007770CCCCCCCCCCCCCCCCCCCCC0777000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFF80000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000FFFFFFFFFFFFFFFFFFFFFFFF"
Cross_CUR_File=%A_Temp%\Cross.CUR
Full_ico_File=%A_Temp%\Full.ico
Null_ico_File=%A_Temp%\Null.ico
控件宽 = 330
窗口宽 := 控件宽 + 20
;********************************************
;                    创建菜单
;********************************************
SetBatchLines -1
OptionsMenu_Text1=总在最前`tWin+Shift+T
Menu, OptionsMenu, Add, %OptionsMenu_Text1% ,GuiMenu
_MenuIsCheck( "OptionsMenu", OptionsMenu_Text1, "AlwaysOnTop")
if (ErrorLevel=-1) ;没有记录时将默认置顶
Menu,OptionsMenu,Check, %OptionsMenu_Text1%
Hotkey,#+t,GuiOnTop
Menu, OptionsMenu, Add,
OptionsMenu_Text2=复制时带 ahk_***`tWin+Shift+C
Menu, OptionsMenu, Add, %OptionsMenu_Text2% ,GuiMenu
_MenuIsCheck( "OptionsMenu", OptionsMenu_Text2, "Copy.ahk_***")
Hotkey, #+C, Copy_ahk_T
Menu, OptionsMenu, Add,
OptionsMenu_Text3=自动捕捉`tWin+Shift+F
Menu, OptionsMenu, Add, %OptionsMenu_Text3% ,GuiMenu
_MenuIsCheck( "OptionsMenu", OptionsMenu_Text3, "AutoCapture")
Hotkey,#+f,AutoCapture
;++++++++++++++++++++++++++++++++++
Menu, MyMenuBar, Add, 选项(&O), :OptionsMenu
;-----------------------------------------------
Menu, aboutMenu, Add, 清除工具属性记录 ,GuiMenu
Menu, aboutMenu, Add
Menu, aboutMenu, Add, AHK中文帮助`t(&H) ,GuiMenu
Menu, aboutMenu, Add, AHK中文论坛`t(&L) ,GuiMenu
Menu, aboutMenu, Add, AHK中文社区`t(&S) ,GuiMenu
Menu, aboutMenu, Add, AHK英文论坛`t(&E) ,GuiMenu
Menu, aboutMenu, Add, 关于`t(&A) ,GuiMenu
Menu, MyMenuBar, Add, 帮助(&H), :aboutMenu
;-----------------------------------------------
Gui, 1:Menu, MyMenuBar
;===============================================
;            创建窗口控件
;===============================================
Gui, 1:Add, GroupBox, x12 y5 w252 h40 , 窗口信息
Gui, 1:Add, Text, x26 y22 w42 h19 , 标题:
Gui, 1:Add, Edit, x62 y19 w190 h19 ReadOnly -Wrap  vTitle
Gui, 1:Add, Picture, x280 y10 w32 h32 gSetico vPic
Gui, 1:Add, Tab2,+Theme -Background -Wrap AltSubmit gTab_Click x6 y50 w340 h358 vTab1,窗口|控件|文本|样式表|操作|IE元素|IE操作
;==========================================================
	Gui, 1:Tab, 1  ;以下创建的控件属于第一个标签页
	Gui, 1:Add, ListView,NoSort Grid NoSortHdr -Multi gListView_DoubleClick vListView1  x10 y75 w%控件宽% h306 , 属性|值
	;列表控件1中的项目,貌似这样写的代码比较少
	ListView1_Text=窗口标题|窗口类|窗口ID|坐标|大小|窗口点击|样式|扩展样式|进程PID|进程名|进程路径|透明色|全局坐标|颜色 RGB|颜色 BGR 
	StringSplit,ListView1_Text_A,ListView1_Text,|
	loop,%ListView1_Text_A0%
		LV_Add("",ListView1_Text_A%A_Index%)
	;调整所有列的宽度以适应行的内容
	LV_ModifyCol(1), LV_ModifyCol(2, 259)
	Gui, 1:Add, Text,x14 y388 w74 VText_T,透明度:
	Gui, 1:Add, Slider, AltSubmit Center Range0-255 NoTicks ToolTip Line1 vSlider1 gSlider x90 y384 w222 h20,255
	GuiControl, Disable,Slider1
	;==========================================================
		Gui, 1:Tab, 2 ;以下创建的控件属于第2个标签页
		Gui, 1:Add, ListView,NoSort Grid NoSortHdr -Multi gListView_DoubleClick vListView2 x10 y75 w%控件宽% h158 , 属性|值
		ListView2_Text=类别名|文本|实例编号|句柄|坐标|大小|点击坐标|样式|扩展样式
		StringSplit,ListView2_Text_A,ListView2_Text,|
		loop,%ListView2_Text_A0%
			LV_Add("",ListView2_Text_A%A_Index%)
		LV_ModifyCol(1), LV_ModifyCol(2, 256)
		;......................
		Gui, 1:Add, ListView,AltSubmit Checked Grid NoSort -Multi HwndLV4H gListView_DoubleClick vListView4 x10 y233 w%控件宽% h170 ,控件列表|ID|句柄|文本|
		;==========================================================
			Gui, 1:Tab, 3 ;以下创建的控件属于第3个标签页 []
			Gui, 1:Add, Edit,HScroll ReadOnly x10 y75 w%控件宽% h162 vVisible_text,这里将显示的是可见文本
			Gui, 1:Add, Edit,HScroll ReadOnly x10 y240 w%控件宽% h162 vHidden_text,这里将显示的是全部文本
			;==========================================================
				Gui, 1:Tab, 4 ;以下创建的控件属于第4个标签页
				;~ Gui, 1:Add, GroupBox, x5 y310 w266 h90 , 全局鼠标
				;~ ;全局鼠标列表
				Gui, 1:Add, ListView,HwndLV3H NoSort NoSortHdr AltSubmit Checked Grid -Multi gListView_DoubleClick vListView3 x10 y75 w%控件宽% h325 , 窗口样式|值|说明
				ListView3_Text=WS_BORDER,0x00800000,细边框|WS_POPUP,0x80000000,弹出式|WS_CAPTION,0x00C00000,标题栏|WS_DISABLED,0x08000000,不可用|WS_DLGFRAME,0x00400000,对话框边框|WS_MAXIMIZE,0x01000000,初始状态为最大化|WS_MAXIMIZEBOX,0x00010000,最大化按钮|WS_MINIMIZE,0x20000000,初始状态为最小化|WS_MINIMIZEBOX,0x00020000,最小化按钮|WS_OVERLAPPED,0x00000000,层叠|WS_SIZEBOX,0x00040000,可调整边框|WS_SYSMENU,0x00080000,标题菜单|WS_VSCROLL,0x00200000,垂直滚动条|WS_HSCROLL,0x00100000,水平滚动条|WS_VISIBLE,0x10000000,可见|WS_EX_TOPMOST,0x00000008,置顶状态|WS_EX_TOOLWINDOW,0x00000080,工具窗口|WS_EX_WINDOWEDGE,0x00000100,凸起边框
				StringSplit,ListView3_Text_A,ListView3_Text,|
				loop,%ListView3_Text_A0% {
					StringSplit,ListView3_Text_A_L,ListView3_Text_A%A_Index%,`,
					LV_Add("",ListView3_Text_A_L1,ListView3_Text_A_L2,ListView3_Text_A_L3)
				}
				LV_ModifyCol()
				;==========================================================
					Gui, 1:Tab, 5 ;以下创建的控件属于第5个标签页
					Gui, Add, Text, x9 y77,窗口识别条件:
					Gui, Add, Checkbox,Checked x90 y74 w44 h18 vCheckbox1,标题
					Gui, Add, Checkbox,Checked x137 y74 w34 h18 vCheckbox2,类
					Gui, Add, Checkbox, x174 y74 w38 h18 vCheckbox3,exe
					Gui, Add, Checkbox, x215 y74 w44 h18 vCheckbox4,Text
					Gui, Add, Checkbox, x262 y74 w38 h18 vCheckbox5,DPI
					Gui, Add, Button,x305 y73 w35 h20 gButton1,生成
					Gui, 1:Add, Edit, HScroll ReadOnly x10 y95 w%控件宽% h305 vGenerate_text
					;==========================================================
						Gui, 1:Tab, 6 ;以下创建的控件属于第6个标签页 IE元素
						Gui, 1:Add, ListView,AltSubmit NoSort NoSortHdr Grid -Multi HwndLV5H gListView_DoubleClick vListView5  x10 y75 w%控件宽% h234 , 元素属性|属性值
						ListView5_Text=document.title|document.url|statustext|tagname|type|name|id|classname|value|title|outertext|innertext|src|href|target
						StringSplit,ListView5_Text_A,ListView5_Text,|
						loop,%ListView5_Text_A0%
							LV_Add("",ListView5_Text_A%A_Index%)
						LV_ModifyCol()
						Gui, Add, Radio, x14 y312 gRadio vRadio1,innerhtml
						Gui, Add, Radio,Checked x104 y312 gRadio vRadio2,outerhtml
						Gui, 1:Add, Edit,ReadOnly x10 y326 w%控件宽% h75 vEdit1
						Radio1Text=
						Radio2Text=
						;==========================================================
							Gui, 1:Tab, 7 ;以下创建的控件属于第7个标签页 IE操作
							Gui, Add, Radio,Checked x14 y74 h18 gRadio vRadio3, 简单代码
							Gui, Add, Radio, x104 y74 h18 gRadio vRadio4, 比较准确
							Gui, 1:Add, Edit, HScroll ReadOnly x10 y94 w%控件宽% h308 vIeGenerate_text
							global Radio3_Text=
							global Radio4_Text=
							;~ GuiControl,Choose,tab1,7
							;==========================================================
							Gui, 1:+HwndAHKID +OwnDialogs
							X:=_RegR("X")="" ? 0:_RegR("X")
							Y:=_RegR("Y")="" ? 0:_RegR("Y")
							;~ MsgBox,%X%
							Gui, 1:Show,x %X% y %Y% w%窗口宽% h412, %AHKInfo_Title%
							;=====================================================
							Gui, 2:Color,FF0000
							Gui, 2:-Caption +ToolWindow +Border +AlwaysOnTop +LastFound
							WinSet, TransColor,FF0000 250
							OnMessage(0x203, "WM_LBUTTONDBLCLK")
							FileDelete,%A_Temp%\Cross.CUR
							FileDelete,%A_Temp%\Full.ico
							FileDelete,%A_Temp%\Null.ico
							;图片控件
							IfNotExist,%Full_ico_File%
								BYTE_TO_FILE(StrToBin(Full_ico),Full_ico_File)
							GuiControl,,Pic,%Full_ico_File%
							;-----------------------------
							;改为屏幕模式
							CoordMode,Mouse
							CoordMode,Pixel
							;窗口是否置顶
							IsCheck:=IsMenuItemChecked( 0, 0, AHKID )
							if (IsCheck=1)
								WinSet,AlwaysOnTop,On,ahk_id %AHKID%
							;捕捉功能
							IsCheck:=IsMenuItemChecked( 0, 4, AHKID )
							if (IsCheck=0)
								SetTimer,GetPos,Off
							else{
								SetTimer,GetPos,On
								WinSetTitle,ahk_id %AHKID%,,(自动)%AHKInfo_Title%
							}
							;==============全局变量============
							global wb
							global ele
							;----------------热键-------------------
							;一键捕捉 ;沿用旧版本ahkinfo的热键
							Hotkey,~MButton,GetPos ;鼠标中键
							Hotkey,~#ctrl,GetPos ;LWin+Ctrl
							Hotkey,~^LWin,GetPos ;Ctrl+LWin
							;定义窗口的热键
							Hotkey,IfWinActive,ahk_id %AHKID%
							Hotkey,Esc,GuiClose ;按Esc退出
							return
							;===========================
GuiClose:
WinGetPos,X,Y,,,ahk_id %AHKID%
_RegW("X",X), _RegW("Y",Y)
FileDelete,%A_Temp%\Cross.CUR
FileDelete,%A_Temp%\Full.ico
FileDelete,%A_Temp%\Null.ico
ExitApp
Slider:
IfWinExist,ahk_id %OutWin3%
{
	GuiControl,,Text_T,透明度(%Slider1%):
	if Slider1!=
		WinSet,Transparent,%Slider1%,ahk_id %OutWin3%
}
return
WM_LBUTTONDBLCLK(wParam, lParam) {
	if (A_GuiControl != "Generate_text")
		return
	SetTimer 延时获取整行, -50
	return

延时获取整行:
	SendInput {LButton Up}{LButton Up}
	Send {Home}
	Sleep 50
	Send +{Down}
	SendInput ^c
	_ToolTip("复制成功")
return
}
GuiMenu: ;菜单事件
	Gui +OwnDialogs
	ThisMenuItemPos:=A_ThisMenuItemPos-1
	ItemPos=%A_ThisMenu%%ThisMenuItemPos%
	;~ **********************
	;~ * 以下是帮助菜单内容 *
	;~ **********************
	if (ItemPos = "aboutMenu0") { ;清除工具的属性记录
		MsgBox, 4132, 询问, 是否要清除AHKInfo的属性记录并退出?
		IfMsgBox,Yes
		{
			RegDelete,HKCU,Software\AutoHotKey\AHKInfo
			ExitApp
		}
	}else if (ItemPos = "aboutMenu2") { ;AHK中文帮助
		Run,https://www.autoahk.com/help/autohotkey/zh-cn/docs/Tutorial.htm
	}else if (ItemPos = "aboutMenu3") { ;AHK中文论坛
		Run,https://www.autohotkey.com/boards/viewforum.php?f=26
	}else if (ItemPos = "aboutMenu4") { ;中文社区
		Run,https://www.autoahk.com/
	}else if (ItemPos = "aboutMenu5") { ;英文社区
		Run,https://www.autohotkey.com/boards/
	}else if (ItemPos = "aboutMenu6") { ;关于
		MsgBox, 262208, 关于 %AHKInfo_Title%, 作者:    星雨朝霞`nQQ:    458926486
		; 加宽窗口,添加DPI生成功能 dbgba  2022年1月13日
		; 加宽窗口,添加DPI生成功能修改后脚本下载网址提供 aahk   QQ-E-Mail: 595076941@qq.com  2022年8月3日

		;~ **********************
		;~ * 以下是选项菜单内容 *
		;~ **********************
	}else if (ItemPos = "OptionsMenu0"){ ;切换置顶
		Menu,%A_ThisMenu%,ToggleCheck,%A_ThisMenuItem%
		IsCheck:=IsMenuItemChecked( 0, 0, AHKID )
		_RegW("AlwaysOnTop",IsCheck)
		if (IsCheck=1)
			WinSet,AlwaysOnTop,On,ahk_id %AHKID%
		else
			WinSet,AlwaysOnTop,Off,ahk_id %AHKID%
	}else if (ItemPos = "OptionsMenu2"){ ;切换复制时带上 ahk_***
		Menu,%A_ThisMenu%,ToggleCheck,%A_ThisMenuItem%
		IsCheck:=IsMenuItemChecked( 0, 2, AHKID )
		_RegW("Copy.ahk_***",IsCheck)
	}else if (ItemPos = "OptionsMenu4"){ ;自动捕捉 AutoCapture
		Menu,%A_ThisMenu%,ToggleCheck,%A_ThisMenuItem%
		IsCheck:=IsMenuItemChecked( 0, 4, AHKID )
		if (IsCheck=0) {
			SetTimer,GetPos,Off
			;~ GuiControl,,Pic,%A_Temp%\Full.ico
			WinSetTitle,ahk_id %AHKID%,,%AHKInfo_Title%
		}else{
			SetTimer,GetPos,On
			WinSetTitle,ahk_id %AHKID%,,(自动)%AHKInfo_Title%
		}
		_RegW("AutoCapture",IsCheck)
	}else
		MsgBox,%ItemPos%
return
GuiOnTop: ;窗口置顶
	;为了能选中菜单项又能触发它的事件!我只想到这种貌似有效又简单的方法
	WinMenuSelectItem,ahk_id %AHKID%,,1&,1&
return
Copy_ahk_T: ;切换复制时带上 ahk_***
	WinMenuSelectItem,ahk_id %AHKID%,,1&,3&
return
AutoCapture:     ;自动捕捉 AutoCapture
	WinMenuSelectItem,ahk_id %AHKID%,,1&,5&
return
Tab_Click:
	GuiControlGet,var,,tab1
	;~ MsgBox,%var%
return
ListView_DoubleClick:
	Gui, 1:ListView,%A_GuiControl% ;切换下面的列表命令对应的列表控件,A_GuiControl包含了当前点击的控件关联变量名
	;双击列表复制
	if (A_GuiControlEvent="DoubleClick"){ ;只有是双击时才触发
		if (A_GuiControl="ListView1" or A_GuiControl="ListView2" or A_GuiControl="ListView3" or A_GuiControl="ListView5") and (A_EventInfo!=0){
			LV_GetText(LV_Text,A_EventInfo ,2) ;获取选中的项目第二列的内容,A_EventInfo包含了当前选中的行数
			if LV_Text !=
			{ ;如果内容不为空
				ahk_x= ;定义一个变量,(我也不知道要不要这样)

				;检查是否选中 复制时带 ahk_
				IsCheck:=IsMenuItemChecked( 0, 2, AHKID ) ;所检查的菜单位置: 第一个菜单第三个项目
				if (IsCheck=1){ ;如果菜单项是选中状态
					if (A_GuiControl="ListView1"){ ;如果是指定的控件
						if (A_EventInfo=2) ;
							ahk_x=ahk_class
						if (A_EventInfo=3)
							ahk_x=ahk_id
						if (A_EventInfo=9)
							ahk_x=ahk_pid
						if (A_EventInfo=10)
							ahk_x:=ahk_exe
					}
					if (A_GuiControl="ListView5")
						ahk_x:="." _LV_GetText(A_EventInfo) ":="
				}

				Clipboard=%ahk_x%%LV_Text%
				_ToolTip( "Clipboard= " Clipboard)
			}
		}
		;控件列表双击事件
		if (A_GuiControl="ListView4" and A_EventInfo!=0){
			LV_GetText(ListView4_T1,A_EventInfo,1), LV_GetText(ListView4_T2,A_EventInfo,4), LV_GetText(ListView4_T3,A_EventInfo,2), LV_GetText(ListView4_T4,A_EventInfo,3)
			ControlGetPos,lvx,lvy,lvw,lvh,%ListView4_T1%,ahk_id %OutWin3%
			ListView4_T5=%lvx%,%lvy%
			ListView4_T6=%lvw%,%lvh%
			ListView4_T7=
			ControlGet,ListView4_T8,Style,,%ListView4_T1%,ahk_id %OutWin3%    ;控件样式
			ControlGet,ListView4_T9,ExStyle,,%ListView4_T1%,ahk_id %OutWin3%    ;控件扩展样式
			Gui, 1:ListView,ListView2
			loop,9
				LV_Modify(A_Index,"Col2",ListView4_T%A_Index%)
			LV_ModifyCol() ;重新调整列宽
		}
	}
	;列表选中事件
	MouseGetPos,,,,LV,2
	if (LV=LV4H and A_GuiControl="ListView4" and A_GuiControlEvent="I" and A_EventInfo!=0){
		IfWinExist,ahk_id %OutWin3%
		{
			LV_GetText(LV_Text,A_EventInfo,1)
			if % InStr(ErrorLevel, "C", true)
				Control,Show,,%LV_Text%,ahk_id %OutWin3%
			else if % InStr(ErrorLevel, "c", true)
				Control,Hide,,%LV_Text%,ahk_id %OutWin3%
			;~ WinSet,Redraw,,ahk_id %OutWin3%

		}
	}
	if (LV=LV5H and A_GuiControl="ListView5" and A_GuiControlEvent="I" and A_EventInfo!=0 and IsObject(wb) and IsObject(ele)){
		if _LV_GetText(A_EventInfo)="Checked" {
			if InStr(ErrorLevel, "C", true)
				ele.Checked:=true
			if InStr(ErrorLevel, "c", true)
				ele.Checked:=false
		}}
		;~ MsgBox,%A_GuiControl%
		;双右击时事件
		if (A_GuiControlEvent="R") {
			if  (A_GuiControl="ListView5" and IsObject(wb) and IsObject(ele)){
				LV_GetText(LV_Text1,A_EventInfo,1)
				LV_GetText(LV_Text2,A_EventInfo,2)
				WV=title,url,value,outertext,innertext
				if InStr(WV,LV_Text1) {
					InputBox,LV_TextOut,元素属性值,输入元素属性值`n%LV_Text1% =,,,150,,,,,%LV_Text2%
					if !ErrorLevel  {
						LV_Modify(A_EventInfo,"Col2",LV_TextOut)
						if _LV_GetText(A_EventInfo)="title"
							wb.document.title:=LV_TextOut
						if _LV_GetText(A_EventInfo)="url"
							wb.Navigate(LV_TextOut)
						if _LV_GetText(A_EventInfo)="value"
							ele.value:=LV_TextOut
						if _LV_GetText(A_EventInfo)="innertext"
							ele.innertext:=LV_TextOut
						if _LV_GetText(A_EventInfo)="outertext"
							ele.outertext:=LV_TextOut
					}
				}}}
				;窗口样式
				if (LV=LV3H and A_GuiControl="ListView3" and A_GuiControlEvent="I" and A_EventInfo!=0 and OutWin3!=AHKID){
					DetectHiddenWindows, on
					IfWinExist,ahk_id %OutWin3%
					{
						;~ MsgBox,
						;~ if (OutWin3!=AHKID) {
						LV_GetText(LV_Text1,A_EventInfo,1)
						LV_GetText(LV_Text,A_EventInfo,2)
						if % InStr(ErrorLevel, "C", true)
							if % InStr(LV_Text1,"EX")
								WinSet,ExStyle,+%LV_Text%,ahk_id %OutWin3%
							else
								WinSet,Style,+%LV_Text%,ahk_id %OutWin3%
						else if % InStr(ErrorLevel, "c", true)
							if % InStr(LV_Text1,"EX")
								WinSet,ExStyle,-%LV_Text%,ahk_id %OutWin3%
							else
								WinSet,Style,-%LV_Text%,ahk_id %OutWin3%
							;~ WinSet,Redraw,,ahk_id %OutWin3%
					} ;}
					DetectHiddenWindows, Off
				}
				return
				;图标控件点击事件
Setico:
	IfNotExist,%Cross_CUR_File%
		BYTE_TO_FILE(StrToBin(Cross_CUR),Cross_CUR_File)
	IfNotExist,%Null_ico_File%
		BYTE_TO_FILE(StrToBin(Null_ico),Null_ico_File)
	GuiControl,,Pic,%Null_ico_File%
	;设置鼠标指针为十字标
	CursorHandle := DllCall( "LoadCursorFromFile", "Str",Cross_CUR_File )
	DllCall( "SetSystemCursor", "Uint",CursorHandle, "Int",32512 )
	SetTimer,GetPos,500
	GuiControl,,ieGenerate_text,等待...
	SetText("等待...")
	;等待左键弹起
	KeyWait,LButton
	Gui, 2:Hide
	SetTimer,GetPos,Off
	;还原鼠标指针
	DllCall( "SystemParametersInfo", "UInt",0x57, "UInt",0, "UInt",0, "UInt",0 )
	;图标设置为原样
	IfNotExist,%Full_ico_File%
		BYTE_TO_FILE(StrToBin(Full_ico),Full_ico_File)
	GuiControl,,Pic,%Full_ico_File%
	;~ GuiControlGet,TABVar,,TAB1 ;当前选项卡序号
	;~ if (TABVar>=6) {
return
Generate(){ ;生成简单代码
	Gui, 1:ListView,ListView1    ;切换到窗口列表以设置数据
	GuiControlGet,Checkbox1_C,,Checkbox1
	GuiControlGet,Checkbox2_C,,Checkbox2
	GuiControlGet,Checkbox3_C,,Checkbox3
	GuiControlGet,Checkbox4_C,,Checkbox4
	GuiControlGet,Checkbox5_C,,Checkbox5
	GuiControlGet,ALL_text,,Hidden_text
	StringSplit,ALL_text,ALL_text,`n
	LV_GetText(text1,1,2) ;标题
	LV_GetText(text2,2,2)    ;类名
	LV_GetText(text3,10,2)    ;进程名
	LV_GetText(text4,6,2)    ;窗口内指定坐标
	Gui, 1:ListView,ListView2
	LV_GetText(text5,1,2) ;获取控件类
	LV_GetText(text6,7,2) ;获取控件内坐标

	loop,%ALL_text0%
	{
		Index:=ALL_text0-A_Index+1
		Text_index:=ALL_text%Index%
		WinText:=Text_index!="" ? ", " SubStr(Text_index,1,10):
		if Text_index!=
			break
		;~ if Text_index!=
		;~ {
		;~ WinText:=SubStr(Text_index,1,10)
		;~ Break
		;~ }

	}
	WinTitle:=
	if (Checkbox1_C=1)
		WinTitle=%text1%
	if (Checkbox2_C=1)
		WinTitle=%WinTitle% ahk_class %text2%
	if (Checkbox3_C=1)
		WinTitle=%WinTitle% ahk_exe %text3%
	if (Checkbox4_C!=1)
		WinText:=""
	if (Checkbox5_C=1)
		DPI修正提示:="【DPI缩放通用坐标修正】", text4 := StrReplace(StrReplace(text4,"x","% ""x"" ")," y","*A_ScreenDPI//" A_ScreenDPI " "" y"" ") "*A_ScreenDPI//" A_ScreenDPI
	SetText("",0)
	if (WinTitle!="" and WinTitle!="ahk_class") {
		;~ SetText(";------<<操作代码>>-------")
		text=
		(
			;等待指定标题窗口出现
		WinWait, %WinTitle%%WinText%

		)
		SetText(text)

		text=
		(
			;点击窗口内指定坐标 %DPI修正提示%
		ControlClick, %text4%, %WinTitle%%WinText%

		)
		SetText(text)
		if text5!=
		{
			text=
			(
				;点击控件
			ControlClick, %text5%, %WinTitle%%WinText%

			)
			SetText(text)

			if text6!=
			{
				text=
				(
					;左键点击控件内指定坐标1次
				ControlClick, %text5%, %WinTitle%%WinText%, , Left, 1, %text6%

				)
				SetText(text)
			}
			if % InStr(text5,"Button")
			{
				text=
				(
					;控件选中(如果此控件为选择框或单选框) Check替换为Uncheck即取消选中
				Control, Check, , %text5%, %WinTitle%%WinText%

				)
				SetText(text)
			}
			text=
			(
				;向控件发送空格键
			ControlSend, %text5%,{Space}, %WinTitle%%WinText%

			)
			SetText(text)
		}}
		;~ Gui, 1:ListView,ListView5    ;切换到窗口列表以设置数据
		;~ IE_Array:=Object()
		Gui, 1:Tab, 7
			iUrl:=GetV("document.url",2)
			itagname:=GetV("tagname",2)
			itype:=GetV("type",2)
			iID:=GetV("id",2)
			iValue:=GetV("Value",2)!="" ? GetV("Value",2):"设置新属性值"
			Index=1
			iCode=
			(
				;脚本由 AHKInfo 生成
ComObjError(false) ;关闭对象错误提示
for window in ComObjCreate("Shell.Application").Windows {
    if InStr(window.document.url,"%iUrl%") { ;网页地址子字符串
        ie:=window
        break 
}} ;连接符合条件的IE窗口,其它窗口上的IE控件请用 IEAttach() 帖子: http://ahk.5d6d.net/viewthread.php?tid=5501
if IsObject(ie)=0 {
				;Exit ;如果连接IE对象失败就退出当前线程,(貌似跳过后面的代码了)
    ie:=ComObjCreate("InternetExplorer.Application") ;如果连接IE对象失败就创建一个IE窗口
    ie.visible :=true ;浏览器窗口可见
    ie.Navigate("%iUrl%") ;如果先加载空白页面 about:blank ,这样IE窗口应该响应得快一点点
}
Loop { ;等待网页加载完成!
    Sleep, 200
    if (ie.readyState="complete" or ie.readyState=4 or A_LastError!=0)
        break
} ;****************************************************************`n`n
			)
			iCode2:=GetV("tagname",2)!="" ? ("if (" itagname ".item(A_Index-1).tagname=`"`"" itagname "`"`" " ):
			iCode2.=GetV("id",2)!="" ? ("and " itagname ".item(A_Index-1).id=`"`"" GetV("id",2) "`"`" " ):
			iCode2.=GetV("src",2)!="" ? ("and " itagname ".item(A_Index-1).src=`"`"" GetV("src",2) "`"`" " ):
			iCode2.=GetV("name",2)!="" ? ("and " itagname ".item(A_Index-1).name=`"`"" GetV("name",2) "`"`" " ):
			iCode2.=GetV("classname",2)!="" ? ("and " itagname ".item(A_Index-1).classname=`"`"" GetV("classname",2) "`"`" " ):
			iCode2.=GetV("href",2)!="" ? ("and " itagname ".item(A_Index-1).href=`"`"" GetV("href",2) "`"`" " ):
			iCode2.=GetV("target",2)!="" ? ("and " itagname ".item(A_Index-1).target=`"`"" GetV("target",2) "`"`" " ):
			;~ iCode2.=GetV("classname",2)!="" ? ".classname`n":
			;~ iCode2.=GetV("innertext",2)!="" ? ".innertext`n":
			;~ iCode2.=GetV("value",2)!="" ? ".value`n":
			Gui, 1:ListView,ListView5    ;切换到窗口列表以设置数据
			Radio4_Text_value=
			(
%itagname%:=ie.document.GetElementsByTagName("%itagname%")
Loop `% %itagname%.length {
%iCode2%) {
    %itagname%.item(A_Index-1).value:="%iValue%"
    break ;找到一个符合条件的元素进行操作后,就退出循环,后面的元素就不比较了,可以提高一点点效率
}}
			)
			Radio4_Text_Click=
			(
%itagname%:=ie.document.GetElementsByTagName("%itagname%")
Loop `% %itagname%.length {
%iCode2%) {
    %itagname%.item(A_Index-1).Click()
    break ;找到一个符合条件的元素进行操作后,就退出循环,后面的元素就不比较了,可以提高一点点效率
}}
			)
			Radio4_Text_Check=
			(
%itagname%:=ie.document.GetElementsByTagName("%itagname%")
Loop `% %itagname%.length {
%iCode2%) {
				;选择单选`/复选框并激活onChange/OnClick事件;设置为 false 即取消选择
    %itagname%.item(A_Index-1).Checked:=true
    %itagname%.item(A_Index-1).fireEvent("onChange")
    %itagname%.item(A_Index-1).fireEvent("OnClick")
    break ;找到一个符合条件的元素进行操作后,就退出循环,后面的元素就不比较了,可以提高一点点效率
}}
			)
			;=*********************************************************************
			if (itagname="Input") {
				if (itype="text" or itype="password")
					if (iID=""){
						Radio3_Text=;设置新属性值`nie.document.GetElementsByTagName("%itagname%").item(%TagIndex%).value:="%iValue%"`n`n
						Radio4_Text:=Radio4_Text_value
					}else{
						Radio3_Text=;设置新属性值`nie.document.getElementById("%iID%").value:="%iValue%"`n`n
						Radio4_Text:=Radio4_Text_value
					}
				if (itype="submit" or itype="button" or itype="image")
					if (iID=""){
						Radio3_Text=;点击元素`nie.document.GetElementsByTagName("%itagname%").item(%TagIndex%).Click()
						Radio4_Text:=Radio4_Text_Click
					}else{
						Radio3_Text=;点击元素`nie.document.getElementById("%iID%").Click()
						Radio4_Text:=Radio4_Text_Click
					}
				if (itype="radio" or itype="checkbox")
					if (iID=""){
						Radio3_Text=;选择单选`/复选框并激活onChange/OnClick事件;设置为 false 即取消选择`nie.document.GetElementsByTagName("%itagname%").item(%TagIndex%).Checked:=true`nie.document.GetElementsByTagName("%itagname%").item(%TagIndex%).fireEvent("onChange")`nie.document.GetElementsByTagName("%itagname%").item(%TagIndex%).fireEvent("OnClick")
						Radio4_Text:=Radio4_Text_Check
					}else{
						Radio3_Text=;选择单选`/复选框并激活onChange/OnClick事件;设置为 false 即取消选择`nie.document.getElementById("%iID%").Checked:=true`nie.document.getElementById("%iID%").fireEvent("onChange")`nie.document.getElementById("%iID%").fireEvent("OnClick")
						Radio4_Text:=Radio4_Text_Check
				}}else if (itagname="button" or itagname="a" or itagname="img" or itagname="span" or itagname="area" or itagname="input_image" `
					or itagname="input_button" or itagname="input_submit" or itagname="input_radio" or itagname="input_reset" `
					or itagname="li" or itagname="td" or itagname="table"){
					if (iID=""){
						Radio3_Text=;点击元素`nie.document.GetElementsByTagName("%itagname%").item(%TagIndex%).Click()
						Radio4_Text:=Radio4_Text_Click
					}else{
						Radio3_Text=;点击元素`nie.document.getElementById("%iID%").Click()
						Radio4_Text:=Radio4_Text_Click
					}
			}else if (itagname="textarea"){
				if (iID="")
					Radio3_Text=;设置新属性值`nie.document.GetElementsByTagName("%itagname%").item(%TagIndex%).value:="设置新属性值"`n`n
				else
					Radio3_Text=;设置新属性值`nie.document.getElementById("%iID%").value:="设置新属性值"`n`n
			}else{
				Radio3_Text=MsgBox,0,`% ".item(%TagIndex%).outerhtml",`% ie.document.GetElementsByTagName("%itagname%").item(%TagIndex%).outerhtml
				;~ Radio4_Text=MsgBox,0,outerhtml,`% %outerhtml%
				Radio4_Text=
				(
%itagname%:=ie.document.GetElementsByTagName("%itagname%")
Loop `% %itagname%.length {
%iCode2%) {
    MsgBox,0,`% ".item(" A_Index-1 ").outerhtml",`% %itagname%.item(A_Index-1).outerhtml
}}
				)
			}
			;"if (" itagname ".item(A_Index-1).tagname=`"`"" itagname "`"`" "
			if InStr(Radio4_Text,itagname ".item(A_Index-1).tagname=`"`"" itagname "`"`" and")
				StringReplace,Radio4_Text,Radio4_Text,% itagname ".item(A_Index-1).tagname=`"`"" itagname "`"`" and"
			else
				Radio4_Text:=Radio3_Text
			global Radio3_TextS:=iCode Radio3_Text "`n"
			global Radio4_TextS:=iCode Radio4_Text "`n"
			GuiControlGet,Check_C,,Radio3
			if Check_C=1
				GuiControl,,ieGenerate_text,%Radio3_TextS%
			else
				GuiControl,,ieGenerate_text,%Radio4_TextS%
	}
	;==================
	GetV(VV,Col=1) {
	Gui, 1:ListView,ListView5    ;切换到窗口列表以设置数据
	loop,% LV_GetCount() {
		LV_GetText(outvar,A_Index)
		if (outvar=VV) {
			return _LV_GetText(A_Index,Col)
		}}
	}
	SetText(iText,o=1){
	StringReplace,iText,iText,%A_Tab% ,,All
	if (o=1){
		GuiControlGet,ControlText,,Generate_text
		if ControlText=`n
			StringReplace,ControlText,ControlText,`n,,All
		GuiControl,,Generate_text,%ControlText%%iText%`n
	}else
		GuiControl,,Generate_text,%iText%`n
}
Radio:
	GuiControlGet,sRadio1,,Radio1
	if sRadio1=1
		GuiControl,,Edit1,%Radio1Text%
	else
		GuiControl,,Edit1,%Radio2Text%

	GuiControlGet,sRadio1,,Radio3
	if sRadio1=1
		GuiControl,,IeGenerate_text,%Radio3_TextS%
	else
		GuiControl,,IeGenerate_text,%Radio4_TextS%
return
;******************************************************************************************************
GetPos:
	MouseGetPos,OutX,OutY,OutWin3,OutCtrl1    ;取鼠标下信息
	WinGetPos,WinX,WinY,WinW,WinH,ahk_id %OutWin3% ;取鼠标下窗口坐标/大小
	WinGetTitle,OutWin1,ahk_id %OutWin3%    ;取鼠标下窗口标题
	WinGetClass,OutWin2,ahk_id %OutWin3%    ;取鼠标下窗口类名
	ControlGetPos,OutCtrlX,OutCtrlY,OutCtrlW,OutCtrlH,%OutCtrl1%,ahk_id %OutWin3%    ;控件坐标/大小
	GuiControlGet,TABVar,,TAB1 ;当前选项卡序号
	;=========================================================
	if (OutWin3=AHKID) { ;如果鼠标下窗口为自身清空所有
		GuiControl,,Title,
		Gui, 1:ListView,ListView1    ;切换到窗口列表以设置数据
		loop,%ListView1_Text_A0%
			LV_Modify(A_Index,"Col2","")
		LV_ModifyCol()
		Gui, 1:ListView,ListView2    ;切换到控件列表以设置数据
		loop,%ListView2_Text_A0%
			LV_Modify(A_Index,"Col2","")
		LV_ModifyCol() ;重新调整列宽
		Gui, 1:ListView,ListView3 ;切换到列表控件3
		loop,%ListView3_Text_A0%
			LV_Modify(A_Index,"-Check")
		Gui, 1:ListView,ListView4 ;切换到列表控件4 类别名|ID|句柄|文本|
		LV_Delete()
		LV_ModifyCol(1,"80","控件列表")
		LV_ModifyCol(2,50) ;重新调整列宽
		LV_ModifyCol(3,50)
		LV_ModifyCol(4,50)
		GuiControl,,Hidden_text,
		GuiControl,,Visible_text,
		GuiControl,,Edit1,
	}
	;===================网页操作===========================
	if InStr(OutCtrl1,"Internet Explorer_Server") {
		ControlGet,CtrlHwnd,Hwnd,,%OutCtrl1%,ahk_id %OutWin3%
		global wb:=_IEObjGetFromHwnd(CtrlHwnd) ;从控件句柄转到对象
		if IsObject(wb) {
			Gui, 1:ListView,ListView5 ;切换到列表控件5 IE
			LV_ModifyCol(2,"","属性值 (等待)" )
			GuiControl,,Title,% wb.document.title
			global ele:=wb.document.elementFromPoint(OutX-(WinX+OutCtrlX),OutY-(WinY+OutCtrlY)) ;取鼠标下网页元素对象
			loop,% LV_GetCount() {
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="document.title"     ? wb.document.title:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="statustext"     ? wb.statustext:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="target"         ? ele.target:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="name"             ? ele.name:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="href"             ? ele.href:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="id"             ? ele.id:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="classname"     ? ele.classname:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="src"             ? ele.src:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="outertext"     ? ele.outertext:)|
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="innertext"     ? ele.innertext:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="type"             ? ele.type:)

				;~ LV_Modify(A_Index,_LV_GetText(A_Index)="checked"        and _LV_GetText(A_Index,2)!="" and ele.checked=-1 ? "Col2 Check":"Col2 -Check",_LV_GetText(A_Index)="checked"     ? (ele.checked=-1 ? "True":"false"):)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="title"             ? ele.title:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="tagname"         ? ele.tagname:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="id"             ? ele.id:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="value"             ? ele.value:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="name"             ? ele.name:)
				LV_Modify(A_Index,"Col2",_LV_GetText(A_Index)="document.url"     ? wb.document.url:)
			}
			LV_ModifyCol(), Radio1Text:=ele.innerhtml, Radio2Text:=ele.outerhtml
			gosub,Radio
		}
	}
	if (OutWin3!=AHKID){ ;不获取自身..和标签页为6以上.IE
		global OutWin3
		;==============设置窗口列表的数据===================
		;~ OutWin1=        ;标题
		;~ OutWin2=        ;类名
		;~ OutWin3=        ;句柄
		;~ OutWin4=        ;窗口坐标
		;~ OutWin5=        ;窗口大小
		;~ OutWin6=        ;窗口点击
		;~ OutWin7=        ;窗口样式
		;~ OutWin8=        ;窗口扩展样式
		;~ OutWin9=        ;进程PID
		;~ OutWin10=        ;进程名
		;~ OutWin11=        ;进程路径
		;===========================================
		Gui, 1:ListView,ListView1    ;切换到窗口列表以设置数据

		GuiControl,,Title,%OutWin1%
		OutWin4=%WinX%,%WinY%
		OutWin5=%WinW%,%WinH%
		OutWin6_X:=OutX-WinX, OutWin6_Y:=OutY-WinY
		OutWin6=x%OutWin6_X% y%OutWin6_Y%
		WinGet,OutWin7, Style,ahk_id %OutWin3%    ;窗口样式
		WinGet,OutWin8, ExStyle,ahk_id %OutWin3%    ;窗口扩展样式
		WinGet,OutWin9,PID,ahk_id %OutWin3%    ;窗口进程PID
		WinGet,OutWin10,ProcessName,ahk_id %OutWin3%    ;窗口进程名
		WinGet,OutWin11,ProcessPath,ahk_id %OutWin3%    ;窗口进程路径
		WinGet,OutWin12,TransColor,ahk_id %OutWin3%        ;获取窗口的透明色
		OutWin13=%OutX% , %OutY%
		PixelGetColor,OutWin14,%OutX%,%OutY%,Slow RGB ;获取鼠标下RGB颜色值
		PixelGetColor,OutWin15,%OutX%,%OutY%,Slow ;获取鼠标下BGR颜色值
		WinGet,OutWin17,Transparent,ahk_id %OutWin3%        ;获取窗口的透明度
		if OutWin16=
			OutWin16=255
		GuiControl, Enable,Slider1
		GuiControl, ,Slider1,%OutWin16%
		GuiControl,,Text_t,透明度(%OutWin16%):
		loop,%ListView1_Text_A0%
			LV_Modify(A_Index,"Col2",OutWin%A_Index%)
		LV_ModifyCol()
		;=============设置控件列表的数据===================
		;~ OutCtrl1=        ;控件类别名
		;~ OutCtrl2=        ;控件文本
		;~ OutCtrl3=        ;控件编号
		;~ OutCtrl4=        ;控件句柄
		;~ OutCtrl5=        ;控件坐标
		;~ OutCtrl6=        ;控件大小
		;~ OutCtrl7=        ;控件内点击坐标
		;~ OutCtrl8=        ;控件样式
		;~ OutCtrl9=        ;控件扩展样式
		;===========================================
		Gui, 1:ListView,ListView2    ;切换到控件列表以设置数据
		if (OutCtrl1!=""){ ;如果控件类别名不为空

			ControlGetText,OutCtrl2,%OutCtrl1%,ahk_id %OutWin3%    ;获取控件文本
			ControlGet,OutCtrl4,Hwnd,,%OutCtrl1%,ahk_id %OutWin3%    ;控件句柄
			OutCtrl3 := DllCall("GetDlgCtrlID", "uint", OutCtrl4)    ;控件ID
			if (OutCtrl3<=0) ;如果获取的控件ID小于0就把控件ID变量置空
				OutCtrl3=
			if (OutCtrlX!="") {
				OutCtrl5=%OutCtrlX%,%OutCtrlY%
				OutCtrl6=%OutCtrlW%,%OutCtrlH%
				if (TABVar<6) ;
					Gui2Show(WinX+OutCtrlX,WinY+OutCtrlY,OutCtrlW,OutCtrlH)
			}else{
				OutCtrl5=
				OutCtrl6=
			}

			if (OutCtrl6!="") {     ;控件内点击坐标
				if (OutX-(WinX+OutCtrlX)>=0) {
					OutCtrl7_X:=OutX-(WinX+OutCtrlX)
					OutCtrl7_Y:=OutY-(WinY+OutCtrlY)
					OutCtrl7=x%OutCtrl7_X% y%OutCtrl7_Y%
				}else
					OutCtrl7=
			}else
				OutCtrl7=
			ControlGet,OutCtrl8,Style,,%OutCtrl1%,ahk_id %OutWin3%    ;控件样式
			ControlGet,OutCtrl9,ExStyle,,%OutCtrl1%,ahk_id %OutWin3%    ;控件扩展样式
			;上面所获取的数据变量名都设置为 同变量名+序号 是为了这里能两句命令就能解决复赋值问题
			loop,%ListView2_Text_A0%
				LV_Modify(A_Index,"Col2",OutCtrl%A_Index%)
			LV_ModifyCol() ;重新调整列宽
			;~ if (TABVar=1) ;如果当前标签是第1个,
			;~ GuiControl, Choose, Tab1,2 ;激活第2个标签页
			;===========================================
		}else{
			;如果控件类别名为空的,控件标签页中全部置空
			loop,%ListView2_Text_A0%
				LV_Modify(A_Index,"Col2","")
			;~ if (TABVar=2) ;如果当前标签是第2个,
			;~ GuiControl, Choose, Tab1,1 ;激活第1个标签页
		}
		;===========================================
		Gui, 1:ListView,ListView3 ;切换到列表控件3
		loop,%ListView3_Text_A0% {
			LV_GetText(LV_TEXT,A_Index,2)
			;~ MsgBox,%LV_TEXT%
			if (OutWin7 & LV_TEXT or OutWin8 & LV_TEXT)
				LV_Modify(A_Index,"Check")
			else
				LV_Modify(A_Index,"-Check")
		}
		LV_ModifyCol()
		;=============设置可见文本的数据===================
		DetectHiddenText,Off
		WinGetText,OutWinText_Visible,ahk_id %OutWin3%
		GuiControl,,Visible_text,%OutWinText_Visible%
		;=============设置全部文本的数据===================
		DetectHiddenText,On
		WinGetText,OutWinText_Hidden,ahk_id %OutWin3%
		GuiControl,,Hidden_text,%OutWinText_Hidden%
		;===========================================
		Gui, 1:ListView,ListView4 ;切换到列表控件4 类别名|ID|句柄|文本|
		WinGet,CtrList,ControlList,ahk_id %OutWin3%
		LV_Delete()
		loop, Parse,CtrList,`n
		{
			ControlGet,CtrlHwnd,Hwnd,,%A_LoopField%,ahk_id %OutWin3%
			CtrlID:= DllCall("GetDlgCtrlID",  "uint", CtrlHwnd)
			if (CtrlID<=0)
				CtrlID=
			ControlGetText,CtrlText,%A_LoopField%,ahk_id %OutWin3%
			ControlGet,Visible,Visible,,%A_LoopField%,ahk_id %OutWin3%
			if (Visible=1)
				Visible=Check
			else if (Visible=0)
				Visible=-Check
			LV_Add(Visible,A_LoopField,CtrlID,CtrlHwnd,CtrlText)
			LV_ModifyCol(1,"","类别名[列表](" A_Index ")")
		}
		LV_ModifyCol()
	}
	;取元素集合序号
	eletag:=wb.document.GetElementsByTagName(ele.tagname)
	loop % eletag.length
		if (eletag.item(A_Index-1).id=ele.id and eletag.item(A_Index-1).classname=ele.classname and eletag.item(A_Index-1).name=ele.name  `
			and eletag.item(A_Index-1).innertext=ele.innertext  and eletag.item(A_Index-1).outerhtml=ele.outerhtml `
			and eletag.item(A_Index-1).target=ele.target and eletag.item(A_Index-1).title=ele.title and eletag.item(A_Index-1).outertext=ele.outertext){
			global TagIndex:=A_Index-1
	break
	}
Gui, 1:ListView,ListView5    ;切换到窗口列表以设置数据
LV_ModifyCol(2,"","属性值 (" eletag.length-1 "/" TagIndex ")" ), Generate()
return
_LV_GetText(Index,Col=1) {
	LV_GetText(sText,Index,Col)
	return sText
}
Button1:
	Generate()
return
_MenuIsCheck( ThisMenu, ThisMenuItem, ValueName) { ;从注册表读取属性
	RegRead,ThisCheck,HKCU,Software\AutoHotKey\AHKInfo,%ValueName%
	if (ThisCheck=1) {
		Menu,%ThisMenu%,Check,%ThisMenuItem%
		ErrorLevel=1
	}else if (ThisCheck=0) {
		Menu,%ThisMenu%,UnCheck,%ThisMenuItem%
		ErrorLevel=0
	}else
		ErrorLevel=-1
}
_RegW( ValueName, value ) { ;写注册表
	RegWrite,REG_DWORD ,HKCU,Software\AutoHotKey\AHKInfo,%ValueName%,%value%
}
_RegR( ValueName) {    ;读注册表
	RegRead,Outvalue,HKCU,Software\AutoHotKey\AHKInfo,%ValueName%
	return %Outvalue%
}
IsMenuItemChecked( MenuPos, SubMenuPos, hWnd ) { ; 检查菜单项是否选中,返回1或0
	hMenu :=DllCall("GetMenu", "UInt",hWnd ), hSubMenu := DllCall("GetSubMenu", "UInt",hMenu, "Int",MenuPos ), VarSetCapacity(mii, 48, 0), NumPut(48, mii, 0), NumPut(1, mii, 4), DllCall( "GetMenuItemInfo", "UInt",hSubMenu, "UInt",SubMenuPos, "Int", 1, "UInt",&mii )
	return ( NumGet(mii, 12) & 0x8 ) ? 1 : 0
}
EmptyMem(PID="AHK Rocks"){ ;释放内存
	pid:=(pid="AHK Rocks") ? DllCall("GetCurrentProcessId") : pid, h:=DllCall("OpenProcess", "UInt", 0x001F0FFF, "Int", 0, "Int", pid), DllCall("SetProcessWorkingSetSize", "UInt", h, "Int", -1, "Int", -1), DllCall("CloseHandle", "Int", h)
}
_ToolTip(Text,OutTime=3000) { ;自动消失的ToolTip
	ToolTip,%Text%
	SetTimer, RemoveToolTip, %OutTime%
}
RemoveToolTip:
	SetTimer, RemoveToolTip, Off
	ToolTip
return
Gui2Show(x,y,w,h) {
	wq := w*2
	Gui, 2:Show,NA x%x% y%y% w%wq% h%h%
	Sleep,300
	Gui, 2:Hide
}
;字符串转二进制
StrToBin(Str) {
	XMLDOM:=ComObjCreate("Microsoft.XMLDOM"), xmlver:="<?xml version=`"`"1.0`"`"?>"
	XMLDOM.loadXML(xmlver), Pic:=XMLDOM.createElement("pic"), Pic.dataType:="bin.hex", pic.nodeTypedValue := Str, StrToByte := pic.nodeTypedValue
	return StrToByte
}
; 数据流保存为文件
BYTE_TO_FILE(body, filePath) {
	Stream := ComObjCreate("Adodb.Stream"), Stream.Type := 1, Stream.Open(), Stream.Write(body), Stream.SaveToFile(filePath,2), Stream.Close()
}
_IEObjGetFromHwnd(h_IECtrl) {
	static Msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
	SendMessage, Msg, 0, 0, , ahk_id %h_IECtrl%
	if (ErrorLevel = "FAIL")
		return
	lResult := ErrorLevel, VarSetCapacity(GUID, 16, 0), GUID := IID_IHTMLDocument2, sGUID := "{332C4425-26CB-11D0-B483-00C04FD90119}", CLSID := DllCall("ole32\CLSIDFromString", "wstr", sGUID, "ptr", &GUID) >= 0 ? &GUID : "", DllCall("oleacc\ObjectFromLresult", "ptr", lResult, "ptr", CLSID, "ptr", 0, "ptr*", pDoc)
	static IID_IWebBrowserApp := "{0002DF05-0000-0000-C000-000000000046}"
	static SID_SWebBrowserApp := IID_IWebBrowserApp
	ComObjError(false), pWeb := ComObjQuery(pDoc, SID_SWebBrowserApp, IID_IWebBrowserApp), ObjRelease(pDoc)
	static VT_DISPATCH := 9, F_OWNVALUE := 1
	oIE := ComObjParameter(VT_DISPATCH, pWeb, F_OWNVALUE)
	return, oIE
}

  

 

/*
©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©
©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©© AhkSpy ©©
©©©©©©©©©©©     ©   ©©©©©©   ©©©©©©©©        ©©©©©©©©©©©©©©©©©©©©©©©
©©©©©©©©©©      ©   ©©©©©©   ©©©©©©©    ©©    ©©©©©©©©©©©©©©©©©©©©©©
©©©©©©©©©       ©   ©©©©©©   ©©©©©©©     ©©©©©©©©©©©©©©©©©©©©©©©©©©©
©©©©©©©©    ©   ©       ©©   ©©©  ©©©       ©©©       ©©   ©©   ©©©©
©©©©©©©    ©©   ©   ©    ©   ©    ©©©©©©      ©   ©    ©   ©©   ©©©©
©©©©©©    ©©©   ©   ©©   ©       ©©©©©©©©©    ©   ©©   ©   ©©   ©©©©
©©©©©           ©   ©©   ©   ©    ©©    ©©    ©   ©    ©    ©   ©©©©
©©©©    ©©©©©   ©   ©©   ©   ©©©  ©©©        ©©       ©©©       ©©©©
©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©   ©©©©©©©©©©©   ©©©©
©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©   ©©©©©©   ©    ©©©©
©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©   ©©©©©©©      ©©©©©
©© AhkSpy ©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©
©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©

    Автор - serzh82saratov
    E-Mail: serzh82saratov@mail.ru

    Благодарность Malcev, teadrinker, YMP, Irbis за их решения
    Описание - http://forum.script-coding.com/viewtopic.php?pid=72459#p72459
    Обсуждение - http://forum.script-coding.com/viewtopic.php?pid=72244#p72244
    Обсуждение на офф. форуме- https://autohotkey.com/boards/viewtopic.php?f=6&t=52872
    Актуальный исходник - https://raw.githubusercontent.com/serzh82saratov/AhkSpy/master/AhkSpy.ahk
*/


Global AhkSpyVersion := 4.76

	; ___________________________ Caption _________________________________________________

ComObjError(false)

Global WS_EX_APPWINDOW := 0x40000, WS_CHILDWINDOW := 0x40000000, WS_EX_LAYERED := 0x80000
		, WS_EX_TRANSPARENT := 0x20, WS_POPUP := 0x80000000, WS_EX_NOACTIVATE := 0x8000000

p1 = %1%
If (p1 = "Zoom")
{  
	Gosub ShowZoom 
	Return
}

SingleInstance()
#NoEnv
#UseHook
#KeyHistory 0
#Requires AutoHotkey v1.1.33+

SetBatchLines, -1
ListLines, Off
DetectHiddenWindows, On
CoordMode, Pixel
CoordMode, Menu

Gosub, CheckAhkVersion
Menu, Tray, UseErrorLevel
Menu, Tray, Icon, Shell32.dll, % A_OSVersion = "WIN_XP" ? 222 : 278

Global Path_User := A_AppData "\AhkSpy"
If !InStr(FileExist(Path_User), "D")
	FileCreateDir, % Path_User


Global MemoryFontSize := IniRead("MemoryFontSize", 0)
	, FontBold := IniRead("FontBold", 0)
	, FontSize := MemoryFontSize ? IniRead("FontSize", "15") : 15			;;  Размер шрифта
	, FontFamily :=  "Arial"				;;  Шрифт - Times New Roman | Georgia | Myriad Pro | Arial
	, FontWeight := FontBold ? 900 : 500	;;  Насыщенность шрифта
	, HeigtButton := 30						;;  Высота кнопок
	, RangeTimer := 100						;;  Период опроса данных, увеличьте на слабом ПК
	HeightStart := 530						;;  Высота окна при старте
	wKey := 136								;;  Ширина кнопок
	wColor := wKey // 2						;;  Ширина цветного фрагмента

DarkTheme := IniRead("DarkTheme", 0)
If !DarkTheme
{
	Global ColorFont := "000000"			;;  Цвет шрифта
	, ColorBg := "FFFFFF"					;;  Цвет фона          "F0F0F0" E4E4E4     F8F8F8
	, ColorBgPaused := "f7f7f7"				;;  Цвет фона при паузе     F0F0F0
	, ColorBgModeButton := "f7f7f7"			;;  E1E1E1
	, ColorSelModeButton := "A9D186"		;;  Цвет фона кнопки текущего режима
	, ColorSelMouseHover := "3399FF"		;;  Цвет фона элемента при наведении мыши  3399FF   96C3DC F9D886 8FC5FC AEC7E1
	, ColorSelMouseHoverText := ColorBg		;;  Цвет текста элемента при наведении мыши     96C3DC F9D886 8FC5FC AEC7E1
	, ColorSelButton := "96C3DC"			;;  Цвет фона при нажатии на кнопки
	, ColorSelAnchor := "FFFF80"			;;  Цвет фона заголовка для якоря
	, ColorHighLightBckg := "FFE0E0"		;;  Цвет фона некоторых абзацев
	, ColorDelimiter := "E14B30"			;;  Цвет шрифта разделителя заголовков и параметров
	, ColorTitle := "27419B"				;;  Цвет шрифта заголовка
	, ColorLineTitles := "444499"			;;  Цвет линии заголовка
	, ColorParam := "189200"				;;  Цвет шрифта параметров
	, ColorErrorAccPath := "ff0000"
	, ColorErrorAccMarquee := "ffcc00"
	, ColorErrorAccMarquee := "ffcc00"
	, ColorStyleComment1 := "f0f0f0"
	, ColorStyleComment2 := "C0C0C0" 
	, ColorSelectedFind := "6666FF" 
	, ColorBorderHoverInput := "4A8DFF"
	, ColorPreOverflowHide := "E2E2E2" 
	, ColorScrollArrows := "686868" 
	, ColorScrollBack := "F0F0F0" 
	, ColorScrollFace := "CDCDCD" 
}
Else 
{
	Global ColorFont := "FFFFFF"			;;  Цвет шрифта
	, ColorBg := "000000"					;;  Цвет фона          "F0F0F0" E4E4E4     F8F8F8  
	, ColorBgPaused := "080808"				;;  Цвет фона при паузе     F0F0F0
	, ColorBgModeButton := "000000"			;;  000000
	, ColorSelModeButton := "469EE1"		;;  Цвет фона кнопки текущего режима
	, ColorSelMouseHover := "FDE182"		;;  Цвет фона элемента при наведении мыши     96C3DC F9D886 8FC5FC AEC7E1
	, ColorSelMouseHoverText := "000000"	;;  Цвет текста элемента при наведении мыши     96C3DC F9D886 8FC5FC AEC7E1
	, ColorSelButton := "693C23"			;;  Цвет фона при нажатии на кнопки
	, ColorSelAnchor := "E8BD7D"			;;  Цвет фона заголовка для якоря   E14B30
	, ColorHighLightBckg := "001F1F"		;;  Цвет фона некоторых абзацев
	, ColorDelimiter := "1EB4CF"			;;  Цвет шрифта разделителя заголовков и параметров
	, ColorTitle := "6BB1E7"				;;  Цвет шрифта заголовка   D8BE64
	, ColorLineTitles := "00FFFF"			;;  Цвет линии заголовка
	, ColorParam := "8EC461"				;;  Цвет шрифта параметров   E76DFF
	, ColorErrorAccPath := "00FFFF"
	, ColorErrorAccMarquee := "0033FF"
	, ColorErrorAccMarquee := "0033FF"
	, ColorStyleComment1 := "0F0F0F"
	, ColorStyleComment2 := "3F3F3F" 
	, ColorSelectedFind := "999900" 
	, ColorBorderHoverInput := "B57200"
	, ColorPreOverflowHide := "1D1D1D" 
	, ColorScrollArrows := "979797" 
	, ColorScrollBack := "0F0F0F" 
	, ColorScrollFace := "323232" 
}
Global ColorBgOriginal := ColorBg

Global ThisMode := IniRead("StartMode", "Control"), LastModeSave := (ThisMode = "LastMode")
, ThisMode := ThisMode = "LastMode" ? IniRead("LastMode", "Control") : ThisMode, CheckAhkNewVersion := IniRead("CheckAhkNewVersion", 0) 
, ActiveNoPause := IniRead("ActiveNoPause", 0), MemoryPos := IniRead("MemoryPos", 0), MemorySize := IniRead("MemorySize", 0)
, MemoryZoomSize := IniRead("MemoryZoomSize", 0), MemoryStateZoom := IniRead("MemoryStateZoom", 0), StateLight := IniRead("StateLight", 1)
, StateLightAcc := IniRead("StateLightAcc", 1), SendCode := IniRead("SendCode", "vk"), StateLightMarker := IniRead("StateLightMarker", 1)
, StateUpdate := IniRead("StateUpdate", 0), SendMode := IniRead("SendMode", "send"), SendModeStr := Format("{:L}", SendMode)
, AnchorFullScroll := IniRead("AnchorFullScroll", 1), MemoryAnchor := IniRead("MemoryAnchor", 1), MenuIdView := IniRead("MenuIdView", 0)
, StateAllwaysSpot := IniRead("AllwaysSpot", 0), w_ShowStyles := IniRead("w_ShowStyles", 0), MarkerInvertFrame := IniRead("MarkerInvertFrame", 1)
, c_ShowStyles := IniRead("c_ShowStyles", 0), ViewStrPos := IniRead("ViewStrPos", 0), OnlyShiftTab := IniRead("OnlyShiftTab", 0)
, WordWrap := IniRead("WordWrap", 0), PreMaxHeightStr := IniRead("MaxHeightOverFlow", "1 / 3"), UpdRegister := IniRead("UpdRegister2", 0)
, UseUIA := IniRead("UseUIA", 0), UIAAlienDetect := IniRead("UIAAlienDetect", 0), MinimizeEscape := IniRead("MinimizeEscape", 0)
, DetectHiddenText := IniRead("DetectHiddenText", "on"), MoveTitles := IniRead("MoveTitles", 1), DynamicAccPath := IniRead("DynamicAccPath", 0)
, DynamicControlPath := IniRead("DynamicControlPath", 0), ActiveScriptAllowChange := IniRead("ActiveScriptAllowChange", 1)

, UpdRegisterLink := "https://u.to/zeONFA", testvar, oDivOld, oDivNew, DivWorkIndex := 2, oDivWork1, oDivWork2

, FontDPI := {96:12,120:10,144:8,168:6}[A_ScreenDPI], ScrollPos := {}, AccCoord := [], oOther := {}
, oFind := {}, Edits := [], oMS := {}, oMenu := {}, oPubObj := {}, osCoords := {}

, ClipAdd_Before := 0, ClipAdd_Delimiter := "`r`n"
, HTML_Win, HTML_Control, HTML_Hotkey, rmCtrlX, rmCtrlY, widthTB, FullScreenMode, hColorProgress, hFindAllText, MsgAhkSpyZoom
, hGui, hTBGui, hActiveX, hFindGui, oDoc, ShowMarker, isFindView, isIE, isPaused, PreMaxHeight := MaxHeightStrToNum()
, PreOverflowHide := !!PreMaxHeight, DecimalCode, GetVKCodeNameStr, GetSCCodeNameStr
, oPubObjGUID, oObjActive := {}, oJScript, oBody, isConfirm, isAhkSpy := 1, TitleText, FreezeTitleText, TitleTextP1, exUIASub
, Shift_Tab_Down, hButtonButton, hButtonControl, hButtonWindow
, TitleTextP2 := TitleTextP2_Reserved := "     ( Shift+Tab - Freeze | RButton - CopySelected | Pause - Pause )     v" AhkSpyVersion
, Sleep, oShowMarkers, oShowAccMarkers, oShowMarkersEx, hDCMarkerInvert, hMarkerGui

#Include *i %A_AppData%\AhkSpy\IncludeSettings.ahk

Global _S1 := "<span>", _S2 := "</span>", _DB := "<span style='position: relative; margin-right: 1em;'></span>"

, _BT1 := "<span class='button' unselectable='on' oncontextmenu='return false' contenteditable='false' ", _BT2 := "</span>"

  ;;	Решает проблему запуска ресайза кнопки когда выделен текст, но не получается установить свой курсор
, _BP1 := "<span contenteditable='false'><span class='button' unselectable='on' oncontextmenu='return false'"
	. " contenteditable='false' style='color: #" ColorParam "' name='pre' ", _BP2 := "</span></span>"
  ;;	Прежнее
; , _BP1 := "<span contenteditable='false' oncontextmenu='return false' class='BB'>" _BT1 "style='color: #" ColorParam "' name='pre' ", _BP2 := "</span></span>"

, _BB1 := "<span contenteditable='false' oncontextmenu='return false' class='BB' style='height: 0px;'>" _BT1 " ", _BB2 := "</span></span>"
, _T1 := "<span class='box'><span class='line'><span class='hr'></span><span class='con'><span class='title' ", _T2 := "</span></span></span><br>"
, _T1P := " style='color: #" ColorParam "' "
, _T0 := "<span class='box'><span class='hr'></span></span><span id='id_T0' style='position: absolute'></span>"
, _PRE1 := "<pre contenteditable='true'>", _PRE2 := "</pre>"
, _LPRE := "<pre contenteditable='true' class='lpre'"
, _DP := "  <span style='color: #" ColorDelimiter "'>&#9642</span>  "
, _StIf := "    <span class='QStyle1'>&#9642</span>    <span class='QStyle2' name='MS:'>"
, _BR := "<p class='br'></p>", _DN := "`n", _DN2 := "<div style='height: 0.50em`;'></div>" 

, _PreOverflowHideCSS := ".lpre {max-width: 99`%; max-height: " PreMaxHeight "px; overflow: auto; border: 1px solid #" ColorPreOverflowHide ";}"

, _BodyWrapCSS := "body, .divwork {word-wrap: break-word`; overflow-x: 'hidden';} .lpre {overflow-x: hidden`;}"

, _ButAccViewer := ExtraFile("AccViewer Source") ? _DB _BT1 " id='run_AccViewer'> run accviewer " _BT2 : ""
, _ButiWB2Learner := ExtraFile("iWB2 Learner") ? _DB _BT1 " id='run_iWB2Learner'> run iwb2 learner " _BT2 : ""
, _ButWindow_Detective := FileExist(Path_User "\Window Detective.lnk") ? _DB _BT1 " id='run_Window_Detective'> run window detective " _BT2 : ""
, oZBID := {0:"ZBID_DEFAULT",1:"ZBID_DESKTOP",2:"ZBID_UIACCESS",3:"ZBID_IMMERSIVE_IHM",4:"ZBID_IMMERSIVE_NOTIFICATION",5:"ZBID_IMMERSIVE_APPCHROME"
	,6:"ZBID_IMMERSIVE_MOGO",7:"ZBID_IMMERSIVE_EDGY",8:"ZBID_IMMERSIVE_INACTIVEMOBODY",9:"ZBID_IMMERSIVE_INACTIVEDOCK"
	,10:"ZBID_IMMERSIVE_ACTIVEMOBODY",11:"ZBID_IMMERSIVE_ACTIVEDOCK",12:"ZBID_IMMERSIVE_BACKGROUND",13:"ZBID_IMMERSIVE_SEARCH"
	,14:"ZBID_GENUINE_WINDOWS",15:"ZBID_IMMERSIVE_RESTRICTED",16:"ZBID_SYSTEM_TOOLS",17:"ZBID_LOCK",18:"ZBID_ABOVELOCK_UX"}
	
If UseUIA
	exUIASub := new UIASub

BLGroup := ["Backlight allways","Backlight disable","Backlight hold shift button"]
oOther.anchor := {}, oOther.CurrentProcessId := DllCall("GetCurrentProcessId")

If MemoryAnchor
{
	If oOther.anchor["Win_text"] := IniRead("Win_Anchor")
		oOther.anchor["Win"] := 1
	If oOther.anchor["Control_text"] := IniRead("Control_Anchor")
		oOther.anchor["Control"] := 1
} 



FixIE()
SeDebugPrivilege() 
OnExit("Exit")

CreateMarkerInvert()
ShowMarkersCreate("oShowAccMarkers", "26419F")  
ShowMarkersCreate("oShowMarkers", "E14B30")

Gui, +AlwaysOnTop +HWNDhGui +ReSize -DPIScale +Owner%hMarkerGui% +E%WS_EX_APPWINDOW% ;   +E%WS_EX_NOACTIVATE%
Gui, Color, %ColorBgPaused%
ActiveScriptAllow() 
Gui, Add, ActiveX, Border voDoc HWNDhActiveX x0 y+0, HTMLFile
ActiveScriptAllow(1)

;	https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.htmlwindow?view=netframework-4.8
;	https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model

LoadJScript()
oBody := oDoc.body 
oJScript := oDoc.Script
oJScript.WordWrap := WordWrap
oJScript.MoveTitles := MoveTitles
ComObjConnect(oDoc, Events)

OnMessage(0x133, "WM_CTLCOLOREDIT")
OnMessage(0x201, "WM_LBUTTONDOWN") 
OnMessage(0x204, "WM_RBUTTONDOWN") 
OnMessage(0x7B, "WM_CONTEXTMENU")
OnMessage(0xA1, "WM_NCLBUTTONDOWN")
OnMessage(0x6, "WM_ACTIVATE")
OnMessage(0x47, "WM_WINDOWPOSCHANGED")
OnMessage(0x4a, "WM_COPYDATA")   

;; OnMessage(WM_WINDOWPOSCHANGING := 0x46, "WM_WINDOWPOSCHANGED") 
;; OnMessage(WM_MOVING := 0x216, "WM_WINDOWPOSCHANGED")
;; OnMessage(WM_MOVE := 0x03, "WM_WINDOWPOSCHANGED")

OnMessage(MsgAhkSpyZoom := DllCall("RegisterWindowMessage", "Str", "MsgAhkSpyZoom"), "MsgZoom")
DllCall("PostMessage", "Ptr", A_ScriptHWND, "UInt", 0x50, "UInt", 0,	 "UInt", 0x409) ;; eng layout
SetWinEventHook("EVENT_OBJECT_CLOAKED", 0x8017)
SetWinEventHook("EVENT_OBJECT_UNCLOAKED", 0x8018) 

Gui, TB: +HWNDhTBGui -Caption -DPIScale +Parent%hGui% +%WS_CHILDWINDOW% -%WS_POPUP% +E%WS_EX_NOACTIVATE%
Gui, TB: Color, %ColorBg%
Gui, TB: Font, % " s" FontDPI, Verdana

Gui, TB: Add, Progress, % "  x1 y0 h" HeigtButton-1 " w" wKey "  vColor_Window Background" ColorBgModeButton  
Gui, TB: Add, Text, % "Border hwndhButtonWindow +0x201 c" ColorFont " BackGroundTrans xp yp hp wp", Window

Gui, TB: Add, Progress, % "x+1 y0 h" HeigtButton-1 " w" wKey " vColor_Control Background" ColorBgModeButton  
Gui, TB: Add, Text, % "Border hwndhButtonControl +0x201 c" ColorFont " BackGroundTrans xp yp hp wp", Control

Gui, TB: Add, Progress, % "x+1 y0 h" HeigtButton-1 " w" HeigtButton " vColor_Zoom Background" ColorBgModeButton  
Gui, TB: Add, Text, % "Border hwndhButtonZoom +0x201 c" ColorFont " BackGroundTrans xp yp hp wp", % Chr("0x1F50D") ; 🔍

Gui, TB: Add, Progress, % "x+1 y0 h" HeigtButton-1 " w" wColor " vColorProgress HWNDhColorProgress c" ColorBgOriginal, 100

Gui, TB: Add, Progress, % "x+1 y0 h" HeigtButton-1 " w" wKey " vColor_Button Background" ColorBgModeButton  
Gui, TB: Add, Text, % "Border hwndhButtonButton +0x201 c" ColorFont " BackGroundTrans xp yp hp wp", Button

Gui, TB: Show, % "x0 y0 NA h" HeigtButton " w" widthTB := wKey * 3 + wColor + HeigtButton + 6

Gui, F: +HWNDhFindGui -Caption -DPIScale +Parent%hGui% +%WS_CHILDWINDOW% -%WS_POPUP%
Gui, F: Color, %ColorBgPaused%
Gui, F: Font, % " s" FontDPI
Gui, F: Add, Edit, x1 y0 w180 h26 gFindNew WantTab HWNDhFindEdit
SendMessage, 0x1501, 1, "Find to page",, ahk_id %hFindEdit%   ;; EM_SETCUEBANNER
Gui, F: Add, UpDown, -16 Horz Range0-1 x+0 yp h26 w52 gFindNext vFindUpDown
GuiControl, F: Move, FindUpDown, h26 w52
Gui, F: Font, % " s" FontDPI
; 0x201 CENTER wh
Gui, F: Add, Text, x+10 yp+1 h24 +0x201 gFindOption c%ColorFont%, % " case sensitive "
Gui, F: Add, Text, x+10 yp hp +0x201 gFindOption c%ColorFont%, % " whole word "
; BS_VCENTER := 0xC00, BS_CENTER := 0x300
Gui, F: Add, Button, % "+0x300 +0xC00 yp hp w20 gFindHide x" widthTB - 21 c%ColorFont%, X   
Gui, F: Add, Text, x+10 yp hp +0x201 w152 vFindMatches Left HWNDhFindAllText c%ColorFont%

	; ___________________________ Menu Create _________________________________________________

Menu, Sys, Add, % name := "Backlight allways", % oMenu.Sys[name] := "_Sys_Backlight"
Menu, Sys, Add, % name := "Backlight hold shift button", % oMenu.Sys[name] := "_Sys_Backlight"
Menu, Sys, Add, % name := "Backlight disable", % oMenu.Sys[name] := "_Sys_Backlight"
Menu, Sys, Check, % BLGroup[StateLight]
Menu, Sys, Add
Menu, Sys, Add, % name := "Window or control backlight", % oMenu.Sys[name] := "_Sys_WClight"
Menu, Sys, % StateLightMarker ? "Check" : "UnCheck", % name
Menu, Sys, Add, % name := "Acc object backlight", % oMenu.Sys[name] := "_Sys_Acclight"
Menu, Sys, % StateLightAcc ? "Check" : "UnCheck", % name
Menu, Sys, Add
Menu, Sys, Add, % name := "Spot together (low speed)", % oMenu.Sys[name] := "_Spot_Together"
Menu, Sys, % StateAllwaysSpot ? "Check" : "UnCheck", % name
Menu, Sys, Add, % name := "Work with the active window", % oMenu.Sys[name] := "_Active_No_Pause"
Menu, Sys, % ActiveNoPause ? "Check" : "UnCheck", % name
Menu, Sys, Add, % name := "Spot only Shift+Tab", % oMenu.Sys[name] := "_OnlyShiftTab"
Menu, Sys, % OnlyShiftTab ? "Check" : "UnCheck", % name

If !A_IsCompiled
{
	Menu, Sys, Add
	Menu, Sys, Add, % name := "Check updates", % oMenu.Sys[name] := "_CheckUpdate"
	Menu, Sys, % StateUpdate ? "Check" : "UnCheck", % name
	If StateUpdate
		SetTimer, UpdateAhkSpy, -1000
}
Else
	StateUpdate := 0

Menu, Sys, Add
Menu, Startmode, Add, % name := "Window", % oMenu.Startmode[name] := "_SelStartMode"
Menu, Startmode, Add, % name := "Control", % oMenu.Startmode[name] := "_SelStartMode"
Menu, Startmode, Add, % name := "Button", % oMenu.Startmode[name] := "_SelStartMode"
Menu, Startmode, Add
Menu, Startmode, Add, % name := "Last Mode", % oMenu.Startmode[name] := "_SelStartMode"

Menu, View, Add, % name := "Dynamic control path (low speed)", % oMenu.View[name] := "_DynamicControlPath"
Menu, View, % DynamicControlPath ? "Check" : "UnCheck", % name
Menu, View, Add, % name := "Dynamic accesible path (low speed, not recommended)", % oMenu.View[name] := "_DynamicAccPath"
Menu, View, % DynamicAccPath ? "Check" : "UnCheck", % name
Menu, View, Add
Menu, View, Add, % name := "Use UI Automation interface", % oMenu.View[name] := "_UseUIA"
Menu, View, % UseUIA ? "Check" : "UnCheck", % name
Menu, View, Add, % name := "UIA change background for different hwnd", % oMenu.View[name] := "_UIAAlienDetect"
Menu, View, % UIAAlienDetect ? "Check" : "UnCheck", % name  
Menu, View, Add  
Menu, View, Add, % name := "Dark theme (reload needed)", % oMenu.View[name] := "_DarkTheme"
Menu, View, % DarkTheme ? "Check" : "UnCheck", % name 
Menu, View, Add, % name := "Font bold (reload needed)", % oMenu.View[name] := "_FontBold"
Menu, View, % FontBold ? "Check" : "UnCheck", % name 
Menu, View, Add, % name := "Word wrap", % oMenu.View[name] := "_WordWrap"
Menu, View, % WordWrap ? "Check" : "UnCheck", % name
Menu, View, Add, % name := "View coordinates string extended", % oMenu.View[name] := "_ViewStrPos"
Menu, View, % ViewStrPos ? "Check" : "UnCheck", % name
Menu, View, Add, % name := "Flash edge", % oMenu.View[name] := "_MarkerInvertFrame"
Menu, View, % MarkerInvertFrame ? "Check" : "UnCheck", % name
Menu, View, Add, % name := "Full scroll with existing anchor", % oMenu.View[name] := "_AnchorFullScroll"
Menu, View, % AnchorFullScroll ? "Check" : "UnCheck", % name  
Menu, View, Add, % name := "Moving titles", % oMenu.View[name] := "_MoveTitles"
Menu, View, % MoveTitles ? "Check" : "UnCheck", % name
Menu, Sys, Add, View settings, :View

Menu, Overflow, Add, % name := "Switch off", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 1", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 2", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 3", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 4", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 5", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 6", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 8", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 10", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 15", % oMenu.Overflow[name] := "_MenuOverflowLabel" 
Menu, Overflow, Check, %PreMaxHeightStr%
; Menu, Overflow, Color, % ColorBgOriginal
Menu, View, Add, Big text overflow hide, :Overflow

Menu, Sys, Add, Start mode, :Startmode
Menu, Startmode, Check, % {"Win":"Window","Control":"Control","Hotkey":"Button","LastMode":"Last Mode"}[IniRead("StartMode", "Control")]

Menu, Script, Add, Reload, Reload
Menu, Script, Add, Exit, Exit
Menu, Script, Add
Menu, Script, Add, % name := "Open script dir", % oMenu.Script[name] := "Help_OpenScriptDir"
Menu, Script, Add, % name := "Open user dir", % oMenu.Script[name] := "Help_OpenUserDir"
Menu, Script, Add
Menu, Script, Add, % name := "Remember position", % oMenu.Script[name] := "_MemoryPos"
Menu, Script, % MemoryPos ? "Check" : "UnCheck", % name
Menu, Script, Add, % name := "Remember size", % oMenu.Script[name] := "_MemorySize"
Menu, Script, % MemorySize ? "Check" : "UnCheck", % name
Menu, Script, Add, % name := "Remember font size", % oMenu.Script[name] := "_MemoryFontSize"
Menu, Script, % MemoryFontSize ? "Check" : "UnCheck", % name
Menu, Script, Add, % name := "Remember state zoom", % oMenu.Script[name] := "_MemoryStateZoom"
Menu, Script, % MemoryStateZoom ? "Check" : "UnCheck", % name
Menu, Script, Add, % name := "Remember zoom size", % oMenu.Script[name] := "_MemoryZoomSize"
Menu, Script, % MemoryZoomSize ? "Check" : "UnCheck", % name
Menu, Script, Add, % name := "Remember anchor", % oMenu.Script[name] := "_MemoryAnchor"
Menu, Script, % MemoryAnchor ? "Check" : "UnCheck", % name
Menu, Script, Add
Menu, Script, Add, % name := "Active script allow change", % oMenu.Script[name] := "_ActiveScriptAllowChange"
Menu, Script, % ActiveScriptAllowChange ? "Check" : "UnCheck", % name 
Menu, Script, Add, % name := "Escape button to minimize", % oMenu.Script[name] := "_MinimizeEscape"
Menu, Script, % MinimizeEscape ? "Check" : "UnCheck", % name 
Menu, Sys, Add, Script, :Script

Menu, Help, Add, % name := "Check updates AutoHotkey", % oMenu.Help[name] := "_CheckAhkNewVersion"
Menu, Help, % CheckAhkNewVersion ? "Check" : "UnCheck", % name
If CheckAhkNewVersion
	SetTimer, CheckAhkNewVersion, -3000 
Menu, Help, Add
If FileExist(SubStr(A_AhkPath,1,InStr(A_AhkPath,"\",,0,1)) "AutoHotkey.chm")
	Menu, Help, Add, % name := "AutoHotKey help file", % oMenu.Help[name] := "LaunchHelp"
Menu, Help, Add, % name := "AutoHotKey official help online", % oMenu.Help[name] := "Sys_Help"
Menu, Help, Add, % name := "AutoHotKey russian help online", % oMenu.Help[name] := "Sys_Help"
Menu, Help, Add
Menu, Help, Add, % name := "About", % oMenu.Help[name] := "Sys_Help"
Menu, Help, Add, % name := "About english", % oMenu.Help[name] := "Sys_Help"
Menu, Sys, Add, Help, :Help

Menu, Sys, Add
Menu, Sys, Add, % name := "Pause", % oMenu.Sys[name] := "_PausedScript"
Menu, Sys, Add, % name := "Suspend hotkeys", % oMenu.Sys[name] := "_Suspend"
Menu, Sys, Add, % name := "Default size", % oMenu.Sys[name] := "DefaultSize"
Menu, Sys, Add, % name := "Full screen", % oMenu.Sys[name] := "FullScreenMode"
Menu, Sys, Add, % name := "Find to page", % oMenu.Sys[name] := "_FindView"

; Menu, Sys, Color, % ColorBgOriginal

#Include *i %A_AppData%\AhkSpy\Include.ahk  ;;	Для продолжения выполнения кода используйте GoTo IncludeLabel
IncludeLabel:

Gui, Show, % "NA " (MemoryPos ? " x" IniRead("MemoryPosX", "Center") " y" IniRead("MemoryPosY", "Center") : "")
. (MemorySize ? " h" IniRead("MemorySizeH", HeightStart) " w" IniRead("MemorySizeW", widthTB) : " h" HeightStart " w" widthTB)
Gui, % "+MinSize" widthTB "x" 313

If ThisMode = Hotkey
	Gui, Show
Gosub, Mode_%ThisMode%

Hotkey_Init("Write_HotkeyHTML", "MLRJ")
 
If (MemoryStateZoom && IniRead("ZoomShow", 0))
	AhkSpyZoomShow()
	
WinGetPos, WinX, WinY, WinWidth, WinHeight, ahk_id %hGui%
If !DllCall("WindowFromPoint", "Int64", WinX & 0xFFFFFFFF | WinY << 32)
&& !DllCall("WindowFromPoint", "Int64", (WinX + WinWidth) & 0xFFFFFFFF | (WinY) << 32)
&& !DllCall("WindowFromPoint", "Int64", (WinX + WinWidth) & 0xFFFFFFFF | (WinY + WinHeight) << 32)
&& !DllCall("WindowFromPoint", "Int64", (WinX) & 0xFFFFFFFF | (WinY + WinHeight) << 32)
	Gui, Show, NA xCenter yCenter

If !UpdRegister
	SetTimer, UpdRegister, -1000 
	
WinSet, TransParent, 255, ahk_id %hGui%
DllCall("RedrawWindow", "Ptr", hGui, "Uint", 0, "Uint", 0, "Uint", 0x1|0x4)

; MsgBox % oDoc.documentMode  "`n" oDoc.compatMode  "`n" oDoc.designMode := "On"
Return 

	; ___________________________ Hotkey`s _________________________________________________

#If isAhkSpy && Sleep != 1 && OnlyShiftTab && !ActiveNoPause && !isPaused && ThisMode != "Hotkey" && IsHwndUnderMouse(hColorProgress) && !WinActive("ahk_id" hGui)

MButton:: SetTimer(Func("WM_RBUTTONDOWN").Bind(0, 0, 0, hColorProgress), "-" 1)  ; WM_RBUTTONDOWN(0, 0, 0, hColorProgress)

#If isAhkSpy && Sleep != 1 && OnlyShiftTab && !ActiveNoPause && !isPaused && ThisMode != "Hotkey" && IsHwndUnderMouse(hColorProgress)

MButton::
+MButton::
+RButton:: SetTimer(Func("WM_RBUTTONDOWN").Bind(0, 0, 0, hColorProgress), "-" 1)  ; WM_RBUTTONDOWN(0, 0, 0, hColorProgress)
	
#If Shift_Tab_Work

+Tab:: Return

#If isAhkSpy && Sleep != 1 && ActiveNoPause

+Tab:: Goto PausedScript

#If (isAhkSpy && Sleep != 1 && !isPaused && ThisMode != "Hotkey")

^Tab:: 
	If OnlyShiftTab 
		OnlyShiftTab := 0, oOther.OnlyShiftTabReset := 1 
	TransParent(0) 
	SetTimer, Mod_Up_Wait_And_TransParent, -1
+Tab:: 
SpotProc:
SpotProc2:  
	Shift_Tab_Work := 1 
	If (A_ThisHotkey != "")
		Shift_Tab_Down := 1 
	If (ThisMode = "Control")
		Spot_Control() && (Write_Control(), (StateAllwaysSpot ? Spot_Win() : 0))
	Else 
		Spot_Win() && (Write_Win(), (StateAllwaysSpot ? Spot_Control() : 0))
	If (!WinActive("ahk_id" hGui) && A_ThisLabel != "SpotProc2" && !OnlyShiftTab && !oOther.OnlyShiftTabReset)
	{
		WinActivate ahk_id %hGui%
		GuiControl, 1:Focus, oDoc
	}
	Else
		ZoomMsg(3)
	KeyWait, Tab, T0.1
	Sleep(10)
	Shift_Tab_Work := 0
	Return
	

#Tab Up::
F8 Up:: ChangeMode()

#If isAhkSpy && (StateLight = 3 || Shift_Tab_Down)

~*RShift Up::
~*LShift Up:: 
ShiftUpHide:
	HideAllMarkers(), Shift_Tab_Down := 0, CheckHideMarker()
	Return

#If isAhkSpy && Sleep != 1

Break::
Pause::
PausedScript:
_PausedScript:
	If isConfirm
		Return
	isPaused := !isPaused
	Try SetTimer, Loop_%ThisMode%, % isPaused ? "Off" : "On"
	ZoomMsg(2, isPaused)
	ColorBg := isPaused ? ColorBgPaused : ColorBgOriginal
	oBody.style.backgroundColor := "#" ColorBg
	ChangeCSS("css_ColorBg", ".title, .button, .divwork {background-color: #" ColorBg ";}")
	If (ThisMode = "Hotkey" && WinActive("ahk_id" hGui))
		Hotkey_Hook(!isPaused)
	If (isPaused && !WinActive("ahk_id" hGui))
		(ThisMode = "Control" ? Spot_Win() : ThisMode = "Win" ? Spot_Control() : 0)
	HideAllMarkers(), CheckHideMarker()
	Menu, Sys, % (isPaused ? "Check" : "UnCheck"), Pause
	isPaused ? TaskbarProgress(4, hGui, 100) : TaskbarProgress(0, hGui)
	TitleText := (TitleTextP1 := "AhkSpy - " ({"Win":"Window","Control":"Control","Hotkey":"Button"}[ThisMode]))
	. (TitleTextP2 := (isPaused ? "                Paused..." : TitleTextP2_Reserved))
	SendMessage, 0xC, 0, &TitleText, , ahk_id %hGui%
	PausedTitleText()
	Return

#If isAhkSpy && Sleep != 1 && WinActive("ahk_id" hGui)

^WheelUp::
^WheelDown::
	FontSize := InStr(A_ThisHotkey, "Up") ? ++FontSize : --FontSize
	FontSize := FontSize < 10 ? 10 : FontSize > 24 ? 24 : FontSize 
	oDivWork1.Style.fontSize := FontSize "px"
	oDivWork2.Style.fontSize := FontSize "px"
	TitleText("FontSize: " FontSize)
	If MemoryFontSize
		IniWrite(FontSize, "FontSize") 
	SetTimer, AnchorScroll, -500
	Return

F1::
+WheelUp:: NextLink("-")

F2::
+WheelDown:: NextLink()

F3::
~!WheelUp:: WheelLeft

F4::
~!WheelDown:: WheelRight

F5:: Write_%ThisMode%()		;;  Return original HTML

F6::
^vk46:: _FindView()											;;  Ctrl+F

F7:: AnchorScroll()

F11:: 
	If oOther.ZoomShow && UnderControl(oOther.hZoomLW)
		Return
	FullScreenMode()
	Return

F12:: 
	If oOther.ZoomShow && UnderControl(oOther.hZoomLW)
		Return
	MouseGetPosScreen(x, y), ShowSys(x + 5, y + 5)
	Return

!Space:: SetTimer, ShowSys, -1

Esc::
	If isFindView
		FindHide()
	Else If FullScreenMode
		FullScreenMode()
	Else
		GuiClose()
	Return

+#Tab:: AhkSpyZoomShow()

#If isAhkSpy && Sleep != 1 && IsIEFocus() && (oDoc.selection.createRange().parentElement.isContentEditable)

^+vk41:: oDoc.execCommand("SelectAll")							;;  Ctrl+Shift+A

#If isAhkSpy && Sleep != 1 && IsIEFocus()

^vk41:: R := oBody.createTextRange(), R.moveToElementText(oDivNew), R.select()		;;  Ctrl+A
; ^vk41:: oBody.createTextRange().select()										;;  Ctrl+A

^vk5A:: oDoc.execCommand("Undo")							;;  Ctrl+Z

^vk59:: oDoc.execCommand("Redo")							;;  Ctrl+Y

^vk43:: GetSelected(CopyText) && ((Clipboard := CopyText), ToolTip("copy", 300))		;;  Ctrl+C

^vk56:: ClipPaste()																		;;  Ctrl+V

^vk58:: CutSelection()								;;  Ctrl+X

Del:: DeleteSelection()							;;  Delete

Tab:: PasteStrSelection("    ")							;;  &emsp	"	"  PasteStrSelection("	")

Enter:: PasteHTMLSelection("<br>")

#If isAhkSpy && Sleep != 1 && ThisMode != "Hotkey" && (IsIEFocus() || MS_IsSelection())

#RButton:: ClipPaste()

#If isAhkSpy && Sleep != 1 && ThisMode != "Hotkey" && (IsIEFocus() || MS_IsSelection()) && IsTextArea() && GetSelected(CopyText)

RButton::
^RButton::
	If (A_ThisHotkey = "^RButton")
		CopyText := CopyCommaParam(CopyText)
	Clipboard := CopyText
	ToolTip("copy", 300)
	Return

+RButton:: ClipAdd(CopyText, 1)
^+RButton:: ClipAdd(CopyCommaParam(CopyText), 1)

#If isAhkSpy && Sleep != 1 && ThisMode = "Hotkey" && (IsIEFocus() || MS_IsSelection()) && IsTextArea() && GetSelected(CopyText) ;;	Mode = Hotkey

RButton::
	KeyWait, RButton, T0.3
	If ErrorLevel
		ClipAdd(CopyText, 1)
	Else
		Clipboard := CopyText, ToolTip("copy", 300)
	Return

#If (isAhkSpy && Sleep != 1 && !isPaused && ThisMode != "Hotkey")

+#Up:: MouseStep(0, -1)
+#Down:: MouseStep(0, 1)
+#Left:: MouseStep(-1, 0)
+#Right:: MouseStep(1, 0)
^+#Up:: MouseStep(0, -10)
^+#Down:: MouseStep(0, 10)
^+#Left:: MouseStep(-10, 0)
^+#Right:: MouseStep(10, 0)

#If oJScript.ButtonOver

+LButton::
	oJScript.onmousedown(oJScript.ButtonOver)
	KeyWait LButton
	if !oJScript.ButtonOver
		return 
	obj := Func("ButtonClick").Bind(oJScript.ButtonOver)
	SetTimer, % obj, -100
	; ButtonClick(oJScript.ButtonOver)
	oJScript.onmouseup(oJScript.ButtonOver, 1)
	Return

#If !WinActive("ahk_id" hGui) && IsAhkSpyUnderMouse(hc)

+LButton::  
	If (hc = hButtonButton)
		SetTimer("Mode_Hotkey", -1)
	Else If (hc = hButtonControl)
		SetTimer("Mode_Control", -1)
	Else If (hc = hButtonWindow)
		SetTimer("Mode_Win", -1) 
	Else If (hc = hButtonZoom) 
		SetTimer("AhkSpyZoomShow", -1) 
	Return 
#If

IsAhkSpyUnderMouse(Byref hc) {
	MouseGetPos, , , hw, hc, 2
	Return (hw = hGui)
}

IsHwndUnderMouse(hwnd) {
	MouseGetPos, , , , hc, 2
	Return (hc = hwnd)
}
	; ___________________________ Mode_Win _________________________________________________
	
Mode_Win: 
	If A_GuiControl
		GuiControl, 1:Focus, oDoc
	ZoomMsg(10, 0)
	; oBody.createTextRange().execCommand("RemoveFormat")   
	ColorButton("Window") 
	
	If (ThisMode = "Hotkey")
		Hotkey_Hook(0)
		
	Try SetTimer, Loop_%ThisMode%, Off
	
	ScrollPos[ThisMode, 1] := oDivNew.scrollLeft
	ScrollPos[ThisMode, 2] := oDivNew.scrollTop
	
	If ThisMode != Win
		HTML_%ThisMode% := oDivNew.innerHTML, prNotThisMode := 1
		
	ThisMode := "Win"
	
	If (HTML_Win = "")
		Spot_Win(1)
	Write_Win(prNotThisMode) 
	
	TitleText := (TitleTextP1 := "AhkSpy - Window") . TitleTextP2
	SendMessage, 0xC, 0, &TitleText, , ahk_id %hGui%
	If isFindView
		FindNewText()

Loop_Win:
	If ((WinActive("ahk_id" hGui) && !ActiveNoPause) || Sleep = 1)
		GoTo Repeat_Loop_Win
	If !OnlyShiftTab && Spot_Win()
		Write_Win(), StateAllwaysSpot ? Spot_Control() : 0
Repeat_Loop_Win:
	If (!isPaused && ThisMode = "Win" && !OnlyShiftTab)
		SetTimer, Loop_Win, -%RangeTimer%
	Return

Spot_Win(NotHTML = 0) {
	Static PrWinPID, ComLine, _ComLine, ProcessBitSize, IsAdmin, WinProcessPath, WinProcessName
	
	If NotHTML
		GoTo HTML_Win
	MouseGetPos, , , WinID, hChild, 3

	If (WinID = hGui || WinID = oOther.hZoom || WinID = oOther.hZoomLW)
		Return 0, HideAllMarkers()

	WinGetTitle, WinTitle, ahk_id %WinID%
	WinTitle := TransformHTML(WinTitle)
	WinGetPos, WinX, WinY, WinWidth, WinHeight, ahk_id %WinID%
	WinX2 := WinX + WinWidth - 1, WinY2 := WinY + WinHeight - 1
	WinGetClass, WinClass, ahk_id %WinID%
	oOther.WinClass := WinClass
	WinGet, WinPID, PID, ahk_id %WinID%
	If (WinPID != PrWinPID) {
		GetCommandLineProc(WinPID, _ComLine, ProcessBitSize, IsAdmin)
		ComLine := TransformHTML(_ComLine), PrWinPID := WinPID
		WinGet, WinProcessPath, ProcessPath, ahk_id %WinID%
		Loop, %WinProcessPath%
			WinProcessPath = %A_LoopFileLongPath%
		SplitPath, WinProcessPath, WinProcessName
	}
	If (WinClass ~= "(Cabinet|Explore)WClass")
		CLSID := GetCLSIDExplorer(WinID)
	WinGet, WinCountProcess, Count, ahk_pid %WinPID%
	WinGet, WinStyle, Style, ahk_id %WinID%
	WinGet, WinExStyle, ExStyle, ahk_id %WinID% 
	{
		WinGet, WinTransparent, Transparent, ahk_id %WinID%
		If WinTransparent !=
			TransparentStr := _BP1 "id='set_button_Transparent'>Transparent:</span>" _BP2 "  <span id='get_win_Transparent' name='MS:'>"  WinTransparent "</span>"     
	
		WinGet, WinTransColor, TransColor, ahk_id %WinID%
		If WinTransColor !=
			TransColorStr := _BP1 "id='set_button_TransColor'>TransColor:</span>" _BP2 "  <span id='get_win_TransColor' name='MS:'>"  WinTransColor "</span>"
	
		OwnedId := DllCall("GetWindow", "Ptr", WinID, UInt, 4, "Ptr")
		If OwnedId
			OwnedIdStr := "<span class='param'>Owned Id:</span> <span name='MS:'>" Format("0x{:x}", OwnedId) "</span>"
			
		EX1Str := Add_DP(1, OwnedIdStr, TransparentStr, TransColorStr)
	} 
	WinGet, CountControl, ControlListHwnd, ahk_id %WinID%	
	RegExReplace(CountControl, "m`a)$", "", CountControl)
	GetClientPos(WinID, caX, caY, caW, caH)
	caWinRight := WinWidth - caW - caX , caWinBottom := WinHeight - caH - caY
	loop 1000
	{
		StatusBarGetText, SBFieldText, %A_Index%, ahk_id %WinID%
		if ErrorLevel
			Break
		(!sb_fields && sb_fields := []), sb_fields[A_Index] := SBFieldText
	}
	if sb_fields.maxindex()
	{
		while (sb_max := sb_fields.maxindex()) && (sb_fields[sb_max] = "")
			sb_fields.Delete(sb_max)
		for k, v in sb_fields
			SBText .= "<span class='param'>(" k "):</span> <span name='MS:' id='sb_field_" A_Index "'>" TransformHTML(v "") "</span>`n"
		If SBText !=
			SBText := _T1 " id='__StatusBarText'> ( StatusBarText ) </span>" _BT1 " id='copy_sbtext' name='" sb_max "'> copy " _BT2 _T2 _PRE1 "<span>" SBText "</span></span>" _PRE2
	}
	DetectHiddenText, % DetectHiddenText
	WinGetText, WinText, ahk_id %WinID%
	If WinText !=
		WinText := _T1 " id='__WindowText'> ( Window Text ) </span><a></a>" _BT1 " id='copy_wintext'> copy " _BT2 _DB _BT1 " id='wintext_hidden'> hidden - " DetectHiddenText " " _BT2 _T2
		. _LPRE  "><pre id='wintextcon'>" TransformHTML(WinText) "</pre>" _PRE2
	MenuText := GetMenu(WinID)

	If ViewStrPos
		ViewStrPos1 := _DP "<span name='MS:'>" WinX ", " WinY ", " WinX2 ", " WinY2 "</span>" _DP "<span name='MS:'>" WinX ", " WinY ", " WinWidth ", " WinHeight "</span>"

	IsWindowUnicodeStr := _DP "<span class='param'>Is unicode:</span>  <span>" (DllCall("user32\IsWindowUnicode", "Ptr", WinID) ? "True" : "False") "</span>"

	CoordMode, Mouse
	MouseGetPos, WinXS, WinYS, h
	If (h = hGui || h = oOther.hZoom || h = oOther.hZoomLW)
		Return 0, HideAllMarkers()
		
	SetPosObject("Window", [WinX, WinY, WinWidth, WinHeight])   
	SetPosObject("AhkSpy", WinGetPosToArray(hActiveX))
	
	If !StateAllwaysSpot 
	{
		oObjActive.ScreenX := WinXS, oObjActive.ScreenY := WinYS
		PixelGetColor, ColorRGB, %WinXS%, %WinYS%, RGB
		GuiControl, TB: -Redraw, ColorProgress
		GuiControl, % "TB: +c" SubStr(ColorRGB, 3), ColorProgress
		GuiControl, TB: +Redraw, ColorProgress
	}
	If WinExist("ahk_class AutoHotkey ahk_pid" WinPID)
	{
		RegExMatch(StrReplace(_ComLine, WinProcessPath), "(.:\\([^""]+))", m)  ; "(.:[^:]+\\([^""]+))", m) 
		If (m1 != "")
			AhkScriptPAth := m1
		Else 
			AhkScriptPAth := WinProcessPath, IsAhkScriptExe := 1 
			
		AhkScriptStringCode := _T1 " id='__ahkscript'> ( AutoHotkey script " (IsAhkScriptExe ? "compiled" : "") ") </span>" _T2   
			. "<div>" _DN2 
			. (!IsAhkScriptExe ? _BP1 " id='ahkscript_edit'> edit " _BP2 _DB : "")
			. _BP1 " id='ahkscript_folder'> in folder " _BP2 _DB
			. _BP1 " id='ahkscript_copypath'> copy as file " _BP2 _DB
			. _BP1 " id='ahkscript_run'> run " _BP2 _DN2
			. _BP1 " id='ahkscript_suspend'> suspend " _BP2 _DB
			. _BP1 " id='ahkscript_pause'> pause " _BP2 _DB
			. _BP1 " id='ahkscript_reload'> reload " _BP2 _DB
			. _BP1 " id='ahkscript_exit'> exit " _BP2 _DN2
			. _BP1 " id='ahkscript_lines'> lines " _BP2 _DB
			. _BP1 " id='ahkscript_variables'> variables " _BP2 _DB
			. _BP1 " id='ahkscript_hotkeys'> hotkeys " _BP2 _DB
			. _BP1 " id='ahkscript_keyhistory'> key history " _BP2 _DN2 "</div>"
			. _PRE1 "<span id='ahkscriptpath' name='MS:'>" TransformHTML(AhkScriptPAth) "</span>" _PRE2
	}
	If (hParent := DllCall("GetAncestor", "Ptr", WinID, Uint, 1)) && (hParent != WinID)
	{
		WinGet, ParentProcessName, ProcessName, ahk_id %hParent% 
		WinGetClass, ParentClass, ahk_id %hParent%
		_ParentWindow := "`n<span class='param'>Parent window:</span>  <span name='MS:'>" ParentClass "</span>" 
			. _DP " <span name='MS:'>" ParentProcessName "</span>" _DP "<span name='MS:'>" Format("0x{:x}", hParent) "</span>"
	}
	DllCall("GetWindowBand", "ptr", WinID, "uint*", band) 
	WindowBand := _DP "<span class='param'>WindowBand:</span>  <span name='MS:Q'>" oZBID[band] " := <span class='param' name='MS:'>" band "</span></span>"	

	; ___________________________ HTML_Win _________________________________________________

HTML_Win:
	If w_ShowStyles
		WinStyles := GetStyles(WinClass, WinStyle, WinExStyle, WinID)
		 
	HTML_Win := ""
	. _T1 " id='__Title'> ( Title ) </span>" _BT1 " id='pause_button'> pause " _BT2 _T2  _BR 
	
	. _PRE1 "<span id='wintitle1' name='MS:'>" WinTitle "</span>" _PRE2 
	
	. _T1 " id='__Class'> ( Class ) </span>" _T2 

	. _PRE1 "<span id='wintitle2'><span class='param' id='wintitle2_' name='MS:S'>ahk_class </span><span name='MS:'>" WinClass "</span></span>" _PRE2 
	
	. _T1 " id='__ProcessName'> ( ProcessName ) </span>" _BT1 " id='copy_alltitle'> copy titles " _BT2  _T2 
	
	. _PRE1 "<span id='wintitle3'><span class='param' name='MS:S' id='wintitle3_'>ahk_exe </span><span name='MS:'>" WinProcessName "</span></span>" _PRE2 
	
	. _T1 " id='__ProcessPath'> ( ProcessPath ) </span>" _BT1 " id='infolder'> in folder " _BT2  _DB  _BT1 " id='paste_process_path'> paste " _BT2  _T2 
	
	. _PRE1 "<span><span class='param' name='MS:S'>ahk_exe </span><span id='copy_processpath' name='MS:'>" WinProcessPath "</span></span>" _PRE2 
	
	. _T1 " id='__CommandLine'> ( CommandLine ) </span>" _BT1 " id='w_command_line'> launch " _BT2  _DB  
		. _BT1 " id='paste_command_line'> paste " _BT2  _DB  _BT1 " id='clean_command_line'> clean " _BT2  _DB  _BT1 " id='command_line_infolder'> in folder " _BT2  _T2 
	
	. _PRE1 "<span id='c_command_line' name='MS:'>" ComLine "</span>" _PRE2
	
	. AhkScriptStringCode
	
	. _T1 " id='__Position'> ( Position ) </span>" _T2 
	
	. _PRE1  _BP1 " id='set_button_pos'>Pos:" _BP2 "  <span name='MS:'>x" WinX " y" WinY "</span>" 
		. _DP "<span name='MS:'>x²" WinX2 " y²" WinY2 "</span>"
		. _DP  _BP1 " id='set_button_pos'>Size:" _BP2 "  <span name='MS:'>w" WinWidth " h" WinHeight "</span>" ViewStrPos1 
	
	. "`n<span class='param'>Client area size:</span>  <span name='MS:'>w" caW " h" caH "</span>" 
		. _DP "<span class='param'>left</span> " caX " <span class='param'>top</span> " caY 
		. " <span class='param'>right</span> " caWinRight " <span class='param'>bottom</span> " caWinBottom  _PRE2 

	. _T1 " id='__Other'> ( Other ) </span>" _BT1 " id='flash_window'> flash " _BT2  _ButWindow_Detective  _T2 

	. _PRE1 "<span class='param' name='MS:N'>PID:</span>  <span name='MS:'>" WinPID "</span>" 
		. _DP  ProcessBitSize  IsAdmin "<span class='param'>Window count:</span> " WinCountProcess  
		. _DP  _BB1 " id='process_close'> process close " _BB2 
		. _DP "<span class='param'>Create info time:  </span><span name='MS:'>" A_Hour ":" A_Min ":" A_Sec 
		. ".<span class='param' style='font-size: 0.75em'>" A_MSec "</span></span>"
		
	. "`n<span class='param' name='MS:N'>HWND:</span>  <span name='MS:'>" WinID "</span>" _DP  _BB1 " id='window_show_hide'> show / hide " _BB2
		. _DP  _BB1 " id='win_close'> close " _BB2  _DP "<span class='param'>Control count:</span>  "
		. CountControl IsWindowUnicodeStr WindowBand _ParentWindow EX1Str CLSID 

	. "`n<span class='param'>Style:  </span><span id='w_Style' name='MS:'>" WinStyle "</span>" 
		. _DP "<span class='param'>ExStyle:  </span><span id='w_ExStyle' name='MS:'>" WinExStyle "</span>" 
		. _DP _BB1 " id='get_styles_w'> " (!w_ShowStyles ? "show" : "hide" ) " styles " _BB2
		. _DP _BB1 " id='update_styles_w'> update styles " _BB2 _PRE2 

	. "`n<span id=WinStyles>" WinStyles "</span>" SBText  WinText  MenuText "<a></a>" _T0 
 
 
	oOther.WinPID := WinPID
	oOther.WinID := WinID
	oOther.ChildID := hChild
	If StateLightMarker && (ThisMode = "Win") && (StateLight = 1 || (StateLight = 3 && GetKeyState("Shift")))
		ShowMarker(WinX, WinY, WinWidth, WinHeight, 5) 
	Return 1
}

Write_Win(scroll = 0) {
	If (ThisMode != "Win")
		Return 0  
	oDivOld := oDivWork%DivWorkIndex%
	DivWorkIndex := DivWorkIndex = 1 ? 2 : 1
	oDivNew := oDivWork%DivWorkIndex%  
	oDivNew.innerHTML := HTML_Win 
	If oOther.anchor[ThisMode]
		AnchorScroll(AnchorColor())
	Else
		oDivNew.scrollTop := scroll ? ScrollPos[ThisMode, 2] : (ScrollPos[ThisMode, 2] := oDivOld.scrollTop)
		
	If oDivNew.scrollLeft
		oDivNew.scrollLeft := 0 

	oDivNew.style.zIndex := 1 
	oDivOld.style.zIndex := 0 
	
	oDivNew.style.visibility := "visible"
	oDivOld.innerHTML := ""
	Return 1 
}

	; ___________________________ Mode_Control _________________________________________________

Mode_Control:
	If A_GuiControl
		GuiControl, 1:Focus, oDoc
	ZoomMsg(10, 0)
	; oBody.createTextRange().execCommand("RemoveFormat")
	ColorButton("Control") 
	If (ThisMode = "Hotkey")
		Hotkey_Hook(0)
		
	Try SetTimer, Loop_%ThisMode%, Off
	
	ScrollPos[ThisMode, 1] := oDivNew.scrollLeft
	ScrollPos[ThisMode, 2] := oDivNew.scrollTop
	
	If ThisMode != Control
		HTML_%ThisMode% := oDivNew.innerHTML, prNotThisMode := 1
		
	ThisMode := "Control"
	
	If (HTML_Control = "")
		Spot_Control(1)
		
	Write_Control(prNotThisMode)
	
	TitleText := (TitleTextP1 := "AhkSpy - Control") . TitleTextP2
	SendMessage, 0xC, 0, &TitleText, , ahk_id %hGui%
	If isFindView
		FindNewText()

Loop_Control:
	If (WinActive("ahk_id" hGui) && !ActiveNoPause) || Sleep = 1
		GoTo Repeat_Loop_Control
	If !OnlyShiftTab && Spot_Control()
		Write_Control(), StateAllwaysSpot ? Spot_Win() : 0
		
Repeat_Loop_Control:
	If (!isPaused && ThisMode = "Control" && !OnlyShiftTab) 
		SetTimer, Loop_Control, -%RangeTimer%  
	Return

Spot_Control(NotHTML = 0) {
	If NotHTML
		GoTo HTML_Control
		
	CoordMode, Mouse, Screen
	MouseGetPos, MXS, MYS, WinID, tControlNN
	
	If (WinID = hGui || WinID = oOther.hZoom || WinID = oOther.hZoomLW)
		Return 0, HideAllMarkers()
		
	osCoords.MXS := MXS, osCoords.MYS := MYS
	oObjActive.ScreenX := MXS, oObjActive.ScreenY := MYS
	CoordMode, Mouse, Window
	MouseGetPos, MXWA, MYWA, , tControlID, 2
	osCoords.MXWA := MXWA, osCoords.MYWA := MYWA
	WinGet, ProcessName_A, ProcessName, A
	WinGet, HWND_A, ID, A
	WinGetClass, WinClass_A, A

	CtrlInfo := "", isIE := 0
	ControlNN := tControlNN, ControlID := tControlID
	WinGetPos, WinX, WinY, WinW, WinH, ahk_id %WinID%
	osCoords.WinW := WinW, osCoords.WinH := WinH
	WinGet, WinPID, PID, ahk_id %WinID%
	osCoords.RWinX := RWinX := MXS - WinX, osCoords.RWinY := RWinY := MYS - WinY
	GetClientPos(WinID, caX, caY, caW, caH)
	MXC := RWinX - caX, MYC := RWinY - caY
	osCoords.caW := caW, osCoords.caH := caH
	osCoords.MXC := MXC, osCoords.MYC := MYC
	 
	cc := _DP "" _BB1 " name='x" RWinX " y" RWinY "' id='control_click'> control click " _BB2  
	WithRespectWin := cc "`n" _BP1 " id='set_pos'>Relative window:" _BP2 "  <span name='MS:' id='coord_rwin'>"
		. Round(RWinX / WinW, 4) ", " Round(RWinY / WinH, 4) "</span>  <span class='param'>for</span> <span name='MS:'>w" WinW " h" WinH "</span>" _DP
	WithRespectClient := _BP1 " id='set_pos'>Relative client:" _BP2 "  <span name='MS:' id='coord_rclient'>" Round(MXC / caW, 4) ", " Round(MYC / caH, 4)
		. "</span>  <span class='param'>for</span> <span name='MS:'>w" caW " h" caH "</span>"

	ControlGetPos, CtrlX, CtrlY, CtrlW, CtrlH,, ahk_id %ControlID%
	
	AccText := AccInfoUnderMouse(MXS, MYS, WinX, WinY, CtrlX, CtrlY, caX, caY, WinID, ControlID)
	If AccText !=
		AccText := _T1 " id='__AccInfo'> ( Accessible ) </span><a></a>" _BT1 " id='flash_acc'> flash " _BT2 _ButAccViewer _T2 AccText
		
	If ControlID
	{
		CtrlCAX := CtrlX - caX, CtrlCAY := CtrlY - caY
		
		CtrlX2 := CtrlX + CtrlW - 1, CtrlY2 := CtrlY + CtrlH - 1
		CtrlCAX2 := CtrlX2 - caX, CtrlCAY2 := CtrlY2 - caY
		
		CtrlSCX := WinX + CtrlX, CtrlSCY := WinY + CtrlY
		CtrlSCX2 := CtrlSCX + CtrlW - 1, CtrlSCY2 := CtrlSCY + CtrlH - 1 
		
		ControlGetText, CtrlText, , ahk_id %ControlID%
		If CtrlText !=
			CtrlText := _T1 " id='__Control_Text'> ( Control Text ) </span><a></a>" _BT1 " id='copy_button_CtrlText'> copy " _BT2 _DB _BT1 " id='settext_button' value=`" ControlID "`> set " _BT2 
				. _DB  _BT1 " id='paste_Control_Text'> paste " _BT2  _T2  _LPRE " id='content_Control_Text'>" TransformHTML(CtrlText) _PRE2
		
		ControlGet, CtrlStyle, Style,,, ahk_id %ControlID%
		ControlGet, CtrlExStyle, ExStyle,,, ahk_id %ControlID%
		WinGetClass, CtrlClass, ahk_id %ControlID%
		
		If (hParent := DllCall("GetParent", "Ptr", ControlID)) && (hParent != WinID)
		{
			WinGetClass, ParentClass, ahk_id %hParent%
			_ParentControl := _DP "<span class='param'>Parent control:</span>  <span name='MS:'>" ParentClass "</span>" _DP "<span name='MS:'>" Format("0x{:x}", hParent) "</span>"
		}
		
		If ViewStrPos
			ViewStrPos1 := _DP "<span name='MS:'>" CtrlX ", " CtrlY ", " CtrlX2 ", " CtrlY2 "</span>" _DP "<span name='MS:'>" CtrlX ", " CtrlY ", " CtrlW ", " CtrlH "</span>"
			, ViewStrPos2 := _DP "<span name='MS:'>" CtrlCAX ", " CtrlCAY ", " CtrlCAX2 ", " CtrlCAY2 "</span>" _DP "<span name='MS:'>" CtrlCAX ", " CtrlCAY ", " CtrlW ", " CtrlH "</span>"
			. _DP "<span name='MS:'>" CtrlSCX ", " CtrlSCY ", " CtrlSCX2 ", " CtrlSCY2 "</span>" _DP "<span name='MS:'>" CtrlSCX ", " CtrlSCY ", " CtrlW ", " CtrlH "</span>" 	
		
		If DynamicControlPath
			ChildToPath(ControlID), control_path_value := SaveChildPath()
	} 
	If ControlNN !=
	{
		rmCtrlX := MXS - WinX - CtrlX, rmCtrlY := MYS - WinY - CtrlY
		ControlNN_Sub := RegExReplace(ControlNN, "S)\d+| ")
		
		;; Scintilla,Edit,SysListView,SysTreeView,ListBox,ComboBox,CtrlNotfySink,msctls_progress
		;; ,msctls_trackbar,msctls_updown,SysTabControl,ToolbarWindow,AtlAxWin,InternetExplorer_Server
		If IsFunc("GetInfo_" ControlNN_Sub)
			Func := ControlNN_Sub
		Else If RegExMatch(ControlNN_Sub, "i)(TreeView|ListView|ListBox|ComboBox|NotfySink|Edit|Scintilla|progress|trackbar|updown|Tab|Toolbar|RichEd)", Match) 
			Func := IsFunc("GetInfo_" Match) ? Match : {RichEd:"Scintilla",TreeView:"SysTreeView", ListView:"SysListView", NotfySink:"CtrlNotfySink"
				, progress:"msctls_progress", trackbar:"msctls_trackbar", updown:"msctls_updown", Tab:"SysTabControl", Toolbar:"ToolbarWindow"}[Match]
			
		If Func
		{
			CtrlInfo := GetInfo_%Func%(ControlID, ClassName)
			If CtrlInfo !=
			{
				If isIE
					CtrlInfo = %_T1% id='__Info_Class'> ( Info - %CtrlClass% ) </span><a></a>%_BT1% id='flash_IE'> flash %_BT2%%_ButiWB2Learner%%_T2%%CtrlInfo%
				Else
					CtrlInfo = %_T1% id='__Info_Class'> ( Info - %CtrlClass% ) </span><a></a>%_T2%%_PRE1%%CtrlInfo%%_PRE2%
			}
		}
		WithRespectControl := _DP "<span name='MS:'>" Round(rmCtrlX / CtrlW, 4) ", " Round(rmCtrlY / CtrlH, 4) "</span>"
	}
	Else
		rmCtrlX := rmCtrlY := ""
	
	ControlGetFocus, CtrlFocus, ahk_id %WinID%
	WinGet, ProcessName, ProcessName, ahk_id %WinID%
	WinGetClass, WinClass, ahk_id %WinID%
	
	MouseGetPos, , , h
	If (h = hGui || h = oOther.hZoom || h = oOther.hZoomLW)
		Return 0, HideAllMarkers()
		
	If !isIE
		SetPosObject("Control", [CtrlSCX, CtrlSCY, CtrlW, CtrlH])  
 
	SetPosObject("AhkSpy", WinGetPosToArray(hActiveX)) 
	
	If UseUIA && exUIASub.Release() && exUIASub.ElementFromPoint(MXS, MYS)
	{ 
		UIAPID := exUIASub.CurrentProcessId
		CurrentControlTypeIndex := Format("0x{:X}", exUIASub.CurrentControlType)
		CurrentControlTypeName := exUIASub.__ControlType(CurrentControlTypeIndex)
		CurrentAutomationId := exUIASub.CurrentAutomationId  
		CurrentLocalizedControlType := exUIASub.CurrentLocalizedControlType
		CurrentHelpText := exUIASub.CurrentHelpText
		UIAHWND := exUIASub.CurrentNativeWindowHandle
		
		
		WinGet, UIAProcessName, ProcessName, ahk_pid %UIAPID%
		WinGet, UIAProcessPath, ProcessPath, ahk_pid %UIAPID%
		
		Loop, %UIAProcessPath%
			UIAProcessPath = %A_LoopFileLongPath%
			
		If UIAAlienDetect && ((UIAPID != WinPID) || (ControlID && ControlID != UIAHWND) || (!ControlID && WinID != UIAHWND))
			bc = style='background-color: #%ColorHighLightBckg%'
		
		UseUIAStr := "`n" _T1 " id='P__UIA_Object'> ( UIA Interface ) </span><a></a>" _T2
		. _PRE1 "<div " bc "><span class='param' name='MS:N'>PID:</span>  <span name='MS:'>" UIAPID "</span>" 
		
		. (UIAHWND ? _DP "<span class='param' name='MS:N'>HWND:</span>  <span name='MS:'>" Format("0x{:x}", UIAHWND) "</span>"
		. _DP "<span class='param' name='MS:N'>ClassName:</span>  <span name='MS:'>" TransformHTML(exUIASub.CurrentClassName) "</span>" : _DP "HWND undefined")
		
		. _DN (CurrentAutomationId != "" ? "<span class='param' name='MS:N'>AutomationId:</span>  <span name='MS:'>" CurrentAutomationId "</span>" : "AutomationId undefined")
			. _DP (CurrentControlTypeIndex != "" ? "<span class='param' name='MS:N'>ControlType:</span>  <span name='MS:'>" CurrentControlTypeName "</span>"
			. _DP " <span name='MS:'>" CurrentControlTypeIndex "</span>" : "ControlType undefined")
			. (CurrentLocalizedControlType != "" ? _DP
			. "<span class='param' name='MS:N'>LocalizedControlType:</span>  <span name='MS:'>" CurrentLocalizedControlType "</span>" : _DP "LocalizedControlType undefined")
		
		. (CurrentHelpText != "" ? _DN "<span class='param' name='MS:N'>HelpText:</span>  <span name='MS:'>" CurrentHelpText "</span>" : "")
		
		. (UIAProcessName != ""
			? _DN "<span class='param' name='MS:N'>ProcessName:</span>  <span name='MS:'>" TransformHTML(UIAProcessName) "</span>"
			. _DP "<span class='param' name='MS:N'>ProcessPath:</span>  <span name='MS:'>" TransformHTML(UIAProcessPath) "</span>" : "")
		. "</div>" _PRE2
	}
	PixelGetColor, ColorBGR, %MXS%, %MYS%
	ColorRGB := Format("0x{:06X}", (ColorBGR & 0xFF) << 16 | (ColorBGR & 0xFF00) | (ColorBGR >> 16))

	sInvert_RGB := Format("{:06X}", ColorRGB ^ 0xFFFFFF)  
	sColorRGB := SubStr(ColorRGB, 3) 
	
	GuiControl, TB: -Redraw, ColorProgress
	GuiControl, % "TB: +c" sColorRGB, ColorProgress
	GuiControl, TB: +Redraw, ColorProgress

	If (!isIE && ThisMode = "Control" && (StateLight = 1 || (StateLight = 3 && GetKeyState("Shift"))))
	{
		If ControlID && StateLightMarker 
			ShowMarker(CtrlSCX, CtrlSCY, CtrlW, CtrlH)
		Else
			HideMarker()
			
		StateLightAcc ? ShowAccMarker(AccCoord[1], AccCoord[2], AccCoord[3], AccCoord[4]) : 0
	}
	If ((S_CaretX := A_CaretX) != "")
		CaretPosStr = <span class='param'>Caret:</span>  <span name='MS:'>x%S_CaretX% y%A_CaretY%</span>
	Else 
		CaretPosStr = <span class='error'>Caret position undefined</span>
	
	; ___________________________ HTML_Control _________________________________________________
 
HTML_Control:

	If ControlID
	{
		If c_ShowStyles
			ControlStyles := GetStyles(CtrlClass, CtrlStyle, CtrlExStyle, ControlID)
			
		HTML_ControlExist := ""
		. _T1 " id='__Control'> ( Control ) </span>" _BT1 " id='flash_control'> flash " _BT2  _ButWindow_Detective  _T2 
		
		. _PRE1 "<span class='param'>ClassNN:</span>  <span name='MS:'>" ControlNN "</span>"
			. _DP  "<span class='param'>Class:</span>  <span name='MS:'>" CtrlClass "</span>"
			
		. "`n" _BP1 " id='set_button_pos'>Pos:" _BP2 "  <span name='MS:'>x" CtrlX " y" CtrlY "</span>" 
			. _DP "<span name='MS:'>x²" CtrlX2 " y²" CtrlY2 "</span>" _DP  _BP1 " id='set_button_pos'>Size:"  _BP2 
			. "  <span name='MS:'>w" CtrlW " h" CtrlH "</span>" ViewStrPos1 
			
		. "`n" "<span class='param'>Relative client area:</span>  <span name='MS:'>x" CtrlCAX " y" CtrlCAY "</span>" 
			. _DP "<span name='MS:'>x²" CtrlCAX2 " y²" CtrlCAY2 "</span>"
			. _DP "<span class='param'>Relative screen:</span>  <span name='MS:'>x" CtrlSCX " y" CtrlSCY "</span>" 
			. _DP "<span name='MS:'>x²" CtrlSCX2 " y²" CtrlSCY2 "</span>"
			. ViewStrPos2 
			
		. "`n" _BP1 " id='set_pos'>Mouse relative control:" _BP2 "  <span name='MS:'>x" rmCtrlX " y" rmCtrlY "</span>" WithRespectControl 
		
		. "`n<span class='param'>HWND:</span>  <span name='MS:'>" ControlID "</span>" _DP  _BB1 " id='control_show_hide'> show / hide " _BB2 
			. _DP  _BB1 " id='control_destroy'> close " _BB2  _DP  _BP1 " id='control_path'> Get path " _BP2 
			. "<span id='control_path_error'></span>" _ParentControl 
			
		. "`n<span class='param'>Style:</span>  <span id='c_Style' name='MS:'>" CtrlStyle "</span>" 
			. _DP "<span class='param'>ExStyle:</span>  <span id='c_ExStyle' name='MS:'>" CtrlExStyle "</span>" 
			. _DP _BB1 " id='get_styles_c'> " (!c_ShowStyles ? "show styles" : "hide styles") " " _BB2
			. _DP _BB1 " id='update_styles_c'> update styles " _BB2   _PRE2
		
		. "`n<span id='control_path_value'>" control_path_value "</span>"
		
		. "`n<span id=ControlStyles>" ControlStyles "</span>" 
	} 
	
	HTML_Control := ""
	. _T1 " id='__Mouse'> ( Mouse ) </span>" _BT1 " id='pause_button'> pause " _BT2 _T2 
	
	. _PRE1  _BP1 " id='set_pos'>Screen:" _BP2 "  <span name='MS:' id='coord_screen'>x" MXS " y" MYS "</span>" _DP  _BP1 " id='set_pos'>Window:" _BP2 
		. "  <span name='MS:' id='coord_win'>x" RWinX " y" RWinY "</span>" _DP  _BP1 " id='set_pos'>Client:" _BP2 
		. "  <span name='MS:' id='coord_client'>x" MXC " y" MYC "</span>" WithRespectWin  WithRespectClient 
	
	. "`n<span class='param'>Relative active window:</span>  <span name='MS:' id='coord_awin'>x" MXWA " y" MYWA "</span>" 
		. _DP "<span class='param'>class</span> <span name='MS:'>" WinClass_A 
		. "</span> <span class='param'>exe</span> <span name='MS:'>" ProcessName_A 
		. "</span> <span class='param'>hwnd</span> <span name='MS:'>" HWND_A "</span>" _PRE2 
	
	. _T1 " id='__PixelColor'> ( PixelColor ) </span>" _T2 
	
	. _PRE1 "<span class='param'>RGB: </span> <span name='MS:' id='ColorRGB'>" ColorRGB "</span>" 
		. _DP "#<span name='MS:' id='sColorRGB'>" sColorRGB "</span>" _DP "<span class='param'>BGR: </span> <span name='MS:' id='ColorBGR'>" ColorBGR "</span>" 
		. _DP "#<span name='MS:' id='sColorBGR'>" SubStr(ColorBGR, 3) "</span>" 
		. _DP "<span class='param'>Invert RGB: </span> <span name='MS:' id='sInvert_RGB0'>0x" sInvert_RGB "</span>" 
		. _DP "#<span name='MS:' id='sInvert_RGB'>" sInvert_RGB "</span>" _DP "<span style='background-color: #" sInvert_RGB "' id='RenderInvert_RGB'>          </span>" _PRE2 
	
	. _T1 " id='__Window'> ( Window ) </span>" _BT1 " id='flash_ctrl_window'> flash " _BT2  _T2 
	 
	. _PRE1 "<span><span class='param' name='MS:S'>ahk_class</span> <span name='MS:'>" WinClass "</span></span> "
		. "<span><span class='param' name='MS:S'>ahk_exe</span> <span name='MS:'>" ProcessName "</span></span> "
		. "<span><span class='param' name='MS:S'>ahk_id</span> <span name='MS:'>" WinID "</span></span> "
		. "<span><span class='param' name='MS:S'>ahk_pid</span> <span name='MS:'>" WinPID "</span></span>"
		. _DP "<span class='param'>Create info time:  </span><span name='MS:'>" A_Hour ":" A_Min ":" A_Sec 
		. ".<span class='param' style='font-size: 0.75em'>" A_MSec "</span></span>"

	. "`n<span class='param'>Cursor:</span>  <span name='MS:'>" A_Cursor "</span>" 
		. _DP  CaretPosStr  _DP "<span class='param'>Client area:</span>  <span name='MS:'>x" caX " y" caY " w" caW " h" caH "</span>"

	. "`n" _BP1 " id='set_button_focus_ctrl'>Focus control:" _BP2 "  <span name='MS:'>" CtrlFocus "</span>" _PRE2 

	. "`n" HTML_ControlExist 

	. "`n" CtrlInfo CtrlText UseUIAStr AccText "<a></a>" _T0
	
	oOther.ControlID := ControlID
	oOther.MouseWinID := WinID
	oOther.CtrlClass := CtrlClass
	oOther.MouseWinClass := WinClass
	Return 1
}

Write_Control(scroll = 0) {
	If (ThisMode != "Control")
		Return 0  
	oDivOld := oDivWork%DivWorkIndex%
	DivWorkIndex := DivWorkIndex = 1 ? 2 : 1
	oDivNew := oDivWork%DivWorkIndex%  
	oDivNew.innerHTML := HTML_Control 

	If oOther.anchor[ThisMode]
		AnchorScroll(AnchorColor())
	Else
		oDivNew.scrollTop := scroll ? ScrollPos[ThisMode, 2] : (ScrollPos[ThisMode, 2] := oDivOld.scrollTop)
		
	If oDivNew.scrollLeft
		oDivNew.scrollLeft := 0 

	oDivNew.style.zIndex := 1 
	oDivOld.style.zIndex := 0 
	
	oDivNew.style.visibility := "visible"
	oDivOld.innerHTML := ""
	Return 1
}

	; ___________________________ Get Menu _________________________________________________

GetMenu(hWnd) {
	;; Static prhWnd, MenuText
	;; If (hWnd = prhWnd)
		;; Return MenuText
	;; prhWnd := hWnd
	SendMessage, 0x1E1, 0, 0, , ahk_id %hWnd%	;;  MN_GETHMENU
	hMenu := ErrorLevel
	If !hMenu || (hMenu + 0 = "")
		Return
	Return _T1 " id='__Menu_text'> ( Menu text ) </span><a></a>" _BT1 " id='copy_menutext'> copy " _BT2 _DB
	. _BT1 " id='menu_idview'> id - " (MenuIdView ? "view" : "hide") " " _BT2 _T2 _LPRE " id='pre_menutext'>" RTrim(GetMenuText(hMenu), "`n")  _PRE2
}

GetMenuText(hMenu, child = 0)
{
	Loop, % DllCall("GetMenuItemCount", "Ptr", hMenu)
	{
		idx := A_Index - 1
		nSize++ := DllCall("GetMenuString", "Ptr", hMenu, "int", idx, "Uint", 0, "int", 0, "Uint", 0x400)   ;;  MF_BYPOSITION
		nSize := (nSize * (A_IsUnicode ? 2 : 1))
		VarSetCapacity(sString, nSize)
		DllCall("GetMenuString", "Ptr", hMenu, "int", idx, "str", sString, "int", nSize, "Uint", 0x400)   ;;  MF_BYPOSITION
		sString := TransformHTML(sString)
		idn := DllCall("GetMenuItemID", "Ptr", hMenu, "int", idx)
		IdItem := "<span class='param menuitemid' style='display: " (!MenuIdView ? "none" : "inline") ";;'>`t`t`t<span name='MS:'>" idn "</span></span>"
		isSubMenu := (idn = -1) && (hSubMenu := DllCall("GetSubMenu", "Ptr", hMenu, "int", idx)) ? 1 : 0
		If isSubMenu
			sContents .= AddTab(child) "<span class='param'>" idx + 1 ":  </span><span name='MS:' class='titleparam'>" sString "</span>" IdItem "`n"
		Else If (sString = "")
			sContents .= AddTab(child) "<span class='param'>" idx + 1 ":  — — — — — — —</span>" IdItem "`n"
		Else
			sContents .= AddTab(child) "<span class='param'>" idx + 1 ":  </span><span name='MS:'>" sString "</span>" IdItem "`n"
		If isSubMenu
			sContents .= GetMenuText(hSubMenu, ++child), --child
	}
	Return sContents
}

AddTab(c) {
	loop % c
		Tab .= "<span class='param';'>↓`t</span>"
	Return Tab
}

	; ___________________________ Get Info Control _________________________________________________

;; Scintilla,Edit,SysListView,SysTreeView,ListBox,ComboBox,CtrlNotfySink,msctls_progress
;; ,msctls_trackbar,msctls_updown,SysTabControl,ToolbarWindow,AtlAxWin,InternetExplorer_Server

;; TreeView, ListView, NotfySink, progress, trackbar, updown, Tab, Toolbar


GetInfo_SysListView(hwnd) { 
	ControlGet, ListText, List,,, ahk_id %hwnd%
	ControlGet, RowCount, List, Count,, ahk_id %hwnd%
	ControlGet, ColCount, List, Count Col,, ahk_id %hwnd%
	ControlGet, SelectedCount, List, Count Selected,, ahk_id %hwnd%
	ControlGet, FocusedCount, List, Count Focused,, ahk_id %hwnd%
	Return	"<span class='param' name='MS:N'>Row count:</span> <span name='MS:'>" RowCount "</span>" _DP
			. "<span class='param' name='MS:N'>Column count:</span> <span name='MS:'>" ColCount "</span>`n"
			. "<span class='param' name='MS:N'>Selected count:</span> <span name='MS:'>" SelectedCount "</span>" _DP
			. "<span class='param' name='MS:N'>Focused row:</span> <span name='MS:'>" FocusedCount "</span>" _PRE2
			. _T1 " id='__Content_SysListView'> ( Content ) </span>" _BT1 " id='copy_button'> copy " _BT2 _T2 _LPRE ">" TransformHTML(ListText)
}

GetInfo_SysTreeView(hwnd) { 
	SendMessage 0x1105, 0, 0, , ahk_id %hwnd%   ;; TVM_GETCOUNT
	ItemCount := ErrorLevel
	Return	"<span class='param' name='MS:N'>Item count:</span> <span name='MS:'>" ItemCount "</span>"
}

GetInfo_ListBox(hwnd) { 
	Return GetInfo_ComboBox(hwnd, 1)
}

GetInfo_ComboBox(hwnd, ListBox = 0) { 
	ControlGet, ListText, List,,, ahk_id %hwnd%
	SendMessage, (ListBox ? 0x188 : 0x147), 0, 0, , ahk_id %hwnd%   ;; 0x188 - LB_GETCURSEL, 0x147 - CB_GETCURSEL
	SelPos := ErrorLevel
	SelPos := SelPos = 0xffffffff || SelPos < 0 ? "NoSelect" : SelPos + 1
	RegExReplace(ListText, "m`a)$", "", RowCount)
	Return	"<span class='param' name='MS:N'>Row count:</span> <span name='MS:'>" RowCount "</span>" _DP
			. "<span class='param' name='MS:N'>Row selected:</span> <span name='MS:'>" SelPos "</span>" _PRE2
			. _T1 " id='__Content_ComboBox'> ( Content ) </span>" _BT1 " id='copy_button'> copy " _BT2 _T2 _LPRE ">" TransformHTML(ListText)
}

GetInfo_CtrlNotifySink(hwnd) { 
	Return GetInfo_Scintilla(hwnd)
}

	;;  http://forum.script-coding.com/viewtopic.php?pid=117128#p117128
	;;  https://msdn.microsoft.com/en-us/library/windows/desktop/ms645478(v=vs.85).aspx

GetInfo_Edit(hwnd) { 
	Edit_GetFont(hwnd, FName, FSize)
	Return GetInfo_Scintilla(hwnd) "`n<span class='param' name='MS:N'>FontSize:</span> <span name='MS:'>" FSize "</span>" 
		. _DP "<span class='param' name='MS:N'>FontName:</span> <span name='MS:'>" FName "</span>"
		. "`n<span class='param' name='MS:N'>DlgCtrlID:</span> <span name='MS:'>" DllCall("GetDlgCtrlID", Ptr, hwnd) "</span>"
}

Edit_GetFont(hwnd, byref FontName, byref FontSize) {
	SendMessage 0x31, 0, 0, , ahk_id %hwnd% ;; WM_GETFONT
	If ErrorLevel = FAIL
		Return
	hFont := Errorlevel, VarSetCapacity(LF, szLF := 60 * (A_IsUnicode ? 2 : 1))
	DllCall("GetObject", UInt, hFont, Int, szLF, UInt, &LF)
	hDC := DllCall("GetDC", UInt, hwnd), DPI := DllCall("GetDeviceCaps", UInt, hDC, Int, 90)
	DllCall("ReleaseDC", Int, 0, UInt, hDC), FontSize := Round((-NumGet(LF, 0, "Int") * 72) / DPI)
	FontName := DllCall("MulDiv", Int, &LF + 28, Int, 1, Int, 1, Str)
}

GetInfo_Scintilla(hwnd) { 
	ControlGet, LineCount, LineCount,,, ahk_id %hwnd%
	ControlGet, CurrentCol, CurrentCol,,, ahk_id %hwnd%
	ControlGet, CurrentLine, CurrentLine,,, ahk_id %hwnd%
	ControlGet, Selected, Selected,,, ahk_id %hwnd%
	SendMessage, 0x00B0, , , , ahk_id %hwnd%			;;  EM_GETSEL
	EM_GETSEL := ErrorLevel >> 16
	SendMessage, 0x00CE, , , , ahk_id %hwnd%			;;  EM_GETFIRSTVISIBLELINE
	EM_GETFIRSTVISIBLELINE := ErrorLevel + 1
	Return	"<span class='param' name='MS:N'>Row count:</span> <span name='MS:'>" LineCount "</span>" _DP
			. "<span class='param' name='MS:N'>Selected length:</span> <span name='MS:'>" StrLen(Selected) "</span>"
			. "`n<span class='param' name='MS:N'>Current row:</span> <span name='MS:'>" CurrentLine "</span>" _DP
			. "<span class='param' name='MS:N'>Current column:</span> <span name='MS:'>" CurrentCol "</span>"
			. "`n<span class='param' name='MS:N'>Current select:</span> <span name='MS:'>" EM_GETSEL "</span>" _DP
			. "<span class='param' name='MS:N'>First visible line:</span> <span name='MS:'>" EM_GETFIRSTVISIBLELINE "</span>"
}

GetInfo_msctls_progress(hwnd) { 
	SendMessage, 0x0400+7,"TRUE",,, ahk_id %hwnd%	;;  PBM_GETRANGE
	PBM_GETRANGEMIN := ErrorLevel
	SendMessage, 0x0400+7,,,, ahk_id %hwnd%			;;  PBM_GETRANGE
	PBM_GETRANGEMAX := ErrorLevel
	SendMessage, 0x0400+8,,,, ahk_id %hwnd%			;;  PBM_GETPOS
	PBM_GETPOS := ErrorLevel
	Return	"<span class='param' name='MS:N'>Level:</span> <span name='MS:'>" PBM_GETPOS "</span>" _DP
			. "<span class='param'>Range:  </span><span class='param' name='MS:N'>Min: </span><span name='MS:'>" PBM_GETRANGEMIN "</span>"
			. "  <span class='param' name='MS:N'>Max:</span> <span name='MS:'>" PBM_GETRANGEMAX "</span>"
}

GetInfo_msctls_trackbar(hwnd) { 
	SendMessage, 0x0400+1,,,, ahk_id %hwnd%			;;  TBM_GETRANGEMIN
	TBM_GETRANGEMIN := ErrorLevel
	SendMessage, 0x0400+2,,,, ahk_id %hwnd%			;;  TBM_GETRANGEMAX
	TBM_GETRANGEMAX := ErrorLevel
	SendMessage, 0x0400,,,, ahk_id %hwnd%			;;  TBM_GETPOS
	TBM_GETPOS := ErrorLevel
	ControlGet, CtrlStyle, Style,,, ahk_id %hwnd%
	(!(CtrlStyle & 0x0200)) ? (TBS_REVERSED := "No")
	: (TBM_GETPOS := TBM_GETRANGEMAX - (TBM_GETPOS - TBM_GETRANGEMIN), TBS_REVERSED := "Yes")
	Return	"<span class='param' name='MS:N'>Level:</span> <span name='MS:'>" TBM_GETPOS "</span>" _DP
			. "<span class='param'>Invert style:</span>" TBS_REVERSED
			. "`n<span class='param'>Range:  </span><span class='param' name='MS:N'>Min: </span><span name='MS:'>" TBM_GETRANGEMIN "</span>" _DP
			. "<span class='param' name='MS:N'>Max:</span> <span name='MS:'>" TBM_GETRANGEMAX "</span>"
}

GetInfo_msctls_updown(hwnd) { 
	SendMessage, 0x0400+102,,,, ahk_id %hwnd%		;;  UDM_GETRANGE
	UDM_GETRANGE := ErrorLevel
	SendMessage, 0x400+114,,,, ahk_id %hwnd%		;;  UDM_GETPOS32
	UDM_GETPOS32 := ErrorLevel
	Return	"<span class='param' name='MS:N'>Level:</span> <span name='MS:'>" UDM_GETPOS32 "</span>" _DP
			. "<span class='param'>Range:  </span><span class='param' name='MS:N'>Min: </span><span name='MS:'>" UDM_GETRANGE >> 16 "</span>"
			. "  <span class='param' name='MS:N'>Max: </span><span name='MS:'>" UDM_GETRANGE & 0xFFFF "</span>"
}

GetInfo_SysTabControl(hwnd) { 
	ControlGet, SelTab, Tab,,, ahk_id %hwnd%
	SendMessage, 0x1300+44,,,, ahk_id %hwnd%		;;  TCM_GETROWCOUNT
	TCM_GETROWCOUNT := ErrorLevel
	SendMessage, 0x1300+4,,,, ahk_id %hwnd%			;;  TCM_GETITEMCOUNT
	TCM_GETITEMCOUNT := ErrorLevel
	Return	"<span class='param' name='MS:N'>Item count:</span> <span name='MS:'>" TCM_GETITEMCOUNT "</span>" _DP
			. "<span class='param' name='MS:N'>Row count:</span> <span name='MS:'>" TCM_GETROWCOUNT "</span>" _DP
			. "<span class='param' name='MS:N'>Selected item:</span> <span name='MS:'>" SelTab "</span>"
}

GetInfo_ToolbarWindow(hwnd) { 
	SendMessage, 0x0418,,,, ahk_id %hwnd%		;;  TB_BUTTONCOUNT
	BUTTONCOUNT := ErrorLevel
	Return	"<span class='param' name='MS:N'>Button count:</span> <span name='MS:'>" BUTTONCOUNT "</span>"
}

	; ___________________________ Get Internet Explorer Info _________________________________________________

	;;  http://www.autohotkey.com/board/topic/84258-iwb2-learner-iwebbrowser2/

GetInfo_AtlAxWin(hwnd) { 
	Return GetInfo_InternetExplorer_Server(hwnd)
}

GetInfo_InternetExplorer_Server(hwnd) {
	Static IID_IWebBrowserApp := "{0002DF05-0000-0000-C000-000000000046}"
	, ratios := [], IID_IHTMLWindow2 := "{332C4427-26CB-11D0-B483-00C04FD90119}"

	isIE := 1 
	MouseGetPos, , , , hwnd, 3
	If !(pwin := WBGet(hwnd))
		Return
	If !ratios[hwnd]
	{
		ratio := pwin.window.screen.deviceXDPI / pwin.window.screen.logicalXDPI
		Sleep 10 ;; при частом запросе deviceXDPI, возвращает пусто
		!ratio && (ratio := 1)
		ratios[hwnd] := ratio
	}
	ratio := ratios[hwnd]
	pelt := pwin.document.elementFromPoint(rmCtrlX / ratio, rmCtrlY / ratio)
	Tag := pelt.TagName
	If (Tag = "IFRAME" || Tag = "FRAME")
	{
		If pFrame := ComObjQuery(pwin.document.parentWindow.frames[pelt.id], IID_IHTMLWindow2, IID_IHTMLWindow2)
			iFrame := ComObject(9, pFrame, 1)
		Else
			iFrame := ComObj(9, ComObjQuery(pelt.contentWindow, IID_IHTMLWindow2, IID_IHTMLWindow2), 1)
		WB2 := ComObject(9, ComObjQuery(pelt.contentWindow, IID_IWebBrowserApp, IID_IWebBrowserApp), 1)
		If ((Var := WB2.LocationName) != "")
			Frame .= "`n<span class='param' name='MS:N'>Title:  </span><span name='MS:'>" TransformHTML(Var) "</span>"
		If ((Var := WB2.LocationURL) != "")
			Frame .= "`n<span class='param' name='MS:N'>URL:  </span><span name='MS:'>" TransformHTML(Var) "</span>"
		If (iFrame.length)
			Frame .= "`n<span class='param' name='MS:N'>Count frames:  </span><span name='MS:'>" TransformHTML(iFrame.length) "</span>"
		If (Tag != "")
			Frame .= "`n<span class='param' name='MS:N'>TagName:  </span><span name='MS:'>" TransformHTML(Tag) "</span>"
		If ((Var := pelt.id) != "")
			Frame .= "`n<span class='param' name='MS:N'>ID:  </span><span name='MS:'>" TransformHTML(Var) "</span>"
		If ((Var := pelt.className) != "")
			Frame .= "`n<span class='param' name='MS:N'>Class:  </span><span name='MS:'>" TransformHTML(Var) "</span>"
		If ((Var := pelt.sourceIndex) != "")
			Frame .= "`n<span class='param' name='MS:N'>Index:  </span><span name='MS:'>" TransformHTML(Var) "</span>"
		If ((Var := pelt.name) != "")
			Frame .= "`n<span class='param' name='MS:N'>Name:  </span><span name='MS:'>" TransformHTML(Var) "</span>"

		If ((Var := pelt.OuterHtml) != "")
			HTML := _T1 " id='P__Outer_HTML_FRAME'" _T1P "> ( Outer HTML ) </span><a></a>" _BT1 " id='copy_button'> copy " _BT2 _T2 _LPRE ">" TransformHTML(Var) _PRE2
		If ((Var := pelt.OuterText) != "")
			Text := _T1 " id='P__Outer_Text_FRAME'" _T1P "> ( Outer Text ) </span><a></a>" _BT1 " id='copy_button'> copy " _BT2 _T2 _LPRE ">" TransformHTML(Var) _PRE2
		If Frame !=
			Frame := _T1 " id='__FrameInfo_FRAME'> ( FrameInfo ) </span>" _T2 "<a></a>" _PRE1 Frame _PRE2 HTML Text

		_pbrt := pelt.getBoundingClientRect()
		pelt := iFrame.document.elementFromPoint((rmCtrlX / ratio) - _pbrt.left, (rmCtrlY / ratio) - _pbrt.top)
		__pbrt := pelt.getBoundingClientRect(), pbrt := {}
		pbrt.left := __pbrt.left + _pbrt.left, pbrt.right := __pbrt.right + _pbrt.left
		pbrt.top := __pbrt.top + _pbrt.top, pbrt.bottom := __pbrt.bottom + _pbrt.top
	}
	Else
		pbrt := pelt.getBoundingClientRect()

	WB2 := ComObject(9, ComObjQuery(pwin, IID_IWebBrowserApp, IID_IWebBrowserApp), 1)

	If ((Location := WB2.LocationName) != "")
		Topic .= "<span class='param' name='MS:N'>Title:  </span><span name='MS:'>"  TransformHTML(Location) "</span>`n"
	If ((URL := WB2.LocationURL) != "")
		Topic .= "<span class='param' name='MS:N'>URL:  </span><span name='MS:'>"  TransformHTML(URL) "</span>"
	If Topic !=
		Topic := _PRE1 Topic _PRE2

	If ((Var := pelt.id) != "")
		Info .= "`n<span class='param' name='MS:N'>ID:  </span><span name='MS:'>" Var "</span>"
	If ((Var := pelt.className) != "")
		Info .= "`n<span class='param' name='MS:N'>Class:  </span><span name='MS:'>" Var "</span>"
	If ((Var := pelt.sourceIndex) != "")
		Info .= "`n<span class='param' name='MS:N'>Index:  </span><span name='MS:'>" Var "</span>"
	If ((Var := pelt.name) != "")
		Info .= "`n<span class='param' name='MS:N'>Name:  </span><span name='MS:'>" TransformHTML(Var) "</span>"

	If ((Var := pelt.OuterHtml) != "")
		HTML := _T1 " id='P__Outer_HTML'" _T1P "> ( Outer HTML ) </span><a></a>" _BT1 " id='copy_button'> copy " _BT2 _T2 _LPRE ">" TransformHTML(Var) _PRE2
	If ((Var := pelt.OuterText) != "")
		Text := _T1 " id='P__Outer_Text'" _T1P "> ( Outer Text ) </span><a></a>" _BT1 " id='copy_button'> copy " _BT2 _T2 _LPRE ">" TransformHTML(Var) _PRE2

	x1 := pbrt.left * ratio, y1 := pbrt.top * ratio
	x2 := pbrt.right * ratio, y2 := pbrt.bottom * ratio
	ObjRelease(pwin), ObjRelease(pelt), ObjRelease(WB2), ObjRelease(iFrame), ObjRelease(pbrt)

	If (ThisMode = "Control") && (StateLight = 1 || (StateLight = 3 && GetKeyState("Shift")))
	{
		WinGetPos, sX, sY, , , ahk_id %hwnd%
		StateLightMarker ? ShowMarker(sX + x1, sY + y1, x2 - x1, y2 - y1) : 0
		StateLightAcc ? ShowAccMarker(AccCoord[1], AccCoord[2], AccCoord[3], AccCoord[4]) : 0
	} 
	; SetPosObject("Control", [Round(sX + x1), Round(sY + y1), Round(x2 - x1), Round(y2 - y1)])  
	SetPosObject("Control", [Format("{:d}", sX + x1), Format("{:d}", sY + y1), Format("{:d}", x2 - x1), Format("{:d}", y2 - y1)])  
	If (pelt.TagName)
		Info := _T1 " id='P__Tag_name' name='MS:N'> ( Tag name: <span name='MS:' style='color: #" ColorFont ";'>"
		. pelt.TagName "</span>" (Frame ? " - (in frame)" : "") " ) </span>" _T2
		. _PRE1  "<span class='param'>Pos: </span><span name='MS:'>x" Round(x1) " y" Round(y1) "</span>"
		. _DP "<span name='MS:'>x²" Round(x2) - 1 " y²" Round(y2) - 1 "</span>"
		. _DP "<span class='param'>Size: </span><span name='MS:'>w" Round(x2 - x1) " h" Round(y2 - y1) "</span>" Info _PRE2

	oPubObj.IEElement := {Pos:[sX + x1, sY + y1, x2 - x1, y2 - y1], hwnd:hwnd}
	
	Return Topic Info HTML Text Frame 
}

WBGet(hwnd) {
	Static Msg := DllCall("RegisterWindowMessage", "Str", "WM_HTML_GETOBJECT")
	, IID_IHTMLWindow2 := "{332C4427-26CB-11D0-B483-00C04FD90119}", GUID, _ := VarSetCapacity(GUID,16,0)
	SendMessage, Msg, , , , ahk_id %hwnd%
	DllCall("oleacc\ObjectFromLresult", "Ptr", ErrorLevel, "Ptr", &GUID, "Ptr", 0, PtrP, pdoc)
	Return ComObj(9, ComObjQuery(pdoc, IID_IHTMLWindow2, IID_IHTMLWindow2), 1), ObjRelease(pdoc)
}

	; ___________________________ Get Acc Info _________________________________________________

	;;  http://www.autohotkey.com/board/topic/77888-accessible-info-viewer-alpha-release-2012-09-20/
	   
AccInfoUnderMouse(mx, my, wx, wy, cx, cy, caX, caY, WinID, ControlID) {
	Static hLibrary, AccObj, WM_GETOBJECT := 0x003D, OBJID_CARET := 0xFFFFFFF8
	
	If (WinID = "") { 
		AccObj := ""
		Return
	}
	If !hLibrary
		hLibrary := DllCall("LoadLibrary", "Str", "oleacc", "Ptr")

	AccObj := ""
	If (oOther.AccCLOAKEDWinID != oPubObj.Acc.WinID)
		ObjRelease(oPubObj.Acc.pAccObj)
		
		;;  https://docs.microsoft.com/en-us/windows/win32/api/oleacc/nf-oleacc-accessibleobjectfrompoint
	If DllCall("oleacc\AccessibleObjectFromPoint"
		, "Int64", mx & 0xFFFFFFFF | my << 32, "Ptr*", pAccObj
		, "Ptr", VarSetCapacity(varChild, 8 + 2 * A_PtrSize, 0) * 0 + &varChild) = 0
		
	; http://forum.script-coding.com/viewtopic.php?pid=139109#p139109
	; Acc := ComObjEnwrap(9, pacc, 1), child := NumGet(varChild,8,"UInt")
	
	AccObj := ComObject(9, pAccObj, 1)
	
	If !IsObject(AccObj)
		Return
	
	ObjAddRef(pAccObj) 
	child := NumGet(varChild, 8, "UInt")
	
	; SendMessage, WM_GETOBJECT, 0, 1, , % "ahk_id" (ControlID ? ControlID : WinID) 
	SendMessage, WM_GETOBJECT, 0, 1, Chrome_RenderWidgetHostHWND1, % "ahk_id " WinID
	
	oPubObj.Acc := {AccObj: Object(AccObj), child: child, WinID: WinID, ControlID: ControlID, pAccObj: pAccObj} 
	
	ChildCount := AccObj.accChildCount
	If child
		Var := "<span name='MS:'>Simple Element</span>" _DP "<span class='param' name='MS:N'>Id:  </span>" child
	Else If ChildCount
		Var := "<span name='MS:'>Container</span>" _DP "<span class='param' name='MS:N'>ChildCount:  </span>" ChildCount _DP "<span class='param' name='MS:N'>Id:  </span>" child 
	Else
		Var := "<span name='MS:'>Real Object</span>" _DP "<span class='param' name='MS:N'>Id:  </span>" child    ;;  _DP "<span class='param' name='MS:N'>Container child count:  </span>" ChildCount
		
	If DynamicAccPath
	{ 
		If acc_path_func(0)
			acc_path_value := SaveAccPath()
		Else 
			error := "<span style='color:#" ColorErrorAccPath "'>  path not found</span>"
	}
	pathbutton := _DP _BP1 " id='acc_path'> Get path " _BP2 "</span><span id='acc_path_error'>" error "</span>" 
	code := _PRE1 "<span class='param'>Type:</span>  " Var pathbutton 
	. _DP _BP1 " id='acc_DoDefaultAction2'> DoDefaultAction " _BP2 "</span>"
	. _PRE2 "<span id='acc_path_value'>" acc_path_value "</span>" 

	AccGetLocation(AccObj, child)
	x := AccCoord[1], y := AccCoord[2], w := AccCoord[3], h := AccCoord[4] 
	SetPosObject("accesible", [x, y, w, h])  

	code .= _T1 " id='P__Position_relative_Acc'" _T1P "> ( Position relative ) </span>" _T2
		. _PRE1 "<span class='param'>Screen: </span>"
		. "<span name='MS:'>x" x " y" y "</span>"
		. _DP "<span name='MS:'>x²" x + w - 1 " y²" y + h - 1 "</span>"
		. _DP "<span class='param'>Size: </span><span name='MS:'>w" w " h" h "</span>"
		.  _DP  "<span class='param'>Mouse: </span><span name='MS:'>x" mx - AccCoord[1] " y" my - AccCoord[2] "</span>`n"

		. "<span class='param'>Window: </span><span name='MS:'>x" x - wx " y" y - wy "</span>"
		. _DP "<span name='MS:'>x²" x - wx + w - 1 " y²" y - wy + h - 1 "</span>"
		
		. _DP "<span class='param'>Client: </span><span name='MS:'>x" x - wx - caX " y" y - wy - caY "</span>"
		. _DP "<span name='MS:'>x²" x - wx + w - 1 - caX " y²" y - wy + h - 1 - caY "</span>"
		 
		. (cx != "" ? _DP "<span class='param'>Control: </span><span name='MS:'>x" (x - wx - cx) " y" (y - wy - cy) "</span>"
		. _DP "<span name='MS:'>x²" (x - wx - cx) + w - 1 " y²" (y - wy - cy) + h - 1 "</span>" : "")  _PRE2

	CaretPos := AccGetLocationToObj(Acc_ObjectFromWindow(WinID, OBJID_CARET))
	If (CaretPos.x != 0 || CaretPos.y != 0)
	{ 
		code .= _T1 " id='P__CaretPos_Acc'" _T1P "> ( Caret position relative ) </span>" _T2
			. _PRE1 "<span class='param'>Screen: </span>"
			. "<span name='MS:'>x" CaretPos.x " y" CaretPos.y "</span>"
			. _DP "<span class='param'>Window: </span>"
			. "<span name='MS:'>x" (CaretPos.x - wx) " y" (CaretPos.y - wy) "</span>"
			. _DP "<span class='param'>Client: </span>"
			. "<span name='MS:'>x" (CaretPos.x - wx - caX) " y" (CaretPos.y - wy - caY) "</span>"
			. _DP "<span class='param'>Size: </span>"
			. "<span name='MS:'>w" CaretPos.w " h" CaretPos.h "</span>" . _PRE2
	} 
	If ((Hwnd := AccWindowFromObject(pAccObj)) != ControlID && Hwnd != WinID) {   ;	можно Acc вместо pAccObj, then ComObjValue
		WinGetClass, CtrlClass, ahk_id %Hwnd%
		WinGet, WinProcess, ProcessName, ahk_id %Hwnd%
		WinGet, WinPID, PID, ahk_id %Hwnd%
		code .= _T1 " id='P__WindowFromObject'" _T1P "> ( WindowFromObject ) </span><a></a>" _T2 _PRE1
		. "<div style='background-color: #" ColorHighLightBckg "'><span class='param' name='MS:N'>HWND:</span>  <span name='MS:'>" Format("0x{:x}", Hwnd) "</span>"
		. _DP "<span class='param' name='MS:N'>Class:</span>  <span name='MS:'>" TransformHTML(CtrlClass) "</span>"
		. _DP "<span class='param' name='MS:N'>Exe:</span>  <span name='MS:'>" TransformHTML(WinProcess) "</span>"
		. _DP "<span class='param' name='MS:N'>PID:</span>  <span name='MS:'>" WinPID "</span></div>" _PRE2
	}
	If ((Var := AccObj.accName(child)) != "")
		code .= _T1 " id='P__Name_Acc'" _T1P "> ( Name ) </span><a></a>" _BT1 " id='copy_button'> copy " _BT2 _T2 _LPRE ">" TransformHTML(Var) _PRE2
		
	If ((Var := AccObj.accValue(child)) != "")
		code .= _T1 " id='P__Value_Acc'" _T1P "> ( Value ) </span><a></a>" _BT1 " id='copy_button'> copy " _BT2 _T2 _LPRE ">" TransformHTML(Var) _PRE2
		
	AccState(AccObj, child, style, strstyles)
	If (strstyles != "")
		code .= _T1 " id='P__State_Acc'" _T1P "> ( State: <span name='MS:' style='color: #" ColorFont ";'>" style "</span> ) </span>" _T2 _PRE1 strstyles _PRE2
		
	If ((Var := AccRole(AccObj, child)) != "")
		code .= _T1 " id='P__Role_Acc'" _T1P "> ( Role ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>"
		. _DP "<span class='param' name='MS:N'>code: </span><span name='MS:'>" AccObj.accRole(child) "</span>" _PRE2
		
	If (child &&(Var := AccRole(AccObj)) != "")
		code .= _T1 " id='P__Role_parent_Acc'" _T1P "> ( Role - parent ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>"
		. _DP "<span class='param' name='MS:N'>code: </span><span name='MS:'>" AccObj.accRole(0) "</span>" _PRE2
		
	If ((Var := AccObj.accDefaultAction(child)) != "")
		code .= _T1 " id='P__Action_Acc'" _T1P "> ( Action ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>" 
		. _DP _BP1 " id='acc_DoDefaultAction'> Execute " _BP2 _PRE2
		
	If ((Var := AccObj.accSelection) > 0)
		code .= _T1 " id='P__Selection_parent_Acc'" _T1P "> ( Selection - parent ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>" _PRE2
	
	If ((Var := AccObj.accDescription(child)) != "")
		code .= _T1 " id='P__Description_Acc'" _T1P "> ( Description ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>" _PRE2
	
	If ((Var := AccObj.accKeyboardShortCut(child)) != "")
		code .= _T1 " id='P__ShortCut_Acc'" _T1P "> ( ShortCut ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>" _PRE2
	
	If ((Var := AccObj.accHelp(child)) != "")
		code .= _T1 " id='P__Help_Acc'" _T1P "> ( Help ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>" _PRE2
	
	If ((Var := AccObj.AccHelpTopic(child)))
		code .= _T1 " id='P__HelpTopic_Acc'" _T1P "> ( HelpTopic ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>" _PRE2
		
	AccAccFocus(WinID, accFocusName, accFocusValue, role, irole)
	If (accFocusName != "")
		code .= _T1 " id='P__Focus_name_Acc'" _T1P "> ( Focus - name ) </span><a></a>" 
		. _BT1 " id='copy_button'> copy " _BT2 _T2 _LPRE ">" TransformHTML(accFocusName) _PRE2
	If (accFocusValue != "")
		code .= _T1 " id='P__Focus_value_Acc'" _T1P "> ( Focus - value ) </span><a></a>"
		. _BT1 " id='copy_button'> copy " _BT2 _T2 _LPRE ">" TransformHTML(accFocusValue) _PRE2
	If (role != "" && irole != "")
		, code .= _T1 " id='P__Focus__Role_Acc'" _T1P "> ( Focus - Role ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(role) "</span>"
		. _DP "<span class='param' name='MS:N'>code: </span><span name='MS:'>" irole "</span>" _PRE2 
	 
	Return code
}


EVENT_OBJECT_CLOAKED(hWinEventHook, event, hwnd, idObject, idChild) { 
	Critical
	If (idObject || idChild) || (hwnd != oPubObj.Acc.WinID)
		Return
	; ToolTip % ComObjType(AccObj, "Name") "`n" A_ThisFunc
	oPubObj.Acc.CLOAKED := 1 
	AccInfoUnderMouse("", "", "", "", "", "", "", "", "", "")
	oOther.AccCLOAKEDpAccObj := oPubObj.Acc.pAccObj
	oOther.AccCLOAKEDWinID := oPubObj.Acc.WinID
}

EVENT_OBJECT_UNCLOAKED(hWinEventHook, event, hwnd, idObject, idChild) {
	Critical
	If (idObject || idChild) || (hwnd != oOther.AccCLOAKEDWinID)
		Return 
	; ToolTip % hwnd "`n" oOther.AccCLOAKEDpAccObj "`n" A_ThisFunc
	ObjRelease(oOther.AccCLOAKEDpAccObj)
	oPubObj.Acc.CLOAKED := 0
	oOther.AccCLOAKEDpAccObj := ""
	oOther.AccCLOAKEDWinID := ""
}
 
accDoDefaultAction() { 
	If oPubObj.Acc.CLOAKED
		Return 0, ToolTip("CLOAKED", 500)
	Acc := Object(oPubObj.Acc.AccObj) 
	Acc.accDoDefaultAction(oPubObj.Acc.child)
}

	;;	https://docs.microsoft.com/ru-ru/windows/desktop/WinAuto/object-state-constants
	;;	http://forum.script-coding.com/viewtopic.php?pid=130762#p130762
AccState(Acc, child, byref style, byref str, i := 1) {
	style := Format("0x{1:08X}", Acc.accState(child))
	If (style = 0)
		Return "", str := "<span class='param' name='MS:'>" AccGetStateText(0) "</span>" _DP "<span name='MS:'>" 0x00000000 "</span>`n"
	While (i <= style) {
		if (i & style)
			str .= "<span class='param' name='MS:'>" AccGetStateText(i) "</span>" _DP "<span name='MS:'>" Format("0x{1:08X}", i) "</span>`n"
		i <<= 1
	}
}

AccWindowFromObject(pacc) {
	If DllCall("oleacc\WindowFromAccessibleObject", "Ptr", IsObject(pacc) ? ComObjValue(pacc) : pacc, "Ptr*", hWnd) = 0
		Return hWnd
}
	;;	http://forum.script-coding.com/viewtopic.php?pid=130762#p130762

AccAccFocus(hWnd, byref name, byref value, byref role, byref irole) {
	Acc := Acc_ObjectFromWindow(hWnd)
	While IsObject(Acc.accFocus)
		Acc := Acc.accFocus
	try 
	{
		child := Acc.accFocus
		name := Acc.accName(child)
		value := Acc.accValue(child)
		role := AccRole(Acc, child) 
		irole := Acc.accRole(0) 
	}
}

AccRole(Acc, ChildId=0) {
	Return ComObjType(Acc, "Name") = "IAccessible" ? AccGetRoleText(Acc.accRole(ChildId)) : ""
}

AccGetRoleText(nRole) {
	nSize := DllCall("oleacc\GetRoleText", "UInt", nRole, "Ptr", 0, "UInt", 0)
	VarSetCapacity(sRole, (A_IsUnicode?2:1)*nSize)
	DllCall("oleacc\GetRoleText", "UInt", nRole, "str", sRole, "UInt", nSize+1)
	Return sRole
}

AccGetStateText(nState) {
	nSize := DllCall("oleacc\GetStateText", "UInt", nState, "Ptr", 0, "UInt", 0)
	VarSetCapacity(sState, (A_IsUnicode?2:1)*nSize)
	DllCall("oleacc\GetStateText", "UInt", nState, "str", sState, "UInt", nSize+1)
	Return sState
}

SaveAccPath(Path = "") {
	Static p
	If Path =
		Return p
	p := Path
}

AddSpace(c) {
	loop % c
		Tab .= "<span class='param';'>↓    </span>"
	Return Tab
}

GetAccPath() { 
	if !Acc_GetPath(arr)
		Return 0  
	If !CompareAcc(Acc_Get("Object", arr[1].Path, 0, "ahk_id " arr[1].hWnd), Object(oPubObj.Acc.AccObj))
		Return ""
		
	for k, v in arr
	{ 
		tree .= AddSpace(k - 1) "<span><span name='MS:'>" v.Path "</span>" _DP  "<span name='MS:'>" v.Hwnd "</span>" 
			. _DP "<span name='MS:'>" v.WinClass "</span>" _DP  "<span name='MS:'>" v.ProcessName "</span></span><span name='MS:P'>     </span>"
			. _DP _BP1 " id='b_hwnd_flash' value='" v.Hwnd "'> flash " _BP2 "`n" 
	}
	tree := _T1 " id='P__Tree_Acc_Path'" _T1P "> ( Accessible path ) </span>" _T2 _PRE1 "<span>" tree "</span>" _PRE2
	SaveAccPath(tree)
	Return 1
}

Acc_GetPath(byref arr) {
    Static DesktopHwnd := DllCall("User32.dll\GetDesktopWindow", "ptr") 
	If oPubObj.Acc.CLOAKED
		Return 0
	Acc := Object(oPubObj.Acc.AccObj) 
	arr := []
	
	While Hwnd := Acc_WindowFromObject(Parent := Acc_Parent(Acc)) { 
		If (DesktopHwnd != Hwnd)
			t1 := GetEnumIndex(Acc)
		If t1 = -1
			Return arr := ""
		If (PrHwnd != "" && Hwnd != PrHwnd)
		{
			PrHwnd := Format("0x{:06X}", PrHwnd)
			WinGetClass, WinClass, ahk_id %PrHwnd%
			WinGet, ProcessName, ProcessName, ahk_id %PrHwnd%
			arr.InsertAt(1, {Hwnd: PrHwnd, Path: SubStr(t2, 1, -1), WinClass: WinClass, ProcessName: ProcessName})
		}
		if (t1 = "" || Hwnd = DesktopHwnd)
		   break
		t2 := t1 "." t2
		PrHwnd := Hwnd
		Acc := Parent 
	}
	Return arr.Count()
}

GetEnumIndex(Acc) {	
	If oPubObj.Acc.CLOAKED
		Return -1
	For Each, child in Acc_Children(Acc_Parent(Acc))
	{ 
		if CompareAcc(child, Acc) 
			return A_Index
	}
}

CompareAcc(Acc1, Acc2) { 
	if IsObject(Acc1) && IsObject(Acc2)
	&& (Acc_Location(Acc1) = Acc_Location(Acc2))
	&& (Acc1.accDefaultAction(0) = Acc2.accDefaultAction(0)) 	
	&& (Acc1.accDescription(0) = Acc2.accDescription(0)) 	
	&& (Acc1.accHelp(0) = Acc2.accHelp(0)) 	
	&& (Acc1.accKeyboardShortcut(0) = Acc.accKeyboardShortcut(0)) 
	
	&& (Acc1.accChildCount = Acc2.accChildCount) 
	&& (Acc1.accName(0) = Acc2.accName(0)) 	
	&& (Acc1.accRole(0) = Acc2.accRole(0)) 	
	&& (Acc1.accState(0) = Acc2.accState(0)) 
	&& (Acc1.accValue(0) = Acc2.accValue(0))
		return 1
}

Acc_Children(Acc) {
	if ComObjType(Acc, "Name") != "IAccessible"
		return
	else
	{
		cChildren := Acc.accChildCount, Children := [] 
		if DllCall("oleacc\AccessibleChildren"
		, "Ptr", ComObjValue(Acc)
		, "Int", 0, "Int", cChildren
		, "Ptr", VarSetCapacity(varChildren, cChildren * (8 + 2 * A_PtrSize), 0) * 0 + &varChildren
		, "Int*", cChildren) = 0 
		{
			Loop %cChildren%
				i := (A_Index - 1) * (A_PtrSize * 2 + 8) + 8
				, child := NumGet(varChildren, i)
				, Children.Insert(NumGet(varChildren, i - 8) = 9 ? Acc_Query(child) : child)
				, NumGet(varChildren, i - 8) = 9 ? ObjRelease(child) : ""
			return Children.MaxIndex() ? Children : ""
		}
	}
}
AccGetLocation(Acc, ChildId=0) {
	Static x := 0, y := 0, w := 0, h := 0
	try Acc.accLocation(ComObj(0x4003,&x), ComObj(0x4003,&y), ComObj(0x4003,&w), ComObj(0x4003,&h), ChildId)
	AccCoord[1]:=NumGet(x,0,"int"), AccCoord[2]:=NumGet(y,0,"int"), AccCoord[3]:=NumGet(w,0,"int"), AccCoord[4]:=NumGet(h,0,"int")
}
AccGetLocationToObj(Acc, ChildId=0) {
	Static x := 0, y := 0, w := 0, h := 0
	try Acc.accLocation(ComObj(0x4003,&x), ComObj(0x4003,&y), ComObj(0x4003,&w), ComObj(0x4003,&h), ChildId)
	Return {"x":NumGet(x,0,"int"),"y":NumGet(y,0,"int"),"w":NumGet(w,0,"int"),"h":NumGet(h,0,"int")}
} 
Acc_Location(Acc, ChildId=0) {
	Static x := 0, y := 0, w := 0, h := 0
	try Acc.accLocation(ComObj(0x4003,&x), ComObj(0x4003,&y), ComObj(0x4003,&w), ComObj(0x4003,&h), ChildId)
	return "x" NumGet(x, 0, "int") " y" NumGet(y, 0, "int") " w" NumGet(w, 0, "int") " h" NumGet(h, 0, "int")
}
Acc_ObjectFromPoint(ByRef _idChild_ = "", x = "", y = "") {
	If DllCall("oleacc\AccessibleObjectFromPoint", "Int64", x==""||y==""?0*DllCall("GetCursorPos","Int64*",pt)+pt:x&0xFFFFFFFF|y<<32
		, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
		Return ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}
Acc_ObjectFromWindow(hWnd, idObject = 0) {
	If DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF
		, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81
		,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0
		Return ComObjEnwrap(9,pacc,1)
}

Acc_WindowFromObject(pacc) {
	If DllCall("oleacc\WindowFromAccessibleObject", "Ptr", IsObject(pacc) ? ComObjValue(pacc) : pacc, "Ptr*", hWnd)=0
		Return	hWnd
} 
Acc_Parent(Acc) { 
	try parent := Acc.accParent 
	return parent ? Acc_Query(parent) : ""
}
Acc_Query(Acc) {
	try return ComObj(9, ComObjQuery(Acc, "{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
Acc_Error(p="") {
	static setting:=0
	return p=""?setting:setting:=p
}
Acc_Role(Acc, ChildId=0) {
	try return ComObjType(Acc,"Name")="IAccessible"?Acc_GetRoleText(Acc.accRole(ChildId)):"invalid object"
}
Acc_GetRoleText(nRole)
{
	nSize := DllCall("oleacc\GetRoleText", "Uint", nRole, "Ptr", 0, "Uint", 0)
	VarSetCapacity(sRole, (A_IsUnicode?2:1)*nSize)
	DllCall("oleacc\GetRoleText", "Uint", nRole, "str", sRole, "Uint", nSize+1)
	Return	sRole
}
Acc_ChildrenByRole(Acc, Role) {
	if ComObjType(Acc,"Name")!="IAccessible"
		ErrorLevel := "Invalid IAccessible Object"
	else {
		cChildren:=Acc.accChildCount, Children:=[]
		if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
			Loop %cChildren% {
				i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i)
				if NumGet(varChildren,i-8)=9
					AccChild:=Acc_Query(child), ObjRelease(child), Acc_Role(AccChild)=Role?Children.Insert(AccChild):
				else
					Acc_Role(Acc, child)=Role?Children.Insert(child):
			}
			return Children.MaxIndex()?Children:, ErrorLevel:=0
		} else
			ErrorLevel := "AccessibleChildren DllCall Failed"
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}
Acc_Get(Cmd, ChildPath="", ChildID=0, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="") {
	static properties := {Action:"DefaultAction", DoAction:"DoDefaultAction", Keyboard:"KeyboardShortcut"}
	AccObj :=   IsObject(WinTitle)? WinTitle
			:   Acc_ObjectFromWindow( WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText), 0 )
	if ComObjType(AccObj, "Name") != "IAccessible"
		ErrorLevel := "Could not access an IAccessible Object"
	else {
		StringReplace, ChildPath, ChildPath, _, %A_Space%, All
		AccError:=Acc_Error(), Acc_Error(true)
		Loop Parse, ChildPath, ., %A_Space%
			try {
				if A_LoopField is digit
					Children:=Acc_Children(AccObj), m2:=A_LoopField ; mimic "m2" output in else-statement
				else
					RegExMatch(A_LoopField, "(\D*)(\d*)", m), Children:=Acc_ChildrenByRole(AccObj, m1), m2:=(m2?m2:1)
				if Not Children.HasKey(m2)
					throw
				AccObj := Children[m2]
			} catch {
				ErrorLevel:="Cannot access ChildPath Item #" A_Index " -> " A_LoopField, Acc_Error(AccError)
				if Acc_Error()
					throw Exception("Cannot access ChildPath Item", -1, "Item #" A_Index " -> " A_LoopField)
				return   ; Acc_Error
			}
		Acc_Error(AccError)
		StringReplace, Cmd, Cmd, %A_Space%, , All
		properties.HasKey(Cmd)? Cmd:=properties[Cmd]:
		try {
			if (Cmd = "Location")
				AccObj.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
			  , ret_val := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")
			else if (Cmd = "Object")
				ret_val := AccObj
			else if Cmd in Role,State
				ret_val := Acc_%Cmd%(AccObj, ChildID+0)
			else if Cmd in ChildCount,Selection,Focus
				ret_val := AccObj["acc" Cmd]
			else
				ret_val := AccObj["acc" Cmd](ChildID+0)
		} catch {
			ErrorLevel := """" Cmd """ Cmd Not Implemented"
			if Acc_Error()
				throw Exception("Cmd Not Implemented", -1, Cmd)
			return
		}
		return ret_val, ErrorLevel:=0
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}

	; ___________________________ UIA _________________________________________________

class UIASub {
	__New() { 
		Try this.pUIA := ComObjCreate("{ff48dba4-60ef-4201-aa87-54103eef594e}","{30cbe57d-d9d0-452a-ab13-7ac5ac4825ee}")
		Catch
			Return 0
	}
	__Get(member) { 
		If !this.__Properties(member, PropI, PropW)
			Return 0
		If (PropW = "RECT")
			Return (this.__Hr(DllCall(this.__Vt(PropI, this.pElement), "ptr", this.pElement
			, "ptr", &(rect, VarSetCapacity(rect, 16)))) ? this.__RectToObject(&rect) : 0), VarSetCapacity(rect, 0)
		If !this.__Hr(DllCall(this.__Vt(PropI, this.pElement), "ptr", this.pElement, "ptr*", out))
			Return 0
		Return PropW = "BSTR" ? StrGet(out) : out   
	}
	__RectToObject(prect) { 
		Return {left: NumGet(prect + 0, 0, "Int"), top: NumGet(prect + 0, 4, "Int"), right: NumGet(prect + 0, 8, "Int"), bottom: NumGet(prect + 0, 12, "Int")
			, width: NumGet(prect + 0, 8, "Int") - NumGet(prect + 0, 0, "Int") + 0, height: NumGet(prect + 0, 12, "Int") - NumGet(prect + 0, 4, "Int") + 0}
	}
	__Delete() {
		ObjRelease(this.pUIA)
	}
	__Vt(n, p) {
		Return NumGet(NumGet(p + 0, "ptr") + n * A_PtrSize, "ptr")
	}
	__Hr(hr) {
		;~ http://blogs.msdn.com/b/eldar/archive/2007/04/03/a-lot-of-hresult-codes.aspx
		; Static err:={0x8000FFFF:"Catastrophic failure.",0x80004001:"Not implemented.",0x8007000E:"Out of memory."
		; ,0x80070057:"One or more arguments are not valid.",0x80004002:"Interface not supported.",0x80004003:"Pointer not valid."
		; ,0x80070006:"Handle not valid.",0x80004004:"Operation aborted.",0x80004005:"Unspecified error.",0x80070005:"General access denied."
		; ,0x800401E5:"The object identified by this moniker could not be found.",0x80040201:"UIA_E_ELEMENTNOTAVAILABLE"
		; ,0x80040200:"UIA_E_ELEMENTNOTENABLED",0x80131509:"UIA_E_INVALIDOPERATION",0x80040202:"UIA_E_NOCLICKABLEPOINT"
		; ,0x80040204:"UIA_E_NOTSUPPORTED",0x80040203:"UIA_E_PROXYASSEMBLYNOTLOADED"} ; //not completed
		if hr && (hr &= 0xFFFFFFFF) {
			Return 0
		}
		Return !hr
	}
	__Properties(name, byref index, byref word) {
		Static properties1 := {CurrentProcessId: [20,"int"],CurrentControlType: [21,"CONTROLTYPEID"],CurrentLocalizedControlType: [22,"BSTR"]
		,CurrentName: [23,"BSTR"],CurrentAcceleratorKey: [24,"BSTR"],CurrentAccessKey: [25,"BSTR"],CurrentHasKeyboardFocus: [26,"BOOL"]
		,CurrentIsKeyboardFocusable: [27,"BOOL"],CurrentIsEnabled: [28,"BOOL"],CurrentAutomationId: [29,"BSTR"],CurrentClassName: [30,"BSTR"]
		,CurrentHelpText: [31,"BSTR"],CurrentCulture: [32,"int"],CurrentIsControlElement: [33,"BOOL"],CurrentIsContentElement: [34,"BOOL"]
		,CurrentIsPassword: [35,"BOOL"],CurrentNativeWindowHandle: [36,"UIA_HWND"],CurrentItemType: [37,"BSTR"],CurrentIsOffscreen: [38,"BOOL"]
		,CurrentOrientation: [39,"OrientationType"],CurrentFrameworkId: [40,"BSTR"],CurrentIsRequiredForForm: [41,"BOOL"],CurrentItemStatus: [42,"BSTR"]
		,CurrentBoundingRectangle: [43,"RECT"],CurrentLabeledBy: [44,"IUIAutomationElement"],CurrentAriaRole: [45,"BSTR"]
		,CurrentAriaProperties: [46,"BSTR"],CurrentIsDataValidForForm: [47,"BOOL"],CurrentControllerFor: [48,"IUIAutomationElementArray"]
		,CurrentDescribedBy: [49,"IUIAutomationElementArray"], CurrentFlowsTo: [50,"IUIAutomationElementArray"],CurrentProviderDescription: [51,"BSTR"]}
		
		Static properties2 := {CachedProcessId: [52,"int"],CachedControlType: [53,"CONTROLTYPEID"],CachedLocalizedControlType: [54,"BSTR"]
		,CachedName: [55,"BSTR"],CachedAcceleratorKey: [56,"BSTR"],CachedAccessKey: [57,"BSTR"],CachedHasKeyboardFocus: [58,"BOOL"]
		,CachedIsKeyboardFocusable: [59,"BOOL"],CachedIsEnabled: [60,"BOOL"],CachedAutomationId: [61,"BSTR"],CachedClassName: [62,"BSTR"]
		,CachedHelpText: [63,"BSTR"],CachedCulture: [64,"int"],CachedIsControlElement: [65,"BOOL"],CachedIsContentElement: [66,"BOOL"]
		,CachedIsPassword: [67,"BOOL"],CachedNativeWindowHandle: [68,"UIA_HWND"],CachedItemType: [69,"BSTR"],CachedIsOffscreen: [70,"BOOL"]
		,CachedOrientation: [71,"OrientationType"],CachedFrameworkId: [72,"BSTR"],CachedIsRequiredForForm: [73,"BOOL"]
		,CachedItemStatus: [74,"BSTR"],CachedBoundingRectangle: [75,"RECT"],CachedLabeledBy: [76,"IUIAutomationElement"]
		,CachedAriaRole: [77,"BSTR"],CachedAriaProperties: [78,"BSTR"],CachedIsDataValidForForm: [79,"BOOL"]
		,CachedControllerFor: [80,"IUIAutomationElementArray"],CachedDescribedBy: [81,"IUIAutomationElementArray"]
		,CachedFlowsTo: [82,"IUIAutomationElementArray"],CachedProviderDescription: [83,"BSTR"]}	; (,)(\d+),(.*?)(`r`n)			: [$2,"$3"],
 
		If properties1.HasKey(name)
			Return 1, index := properties1[name][1], word := properties1[name][2]
		If properties2.HasKey(name)
			Return 1, index := properties2[name][1], word := properties2[name][2] 
	}
	__ControlType(n) {
		Static name := {50000:"Button",50001:"Calendar",50002:"CheckBox",50003:"ComboBox",50004:"Edit",50005:"Hyperlink",50006:"Image"
		,50007:"ListItem",50008:"List",50009:"Menu",50010:"MenuBar",50011:"MenuItem",50012:"ProgressBar",50013:"RadioButton"
		,50014:"ScrollBar",50015:"Slider",50016:"Spinner",50017:"StatusBar",50018:"Tab",50019:"TabItem",50020:"Text",50021:"ToolBar"
		,50022:"ToolTip",50023:"Tree",50024:"TreeItem",50025:"Custom",50026:"Group",50027:"Thumb",50028:"DataGrid",50029:"DataItem"
		,50030:"Document",50031:"SplitButton",50032:"Window",50033:"Pane",50034:"Header",50035:"HeaderItem",50036:"Table",50037:"TitleBar",50038:"Separator"}
		Return name[n]
	}
	Release() {
		Return 1, this.pElement && ObjRelease(this.pElement), this.pElement := 0
	} 
	ElementFromPoint(x = "", y = "") {  
		Return this.pElement := this.__Hr(DllCall(this.__Vt(7, this.pUIA), "ptr", this.pUIA, "int64"
			, x = "" ? 0 * DllCall("GetCursorPos", "Int64*", pt) + pt : x & 0xFFFFFFFF | y << 32, "ptr*", pElement)) ? pElement : 0 
	}
	ElementFromHandle(hwnd) {
		Return this.pElement := this.__Hr(DllCall(this.__Vt(6, this.pUIA), "ptr", this.pUIA, "ptr", hwnd, "ptr*", pElement)) ? pElement : 0 
	}
}

	; ___________________________ Mode_Hotkey _________________________________________________

Mode_Hotkey:
	Try SetTimer, Loop_%ThisMode%, Off
	ZoomMsg(10, 1) 
	ShowMarker ? (HideAllMarkers()) : 0
	ColorButton("Button") 
	; oBody.createTextRange().execCommand("RemoveFormat")
	
	ScrollPos[ThisMode, 1] := oDivNew.scrollLeft
	ScrollPos[ThisMode, 2] := oDivNew.scrollTop
	
	If ThisMode != Hotkey
		HTML_%ThisMode% := oDivNew.innerHTML, prNotThisMode := 1
		
	ThisMode := "Hotkey"
	
	If A_GuiControl  ;;	WinActive("ahk_id" hGui)
		Hotkey_Hook(!isPaused)

	If (HTML_Hotkey = "")
		Write_HotkeyHTML({Mods:"Waiting pushed buttons..."}, 1)
	Else 
		Write_Hotkey(prNotThisMode)
	
	TitleText := (TitleTextP1 := "AhkSpy - Button") . TitleTextP2
	SendMessage, 0xC, 0, &TitleText, , ahk_id %hGui% 
	; WinActivate ahk_id %hGui%  
	If A_GuiControl
		GuiControl, 1:Focus, oDoc
	If isFindView
		FindNewText()		
	oDoc.getElementById("b_CASend").innerText := " send to " (oOther.ControlID ? "control" : "window")
	Return

Write_HotkeyHTML(K, scroll = 0) {
	Static PrHK1, PrHK2, Name

	Mods := K.Mods, KeyName := K.Name
	Prefix := K.Pref
	Hotkey := K.HK = "" ? K.TK : K.HK
	LRMods := K.LRMods, LRPref := TransformHTML(K.LRPref)
	ThisKey := K.TK, VKCode := K.VK, SCCode := K.SC
	If (K.NFP && Mods KeyName != "")
		NotPhysical	:= " " _DP "<span style='color:#" ColorDelimiter "'> Emulated</span>"

	HK1 := K.IsCode ? Hotkey : ThisKey
	HK2 := HK1 = PrHK1 ? PrHK2 : PrHK1, PrHK1 := HK1, PrHK2 := HK2
	HKComm1 := "    `;  """ (StrLen(Name := GetKeyName(HK2)) = 1 ? Format("{:U}", Name) : Name)
	HKComm2 := (StrLen(Name := GetKeyName(HK1)) = 1 ? Format("{:U}", Name) : Name) """"

	If K.IsCode
		Comment := "<span class='param' name='MS:SP'>    `;  """ KeyName """</span>"
	If (Hotkey != "")
		FComment := "<span class='param' name='MS:SP'>    `;  """ (K.HK = "" ? K.TK : Mods KeyName) """</span>"

	If (LRMods != "")
	{
		LRMStr := "<span name='MS:'>" LRMods KeyName "</span>"
		If (K.HK != "")
			LRPStr := "  " _DP "  <span><span name='MS:'>" LRPref Hotkey "::</span><span class='param' name='MS:SP'>    `;  """ LRMods KeyName """</span></span>"
	}
	If Prefix !=
		DUMods := (K.MLCtrl ? "{LCtrl Down}" : "") (K.MRCtrl ? "{RCtrl Down}" : "")
			. (K.MLShift ? "{LShift Down}" : "") (K.MRShift ? "{RShift Down}" : "")
			. (K.MLAlt ? "{LAlt Down}" : "") (K.MRAlt ? "{RAlt Down}" : "")
			. (K.MLWin ? "{LWin Down}" : "") (K.MRWin ? "{RWin Down}" : "") . "{" Hotkey "}"
			. (K.MLCtrl ? "{LCtrl Up}" : "") (K.MRCtrl ? "{RCtrl Up}" : "")
			. (K.MLShift ? "{LShift Up}" : "") (K.MRShift ? "{RShift Up}" : "")
			. (K.MLAlt ? "{LAlt Up}" : "") (K.MRAlt ? "{RAlt Up}" : "")
			. (K.MLWin ? "{LWin Up}" : "") (K.MRWin ? "{RWin Up}" : "")

	SendHotkey := Hotkey

	oOther.ControlSend := (DUMods = "" ? "{" SendHotkey "}" : DUMods)

	If (oOther.ControlID || oOther.MouseWinID)
		CASend := _DP  _BP1 " id='b_CASend'> send to " (oOther.ControlID ? "control" : "window") " " _BP2  
  
	VKCode_ := "0x" SubStr(VKCode, 3)
	SCCode_ := "0x" SubStr(SCCode, 3)

	If DecimalCode
		(VKCode_ += 0), SCCode_ += 0
	s_DecimalCode := DecimalCode ? "dec" : "hex"

	If (DUMods != "") 
		LRSend := "  " _DP "  <span><span name='MS:'>" SendMode  " <span name='MS:'>" DUMods "</span></span>" Comment "</span>"
	If SCCode !=
		ThisKeySC := "   " _DP "   <span name='MS:'>" VKCode "</span>   " _DP "   <span name='MS:'>" SCCode "</span>   "
		. _DP "   <span name='MS:' id='v_VKDHCode'>" VKCode_ "</span>   " _DP "   <span name='MS:' id='v_SCDHCode'>" SCCode_ "</span>"
	Else
		ThisKeySC := "   " _DP "   <span name='MS:' id='v_VKDHCode'>" VKCode_ "</span>"
	
	
	HTML_Hotkey := ""
	. _T1 "> ( Pushed buttons ) </span>" _BT1 " id='pause_button'> pause " _BT2  _DB  _BT1 " id='LButton_Hotkey'> LButton " _BT2  _T2 
	
	. _PRE1 "<br><span name='MS:'>" Mods  KeyName "</span>" NotPhysical "<br><br>" LRMStr "<br>" _PRE2 

	. _T1 "> ( Command syntax ) </span>" _BT1 " id='SendCode'> " SendCode " " _BT2  _DB  _BT1 " id='SendMode'> " SendModeStr " " _BT2  _T2 

	. _PRE1 "<br><span><span name='MS:'>" Prefix  Hotkey "::</span>" FComment "</span>" LRPStr 

	. "`n<span name='MS:P'>        </span>"

	. "`n<span><span name='MS:'>" SendMode " <span name='MS:'>" Prefix "{" SendHotkey "}</span></span>" Comment "</span>" LRSend 

	. "`n<span name='MS:P'>        </span>"

	. "`n<span><span name='MS:'>ControlSend, ahk_parent, <span name='MS:'>" oOther.ControlSend "</span>, WinTitle</span>" Comment . CASend "</span>"

	. "`n<span name='MS:P'>        </span>"
	
	. "`n<span><span name='MS:'>GetKeyState(""" SendHotkey """, ""P"")</span>" Comment "</span>   " 
		. _DP "   <span><span name='MS:'>KeyWait, " SendHotkey ", D T0.5</span>" Comment "</span>"
	
	. "`n<span name='MS:P'>        </span>"

	. "`n<span><span name='MS:'>" HK2 " & " HK1 "::</span><span class='param' name='MS:SP'>" HKComm1 " & " HKComm2 "</span></span>   " 
		. _DP "   <span><span name='MS:'>" HK2 "::" HK1 "</span><span class='param' name='MS:SP'>" HKComm1 " &#8250 &#8250 " HKComm2 "</span></span>"
	
	. "`n<span name='MS:P'>        </span>" _PRE2

	. _T1 "> ( Key ) </span>" _BT1 " id='numlock'> num " _BT2  _DB  _BT1 " id='locale_change'> locale " _BT2  
		. _DB  _BT1 " id='hook_reload'> hook reload " _BT2  _DB  _BT1 " id='b_DecimalCode'> " s_DecimalCode " " _BT2
		. _DB  _BT1 " id='hotkey_clip_cursor'> clip cursor " _BT2  _T2 
		
	. _PRE1 "<br><span name='MS:'>" ThisKey "</span>   " _DP "   <span name='MS:'>" VKCode  SCCode "</span>" ThisKeySC 
	
	. "`n`n" _PRE2

	. _T1 "> ( GetKeyName ) </span>" _BT1 " id='paste_keyname'> paste " _BT2  _T2 
	. "<br>"
	. "<span id='hotkeybox'><input id='edithotkey' value='" oDoc.getElementById("edithotkey").value "'><button id='keyname'> &#8250 </button>"
		. "<input id='editkeyname' value='" oDoc.getElementById("editkeyname").value "'></span>"
	. "<br>"
	. "<br>"
	. "<span id='vkname'>" GetVKCodeNameStr "</span><span id='scname'>" GetSCCodeNameStr "</span>"
	. _T0


	HTML_Hotkey = %HTML_Hotkey%
	( 
		<style> 
		pre {
			line-height: 1.1em;
		}
		#SendCode, #SendMode {
			text-align: center;
			position: absolute;
		}
		#SendCode {
			width: 3em; left: 12em;
		}
		#SendMode {
			width: 5em; left: 16em;
		}
		#hotkeybox {
			position: relative;
			white-space: pre;
			left: 5px;
			display: inline;
		}
		#edithotkey, #keyname, #editkeyname {
			font-size: 1.2em;
			text-align: center;
			border: 1px dotted;
			border-color: #%ColorFont%;
		}
		#keyname {
			position: relative;
			background-color: #%ColorParam%;
			top: 0px; left: 2px; width: 3em;
			width: 3em;
		}
		#editkeyname {
			position: relative;
			left: 4px; top: 0px;
		} 
		</style>
	) 
	Write_Hotkey(scroll)
}

Write_Hotkey(scroll = 0) {
	oDivOld := oDivWork%DivWorkIndex%
	DivWorkIndex := DivWorkIndex = 1 ? 2 : 1
	oDivNew := oDivWork%DivWorkIndex%  
	oDivNew.innerHTML := HTML_Hotkey  
	oDivNew.scrollTop := scroll ? ScrollPos[ThisMode, 2] : (ScrollPos[ThisMode, 2] := oDivOld.scrollTop)
		
	If oDivNew.scrollLeft
		oDivNew.scrollLeft := 0 

	oDivNew.style.zIndex := 1 
	oDivOld.style.zIndex := 0 
	
	oDivNew.style.visibility := "visible"
	oDivOld.innerHTML := ""
	Return 1
}

	; ___________________________ Hotkey Functions _________________________________________________

	;;  http://forum.script-coding.com/viewtopic.php?pid=69765#p69765

Hotkey_Init(Func, Options = "") {
	#HotkeyInterval 0
	Hotkey_Arr("Func", Func)
	Hotkey_Arr("Up", !!InStr(Options, "U"))
	Hotkey_MouseAndJoyInit(Options)
	Hotkey_SetHook()
	Hotkey_Arr("Hook") ? (Hotkey_Hook(0), Hotkey_Hook(1)) : 0
}

Hotkey_Main(In) {
	Static Prefix := {"LCtrl":"<^","LShift":"<+","LAlt":"<!","LWin":"<#"
	,"RCtrl":">^","RShift":">+","RAlt":">!","RWin":">#"}, K := {}, ModsOnly
	Local IsMod, sIsMod
	IsMod := In.IsMod
	If (In.Opt = "Down") {
		If (K["M" IsMod] != "")
			Return 1
		sIsMod := SubStr(IsMod, 2)
		K["M" sIsMod] := sIsMod "+", K["P" sIsMod] := SubStr(Prefix[IsMod], 2)
		K["M" IsMod] := IsMod "+", K["P" IsMod] := Prefix[IsMod]
	}
	Else If (In.Opt = "Up") {
		sIsMod := SubStr(IsMod, 2)
		K.ModUp := 1, K["M" IsMod] := K["P" IsMod] := ""
		If (K["ML" sIsMod] = "" && K["MR" sIsMod] = "")
			K["M" sIsMod] := K["P" sIsMod] := ""
		If (!Hotkey_Arr("Up") && K.HK != "")
			Return 1
	}
	Else If (In.Opt = "OnlyMods") {
		If !ModsOnly
			Return 0
		K.MCtrl := K.MShift := K.MAlt := K.MWin := K.Mods := ""
		K.PCtrl := K.PShift := K.PAlt := K.PWin := K.Pref := ""
		K.PRCtrl := K.PRShift := K.PRAlt := K.PRWin := ""
		K.PLCtrl := K.PLShift := K.PLAlt := K.PLWin := K.LRPref := ""
		K.MRCtrl := K.MRShift := K.MRAlt := K.MRWin := ""
		K.MLCtrl := K.MLShift := K.MLAlt := K.MLWin := K.LRMods := ""
		Func(Hotkey_Arr("Func")).Call(K)
		Return ModsOnly := 0
	}
	Else If (In.Opt = "GetMod")
		Return !!(K.PCtrl K.PShift K.PAlt K.PWin)
	Else If (In = "LButton")
		GoTo, Hotkey_PressLButton

	K.UP := In.UP, K.IsJM := 0, K.Time := In.Time, K.NFP := In.NFP, K.IsMod := IsMod
	K.Mods := K.MCtrl K.MShift K.MAlt K.MWin
	K.LRMods := K.MLCtrl K.MRCtrl K.MLShift K.MRShift K.MLAlt K.MRAlt K.MLWin K.MRWin
	K.VK := "vk" In.VK, K.SC := "sc" In.SC, K.TK := GetKeyName(K.VK K.SC)
	K.TK := K.TK = "" ? K.VK K.SC : (StrLen(K.TK) = 1 ? Format("{:U}", K.TK) : K.TK)
	(IsMod) ? (K.HK := K.Pref := K.LRPref := K.Name := K.IsCode := "", ModsOnly := K.Mods = "" ? 0 : 1)
	: (K.IsCode := (SendCode != "name" && StrLen(K.TK) = 1)  ;;	 && !Instr("1234567890-=", K.TK)
	, K.HK := K.IsCode ? K[SendCode] : K.TK
	, K.Name := K.HK = "vkBF" ? "/" : K.TK
	, K.Pref := K.PCtrl K.PShift K.PAlt K.PWin
	, K.LRPref := K.PLCtrl K.PRCtrl K.PLShift K.PRShift K.PLAlt K.PRAlt K.PLWin K.PRWin
	, ModsOnly := 0)
	Func(Hotkey_Arr("Func")).Call(K)
	Return 1

Hotkey_PressLButton:
	ThisHotkey := "LButton"
	K.NFP := !GetKeyState(ThisHotkey, "P")
	GoTo, Hotkey_Drop

Hotkey_PressMouseRButton:
	If !WM_CONTEXTMENU() && !Hotkey_Hook(0)
		Return

Hotkey_PressJoy:
Hotkey_PressMouse:
	ThisHotkey := A_ThisHotkey
	K.NFP := !GetKeyState(ThisHotkey, "P")
Hotkey_Drop:
	K.Time := A_TickCount
	K.Mods := K.MCtrl K.MShift K.MAlt K.MWin
	K.LRMods := K.MLCtrl K.MRCtrl K.MLShift K.MRShift K.MLAlt K.MRAlt K.MLWin K.MRWin
	K.Pref := K.PCtrl K.PShift K.PAlt K.PWin
	K.LRPref := K.PLCtrl K.PRCtrl K.PLShift K.PRShift K.PLAlt K.PRAlt K.PLWin K.PRWin
	K.HK := K.Name := K.TK := ThisHotkey, ModsOnly := K.UP := K.IsCode := 0, K.IsMod := K.SC := ""
	K.IsJM := A_ThisLabel = "Hotkey_PressJoy" ? 1 : 2
	K.VK := A_ThisLabel = "Hotkey_PressJoy" ? "" : Format("vk{:X}", GetKeyVK(ThisHotkey))
	Func(Hotkey_Arr("Func")).Call(K)
	Return 1
}

#If Hotkey_Arr("Hook")
#If Hotkey_Arr("Hook") && GetKeyState("RButton", "P")
#If Hotkey_Arr("Hook") && !Hotkey_Main({Opt:"GetMod"})
#If

Hotkey_MouseAndJoyInit(Options) {
	Static MouseKey := "MButton|WheelDown|WheelUp|WheelRight|WheelLeft|XButton1|XButton2"
	Local S_FormatInteger, Option
	Option := InStr(Options, "M") ? "On" : "Off"
	Hotkey, IF, Hotkey_Arr("Hook")
	Loop, Parse, MouseKey, |
		Hotkey, %A_LoopField%, Hotkey_PressMouse, % Option
	Option := InStr(Options, "L") ? "On" : "Off"
	Hotkey, IF, Hotkey_Arr("Hook") && GetKeyState("RButton"`, "P")
	Hotkey, LButton, Hotkey_PressMouse, % Option
	Option := InStr(Options, "R") ? "On" : "Off"
	Hotkey, IF, Hotkey_Arr("Hook")
	Hotkey, RButton, Hotkey_PressMouseRButton, % Option
	Option := InStr(Options, "J") ? "On" : "Off"
	S_FormatInteger := A_FormatInteger
	SetFormat, IntegerFast, D
	Hotkey, IF, Hotkey_Arr("Hook") && !Hotkey_Main({Opt:"GetMod"})
	Loop, 128
		Hotkey % Ceil(A_Index / 32) "Joy" Mod(A_Index - 1, 32) + 1, Hotkey_PressJoy, % Option
	SetFormat, IntegerFast, %S_FormatInteger%
	Hotkey, IF
}

Hotkey_Hook(Val = 1) {
	Hotkey_Arr("Hook", Val)
	!Val && Hotkey_Main({Opt:"OnlyMods"})
}

Hotkey_Arr(P*) {
	Static Arr := {}
	Return P.MaxIndex() = 1 ? Arr[P[1]] : (Arr[P[1]] := P[2])
}

	;;  http://forum.script-coding.com/viewtopic.php?id=6350

Hotkey_LowLevelKeyboardProc(nCode, wParam, lParam) {
	Static Mods := {"A4":"LAlt","A5":"RAlt","A2":"LCtrl","A3":"RCtrl"
	,"A0":"LShift","A1":"RShift","5B":"LWin","5C":"RWin"}, oMem := []
	, HEAP_ZERO_MEMORY := 0x8, Size := 16, hHeap := DllCall("GetProcessHeap", Ptr)
	Local pHeap, Lp, Ext, VK, SC, SC1, SC2, IsMod, Time, NFP, KeyUp
	Critical

	If !Hotkey_Arr("Hook")
		Return DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "UInt", wParam, "UInt", lParam)
	pHeap := DllCall("HeapAlloc", Ptr, hHeap, UInt, HEAP_ZERO_MEMORY, Ptr, Size, Ptr)
	DllCall("RtlMoveMemory", Ptr, pHeap, Ptr, lParam, Ptr, Size), oMem.Push(pHeap)
	SetTimer, Hotkey_HookProcWork, -10
	Return nCode < 0 ? DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "UInt", wParam, "UInt", lParam) : 1

	Hotkey_HookProcWork:
		While (oMem[1] != "") {
			If Hotkey_Arr("Hook") {
				Lp := oMem[1]
				VK := Format("{:X}", NumGet(Lp + 0, "UInt"))
				Ext := NumGet(Lp + 0, 8, "UInt")
				SC1 := NumGet(Lp + 0, 4, "UInt")
				NFP := (Ext >> 4) & 1				;;  Не физическое нажатие
				KeyUp := Ext >> 7
				;; Time := NumGet(Lp + 12, "UInt")
				IsMod := Mods[VK]
				If !SC1
					SC2 := GetKeySC("vk" VK), SC := SC2 = "" ? "" : Format("{:X}", SC2)
				Else
					SC := Format("{:X}", (Ext & 1) << 8 | SC1)
				If !KeyUp
					IsMod ? Hotkey_Main({VK:VK, SC:SC, Opt:"Down", IsMod:IsMod, NFP:NFP, Time:Time, UP:0})
					: Hotkey_Main({VK:VK, SC:SC, NFP:NFP, Time:Time, UP:0})
				Else
					IsMod ? Hotkey_Main({VK:VK, SC:SC, Opt:"Up", IsMod:IsMod, NFP:NFP, Time:Time, UP:1})
					: (Hotkey_Arr("Up") ? Hotkey_Main({VK:VK, SC:SC, NFP:NFP, Time:Time, UP:1}) : 0)
			}
			DllCall("HeapFree", Ptr, hHeap, UInt, 0, Ptr, Lp)
			oMem.RemoveAt(1)
		}
		Return
}

Hotkey_SetHook(On = 1) {
	Static hHook
	If (On = 1 && !hHook)
		hHook := DllCall("SetWindowsHookEx" . (A_IsUnicode ? "W" : "A")
				, "Int", 13   ;;  WH_KEYBOARD_LL
				, "Ptr", RegisterCallback("Hotkey_LowLevelKeyboardProc", "Fast")
				, "Ptr", DllCall("GetModuleHandle", "UInt", 0, "Ptr")
				, "UInt", 0, "Ptr")
	Else If !On
		DllCall("UnhookWindowsHookEx", "Ptr", hHook), hHook := "", Hotkey_Hook(0)
}

GetVKCodeName(id) {  
  ;;	https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes
  ;;	http://www.kbdedit.com/manual/low_level_vk_list.html

	Static Start, VK_, Chr, Num, Undefined, Reserved, Unassigned, VK_Names
	
	If !Start
	{
		Start := 1 
		VK_ := {01:"VK_LBUTTON",02:"VK_RBUTTON",03:"VK_CANCEL",04:"VK_MBUTTON",05:"VK_XBUTTON1",06:"VK_XBUTTON2",08:"VK_BACK",09:"VK_TAB"
		,0C:"VK_CLEAR",0D:"VK_RETURN",10:"VK_SHIFT",11:"VK_CONTROL",12:"VK_MENU",13:"VK_PAUSE",14:"VK_CAPITAL"
		,15:"VK_KANA := VK_HANGEUL := VK_HANGUL := VK_HANGUEL"
		,17:"VK_JUNJA",18:"VK_FINAL",19:"VK_HANJA := VK_KANJI",1B:"VK_ESCAPE",1C:"VK_CONVERT",1D:"VK_NONCONVERT",1E:"VK_ACCEPT"
		,1F:"VK_MODECHANGE",20:"VK_SPACE",21:"VK_PRIOR",22:"VK_NEXT",23:"VK_END",24:"VK_HOME",25:"VK_LEFT",26:"VK_UP",27:"VK_RIGHT"
		,28:"VK_DOWN",29:"VK_SELECT",2A:"VK_PRINT",2B:"VK_EXECUTE",2C:"VK_SNAPSHOT",2D:"VK_INSERT",2E:"VK_DELETE",2F:"VK_HELP"
		,30:"VK_KEY_0",31:"VK_KEY_1",32:"VK_KEY_2",33:"VK_KEY_3",34:"VK_KEY_4",35:"VK_KEY_5",36:"VK_KEY_6",37:"VK_KEY_7",38:"VK_KEY_8"
		,39:"VK_KEY_9",41:"VK_KEY_A",42:"VK_KEY_B",43:"VK_KEY_C",44:"VK_KEY_D",45:"VK_KEY_E",46:"VK_KEY_F",47:"VK_KEY_G",48:"VK_KEY_H"
		,49:"VK_KEY_I",4A:"VK_KEY_J",4B:"VK_KEY_K",4C:"VK_KEY_L",4D:"VK_KEY_M",4E:"VK_KEY_N",4F:"VK_KEY_O",50:"VK_KEY_P",51:"VK_KEY_Q"
		,52:"VK_KEY_R",53:"VK_KEY_S",54:"VK_KEY_T",55:"VK_KEY_U",56:"VK_KEY_V",57:"VK_KEY_W",58:"VK_KEY_X",59:"VK_KEY_Y",5A:"VK_KEY_Z"
		,5B:"VK_LWIN",5C:"VK_RWIN",5D:"VK_APPS",5F:"VK_SLEEP",60:"VK_NUMPAD0",61:"VK_NUMPAD1",62:"VK_NUMPAD2",63:"VK_NUMPAD3"
		,64:"VK_NUMPAD4",65:"VK_NUMPAD5",66:"VK_NUMPAD6",67:"VK_NUMPAD7",68:"VK_NUMPAD8",69:"VK_NUMPAD9",6A:"VK_MULTIPLY"
		,6B:"VK_ADD",6C:"VK_SEPARATOR",6D:"VK_SUBTRACT",6E:"VK_DECIMAL",6F:"VK_DIVIDE",70:"VK_F1",71:"VK_F2",72:"VK_F3",73:"VK_F4"
		,74:"VK_F5",75:"VK_F6",76:"VK_F7",77:"VK_F8",78:"VK_F9",79:"VK_F10",7A:"VK_F11",7B:"VK_F12",7C:"VK_F13",7D:"VK_F14",7E:"VK_F15"
		,7F:"VK_F16",80:"VK_F17",81:"VK_F18",82:"VK_F19",83:"VK_F20",84:"VK_F21",85:"VK_F22",86:"VK_F23",87:"VK_F24"}
	
		VK__ := {90:"VK_NUMLOCK",91:"VK_SCROLL",92:"VK_OEM_FJ_JISHO := VK_OEM_NEC_EQUAL",93:"VK_OEM_FJ_MASSHOU",94:"VK_OEM_FJ_TOUROKU"
		,95:"VK_OEM_FJ_LOYA",96:"VK_OEM_FJ_ROYA",A0:"VK_LSHIFT",A1:"VK_RSHIFT",A2:"VK_LCONTROL",A3:"VK_RCONTROL",A4:"VK_LMENU"
		,A5:"VK_RMENU",A6:"VK_BROWSER_BACK",A7:"VK_BROWSER_FORWARD",A8:"VK_BROWSER_REFRESH",A9:"VK_BROWSER_STOP",AA:"VK_BROWSER_SEARCH"
		,AB:"VK_BROWSER_FAVORITES",AC:"VK_BROWSER_HOME",AD:"VK_VOLUME_MUTE",AE:"VK_VOLUME_DOWN",AF:"VK_VOLUME_UP",B0:"VK_MEDIA_NEXT_TRACK"
		,B1:"VK_MEDIA_PREV_TRACK",B2:"VK_MEDIA_STOP",B3:"VK_MEDIA_PLAY_PAUSE",B4:"VK_LAUNCH_MAIL",B5:"VK_LAUNCH_MEDIA_SELECT"
		,B6:"VK_LAUNCH_APP1",B7:"VK_LAUNCH_APP2",BA:"VK_OEM_1",BB:"VK_OEM_PLUS",BC:"VK_OEM_COMMA",BD:"VK_OEM_MINUS",BE:"VK_OEM_PERIOD"
		,BF:"VK_OEM_2",C0:"VK_OEM_3",C1:"VK_ABNT_C1",C2:"VK_ABNT_C2",DB:"VK_OEM_4",DC:"VK_OEM_5",DD:"VK_OEM_6",DE:"VK_OEM_7",DF:"VK_OEM_8"
		,E1:"VK_OEM_AX",E2:"VK_OEM_102",E3:"VK_ICO_HELP",E4:"VK_ICO_00",E5:"VK_PROCESSKEY",E6:"VK_ICO_CLEAR",E7:"VK_PACKET",E9:"VK_OEM_RESET"
		,EA:"VK_OEM_JUMP",EB:"VK_OEM_PA1",EC:"VK_OEM_PA2",ED:"VK_OEM_PA3",EE:"VK_OEM_WSCTRL",EF:"VK_OEM_CUSEL",F0:"VK_OEM_ATTN"
		,F1:"VK_OEM_FINISH",F2:"VK_OEM_COPY",F3:"VK_OEM_AUTO",F4:"VK_OEM_ENLW",F5:"VK_OEM_BACKTAB",F6:"VK_ATTN",F7:"VK_CRSEL"
		,F8:"VK_EXSEL",F9:"VK_EREOF",FA:"VK_PLAY",FB:"VK_ZOOM",FC:"VK_NONAME",FD:"VK_PA1",FE:"VK_OEM_CLEAR",FF:"VK__none_"}
	 
		for k, v in VK__
			VK_[k] := v
		VK_Names := {}
		for k, v in VK_
			for a, b in StrSplit(v, ":=", " ")
				VK_Names[b] := k
			 
		Undefined := "07|0E|0F|16|1A|3A|3B|3C|3D|3E|3F|40"
		Reserved := "0A|0B|5E|B8|B9|C3|C4|C5|C6|C7|C8|C9|CA|CB|CC|CD|CE|CF|D0|D1|D2|D3|D4|D5|D6|D7|E0"
		Unassigned := "88|89|8A|8B|8C|8D|8E|8F|97|98|99|9A|9B|9C|9D|9E|9F|D8|D9|DA|E8"
	}
	If (id ~= "i)^vk_") && VK_Names.HasKey(id)
		Return QVK(oDoc.getElementById("edithotkey").value := Format("{:U}", id), "0x" VK_Names[id])  ;;	vK_EreOF
		
	If VK := GetKeyVK(id)  
		id := Format("0x{:02X}", VK)
	Else If (id ~= "i)^vk")
		id := "0x" RegExReplace(id, "i)(^vk([0-9a-f]+)).*", "$2")  
		
	If !(InStr(id, "0x") && id > 0 && id < 256)
		Return   ;;	"Is not virtual key code" 
	id := Format("{:02X}", id) 
	If VK_[id]
		Return  QVK(VK_[id], "0x" id)  
	If InStr("|" Undefined "|", "|" id "|")
		Return QVK("0x" id " is Undefined", "", 0)
	If InStr("|" Reserved "|", "|" id "|")
		Return QVK("0x" id " is Reserved", "", 0)
	If InStr("|" Unassigned "|", "|" id "|")
		Return QVK("0x" id " is Unassigned", "", 0) 
} 

QVK(key, value, VK = 1) {
	Static S, T, Description1, Description2
	If !S && S := 1 
		T := _T1 "> ( GetKeyVK ) </span>" _T2 "<br>"
		, Description1 := "<span style='color: #" ColorParam "'>Virtual-key code symbolic names:  </span>"
		, Description2 := "<span style='color: #" ColorDelimiter "'>Virtual-key code symbolic names:  </span>"
	If VK
		Return T _PRE1 Description1 "<span><span name='MS:'>" key "</span><span class='param' name='MS:SP'> := " value "</span></span><br>" _PRE2
	Return T _PRE1 Description2 "<span class='QStyle2'>" key "</span><br>" _PRE2
}

GetScanCode(id) { 
	If SC := GetKeySC(id) 
		Return _T1 "> ( GetKeySC ) </span>" _T2 "<br>" _PRE1 "<span name='MS:'>" Format("0x{:03X}", SC) "</span><br>" _PRE2 
}


	; ___________________________ Menu Labels _________________________________________________

ShowSys(x, y) {
ShowSys:
	ZoomMsg(9, 1)
	DllCall("SetTimer", "Ptr", A_ScriptHwnd, "Ptr", 1, "UInt", 116, "Ptr", RegisterCallback("MenuCheck", "Fast"))
	Menu, Sys, Show, % x, % y
	ZoomMsg(9, 0)
	Return
}

MenuCheck()  {
	DllCall("KillTimer", "Ptr", A_ScriptHwnd, "Ptr", 1)
	If !WinExist("ahk_class #32768 ahk_pid " oOther.CurrentProcessId)
		Return
	If GetKeyState("RButton")
	{
		MouseGetPos, , , WinID
		Menu := MenuGetName(GetMenuForMenu(WinID))
		If Menu && (F := oMenu[Menu][oOther.ThisMenuItem := AccUnderMouse(WinID, Id).accName(Id)]) && (F ~= "^_")
		{
			;; If !(F ~= "^_") ;; Return DllCall("mouse_event", "UInt", 0x0002|0x0004)  
			;;	WinClose("ahk_class #32768 ahk_pid " oOther.CurrentProcessId), SetTimer(F, -1)
			oOther.MenuItemExist := 1
			If IsLabel(F)
				GoSub, % F
			Else
				%F%()
			oOther.MenuItemExist := 0
		}
		KeyWait, RButton
	}
	DllCall("SetTimer", "Ptr", A_ScriptHwnd, "Ptr", 1, "UInt", 16, "Ptr", RegisterCallback("MenuCheck", "Fast"))
}

GetMenuForMenu(hWnd) {
	SendMessage, 0x1E1, 0, 0, , ahk_id %hWnd%	;;  MN_GETHMENU
	hMenu := ErrorLevel
	If (hMenu + 0)
		Return hMenu
}

AccUnderMouse(WinID, ByRef child) {
	Static h
	If Not h
		h := DllCall("LoadLibrary", "Str", "oleacc", "Ptr")
	If DllCall("oleacc\AccessibleObjectFromPoint"
		, "Int64", 0 * DllCall("GetCursorPos", "Int64*", pt) + pt, "Ptr*", pacc
		, "Ptr", VarSetCapacity(varChild, 8 + 2 * A_PtrSize, 0) * 0 + &varChild) = 0
	Acc := ComObjEnwrap(9, pacc, 1)
	If IsObject(Acc)
		Return Acc, child := NumGet(varChild, 8, "UInt")
}

MaxHeightStrToNum()  {
	Return Round(A_ScreenHeight / SubStr(PreMaxHeightStr, 5))
}

_DarkTheme: 
	IniWrite(DarkTheme := !DarkTheme, "DarkTheme")
	Menu, View, % DarkTheme ? "Check" : "UnCheck"
	, % oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	Return
	
_ActiveScriptAllowChange: 
	IniWrite(ActiveScriptAllowChange := !ActiveScriptAllowChange, "ActiveScriptAllowChange")
	Menu, Script, % ActiveScriptAllowChange ? "Check" : "UnCheck"
	, % oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	Return
	
_FontBold: 
	IniWrite(FontBold := !FontBold, "FontBold")
	Menu, View, % FontBold ? "Check" : "UnCheck"
	, % oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	Return

_ViewStrPos:
	IniWrite(ViewStrPos := !ViewStrPos, "ViewStrPos")
	Menu, View, % ViewStrPos ? "Check" : "UnCheck"
	, % oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	Return

_MenuOverflowLabel:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	PreOverflowHide := ThisMenuItem = "Switch off" ? 0 : 1
	IniWrite(ThisMenuItem, "MaxHeightOverFlow")
	for k, v in ["Switch off","1 / 1","1 / 2","1 / 3","1 / 4","1 / 5","1 / 6","1 / 8","1 / 10","1 / 15"]
		Menu, Overflow, UnCheck, % v
	Menu, Overflow, Check, % PreMaxHeightStr := ThisMenuItem
	PreMaxHeight := MaxHeightStrToNum()
	_PreOverflowHideCSS := ".lpre {max-width: 99`%; max-height: " PreMaxHeight "px; overflow: auto; border: 1px solid #" ColorPreOverflowHide ";}"
	ChangeCSS("css_PreOverflowHide", PreOverflowHide ? _PreOverflowHideCSS : "")
	AnchorFitScroll()
	Return

_Sys_Backlight:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	Menu, Sys, UnCheck, % BLGroup[StateLight]
	Menu, Sys, Check, % ThisMenuItem
	IniWrite((StateLight := InArr(ThisMenuItem, BLGroup)), "StateLight")
	Return

_MemoryAnchor:
	IniWrite(MemoryAnchor := !MemoryAnchor, "MemoryAnchor")
	If MemoryAnchor
		IniWrite(oOther.anchor["Win_text"], "Win_Anchor")
		, IniWrite(oOther.anchor["Control_text"], "Control_Anchor")
	Menu, Script, % MemoryAnchor ? "Check" : "UnCheck", Remember anchor
	Return

_AnchorFullScroll:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	IniWrite(AnchorFullScroll := !AnchorFullScroll, "AnchorFullScroll") 
	Menu, View, % AnchorFullScroll ? "Check" : "UnCheck", % ThisMenuItem 
	
	If AnchorFullScroll
		AnchorScroll()
	Else 
		oJScript.QS(oDivNew, "#id_T0").style.height := 0 "px" 
	oDivNew.scrollTop := oDivNew.scrollTop + oDoc.getElementById("anchor").getBoundingClientRect().top - 6
	Return

_DynamicControlPath:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	IniWrite(DynamicControlPath := !DynamicControlPath, "DynamicControlPath")
	Menu, View, % DynamicControlPath ? "Check" : "UnCheck", % ThisMenuItem
	Return

_DynamicAccPath:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	IniWrite(DynamicAccPath := !DynamicAccPath, "DynamicAccPath")
	Menu, View, % DynamicAccPath ? "Check" : "UnCheck", % ThisMenuItem
	Return

_UseUIA:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	IniWrite(UseUIA := !UseUIA, "UseUIA")
	If UseUIA && !IsObject(exUIASub)
		exUIASub := new UIASub
	Menu, View, % UseUIA ? "Check" : "UnCheck", % ThisMenuItem
	Return
	
_UIAAlienDetect:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	IniWrite(UIAAlienDetect := !UIAAlienDetect, "UIAAlienDetect") 
	Menu, View, % UIAAlienDetect ? "Check" : "UnCheck", % ThisMenuItem
	Return

_SelStartMode:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	for k, v in ["Window","Control","Button","Last Mode"]
		Menu, Startmode, UnCheck, % v
	IniWrite({"Window":"Win","Control":"Control","Button":"Hotkey","Last Mode":"LastMode"}[ThisMenuItem], "StartMode")
	LastModeSave := (ThisMenuItem = "Last Mode")
	Menu, Startmode, Check, % ThisMenuItem
	Return

_OnlyShiftTab:
	IniWrite(OnlyShiftTab := !OnlyShiftTab, "OnlyShiftTab")
	Menu, Sys, % (OnlyShiftTab ? "Check" : "UnCheck"), Spot only Shift+Tab
	ZoomMsg(12, OnlyShiftTab)
	If !OnlyShiftTab
		Try SetTimer, Loop_%ThisMode%, -100
	If OnlyShiftTab && ActiveNoPause
		GoSub _Active_No_Pause
	Return

_Active_No_Pause:
	ActiveNoPause := IniWrite(!ActiveNoPause, "ActiveNoPause")
	Menu, Sys, % (ActiveNoPause ? "Check" : "UnCheck"), Work with the active window
	ZoomMsg(6, ActiveNoPause)
	If OnlyShiftTab && ActiveNoPause
		GoSub _OnlyShiftTab
	Return

_Suspend:
	isAhkSpy := !isAhkSpy
	Menu, Sys, % !isAhkSpy ? "Check" : "UnCheck", Suspend hotkeys
	ZoomMsg(8, !isAhkSpy)
	Return

_CheckUpdate:
	SetTimer, UpdateAhkSpy, Off
	SetTimer, Upd_Verifi, Off
	StateUpdate := IniWrite(!StateUpdate, "StateUpdate")
	Menu, Sys, % (StateUpdate ? "Check" : "UnCheck"), Check updates
	If StateUpdate
		SetTimer, UpdateAhkSpy, -1 
	Return
	
_CheckAhkNewVersion:
	SetTimer, CheckAhkNewVersion, Off
	SetTimer, lCheckAhkNewVersion, Off
	CheckAhkNewVersion := IniWrite(!CheckAhkNewVersion, "CheckAhkNewVersion")
	Menu, Help, % (CheckAhkNewVersion ? "Check" : "UnCheck"), Check updates AutoHotkey
	If CheckAhkNewVersion
		SetTimer, CheckAhkNewVersion, -1 
	Return


_Sys_Acclight:
	StateLightAcc := IniWrite(!StateLightAcc, "StateLightAcc"), HideAccMarker()
	Menu, Sys, % (StateLightAcc ? "Check" : "UnCheck"), Acc object backlight
	Return

_Sys_WClight:
	StateLightMarker := IniWrite(!StateLightMarker, "StateLightMarker"), HideMarker()
	Menu, Sys, % (StateLightMarker ? "Check" : "UnCheck"), Window or control backlight
	Return

_Spot_Together:
	StateAllwaysSpot := IniWrite(!StateAllwaysSpot, "AllwaysSpot")
	Menu, Sys, % (StateAllwaysSpot ? "Check" : "UnCheck"), Spot together (low speed)
	Return

_MemoryPos:
	IniWrite(MemoryPos := !MemoryPos, "MemoryPos")
	Menu, Script, % MemoryPos ? "Check" : "UnCheck", Remember position
	SavePos()
	Return

_MemorySize:
	IniWrite(MemorySize := !MemorySize, "MemorySize")
	Menu, Script, % MemorySize ? "Check" : "UnCheck", Remember size
	SaveSize()
	Return

_MemoryFontSize:
	IniWrite(MemoryFontSize := !MemoryFontSize, "MemoryFontSize")
	Menu, Script, % MemoryFontSize ? "Check" : "UnCheck", Remember font size
	If MemoryFontSize
		IniWrite(FontSize, "FontSize")
	Return

_MemoryZoomSize:
	IniWrite(MemoryZoomSize := !MemoryZoomSize, "MemoryZoomSize")
	Menu, Script, % MemoryZoomSize ? "Check" : "UnCheck", Remember zoom size
	ZoomMsg(4, MemoryZoomSize)
	Return
	
_MinimizeEscape:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	IniWrite(MinimizeEscape := !MinimizeEscape, "MinimizeEscape")
	Menu, Script, % MinimizeEscape ? "Check" : "UnCheck", %ThisMenuItem%
	Return

_MoveTitles:
	IniWrite(MoveTitles := !MoveTitles, "MoveTitles")
	Menu, View, % MoveTitles ? "Check" : "UnCheck", Moving titles
	if oJScript.MoveTitles := MoveTitles
		oJScript.shift(0)
	else
		oDivNew.scrollLeft := 0, oJScript.conleft30()
	Return
	
_MarkerInvertFrame:
	IniWrite(MarkerInvertFrame := !MarkerInvertFrame, "MarkerInvertFrame")
	Menu, View, % MarkerInvertFrame ? "Check" : "UnCheck", Flash edge
	WinSet, Region, , ahk_id %hMarkerGui%
	Return

_MemoryStateZoom:
	IniWrite(MemoryStateZoom := !MemoryStateZoom, "MemoryStateZoom")
	Menu, Script, % MemoryStateZoom ? "Check" : "UnCheck", Remember state zoom
	IniWrite(oOther.ZoomShow, "ZoomShow")
	Return

_WordWrap:
	IniWrite(WordWrap := !WordWrap, "WordWrap")
	Menu, View, % WordWrap ? "Check" : "UnCheck", Word wrap
	If WordWrap
		oDivNew.scrollLeft := 0
	oJScript.WordWrap := WordWrap
	ChangeCSS("css_Body", WordWrap ? _BodyWrapCSS : "")
	Return

Sys_Help:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	If ThisMenuItem = AutoHotKey official help online
		RunPath("http://ahkscript.org/docs/AutoHotkey.htm")
	Else If ThisMenuItem = AutoHotKey russian help online
		RunPath("http://www.script-coding.com/AutoHotkeyTranslation.html")
	Else If ThisMenuItem = About
		RunPath("http://forum.script-coding.com/viewtopic.php?pid=72459#p72459")
	Else If ThisMenuItem = About english
		RunPath("https://www.autohotkey.com/boards/viewtopic.php?f=6&t=52872") 
	Return

LaunchHelp:
	If !FileExist(SubStr(A_AhkPath,1,InStr(A_AhkPath,"\",,0,1)) "AutoHotkey.chm")
		Return
	IfWinNotExist AutoHotkey Help ahk_class HH Parent ahk_exe hh.exe
		Run % SubStr(A_AhkPath,1,InStr(A_AhkPath,"\",,0,1)) "AutoHotkey.chm"
	WinActivate
	Minimize()
	Return

DefaultSize:
	If FullScreenMode
	{
		FullScreenMode()
		Gui, 1: Restore
		Sleep 200
	}
	Gui, 1: Show, % "NA w" widthTB "h" HeightStart
	ZoomMsg(5)
	If !MemoryFontSize
		oDoc.getElementById("pre").style.fontSize := FontSize := 15
	Return

Reload:
	Reload
	Return

Help_OpenUserDir:
	RunPath(Path_User)
	Return

Help_OpenScriptDir:
	SelectFilePath(A_ScriptFullPath)
	Minimize()
	Return

	; ___________________________ Functions _________________________________________________

WM_ACTIVATE(wp, lp) {
	Critical
	If isConfirm
		Return
	If ((wp & 0xFFFF = 0) && lp != hGui)  ;;	Deactivated
	{
		ZoomMsg(7, 0)
		If Hotkey_Arr("Hook")
			Hotkey_Hook(0)
	}
	Else If (wp & 0xFFFF != 0 && WinActive("ahk_id" hGui)) ;;	Activated
	{
		ZoomMsg(7, 1)
		If (ThisMode = "Hotkey" && !isPaused)
			Hotkey_Hook(1)
		If !ActiveNoPause
			HideAllMarkers(), CheckHideMarker()
	}
}

WM_WINDOWPOSCHANGED(Wp, Lp) {
	Static PtrAdd := A_PtrSize = 8 ? 8 : 0
	; Critical
	If (NumGet(Lp + 0, 0, "Ptr") != hGui) || Sleep = 1
		Return  
		
	If oOther.ZoomShow
	{
		x := NumGet(Lp + 0, 8 + PtrAdd, "UInt")
		y := NumGet(Lp + 0, 12 + PtrAdd, "UInt")
		w := NumGet(Lp + 0, 16 + PtrAdd, "UInt")
		
		hDWP := DllCall("BeginDeferWindowPos", "Int", 2)
		
		; hDWP := DllCall("DeferWindowPos"
		; , "Ptr", hDWP, "Ptr", hGui, "UInt", -1  ;;	for +AlwaysOnTop
		; , "Int", 0, "Int", 0, "Int", 0, "Int", 0
		; , "UInt", 0x0003)    ;;  SWP_NOMOVE := 0x0002 | SWP_NOSIZE := 0x0001
		
		hDWP := DllCall("DeferWindowPos"
		, "Ptr", hDWP, "Ptr", oOther.hZoom, "UInt", 0
		, "Int", x + w, "Int", y, "Int", 0, "Int", 0
		, "UInt", 0x0011)    ;; 0x0010 := SWP_NOACTIVATE | 0x0001 := SWP_NOSIZE
		
		hDWP := DllCall("DeferWindowPos"
		, "Ptr", hDWP, "Ptr", oOther.hZoomLW, "UInt", 0
		, "Int", x + w + 1, "Int", y + 46, "Int", 0, "Int", 0
		, "UInt", 0x0211)    ;; 0x0010 := SWP_NOACTIVATE | 0x0001 := SWP_NOSIZE | SWP_NOOWNERZORDER := 0x0200
		
		DllCall("EndDeferWindowPos", "Ptr", hDWP)
	}
	If MemoryPos
		SetTimer, SavePos, -400  
} 

GuiSize:
	If A_Gui != 1
		Return
	If A_EventInfo = 1
		ZoomMsg(11, 1)
	Sleep := A_EventInfo  ;;	= 1 minimize
	If A_EventInfo != 1
	{
		ControlsMove(A_GuiWidth, A_GuiHeight)
		If MemorySize
			SetTimer, SaveSize, -400
	}
	Else
		HideAllMarkers(), CheckHideMarker()
	Try SetTimer, Loop_%ThisMode%, % A_EventInfo = 1 || isPaused ? "Off" : "On"
	Return

Minimize() {
	Sleep := 1
	Gui, 1: Minimize
}

GetNameFile(Folder, Name = "Myfile ", Ext = "txt", i = 1) {
	While FileExist(Folder "\" Name "(" i ")." Ext)
		i := A_Index
	Return Folder "\" Name "(" i ")." Ext
}

TimerFunc(hFunc, Time) {
	Try SetTimer, % hFunc, % Time
}

Exit() {
	Gui, %hGui%:, Hide
	Hotkey_SetHook(0)
	If LastModeSave
		IniWrite(ThisMode, "LastMode")  
	oDoc := ""
	DllCall("ReleaseDC", "UPtr", 0, "UPtr", hDCMarkerInvert)
	ExitApp
}

GuiClose() {
	If MinimizeEscape && GetKeyState("Esc", "P")
		Return 1, Minimize()  
	ExitApp
}

CheckAhkVersion:
	If A_AhkVersion < 1.1.33.02
	{
		MsgBox Requires AutoHotkey_L version 1.1.33.02+
		RunPath("http://ahkscript.org/download/")
		ExitApp
	}
	Return

ChangeMode() {
	Try SetTimer, Loop_%ThisMode%, Off
	HideAllMarkers(), MS_Cancel()
	GoSub % "Mode_" (ThisMode = "Control" ? "Win" : "Control")
}
	
WM_NCLBUTTONDOWN(wp) {
	Static HTMINBUTTON := 8

	If (wp = HTMINBUTTON)
	{
		SetTimer, Minimize, -10
		Return 0
	}
} 

TransParent(v) {
	oOther.TransParent := !v
	WinSet, TransParent, % v, % "ahk_id" hGui
	WinSet, TransParent, % v, % "ahk_id" oOther.hZoom
	If !v
		WinHide, % "ahk_id" oOther.hZoomLW
	Else
		WinShow, % "ahk_id" oOther.hZoomLW
} 
		
WM_RBUTTONDOWN(wp, lp, msg, hwnd, tp = 0) { 
	If (hwnd = hColorProgress && !ActiveNoPause && !isPaused && ThisMode != "Hotkey")
	{
		If GetKeyState("Shift")
			TransParent(0)
		ToolTip("Spot", 300)
		ZoomMsg(7, 0) 
		ActiveNoPause := 1
		If OnlyShiftTab 
			OnlyShiftTab := 0, oOther.OnlyShiftTabReset := 1, ZoomMsg(12, 0)
		SetTimer, Loop_%ThisMode%, -1 
		SetTimer, RButton_Up_Wait, -1
	}
} 

RButton_Up_Wait:
	If GetKeyState("RButton", "P") || GetKeyState("MButton", "P") {
		SetTimer, %A_ThisLabel%, -30
		Return
	}
	ActiveNoPause := 0 
	If oOther.OnlyShiftTabReset
		OnlyShiftTab := 1, oOther.OnlyShiftTabReset := 0, ZoomMsg(12, 1)
	If OnlyShiftTab
		SetTimer, Loop_%ThisMode%, Off 
	SetTimer, ShiftUpHide, -300
	Sleep 100
	If GetKeyState("LShift", "P")
	{ 
		ZoomMsg(2, 1)
		HideAllMarkers()
		oObjActive.Magnify.Call(2)
		oObjActive.Redraw.Call()  
	}   
	If oOther.TransParent
		TransParent("Off")  
	If !OnlyShiftTab  
	{
		WinActivate ahk_id %hGui%
		GuiControl, 1:Focus, oDoc
	}
	ToolTip("Stop", 300)
	ZoomMsg(2, 0)
	Return

Mod_Up_Wait_And_TransParent:
	If GetKeyState("LShift", "P") || GetKeyState("LControl", "P") {
		SetTimer, %A_ThisLabel%, -50
		Return
	}
	Sleep := 1
	; ZoomMsg(3) 
	If oOther.OnlyShiftTabReset
		OnlyShiftTab := 1, oOther.OnlyShiftTabReset := 0, ZoomMsg(12, 1)
	HideAllMarkers()
	ZoomMsg(2, 1)
	oObjActive.Magnify.Call(2)
	oObjActive.Redraw.Call()   
	TransParent("Off")
	If !OnlyShiftTab || oOther.OnlyShiftTabReset
	{
		WinActivate ahk_id %hGui%
		GuiControl, 1:Focus, oDoc 
	} 
	ToolTip("Stop", 300)  
	ZoomMsg(2, 0)
	Sleep := 0
	Return


ColorButton(name) {
	for k, v in ["Window", "Control", "Button"]
		ColorProgress("Color_" v, v = name ? ColorSelModeButton : ColorBgModeButton) 
}

ColorProgress(name, color) {  
	GuiControl, % "TB: +Background" color, %name% 
	Gui, TB: Color, %ColorBg%
}

WM_LBUTTONDOWN(wp, lp, msg, hwnd) { 
	If (A_GuiControl = "Color_Window")   
		Gosub Mode_Win
	Else If (A_GuiControl = "Color_Control")  
		Gosub Mode_Control
	Else If (A_GuiControl = "Color_Button")  
		Gosub Mode_Hotkey
	Else If (A_GuiControl = "Color_Zoom")  
		AhkSpyZoomShow() 
	Else If (hwnd = hFindGui)
	{
		MouseGetPos, , , , hControl, 2
		If (hControl = hFindAllText)
			SetTimer, FindAll, -250 
	}
	Else If A_GuiControl = ColorProgress
	{
		If ThisMode = Hotkey
			oDoc.execCommand("Paste"), ToolTip("Paste", 300)
		Else
		{ 
			SendInput {LAlt Down}{Escape}{LAlt Up}
			ToolTip("Alt+Escape", 300)
			ZoomMsg(7, 0)
			If (OnlyShiftTab && !isPaused)
			{
				ToolTip("Spot", 300) 
				OnlyShiftTab := 0
				ZoomMsg(12, 0)
				SetTimer, Loop_%ThisMode%, -1
				SetTimer, OnlyShiftTab_LButton_Up_Wait, -1
			}
		}
	}
}
 
OnlyShiftTab_LButton_Up_Wait:
	KeyWait, LButton 
	OnlyShiftTab := 1
	ZoomMsg(12, 1)
	SetTimer, Loop_%ThisMode%, Off
	SetTimer, ShiftUpHide, -300
	Sleep 100
	ToolTip("Stop", 300) 
	return

   ;;  http://forum.script-coding.com/viewtopic.php?pid=131490#p131490
/*
ChildFromPath(str, hwnd) 
{
	Static GW_HWNDNEXT := 2, GW_CHILD := 5
	hwnd := DllCall("GetWindow", "Ptr", hwnd, UInt, GW_CHILD, "Ptr")
	arr := StrSplit(str, "."), off := 1, i := 1
	Loop 
	{
		If (i = arr[off])
		{
			If (off = arr.Count())
				return hwnd
			hwnd := DllCall("GetWindow", "Ptr", hwnd, UInt, GW_CHILD, "Ptr"), ++off, i := 1 
		}
		Else If (++i) && !(hwnd := DllCall("GetWindow", "Ptr", hwnd, UInt, GW_HWNDNEXT, "Ptr"))
			return   
	}
} 
*/
ChildToPath(hwnd) {
	If !WinExist("ahk_id" hwnd)
		Return 0
	arr := []
 	_ChildToPath(hwnd, arr) 
	for k, v in arr
	{  
		Hwnd := Format("0x{:06X}", v.Hwnd)
		WinGetClass, WinClass, ahk_id %Hwnd%
		WinGet, ProcessName, ProcessName, ahk_id %Hwnd%
		tree .= AddSpace2(k - 1) "<span><span name='MS:'>" v.Path "</span>" _DP  "<span name='MS:'>" Hwnd "</span>" 
			. _DP "<span name='MS:'>" WinClass "</span>" _DP  "<span name='MS:'>" ProcessName "</span></span><span name='MS:P'>     </span>"
			. _DP _BP1 " id='b_hwnd_flash' value='" Hwnd "'> flash " _BP2 "`n"
	} 
	tree := _T1 " id='P__Tree_Control_Path'" _T1P "> ( Control path ) </span>" _T2 _PRE1 "<span>" tree "</span>" _PRE2 
	SaveChildPath(tree)
	Return 1
}

_ChildToPath(hwnd, arr, i = 1) {
	Static GA_PARENT := 1, GA_ROOT := 2, GW_HWNDPREV := 3
	Static DesktopHwnd := DllCall("User32.dll\GetDesktopWindow", "ptr") 
	While hPrev := DllCall("GetWindow", "Ptr", hwnd, UInt, GW_HWNDPREV, "Ptr")
		++i, hwnd := hPrev
	   ;;  DllCall("GetParent", "Ptr", hwnd)
	hParent := DllCall("GetAncestor", "Ptr", hwnd, Uint, GA_PARENT)
	if !hParent || (hParent = DesktopHwnd)
		return
	arr.InsertAt(1, {Hwnd:hParent,Path: RTrim(i "." arr[1].Path, ".")})
	return _ChildToPath(hParent, arr, 1)
}

AddSpace2(c) {
	loop % c
		Tab .= "<span class='param';'>↓  </span>"
	Return Tab
}
SaveChildPath(Path = "") {
	Static p
	If Path =
		Return p
	p := Path
}

ActivateUnderMouse() {
	MouseGetPos, , , WinID
 	WinActivate, ahk_id %WinID%
}

MouseGetPosScreen(ByRef x, ByRef y) {
	VarSetCapacity(POINT, 8, 0)
	NumPut(x, &POINT, 0, "Int")
	NumPut(y, &POINT, 4, "Int")
	DllCall("GetCursorPos", "Ptr", &POINT)
	x := NumGet(POINT, 0, "Int"), y := NumGet(POINT, 4, "Int")
}

WM_CONTEXTMENU() {
	MouseGetPos, , , wid, cid, 2
	If (hColorProgress = cid) {
		Gosub, PausedScript
		ToolTip("Pause", 300)
		Return 0
	}
	Else If (cid != hActiveX && wid = hGui) {
		SetTimer, ShowSys, -1
		Return 0
	}
	Return 1
}

IsTextArea() {
	MouseGetPos, , , , cid, 3
	Return (DllCall("GetParent", Ptr, cid) = hActiveX)
}

ControlsMove(Width, Height) { 
	hDWP := DllCall("BeginDeferWindowPos", "Int", isFindView ? 3 : 2)
	hDWP := DllCall("DeferWindowPos"
	, "Ptr", hDWP, "Ptr", hTBGui, "UInt", 0
	, "Int", (Width - widthTB) // 2.2, "Int", 0, "Int", 0, "Int", 0
	, "UInt", 0x0011)    ;; 0x0010 := SWP_NOACTIVATE | 0x0001 := SWP_NOSIZE
	hDWP := DllCall("DeferWindowPos"
	, "Ptr", hDWP, "Ptr", hActiveX, "UInt", 0
	, "Int", 0, "Int", HeigtButton
	, "Int", Width, "Int", Height - HeigtButton - (isFindView ? 28 : 0)
	, "UInt", 0x0010)    ;; 0x0010 := SWP_NOACTIVATE
	If isFindView
		hDWP := DllCall("DeferWindowPos"
		, "Ptr", hDWP, "Ptr", hFindGui, "UInt", 0
		, "Int", (Width - widthTB) // 2.2, "Int", (Height - (Height < HeigtButton * 2 ? -2 : 27))
		, "Int", 0, "Int", 0
		, "UInt", 0x0011)    ;; 0x0010 := SWP_NOACTIVATE | 0x0001 := SWP_NOSIZE
	DllCall("EndDeferWindowPos", "Ptr", hDWP)
	
	SetTimer, AnchorFitScroll, -500 
}

ZoomSpot() {
	If (!isPaused && Sleep != 1 && WinActive("ahk_id" hGui))
		(ThisMode = "Control" ? (Spot_Control() (StateAllwaysSpot ? Spot_Win() : 0) Write_Control()) : (Spot_Win() (StateAllwaysSpot ? Spot_Control() : 0) Write_Win()))
}

MsgZoom(wParam, lParam) {  ;;	получает
	If (wParam = 1)  ;;	шаг мыши
		SetTimer, ZoomSpot, -1
	Else If (wParam = 2)  ;;	ZoomShow
		oOther.ZoomShow := lParam, (MemoryStateZoom && IniWrite(lParam, "ZoomShow"))
	Else If (wParam = 0)  ;;	хэндл окна
		oOther.hZoom := lParam
	Else If (wParam = 3)  ;;	хэндл окна LW
		oOther.hZoomLW := lParam
}	

WM_COPYDATA(wParam, lParam) { 
    CopyOfData := StrGet(NumGet(lParam + 2*A_PtrSize))   
	If (wParam = 1 && ThisMode = "Control") {
		arr := StrSplit(CopyOfData, "`n") 
		BGR := arr[1], offX := arr[2], offY := arr[3]
		ColorRGB := Format("0x{:06X}", (BGR & 0xFF) << 16 | (BGR & 0xFF00) | (BGR >> 16))
		ColorBGR := Format("0x{:06X}", BGR)
		oDoc.getElementById("ColorRGB").innerText := ColorRGB
		oDoc.getElementById("sColorRGB").innerText := SubStr(ColorRGB, 3)  
		oDoc.getElementById("ColorBGR").innerText := ColorBGR
		oDoc.getElementById("sColorBGR").innerText := SubStr(ColorBGR, 3)  
		sInvert_RGB := Format("{:06X}", ColorRGB ^ 0xFFFFFF)    
		oDoc.getElementById("sInvert_RGB0").innerText := "0x" sInvert_RGB
		oDoc.getElementById("sInvert_RGB").innerText := sInvert_RGB 
		oDoc.getElementById("RenderInvert_RGB").style.backgroundColor := "#" sInvert_RGB
		GuiControl, TB: -Redraw, ColorProgress
		GuiControl, % "TB: +c" SubStr(ColorRGB, 3), ColorProgress
		GuiControl, TB: +Redraw, ColorProgress  
		
		oDoc.getElementById("coord_screen").innerText := "x" (osCoords.MXS + offX) " y" (osCoords.MYS + offY)
		oDoc.getElementById("coord_win").innerText := "x" (osCoords.RWinX + offX) " y" (osCoords.RWinY + offY)
		oDoc.getElementById("coord_client").innerText := "x" (osCoords.MXC + offX) " y" (osCoords.MYC + offY)
		oDoc.getElementById("coord_awin").innerText := "x" (osCoords.MXWA + offX) " y" (osCoords.MYWA + offY)
		oDoc.getElementById("coord_rwin").innerText := Round((osCoords.RWinX + offX) / osCoords.WinW, 4) ", " Round((osCoords.RWinY + offY) / osCoords.WinH, 4)
		oDoc.getElementById("coord_rclient").innerText := Round((osCoords.MXC + offX) / osCoords.caW, 4) ", " Round((osCoords.MYC + offY) / osCoords.caH, 4)
	}
    return true
}

ZoomMsg(wParam = -1, lParam = -1) {  ;;	отправляет
	If WinExist("AhkSpyZoom ahk_id" oOther.hZoom)
		SendMessage, % MsgAhkSpyZoom, wParam, lParam, , % "ahk_id" oOther.hZoom
}

ZoomSleep() {
	Sleep := 1
}
ZoomNoSleep() {
	Sleep := 0
}

AhkSpyZoomShow() {
	If !oPubObjGUID
		ObjRegisterActive(oObjActive, oPubObjGUID := CreateGUID())
		, oObjActive.AhkSpy_Minimize := Func("Minimize")
		, oObjActive.ZoomSleep := Func("ZoomSleep")
		, oObjActive.ZoomNoSleep := Func("ZoomNoSleep")
	If !WinExist("ahk_id" oOther.hZoom) {
		Hotkey := ThisMode = "Hotkey"
		Suspend := !isAhkSpy
		If A_IsCompiled
			Run "%A_ScriptFullPath%" "Zoom" "%hGui%" "%ActiveNoPause%" "%isPaused%" "%Suspend%" "%Hotkey%" "%OnlyShiftTab%" "%oPubObjGUID%" "%HeigtButton%", , , PID
		Else
			Run "%A_AHKPath%" "%A_ScriptFullPath%" "Zoom" "%hGui%" "%ActiveNoPause%" "%isPaused%" "%Suspend%" "%Hotkey%" "%OnlyShiftTab%" "%oPubObjGUID%" "%HeigtButton%", , , PID
		WinWait, % "ahk_pid" PID, , 1
	}
	Else If DllCall("IsWindowVisible", "Ptr", oOther.hZoom)
		ZoomMsg(0)
	Else
		ZoomMsg(1) 
	SetTimer(Func("ColorProgress").Bind("Color_Zoom", ColorSelModeButton), "-" 1)
	SetTimer(Func("ColorProgress").Bind("Color_Zoom", ColorBgModeButton), "-" 150)
} 

SetPosObject(Name, arr) {
	If !oOther.ZoomShow
		Return
	oObjActive["Coords" Name] := arr
} 

SavePos() {
	If FullScreenMode || !MemoryPos
		Return
	WinGet, Min, MinMax, ahk_id %hGui%
	If (Min = 0)
	{
		WinGetPos, WinX, WinY, , , ahk_id %hGui%
		IniWrite(WinX, "MemoryPosX"), IniWrite(WinY, "MemoryPosY")
	}
}

SaveSize() {
	If FullScreenMode || !MemorySize
		Return
	WinGet, Min, MinMax, ahk_id %hGui%
	If (Min = 0)
	{
		GetClientPos(hGui, _, _, WinWidth, WinHeight)
		IniWrite(WinWidth, "MemorySizeW"), IniWrite(WinHeight, "MemorySizeH")
	}
}

	;;  http://forum.script-coding.com/viewtopic.php?pid=87817#p87817
	;;  http://www.autohotkey.com/board/topic/93660-embedded-ie-shellexplorer-render-issues-fix-force-it-to-use-a-newer-render-engine/

   ; +1:: MsgBox % oDoc.compatMode "`n" oDoc.documentMode
   
FixIE() {
	Key := "Software\Microsoft\Internet Explorer\MAIN"
	. "\FeatureControl\FEATURE_BROWSER_EMULATION", ver := 8000
	If A_IsCompiled
		ExeName := A_ScriptName
	Else
		SplitPath, A_AhkPath, ExeName
	RegRead, value, HKCU, %Key%, %ExeName%
	If (value != ver)
		RegWrite, REG_DWORD, HKCU, %Key%, %ExeName%, %ver%
}

; так не работает  https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/ms537169%28v%3dvs.85%29
ActiveScriptAllow(Off = 0) {
	Static keyInternet := "Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3", IsAllow := 1
	If !ActiveScriptAllowChange
		Return
	If !Off
	{
		RegRead, value, HKCU, %KEYInternet%, 1400
		If (value = 0)   ; Включено
			Return 
		IsAllow := 0 
		RegWrite, REG_DWORD, HKCU, %KEYInternet%, 1400, 0   ; Включить
		Return
	}
	Else If !IsAllow 
		RegWrite, REG_DWORD, HKCU, %KEYInternet%, 1400, 3   ; Выключить
}

ObjRegisterActive(Object, CLSID, Flags := 0) {
   static cookieJar := {}
   if !CLSID  {
      if (( cookie := cookieJar.Delete(Object) ) != "")
         DllCall("oleaut32\RevokeActiveObject", UInt, cookie, Ptr, 0)
      Return
   }
   if cookieJar[Object]
      throw Exception("Object is already registered", -1)
   VarSetCapacity(_clsid, 16, 0)
   if (hr := DllCall("ole32\CLSIDFromString", WStr, CLSID, Ptr, &_clsid)) < 0
      throw Exception("Invalid CLSID", -1, CLSID)
   hr := DllCall("oleaut32\RegisterActiveObject", Ptr, &Object, Ptr, &_clsid, UInt, Flags, UIntP, cookie, UInt)
   if hr < 0
      throw Exception(format("Error 0x{:x}", hr), -1)
   cookieJar[Object] := cookie
}

CreateGUID()
{
   VarSetCapacity(pguid, 16, 0)
   if !DllCall("ole32.dll\CoCreateGuid", Ptr, &pguid)  {
      size := VarSetCapacity(sguid, (38 << !!A_IsUnicode) + 1, 0)
      if DllCall("ole32.dll\StringFromGUID2", Ptr, &pguid, Ptr, &sguid, UInt, size)
         Return StrGet(&sguid)
   }
}

RunPath(Link, WorkingDir = "", Option = "") {
	Run %Link%, %WorkingDir%, %Option%
	Minimize()
}

RunRealPath(Path) {
	SplitPath, Path, , Dir
	Dir := LTrim(Dir, """")
	While !InStr(FileExist(Dir), "D")
		Dir := SubStr(Dir, 1, -1)
	Run, %Path%, %Dir%
}

RunAhkPath(Path, Param = "") {
	SplitPath, Path, , , Extension
	If Extension = exe
		RunPath(Path)
	Else If (!A_IsCompiled && Extension = "ahk")
		RunPath("""" A_AHKPath """ """ Path """ """ Param """")
}

RunShell(Path) {
	ComObjCreate("WScript.Shell").Exec(Path)
}

ExtraFile(Name, GetNoCompile = 0) {
	If FileExist(Path_User "\" Name ".exe")
		Return Path_User "\" Name ".exe"
	If !A_IsCompiled && FileExist(Path_User "\" Name ".ahk")
		Return Path_User "\" Name ".ahk"
}

ShowMarker(x, y, w, h, b := 4) { 
	(w < 8 || h < 8) && (b := 2)
	ShowMarkers(oShowMarkers, x, y, w, h, b)
}

ShowAccMarker(x, y, w, h, b := 2) { 
	ShowMarkers(oShowAccMarkers, x, y, w, h, b)
}

ShowMarkerEx(x, y, w, h, b := 4) { 
	(w < 8 || h < 8) && (b := 2)
	ShowMarkers(oShowMarkersEx, x, y, w, h, b)
}

HideMarker() {
	HideMarkers(oShowMarkers)
}

HideAccMarker() {
	HideMarkers(oShowAccMarkers)
}

HideMarkerEx() {
	HideMarkers(oShowMarkersEx)
}

HideAllMarkers() {
	HideMarker(), HideAccMarker()
}

ShowMarkers(arr, x, y, w, h, b) {
	hDWP := DllCall("BeginDeferWindowPos", "Int", 4)
	for k, v in [[x, y, b, h],[x, y+h-b, w, b],[x+w-b, y, b, h],[x, y, w, b]]
		{
			hDWP := DllCall("DeferWindowPos"
			, "Ptr", hDWP, "Ptr", arr[k], "UInt", -1  ;;	-1 := HWND_TOPMOST
			, "Int", v[1], "Int", v[2], "Int", v[3], "Int", v[4]
			, "UInt", 0x0250)    ;; 0x0010 := SWP_NOACTIVATE | 0x0040 := SWP_SHOWWINDOW | SWP_NOOWNERZORDER := 0x0200
		}
	DllCall("EndDeferWindowPos", "Ptr", hDWP)
	ShowMarker := 1
}

HideMarkers(arr) {
	hDWP := DllCall("BeginDeferWindowPos", "Int", 4)
	Loop 4
		hDWP := DllCall("DeferWindowPos"
		, "Ptr", hDWP, "Ptr", arr[A_Index], "UInt", 0
		, "Int", 0, "Int", 0, "Int", 0, "Int", 0
		, "UInt", 0x0083)    ;; 0x0080 := SWP_HIDEWINDOW | SWP_NOMOVE := 0x0002 | SWP_NOSIZE := 0x0001
	DllCall("EndDeferWindowPos", "Ptr", hDWP)
	ShowMarker := 0
}

ShowMarkersCreate(arr, color) {
	If !!%arr%
		Return
	S_DefaultGui := A_DefaultGui, %arr% := {}
	
	loop 4
	{
		Gui, New
		Gui, Margin, 0, 0
		Gui, -DPIScale +Owner +HWNDHWND -Caption +%WS_CHILDWINDOW% +E%WS_EX_NOACTIVATE% +ToolWindow -%WS_POPUP% +AlwaysOnTop  +E%WS_EX_TRANSPARENT% 
		Gui, Color, %color% 
		WinSet, TransParent, 250, ahk_id %HWND%
		%arr%[A_Index] := HWND
		Gui, Show, NA Hide
	}
	Gui, %S_DefaultGui%:Default
}

CheckHideMarker() {
	Static Try
	Try := 0
	SetTimer, __CheckHideMarker, -50
	Return

	__CheckHideMarker:
		If (Sleep = 1 || (WinActive("ahk_id" hGui) && !ActiveNoPause) || isPaused)
			HideAllMarkers()
		If (Try := ++Try > 2 ? 0 : Try)
			SetTimer, __CheckHideMarker, -150
		Return
}

FlashArea(x, y, w, h, att = 1) {
	Static hFunc, max := 6
	If (att = 1)
		Try SetTimer, % hFunc, Off
	Mod(att, 2) ? ShowMarkerInvert(x, y, w, h, 5) : HideMarkerInvert()
	If (att = max)
		Return
	hFunc := Func("FlashArea").Bind(x, y, w, h, ++att)
	SetTimer, % hFunc, -100
}

CreateMarkerInvert() {    
	Gui, MI: -DPIScale +HWNDhMarkerGui -Caption +AlwaysOnTop +ToolWindow +E%WS_EX_TRANSPARENT% 
	hDCMarkerInvert := DllCall("GetDC", "Ptr", hMarkerGui)
	WinSet, TransParent, 0, ahk_id %hMarkerGui% 
}

HideMarkerInvert() {
	WinSet, TransParent, 0, ahk_id %hMarkerGui% 
 	Gui, MI: Show, Hide
}

ShowMarkerInvert(x, y, w, h, b := 6) {
	Try Gui, MI: Show, NA x%x% y%y% w%w% h%h% 
	If MarkerInvertFrame
	{
		w < 16 || h < 16 ? b := 2 : 0
		WinSet, Region, % "0-0 " w "-0 " w "-" h " 0-" h " 0-0 " b "-" b
			. " " w-b "-" b " " w-b "-" h-b " " b "-" h-b " " b "-" b, ahk_id %hMarkerGui%
	}
	hDC := DllCall("GetDC", "Ptr", 0, "Ptr") 
	
	DllCall("BitBlt", "Ptr", hDCMarkerInvert, "int", 0, "int", 0, "int", w, "int", h
			, "Ptr", hDC, "int", X, "int", Y, "Uint", 0x00330008)   ;; NOTSRCCOPY
	
	WinSet, TransParent, 255, ahk_id %hMarkerGui%
	Gui, MI: +AlwaysOnTop
	DllCall("ReleaseDC", "UPtr", 0, "UPtr", hDC)
}

SetEditColor(hwnd, BG, FG) {
	Edits[hwnd] := {BG:BG,FG:FG}
	WM_CTLCOLOREDIT(DllCall("GetDC", "Ptr", hwnd), hwnd)
	DllCall("RedrawWindow", "Ptr", hwnd, "Uint", 0, "Uint", 0, "Uint", 0x1|0x4)
}

WM_CTLCOLOREDIT(wParam, lParam) {
	If !Edits.HasKey(lParam)
		Return 0
	hBrush := DllCall("CreateSolidBrush", UInt, Edits[lParam].BG)
	DllCall("SetTextColor", Ptr, wParam, UInt, Edits[lParam].FG)
	DllCall("SetBkColor", Ptr, wParam, UInt, Edits[lParam].BG)
	DllCall("SetBkMode", Ptr, wParam, UInt, 2)
	Return hBrush
}

InArr(Val, Arr) {
	For k, v in Arr
		If (v == Val)
			Return k
}

TransformHTML(str) {
	Transform, str, HTML, %str%, 3
	StringReplace, str, str, <br>, , 1
	Return str
}

PausedTitleText() {
	Static i := 0, Str := "           Paused..."
 	If !isPaused
		Return i := 0
	i := i > 20 ? 2 : i + 1
	TitleTextP2 := "     " SubStr(Str, i) . SubStr(Str, 1, i - 1)
	TitleText := TitleTextP1 . TitleTextP2
	If !FreezeTitleText
		SendMessage, 0xC, 0, &TitleText, , ahk_id %hGui%
	SetTimer, PausedTitleText, -200
}

TitleText(Text, Time = 1000) {
	FreezeTitleText := 1
	StringReplace, Text, Text, `r`n, % Chr(8629), 1
	StringReplace, Text, Text, %A_Tab%, % "      ", 1
	SendMessage, 0xC, 0, &Text, , ahk_id %hGui%
	SetTimer, TitleShow, -%Time%
}

TitleShow:
	SendMessage, 0xC, 0, &TitleText, , ahk_id %hGui%
	FreezeTitleText := 0
	Return

ClipAdd(Text, AddTip = 0) {
	If ClipAdd_Before
		Clipboard := Text ClipAdd_Delimiter Clipboard
	Else
		Clipboard := Clipboard ClipAdd_Delimiter Text
	If AddTip
		ToolTip("add", 300)
}

ClipPaste() {
 	If oMS.ELSel && (oMS.ELSel.OuterText != "" || MS_Cancel())
		oMS.ELSel.innerHTML := TransformHTML(Clipboard), oMS.ELSel.Name := "MS:"
		, MoveCaretToSelection(0)
	Else
		oDoc.execCommand("Paste")
	ToolTip("paste", 300)
}

CutSelection() {
 	If MS_IsSelection()
		MoveCaretToSelection(0), Clipboard := oMS.ELSel.OuterText
		, oMS.ELSel.OuterText := "", MS_Cancel()
	Else
		oDoc.execCommand("Cut")
	ToolTip("cut", 300)
}

DeleteSelection() {
 	If MS_IsSelection()
		MoveCaretToSelection(0), oMS.ELSel.OuterText := "", MS_Cancel()
	Else
		oDoc.execCommand("Delete")
}

PasteStrSelection(Str) {
 	If MS_IsSelection()
		MoveCaretToSelection(0), oMS.ELSel.OuterText := TransformHTML(Str), MS_Cancel()
	Else
		oDoc.selection.createRange().text := Str
}

PasteTab() {
	TempClipboard := ClipboardAll
	Clipboard := "" A_Tab ""
	oDoc.execCommand("Paste")
	Clipboard := TempClipboard 
}

PasteHTMLSelection(Str) {
 	If MS_IsSelection()
		oMS.ELSel.innerHTML := Str, MoveCaretToSelection(0)
	Else
		oDoc.selection.createRange().pasteHTML(Str)
}

MoveCaretToSelection(start) {
	R := oBody.createTextRange(), R.moveToElementText(oMS.ELSel), R.collapse(start), R.select()
}

GetSelected(ByRef Text, ByRef IsoMS = "") {
	Text := oMS.ELSel.OuterText
 	If (Text != "")
		IsoMS := 1
	Else
		Text := oDoc.selection.createRange().text, IsoMS := 0
	Return (Text != "")
}

CopyCommaParam(Text) {
 	If !(Text ~= "(x|y|w|h|" Chr(178) ")-*\d+")
		Return Text
	Text := RegExReplace(Text, "i)(x|y|w|h|#|\s|" Chr(178) "|" Chr(9642) ")+", " ")
	Text := TRim(Text, " "), Text := RegExReplace(Text, "(\s|,)+", ", ")
	Return Text
}

Add_DP(addN, Items*) {
 	For k, v in Items 
		If v != 
			Ret .= v _DP
	If Ret =
		Return
	Return (addN ? "`n" : "") SubStr(Ret, 1, -StrLen(_DP))
}

	;;  http://forum.script-coding.com/viewtopic.php?pid=53516#p53516

;; GetCommandLineProc(pid) {
	;; ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process WHERE ProcessId = " pid)._NewEnum.next(X)
	;; Return Trim(X.CommandLine)
;; }

	;;  http://forum.script-coding.com/viewtopic.php?pid=111775#p111775

GetCommandLineProc(PID, ByRef Cmd, ByRef Bit, ByRef IsAdmin) {
	Static PROCESS_QUERY_INFORMATION := 0x400, PROCESS_VM_READ := 0x10, STATUS_SUCCESS := 0

	hProc := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, Int, 0, UInt, PID, Ptr)
	if A_Is64bitOS
		DllCall("IsWow64Process", Ptr, hProc, UIntP, IsWow64), Bit := (IsWow64 ? "32" : "64") " bit" _DP
	if (!A_Is64bitOS || IsWow64)
		PtrSize := 4, PtrType := "UInt", pPtr := "UIntP", offsetCMD := 0x40
	else
		PtrSize := 8, PtrType := "Int64", pPtr := "Int64P", offsetCMD := 0x70
	hModule := DllCall("GetModuleHandle", "str", "Ntdll", Ptr)
	if (A_PtrSize < PtrSize) {            ;; скрипт 32, целевой процесс 64
		if !QueryInformationProcess := DllCall("GetProcAddress", Ptr, hModule, AStr, "NtWow64QueryInformationProcess64", Ptr)
			failed := "NtWow64QueryInformationProcess64"
		if !ReadProcessMemory := DllCall("GetProcAddress", Ptr, hModule, AStr, "NtWow64ReadVirtualMemory64", Ptr)
			failed := "NtWow64ReadVirtualMemory64"
		info := 0, szPBI := 48, offsetPEB := 8
	}
	else  {
		if !QueryInformationProcess := DllCall("GetProcAddress", Ptr, hModule, AStr, "NtQueryInformationProcess", Ptr)
			failed := "NtQueryInformationProcess"
		ReadProcessMemory := "ReadProcessMemory"
		if (A_PtrSize > PtrSize)            ;; скрипт 64, целевой процесс 32
			info := 26, szPBI := 8, offsetPEB := 0
		else                                ;; скрипт и целевой процесс одной битности
			info := 0, szPBI := PtrSize * 6, offsetPEB := PtrSize
	}
	if failed  {
		DllCall("CloseHandle", Ptr, hProc)
		Return
	}
	VarSetCapacity(PBI, 48, 0)
	if DllCall(QueryInformationProcess, Ptr, hProc, UInt, info, Ptr, &PBI, UInt, szPBI, UIntP, bytes) != STATUS_SUCCESS  {
		DllCall("CloseHandle", Ptr, hProc)
		Return
	}
	pPEB := NumGet(&PBI + offsetPEB, PtrType)
	DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pPEB + PtrSize * 4, pPtr, pRUPP, PtrType, PtrSize, UIntP, bytes)
	DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pRUPP + offsetCMD, UShortP, szCMD, PtrType, 2, UIntP, bytes)
	DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pRUPP + offsetCMD + PtrSize, pPtr, pCMD, PtrType, PtrSize, UIntP, bytes)
	VarSetCapacity(buff, szCMD, 0)
	DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pCMD, Ptr, &buff, PtrType, szCMD, UIntP, bytes)
	Cmd := StrGet(&buff, "UTF-16")

	DllCall("advapi32\OpenProcessToken", "ptr", hProc, "uint", 0x0008, "ptr*", hToken)
	DllCall("advapi32\GetTokenInformation", "ptr", hToken, "int", 20, "uint*", IsAdmin, "uint", 4, "uint*", size)
	DllCall("CloseHandle", "ptr", hToken)
	IsAdmin := (IsAdmin ? "Admin" _DP : "")

	DllCall("CloseHandle", Ptr, hProc)
}

SeDebugPrivilege() {
	Static PROCESS_QUERY_INFORMATION := 0x400, TOKEN_ADJUST_PRIVILEGES := 0x20, SE_PRIVILEGE_ENABLED := 0x2

	hProc := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION, Int, false, UInt, oOther.CurrentProcessId, Ptr)
	DllCall("Advapi32\OpenProcessToken", Ptr, hProc, UInt, TOKEN_ADJUST_PRIVILEGES, PtrP, token)
	DllCall("Advapi32\LookupPrivilegeValue", Ptr, 0, Str, "SeDebugPrivilege", Int64P, luid)
	VarSetCapacity(TOKEN_PRIVILEGES, 16, 0)
	NumPut(1, TOKEN_PRIVILEGES, "UInt")
	NumPut(luid, TOKEN_PRIVILEGES, 4, "Int64")
	NumPut(SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, 12, "UInt")
	DllCall("Advapi32\AdjustTokenPrivileges", Ptr, token, Int, false, Ptr, &TOKEN_PRIVILEGES, UInt, 0, Ptr, 0, Ptr, 0)
	res := A_LastError
	DllCall("CloseHandle", Ptr, token)
	DllCall("CloseHandle", Ptr, hProc)
	Return res  ;; в случае удачи 0
}

	;;  http://www.autohotkey.com/board/topic/69254-func-api-getwindowinfo-ahk-l/#entry438372

GetClientPos(hwnd, ByRef left, ByRef top, ByRef w, ByRef h) {
	Static _ := VarSetCapacity(pwi, 60, 0)
	DllCall("GetWindowInfo", "Ptr", hwnd, "Ptr", &pwi)
	left := NumGet(pwi, 20, "Int") - NumGet(pwi, 4, "Int")
	top := NumGet(pwi, 24, "Int") - NumGet(pwi, 8, "Int")
	w := NumGet(pwi, 28, "Int") - NumGet(pwi, 20, "Int")
	h := NumGet(pwi, 32, "Int") - NumGet(pwi, 24, "Int")
}

	;;  http://forum.script-coding.com/viewtopic.php?pid=81833#p81833

SelectFilePath(FilePath) { 
	FilePath := TRim(FilePath)
	FilePath := RegExReplace(FilePath, "(^""|""$)")
	FilePath := TRim(FilePath)
	
	If !FileExist(FilePath)
		Return 0
	SplitPath, FilePath,, Dir
	for window in ComObjCreate("Shell.Application").Windows  {
		ShellFolderView := window.Document
		Try If ((Folder := ShellFolderView.Folder).Self.Path != Dir)
			Continue
		Catch
			Continue
		for item in Folder.Items  {
			If (item.Path != FilePath)
				Continue
			ShellFolderView.SelectItem(item, 1|4|8|16)
			WinActivate, % "ahk_id" window.hwnd
			Return 1
		}
	}
	Run, %A_WinDir%\explorer.exe /select`, "%FilePath%", , UseErrorLevel
	Return 1
}

FileToClipboard(PathToCopy,Method="copy") {
	FileCount:=0
	PathLength:=0

	; Count files and total string length
	Loop,Parse,PathToCopy,`n,`r
	{
		FileCount++
		PathLength+=StrLen(A_LoopField)
	}

	pid:=DllCall("GetCurrentProcessId","uint")
	hwnd:=WinExist("ahk_pid " . pid)
	; 0x42 = GMEM_MOVEABLE(0x2) | GMEM_ZEROINIT(0x40)
	hPath := DllCall("GlobalAlloc","uint",0x42,"uint",20 + (PathLength + FileCount + 1) * 2,"UPtr")
	pPath := DllCall("GlobalLock","UPtr",hPath)
	NumPut(20,pPath+0),pPath += 16 ; DROPFILES.pFiles = offset of file list
	NumPut(1,pPath+0),pPath += 4 ; fWide = 0 -->ANSI,fWide = 1 -->Unicode
	Offset:=0
	Loop,Parse,PathToCopy,`n,`r ; Rows are delimited by linefeeds (`r`n).
		offset += StrPut(A_LoopField,pPath+offset,StrLen(A_LoopField)+1,"UTF-16") * 2

	DllCall("GlobalUnlock","UPtr",hPath)
	DllCall("OpenClipboard","UPtr",hwnd)
	DllCall("EmptyClipboard")
	DllCall("SetClipboardData","uint",0xF,"UPtr",hPath) ; 0xF = CF_HDROP

	; Write Preferred DropEffect structure to clipboard to switch between copy/cut operations
	; 0x42 = GMEM_MOVEABLE(0x2) | GMEM_ZEROINIT(0x40)
	mem := DllCall("GlobalAlloc","uint",0x42,"uint",4,"UPtr")
	str := DllCall("GlobalLock","UPtr",mem)

	if (Method="copy")
		DllCall("RtlFillMemory","UPtr",str,"uint",1,"UChar",0x05)
	else if (Method="cut")
		DllCall("RtlFillMemory","UPtr",str,"uint",1,"UChar",0x02)
	else
	{
		DllCall("CloseClipboard")
		return
	}

	DllCall("GlobalUnlock","UPtr",mem)

	cfFormat := DllCall("RegisterClipboardFormat","Str","Preferred DropEffect")
	DllCall("SetClipboardData","uint",cfFormat,"UPtr",mem)
	DllCall("CloseClipboard") 
}

ExecCommandAutoHotkey(Command, PID) {
    Static WM_COMMAND := 0x111
     , Commands := {"Reload Script": 65400
           , "Edit Script": 65401
           , "Suspend Hotkeys": 65404
           , "Pause Script": 65403
           , "Exit Script": 65405
           , "Recent Lines": 65406
           , "Variables": 65407
           , "Hotkeys": 65408
           , "Key history": 65409
           , "AHK User Manual": 65411}
	PostMessage WM_COMMAND, % Commands[Command],,, % "ahk_class AutoHotkey ahk_pid" . PID   
} 

GetCLSIDExplorer(hwnd) {
	for window in ComObjCreate("Shell.Application").Windows
		If (window.hwnd = hwnd)
			Return (CLSID := window.Document.Folder.Self.Path) ~= "^::\{" ? "`n<span class='param'>CLSID: </span><span name='MS:'>" CLSID "</span>": ""
}

ChangeLocal(hWnd) {
	Static WM_INPUTLANGCHANGEREQUEST := 0x0050, INPUTLANGCHANGE_FORWARD := 0x0002
	SendMessage, WM_INPUTLANGCHANGEREQUEST, INPUTLANGCHANGE_FORWARD, , , % "ahk_id" hWnd
}

GetLangName(hWnd) {
	Static LOCALE_SENGLANGUAGE := 0x1001
	Locale := DllCall("GetKeyboardLayout", Ptr, DllCall("GetWindowThreadProcessId", Ptr, hWnd, UInt, 0, Ptr), Ptr) & 0xFFFF
	Size := DllCall("GetLocaleInfo", UInt, Locale, UInt, LOCALE_SENGLANGUAGE, UInt, 0, UInt, 0) * 2
	VarSetCapacity(lpLCData, Size, 0)
	DllCall("GetLocaleInfo", UInt, Locale, UInt, LOCALE_SENGLANGUAGE, Str, lpLCData, UInt, Size)
	Return lpLCData
}

ConfirmAction(Action) {
	If !WinActive("ahk_id" hGui) || GetKeyState("Shift")
		Return
	If (!isPaused && bool := 1)
		Gosub, PausedScript
	isConfirm := 1
	bool2 := MsgConfirm(Action, "AhkSpy", hGui)
	isConfirm := 0
	If bool
		Gosub, PausedScript
	If !bool2
		Exit
	Return 1
}

MsgConfirm(Info, Title, hWnd) {
	Static hMsgBox, Text, Yes, No, WinW, WinH
	If !hMsgBox {
		Gui, MsgBox:+HWNDhMsgBox -DPIScale -SysMenu +Owner%hWnd% +AlwaysOnTop
		Gui, MsgBox:Font, % "s" FontDPI " c" ColorFont
		Gui, MsgBox:Color, %ColorBgOriginal%
		Gui, MsgBox:Add, Text, w200 vText r1 Center 
		Gui, MsgBox:Add, Button, w88 vYes xp+4 y+20 gMsgBoxLabel, Yes
		Gui, MsgBox:Add, Button, w88 vNo x+20 gMsgBoxLabel, No 
		WinSet, TransParent, 0, ahk_id %hMsgBox% 
		Gui, MsgBox:Show, NA AutoSize x-32000 y-32000
		WinGetPos, , , WinW, WinH, ahk_id %hMsgBox%
	}
	Gui, MsgBox:+Owner%hWnd% +AlwaysOnTop
	Gui, %hWnd%:+Disabled
	GuiControl, MsgBox:Text, Text, % Info
	CoordMode, Mouse
	MouseGetPos, X, Y
	x := X - (WinW / 2)
	y := Y - WinH - 10
	Gui, MsgBox: Show, NA x%x% y%y%, % Title
	Sleep 1
	WinSet, TransParent, 255, ahk_id %hMsgBox%
	Gui, MsgBox: Show, , % Title
	Gui MsgBox:+AlwaysOnTop
	GuiControl, MsgBox:+Default, No
	GuiControl, MsgBox:Focus, No
	While (RetValue = "")
		Sleep 30
	Gui, %hWnd%:-Disabled
	WinSet, TransParent, 0, ahk_id %hMsgBox% 
	Gui, MsgBox: Show, x-32000 y-32000
	Return RetValue

	MsgBoxLabel:
		RetValue := {Yes:1,No:0}[A_GuiControl]
		Return
}

UnderControl(h) { 
	MouseGetPos, , , Control, , 2
	Return (Control = h)
}

MouseStep(x, y) {
	MouseMove, x, y, 0, R
	If (WinActive("ahk_id" hGui) && !ActiveNoPause) || OnlyShiftTab
	{
		(ThisMode = "Control" ? (Spot_Control() (StateAllwaysSpot ? Spot_Win() : 0) Write_Control()) : (Spot_Win() (StateAllwaysSpot ? Spot_Control() : 0) Write_Win()))
		If DllCall("IsWindowVisible", "Ptr", oOther.hZoom)
			ZoomMsg(3)
	}
	Shift_Tab_Down := 1
}

IsIEFocus() {
	If !WinActive("ahk_id" hGui)
		Return 0
	ControlGetFocus, Focus
	Return InStr(Focus, "Internet")
}

NextLink(s = "") {
	curpos := oDivNew.scrollTop, oDivNew.scrollLeft := 0
	If (!curpos && s = "-")
		Return
	While (pos := oDoc.getElementsByTagName("a").item(A_Index-1).getBoundingClientRect().top) != ""
		(s 1) * pos - 12 > 0 && (!res || abs(res) > abs(pos)) ? res := pos : ""       ;; http://forum.script-coding.com/viewtopic.php?pid=82360#p82360
	If (res = "" && s = "")
		Return
	st := !res ? -curpos : res, co := abs(st) > 150 ? 20 : 10
	Loop % co
		oDivNew.scrollTop := curpos + (st*(A_Index/co))  
	oDivNew.scrollTop := curpos + res - 6
}  

AnchorColor() {
	If !oOther.anchor[ThisMode]
		Return 
	el := GetAnchor()
	el.parentElement.parentElement.firstChild.style.backgroundColor := "#" ColorSelAnchor
	Return el
}

GetAnchor() {
	If !oOther.anchor[ThisMode "_text"]
		Return
	Return oJScript.QS(oDivNew, "#" oOther.anchor[ThisMode "_text"]) ; .parentElement.parentElement.firstChild
}

AnchorScroll(EL = "") { 
	If !oOther.anchor[ThisMode]
		Return
	If !EL
		el := GetAnchor()
	_AnchorFitScroll(EL)  
	oDivNew.scrollTop := oDivNew.scrollTop + EL.getBoundingClientRect().top - 6
}  
 
_AnchorFitScroll(EL, off = 0) { 
	If !AnchorFullScroll
		Return 
	ta := EL.getBoundingClientRect().top   
	ELLast := oJScript.QS(oDivNew, "#id_T0") 
	tl := ELLast.getBoundingClientRect().top   
	clH := oDivNew.clientHeight   
	res := clH - (tl - ta)  
	If res < 0
		res := 0 
	; ToolTip % clH "`n" tl "`n" ba  "`n"  "`n" res, , , 2
	ELLast.style.height := res "px"
	Return 1
}
 
AnchorFitScroll() {
	_AnchorFitScroll(GetAnchor()) 
}

TaskbarProgress(state, hwnd, pct = "") {
	static tbl
	if !tbl {
		try tbl := ComObjCreate("{56FDF344-FD6D-11d0-958A-006097C9A090}", "{ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf}")
		catch
			tbl := "error"
	}
	if tbl = error
		Return
	DllCall(NumGet(NumGet(tbl+0)+10*A_PtrSize), "ptr", tbl, "ptr", hwnd, "uint", state)
	if pct !=
		DllCall(NumGet(NumGet(tbl+0)+9*A_PtrSize), "ptr", tbl, "ptr", hwnd, "int64", pct, "int64", 100)
}

/*
HighLight(elem, time = "", RemoveFormat = 1) {
	If (elem.OuterText = "")
		Return
	Try SetTimer, UnHighLight, % "-" time
	R := oBody.createTextRange()
	(RemoveFormat ? R.execCommand("RemoveFormat") : 0)
	R.collapse(1)
	R.select()
	R.moveToElementText(elem)
	
	; https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/hh801229(v=vs.85)#forecolor
	R.execCommand("ForeColor", 0, ColorBgOriginal) ; неработает 
	R.execCommand("BackColor", 0, ColorSelMouseHover)
	Return

	UnHighLight:
		oBody.createTextRange().execCommand("RemoveFormat")
		Return
}
*/

HighLight(elements, time = 500) {
	Static arr, ot
	R := oBody.createTextRange(), R.collapse(1), R.select()
	
	If elements
		(arr && SetTimer(ot, "Off") %A_ThisFunc%(0))
		, bc := "#" ColorSelMouseHover, tc := "#" ColorSelMouseHoverText 
	Else 
		elements := arr, delete := 1
		
	for k, el in elements
	{
		el.style.backgroundColor := bc
		el.style.color := tc
		Loop % el.all.length
			el.all[A_Index - 1].style.color := tc
	}
	If delete 
		Return 0, arr := 0 
	arr := elements 
	Return 1, SetTimer(ot := Func(A_ThisFunc).Bind(0), "-" time)
}

Hotkey_ClipCursor() { 
	Static lpRect, _ := VarSetCapacity(lpRect, 16, 0)  
	DllCall("GetClipCursor", "Ptr", &lpRect) 
	
	If NumGet(lpRect, 0, "uint") > 0xffff || NumGet(lpRect, 0, "uint") = 0
	{ 
		; WinGetPos, WinX, WinY, WinWidth, WinHeight, % "ahk_id" hActiveX 
		CoordMode, Mouse, Screen
		MouseGetPos, X, Y
		NumPut(X, lpRect, 0, "uint")
		NumPut(Y, lpRect, 4, "uint")
		NumPut(X, lpRect, 8, "uint")
		NumPut(Y, lpRect, 12, "uint") 
		DllCall("ClipCursor", "Ptr", &lpRect + 0)   
		ToolTip2("Cancel press down and up lbutton, and press lbutton 2 seconds, else Ctrl+Alt+Delete", -1, 0, -100, 2)
	}
	Else  
	{
		KeyWait LButton
		KeyWait LButton, D
		KeyWait LButton, T2
		If ErrorLevel
			DllCall("ClipCursor", "Ptr", 0), ToolTip2("", -1, , , 2)
	}
}
	; ___________________________ Command as function _________________________________________________
 
WinGetPosToArray(h) {
	WinGetPos, WinX, WinY, WinW, WinH, % "ahk_id " h
	return [WinX, WinY, WinW, WinH] 
}

IniRead(Key, Error := " ") {
	IniRead, Value, %A_AppData%\AhkSpy\Settings.ini, AhkSpy, %Key%, %Error%
	If (Value = "" && Error != " ")
		Value := Error
	Return Value
}

IniWrite(Value, Key) {
	IniWrite, %Value%, %A_AppData%\AhkSpy\Settings.ini, AhkSpy, %Key%
	Return Value
}

MsgBox(msg) {
	MsgBox %msg%
}

WinClose(title) {
	WinClose % title
}

Sleep(time) {
	Sleep time
}

SendInput(key) {
	SendInput % key
}

SetTimer(funcorlabel, time = -500) {
	SetTimer, % funcorlabel, % time
}

GuiControl(SubCommand, ControlID = "", Value = "") { 
	GuiControl, %SubCommand%, %ControlID%, %Value%
}

MouseMoveScreen(x, y) {
	CoordMode, Mouse, Screen
	SetMouseDelay, 0, 0
	SendEvent {Click %x%, %y%, 0}  
}

ToolTip(text, time = 500) {
	CoordMode, Mouse
	CoordMode, ToolTip
	MouseGetPos, X, Y
	ToolTip, %text%, X-10, Y-45
	If (time > 0)
		SetTimer, HideToolTip, -%time%
	Return 1

	HideToolTip:
		ToolTip
		Return
}

ToolTip2(text, time = 500, x = 0, y = 0, ex = 1, CoordMode = "Mouse") {
	If CoordMode = Mouse
	{
		CoordMode, Mouse
		CoordMode, ToolTip
		MouseGetPos, mX, mY
		X+=mX, Y+=mY
	}
	Else 
		CoordMode, ToolTip, %CoordMode%  ;	Screen, Window, Client  (if omitted, it defaults to Screen)
	ToolTip, %text%, x, y, ex
	If (time > 0)
		SetTimer, HideToolTip2, -%time%
	Return 1

	HideToolTip2:
		ToolTip
		Return
}
	; ___________________________ Update _________________________________________________

UpdateAhkSpy(in = 1) {
	Static att, Ver, req
		, url1 := "https://raw.githubusercontent.com/serzh82saratov/AhkSpy/master/Readme.txt"
		, url2 := "https://raw.githubusercontent.com/serzh82saratov/AhkSpy/master/AhkSpy.ahk"

	If !req
		req := ComObjCreate("WinHttp.WinHttpRequest.5.1"), req.Option(6) := 0
	req.open("GET", url%in%, 1), req.send(), att := 0
	SetTimer, Upd_Verifi, -3000
	Return

	Upd_Verifi:
		If (Status := req.Status) = 200
		{
			Text := req.responseText
			If (req.Option(1) = url1)
				Return (Ver := RegExReplace(Text, "i).*?version\s*(.*?)\R.*", "$1")) > AhkSpyVersion ? UpdateAhkSpy(2) : 0
			If (!InStr(Text, "AhkSpyVersion"))
				Return
			HideAllMarkers()
			If InStr(FileExist(A_ScriptFullPath), "R")
			{
				MsgBox, % 16+262144+8192, AhkSpy, Exist new version %Ver%!`n`nBut the file has an attribute "READONLY".`nUpdate imposible.
				Return
			}
			MsgBox, % 4+32+262144+8192, AhkSpy, Exist new version!`nUpdate v%AhkSpyVersion% to v%Ver%?
			IfMsgBox, No
				Return
			File := FileOpen(A_ScriptFullPath, "w", "UTF-8")
			File.Length := 0, File.Write(Text), File.Close()
			Reload
		}
		Error := (++att = 20 || Status != "")
		SetTimer, % Error ? "UpdateAhkSpy" : "Upd_Verifi", % Error ? -60000 : -3000
		Return
}

UpdRegister() {
	Static req, att := 0
	req := ComObjCreate("WinHttp.WinHttpRequest.5.1")
	req.open("post", UpdRegisterLink, 1), req.send()
	SetTimer, UpdRegister_Verifi, -2000
	Return

	UpdRegister_Verifi:
		++att
		If (req.Status = 200)
			IniWrite(1, "UpdRegister2")
		Else If (att <= 3)
			SetTimer, UpdRegister_Verifi, -2000
		Return
}

CheckAhkNewVersion() {
	Static req, att := 0
	req := ComObjCreate("WinHttp.WinHttpRequest.5.1")
	req.Option(6) := 0
	req.open("GET", "https://www.autohotkey.com/download/", 1)
	req.send()
	SetTimer, lCheckAhkNewVersion, -3000
	Return

	lCheckAhkNewVersion:
		++att
		If (req.Status = 200)
		{ 
			; RegExMatch(req.responseText, "O)<!--update-->v(.*?) - ", m), ver := m[1]
			ver := RegExReplace(req.responseText, "s).*?<!--update-->v(.*?) - .*", "$1")
			If StrReplace(ver, ".") <= StrReplace(A_AhkVersion, ".")
				Return
			MsgBox, % 4+32+262144+8192, AhkSpy, AutoHotkey new version!`nFor update v%A_AhkVersion% to v%Ver%, need to go autohotkey.com?
			IfMsgBox, No
				Return
			Run https://www.autohotkey.com/download/
			Return
		}
		If (att <= 3)
			SetTimer, lCheckAhkNewVersion, -2000
		Return 
}


	; ___________________________ WindowStyles _________________________________________________

ViewStylesWin(update = 0) {  ;;
	
	If update
	{
		WinGet, WinStyle, Style, % "ahk_id" oOther.WinID
		WinGet, WinExStyle, ExStyle, % "ahk_id" oOther.WinID
		
		If (WinStyle WinExStyle = "")
			Return ToolTip("Window not exist", 500)
		oDoc.getElementById("w_Style").innerText := WinStyle
		oDoc.getElementById("w_ExStyle").innerText := WinExStyle
		w_ShowStyles := 0
	}  
	oDoc.getElementById("get_styles_w").innerText := !(w_ShowStyles := !w_ShowStyles) ? " show styles " : " hide styles "
	IniWrite(w_ShowStyles, "w_ShowStyles")
			
	If w_ShowStyles || update
		Styles := "<a></a>" GetStyles(oOther.WinClass
			, oDoc.getElementById("w_Style").innerText
			, oDoc.getElementById("w_ExStyle").innerText
			, oOther.WinID)

	oDoc.getElementById("WinStyles").innerHTML := Styles
	HTML_Win := oDivNew.innerHTML
}

ViewStylesControl(update = 0) {  ;;
	
	If update
	{
		ControlGet, CtrlStyle, Style,,, % "ahk_id" oOther.ControlID
		ControlGet, CtrlExStyle, ExStyle,,, % "ahk_id" oOther.ControlID
		
		If (CtrlStyle CtrlExStyle = "")
			Return ToolTip("Window not exist", 500)
		oDoc.getElementById("c_Style").innerText := CtrlStyle
		oDoc.getElementById("c_ExStyle").innerText := CtrlExStyle
		c_ShowStyles := 0
	} 
	oDoc.getElementById("get_styles_c").innerText := !(c_ShowStyles := !c_ShowStyles) ? " show styles " : " hide styles "
	IniWrite(c_ShowStyles, "c_ShowStyles")  

	If c_ShowStyles
		Styles := "<a></a>" GetStyles(oOther.CtrlClass
			, oDoc.getElementById("c_Style").innerText
			, oDoc.getElementById("c_ExStyle").innerText
			, oOther.ControlID)
	oDoc.getElementById("ControlStyles").innerHTML := Styles
	HTML_Control := oDivNew.innerHTML
} 

GetStyles(Class, Style, ExStyle, hWnd, IsChild = 0, IsChildInfoExist = 0) {
	;;	http://msdn.microsoft.com/en-us/library/windows/desktop/ms632600(v=vs.85).aspx			Styles
	;;	http://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx			ExStyles
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25880#p25880							Forum Constants
	;;	https://github.com/AHK-just-me/AHK_Gui_Constants/tree/master/Sources			GitHub Constants
	
	;;	http://www.frolov-lib.ru/books/bsp/v11/ch3_2.htm   русский фак по стилям
	;;	https://github.com/strobejb/winspy/blob/master/src/DisplayStyleInfo.c			Логика WinSpy++
	;;	http://forum.script-coding.com/viewtopic.php?pid=130846#p130846
	
	Static Styles, ExStyles, ClassStyles, DlgStyles, ToolTipStyles, GCL_STYLE := -26
	
	If !hWnd
		Return
	If !Styles
		   ;;  В массивах стили без условий
		Styles := {"WS_BORDER":"0x00800000", "WS_SYSMENU":"0x00080000"
		, "WS_CLIPCHILDREN":"0x02000000", "WS_CLIPSIBLINGS":"0x04000000", "WS_DISABLED":"0x08000000"
		, "WS_HSCROLL":"0x00100000", "WS_MAXIMIZE":"0x01000000"
		, "WS_VISIBLE":"0x10000000", "WS_VSCROLL":"0x00200000"}

		, ExStyles := {"WS_EX_ACCEPTFILES":"0x00000010", "WS_EX_APPWINDOW":"0x00040000", "WS_EX_CLIENTEDGE":"0x00000200"
		, "WS_EX_CONTROLPARENT":"0x00010000", "WS_EX_DLGMODALFRAME":"0x00000001", "WS_EX_LAYOUTRTL":"0x00400000"
		, "WS_EX_LEFTSCROLLBAR":"0x00004000", "WS_EX_WINDOWEDGE":"0x00000100"
		, "WS_EX_MDICHILD":"0x00000040", "WS_EX_NOACTIVATE":"0x08000000", "WS_EX_NOINHERITLAYOUT":"0x00100000"
		, "WS_EX_NOPARENTNOTIFY":"0x00000004", "WS_EX_NOREDIRECTIONBITMAP":"0x00200000", "WS_EX_RIGHT":"0x00001000"
		, "WS_EX_RTLREADING":"0x00002000", "WS_EX_STATICEDGE":"0x00020000"
		, "WS_EX_TOOLWINDOW":"0x00000080", "WS_EX_TOPMOST":"0x00000008", "WS_EX_TRANSPARENT":"0x00000020"}

		, ClassStyles := {"CS_BYTEALIGNCLIENT":"0x00001000", "CS_BYTEALIGNWINDOW":"0x00002000", "CS_CLASSDC":"0x00000040", "CS_IME":"0x00010000"
		, "CS_DBLCLKS":"0x00000008", "CS_DROPSHADOW":"0x00020000", "CS_GLOBALCLASS":"0x00004000", "CS_HREDRAW":"0x00000002"
		, "CS_NOCLOSE":"0x00000200", "CS_OWNDC":"0x00000020", "CS_PARENTDC":"0x00000080", "CS_SAVEBITS":"0x00000800", "CS_VREDRAW":"0x00000001"}
	
	orStyle := Style
	Style := sStyle := Style & 0xffff0000

	IF (Style & 0x00C00000) = 0x00C00000  && (WS_CAPTION := 1, WS_BORDER := 1, Style -= 0x00C00000)  ;;	WS_CAPTION && WS_BORDER 
		Ret .= QStyle("WS_CAPTION", "0x00C00000") QStyle("WS_BORDER", "0x00800000") 
		
	IF !WS_CAPTION && (Style & 0x00400000) && (WS_DLGFRAME := 1, Style -= 0x00400000)  ;;	WS_DLGFRAME 
		Ret .= QStyle("WS_DLGFRAME", "0x00400000", "!(WS_CAPTION)")
		
	For K, V In Styles
		If (Style & V) = V && (%K% := 1, Style -= V) 
			Ret .= QStyle(K, V)
 
	IF (Style & 0x00040000) && (WS_SIZEBOX := 1, WS_THICKFRAME := 1, Style -= 0x00040000)  ;;	WS_SIZEBOX := WS_THICKFRAME 
		Ret .= QStyle("WS_SIZEBOX := WS_THICKFRAME", "0x00040000")

	IF (Style & 0x40000000) && (WS_CHILD := 1, Style -= 0x40000000)  ;;	WS_CHILD := WS_CHILDWINDOW := 0x40000000
		Ret .= QStyle("WS_CHILD := WS_CHILDWINDOW", "0x40000000") 
		
	IF (Style & 0x00010000) && (WS_TABSTOP := 1, Style -= 0x00010000)  ;;	WS_TABSTOP
		Ret .= QStyle("WS_TABSTOP", "0x00010000")    ;;  , "(WS_CHILD)"
		
	IF (Style & 0x00020000) && WS_CHILD && (WS_GROUP := 1, Style -= 0x00020000)  ;;	WS_GROUP
		Ret .= QStyle("WS_GROUP", "0x00020000", "(WS_CHILD)")  

	IF (Style & 0x20000000) && (WS_MINIMIZE := 1, Style -= 0x20000000)  ;;	WS_MINIMIZE := WS_ICONIC
		Ret .= QStyle("WS_MINIMIZE := WS_ICONIC", "0x20000000")   

	IF (Style & 0x80000000) && !WS_CHILD && (WS_POPUP := 1, Style -= 0x80000000)  ;;	WS_POPUP
		Ret .= QStyle("WS_POPUP", "0x80000000", "!(WS_CHILD)")  

	IF (WS_POPUP && WS_BORDER && WS_SYSMENU) && (WS_POPUPWINDOW := 1)  ;;	WS_POPUPWINDOW
		Ret .= QStyle("WS_POPUPWINDOW", "0x80880000", "(WS_POPUP | WS_BORDER | WS_SYSMENU)")

	IF !WS_POPUP && !WS_CHILD && WS_BORDER && WS_CAPTION && (WS_OVERLAPPED := 1)  ;;	WS_OVERLAPPED := WS_TILED
		Ret .= QStyle("WS_OVERLAPPED := WS_TILED", "0x00000000", "(WS_BORDER | WS_CAPTION) & !(WS_POPUP | WS_CHILD)")

	IF WS_SYSMENU && (sStyle & 0x00020000) && (WS_MINIMIZEBOX := 1, (Style & 0x00020000) && (Style -= 0x00020000))  ;;	WS_MINIMIZEBOX
		Ret .= QStyle("WS_MINIMIZEBOX", "0x00020000", "(WS_SYSMENU)") 

	IF WS_SYSMENU && (sStyle & 0x00010000) && (WS_MAXIMIZEBOX := 1)  ;;	WS_MAXIMIZEBOX
		Ret .= QStyle("WS_MAXIMIZEBOX", "0x00010000", "(WS_SYSMENU)")

	If (WS_OVERLAPPED && WS_SIZEBOX && WS_SYSMENU && WS_MINIMIZEBOX && WS_MAXIMIZEBOX)  ;;	WS_OVERLAPPEDWINDOW := WS_TILEDWINDOW
		Ret .= QStyle("WS_OVERLAPPEDWINDOW := WS_TILEDWINDOW", "0x00CF0000", "(WS_OVERLAPPED | WS_SIZEBOX | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)") 

	If IsFunc("GetStyle_" Class)
		ChildStyles := GetStyle_%Class%(orStyle, hWnd, ChildExStyles)
				
	sExStyle := ExStyle
	For K, V In ExStyles
		If (ExStyle & V) && (%K% := 1, ExStyle -= V)
			RetEx .= QStyle(K, V)  

	IF !CS_OWNDC && !CS_CLASSDC && (ExStyle & 0x02000000) && (1, ExStyle -= 0x02000000)  ;;	WS_EX_COMPOSITED
		RetEx .= QStyle("WS_EX_COMPOSITED", "0x02000000", "!(CS_OWNDC | CS_CLASSDC)")  

	IF !WS_MAXIMIZEBOX && !WS_MINIMIZEBOX && (ExStyle & 0x00000400) && (1, ExStyle -= 0x00000400)  ;;	WS_EX_CONTEXTHELP
		RetEx .= QStyle("WS_EX_CONTEXTHELP", "0x00000400", "!(WS_MAXIMIZEBOX | WS_MINIMIZEBOX)")   
		
	IF !CS_OWNDC && !CS_CLASSDC && (ExStyle & 0x00080000) && (1, ExStyle -= 0x00080000)  ;;	WS_EX_LAYERED
		RetEx .= QStyle("WS_EX_LAYERED", "0x00080000", "!(CS_OWNDC | CS_CLASSDC)")   

	IF !WS_EX_RIGHT  ;;	WS_EX_LEFT
		RetEx .= QStyle("WS_EX_LEFT", "0x00000000", "!(WS_EX_RIGHT)")    

	IF !WS_EX_LEFTSCROLLBAR  ;;	WS_EX_RIGHTSCROLLBAR
		RetEx .= QStyle("WS_EX_RIGHTSCROLLBAR", "0x00000000", "!(WS_EX_LEFTSCROLLBAR)")     

	IF !WS_EX_RTLREADING  ;;	WS_EX_LTRREADING
		RetEx .= QStyle("WS_EX_LTRREADING", "0x00000000", "!(WS_EX_RTLREADING)")      

	IF WS_EX_WINDOWEDGE && WS_EX_CLIENTEDGE  ;;	WS_EX_OVERLAPPEDWINDOW
		RetEx .= QStyle("WS_EX_OVERLAPPEDWINDOW", "0x00000300", "(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE)")       

	IF WS_EX_WINDOWEDGE && WS_EX_TOOLWINDOW && WS_EX_TOPMOST  ;;	WS_EX_PALETTEWINDOW 
		RetEx .= QStyle("WS_EX_PALETTEWINDOW", "0x00000188", "(WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST)")
 
	IF Style
		Ret .= QStyleRest(8, Style) 
	If Ret !=
		Res .= _T1 " id='__Styles_Win'>" QStyleTitle("Styles", "", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2  
	Res .= ChildStyles
	IF ExStyle
		RetEx .= QStyleRest(8, ExStyle)  
	If RetEx !=
		Res .= _T1 " id='__ExStyles_Win'>" QStyleTitle("ExStyles", "", 8, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2 
	Res .= ChildExStyles 
		
	;;  https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setclasslongw
	StyleBits := DllCall("GetClassLong", "Ptr", hWnd, "int", GCL_STYLE)	
	For K, V In ClassStyles
		If (StyleBits & V) && (%K% := 1)
				RetClass .= QStyle(K, V) 
	
	If RetClass !=
		Res .= _T1 " id='__ClassStyles_Win'>" QStyleTitle("Class Styles", "", 8, StyleBits) "</span>" _T2 _PRE1 RetClass _PRE2

	Return Res
}

QStyleTitle(Title, Name, F, V) {
	If Name !=
		Return " ( " Title " - <span name='MS:' style='color: #" ColorParam ";'>" Name "</span>: <span name='MS:' style='color: #" ColorFont ";'>" Format("0x{:0" F "X}", V) "</span> ) " 
	Return " ( " Title ": <span name='MS:' style='color: #" ColorFont ";'>" Format("0x{:0" F "X}", V) "</span> ) "  
}
QStyleRest(F, V) {
	Return "<span style='color: #" ColorDelimiter ";' name='MS:'>" Format("0x{1:0" F "X}", V) "</span>`n"
}
QStyle(k, v, q = "") {
	Return "<span name='MS:Q'>" k " := <span class='param' name='MS:'>" v "</span></span>" . (q != "" ? _StIf q "</span>`n" : "`n")
}
	; ___________________________ ControlStyles _________________________________________________

/*
	Added:
	Button, Edit, Static, SysListView32, SysTabControl32, SysDateTimePick32, SysMonthCal32, ComboBox, ListBox
	, msctls_trackbar32, msctls_statusbar32, msctls_progress32, msctls_updown32, SysLink, SysHeader32
	, ToolbarWindow32, SysTreeView32, ReBarWindow32, SysAnimate32, SysPager, #32770, tooltips_class32
*/  
	
GetStyle_#32770(Style, hWnd)  {
	;;	https://docs.microsoft.com/en-us/windows/desktop/dlgbox/dialog-box-styles
	Static oStyles
	If !oStyles
		oStyles := {"DS_3DLOOK":"0x00000004","DS_ABSALIGN":"0x00000001","DS_CENTER":"0x00000800","DS_CENTERMOUSE":"0x00001000","DS_CONTEXTHELP":"0x00002000"
		,"DS_CONTROL":"0x00000400","DS_FIXEDSYS":"0x00000008","DS_LOCALEDIT":"0x00000020","DS_MODALFRAME":"0x00000080","DS_NOFAILCREATE":"0x00000010"
		,"DS_NOIDLEMSG":"0x00000100","DS_SETFONT":"0x00000040","DS_SETFOREGROUND":"0x00000200","DS_SHELLFONT":"0x00000048","DS_SYSMODAL":"0x00000002"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (1, Style -= V)
			Ret .= QStyle(K, V)   
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "#32770", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}


GetStyle_tooltips_class32(Style, hWnd)  {
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/tooltip-styles
	Static oStyles
	If !oStyles
		oStyles := {"TTS_ALWAYSTIP":"0x00000001","TTS_BALLOON":"0x00000040","TTS_CLOSE":"0x00000080","TTS_NOANIMATE":"0x00000010","TTS_NOFADE":"0x00000020"
		,"TTS_NOPREFIX":"0x00000002","TTS_USEVISUALSTYLE":"0x00000100"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (1, Style -= V)
			Ret .= QStyle(K, V)   
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "tooltips_class32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}



GetStyle_Static(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25869#p25869
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/static-control-styles
	Static oStyles, oEx
	If !oStyles
		oStyles := {"SS_ELLIPSISMASK":"0xC000"
		,"SS_REALSIZECONTROL":"0x0040","SS_NOPREFIX":"0x0080","SS_NOTIFY":"0x0100","SS_CENTERIMAGE":"0x0200","SS_RIGHTJUST":"0x0400"
		,"SS_REALSIZEIMAGE":"0x0800","SS_SUNKEN":"0x1000","SS_EDITCONTROL":"0x2000","SS_ENDELLIPSIS":"0x4000","SS_PATHELLIPSIS":"0x8000"
		,"SS_WORDELLIPSIS":"0xC000"}

		, oEx := {"SS_CENTER":"0x0001","SS_RIGHT":"0x0002","SS_ICON":"0x0003","SS_BLACKRECT":"0x0004"
		,"SS_GRAYRECT":"0x0005","SS_WHITERECT":"0x0006","SS_BLACKFRAME":"0x0007","SS_GRAYFRAME":"0x0008","SS_WHITEFRAME":"0x0009"
		,"SS_USERITEM":"0x000A","SS_SIMPLE":"0x000B","SS_LEFTNOWORDWRAP":"0x000C","SS_OWNERDRAW":"0x000D","SS_BITMAP":"0x000E"
		,"SS_ENHMETAFILE":"0x000F","SS_ETCHEDHORZ":"0x0010","SS_ETCHEDVERT":"0x0011","SS_ETCHEDFRAME":"0x0012","SS_TYPEMASK":"0x001F"}

	Style := sStyle := Style & 0xffff
	For K, V In oEx
		If ((Style & 0x1F) = V) && (%K% := 1, Style -= V)
		{ 
			Ret .= QStyle(K, V)
			Break
		}
	For K, V In oStyles
		If Style && ((Style & V) = V) && (%K% := 1, Style -= V) 
			Ret .= QStyle(K, V)
	IF !SS_CENTER && !SS_RIGHT  ;;	SS_LEFT
		Ret .= QStyle("SS_LEFT", "0x0000", "!(SS_CENTER | SS_RIGHT)")
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "Static", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_Button(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25841#p25841
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/button-styles
	Static oStyles, oEx
	If !oStyles
		oStyles := {"BS_ICON":"0x0040","BS_BITMAP":"0x0080","BS_LEFT":"0x0100","BS_RIGHT":"0x0200","BS_CENTER":"0x0300"
		,"BS_TOP":"0x0400","BS_BOTTOM":"0x0800","BS_VCENTER":"0x0C00","BS_PUSHLIKE":"0x1000","BS_MULTILINE":"0x2000"
		,"BS_NOTIFY":"0x4000","BS_FLAT":"0x8000"}

		, oEx := {"BS_DEFPUSHBUTTON":"0x0001","BS_CHECKBOX":"0x0002","BS_AUTOCHECKBOX":"0x0003"
		,"BS_RADIOBUTTON":"0x0004","BS_3STATE":"0x0005","BS_AUTO3STATE":"0x0006","BS_GROUPBOX":"0x0007","BS_USERBUTTON":"0x0008"
		,"BS_AUTORADIOBUTTON":"0x0009","BS_PUSHBOX":"0x000A","BS_OWNERDRAW":"0x000B","BS_COMMANDLINK":"0x000E"
		,"BS_DEFCOMMANDLINK":"0x000F","BS_SPLITBUTTON":"0x000C","BS_DEFSPLITBUTTON":"0x000D","BS_PUSHBUTTON":"0x0000","BS_TEXT":"0x0000"}
		  ;; "BS_TYPEMASK":"0x000F"

	Style := sStyle := Style & 0xffff
	For K, V In oEx
		If ((Style & 0xF) = V) && (%K% := 1, Style -= V)
		{
			Ret .= QStyle(K, V)
			Break
		}
	If ((Style & 0x0020) = 0x0020)  ;;	BS_LEFTTEXT  ;;	BS_RIGHTBUTTON
		Ret .= QStyle("BS_LEFTTEXT := BS_RIGHTBUTTON", "0x0020")

	For K, V In oStyles
		If ((Style & V) = V) && (%K% := 1, Style -= V)
			Ret .= QStyle(K, V)

	IF !BS_ICON && !BS_BITMAP && !BS_AUTOCHECKBOX && !BS_AUTORADIOBUTTON && !BS_CHECKBOX && !BS_RADIOBUTTON  ;;	BS_TEXT
		Ret .= QStyle("BS_TEXT", "0x0000", "!(BS_ICON | BS_BITMAP | BS_AUTOCHECKBOX | BS_AUTORADIOBUTTON | BS_CHECKBOX | BS_RADIOBUTTON)")

	IF !BS_DEFPUSHBUTTON && !BS_CHECKBOX && !BS_AUTOCHECKBOX && !BS_RADIOBUTTON && !BS_GROUPBOX && !BS_AUTORADIOBUTTON  ;;	BS_PUSHBUTTON
		Ret .= QStyle("BS_PUSHBUTTON", "0x0000", "!(BS_DEFPUSHBUTTON | BS_CHECKBOX | BS_AUTOCHECKBOX | BS_RADIOBUTTON | BS_GROUPBOX | BS_AUTORADIOBUTTON)")

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "Button", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_Edit(Style, hWnd, byref ResEx)  {
	; https://www.autohotkey.com/boards/viewtopic.php?p=25848#p25848
	; https://docs.microsoft.com/en-us/windows/desktop/controls/edit-control-styles
	; https://docs.microsoft.com/en-us/windows/win32/controls/edit-control-window-extended-styles
	; https://docs.microsoft.com/en-us/windows/win32/controls/em-setextendedstyle
	Static oStyles, oExStyles, EM_GETEXTENDEDSTYLE := 0x1500 + 11
	If !oStyles
		oStyles := {"ES_CENTER":"0x0001","ES_RIGHT":"0x0002","ES_MULTILINE":"0x0004"
		,"ES_UPPERCASE":"0x0008","ES_LOWERCASE":"0x0010","ES_PASSWORD":"0x0020","ES_AUTOVSCROLL":"0x0040"
		,"ES_AUTOHSCROLL":"0x0080","ES_NOHIDESEL":"0x0100","ES_OEMCONVERT":"0x0400","ES_READONLY":"0x0800"
		,"ES_WANTRETURN":"0x1000","ES_NUMBER":"0x2000"}
		
		, oExStyles := {"ES_EX_ALLOWEOL_CR":"0x0001","ES_EX_ALLOWEOL_LF":"0x0002"
		,"ES_EX_CONVERT_EOL_ON_PASTE":"0x0004","ES_EX_ZOOMABLE":"0x0010"}

	SendMessage, EM_GETEXTENDEDSTYLE, 0, 0, , ahk_id %hWnd%
	ExStyle := sExStyle := ErrorLevel
	
	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (%K% := 1, Style -= V)
			Ret .= QStyle(K, V)

	IF !ES_CENTER && !ES_RIGHT  ;;	ES_LEFT
		Ret .= QStyle("ES_LEFT", "0x0000", "!(ES_CENTER | ES_RIGHT)")

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "Edit", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2

	IF ExStyle
	{ 
		For K, V In oExStyles
			If ((ExStyle & V) = V) && (%K% := 1, ExStyle -= V)
				RetEx .= QStyle(K, V)  
		
		If (sExStyle & 3)
			RetEx .= QStyle("ES_EX_ALLOWEOL_ALL", "0x0003", "(ES_EX_ALLOWEOL_CR && ES_EX_ALLOWEOL_LF)")  
		IF ExStyle
			RetEx .= QStyleRest(4, ExStyle)
		
		If RetEx !=
			ResEx := _T1 " id='__ExStyles_Control'>" QStyleTitle("ExStyles", "Edit", 4, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2
	} 
	
	Return Res
}

GetStyle_ComboLBox(Style, hWnd)  {
	Return GetStyle_ListBox(Style, hWnd)
}

GetStyle_ListBox(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25855#p25855
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/list-box-styles
	Static oStyles
	If !oStyles
		oStyles := {"LBS_NOTIFY":"0x0001","LBS_SORT":"0x0002","LBS_NOREDRAW":"0x0004","LBS_MULTIPLESEL":"0x0008"
		,"LBS_OWNERDRAWFIXED":"0x0010","LBS_OWNERDRAWVARIABLE":"0x0020","LBS_HASSTRINGS":"0x0040"
		,"LBS_USETABSTOPS":"0x0080","LBS_NOINTEGRALHEIGHT":"0x0100","LBS_MULTICOLUMN":"0x0200"
		,"LBS_WANTKEYBOARDINPUT":"0x0400","LBS_EXTENDEDSEL":"0x0800","LBS_DISABLENOSCROLL":"0x1000","LBS_NODATA":"0x2000"
		,"LBS_NOSEL":"0x4000","LBS_COMBOBOX":"0x8000"}
		, WS_VSCROLL := 0x200000, WS_BORDER := 0x800000

	wStyle := Style, Style := sStyle := Style & 0xffff

	For K, V In oStyles
		If ((Style & V) = V) && (%K% := 1, Style -= V)
			Ret .= QStyle(K, V) 

	IF LBS_NOTIFY && LBS_SORT && (wStyle & WS_VSCROLL) && (wStyle & WS_BORDER) && (1, Style -= 0x0003)  ;;	LBS_STANDARD 
		Ret .= QStyle("LBS_STANDARD", "0xA00003", "(LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER)")

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "ListBox", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_SysAnimate32(Style, hWnd)  {
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/animation-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"ACS_CENTER":"0x0001","ACS_TRANSPARENT":"0x0002","ACS_AUTOPLAY":"0x0004","ACS_TIMER":"0x0008"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (1, Style -= V)
			Ret .= QStyle(K, V)  
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysAnimate32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_SysPager(Style, hWnd)  {
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/pager-control-styles
	Static oStyles, oEx
	If !oStyles
		oStyles := {"PGS_HORZ":"0x0001","PGS_AUTOSCROLL":"0x0002","PGS_DRAGNDROP":"0x0004"}
		, oEx := {"PGS_VERT":"0x0000"}
	Style := sStyle := Style & 0xffff
	If !(Style & oStyles.PGS_HORZ)
		Ret .= "<span name='MS:'>PGS_VERT := <span class='param' name='MS:'>0x0000   !(PGS_HORZ)</span></span>`n"
	For K, V In oStyles
		If ((Style & V) = V) && (1, Style -= V)
			Ret .= QStyle(K, V)
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysPager", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_msctls_updown32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25878#p25878
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/up-down-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"UDS_WRAP":"0x0001","UDS_SETBUDDYINT":"0x0002","UDS_ALIGNRIGHT":"0x0004","UDS_ALIGNLEFT":"0x0008"
		,"UDS_AUTOBUDDY":"0x0010","UDS_ARROWKEYS":"0x0020","UDS_HORZ":"0x0040","UDS_NOTHOUSANDS":"0x0080","UDS_HOTTRACK":"0x0100"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (1, Style -= V) 
			Ret .= QStyle(K, V) 
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "msctls_updown32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_SysDateTimePick32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25878#p25878
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/date-and-time-picker-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"DTS_UPDOWN":"0x0001","DTS_SHOWNONE":"0x0002","DTS_LONGDATEFORMAT":"0x0004","DTS_TIMEFORMAT":"0x0009"
			,"DTS_SHORTDATECENTURYFORMAT":"0x000C","DTS_APPCANPARSE":"0x0010","DTS_RIGHTALIGN":"0x0020"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (%K% := 1, Style -= V)
			Ret .= QStyle(K, V) 
	IF !DTS_LONGDATEFORMAT  ;;	DTS_SHORTDATEFORMAT
		Ret .= QStyle("DTS_SHORTDATEFORMAT", "0x0000", "!(DTS_LONGDATEFORMAT)")

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysDateTimePick32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_SysMonthCal32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25861#p25861
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/month-calendar-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"MCS_DAYSTATE":"0x0001","MCS_MULTISELECT":"0x0002","MCS_WEEKNUMBERS":"0x0004","MCS_NOTODAYCIRCLE":"0x0008"
		,"MCS_NOTODAY":"0x0010","MCS_NOTRAILINGDATES":"0x0040","MCS_SHORTDAYSOFWEEK":"0x0080","MCS_NOSELCHANGEONNAV":"0x0100"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (1, Style -= V)
			Ret .= QStyle(K, V) 
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style) 
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysMonthCal32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_msctls_trackbar32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25875#p25875
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/trackbar-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"TBS_AUTOTICKS":"0x0001","TBS_VERT":"0x0002"
		,"TBS_BOTH":"0x0008","TBS_NOTICKS":"0x0010","TBS_ENABLESELRANGE":"0x0020"
		,"TBS_FIXEDLENGTH":"0x0040","TBS_NOTHUMB":"0x0080","TBS_TOOLTIPS":"0x0100","TBS_REVERSED":"0x0200"
		,"TBS_DOWNISLEFT":"0x0400","TBS_NOTIFYBEFOREMOVE":"0x0800","TBS_TRANSPARENTBKGND":"0x1000"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (%K% := 1, Style -= V)
			Ret .= QStyle(K, V)

	IF !TBS_VERT
	{
		Ret .= QStyle("TBS_HORZ", "0x0000", "!(TBS_VERT)")  ;;	TBS_HORZ
		IF ((Style & 0x0004) = 0x0004) && (1, Style -= 0x0004)  ;;	TBS_TOP 
			Ret .= QStyle("TBS_TOP", "0x0004", "(TBS_HORZ)")
		IF !TBS_TOP  ;;	TBS_BOTTOM 
			Ret .= QStyle("TBS_BOTTOM", "0x0000", "!(TBS_TOP) && (TBS_HORZ)")
	}
	Else
	{
		IF ((Style & 0x0004) = 0x0004) && (TBS_LEFT := 1, Style -= 0x0004)  ;;	TBS_LEFT
			Ret .= QStyle("TBS_LEFT", "0x0004", "(TBS_VERT)")

		IF !TBS_LEFT  ;;	TBS_RIGHT 
			Ret .= QStyle("TBS_RIGHT", "0x0000", "!(TBS_LEFT) && (TBS_VERT)")
	}
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "msctls_trackbar32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_msctls_statusbar32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25870#p25870
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/status-bar-styles
	Static oStyles
	If !oStyles
		oStyles := {"SBARS_SIZEGRIP":"0x0100","SBARS_TOOLTIPS":"0x0800"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (1, Style -= V)
			Ret .= QStyle(K, V)
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "msctls_statusbar32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_msctls_progress32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25864#p25864
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/progress-bar-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"PBS_SMOOTH":"0x0001","PBS_VERTICAL":"0x0004","PBS_MARQUEE":"0x0008","PBS_SMOOTHREVERSE":"0x0010"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (1, Style -= V) 
			Ret .= QStyle(K, V) 
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "msctls_progress32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_SysHeader32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25850#p25850
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/header-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"HDS_BUTTONS":"0x0002","HDS_CHECKBOXES":"0x0400","HDS_DRAGDROP":"0x0040","HDS_FILTERBAR":"0x0100","HDS_FLAT":"0x0200"
		,"HDS_FULLDRAG":"0x0080","HDS_HIDDEN":"0x0008","HDS_HORZ":"0x0000","HDS_HOTTRACK":"0x0004","HDS_NOSIZING":"0x0800","HDS_OVERFLOW":"0x1000"}

	;; Style := DllCall("GetWindowLong", "Ptr", hWnd, "int", GWL_STYLE := -16)

	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (1, Style -= V)
			Ret .= QStyle(K, V)
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysHeader32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_SysLink(Style, hWnd) {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25859#p25859
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/syslink-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"LWS_IGNORERETURN":"0x0002","LWS_NOPREFIX":"0x0004","LWS_RIGHT":"0x0020"
		,"LWS_TRANSPARENT":"0x0001","LWS_USECUSTOMTEXT":"0x0010","LWS_USEVISUALSTYLE":"0x0008"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (1, Style -= V)
			Ret .= QStyle(K, V)
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style) 
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysLink", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_ReBarWindow32(Style, hWnd) {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25865#p25865
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/rebar-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"RBS_AUTOSIZE":"0x2000","RBS_BANDBORDERS":"0x0400","RBS_DBLCLKTOGGLE":"0x8000","RBS_FIXEDORDER":"0x0800"
		,"RBS_REGISTERDROP":"0x1000","RBS_TOOLTIPS":"0x0100","RBS_VARHEIGHT":"0x0200","RBS_VERTICALGRIPPER":"0x4000"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (1, Style -= V)
			Ret .= QStyle(K, V)
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "ReBarWindow32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	Return Res
}

GetStyle_CommonControl(Style, ByRef NewStyle) {   ;;	Остаток от стилей контролов
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25846#p25846
	Static oStyles, oEx
	If !oStyles
		oStyles := {"CCS_ADJUSTABLE":"0x0020","CCS_BOTTOM":"0x0003","CCS_NODIVIDER":"0x0040","CCS_NOMOVEY":"0x0002"
		,"CCS_NOPARENTALIGN":"0x0008","CCS_NORESIZE":"0x0004","CCS_TOP":"0x0001","CCS_VERT":"0x0080"}

		,oEx := {"CCS_LEFT":"0x0081","CCS_NOMOVEX":"0x0082","CCS_RIGHT":"0x0083"}

	NewStyle := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((NewStyle & V) = V) && (%K% := 1, NewStyle -= V)
			Ret .= QStyle(K, V)
	IF !CCS_VERT && !CCS_TOP && (NewStyle & oEx.CCS_LEFT) && (1, NewStyle -= oEx.CCS_LEFT)  ;;	CCS_LEFT
		Ret .= QStyle("CCS_LEFT", "0x0081", "!(CCS_VERT | CCS_TOP)")
	IF !CCS_VERT && !CCS_NOMOVEY && (NewStyle & oEx.CCS_NOMOVEX) && (1, NewStyle -= oEx.CCS_NOMOVEX)  ;;	CCS_NOMOVEX
		Ret .= QStyle("CCS_NOMOVEX", "0x0082", "!(CCS_VERT | CCS_NOMOVEY)") 
	IF !CCS_VERT && !CCS_BOTTOM && (NewStyle & oEx.CCS_RIGHT) && (1, NewStyle -= oEx.CCS_RIGHT)  ;;	CCS_RIGHT
		Ret .= QStyle("CCS_RIGHT", "0x0083", "!(CCS_VERT | CCS_BOTTOM)") 
	Return Ret
}




GetStyle_SysListView32(Style, hWnd, byref ResEx)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25857#p25857
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/list-view-window-styles
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/extended-list-view-styles
	Static oStyles, oExStyles, oEx, LVM_GETEXTENDEDLISTVIEWSTYLE := 0x1037
	If !oStyles
		oStyles := {"LVS_AUTOARRANGE":"0x0100","LVS_EDITLABELS":"0x0200"
		,"LVS_NOLABELWRAP":"0x0080","LVS_NOSCROLL":"0x2000"
		,"LVS_OWNERDRAWFIXED":"0x0400","LVS_SHAREIMAGELISTS":"0x0040","LVS_SHOWSELALWAYS":"0x0008","LVS_SINGLESEL":"0x0004"
		,"LVS_OWNERDATA":"0x1000","LVS_SORTASCENDING":"0x0010","LVS_SORTDESCENDING":"0x0020"}

		, oExStyles := {"LVS_EX_AUTOAUTOARRANGE":"0x01000000","LVS_EX_AUTOCHECKSELECT":"0x08000000","LVS_EX_AUTOSIZECOLUMNS":"0x10000000"
		,"LVS_EX_BORDERSELECT":"0x00008000","LVS_EX_CHECKBOXES":"0x00000004","LVS_EX_COLUMNOVERFLOW":"0x80000000","LVS_EX_COLUMNSNAPPOINTS":"0x40000000"
		,"LVS_EX_DOUBLEBUFFER":"0x00010000","LVS_EX_FLATSB":"0x00000100","LVS_EX_FULLROWSELECT":"0x00000020","LVS_EX_GRIDLINES":"0x00000001"
		,"LVS_EX_HEADERDRAGDROP":"0x00000010","LVS_EX_HEADERINALLVIEWS":"0x02000000","LVS_EX_HIDELABELS":"0x00020000"
		,"LVS_EX_INFOTIP":"0x00000400","LVS_EX_JUSTIFYCOLUMNS":"0x00200000","LVS_EX_LABELTIP":"0x00004000","LVS_EX_MULTIWORKAREAS":"0x00002000"
		,"LVS_EX_ONECLICKACTIVATE":"0x00000040","LVS_EX_REGIONAL":"0x00000200","LVS_EX_SIMPLESELECT":"0x00100000","LVS_EX_SINGLEROW":"0x00040000"
		,"LVS_EX_SNAPTOGRID":"0x00080000","LVS_EX_SUBITEMIMAGES":"0x00000002","LVS_EX_TRACKSELECT":"0x00000008","LVS_EX_TRANSPARENTBKGND":"0x00400000"
		,"LVS_EX_TRANSPARENTSHADOWTEXT":"0x00800000","LVS_EX_TWOCLICKACTIVATE":"0x00000080"
		,"LVS_EX_UNDERLINECOLD":"0x00001000","LVS_EX_UNDERLINEHOT":"0x00000800"}

		,oEx := {"LVS_TYPEMASK":"0x0003","LVS_ICON":"0x0000","LVS_REPORT":"0x0001","LVS_SMALLICON":"0x0002","LVS_LIST":"0x0003"
		,"LVS_ALIGNMASK":"0x0C00","LVS_ALIGNTOP":"0x0000","LVS_ALIGNLEFT":"0x0800"
		,"LVS_TYPESTYLEMASK":"0xFC00","LVS_NOSORTHEADER":"0x8000","LVS_NOCOLUMNHEADER":"0x4000"}

	SendMessage, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0,, ahk_id %hWnd%
	ExStyle := sExStyle := ErrorLevel
	Style := sStyle := Style & 0xffff

	For K, V In oStyles
		If ((sStyle & V) = V) && (%K% := 1, Style -= V)
			Ret .= QStyle(K, V) 

	IF ((sStyle & oEx.LVS_TYPEMASK) = oEx.LVS_REPORT) && (LVS_REPORT := 1, Style -= oEx.LVS_REPORT)      ;;	LVS_REPORT 
		Ret .= QStyle("LVS_REPORT", "0x0001", "(LVS_TYPEMASK = 0x0001)")
	IF ((sStyle & oEx.LVS_TYPEMASK) = oEx.LVS_SMALLICON) && (LVS_SMALLICON := 1, Style -= oEx.LVS_SMALLICON)      ;;	LVS_SMALLICON
		Ret .= QStyle("LVS_SMALLICON", "0x0002", "(LVS_TYPEMASK = 0x0002)")
	IF ((sStyle & oEx.LVS_TYPEMASK) = oEx.LVS_LIST) && (LVS_LIST := 1, Style -= oEx.LVS_LIST)      ;;	LVS_LIST
		Ret .= QStyle("LVS_LIST", "0x0003", "(LVS_TYPEMASK = 0x0003)")
	IF ((sStyle & oEx.LVS_TYPEMASK) = oEx.LVS_ICON) && !LVS_REPORT && !LVS_SMALLICON && !LVS_LIST && (LVS_ICON := 1)      ;;	LVS_ICON
		Ret .= QStyle("LVS_ICON", "0x0000", "!(LVS_REPORT | LVS_SMALLICON | LVS_LIST)")
	IF ((sStyle & oEx.LVS_ALIGNMASK) = oEx.LVS_ALIGNLEFT) && (LVS_ALIGNLEFT := 1, Style -= oEx.LVS_ALIGNLEFT)      ;;	LVS_ALIGNLEFT
		Ret .= QStyle("LVS_ALIGNLEFT", "0x0800", "(LVS_ALIGNMASK = 0x0800)")
	IF ((sStyle & oEx.LVS_ALIGNMASK) = oEx.LVS_ALIGNTOP) && (LVS_SMALLICON || LVS_ICON) && (LVS_ALIGNTOP := 1, Style -= oEx.LVS_ALIGNTOP)      ;;	LVS_ALIGNTOP
		Ret .= QStyle("LVS_ALIGNTOP", "0x0000", "(LVS_SMALLICON || LVS_ICON)")
	IF ((sStyle & oEx.LVS_NOSORTHEADER) = oEx.LVS_NOSORTHEADER) && (LVS_NOSORTHEADER := 1, Style -= oEx.LVS_NOSORTHEADER)      ;;	LVS_NOSORTHEADER
		Ret .= QStyle("LVS_NOSORTHEADER", "0x8000", "(LVS_TYPEMASK = 0x0003)")
	IF ((sStyle & oEx.LVS_NOCOLUMNHEADER) = oEx.LVS_NOCOLUMNHEADER) && (LVS_NOCOLUMNHEADER := 1, Style -= oEx.LVS_NOCOLUMNHEADER)      ;;	LVS_NOCOLUMNHEADER
		Ret .= QStyle("LVS_NOCOLUMNHEADER", "0x4000")

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysListView32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	 
	For K, V In oExStyles
		If ((ExStyle & V) = V) && (%K% := 1, ExStyle -= V)
			RetEx .= QStyle(K, V)

	IF ExStyle
		RetEx .= QStyleRest(8, ExStyle)  
	If RetEx !=
		ResEx := _T1 " id='__ExStyles_Control'>" QStyleTitle("ExStyles", "SysListView32", 8, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2
	 
	 Return Res
}

GetStyle_SysTreeView32(Style, hWnd, byref ResEx)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25876#p25876
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/tree-view-control-window-styles
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/tree-view-control-window-extended-styles
	Static oStyles, oExStyles, TVM_GETEXTENDEDSTYLE := 0x112D
	If !oStyles
		oStyles := {"TVS_CHECKBOXES":"0x0100","TVS_DISABLEDRAGDROP":"0x0010","TVS_EDITLABELS":"0x0008","TVS_FULLROWSELECT":"0x1000","TVS_HASBUTTONS":"0x0001"
		,"TVS_HASLINES":"0x0002","TVS_INFOTIP":"0x0800","TVS_LINESATROOT":"0x0004","TVS_NOHSCROLL":"0x8000","TVS_NONEVENHEIGHT":"0x4000","TVS_NOSCROLL":"0x2000"
		,"TVS_NOTOOLTIPS":"0x0080","TVS_RTLREADING":"0x0040","TVS_SHOWSELALWAYS":"0x0020","TVS_SINGLEEXPAND":"0x0400","TVS_TRACKSELECT":"0x0200"}

		, oExStyles := {"TVS_EX_AUTOHSCROLL":"0x0020","TVS_EX_DIMMEDCHECKBOXES":"0x0200","TVS_EX_DOUBLEBUFFER":"0x0004","TVS_EX_DRAWIMAGEASYNC":"0x0400"
		,"TVS_EX_EXCLUSIONCHECKBOXES":"0x0100","TVS_EX_FADEINOUTEXPANDOS":"0x0040","TVS_EX_MULTISELECT":"0x0002","TVS_EX_NOINDENTSTATE":"0x0008"
		,"TVS_EX_NOSINGLECOLLAPSE":"0x0001","TVS_EX_PARTIALCHECKBOXES":"0x0080","TVS_EX_RICHTOOLTIP":"0x0010"}

	SendMessage, TVM_GETEXTENDEDSTYLE, 0, 0,, ahk_id %hWnd%
	ExStyle := sExStyle := ErrorLevel
	Style := sStyle := Style & 0xffff

	For K, V In oStyles
		If ((sStyle & V) = V) && (1, Style -= V)
			Ret .= QStyle(K, V)

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysTreeView32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
 
	For K, V In oExStyles
		If ((ExStyle & V) = V) && (1, ExStyle -= V)
			RetEx .= QStyle(K, V)

	IF ExStyle
		RetEx .= QStyleRest(8, ExStyle)  
	If RetEx !=
		ResEx := _T1 " id='__ExStyles_Control'>" QStyleTitle("ExStyles", "SysTreeView32", 8, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2
	
	Return Res
}

GetStyle_SysTabControl32(Style, hWnd, byref ResEx)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25871#p25871
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/tab-control-styles
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/tab-control-extended-styles
	Static oStyles, TCM_GETEXTENDEDSTYLE := 0x1335
	If !oStyles
		oStyles := {"TCS_SCROLLOPPOSITE":"0x0001","TCS_MULTISELECT":"0x0004","TCS_FLATBUTTONS":"0x0008"
		,"TCS_FORCELABELLEFT":"0x0020","TCS_HOTTRACK":"0x0040","TCS_BUTTONS":"0x0100","TCS_MULTILINE":"0x0200"
		,"TCS_FORCEICONLEFT":"0x0010","TCS_FIXEDWIDTH":"0x0400","TCS_RAGGEDRIGHT":"0x0800","TCS_FOCUSONBUTTONDOWN":"0x1000"
		,"TCS_OWNERDRAWFIXED":"0x2000","TCS_TOOLTIPS":"0x4000","TCS_FOCUSNEVER":"0x8000"}

	SendMessage, TCM_GETEXTENDEDSTYLE, 0, 0,, ahk_id %hWnd%
	ExStyle := sExStyle := ErrorLevel
	Style := sStyle := Style & 0xffff
	For K, V In oStyles
		If ((Style & V) = V) && (%K% := 1, Style -= V)
			Ret .= QStyle(K, V)

	IF !TCS_BUTTONS   ;;	TCS_TABS
		Ret .= QStyle("TCS_TABS", "0x0000", "!(TCS_BUTTONS)")
	IF !TCS_MULTILINE   ;;	TCS_SINGLELINE
		Ret .= QStyle("TCS_SINGLELINE", "0x0000", "!(TCS_MULTILINE)")
	IF TCS_MULTILINE   ;;	TCS_RIGHTJUSTIFY
		Ret .= QStyle("TCS_RIGHTJUSTIFY", "0x0000", "(TCS_MULTILINE)")
	IF TCS_MULTILINE && ((Style & 0x0080) = 0x0080) && (TCS_VERTICAL := 1, Style -= 0x0080)  ;;	"TCS_VERTICAL":"0x0080"
		Ret .= QStyle("TCS_VERTICAL", "0x0080", "(TCS_MULTILINE)")
	IF ((Style & 0x0002) = 0x0002) && (1, Style -= 0x0002)   ;;	"TCS_BOTTOM":"0x0002","TCS_RIGHT":"0x0002"
	{
		IF TCS_VERTICAL
			Ret .= QStyle("TCS_RIGHT", "0x0002", "(TCS_VERTICAL)")
		Else
			Ret .= QStyle("TCS_BOTTOM", "0x0002", "!(TCS_VERTICAL)")
	}
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysTabControl32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
 
	If ((ExStyle & 0x00000001) = 0x00000001) && (1, ExStyle -= 0x00000001)  ;;	TCS_EX_FLATSEPARATORS
		RetEx .= QStyle("TCS_EX_FLATSEPARATORS", "0x00000001")
	If ((ExStyle & 0x00000002) = 0x00000002) && (1, ExStyle -= 0x00000002)  ;;	TCS_EX_REGISTERDROP
		RetEx .= QStyle("TCS_EX_REGISTERDROP", "0x00000002")

	IF ExStyle
		RetEx .= QStyleRest(8, ExStyle)  
	If RetEx !=
		ResEx := _T1 " id='__ExStyles_Control'>" QStyleTitle("ExStyles", "SysTabControl32", 8, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2
	
	Return Res
}

GetStyle_ComboBox(Style, hWnd, byref ResEx)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25842#p25842
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/combo-box-styles
	Static oStyles, oExStyles, oEx, CBEM_GETEXTENDEDSTYLE := 0x0409
	If !oStyles
		oStyles := {"CBS_SIMPLE":"0x0001","CBS_DROPDOWN":"0x0002","CBS_OWNERDRAWFIXED":"0x0010"
		,"CBS_OWNERDRAWVARIABLE":"0x0020","CBS_AUTOHSCROLL":"0x0040","CBS_OEMCONVERT":"0x0080","CBS_SORT":"0x0100"
		,"CBS_HASSTRINGS":"0x0200","CBS_NOINTEGRALHEIGHT":"0x0400","CBS_DISABLENOSCROLL":"0x0800"
		,"CBS_UPPERCASE":"0x2000","CBS_LOWERCASE":"0x4000"}
		, oEx := {"CBS_DROPDOWNLIST":"0x0003"}
		, oExStyles := {"CBES_EX_CASESENSITIVE":"0x0010","CBES_EX_NOEDITIMAGE":"0x0001","CBES_EX_NOEDITIMAGEINDENT":"0x0002"
		,"CBES_EX_NOSIZELIMIT":"0x0008","CBES_EX_PATHWORDBREAKPROC":"0x0004","CBES_EX_TEXTENDELLIPSIS":"0x0020"}
	
	If (hParent := DllCall("GetParent", "Ptr", hWnd))
	{
		WinGetClass, ParentClass, ahk_id %hParent%
		If ParentClass = ComboBoxEx32
		{
			SendMessage, CBEM_GETEXTENDEDSTYLE, 0, 0, , ahk_id %hParent%
			ExStyle := sExStyle := ErrorLevel
			For K, V In oExStyles
				If ((ExStyle & V) = V) && (1, ExStyle -= V) 
					RetEx .= QStyle(K, V)
			IF ExStyle
				RetEx .= QStyleRest(4, ExStyle) 
		} 
	}
	Style := sStyle := Style & 0xffff
	If ((Style & oEx.CBS_DROPDOWNLIST) = oEx.CBS_DROPDOWNLIST) && (1, Style -= oEx.CBS_DROPDOWNLIST)  ;;	CBS_DROPDOWNLIST
		Ret .= QStyle("CBS_DROPDOWNLIST", oEx.CBS_DROPDOWNLIST)
	For K, V In oStyles
		If ((Style & V) = V) && (1, Style -= V)
			Ret .= QStyle(K, V)
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style) 
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "ComboBox", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2 
	If RetEx !=
		ResEx := _T1 " id='__ExStyles_Control'>" QStyleTitle("ExStyles", "ComboBoxEx32", 4, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2
	Return Res
}

GetStyle_ToolbarWindow32(Style, hWnd, byref ResEx)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25872#p25872
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/toolbar-control-and-button-styles
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/toolbar-extended-styles
	;;	https://docs.microsoft.com/en-us/windows/desktop/api/Commctrl/ns-commctrl-_tbbutton
	Static oStyles, oExStyles, TB_GETSTYLE := 0x0439, TB_GETEXTENDEDSTYLE := 0x0455
	If !oStyles
		oStyles := {"TBSTYLE_ALTDRAG":"0x0400","TBSTYLE_CUSTOMERASE":"0x2000","TBSTYLE_FLAT":"0x0800","TBSTYLE_LIST":"0x1000"
		,"TBSTYLE_REGISTERDROP":"0x4000","TBSTYLE_TOOLTIPS":"0x0100","TBSTYLE_TRANSPARENT":"0x8000","TBSTYLE_WRAPABLE":"0x0200"}

		, oExStyles := {"TBSTYLE_EX_DOUBLEBUFFER":"0x80","TBSTYLE_EX_DRAWDDARROWS":"0x01","TBSTYLE_EX_HIDECLIPPEDBUTTONS":"0x10"
		,"TBSTYLE_EX_MIXEDBUTTONS":"0x08","TBSTYLE_EX_MULTICOLUMN":"0x02","TBSTYLE_EX_VERTICAL":"0x04"}

	SendMessage, TB_GETSTYLE, 0, 0, , ahk_id %hWnd%
	Style := sStyle := ErrorLevel & 0xffff

	SendMessage, TB_GETEXTENDEDSTYLE, 0, 0, , ahk_id %hWnd%
	ExStyle := sExStyle := ErrorLevel 
	
	For K, V In oStyles
		If ((sStyle & V) = V) && (1, Style -= V)
			Ret .= QStyle(K, V)

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(8, Style)   
	If Ret !=
		Res .= _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "ToolbarWindow32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2 
	For K, V In oExStyles
		If ((ExStyle & V) = V) && (1, ExStyle -= V)
			RetEx .= QStyle(K, V)

	IF ExStyle
		RetEx .= QStyleRest(4, ExStyle)  
	If RetEx !=
		ResEx := _T1 " id='__ExStyles_Control'>" QStyleTitle("ExStyles", "ToolbarWindow32", 4, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2 
		
	Return Res
	
/*
		oBTNS := {"BTNS_BUTTON":"0x00","BTNS_SEP":"0x01","BTNS_CHECK":"0x02","BTNS_GROUP":"0x04","BTNS_CHECKGROUP":"0x06","BTNS_DROPDOWN":"0x08"
		,"BTNS_AUTOSIZE":"0x10","BTNS_NOPREFIX":"0x20","BTNS_SHOWTEXT":"0x40","BTNS_WHOLEDROPDOWN":"0x80"}

		VarSetCapacity(TBBUTTON, A_PtrSize == 8 ? 32 : 20, 0)

		iBitmap := NumGet(TBBUTTON, 0, "Int")
		idCommand := NumGet(TBBUTTON, 4, "Int")
		fsState := NumGet(TBBUTTON, 8, "UChar")
		fsStyle := NumGet(TBBUTTON, 9, "UChar")
		bReserved := NumGet(TBBUTTON, 10, "UChar")
		;;bReserved := NumGet(TBBUTTON, 10, "UChar")
		dwData := NumGet(TBBUTTON, A_PtrSize == 8 ? 16 : 12, "UPtr")
		iString := NumGet(TBBUTTON, A_PtrSize == 8 ? 24 : 16, "Ptr")
*/
}

	; ___________________________ FullScreen _________________________________________________

FullScreenMode() {
	Static Max, hFunc
	hwnd := WinExist("ahk_id" hGui)
	If !FullScreenMode
	{
		FullScreenMode := 1
		Menu, Sys, Check, Full screen
		WinGetNormalPos(hwnd, X, Y, W, H)
		WinGet, Max, MinMax, ahk_id %hwnd%
		If Max = 1
			WinSet, Style, -0x01000000	;;	WS_MAXIMIZE
		Gui, 1: -ReSize -Caption
		Gui, 1: Show, x0 y0 w%A_ScreenWidth% h%A_ScreenHeight%
		Gui, 1: Maximize
		WinSetNormalPos(hwnd, X, Y, W, H)
		hFunc := Func("ControlsMove").Bind(A_ScreenWidth, A_ScreenHeight)
	}
	Else
	{
		Gui, 1: +ReSize +Caption
		If Max = 1
		{
			WinGetNormalPos(hwnd, X, Y, W, H)
			Gui, 1: Maximize
			WinSetNormalPos(hwnd, X, Y, W, H)
		}
		Else
			Gui, 1: Restore
		Sleep 20
		GetClientPos(hwnd, _, _, Width, Height)
		hFunc := Func("ControlsMove").Bind(Width, Height)
		FullScreenMode := 0
		Menu, Sys, UnCheck, Full screen
	}
	SetTimer, % hFunc, -10
}

WinGetNormalPos(hwnd, ByRef x, ByRef y, ByRef w, ByRef h) {
	VarSetCapacity(wp, 44), NumPut(44, wp)
	DllCall("GetWindowPlacement", "Ptr", hwnd, "Ptr", &wp)
	x := NumGet(wp, 28, "int"), y := NumGet(wp, 32, "int")
	w := NumGet(wp, 36, "int") - x,  h := NumGet(wp, 40, "int") - y
}

WinSetNormalPos(hwnd, x, y, w, h) {
	VarSetCapacity(wp, 44, 0), NumPut(44, wp, 0, "uint")
	DllCall("GetWindowPlacement", "Ptr", hWnd, "Ptr", &wp)
	NumPut(x, wp, 28, "int"), NumPut(y, wp, 32, "int")
	NumPut(w + x, wp, 36, "int"), NumPut(h + y, wp, 40, "int")
	DllCall("SetWindowPlacement", "Ptr", hWnd, "Ptr", &wp)
}

	; ___________________________ Find _________________________________________________

_FindView() {
	If isFindView
		Return FindHide(), AnchorFitScroll()
	GuiControlGet, p, 1:Pos, %hActiveX%
	GuiControl, 1:Move, %hActiveX%, % "x" pX " y" pY " w" pW " h" pH - 28
	Gui, F: Show, % "NA x" (pW - widthTB) // 2.2 " h26 y" (pY + pH - 27)
	isFindView := 1
	GuiControl, F:Focus, Edit1
	Menu, Sys, Check, Find to page
	FindSearch(1) 
	AnchorFitScroll()
}

FindHide() {
	Gui, F: Show, Hide
	GuiControlGet, a, 1:Pos, %hActiveX%
	GuiControl, 1:Move, %hActiveX%, % "x" aX "y" aY "w" aW "h" aH + 28
	isFindView := 0
	GuiControl, Focus, %hActiveX%
	Menu, Sys, UnCheck, Find to page
}

FindOption(Hwnd) {
	GuiControlGet, p, Pos, %Hwnd%
	If pX =
		Return
	ControlGet, Style, Style,, , ahk_id %Hwnd%
	ControlGetText, Text, , ahk_id %Hwnd%
	DllCall("DestroyWindow", "Ptr", Hwnd)
	; BS_PUSHLIKE := 0x1000
	Gui, %A_Gui%: Add, Text, % "x" pX " y" pY " w" pW " h" pH " g" A_ThisFunc " c" ColorFont " " (Style & 0x1000 ? "+0x0201" : "+Border +0x1201"), % Text
	InStr(Text, "sensitive") ? (oFind.Registr := !(Style & 0x1000)) : (oFind.Whole := !(Style & 0x1000))
	FindSearch(1)
	FindAll()
}

FindNew(Hwnd) {
	ControlGetText, Text, , ahk_id %Hwnd%
	oFind.Text := Text
	hFunc := Func("FindSearch").Bind(1)
	SetTimer, FindAll, -150
	SetTimer, % hFunc, -150
}

FindNewText() {
	hFunc := Func("FindSearch").Bind(1)
	SetTimer, % hFunc, -1
	SetTimer, FindAll, -150
}

FindNext(Hwnd) {
	SendMessage, 0x400+114,,,, ahk_id %Hwnd%		;;  UDM_GETPOS32
	Back := !ErrorLevel
	FindSearch(0, Back)
}

FindAll() {
	If (oFind.Text = "")
	{
		GuiControl, F:Text, FindMatches
		Return
	}
	R := oBody.createTextRange()
	Matches := 0
	R.collapse(1)
	Option := (oFind.Whole ? 2 : 0) ^ (oFind.Registr ? 4 : 0)
	Loop
	{
		F := R.findText(oFind.Text, 1, Option)
		If (F = 0)
			Break
		El := R.parentElement()
		If (El.TagName = "INPUT" || El.className ~= "^(button|title|param)$") && !R.collapse(0)  ;;	https://msdn.microsoft.com/en-us/library/ff976065(v=vs.85).aspx
			Continue
		; R.execCommand("BackColor", 0, "EF0FFF")
		; R.execCommand("ForeColor", 0, "FFEEFF")
		R.collapse(0), ++Matches
	}
	GuiControl, F:Text, FindMatches, % Matches ? Matches : ""
}

FindSearch(New, Back = 0) {
	Global hFindEdit
	R := oDoc.selection.createRange()
	sR := R.duplicate()
	R.collapse(New || Back ? 1 : 0)
	If (oFind.Text = "" && !R.select()) 
		SetEditColor(hFindEdit, "0x" ColorBgOriginal, "0x" ColorFont)
	Else {
		Option := (Back ? 1 : 0) ^ (oFind.Whole ? 2 : 0) ^ (oFind.Registr ? 4 : 0)
		Loop {
			F := R.findText(oFind.Text, 1, Option)
			If (F = 0) {
				If !A {
					R.moveToElementText(oBody), R.collapse(!Back), A := 1
					Continue
				}
				If New
					sR.collapse(1), sR.select()
				Break
			}
			If (!New && R.isEqual(sR)) {
				If A {
					hFunc := Func("SetEditColor").Bind(hFindEdit, "0x" ColorBgOriginal, "0x" ColorFont)
					SetTimer, % hFunc, -200
				}
				Break
			}
			El := R.parentElement()

			If (El.TagName = "INPUT" || El.className ~= "^(button|title|param)$") && !R.collapse(Back)
				Continue
			R.select(), F := 1
			Break
		}
		If (F != 1)
			SetEditColor(hFindEdit, "0x" ColorSelectedFind, "0x" ColorFont)
		Else
			SetEditColor(hFindEdit, "0x" ColorBgOriginal, "0x" ColorFont)
	}
}
	; ___________________________ Mouse hover selection _________________________________________________

MS_Cancel() {
	If !oMS.ELSel
		Return
	oMS.ELSel.style.backgroundColor := "" 
	oMS.ELSel.style.color := ""
	
	Loop % oMS.ELSel.all.length 
		oMS.ELSel.all[A_Index-1].style.color := ""
	oMS.ELSel := ""	
}

MS_SelectionCheck() {
	Selection := oDoc.selection.createRange().text != ""
	If Selection
		(!oMS.Selection && MS_Cancel())
	Else If oMS.Selection && MS_IsSelect(EL := oDoc.elementFromPoint(oMS.SCX, oMS.SCY))
		MS_Select(EL)
	oMS.Selection := Selection
}

MS_MouseOver() {
	EL := oMS.EL 
	If !MS_IsSelect(EL)
		Return
	MS_Select(EL)
}

MS_IsSelect(EL) {
	If InStr(EL.Name, "MS:")
		Return 1
}

MS_IsSelection() {
	Return oMS.ELSel.OuterText != ""
}

MS_Select(EL) { 
	If EL.Name = "MS:S" || EL.Name = "MS:SP"
		oMS.ELSel := EL.ParentElement 
	Else If EL.Name = "MS:N"
		oMS.ELSel := oDoc.all.item(EL.sourceIndex + 1)
	Else If EL.Name = "MS:P"
		oMS.ELSel := oDoc.all.item(EL.sourceIndex - 1).ParentElement
	Else
		oMS.ELSel := EL
		
	oMS.ELSel.style.backgroundColor := "#" ColorSelMouseHover
	oMS.ELSel.style.color := "#" ColorSelMouseHoverText
	
	Loop % oMS.ELSel.all.length 
		oMS.ELSel.all[A_Index-1].style.color := "#" ColorSelMouseHoverText
		 
	; ToolTip % oMS.ELSel.all.length "`n" oMS.TextColor2.OuterText "`n" EL.Name "`n" el.style.color 
}
 
	; ___________________________ Load JScripts _________________________________________________
 
ChangeCSS(id, css) {	;;  https://webo.in/articles/habrahabr/68-fast-dynamic-css/ 
	oDoc.getElementById(id).styleSheet.cssText := css
}

LoadJScript() {
	Static onhkinput, ontooltip 
	PreOver_ := PreOverflowHide ? _PreOverflowHideCSS : ""
	BodyWrap_ := WordWrap ? _BodyWrapCSS : ""
html =
(
<head> 
	<style id='css_ColorBg' type="text/css">body, .title, .button, .divwork {background-color: #%ColorBg%;}</style>
	<style id='css_PreOverflowHide' type="text/css">%PreOver_%</style>
	<style id='css_Body' type="text/css">%BodyWrap_%</style>
	<style id='css_Test' type="text/css"></style>
<style>

* {
	margin: 0;
	background: none;
	font-family: %FontFamily%;
	font-weight: %FontWeight%;
	color: #%ColorFont%; 
	// word-spacing: 0.5em;
}
body {  
	overflow: hidden; 
}
.divwork {
	position: absolute; 
	top: 5px;
	left: 5px;
	right: 1px;
	bottom: 1px; 
	font-size: %FontSize%px;
	visibility: hidden;
	overflow: auto;
	scrollbar-face-color: #%ColorScrollFace%;			/* Цвет ползунка  */
    scrollbar-arrow-color: #%ColorScrollArrows%;		/* Цвет стрелок */
    scrollbar-base-color: #%ColorScrollBack%; 	/* Цвет полосы */
	scrollbar-highlight-color: #%ColorScrollBack%;
    scrollbar-shadow-color: #%ColorScrollBack%; /* Цвет тени */
	scrollbar-track-color: #%ColorScrollBack%;
}
.br {
	height:0.1em;
} 
.box {
	position: absolute;
	overflow: hidden; 
	width: 100`%;
	height: 1.5em;
	background: transparent;
	left: 0px;
}
.line {
	position: absolute;
	width: 100`%;
	top: 1px;
}
.con {
	position: absolute;
	left: 30`%;
}
.title {
	margin-right: 50px;
	white-space: pre;
	color: #%ColorTitle%;
}
.hr {
	position: absolute;
	width: 100`%;
	border-bottom: 0.2em dashed;
	border-color: #%ColorLineTitles%;
	height: 0.5em;
}
pre {
	margin-bottom: 0.1em;
	margin-top: 0.1em;
	line-height: 1.4em;
}
.button {
	cursor: hand;
	position: relative;
	border: 1px dotted;
	border-color: #%ColorFont%;
	white-space: pre;
}
.BB {
	display: inline-block; 
} 
.param {
	color: #%ColorParam%;
}
.QStyle1 {
	color: #%ColorStyleComment1%;
}
.QStyle2 {
	color: #%ColorStyleComment2%;
}
.error {
	color: #%ColorDelimiter%;
}  
.titleparam {
	color: #%ColorTitle%;
}
#anchor {
	background-color: #%ColorSelAnchor%;
} 
</style>

</head>

<body contenteditable='false' id='body'>
	<div id='divwork1' class='divwork' onscroll='scrolldiv(this)' onresize='resizediv(this)'></div>
	<div id='divwork2' class='divwork' onscroll='scrolldiv(this)' onresize='resizediv(this)'></div>
</body>

<script type="text/javascript">
	var prWidth, WordWrap, MoveTitles, key1, key2, ButtonOver, ButtonOverColor; 
	
	function shift(el, scroll) {
		var col, Width, clientWidth, scrollLeft, Offset;
		
		clientWidth = el.clientWidth;
		// tooltip(el.id + "   " + el.style.width);
		// alert(clientWidth);
		if (clientWidth < 0)
			return
		scrollLeft = el.scrollLeft;
		Width = (clientWidth + scrollLeft);
		if (scroll && Width == prWidth)
			return
		if (MoveTitles == 1) {
			Offset = ((clientWidth / 100 * 30) + scrollLeft);
			col = el.querySelectorAll('.con');
			for (var i = 0; i < col.length; i++) {
				col[i].style.left = Offset + "px";
			}
		}
		col = el.querySelectorAll('.box');
		for (var i = 0; i < col.length; i++) {
			col[i].style.width = Width + 'px';
		}
		prWidth = Width;
	}
	function conleft30() {
		col = document.querySelectorAll('.con');
		for (var i = 0; i < col.length; i++) {
			col[i].style.left = "30`%";
		}
	}
	function menuitemdisplay(param) {
		col = document.querySelectorAll('.menuitemid');
		for (var i = 0; i < col.length; i++) {
			col[i].style.display = param;
		}
	}
	function getname(el) {
		alert(el.className);
	}
	function removemenuitem(parent, selector) {
		col = parent.querySelectorAll(selector);
		for (var i = 0; i < col.length; i++) {
			parent.removeChild(col[i])
		}
	}
	function resizediv(el) {
		shift(el, 0);
	} 
	function scrolldiv(el) {
		if (WordWrap == 1)
			return 
		shift(el, 1);
	}
	function onmousedown(el) {  // строка 57  
		el.style.backgroundColor = "#%ColorSelButton%";
		ButtonOverColor = el.style.color; 
		el.style.color = "#%ColorBgOriginal%";
		el.style.border = "1px solid"; 
		el.style.borderColor = "#%ColorFont%";
	}
	function onmouseup(el, man) { 
		el.style.backgroundColor = "";
		// el.style.color = (el.name != "pre" ? "#%ColorFont%" : "#%ColorParam%");
		el.style.color = ButtonOverColor;
		if (!man && window.event.button == 2 && el.parentElement.className == 'BB')
			document.documentElement.focus();
	}
	function onmouseover(el) {   
		ButtonOverColor = el.style.color;
		el.style.zIndex = "2";
		el.style.border = "1px solid"; 
		el.style.borderColor = "#%ColorFont%"; 
		ButtonOver = el;
		return 0;
	}
	function onmouseout(el) {  
		el.style.zIndex = "0";
		el.style.backgroundColor = "";
		// el.style.color = (el.name != "pre" ? "#%ColorFont%" : "#%ColorParam%");
		el.style.color = ButtonOverColor;
		el.style.border = "1px dotted";
		el.style.borderColor = "#%ColorFont%";
		ButtonOver = 0;
	} 
	function Assync (param) {
		setTimeout(param, 1);
	}
	function ElementName (param) {
		try {
			el = document.querySelector("[name=" + param + "]");
		} catch (e) {
			return
		}
		return el
	}
	function QS(el, param) {
		return el.querySelector(param); 
	}
	
	//	alert(value);
	//	tooltip(value);
	
</script> 

<script id='tooltipevent' type="text/javascript">
	function tooltip(text) {
		key1 = text;
		tooltipevent.click();
	}
</script>
) 
oDoc.Write("<!DOCTYPE html><head><meta http-equiv=""X-UA-Compatible"" content=""IE=8""></head>" html)
oDoc.Close() 
oDivWork1 := oDoc.getElementById("divwork1")
oDivWork2 := oDoc.getElementById("divwork2") 
 
ComObjConnect(ontooltip := oDoc.getElementById("tooltipevent"), "tooltip_") 
} 

	; ___________________________ Doc Events _________________________________________________

tooltip_onclick() {
	ToolTip(oJScript.key1, 500)
}

BodyExistCheck() { 
	If (oDivNew.innerHTML != "")
		return 
	LoadJScript()
	DivWorkIndex := 2
	oBody := oDoc.body 
	Write_%ThisMode%()  
} 


Class Events {  ;;	http://forum.script-coding.com/viewtopic.php?pid=82283#p82283
	onclick() {
		oevent := oDoc.parentWindow.event.srcElement
		If (oevent.className = "button" || oevent.tagname = "button")
			Return ButtonClick(oevent)
		If (ThisMode = "Hotkey" && !Hotkey_Arr("Hook") && !isPaused && oevent.tagname ~= "PRE|SPAN")
			Hotkey_Hook(1)
	}
	ondblclick() {
		Static wordchar := "(*UCP)[_²#\.\w]"
		oevent := oDoc.parentWindow.event.srcElement
		
		If (oevent.className = "button" || oevent.tagname = "button")
			Return ButtonClick(oevent)
			
		If (oevent.tagname != "input" && (rng := oDoc.selection.createRange()).text != "" && oevent.isContentEditable)
		{ 
			While len != StrLen(rng.text) { 
				len := StrLen(rng.text)
				(SubStr(rng.text, 0) ~= wordchar ? rng.moveEnd("character", 1) 
				: (rng.moveEnd("character", -1), len := StrLen(rng.text))) 
			} 
			While !b {
				rng.moveStart("character", -1) 
				(SubStr(rng.text, 1, 1) ~= wordchar ? 0
				: (rng.moveStart("character", 1), b := 1)) 
			}
			sel := rng.text, rng.moveEnd("character", StrLen(RTrim(sel)) - StrLen(sel)), rng.select()   
		}
		Else If (ThisMode != "Hotkey" && (oevent.className = "title" || oevent.className = "con" || oevent.className = "hr" || oevent.className = "box"))  ;;	anchor
		{
			R := oDoc.selection.createRange(), R.collapse(1), R.select()
			
			If oevent.className = "con"
				_text := oevent.firstChild.id, EL := oevent.parentElement.firstChild
			Else If oevent.className = "hr"
				_text := oevent.parentElement.childNodes[1].firstChild.id, EL := oevent
			Else If oevent.className = "box"
				_text := oevent.firstChild.childNodes[1].firstChild.id, EL := oevent.firstChild.firstChild
			Else If oevent.className = "title"
				_text := oevent.id, EL := oevent.parentElement.parentElement.firstChild
				
			If (_text = "P__Tree_Acc_Path" || _text = "")
				Return
				
			If oOther.anchor[ThisMode]
			{
				pEL := GetAnchor().parentElement.parentElement.firstChild
				pEL.style.background := "'none'"
				pEL.Id := ""
				
				If (_text = oOther.anchor[ThisMode "_text"])
				{
					If AnchorFullScroll 
						oJScript.QS(oDivNew, "#id_T0").style.height := 0
					If MemoryAnchor
						IniWrite("", ThisMode "_Anchor")
					Return oOther.anchor[ThisMode] := 0, oOther.anchor[ThisMode "_text"] := "" 
				}
			}
			
			oOther.anchor[ThisMode] := 1
			oOther.anchor[ThisMode "_text"] := _text
			EL.Id := "anchor"
			EL.style.backgroundColor := "#" ColorSelAnchor
			
			_AnchorFitScroll(EL)
			
			oDivNew.scrollTop := oDivNew.scrollTop + EL.getBoundingClientRect().top - 6
			
			If MemoryAnchor
				IniWrite(oOther.anchor[ThisMode "_text"], ThisMode "_Anchor") 
		}
	}
	onfocusin() { 
		If !(oDoc.parentWindow.event.srcElement.id = "editkeyname" || oDoc.parentWindow.event.srcElement.id = "edithotkey") 
			Return 
		oDoc.parentWindow.event.srcElement.style.border := "1px solid #" ColorBorderHoverInput
		Sleep(1), Hotkey_Hook(0) 
	} 
	onfocusout() {
		If !(oDoc.parentWindow.event.srcElement.id = "editkeyname" || oDoc.parentWindow.event.srcElement.id = "edithotkey") 
			Return
		oDoc.parentWindow.event.srcElement.style.border := "1px dotted"
		oDoc.parentWindow.event.srcElement.style.borderColor :=  "#" ColorFont
		
		If (WinActive("ahk_id" hGui) && !isPaused && ThisMode = "Hotkey")
			Sleep(1), Hotkey_Hook(1)
	}
	onmouseup() {   
		if (oDoc.parentWindow.event.srcElement.className != "button")
			return
		oJScript.onmouseup(oDoc.parentWindow.event.srcElement, 0)
    }
	onmousedown() {   
		if oDoc.parentWindow.event.button != 1		;   only left button https://msdn.microsoft.com/en-us/library/aa703876(v=vs.85).aspx
			return
		if (oDoc.parentWindow.event.srcElement.className != "button")
			return 
		oJScript.onmousedown(oDoc.parentWindow.event.srcElement)
    }
    onmouseover() {   
		if (oDoc.parentWindow.event.srcElement.className = "button")
			return oJScript.onmouseover(oDoc.parentWindow.event.srcElement) 
		If oMS.Selection
			Return
		oMS.EL := oDoc.parentWindow.event.srcElement
		SetTimer, MS_MouseOver, -50
    }
	onmouseout() {
		if (oDoc.parentWindow.event.srcElement.className = "button")
			return oJScript.onmouseout(oDoc.parentWindow.event.srcElement) 
		MS_Cancel()
    }
	onselectionchange() { 
		e := oDoc.parentWindow.event
		oMS.SCX := e.clientX, oMS.SCY := e.clientY
		SetTimer, MS_SelectionCheck, -70
		SetTimer, BodyExistCheck, -1000
    }
	onselectstart() {
		SetTimer, MS_Cancel, -8
    } 
	
	SendMode() {
		IniWrite(SendMode := {Send:"SendInput",SendInput:"SendPlay",SendPlay:"SendEvent",SendEvent:"Send"}[SendMode], "SendMode")
		SendModeStr := Format("{:L}", SendMode), oDoc.getElementById("SendMode").innerText := " " SendModeStr " "
	}
	SendCode() {
		IniWrite(SendCode := {vk:"sc",sc:"name",name:"vk"}[SendCode], "SendCode")
		oDoc.getElementById("SendCode").innerText := " " SendCode " "
	}
	LButton_Hotkey() {
		If Hotkey_Arr("Hook")
			Hotkey_Main("LButton")
	}
	num_scroll(thisid) {
		(OnHook := Hotkey_Arr("Hook")) ? Hotkey_Hook(0) : 0
		SendInput, {%thisid%}
		(OnHook ? Hotkey_Hook(1) : 0)
		ToolTip(thisid " " (GetKeyState(thisid, "T") ? "On" : "Off"), 500)
	}
	NextChangeLocal() {
		(OnHook := Hotkey_Arr("Hook")) ? Hotkey_Hook(0) : 0
		ChangeLocal(hActiveX)
		ToolTip(GetLangName(hActiveX), 500)
		(OnHook ? Hotkey_Hook(1) : 0)
	}
	clean_command_line() { 
		cl := oDoc.getElementById("c_command_line").OuterText
		StringReplace, cl, cl, ", , 1 
		process := oDoc.getElementById("copy_processpath").OuterText
		cl := RegExReplace(cl, "i)\Q" process "\E(.*)", "$1", , 1)
		StringReplace, cl, cl, /CP65001, , 1  
		cl := Trim(cl, " ")
		oDoc.getElementById("c_command_line").innerText :=  RegExReplace(cl, "i)\Q" process "\E(.*)", "$1", , 1)
	}
}

ButtonClick(oevent) { 
	thisid := oevent.id
	If (thisid = "copy_wintext")
		o := oDoc.getElementById("wintextcon")
		, GetKeyState("Shift") ? ClipAdd(o.OuterText, 1) : (Clipboard := o.OuterText), HighLight([o])
	Else If (thisid = "wintext_hidden")
	{
		R := oBody.createTextRange(), R.collapse(1), R.select()
		oDoc.getElementById("wintextcon").disabled := 1
		DetectHiddenText, % DetectHiddenText := (DetectHiddenText = "on" ? "off" : "on")
		IniWrite(DetectHiddenText, "DetectHiddenText")
		If !WinExist("ahk_id" oOther.WinID) && ToolTip("Window not exist", 500)
			Return oDoc.getElementById("wintext_hidden").innerText := " hidden - " DetectHiddenText " "
		WinGetText, WinText, % "ahk_id" oOther.WinID
		oDoc.getElementById("wintextcon").innerHTML := "<pre>" TransformHTML(WinText) "</pre>"
		HTML_Win := oDivNew.innerHTML
		Sleep 200
		oDoc.getElementById("wintextcon").disabled := 0
		oDoc.getElementById("wintext_hidden").innerText := " hidden - " DetectHiddenText " "
	}
	Else If (thisid = "menu_idview")
	{
		IniWrite(MenuIdView := !MenuIdView, "MenuIdView")
		oJScript.menuitemdisplay(!MenuIdView ? "none" : "inline")
		oDoc.getElementById("menu_idview").innerText :=  " id - " (MenuIdView ? "view" : "hide") " "
	}
	Else If (thisid = "copy_menutext")
	{
		pre_menutext := oDoc.getElementById("pre_menutext")
		preclone := pre_menutext.cloneNode(true)
		oJScript.removemenuitem(preclone, ".menuitemsub")
		If !MenuIdView
			oJScript.removemenuitem(preclone, ".menuitemid")
		GetKeyState("Shift") ? ClipAdd(preclone.OuterText, 1) : (Clipboard := preclone.OuterText)
		HighLight([pre_menutext]), preclone := ""
	}
	Else If (thisid = "copy_button")
	{
		o := oDoc.all.item(oevent.sourceIndex + 2) 
		GetKeyState("Shift") ? ClipAdd(o.OuterText, 1) : (Clipboard := o.OuterText), HighLight([o])
	}
	Else If (thisid = "copy_button_CtrlText")
	{
		o := oDoc.all.item(oevent.sourceIndex + 6) 
		GetKeyState("Shift") ? ClipAdd(o.OuterText, 1) : (Clipboard := o.OuterText), HighLight([o])
	} 
	Else If (thisid = "settext_button")
		ControlSetText, , % oDoc.getElementById("content_Control_Text").OuterText, % "ahk_id" oevent.value 
	Else If thisid = copy_alltitle
	{
		HighLight([oDoc.getElementById("wintitle1")
			, oDoc.getElementById("wintitle2")
			, oDoc.getElementById("wintitle3")]) 
		
		Text := (t:=oDoc.getElementById("wintitle1").OuterText) . (t = "" ? "" : " ")
		. oDoc.getElementById("wintitle2").OuterText " " oDoc.getElementById("wintitle3").OuterText
		GetKeyState("Shift") ? ClipAdd(Text, 1) : (Clipboard := Text)
	}
	Else If thisid = copy_sbtext
	{
		elements := []
		Loop % oDoc.getElementById("copy_sbtext").name
			el := oDoc.getElementById("sb_field_" A_Index), elements.Push(el), Text .= el.OuterText "`r`n"
		HighLight(elements)
		Text := RTrim(Text, "`r`n"), GetKeyState("Shift") ? ClipAdd(Text, 1) : (Clipboard := Text)
	}
	Else If thisid = keyname
	{ 
		edithotkey := oDoc.getElementById("edithotkey"), editkeyname := oDoc.getElementById("editkeyname")
		value := edithotkey.value 
		
		If (value = "    " || value = A_Tab)
			value := A_Tab
		Else If (value != " ")
			value := RegExReplace(value, "^\s*(.*?)\s*$", "$1")
			
		If RegExMatch(value, "i)^0x([0-9a-f]+)$", M)
			key := (StrLen(M1) > 2 ? "sc" : "vk") . Format("{:U}", M1)
		Else
			key := value 
		oDoc.getElementById("edithotkey").value := key 
		
		name := GetKeyName(key)
		If (name = key)
			editkeyname.value := Format("vk{:X}", GetKeyVK(key)) (!(sc := GetKeySC(key)) ? "" : Format("sc{:X}", sc))
		Else
			editkeyname.value := (StrLen(name) = 1 ? (Format("{:U}", name)) : name)
			
		o := name = "" ? edithotkey : editkeyname
		o.focus(), o.createTextRange().select()
		oDoc.getElementById("vkname").innerHTML := GetVKCodeNameStr := GetVKCodeName(key)
		oDoc.getElementById("scname").innerHTML := GetSCCodeNameStr := GetScanCode(key)
		HTML_Hotkey := oDivNew.innerHTML 
	}
	Else If thisid = hook_reload
	{
		Suspend On
		Suspend Off
		bool := Hotkey_Arr("Hook"), Hotkey_SetHook(0), Hotkey_SetHook(1), Hotkey_Arr("Hook", bool), ToolTip("Ok", 300)
	}
	Else If thisid = hotkey_clip_cursor
		Hotkey_ClipCursor()
	Else If thisid = pause_button
		Gosub, PausedScript
	Else If (thisid = "infolder" || thisid = "command_line_infolder")
	{	
		If (thisid = "command_line_infolder")
			FilePath := oDoc.getElementById("c_command_line").OuterText
		Else 
			FilePath := oDoc.getElementById("copy_processpath").OuterText

		SelectFilePath(FilePath) ? Minimize() : ToolTip("File not exist", 500)		 
	}
	Else If (thisid = "flash_window" || thisid = "flash_control" || thisid = "flash_ctrl_window")
	{
		hwnd := thisid = "flash_window" ? oOther.WinID : thisid = "flash_ctrl_window" ? oOther.MouseWinID : oOther.ControlID

		If !WinExist("ahk_id" hwnd)
			Return ToolTip("Window not exist", 500)
		WinGetPos, WinX, WinY, WinWidth, WinHeight, % "ahk_id" hwnd
		FlashArea(WinX, WinY, WinWidth, WinHeight)
	}
	Else If (thisid = "flash_acc")
	{
		If oPubObj.Acc.CLOAKED
			Return 0, ToolTip("CLOAKED", 500)
		Acc := Object(oPubObj.Acc.AccObj)
		AccGetLocation(Acc, oPubObj.Acc.child)
		FlashArea(AccCoord[1], AccCoord[2], AccCoord[3], AccCoord[4])
	}
	Else If (thisid = "flash_IE")
	{
		If !WinExist("ahk_id" oPubObj.IEElement.hwnd)
			Return ToolTip("Parent window not exist", 500)
		FlashArea(oPubObj.IEElement.Pos[1], oPubObj.IEElement.Pos[2], oPubObj.IEElement.Pos[3], oPubObj.IEElement.Pos[4])
	}
	Else If thisid = paste_process_path
		oDoc.getElementById("copy_processpath").innerHTML := TransformHTML(Trim(Trim(Clipboard), """"))
	Else If thisid = w_command_line
		RunRealPath(oDoc.getElementById("c_command_line").OuterText)
	Else If thisid = clean_command_line
		Events.clean_command_line()
	Else If thisid = paste_command_line
		oDoc.getElementById("c_command_line").innerHTML := TransformHTML(Clipboard)
	Else If thisid = paste_Control_Text
		oDoc.getElementById("content_Control_Text").innerText := Clipboard
	Else If (thisid = "process_close" && (oOther.WinPID || !ToolTip("Invalid parametrs", 500)) && ConfirmAction("Process close?"))
		Process, Close, % oOther.WinPID
	Else If (thisid = "win_close" && (oOther.WinPID || !ToolTip("Invalid parametrs", 500)) && ConfirmAction("Window close?"))
		WinClose, % "ahk_id" oOther.WinID
	Else If (thisid = "control_destroy" && (WinExist("ahk_id" oOther.ControlID) || !ToolTip("window not exist", 500)) && ConfirmAction("Window close?"))
			WinClose, % "ahk_id" oOther.ControlID     ;; DllCall("DestroyWindow", "Ptr", oOther.ControlID)   ;;  не работает
	Else If (thisid = "control_show_hide" || thisid = "window_show_hide")
	{
		Hwnd := thisid = "window_show_hide" ? oOther.WinID : oOther.ControlID
		If !WinExist("ahk_id" Hwnd)  
			Return ToolTip("window not exist", 500)
		If b := DllCall("IsWindowVisible", "Ptr", Hwnd) 
			WinHide, % "ahk_id" Hwnd
		Else 
			WinShow, % "ahk_id" Hwnd
		ToolTip(b ? "Hide" : "Show" , 500)
	}
	Else If (thisid = "SendCode")
		Events.SendCode()
	Else If (thisid = "SendMode")
		Events.SendMode()
	Else If (thisid = "LButton_Hotkey")
		Events.LButton_Hotkey()
	Else If (thisid = "numlock" || thisid = "scrolllock")
		Events.num_scroll(thisid)
	Else If thisid = locale_change
		Events.NextChangeLocal()
	Else If thisid = paste_keyname
		edithotkey := oDoc.getElementById("edithotkey"), edithotkey.value := "", edithotkey.focus()
		, oDoc.execCommand("Paste"), oDoc.getElementById("keyname").click()
	Else If thisid = get_styles_w
		ViewStylesWin()
	Else If thisid = update_styles_w
		ViewStylesWin(1) 
	Else If thisid = get_styles_c
		ViewStylesControl()
	Else If thisid = update_styles_c
		ViewStylesControl(1) 
	Else If thisid = run_AccViewer
		RunAhkPath(ExtraFile("AccViewer Source"), oPubObjGUID)
	Else If thisid = run_iWB2Learner
		RunAhkPath(ExtraFile("iWB2 Learner"))
	Else If (thisid = "run_Window_Detective" && ConfirmAction("Run Window Detective?"))
	{
		Minimize()
		If WinExist("Window Detective ahk_class Qt5QWindowIcon ahk_exe Window Detective.exe")
			WinActivate
		Else
			Run % Path_User "\Window Detective.lnk"
		TimerFunc(Func("MyWindowDetectiveStart").Bind(ThisMode = "Win" ? oOther.WinID : oOther.ControlID, WinExist() ? 1 : 0), -300)
	}
	Else If (thisid = "set_button_Transparent" && ToolTip((v := oDoc.getElementById("get_win_Transparent").innerText + 0), 500)) 
		WinSet, Transparent, % v, % "ahk_id" oOther.WinID
	Else If thisid = set_button_TransColor
		WinSet, TransColor, % oDoc.getElementById("get_win_TransColor").innerText, % "ahk_id" oOther.WinID
	Else If thisid = set_button_pos
	{
		HayStack := oevent.OuterText = "Pos:"
		? oDoc.all.item(oevent.sourceIndex + 1).OuterText " " oDoc.all.item(oevent.sourceIndex + 7).OuterText
		: oDoc.all.item(oevent.sourceIndex - 5).OuterText " " oDoc.all.item(oevent.sourceIndex + 1).OuterText
		RegExMatch(HayStack, "(-*\d+[\.\d+]*).*\s+.*?(-*\d+[\.\d+]*).*\s+.*?(-*\d+[\.\d+]*).*\s+.*?(-*\d+[\.\d+]*)", p)
		If (p1 + 0 = "" || p2 + 0 = "" || p3 + 0 = "" || p4 + 0 = "")
			Return ToolTip("Invalid parametrs", 500)
		If (ThisMode = "Win")
			WinMove, % "ahk_id " oOther.WinID, , p1, p2, p3, p4
		Else
			ControlMove, , p1, p2, p3, p4, % "ahk_id " oOther.ControlID
	}
	Else If thisid = control_click
	{
		ControlClick, % oDoc.getElementById("coord_win").innerText, % "ahk_id" oOther.MouseWinID, , , , Pos
	}
	Else If thisid = set_button_focus_ctrl
	{ 
		WinActivate, % "ahk_id " oOther.WinID
		hWnd := oOther.ControlID 
		ControlFocus, , ahk_id %hWnd%
		WinGetPos, X, Y, W, H, ahk_id %hWnd%
		FlashArea(x, y, w, h)
		If GetKeyState("Shift") && (X + Y != "") 
			MouseMoveScreen(X + W // 2, Y + H // 2)
	}
	Else If thisid = set_pos
	{ 
		thisbutton := oevent.OuterText
		If thisbutton != Screen:
		{
			hWnd := oOther.MouseWinID
			If !WinExist("ahk_id " hwnd)
				Return ToolTip("Window not exist", 500)
			WinGet, Min, MinMax, % "ahk_id " hwnd
			If Min = -1
				Return ToolTip("Window minimize", 500)
			WinGetPos, X, Y, W, H, ahk_id %hWnd%
		}
		If thisbutton = Relative window:
		{
			RegExMatch(oDoc.all.item(oevent.sourceIndex + 1).OuterText, "(-*\d+[\.\d+]*).*\s+.*?(-*\d+[\.\d+]*)", p)
			If (p1 + 0 = "" || p2 + 0 = "")
				Return ToolTip("Invalid parametrs", 500)
			BlockInput, MouseMove  
			MouseMoveScreen(X + Round(W * p1), Y + Round(H * p2))
		}
		Else If thisbutton = Relative client:
		{
			RegExMatch(oDoc.all.item(oevent.sourceIndex + 1).OuterText, "(-*\d+[\.\d+]*).*\s+.*?(-*\d+[\.\d+]*)", p)
			If (p1 + 0 = "" || p2 + 0 = "")
				Return ToolTip("Invalid parametrs", 500)
			GetClientPos(hWnd, caX, caY, caW, caH) 
			MouseMoveScreen(X + Round(caW * p1) + caX, Y + Round(caH * p2) + caY)
		}
		Else
		{
			RegExMatch(oDoc.all.item(oevent.sourceIndex + 1).OuterText, "(-*\d+[\.\d+]*).*\s+.*?(-*\d+[\.\d+]*)", p)
			If (p1 + 0 = "" || p2 + 0 = "")
				Return ToolTip("Invalid parametrs", 500)
			BlockInput, MouseMove
			If thisbutton = Screen:  
				MouseMoveScreen(p1, p2)
			Else If thisbutton = Window:  
				MouseMoveScreen(X + p1, Y + p2)
			Else If thisbutton = Mouse relative control:
			{
				hWnd := oOther.ControlID
				If !WinExist("ahk_id " hwnd)
					Return ToolTip("Control not exist", 500)
				WinGetPos, X, Y, W, H, ahk_id %hWnd%  
				MouseMoveScreen(X + p1, Y + p2)
			}
			Else If thisbutton = Client:
			{
				GetClientPos(hWnd, caX, caY, caW, caH)  
				MouseMoveScreen(X + p1 + caX, Y + p2 + caY) 
			}
		}
		If isPaused
		{
			BlockInput, MouseMoveOff
			Return
		}
		If Shift := GetKeyState("Shift")
			ActivateUnderMouse() 
		GoSub, SpotProc2
		BlockInput, MouseMoveOff
		If !Shift
			Sleep(500), HideAllMarkers(), CheckHideMarker()
	} 
	Else If thisid = b_DecimalCode
	{
		oDoc.getElementById("b_DecimalCode").innerText := (DecimalCode := !DecimalCode) ? " dec " : " hex "
		str := oDoc.getElementById("v_SCDHCode").innerText
		oDoc.getElementById("v_SCDHCode").innerText := (DecimalCode) ? Format("{:d}", str) : Format("0x{:X}", str)
		str := oDoc.getElementById("v_VKDHCode").innerText
		oDoc.getElementById("v_VKDHCode").innerText := (DecimalCode) ? Format("{:d}", str) : Format("0x{:X}", str)
	}
	Else If (thisid = "acc_DoDefaultAction" || thisid = "acc_DoDefaultAction2")
		accDoDefaultAction()  
	Else If thisid = b_hwnd_flash
	{ 
		WinGetPos, X, Y, W, H, % "ahk_id" oevent.value
		FlashArea(x, y, w, h)
	}
	Else If thisid = acc_path 
		acc_path_func(1)
	Else If thisid = control_path 
		control_path_func()
	Else If thisid = b_CASend
	{  
		h := (oOther.ControlID ? oOther.ControlID : oOther.MouseWinID)
		If !WinExist("ahk_id " h)
			Return ToolTip("Window not found!", 500)
		ControlSend, , % oOther.ControlSend, ahk_id %h%
		ToolTip("send to " . (oOther.ControlID ? "control: " oOther.CtrlClass : "window: " oOther.MouseWinClass), 700)
	} 
	Else If InStr(thisid, "ahkscript_")
	{
		ToolTip("Ok", 300)
		ahkscriptpath := oDoc.getElementById("ahkscriptpath").innerText 
		If !FileExist(ahkscriptpath)
			Return ToolTip("File not exist!", 500)
		If (thisid = "ahkscript_folder")
			SelectFilePath(ahkscriptpath) ? Minimize() : ToolTip("Invalide path", 500)
		Else If (thisid = "ahkscript_copypath")
			FileToClipboard(ahkscriptpath) 
		Else If (thisid = "ahkscript_run")
			RunRealPath(ahkscriptpath) 
		Else If (thisid = "ahkscript_edit")
			RunRealPath("*Edit " ahkscriptpath)
		Else 
		{ 
			If !WinExist("ahk_class AutoHotkey ahk_pid" . oOther.WinPID)	  
				Return ToolTip("Script not found!", 500)
			If (thisid = "ahkscript_suspend")
				ExecCommandAutoHotkey("Suspend Hotkeys", oOther.WinPID)
			Else If (thisid = "ahkscript_pause")
				ExecCommandAutoHotkey("Pause Script", oOther.WinPID)
			Else If (thisid = "ahkscript_reload")
				ExecCommandAutoHotkey("Reload Script", oOther.WinPID)
			Else If (thisid = "ahkscript_exit")
				ExecCommandAutoHotkey("Exit Script", oOther.WinPID)
			Else If (thisid = "ahkscript_lines")
				ExecCommandAutoHotkey("Recent Lines", oOther.WinPID)
			Else If (thisid = "ahkscript_variables")
				ExecCommandAutoHotkey("Variables", oOther.WinPID)
			Else If (thisid = "ahkscript_hotkeys")
				ExecCommandAutoHotkey("Hotkeys", oOther.WinPID)
			Else If (thisid = "ahkscript_keyhistory")
				ExecCommandAutoHotkey("Key history", oOther.WinPID)
			Else If (thisid = "ahkscript_edit")
				ExecCommandAutoHotkey("Edit Script", oOther.WinPID) 
		}
	}  
}

control_path_func() {
	If !ChildToPath(oOther.ControlID)
		oDoc.getElementById("control_path_error").outerHTML := "<span style='color:#" ColorErrorAccPath "'>  control not found</span>" 
	oDoc.getElementById("control_path_value").innerHTML := SaveChildPath()
	HTML_Control := oDivNew.innerHTML
}

acc_path_func(manual) {
	;; If (manual && oOther.anchor[ThisMode "_text"] = "P__Tree_Acc_Path")
		;; MsgBox %  oDoc.getElementById("P__Tree_Acc_Path").innerHTML
	If !Malcev_AccPathNotBlink && manual
	{
		oDoc.getElementById("acc_path").disabled := 1
		, oDoc.getElementById("acc_path_value").disabled := 1 
		w := oDoc.getElementById("acc_path").offsetWidth
		marquee = 
		( 
			<marquee behavior='scroll' direction='right' bgcolor='#" ColorErrorAccMarquee "' width="%w%px"> • • • 
			</marquee>
		)
		oDoc.getElementById("acc_path").innerHTML := marquee   
	}
	b := GetAccPath() 
	If !manual
		Return b
	If b
	{ 
		oDoc.getElementById("acc_path_error").innerHTML := ""
		oDoc.getElementById("acc_path_value").innerHTML := SaveAccPath() 
	}
	If !b
	{
		oDoc.getElementById("acc_path_error").innerHTML := "<span style='color:#" ColorErrorAccPath "'>  "
			. (oPubObj.Acc.CLOAKED ? "CLOAKED" : (b = 0 ? "path not found" : "path not correct"))  "  </span>" 
		oDoc.getElementById("acc_path_value").innerHTML := ""
	}
	Else 
		oDoc.getElementById("acc_path_value").disabled := 0
	
	oDoc.getElementById("acc_path").innerHTML := ""
	oDoc.getElementById("acc_path").innerText := " Get path "
	oDoc.getElementById("acc_path").disabled := 0
	HTML_Control := oDivNew.innerHTML
}

	; ___________________________ SingleInstance _________________________________________________

SingleInstance(Icon = 0) {
	#NoTrayIcon
	#SingleInstance Off
	DetectHiddenWindows, On
	WinGetTitle, MyTitle, ahk_id %A_ScriptHWND%
	WinGet, id, List, %MyTitle% ahk_class AutoHotkey
	Loop, %id%
	{
		this_id := id%A_Index%
		If (this_id != A_ScriptHWND)
			WinClose, ahk_id %this_id%
	}
	Loop, %id%
	{
		this_id := id%A_Index%
		If (this_id != A_ScriptHWND)
		{
			Start := A_TickCount
			While WinExist("ahk_id" this_id)
			{
				If (A_TickCount - Start > 1500)
				{
					MsgBox, 8196, , Could not close the previous instance of this script.  Keep waiting?
					IfMsgBox, Yes
					{
						WinClose, ahk_id %this_id%
						Sleep 200
						WinGet, WinPID, PID, ahk_id %this_id%
						Process, Close, %WinPID%
						Start := A_TickCount + 200
						Continue
					}
					OnExit
					ExitApp
				}
				Sleep 1
			}
		}
	}
	If Icon
		Menu, Tray, Icon
}

	; __________________________________________________________________________________
	; ___________________________ Zoom _________________________________________________
	; __________________________________________________________________________________

ShowZoom:
hAhkSpy = %2%
If !WinExist("ahk_id" hAhkSpy)
	ExitApp
ActiveNoPause = %3%
AhkSpyPause = %4%
Suspend = %5%
Hotkey = %6%
OnlyShiftTab = %7%
GUID = %8%
HeigtButton = %9%

ListLines Off
SetBatchLines,-1
DetectHiddenWindows On
CoordMode, Mouse, Screen
CoordMode, ToolTip, Screen

Global ObjActive := ComObjActive(GUID), oZoom := {}, isZoom := 1, hAhkSpy, oMenu := {}, oOther := {}
, MsgAhkSpyZoom, ActiveNoPause, SpyActive, GuiColor, TextColor, GuiColorDisp, HeigtButton
If IniRead("DarkTheme", 0)
	GuiColor := "0A0A0A", TextColor := "F5F5F5", GuiColorDisp := "263FA4"
Else 
	GuiColor := "F5F5F5", TextColor := "0A0A0A", GuiColorDisp := "FFE891"
If !oZoom.pToken := GdipStartup()
{
	MsgBox, 4112, Gdiplus Error, Gdiplus failed to start. Please ensure you have Gdiplus on your system.
	ExitApp
}
Z_MsgZoom(8, Suspend)
Z_MsgZoom(2, AhkSpyPause)
Z_MsgZoom(6, ActiveNoPause)
Z_MsgZoom(7, !!WinActive("ahk_id" hAhkSpy))
Z_MsgZoom(10, Hotkey)
Z_MsgZoom(12, OnlyShiftTab)

oZoom.CurrentProcessId := DllCall("GetCurrentProcessId")
OnMessage(MsgAhkSpyZoom := DllCall("RegisterWindowMessage", "Str", "MsgAhkSpyZoom"), "Z_MsgZoom")
OnMessage(0x0020, "WM_SETCURSOR")
OnExit("ZoomOnClose")
OnMessage(0x201, "LBUTTONDOWN") ;; WM_LBUTTONDOWN
OnMessage(0x204, "RBUTTONDOWN") ;; WM_RBUTTONDOWN
OnMessage(0xA1, "LBUTTONDOWN") ;; WM_NCLBUTTONDOWN
 
SetWinEventHook("EVENT_OBJECT_DESTROY", 0x8001)
SetWinEventHook("EVENT_SYSTEM_MINIMIZESTART", 0x0016)
SetWinEventHook("EVENT_SYSTEM_MINIMIZEEND", 0x0017)
SetWinEventHook("EVENT_SYSTEM_MOVESIZESTART", 0x000A)
SetWinEventHook("EVENT_SYSTEM_MOVESIZEEND", 0x000B)			

ObjActive.Magnify := Func("Magnify")
ObjActive.Redraw := Func("Redraw") 

ZoomCreate()  
Send_AhkSpy(0, oZoom.hGui)  
Send_AhkSpy(3, oZoom.hLW) 

WinGet, Min, MinMax, % "ahk_id " hAhkSpy
If Min != -1
	ZoomShow()

MenuAdd("Zoom", "Save to temp file and edit", "_gSave_to_file")
MenuAdd("Zoom", "Save to clipboard", "_gSave_to_Clipboard")
MenuAdd("Zoom", "Save to clipboard as Base64", "_gSave_as_Base64") 
MenuAdd("Zoom")
MenuAdd("Zoom", "Save to file", "_gSave_to_file")
MenuAdd("Zoom", "Save to file and edit", "_gSave_to_file") 
MenuAdd("Zoom", "Select window", "_gMenuZoom", "+BarBreak")
MenuAdd("Zoom", "Select control", "_gMenuZoom")
MenuAdd("Zoom", "Select accesible", "_gMenuZoom")
MenuAdd("Zoom")
MenuAdd("Zoom", "Select AhkSpy", "_gMenuZoom") 
Return 

#If isZoom && oZoom.Show && UnderRender()
Up::MoveStep(0, -1)
Down::MoveStep(0, 1)
Left::MoveStep(-1, 0)
Right::MoveStep(1, 0)
+Up::MoveStep(0, -10)
+Down::MoveStep(0, 10)
+Left::MoveStep(-10, 0)
+Right::MoveStep(10, 0)

#If isZoom && oZoom.Show && oZoom.Crop && UnderRender()
Home::
MButton:: CoupCrop()
+Home::
+MButton:: CircleCoupCrop()
#If isZoom && oZoom.Show && UnderRender()
End::CropToggle()
PgUp::
PgDn::
WheelUp::
WheelDown:: ChangeZoom(FastZoom(InStr(A_ThisHotKey, "Up")))

Tab::
F1::
F11:: ZoomMaximize()

F12:: 
AppsKey::ZoomMenu()

#If isZoom && oZoom.Show && GetMinMax(oZoom.hGui) = 1
Esc:: ZoomMaximize() 
#If

; 1::Gui, Zoom: +Caption  -E%WS_EX_NOACTIVATE%   

; 2::Gui, Zoom: -Caption +E%WS_EX_NOACTIVATE%

ZoomCreate() { 
	oZoom.Zoom := IniRead("MagnifyZoom", 4)
	oZoom.Mark := IniRead("MagnifyMark", "Cross")
	oZoom.MemoryZoomSize := IniRead("MemoryZoomSize", 0)
	oZoom.GuiMinW := 380
	oZoom.GuiMinH := 351
	FontSize := {96:12,120:10,144:8,168:6}[A_ScreenDPI]
	If oZoom.MemoryZoomSize
		GuiW := IniRead("MemoryZoomSizeW", oZoom.GuiMinW), GuiH := IniRead("MemoryZoomSizeH", oZoom.GuiMinH)
	Else
		GuiW := oZoom.GuiMinW, GuiH := oZoom.GuiMinH
	Gui, Zoom: -Caption -DPIScale +Border +LabelZoomOn +HWNDhGuiZoom +AlwaysOnTop +E%WS_EX_NOACTIVATE%    ;;	+Owner%hAhkSpy%
	Gui, Zoom: Color, %GuiColor%
	Gui, Zoom: Add, Text, hwndhStatic +Border
	; DllCall("SetClassLong", "Ptr", hGuiZoom, "int", -26
	; , "int", DllCall("GetClassLong", "Ptr", hGuiZoom, "int", -26) | 0x20000)

	Gui, LW: -Caption +E%WS_EX_LAYERED% +AlwaysOnTop +ToolWindow +HWNDhLW +E%WS_EX_NOACTIVATE% +Owner%hGuiZoom% ;;	++E%WS_EX_NOACTIVATE% +E%WS_EX_TRANSPARENT%

	Gui, ZoomTB: +HWNDhTBGui -Caption -DPIScale +Parent%hGuiZoom% +E%WS_EX_NOACTIVATE% +%WS_CHILDWINDOW% -%WS_POPUP%
	Gui, ZoomTB: Color, %GuiColor%
	h := 32
	Gui, ZoomTB: Add, Slider, % "hwndhSliderZoom gSliderZoom x8 Range1-50 w152 y" (44-h)/2 " h" h " Center AltSubmit NoTicks", % oZoom.Zoom
	Gui, ZoomTB: Font, % "s" FontSize + 2
	Gui, ZoomTB: Add, Text, hwndhTextZoom +0x201 x+10 yp w36 hp c%TextColor%, % oZoom.Zoom
	Gui, ZoomTB: Font, % "s" FontSize + 4
	Gui, ZoomTB: Add, Button, hwndhZoomHideBut gZoomHide x+10 ys h%h% w22, % Chr(0x00D7)
	Gui, ZoomTB: Font, % "s" FontSize - 2
	Gui, ZoomTB: Add, Button, hwndhChangeMark gChangeMark x+10 yp hp w62, % oZoom.Mark
	Gui, ZoomTB: Add, Text, % "hwndhCropWidth hidden Border Section c" TextColor " xp yp wp h" h / 2
	Gui, ZoomTB: Add, Text, % "hwndhCropHeight hidden Border c" TextColor " xs y+0 wp hp"
	Gui, ZoomTB: Font, % "s" FontSize + 4
	Gui, ZoomTB: Add, Button, gZoomMenu hwndhZoomMenu x+10 ys h%h% w22, % Chr(0x2261)
	Gui, ZoomTB: Add, Button, gZoomMaximize x+10 yp hp wp, % Chr(0x1F791) 
	Gui, ZoomTB: Show, NA x0 y0
	Gui, Zoom: Show, % "NA Hide w" GuiW " h" GuiH, AhkSpyZoom
	Gui, Zoom: +MinSize
	
	WinSet, TransParent, 255, ahk_id %hGuiZoom%
	
	oZoom.hdcSrc := DllCall("GetDC", "UPtr", 0, "UPtr")
	oZoom.hDCBuf := CreateCompatibleDC()
	oZoom.hdcMemory := CreateCompatibleDC()

	oZoom.hGui := hGuiZoom
	oZoom.hStatic := hStatic
	oZoom.hTBGui := hTBGui
	oZoom.hLW := hLW

	oZoom.vTextZoom := hTextZoom
	oZoom.vChangeMark := hChangeMark
	oZoom.vCropWidth := hCropWidth
	oZoom.vCropHeight := hCropHeight 
	
	oZoom.vZoomHideBut := hZoomHideBut
	oZoom.vSliderZoom := hSliderZoom
	oZoom.vZoomMenu := hZoomMenu
}

SetSize() {
	Static Top := 45, Left := 0, Right := 6, Bottom := 6

	Width := oZoom.LWWidth := oZoom.GuiWidth - Left - Right
	Height := oZoom.LWHeight := oZoom.GuiHeight - Top - Bottom

	Zoom := oZoom.Zoom
	conW := Mod(Width, Zoom) ? Width - Mod(Width, Zoom) + Zoom : Width
	conW := Mod(conW // Zoom, 2) ? conW : conW + Zoom

	conH := Mod(Height, Zoom) ? Height - Mod(Height, Zoom) + Zoom : Height
	conH := Mod(conH // Zoom, 2) ? conH : conH + Zoom

	oZoom.conX := (((conW - Width) // 2)) * -1
	oZoom.conY :=  (((conH - Height) // 2)) * -1
	
	hDWP := DllCall("BeginDeferWindowPos", "Int", 2)
	hDWP := DllCall("DeferWindowPos"
	, "Ptr", hDWP, "Ptr", oZoom.hStatic, "UInt", 0
	, "Int", Left - 1, "Int", Top - 1, "Int", Width + 2, "Int", Height + 2
	, "UInt", 0x0010)    ;; 0x0010 := SWP_NOACTIVATE
	hDWP := DllCall("DeferWindowPos"
	, "Ptr", hDWP, "Ptr", oZoom.hTBGui, "UInt", 0
	, "Int", (oZoom.GuiWidth - oZoom.GuiMinW) / 2
	, "Int", 0, "Int", 0, "Int", 0
	, "UInt", 0x0011)    ;; 0x0010 := SWP_NOACTIVATE | 0x0001 := SWP_NOSIZE
	DllCall("EndDeferWindowPos", "Ptr", hDWP)

	oZoom.nWidthSrc := conW // Zoom
	oZoom.nHeightSrc := conH // Zoom
	oZoom.nXOriginSrcOffset := oZoom.nWidthSrc//2
	oZoom.nYOriginSrcOffset := oZoom.nHeightSrc//2
	oZoom.nWidthDest := conW
	oZoom.nHeightDest := conH
	oZoom.xCenter := Round(Width / 2 - Zoom / 2)
	oZoom.yCenter := Round(Height / 2 - Zoom / 2)

	ChangeMarker()

	If oZoom.MemoryZoomSize
		SetTimer, ZoomCheckSize, -100
}

ChangeMarker() {
	Try GoTo % "Marker" oZoom.Mark

	MarkerCross:
		oZoom.oMarkers["Cross"] := [{x:0,y:oZoom.yCenter - 1,w:oZoom.nWidthDest,h:1}
		, {x:0,y:oZoom.yCenter + oZoom.Zoom,w:oZoom.nWidthDest,h:1}
		, {x:oZoom.xCenter - 1,y:0,w:1,h:oZoom.nHeightDest}
		, {x:oZoom.xCenter + oZoom.Zoom,y:0,w:1,h:oZoom.nHeightDest}]
		Return

	MarkerSquare:
		oZoom.oMarkers["Square"] := [{x:oZoom.xCenter - 1,y:oZoom.yCenter,w:oZoom.Zoom + 2,h:1}
		, {x:oZoom.xCenter - 1,y:oZoom.yCenter + oZoom.Zoom + 1,w:oZoom.Zoom + 2,h:1}
		, {x:oZoom.xCenter - 1,y:oZoom.yCenter + 1,w:1,h:oZoom.Zoom}
		, {x:oZoom.xCenter + oZoom.Zoom,y:oZoom.yCenter + 1,w:1,h:oZoom.Zoom}]
		Return

	MarkerGrid:
		If (oZoom.Zoom = 1) {
			Gosub MarkerSquare
			oZoom.oMarkers["Grid"] := oZoom.oMarkers["Square"]
			Return
		}
		oZoom.oMarkers["Grid"] := [{x:oZoom.xCenter - oZoom.Zoom,y:oZoom.yCenter - oZoom.Zoom,w:oZoom.Zoom * 3,h:1}
		, {x:oZoom.xCenter - oZoom.Zoom,y:oZoom.yCenter,w:oZoom.Zoom * 3,h:1}
		, {x:oZoom.xCenter - oZoom.Zoom,y:oZoom.yCenter + oZoom.Zoom,w:oZoom.Zoom * 3,h:1}
		, {x:oZoom.xCenter - oZoom.Zoom,y:oZoom.yCenter + oZoom.Zoom * 2,w:oZoom.Zoom * 3,h:1}
		, {x:oZoom.xCenter - oZoom.Zoom,y:oZoom.yCenter - oZoom.Zoom,w:1,h:oZoom.Zoom * 3}
		, {x:oZoom.xCenter,y:oZoom.yCenter - oZoom.Zoom,w:1,h:oZoom.Zoom * 3}
		, {x:oZoom.xCenter + oZoom.Zoom,y:oZoom.yCenter - oZoom.Zoom,w:1,h:oZoom.Zoom * 3}
		, {x:oZoom.xCenter + oZoom.Zoom * 2,y:oZoom.yCenter - oZoom.Zoom,w:1,h:oZoom.Zoom * 3}]
		Return
}

ZoomCheckSize() {
	Static PrWidth, PrHeight
	If (PrWidth = oZoom.GuiWidth && PrHeight = oZoom.GuiHeight)
		Return
	PrWidth := oZoom.GuiWidth, PrHeight := oZoom.GuiHeight
	IniWrite(PrWidth, "MemoryZoomSizeW"), IniWrite(PrHeight, "MemoryZoomSizeH")
}

SliderZoom() {
	SetTimer, ChangeZoom, -1
}

ChangeZoom(Val = "")  {
	If Val =
		GuiControlGet, Val, ZoomTB:, % oZoom.vSliderZoom
	If (Val < 1 || Val > 50)
		Return
	GuiControl, ZoomTB:, % oZoom.vSliderZoom, % oZoom.Zoom := Val
	GuiControl, ZoomTB:, % oZoom.vTextZoom, % oZoom.Zoom
	SetSize()
	Redraw()
	SetTimer, MagnifyZoomSave, -200
}

FastZoom(Add) {
 	Z := oZoom.Zoom, R := Mod(Z, 5)
	If Add
		Z := Z >= 10 ? Z + (5 - R) : Z + 1
	Else	
		Z := Z > 10 ? Z - (!R ? 5 : R) : Z - 1
	Return Z
}

MagnifyZoomSave() {
	IniWrite(oZoom.Zoom, "MagnifyZoom")
}

MoveStep(StepX, StepY) { 
	oZoom.nXOriginSrc += StepX
	oZoom.nYOriginSrc += StepY
	LimitsOriginSrc(), Redraw(), SendCoords()
}

ChangeMark()  {
	Static Mark := {"Cross":"Square","Square":"Grid","Grid":"None","None":"Cross","":"None"}
	oZoom.Mark := Mark[oZoom.Mark], ChangeMarker(), Redraw()
	GuiControl, ZoomTB:, % oZoom.vChangeMark, % oZoom.Mark
	GuiControl, ZoomTB:, -0x0001, % oZoom.vChangeMark
	GuiControl, ZoomTB:, Focus, % oZoom.vTextZoom
	SetTimer, MagnifyMarkSave, -300
}

MagnifyMarkSave() {
	IniWrite(oZoom.Mark, "MagnifyMark")
}

SetWinEventHook(EventProc, eventMin, eventMax = 0)  {
	; DllCall("CoInitialize", UInt, 0)
	Return DllCall("SetWinEventHook"
				, "UInt", eventMin, "UInt", eventMax := !eventMax ? eventMin : eventMax
				, "Ptr", hmodWinEventProc := 0, "Ptr", lpfnWinEventProc := RegisterCallback(EventProc, "F")
				, "UInt", idProcess := 0, "UInt", idThread := 0
				, "UInt", dwflags := 0x0|0x2, "Ptr")	;;	WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS
}

UnhookWinEvent(hWinEventHook) {  
	DllCall("UnhookWinEvent", "Ptr", hWinEventHook)
	DllCall("GlobalFree", "Ptr", &hWinEventHook) ; free up allocated memory for RegisterCallback
}

ZoomShow() {
	ShowZoom(1) 
	Send_AhkSpy(2, 1)
	ZoomRules("ZoomHide", 0)
	GuiControl, ZoomTB:, Focus, % oZoom.vTextZoom
}

ZoomHide() {
	ZoomRules("ZoomHide", 1)
	ShowZoom(0) 
	Send_AhkSpy(2, 0)
	GuiControl, ZoomTB:, -0x0001, % oZoom.vZoomHideBut
	GuiControl, ZoomTB:, Focus, % oZoom.vTextZoom
}

ShowZoom(Show) {
	oZoom.Show := Show
	If Show {
		WinGetPos, WinX, WinY, WinW, , ahk_id %hAhkSpy%
		oZoom.LWX := WinX + WinW + 1, oZoom.LWY := WinY + 46
		Gui,  Zoom: Show, % "NA Hide x" WinX + WinW " y" WinY
		Gui,  LW: Show, % "NA x" oZoom.LWX " y" oZoom.LWY " w" 0 " h" 0
		Gui,  Zoom: Show, NA
		try Gui, LW: Show, % "NA x" oZoom.LWX " y" oZoom.LWY " w" oZoom.LWWidth " h" oZoom.LWHeight 
	}
	Else 
	{
		Gui,  LW: Show, % "NA w" 0 " h" 0  ;;	нельзя применять Hide, иначе после появления и ресайза остаётся прозрачный след
		Gui,  Zoom: Show, NA Hide
	}
}

MenuAdd(MenuName, Name = "", Label = "", Options = "") {
	Menu, %MenuName%, Add, %Name%, % oMenu.Zoom[Name] := Label, %Options%
}

	; ___________________________ Zoom Events _________________________________________________

ZoomOnSize() {
	Critical
	If A_EventInfo != 0
		Return
	oZoom.GuiWidth := A_GuiWidth
	oZoom.GuiHeight := A_GuiHeight
	SetSize()
	Redraw()
}

ZoomMaximize() { 
	WinGet, Min, MinMax, % "ahk_id " oZoom.hGui
	If Min = 1
		WinRestore, % "ahk_id " oZoom.hGui
	Else 
		WinMaximize, % "ahk_id " oZoom.hGui   
	WinGetPos, WinX, WinY, WinW, WinH, % "ahk_id " oZoom.hGui 
	oZoom.GuiWidth := WinW
	oZoom.GuiHeight := WinH
	SetSize()
	oZoom.LWWidth := oZoom.GuiWidth - 6
	oZoom.LWHeight := oZoom.GuiHeight - 51 
	oZoom.LWX := WinX + 1, oZoom.LWY := WinY + 46 
	Gui,  LW: Show, % "NA x" oZoom.LWX " y" oZoom.LWY " w" oZoom.LWWidth " h" oZoom.LWHeight  
	Redraw() 
	If Min = 1
		WinActivate, % "ahk_id " hAhkSpy
}

ZoomOnClose() {
	ReleaseDC(oZoom.hdcSrc)
	DeleteDC(oZoom.hdcSrc)
	DeleteDC(oZoom.hDCBuf)
	DeleteDC(oZoom.hdcMemory)
	GdipShutdown(oZoom.pToken)
	RestoreCursors()
	ExitApp
}

	; wParam: 0 hide, 1 show, 2 пауза AhkSpy, 3 однократный зум, 4 MemoryZoomSize, 5 MinSize, 6 ActiveNoPause
	; , 7 WinActive AhkSpy, 8 Suspend, 9 Menu, 10 Hotkey, 11 MIN, 12 ShiftTab

Zoom_Msg(wParam, lParam) {
	If wParam = 0  ;;	hide
		ZoomHide()
	Else If wParam = 1  ;;	show
		ZoomShow()
	If wParam = 2  ;;	пауза AhkSpy
		ZoomRules("Pause", lParam)
	Else If wParam = 3  ;;	однократный зум  ;;	AhkSpy отвечает за контекст вызова
		Magnify(1)
	Else If wParam = 4  ;;	MemoryZoomSize
	{
		If (oZoom.MemoryZoomSize := lParam)
			IniWrite(oZoom.GuiWidth, "MemoryZoomSizeW"), IniWrite(oZoom.GuiHeight, "MemoryZoomSizeH")
	}
	Else If (wParam = 5 && DllCall("IsWindowVisible", "Ptr", oZoom.hGui))  ;;	MinSize
		Gui, Zoom:Show, % "NA w" oZoom.GuiMinW " h" oZoom.GuiMinH
	Else If wParam = 6  ;;	ActiveNoPause
		ActiveNoPause := lParam, ZoomRules("Win", ActiveNoPause ? 0 : SpyActive)
	Else If wParam = 7  ;;	WinActive AhkSpy
		SpyActive := lParam, ZoomRules("Win", ActiveNoPause ? 0 : SpyActive)
	Else If wParam = 8  ;;	Suspend
		Suspend % lParam ? "On" : "Off"
	Else If wParam = 9  ;;	Menu
		ZoomRules("Menu", lParam)
	Else If wParam = 10  ;;	Menu
		ZoomRules("Hotkey", lParam)
	Else If wParam = 11  ;;	MIN
		ZoomRules("MIN", 1)
	Else If wParam = 12  ;;	ShiftTab
		ZoomRules("ShiftTab", lParam)
}

Z_MsgZoom(wParam, lParam) {
	obj := Func("Zoom_Msg").Bind(wParam, lParam)
	SetTimer, % obj, -1
	Return 0
}

ZoomRules(Rule, value) {
	Static IsStart, Rules, Arr, Len
	If !IsStart
	{
		Arr := {"ZoomHide":1, "Pause":2, "Win":3, "Sleep":4, "Menu":5, "MIN":6, "MOVE":7, "SIZE":8, "Hotkey":9, "ShiftTab":10}, Len := Arr.Count()
		Loop % VarSetCapacity(Rules, Len - 1)
			StrPut(0, &Rules + A_Index - 1, 1, "CP0")
		IsStart := 1
	}
	StrPut(!!value, &Rules + Arr[Rule] - 1, 1, "CP0")
	If oZoom.Work := !(StrGet(&Rules, Len, "CP0") + 0)
		SetTimer, Magnify, -1
	; ToolTip % Rule "`n" Arr[Rule] "`n" value "`n`n`n"  (StrGet(&Rules, Len, "CP0")) "`n123456789" "`n" oZoom.Work,4,55,6
}

EVENT_OBJECT_DESTROY(hWinEventHook, event, hwnd, idObject, idChild) {
	If (idObject || idChild)
		Return
	If (hwnd = hAhkSpy)
		ExitApp
}

EVENT_SYSTEM_MINIMIZESTART(hWinEventHook, event, hwnd, idObject, idChild) {
	If (idObject || idChild)
		Return
	If (hwnd != hAhkSpy)
		Return
	ZoomRules("MIN", 1)
	If oZoom.Show
		oZoom.Minimize := 1, ShowZoom(0)
}

EVENT_SYSTEM_MINIMIZEEND(hWinEventHook, event, hwnd, idObject, idChild) {
	If (idObject || idChild)
		Return
	If (hwnd != hAhkSpy)
		Return
	If oZoom.Minimize
	{
		isEnabled := false, DllCall("dwmapi.dll\DwmIsCompositionEnabled", "UInt", &isEnabled)
		Sleep % !!isEnabled ? 300 : 10
		ShowZoom(1)
		oZoom.Minimize := 0
	}
	ZoomRules("MIN", 0)
}

EVENT_SYSTEM_MOVESIZESTART(hWinEventHook, event, hwnd, idObject, idChild) {
	If (idObject || idChild)
		Return
	If (hwnd != hAhkSpy)
		Return
	ZoomRules("MOVE", 1)
}

EVENT_SYSTEM_MOVESIZEEND(hWinEventHook, event, hwnd, idObject, idChild) {
	If (idObject || idChild)
		Return
	If (hwnd != hAhkSpy)
		Return
	ZoomRules("MOVE", 0)
}

	; ___________________________ Zoom Sizing _________________________________________________

  ;;	https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadcursora
WM_SETCURSOR(W, L, M, H) {
	Static SIZENWSE := DllCall("User32.dll\LoadCursor", "Ptr", NULL, "Int", 32642, "UPtr")
			, SIZENS := DllCall("User32.dll\LoadCursor", "Ptr", NULL, "Int", 32645, "UPtr")
			, SIZEWE := DllCall("User32.dll\LoadCursor", "Ptr", NULL, "Int", 32644, "UPtr")
	If (oZoom.SIZING = 2)
		Return
	If (W = oZoom.hGui)
	{
		MouseGetPos, mX, mY
		WinGetPos, WinX, WinY, WinW, WinH, % "ahk_id " oZoom.hLW
		If (mX > WinX && mY > WinY)
		{
			If (mX < WinX + WinW - 10)
				DllCall("User32.dll\SetCursor", "Ptr", SIZENS), oZoom.SIZINGType := "NS"
			Else If (mY < WinY + WinH - 10)
				DllCall("User32.dll\SetCursor", "Ptr", SIZEWE), oZoom.SIZINGType := "WE"
			Else
				DllCall("User32.dll\SetCursor", "Ptr", SIZENWSE), oZoom.SIZINGType := "NWSE"
			Return oZoom.SIZING := 1
		}
	}
	Else
		oZoom.SIZING := 0, oZoom.SIZINGType := ""
}

LBUTTONDOWN(W, L, M, H) { 
	If oZoom.SIZING
	{
		ZoomRules("SIZE", 1)
		oZoom.SIZING := 2
		SetSystemCursor("SIZE" oZoom.SIZINGType)
		SetTimer, Sizing, -10
		KeyWait LButton
		SetTimer, Sizing, Off
		RestoreCursors()
		ZoomRules("SIZE", 0)
		oZoom.SIZING := 0, oZoom.SIZINGType := ""
	}
	Else If (H = oZoom.hLW)
	{
		SetTimer, Hand, -1
	}
}

RBUTTONDOWN(W, L, M, H) { 
	If (H = oZoom.vZoomMenu)
		Return ZoomMenu()
	If !(H = oZoom.hLW)
		Return 
	SetTimer CropToggle, -100
}

CropToggle() {
	If !oZoom.Crop
		oZoom.Crop := 1, oZoom.CropX := oZoom.nXOriginSrc, oZoom.CropY := oZoom.nYOriginSrc
	Else 
		oZoom.Crop := 0
	CropMarkToggle()
	Redraw()
	CropChangeControls() 
}

CropMarkToggle() { 
	If (oZoom.Crop && (oZoom.CropPrMark := oZoom.Mark) && oZoom.Mark != "Cross")
		oZoom.Mark := "Cross", ChangeMarker()
	Else If (!oZoom.Crop && oZoom.Mark != oZoom.CropPrMark)
		oZoom.Mark := oZoom.CropPrMark, ChangeMarker()  
}

CropChangeControls() { 
	GuiControl("ZoomTB:", oZoom.vChangeMark, oZoom.Mark)
	GuiControl("ZoomTB:Hide" oZoom.Crop, oZoom.vChangeMark)
	GuiControl("ZoomTB:Show" oZoom.Crop, oZoom.vCropWidth)
	GuiControl("ZoomTB:Show" oZoom.Crop, oZoom.vCropHeight) 
} 

ZoomMenu() { 
	ObjActive.ZoomSleep()
	WinActivate, % "ahk_id " oZoom.hGui
	ZoomRules("Win", 0)
	DllCall("SetTimer", "Ptr", A_ScriptHwnd, "Ptr", 1, "UInt", 333, "Ptr", RegisterCallback("ZoomMenuCheck", "Fast"))
	CoordMode, Menu, Screen 
	If A_GuiControl =
	{
		MouseGetPosScreen(x, y)
		Menu, Zoom, Show, % x - 200, % y + 20
	}
	Else 
	{ 
		WinGetPos, WinX, WinY, WinW, WinH, % "ahk_id " oZoom.vZoomMenu  
		Menu, Zoom, Show, % WinX - 200, % WinY + WinH
	}
	ObjActive.ZoomNoSleep()
}

ZoomMenuCheck()  {
	DllCall("KillTimer", "Ptr", A_ScriptHwnd, "Ptr", 1) 
	If !WinExist("ahk_class #32768 ahk_pid " oZoom.CurrentProcessId)
		Return
	If GetKeyState("RButton")
	{
		MouseGetPos, , , WinID
		Menu := MenuGetName(GetMenuForMenu(WinID)) 
		If Menu && (F := oMenu[Menu][oOther.ThisMenuItem := AccUnderMouse(WinID, Id).accName(Id)])
		{
			oOther.MenuItemExist := 1
			If  !(F ~= "^_")
			{
				KeyWait, RButton
				WinClose % "ahk_id " WinID
			}
			If IsLabel(F)
				GoSub, % F
			Else
				%F%()
			oOther.MenuItemExist := 0
		}
		KeyWait, RButton
	}
	DllCall("SetTimer", "Ptr", A_ScriptHwnd, "Ptr", 1, "UInt", 64, "Ptr", RegisterCallback("ZoomMenuCheck", "Fast"))
}

_gMenuZoom() { 
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem 
	p := ObjActive["Coords" SubStr(ThisMenuItem, 8)]	; SetPosObject
	If p[1] = "" || p[2] = "" || p[3] = "" || p[4] = ""
		Return ToolTip("Coordinates not found!", 800)
	oZoom.Crop := 1
	x := p[1] + 0, y := p[2] + 0, w := p[3] + 0, h := p[4] + 0
	If ThisMenuItem = Select AhkSpy
		y -= HeigtButton, h += HeigtButton
	oZoom.nXOriginSrc := x - oZoom.VSX, oZoom.nYOriginSrc := y - oZoom.VSY
	oZoom.CropX := x + w - 1 - oZoom.VSX, oZoom.CropY := y + h - 1 - oZoom.VSY 
	CropMarkToggle()
	Redraw()
	CropChangeControls()
	SendCoords()
}

_gSave_to_Clipboard() { 
	If !pBitmap := GetBitmap()
		Return ToolTip("Bitmap not found!", 800)
	SetBitmapToClipboard(pBitmap) 
	DllCall("gdiplus\GdipDisposeImage", "UPtr", pBitmap) 
	ToolTip("Copy to clipboard", 800)
}

_gSave_as_Base64() {
	If GetKeyState("Control", "P")
		tovar := 1
	If GetKeyState("Shift", "P")
		nocrlf := 1
	If !pBitmap := GetBitmap()
		Return ToolTip("Bitmap not found!", 800)  
		
	If BitmapToBase64(pBitmap, tovar || nocrlf ? 1 : 0, Base64) != 0
		Return DllCall("gdiplus\GdipDisposeImage", "UPtr", pBitmap), ToolTip("Error BitmapToBase64!", 1200) 

	DllCall("gdiplus\GdipDisposeImage", "UPtr", pBitmap) 
	DllCall("OpenClipboard", Ptr, 0)
	DllCall("EmptyClipboard")
	DllCall("CloseClipboard")
	If tovar
		Base64 := FormatBase64ToVaribles(Base64, "Base64", nocrlf ? 0 : 128) 
	Clipboard := Base64
	ToolTip("Copy to clipboard as Base64" (tovar ? " and format AHK variable" : "") (nocrlf ? " and no CRLF" : ""), 800)
		
	; File := A_Temp "\AhkSpy picture for Base64.png"
	; SaveBitmapToFile(pBitmap, File) 
	; DllCall("gdiplus\GdipDisposeImage", "UPtr", pBitmap) 
	; FileGetSize, nSize, %File%
	; FileRead, buff, *c %File% 
	; If Control
		; Base64 := CryptBinaryToStringBASE64(&buff, nSize, 1)
		; , Base64 := FormatBase64ToVaribles(Base64, "Base64", 128) 
	; Else
		; Base64 := CryptBinaryToStringBASE64(&buff, nSize, 0)
	; VarSetCapacity(buff, 0)
	; DllCall("OpenClipboard", Ptr, 0)
	; DllCall("EmptyClipboard")
	; DllCall("CloseClipboard")
	; Clipboard := Base64
	; ToolTip("Copy to clipboard as Base64" (Control ? " and format AHK variable" : ""), 800)
}  

_gSave_to_file() { 
	If !pBitmap := GetBitmap()
		Return ToolTip("Bitmap not found!", 800)
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	
	file := (ThisMenuItem = "Save to temp file and edit") 
	? A_Temp "\AhkSpy picture.png"
	: A_Desktop "\AhkSpy picture " A_YYYY "-" A_MM "-" A_DD " " A_Hour "." A_Min "." A_Sec ".png"
	
	; GetNameFile(A_Desktop, "AhkSpy picture ", "png")
	
	SaveBitmapToFile(pBitmap, file)
	DllCall("gdiplus\GdipDisposeImage", "UPtr", pBitmap)
	If (ThisMenuItem = "Save to file and edit") || (ThisMenuItem = "Save to temp file and edit")
	{ 
		WinClose % "ahk_class #32768 ahk_pid " oZoom.CurrentProcessId
		If GetMinMax(oZoom.hGui) = 1
			ZoomMaximize()
		Run edit %file%
		ObjActive.AhkSpy_Minimize()
	}
	Else
		ToolTip("Save file to desktop", 800)
}

GetBitmap() {
	If oZoom.Crop
		w := oZoom.CropWidth, h := oZoom.CropHeight
		, sx := Min(oZoom.CropX, oZoom.nXOriginSrc)
		, sy := Min(oZoom.CropY, oZoom.nYOriginSrc)
	Else
		w := oZoom.VirtualScreenWidth
		, h := oZoom.VirtualScreenHeight
		, sx := 0, sy := 0
	
	chdc := CreateCompatibleDC()
	hbm := CreateDIBSection(w, h, chdc)
	obm := SelectObject(chdc, hbm)
	DllCall("BitBlt", "Ptr", chdc, "int", 0, "int", 0, "int", w, "int", h
			, "Ptr", oZoom.hdcMemory, "int", sx, "int", sy, "Uint", 0x00CC0020) 
	DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "UPtr", hbm, "UPtr", 0, "UPtr*", pBitmap)
	SelectObject(chdc, obm), DeleteObject(hbm), DeleteDC(chdc)
	return pBitmap
}

CircleCoupCrop() {
	If oZoom.CropWidth = 1 && oZoom.CropHeight = 1
		Return
	x := oZoom.CropX, y := oZoom.CropY
	If oZoom.nXOriginSrc > oZoom.CropX && oZoom.nYOriginSrc > oZoom.CropY ; RD - текущее правее и ниже диагонали Crop
		oZoom.CropX := oZoom.nXOriginSrc, oZoom.nXOriginSrc := x
	Else If oZoom.nXOriginSrc < oZoom.CropX && oZoom.nYOriginSrc > oZoom.CropY ; LD
		oZoom.CropY := oZoom.nYOriginSrc, oZoom.nYOriginSrc := y
	Else If oZoom.nXOriginSrc < oZoom.CropX && oZoom.nYOriginSrc < oZoom.CropY ; LU 
		oZoom.CropX := oZoom.nXOriginSrc, oZoom.nXOriginSrc := x
	Else If oZoom.nXOriginSrc > oZoom.CropX && oZoom.nYOriginSrc < oZoom.CropY ; RU
		oZoom.CropY := oZoom.nYOriginSrc, oZoom.nYOriginSrc := y
	Else
		Return CoupCrop()
	Redraw()
	SendCoords()
} 

CoupCrop() {
	x := oZoom.CropX, y := oZoom.CropY
	oZoom.CropX := oZoom.nXOriginSrc, oZoom.CropY := oZoom.nYOriginSrc
	oZoom.nXOriginSrc := x, oZoom.nYOriginSrc := y
	Redraw()
	SendCoords()
}

SendCoords() { 
	OffX := (oZoom.nXOriginSrc - oZoom.sXOriginSrc)
	OffY := (oZoom.nYOriginSrc - oZoom.sYOriginSrc)
	If (oZoom.displaced && OffX OffY = "00" && (1, oZoom.displaced := 0))
		Gui, Zoom: Color, %GuiColor%
	Else If (!oZoom.displaced && OffX OffY != "00" && (1, oZoom.displaced := 1)) 
		Gui, Zoom: Color, %GuiColorDisp% 
	BGR := DllCall("gdi32.dll\GetPixel", "Ptr", oZoom.hdcMemory, "int", oZoom.nXOriginSrc, "int", oZoom.nYOriginSrc)
	Send_WM_COPYDATA(1, BGR "`n" OffX "`n" OffY, hAhkSpy)
}

Hand() {
	SetTimer, Magnify, Off
	DllCall("GetCursorPos", "int64P", pt)
	oZoom.MoveHandX := pt << 32 >> 32, oZoom.MoveHandY := pt >> 32
	oZoom.MoveXSrc := oZoom.nXOriginSrc
	oZoom.MoveYSrc := oZoom.nYOriginSrc
	SetSystemCursor("HAND")
	SetTimer, MoveHand, 10
	KeyWait, LButton
	SetTimer, MoveHand, Off
	RestoreCursors()
	oZoom.SIZING := 0
	If oZoom.Work
		SetTimer, Magnify, -10
}
	
MoveHand() {
	Static PrnXOriginSrc, PrnYOriginSrc
	PrnXOriginSrc := oZoom.nXOriginSrc
	PrnYOriginSrc := oZoom.nYOriginSrc
	DllCall("GetCursorPos", "int64P", pt)
	MouseX := pt << 32 >> 32, MouseY := pt >> 32 
	XOdds := oZoom.MoveHandX - MouseX
	XOff := XOdds > 0 ? Floor(XOdds / oZoom.Zoom) : Ceil(XOdds / oZoom.Zoom)
	oZoom.nXOriginSrc := oZoom.MoveXSrc + XOff
	YOdds := oZoom.MoveHandY - MouseY
	YOff := YOdds > 0 ? Floor(YOdds / oZoom.Zoom) : Ceil(YOdds / oZoom.Zoom)
	oZoom.nYOriginSrc := oZoom.MoveYSrc + YOff
	If (PrnXOriginSrc <> oZoom.nXOriginSrc || PrnYOriginSrc <> oZoom.nYOriginSrc)
	{
		LimitsOriginSrc()
		SendCoords()
	} 
	Redraw() 
}

LimitsOriginSrc() {
	X := oZoom.nXOriginSrc
	oZoom.nXOriginSrc := X < 0 ? 0 : X > oZoom.VirtualScreenWidth - 1 ? oZoom.VirtualScreenWidth - 1 : X
	Y := oZoom.nYOriginSrc
	oZoom.nYOriginSrc := Y < 0 ? 0 : Y > oZoom.VirtualScreenHeight - 1 ? oZoom.VirtualScreenHeight - 1 : Y
}

UnderRender() { 
	MouseGetPos, , , Control, , 2
	Return (Control = oZoom.hLW)
}

GetMinMax(h) {
	WinGet, Min, MinMax, % "ahk_id " h
	Return Min
}

Sizing() {
	MouseGetPos, mX, mY
	WinGetPos, WinX, WinY, , , % "ahk_id " oZoom.hGui
	If (oZoom.SIZINGType = "NWSE" || oZoom.SIZINGType = "WE")
		Width := " w" (mX - WinX < oZoom.GuiMinW ? oZoom.GuiMinW : mX - WinX)
	If (oZoom.SIZINGType = "NWSE" || oZoom.SIZINGType = "NS")
		Height := " h" (mY - WinY < oZoom.GuiMinH ? oZoom.GuiMinH : mY - WinY)
	Gui, Zoom:Show, % "NA" Width . Height
	SetTimer, Sizing, -1
}

SetSystemCursor(CursorName, cx = 0, cy = 0) {
	Static SystemCursors := {ARROW:32512, IBEAM:32513, WAIT:32514, CROSS:32515, UPARROW:32516, SIZE:32640, ICON:32641, SIZENWSE:32642
					, SIZENESW:32643, SIZEWE:32644 ,SIZENS:32645, SIZEALL:32646, NO:32648, HAND:32649, APPSTARTING:32650, HELP:32651}
	Local CursorHandle, hImage, Name, ID
	If (CursorHandle := DllCall("LoadCursor", Uint, 0, Int, SystemCursors[CursorName]))
		For Name, ID in SystemCursors
			hImage := DllCall("CopyImage", Ptr, CursorHandle, Uint, 0x2, Int, cx, Int, cy, Uint, 0)
			, DllCall("SetSystemCursor", Ptr, hImage, Int, ID)
}

RestoreCursors() {
	DllCall("SystemParametersInfo", UInt, 0x57, UInt, 0, UInt, 0, UInt, 0)  ;;	SPI_SETCURSORS := 0x57
}

Send_AhkSpy(i, Param) { 
	PostMessage, % MsgAhkSpyZoom, i, % Param, , ahk_id %hAhkSpy%
}

Send_WM_COPYDATA(ByRef WParam, ByRef StringToSend, ByRef hwnd) {
    Static TimeOutTime := 0, WM_COPYDATA := 0x4a
    VarSetCapacity(CopyDataStruct, 3*A_PtrSize, 0)   
    SizeInBytes := (StrLen(StringToSend) + 1) * (A_IsUnicode ? 2 : 1)
    NumPut(SizeInBytes, CopyDataStruct, A_PtrSize)   
    NumPut(&StringToSend, CopyDataStruct, 2*A_PtrSize)  
    Prev_DetectHiddenWindows := A_DetectHiddenWindows 
    DetectHiddenWindows On  
    SendMessage, WM_COPYDATA, WParam, &CopyDataStruct,, ahk_id %hwnd%,,,, %TimeOutTime%
    DetectHiddenWindows %Prev_DetectHiddenWindows%   
    return ErrorLevel
}

	; ___________________________ Zoom Magnify _________________________________________________

Magnify(one = 0) { 
	If (a := oZoom.Work) || one
	{
		MouseGetPos, , , WinID
		If b := (WinID != oZoom.hLW && WinID != oZoom.hGui && WinID != hAhkSpy)
		{ 
			oZoom.NewSpot := 1, oZoom.MouseX := ObjActive.ScreenX, oZoom.MouseY := ObjActive.ScreenY
			If oZoom.Crop
				oZoom.Crop := 0, CropChangeControls()
			UpdateWindow(oZoom.hdcSrc, oZoom.MouseX - oZoom.nXOriginSrcOffset, oZoom.MouseY - oZoom.nYOriginSrcOffset)
		}
	}
	If oZoom.NewSpot && (!a || one && b || a && !b)
		Memory()
	If a
		SetTimer, Magnify, -10
	;; ToolTip % A_TickCount "`nMagnify", 4, 4, 4
}

Redraw() {
	UpdateWindow(oZoom.hdcMemory, oZoom.nXOriginSrc - oZoom.nXOriginSrcOffset , oZoom.nYOriginSrc - oZoom.nYOriginSrcOffset)
}

Memory() {
	SysGet, VSX, 76
	SysGet, VSY, 77
	oZoom.VSX := VSX
	oZoom.VSY := VSY
	SysGet, VirtualScreenWidth, 78
	SysGet, VirtualScreenHeight, 79
	oZoom.nXOriginSrc := oZoom.sXOriginSrc := oZoom.MouseX - VSX
	oZoom.nYOriginSrc := oZoom.sYOriginSrc := oZoom.MouseY - VSY 
	hBM := DllCall("Gdi32.Dll\CreateCompatibleBitmap", "Ptr", oZoom.hdcSrc, "Int", VirtualScreenWidth, "Int", VirtualScreenHeight)
	DllCall("Gdi32.Dll\SelectObject", "Ptr", oZoom.hdcMemory, "Ptr", hBM), DllCall("DeleteObject", "Ptr", hBM)
	StretchBlt(oZoom.hdcMemory, 0, 0, VirtualScreenWidth, VirtualScreenHeight, oZoom.hdcSrc, VSX, VSY, VirtualScreenWidth, VirtualScreenHeight)
	oZoom.VirtualScreenWidth := VirtualScreenWidth, oZoom.VirtualScreenHeight := VirtualScreenHeight
	oZoom.NewSpot := 0
	If oZoom.displaced && (1, oZoom.displaced := 0)
		Gui, Zoom: Color, %GuiColor% 
} 		

	; ___________________________ Zoom Gdip _________________________________________________

UpdateWindow(Src, X, Y) {
	hbm := CreateDIBSection(oZoom.nWidthDest, oZoom.nHeightDest, oZoom.hDCBuf)
	DllCall("SelectObject", "UPtr", oZoom.hDCBuf, "UPtr", hbm)
	StretchBlt(oZoom.hDCBuf, oZoom.conX, oZoom.conY, oZoom.nWidthDest, oZoom.nHeightDest
	, Src, X, Y, oZoom.nWidthSrc, oZoom.nHeightSrc)
	For k, v In oZoom.oMarkers[oZoom.Mark]
		StretchBlt(oZoom.hDCBuf, v.x, v.y, v.w, v.h, oZoom.hDCBuf, v.x, v.y, v.w, v.h, 0x5A0049)	;; PATINVERT
	CropRender()	  
	DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "UPtr", hbm, "UPtr", 0, "UPtr*", pBitmap)
	; DllCall("SelectObject", "UPtr", oZoom.hDCBuf, "UPtr", hbm)
	DllCall("gdiplus\GdipCreateFromHDC", "UPtr", oZoom.hDCBuf, "UPtr*", G)
	; DllCall("gdiplus\GdipSetInterpolationMode", "UPtr", G, "int", 5)
	DrawImage(G, pBitmap, 0, 0, oZoom.LWWidth, oZoom.LWHeight)
	If oZoom.Show
		UpdateLayeredWindow(oZoom.hLW, oZoom.hDCBuf, oZoom.LWWidth, oZoom.LWHeight)
	DllCall("DeleteObject", "UPtr", hbm)
	DllCall("gdiplus\GdipDeleteGraphics", "UPtr", G)
	DllCall("gdiplus\GdipDisposeImage", "UPtr", pBitmap)
}

CropRender() {
	Static thickness := 2
	If !oZoom.Crop
		Return 
	x := (oZoom.nXOriginSrc - oZoom.CropX) * oZoom.Zoom
	y := (oZoom.nYOriginSrc - oZoom.CropY) * oZoom.Zoom
	xoff := x < 0 ? oZoom.Zoom : 0
	yoff := y < 0 ? oZoom.Zoom : 0  
	oZoom.oMarkers["CropCross"] := [] 
	If y
		oZoom.oMarkers["CropCross"].Push({x:oZoom.xCenter - x + xoff,y:oZoom.yCenter - y - 1,w:x + oZoom.Zoom + -xoff * 2,h:thickness} 
										, {x:oZoom.xCenter - x + xoff,y:oZoom.yCenter - y + oZoom.Zoom,w:x + oZoom.Zoom + -xoff * 2,h:thickness})
	If x
		oZoom.oMarkers["CropCross"].Push({x:oZoom.xCenter - x - 1,y:oZoom.yCenter - y + yoff,h:y + oZoom.Zoom + -yoff * 2,w:thickness} 
								, {x:oZoom.xCenter - x + oZoom.Zoom,y:oZoom.yCenter - y + yoff,h:y + oZoom.Zoom + -yoff * 2,w:thickness})
	For k, v In oZoom.oMarkers["CropCross"]
		StretchBlt(oZoom.hDCBuf, v.x, v.y, v.w, v.h, oZoom.hDCBuf, v.x, v.y, v.w, v.h, 0x5A0049)	;; PATINVERT
	
	oZoom.CropWidth := Abs(oZoom.nXOriginSrc - oZoom.CropX) + 1
	oZoom.CropHeight := Abs(oZoom.nYOriginSrc - oZoom.CropY) + 1
	GuiControl("ZoomTB:", oZoom.vCropWidth, "W: " oZoom.CropWidth)
	GuiControl("ZoomTB:", oZoom.vCropHeight, "H: " oZoom.CropHeight) 
}

GdipStartup() {
	if !DllCall("GetModuleHandle", "str", "gdiplus", UPtr)
		DllCall("LoadLibrary", "str", "gdiplus")
	VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
	DllCall("gdiplus\GdiplusStartup", A_PtrSize ? "UPtr*" : "uint*", pToken, UPtr, &si, UPtr, 0)
	Return pToken
}

GdipShutdown(pToken) {
	DllCall("gdiplus\GdiplusShutdown", UPtr, pToken)
	if hModule := DllCall("GetModuleHandle", "str", "gdiplus", UPtr)
		DllCall("FreeLibrary", UPtr, hModule)
	Return 0
}

SelectObject(hdc, hgdiobj) {
   Ptr := A_PtrSize ? "UPtr" : "UInt"
   return DllCall("SelectObject", Ptr, hdc, Ptr, hgdiobj)
} 

DeleteObject(hObject) {
   return DllCall("DeleteObject", A_PtrSize ? "UPtr" : "UInt", hObject)
}

UpdateLayeredWindow(hwnd, hdc, w, h) {
	Return DllCall("UpdateLayeredWindow"
					, UPtr, hwnd
					, UPtr, 0
					, UPtr, 0
					, "int64*", w|h<<32
					, UPtr, hdc
					, "int64*", 0
					, "uint", 0
					, "UInt*", 33488896  ;;	(Alpha := 255)<<16|1<<24
					, "uint", 2)
}

StretchBlt(ddc, dx, dy, dw, dh, sdc, sx, sy, sw, sh, Raster=0x40CC0020) {  ;;	0x00CC0020|0x40000000
	Return DllCall("gdi32\StretchBlt"
					, UPtr, ddc
					, "int", dx
					, "int", dy
					, "int", dw
					, "int", dh
					, UPtr, sdc
					, "int", sx
					, "int", sy
					, "int", sw
					, "int", sh
					, "uint", Raster)
}

CreateDIBSection(w, h, hdc) {
	Static bi, _ := VarSetCapacity(bi, 40, 0)
	NumPut(w, bi, 4, "uint")
	NumPut(h, bi, 8, "uint")
	NumPut(40, bi, 0, "uint")
	NumPut(1, bi, 12, "ushort")
	NumPut(0, bi, 16, "uInt")
	NumPut(32, bi, 14, "ushort")
	Return DllCall("CreateDIBSection"
					, "UPtr", hdc
					, "UPtr", &bi
					, "uint", 0
					, "UPtr*",
					, "UPtr", 0
					, "uint", 0, "UPtr")
}

DrawImage(pGraphics, pBitmap, dx, dy, dw, dh) {
	Return DllCall("gdiplus\GdipDrawImageRectRect"
				, "UPtr", pGraphics
				, "UPtr", pBitmap
				, "float", dx
				, "float", dy
				, "float", dw
				, "float", dh
				, "float", dx
				, "float", dy
				, "float", dw
				, "float", dh
				, "int", 2
				, "UPtr",
				, "UPtr", 0
				, "UPtr", 0)
} 

ReleaseDC(hdc, hwnd=0) {
	Return DllCall("ReleaseDC", "UPtr", hwnd, "UPtr", hdc)
}

DeleteDC(hdc) {
	Return DllCall("DeleteDC", "UPtr", hdc)
}

CreateCompatibleDC(hdc=0) {
	Return DllCall("CreateCompatibleDC", "UPtr", hdc)
}

CreateHBITMAPFromBitmap(pBitmap, Background:=0xffffffff) {
; background should be zero, to not alter the semi-transparent areas of the image
   hBitmap := 0
   DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", A_PtrSize ? "UPtr" : "UInt", pBitmap, A_PtrSize ? "UPtr*" : "uint*", hBitmap, "int", Background)
   return hBitmap
}

SetBitmapToClipboard(pBitmap) {
; modified by Marius Șucan to have this function report errors

   Ptr := A_PtrSize ? "UPtr" : "UInt"
   off1 := A_PtrSize = 8 ? 52 : 44
   off2 := A_PtrSize = 8 ? 32 : 24
   r1 := DllCall("OpenClipboard", Ptr, 0)
   If !r1
      Return -1

   hBitmap := CreateHBITMAPFromBitmap(pBitmap, 0)
   If !hBitmap
   {
      DllCall("CloseClipboard")
      Return -3
   }

   r2 := DllCall("EmptyClipboard")
   If !r2
   {
      DeleteObject(hBitmap)
      DllCall("CloseClipboard")
      Return -2
   }

   DllCall("GetObject", Ptr, hBitmap, "int", VarSetCapacity(oi, A_PtrSize = 8 ? 104 : 84, 0), Ptr, &oi)
   hdib := DllCall("GlobalAlloc", "uint", 2, Ptr, 40+NumGet(oi, off1, "UInt"), Ptr)
   pdib := DllCall("GlobalLock", Ptr, hdib, Ptr)
   DllCall("RtlMoveMemory", Ptr, pdib, Ptr, &oi+off2, Ptr, 40)
   DllCall("RtlMoveMemory", Ptr, pdib+40, Ptr, NumGet(oi, off2 - (A_PtrSize ? A_PtrSize : 4), Ptr), Ptr, NumGet(oi, off1, "UInt"))
   DllCall("GlobalUnlock", Ptr, hdib)
   DeleteObject(hBitmap)
   r3 := DllCall("SetClipboardData", "uint", 8, Ptr, hdib) ; CF_DIB = 8
   DllCall("CloseClipboard")
   DllCall("GlobalFree", Ptr, hdib)
   E := r3 ? 0 : -4    ; 0 - success
   Return E
}

SaveBitmapToFile(pBitmap, sOutput)  {
	SplitPath, sOutput,,, Extension
	if Extension not in PNG
		return -1
	DllCall("gdiplus\GdipGetImageEncodersSize", UIntP, nCount, UIntP, nSize)
	VarSetCapacity(ci, nSize)
	DllCall("gdiplus\GdipGetImageEncoders", UInt, nCount, UInt, nSize, Ptr, &ci)
	if !(nCount && nSize)
		return -2 
	Loop, % nCount  {
		sString := StrGet(NumGet(ci, (idx := (48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize), "UTF-16")
		if !InStr(sString, "*." Extension)
			continue

		pCodec := &ci+idx
		break
	} 
	if !pCodec
		return -3
	if A_IsUnicode
		pOutput := &sOutput
	else  {
		VarSetCapacity(wOutput, StrPut(sOutput, "UTF-16")*2, 0)
		StrPut(sOutput, &wOutput, "UTF-16")
		pOutput := &wOutput
	}
	E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, pOutput, Ptr, pCodec, UInt, 0)
	return E ? -5 : 0
}

BitmapToBase64(pBitmap, NOCRLF, byref Base64) {  
	DllCall("gdiplus\GdipGetImageEncodersSize", UintP, nCount, UintP, nSize) 
	VarSetCapacity(ci, nSize)
	DllCall("gdiplus\GdipGetImageEncoders", UInt, nCount, UInt, nSize, Ptr, &ci)
	if !(nCount && nSize)
		return -2 
	Loop, % nCount  {
		sString := StrGet(NumGet(ci, (idx := (48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize), "UTF-16")
		if !InStr(sString, "*." "PNG")
			continue
		pCodec := &ci+idx
		break
	} 
	if !pCodec
		return -3  
	DllCall( "ole32\CreateStreamOnHGlobal", UInt, 0, Int, 1, PtrP, pStream )
	if !E := DllCall( "gdiplus\GdipSaveImageToStream", Ptr, pBitmap, Ptr, pStream, Ptr, pCodec, UInt, 0)  {
		DllCall( "ole32\GetHGlobalFromStream", Ptr, pStream, PtrP, hData )
		pData := DllCall( "GlobalLock", Ptr, hData, Ptr )
		nSize := DllCall( "GlobalSize", Ptr, hData, Ptr )
		VarSetCapacity( buff, 0), VarSetCapacity( buff, nSize, 0 )
		DllCall( "RtlMoveMemory", Ptr, &buff, Ptr, pData, UInt, nSize )
		DllCall( "GlobalUnlock", Ptr, hData )
		DllCall( "GlobalFree", Ptr, hData )
	}
	ObjRelease(pStream)  
	Base64 := CryptBinaryToStringBASE64(&buff, nSize, NOCRLF)
	return 0
}  
 
FormatBase64ToVaribles(Base64, Name, LenRow = 128) {
	DATALen := StrLen(Base64)
	RowLen := !LenRow ? 16000 : LenRow
	If (RowLen = 16000) || (RowLen >= DATALen)
		Return DataToVarExp(Base64, Name, DATALen)
	Step := 0, Pos := 1  
	If !LenRow
	{
		Loop % Ceil(DATALen / RowLen)
		{
			Str .= SubStr(Base64, Pos, RowLen)
			Pos += RowLen
			If (Pos < DATALen)
				Str .= "`n" Name " = %" Name "%"
		}
		Return Name " = " Str
	} 
	Loop % Ceil(DATALen / RowLen)
	{   
		Str .= SubStr(Base64, Pos, RowLen) "`n" 
		Pos += RowLen, ++Step
		If (Pos >= DATALen || Step * RowLen >= 16000)
			Step := 0, Str .= ")" . (Pos < DATALen ? "`n" Name " = %" Name "%`n(`n" : "")
	}
	Return Name " = `n(`n" Str
}	

DataToVarExp(Base64, Name, DATALen) {
	RowLen := 16000, Pos := 1   
	If (RowLen >= DATALen)
		Return Name " := """ Base64 """"
	Loop % Ceil(DATALen / RowLen)
	{
		p := SubStr(Base64, Pos, RowLen) 
		Pos += RowLen
		Str .= "`n" Name " .= """ p """"
	}
	Return StrReplace(Str, " .= """, " := """, , 1) 
}	

CryptBinaryToStringBASE64(pData, Bytes, NOCRLF = "")  {
   static CRYPT_STRING_BASE64 := 1, CRYPT_STRING_NOCRLF := 0x40000000
   CRYPT := CRYPT_STRING_BASE64 | (NOCRLF ? CRYPT_STRING_NOCRLF : 0)
   
   DllCall("Crypt32\CryptBinaryToString", Ptr, pData, UInt, Bytes, UInt, CRYPT, Ptr, 0, UIntP, Chars)
   VarSetCapacity(OutData, Chars * (A_IsUnicode ? 2 : 1))
   DllCall("Crypt32\CryptBinaryToString", Ptr, pData, UInt, Bytes, UInt, CRYPT, Str, OutData, UIntP, Chars)
   Return OutData
}
	; ___________________________ End _________________________________________________

	;;)			01:58 20.01.2021

  

 

/*
©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©
©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©© AhkSpy ©©
©©©©©©©©©©©     ©   ©©©©©©   ©©©©©©©©        ©©©©©©©©©©©©©©©©©©©©©©©
©©©©©©©©©©      ©   ©©©©©©   ©©©©©©©    ©©    ©©©©©©©©©©©©©©©©©©©©©©
©©©©©©©©©       ©   ©©©©©©   ©©©©©©©     ©©©©©©©©©©©©©©©©©©©©©©©©©©©
©©©©©©©©    ©   ©       ©©   ©©©  ©©©       ©©©       ©©   ©©   ©©©©
©©©©©©©    ©©   ©   ©    ©   ©    ©©©©©©      ©   ©    ©   ©©   ©©©©
©©©©©©    ©©©   ©   ©©   ©       ©©©©©©©©©    ©   ©©   ©   ©©   ©©©©
©©©©©           ©   ©©   ©   ©    ©©    ©©    ©   ©    ©    ©   ©©©©
©©©©    ©©©©©   ©   ©©   ©   ©©©  ©©©        ©©       ©©©       ©©©©
©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©   ©©©©©©©©©©©   ©©©©
©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©   ©©©©©©   ©    ©©©©
©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©   ©©©©©©©      ©©©©©
©© AhkSpy ©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©
©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©

    Автор - serzh82saratov
    E-Mail: serzh82saratov@mail.ru

    Благодарность Malcev, teadrinker, YMP, Irbis за их решения
    Описание - http://forum.script-coding.com/viewtopic.php?pid=72459#p72459
    Обсуждение - http://forum.script-coding.com/viewtopic.php?pid=72244#p72244
    Обсуждение на офф. форуме- https://autohotkey.com/boards/viewtopic.php?f=6&t=52872
    Актуальный исходник - https://raw.githubusercontent.com/serzh82saratov/AhkSpy/master/AhkSpy.ahk
	
	баги
		64bit https://forum.script-coding.com/viewtopic.php?pid=153917#p153917
		Acc_GetPath http://forum.script-coding.com/viewtopic.php?pid=147218#p147218
*/


Global AhkSpyVersion := 5.08
          
	; ___________________________ Caption _________________________________________________

ComObjError(false)

WS_EX_APPWINDOW := 0x40000, WS_CHILDWINDOW := 0x40000000, WS_EX_LAYERED := 0x80000
, WS_EX_TRANSPARENT := 0x20, WS_POPUP := 0x80000000, WS_EX_NOACTIVATE := 0x8000000

p1 = %1%
If (p1 = "Zoom")
{  
	Gosub ShowZoom 
	Return
}

SingleInstance()
#NoEnv
#UseHook
#KeyHistory 0
#MaxMem 4095

SetBatchLines, -1
ListLines, Off
DetectHiddenWindows, On
CoordMode, Pixel
CoordMode, Menu

Gosub, CheckAhkVersion
Menu, Tray, UseErrorLevel
Menu, Tray, Icon, Shell32.dll, % A_OSVersion = "WIN_XP" ? 222 : 278

Global Path_User := A_AppData "\AhkSpy"
If !InStr(FileExist(Path_User), "D")
	FileCreateDir, % Path_User


Global MemoryFontSize := IniRead("MemoryFontSize", 0)
	, FontBold := IniRead("FontBold", 0)
	, FontSize := MemoryFontSize ? IniRead("FontSize", "15") : 15			;;  Размер шрифта
	, FontFamily :=  "Arial"				;;  Шрифт - Times New Roman | Georgia | Myriad Pro | Arial
	, FontWeight := FontBold ? 900 : 500	;;  Насыщенность шрифта
	, HeigtButton := 30						;;  Высота кнопок
	, RangeTimer := 100						;;  Период опроса данных, увеличьте на слабом ПК
	HeightStart := 530						;;  Высота окна при старте
	wKey := 136								;;  Ширина кнопок
	wColor := wKey // 2						;;  Ширина цветного фрагмента

DarkTheme := IniRead("DarkTheme", 0)
If !DarkTheme
{
	Global ColorFont := "000000"			;;  Цвет шрифта
	, ColorBg := "FFFFFF"					;;  Цвет фона          "F0F0F0" E4E4E4     F8F8F8
	, ColorBgPaused := "f7f7f7"				;;  Цвет фона при паузе     F0F0F0
	, ColorBgModeButton := "f7f7f7"			;;  E1E1E1
	, ColorSelModeButton := "A9D186"		;;  Цвет фона кнопки текущего режима
	, ColorSelMouseHover := "3399FF"		;;  Цвет фона элемента при наведении мыши  3399FF   96C3DC F9D886 8FC5FC AEC7E1
	, ColorSelMouseHoverText := ColorBg		;;  Цвет текста элемента при наведении мыши     96C3DC F9D886 8FC5FC AEC7E1
	, ColorSelButton := "96C3DC"			;;  Цвет фона при нажатии на кнопки
	, ColorSelAnchor := "FFFF80"			;;  Цвет фона заголовка для якоря
	, ColorHighLightBckg := "FFE0E0"		;;  Цвет фона некоторых абзацев
	, ColorDelimiter := "E14B30"			;;  Цвет шрифта разделителя заголовков и параметров
	, ColorTitle := "27419B"				;;  Цвет шрифта заголовка
	, ColorLineTitles := "444499"			;;  Цвет линии заголовка
	, ColorParam := "189200"				;;  Цвет шрифта параметров
	, ColorErrorAccPath := "ff0000"
	, ColorErrorAccMarquee := "ffcc00"
	, ColorErrorAccMarquee := "ffcc00"
	, ColorStyleComment1 := "f0f0f0"
	, ColorStyleComment2 := "C0C0C0" 
	, ColorSelectedFind := "6666FF" 
	, ColorBorderHoverInput := "4A8DFF"
	, ColorPreOverflowHide := "E2E2E2" 
	, ColorScrollArrows := "686868" 
	, ColorScrollBack := "F0F0F0" 
	, ColorScrollFace := "CDCDCD" 
	, ColorStyleNoApply := ColorStyleComment2 
}
Else 
{
	Global ColorFont := "FFFFFF"			;;  Цвет шрифта
	, ColorBg := "000000"					;;  Цвет фона          "F0F0F0" E4E4E4     F8F8F8  
	, ColorBgPaused := "080808"				;;  Цвет фона при паузе     F0F0F0
	, ColorBgModeButton := "000000"			;;  000000
	, ColorSelModeButton := "469EE1"		;;  Цвет фона кнопки текущего режима
	, ColorSelMouseHover := "FDE182"		;;  Цвет фона элемента при наведении мыши     96C3DC F9D886 8FC5FC AEC7E1
	, ColorSelMouseHoverText := "000000"	;;  Цвет текста элемента при наведении мыши     96C3DC F9D886 8FC5FC AEC7E1
	, ColorSelButton := "693C23"			;;  Цвет фона при нажатии на кнопки
	, ColorSelAnchor := "E8BD7D"			;;  Цвет фона заголовка для якоря   E14B30
	, ColorHighLightBckg := "001F1F"		;;  Цвет фона некоторых абзацев
	, ColorDelimiter := "1EB4CF"			;;  Цвет шрифта разделителя заголовков и параметров
	, ColorTitle := "6BB1E7"				;;  Цвет шрифта заголовка   D8BE64
	, ColorLineTitles := "00FFFF"			;;  Цвет линии заголовка
	, ColorParam := "8EC461"				;;  Цвет шрифта параметров   E76DFF
	, ColorErrorAccPath := "00FFFF"
	, ColorErrorAccMarquee := "0033FF"
	, ColorErrorAccMarquee := "0033FF"
	, ColorStyleComment1 := "0F0F0F"
	, ColorStyleComment2 := "3F3F3F" 
	, ColorSelectedFind := "999900" 
	, ColorBorderHoverInput := "B57200"
	, ColorPreOverflowHide := "1D1D1D" 
	, ColorScrollArrows := "979797" 
	, ColorScrollBack := "0F0F0F" 
	, ColorScrollFace := "323232" 
	, ColorStyleNoApply := "E56749" 
}
Global ColorBgOriginal := ColorBg

Global ThisMode := IniRead("StartMode", "Control"), LastModeSave := (ThisMode = "LastMode")
, ThisMode := ThisMode = "LastMode" ? IniRead("LastMode", "Control") : ThisMode, CheckAhkNewVersion := IniRead("CheckAhkNewVersion", 0) 
, ActiveNoPause := IniRead("ActiveNoPause", 0), MemoryPos := IniRead("MemoryPos", 0), MemorySize := IniRead("MemorySize", 0)
, MemoryZoomSize := IniRead("MemoryZoomSize", 0), MemoryStateZoom := IniRead("MemoryStateZoom", 0), StateLight := IniRead("StateLight", 1)
, StateLightAcc := IniRead("StateLightAcc", 1), SendCode := IniRead("SendCode", "vk"), StateLightMarker := IniRead("StateLightMarker", 1)
, StateUpdate := IniRead("StateUpdate", 0), SendMode := IniRead("SendMode", "send"), SendModeStr := Format("{:L}", SendMode)
, AnchorFullScroll := IniRead("AnchorFullScroll", 1), MemoryAnchor := IniRead("MemoryAnchor", 1), MenuIdView := IniRead("MenuIdView", 0)
, StateAllwaysSpot := IniRead("AllwaysSpot", 0), w_ShowStyles := IniRead("w_ShowStyles", 0), MarkerInvertFrame := IniRead("MarkerInvertFrame", 1)
, c_ShowStyles := IniRead("c_ShowStyles", 0), ViewStrPos := IniRead("ViewStrPos", 0), OnlyShiftTab := IniRead("OnlyShiftTab", 0)
, view_control_child := IniRead("view_control_child", 0), gLocalData, gLocalOpen := {Control:[], Win:[]}
, WordWrap := IniRead("WordWrap", 0), PreMaxHeightStr := IniRead("MaxHeightOverFlow", "1 / 3"), UpdRegister := IniRead("UpdRegister2", 0)
, UseUIA := IniRead("UseUIA", 0), UIAAlienDetect := IniRead("UIAAlienDetect", 0), MinimizeEscape := IniRead("MinimizeEscape", 0)
, DetectHiddenText := IniRead("DetectHiddenText", "on"), MoveTitles := IniRead("MoveTitles", 1), DynamicAccPath := IniRead("DynamicAccPath", 0)
, DynamicControlPath := IniRead("DynamicControlPath", 0), ActiveScriptAllowChange := IniRead("ActiveScriptAllowChange", 1)

, UpdRegisterLink := "https://u.to/zeONFA", testvar, oDivOld, oDivNew, DivWorkIndex := 2, oDivWork1, oDivWork2

, FontDPI := {96:12,120:10,144:8,168:6}[A_ScreenDPI], ScrollPos := {}, AccCoord := [], oOther := {}
, oFind := {}, Edits := [], oMS := {}, oMenu := {}, oPubObj := {}, osCoords := {}

, ClipAdd_Before := 0, ClipAdd_Delimiter := "`r`n"
, HTML_Win, HTML_Control, HTML_Hotkey, rmCtrlX, rmCtrlY, widthTB, FullScreenMode, hColorProgress, hFindAllText, MsgAhkSpyZoom
, hGui, hTBGui, hActiveX, hFindGui, oDoc, ShowMarker, isFindView, isIE, isPaused, PreMaxHeight := MaxHeightStrToNum()
, PreOverflowHide := !!PreMaxHeight, DecimalCode, GetVKCodeNameStr, GetSCCodeNameStr
, oPubObjGUID, oObjActive := {}, oJScript, oBody, isConfirm, isAhkSpy := 1, TitleText, FreezeTitleText, TitleTextP1, exUIASub
, Shift_Tab_Down, hButtonButton, hButtonControl, hButtonWindow
, TitleTextP2 := TitleTextP2_Reserved := "     (  Shift+Tab:信息固定|右键:复制|Pause:暂停 )     v" AhkSpyVersion
, Sleep, oShowMarkers, oShowAccMarkers, oShowMarkersEx, hDCMarkerInvert, hMarkerGui

#Include *i %A_AppData%\AhkSpy\IncludeSettings.ahk

Global _S1 := "<span>", _S2 := "</span>", _DB := "<span style='position: relative; margin-right: 1em;'></span>"

, _BT1 := "<span class='button' unselectable='on' oncontextmenu='return false' contenteditable='false' ", _BT2 := "</span>"

  ;;	Решает проблему запуска ресайза кнопки когда выделен текст, но не получается установить свой курсор
, _BP1 := "<span contenteditable='false'><span class='button' unselectable='on' oncontextmenu='return false'"
	. " contenteditable='false' style='color: #" ColorParam "' name='pre' ", _BP2 := "</span></span>"
, _BPE1 := "<span contenteditable='false'><span class='button' unselectable='on' oncontextmenu='return false'"
	. " contenteditable='false' style='color: #" ColorStyleNoApply "' name='pre' ", _BPE2 := "</span></span>"
	
  ;;	Прежнее
; , _BP1 := "<span contenteditable='false' oncontextmenu='return false' class='BB'>" _BT1 "style='color: #" ColorParam "' name='pre' ", _BP2 := "</span></span>"

, _BB1 := "<span contenteditable='false' oncontextmenu='return false' class='BB' style='height: 0px;'>" _BT1 " ", _BB2 := "</span></span>"
, _T1 := "<span class='box'><span class='line'><span class='hr'></span><span class='con'><span class='title' ", _T2 := "</span></span></span><br>"
, _T1P := " style='color: #" ColorParam "' "
, _T0 := "<span class='box'><span class='hr'></span></span><span id='id_T0' style='position: absolute'></span>"
, _PRE1 := "<pre contenteditable='true'>", _PRE2 := "</pre>"
, _LPRE := "<pre contenteditable='true' class='lpre'", _PRE := "<pre contenteditable='true' "
, _DP := "  <span style='color: #" ColorDelimiter "'>&#9642</span>  "
, _DP2 := "  <span style='color: #" ColorDelimiter "' name='MS:P'>&#9642</span>  "
, _StIf := "    <span class='QStyle1'>&#9642</span>    <span class='QStyle2' name='MS:'>"
, _BR := "<p class='br'></p>", _DN := "`n", _DN2 := "<div style='height: 0.50em`;'></div>" 

, _PreOverflowHideCSS := ".lpre {max-width: 99`%; max-height: " PreMaxHeight "px; overflow: auto; border: 1px solid #" ColorPreOverflowHide ";}"

, _BodyWrapCSS := "body, .divwork {word-wrap: break-word`; overflow-x: 'hidden';} .lpre {overflow-x: hidden`;}"

, _ButAccViewer := ExtraFile("AccViewer Source") ? _DB _BT1 " id='run_AccViewer'> run accviewer " _BT2 : ""
, _ButiWB2Learner := ExtraFile("iWB2 Learner") ? _DB _BT1 " id='run_iWB2Learner'> run iwb2 learner " _BT2 : ""
, _ButWindow_Detective := FileExist(Path_User "\Window Detective.lnk") ? _DB _BT1 " id='run_Window_Detective'> run window detective " _BT2 : ""
, oZBID := {0:"ZBID_DEFAULT",1:"ZBID_DESKTOP",2:"ZBID_UIACCESS",3:"ZBID_IMMERSIVE_IHM",4:"ZBID_IMMERSIVE_NOTIFICATION",5:"ZBID_IMMERSIVE_APPCHROME"
	,6:"ZBID_IMMERSIVE_MOGO",7:"ZBID_IMMERSIVE_EDGY",8:"ZBID_IMMERSIVE_INACTIVEMOBODY",9:"ZBID_IMMERSIVE_INACTIVEDOCK"
	,10:"ZBID_IMMERSIVE_ACTIVEMOBODY",11:"ZBID_IMMERSIVE_ACTIVEDOCK",12:"ZBID_IMMERSIVE_BACKGROUND",13:"ZBID_IMMERSIVE_SEARCH"
	,14:"ZBID_GENUINE_WINDOWS",15:"ZBID_IMMERSIVE_RESTRICTED",16:"ZBID_SYSTEM_TOOLS",17:"ZBID_LOCK",18:"ZBID_ABOVELOCK_UX"}
	
If UseUIA
	exUIASub := new UIASub

BLGroup := ["Backlight allways","Backlight disable","Backlight hold shift button"]
oOther.anchor := {}, oOther.CurrentProcessId := DllCall("GetCurrentProcessId")

If MemoryAnchor
{
	If oOther.anchor["Win_text"] := IniRead("Win_Anchor")
		oOther.anchor["Win"] := 1
	If oOther.anchor["Control_text"] := IniRead("Control_Anchor")
		oOther.anchor["Control"] := 1
} 



FixIE()
SeDebugPrivilege() 
OnExit("Exit")

CreateMarkerInvert()
ShowMarkersCreate("oShowAccMarkers", "26419F")  
ShowMarkersCreate("oShowMarkers", "E14B30")

Gui, +AlwaysOnTop +HWNDhGui +ReSize -DPIScale +E%WS_EX_APPWINDOW%  ;   +E%WS_EX_NOACTIVATE%;  +Owner%hMarkerGui%
Gui, Color, %ColorBgPaused%
ActiveScriptAllow() 
Gui, Add, ActiveX, Border voDoc HWNDhActiveX x0 y+0, HTMLFile
ActiveScriptAllow(1)

;	https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.htmlwindow?view=netframework-4.8
;	https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model

LoadJScript()
oBody := oDoc.body 
oJScript := oDoc.Script
oJScript.WordWrap := WordWrap
oJScript.MoveTitles := MoveTitles
ComObjConnect(oDoc, Events)

OnMessage(0x133, "WM_CTLCOLOREDIT")
OnMessage(0x201, "WM_LBUTTONDOWN") 
OnMessage(0x204, "WM_RBUTTONDOWN") 
OnMessage(0x7B, "WM_CONTEXTMENU")
OnMessage(0xA1, "WM_NCLBUTTONDOWN")
OnMessage(0x6, "WM_ACTIVATE")
OnMessage(0x47, "WM_WINDOWPOSCHANGED")
OnMessage(0x4a, "WM_COPYDATA")   

;; OnMessage(WM_WINDOWPOSCHANGING := 0x46, "WM_WINDOWPOSCHANGED") 
;; OnMessage(WM_MOVING := 0x216, "WM_WINDOWPOSCHANGED")
;; OnMessage(WM_MOVE := 0x03, "WM_WINDOWPOSCHANGED")

OnMessage(MsgAhkSpyZoom := DllCall("RegisterWindowMessage", "Str", "MsgAhkSpyZoom"), "MsgZoom")
DllCall("PostMessage", "UPtr", A_ScriptHWND, "UInt", 0x50, "UInt", 0,	 "UInt", 0x409) ;; eng layout
SetWinEventHook("EVENT_OBJECT_CLOAKED", 0x8017)
SetWinEventHook("EVENT_OBJECT_UNCLOAKED", 0x8018) 

Gui, TB: +HWNDhTBGui -Caption -DPIScale +Parent%hGui% +%WS_CHILDWINDOW% -%WS_POPUP% +E%WS_EX_NOACTIVATE%
Gui, TB: Color, %ColorBg%
Gui, TB: Font, % " s" FontDPI, Verdana

Gui, TB: Add, Progress, % "  x1 y0 h" HeigtButton-1 " w" wKey "  vColor_Window Background" ColorBgModeButton  
Gui, TB: Add, Text, % "Border hwndhButtonWindow +0x201 c" ColorFont " BackGroundTrans xp yp hp wp", 窗口

Gui, TB: Add, Progress, % "x+1 y0 h" HeigtButton-1 " w" wKey " vColor_Control Background" ColorBgModeButton  
Gui, TB: Add, Text, % "Border hwndhButtonControl +0x201 c" ColorFont " BackGroundTrans xp yp hp wp", 控件

Gui, TB: Add, Progress, % "x+1 y0 h" HeigtButton-1 " w" HeigtButton " vColor_Zoom Background" ColorBgModeButton  
Gui, TB: Add, Text, % "Border hwndhButtonZoom +0x201 c" ColorFont " BackGroundTrans xp yp hp wp", % Chr("0x1F50D") ; 🔍

Gui, TB: Add, Progress, % "x+1 y0 h" HeigtButton-1 " w" wColor " vColorProgress HWNDhColorProgress c" ColorBgOriginal, 100

Gui, TB: Add, Progress, % "x+1 y0 h" HeigtButton-1 " w" wKey " vColor_Button Background" ColorBgModeButton  
Gui, TB: Add, Text, % "Border hwndhButtonButton +0x201 c" ColorFont " BackGroundTrans xp yp hp wp", 按键

Gui, TB: Show, % "x0 y0 NA h" HeigtButton " w" widthTB := wKey * 3 + wColor + HeigtButton + 6

Gui, F: +HWNDhFindGui -Caption -DPIScale +Parent%hGui% +%WS_CHILDWINDOW% -%WS_POPUP%
Gui, F: Color, %ColorBgPaused%
Gui, F: Font, % " s" FontDPI
Gui, F: Add, Edit, x1 y0 w180 h26 gFindNew WantTab HWNDhFindEdit
SendMessage, 0x1501, 1, "Find to page",, ahk_id %hFindEdit%   ;; EM_SETCUEBANNER
Gui, F: Add, UpDown, -16 Horz Range0-1 x+0 yp h26 w52 gFindNext vFindUpDown
GuiControl, F: Move, FindUpDown, h26 w52
Gui, F: Font, % " s" FontDPI
; 0x201 CENTER wh
Gui, F: Add, Text, x+10 yp+1 h24 +0x201 gFindOption c%ColorFont%, % " case sensitive "
Gui, F: Add, Text, x+10 yp hp +0x201 gFindOption c%ColorFont%, % " whole word "
; BS_VCENTER := 0xC00, BS_CENTER := 0x300
Gui, F: Add, Button, % "+0x300 +0xC00 yp hp w20 gFindHide x" widthTB - 21 c%ColorFont%, X   
Gui, F: Add, Text, x+10 yp hp +0x201 w152 vFindMatches Left HWNDhFindAllText c%ColorFont%

	; ___________________________ Menu Create _________________________________________________

Menu, Sys, Add, % name := "一直背光", % oMenu.Sys[name] := "_Sys_Backlight"
Menu, Sys, Add, % name := "按住shift按键时背光", % oMenu.Sys[name] := "_Sys_Backlight"
Menu, Sys, Add, % name := "禁用背光", % oMenu.Sys[name] := "_Sys_Backlight"
Menu, Sys, Check, % BLGroup[StateLight]
Menu, Sys, Add
Menu, Sys, Add, % name := "窗口或控件背光", % oMenu.Sys[name] := "_Sys_WClight"
Menu, Sys, % StateLightMarker ? "Check" : "UnCheck", % name
Menu, Sys, Add, % name := "Acc 对象背光", % oMenu.Sys[name] := "_Sys_Acclight"
Menu, Sys, % StateLightAcc ? "Check" : "UnCheck", % name
Menu, Sys, Add
Menu, Sys, Add, % name := "一起Spot (低速)", % oMenu.Sys[name] := "_Spot_Together"
Menu, Sys, % StateAllwaysSpot ? "Check" : "UnCheck", % name
Menu, Sys, Add, % name := "使用活动窗口", % oMenu.Sys[name] := "_Active_No_Pause"
Menu, Sys, % ActiveNoPause ? "Check" : "UnCheck", % name
Menu, Sys, Add, % name := "仅Shift+Tab时Spot", % oMenu.Sys[name] := "_OnlyShiftTab"
Menu, Sys, % OnlyShiftTab ? "Check" : "UnCheck", % name

If !A_IsCompiled
{
	Menu, Sys, Add
	Menu, Sys, Add, % name := "检查更新", % oMenu.Sys[name] := "_CheckUpdate"
	Menu, Sys, % StateUpdate ? "Check" : "UnCheck", % name
	If StateUpdate
		SetTimer, UpdateAhkSpy, -1000
}
Else
	StateUpdate := 0

Menu, Sys, Add
Menu, Startmode, Add, % name := "窗口", % oMenu.Startmode[name] := "_SelStartMode"
Menu, Startmode, Add, % name := "控件", % oMenu.Startmode[name] := "_SelStartMode"
Menu, Startmode, Add, % name := "按键", % oMenu.Startmode[name] := "_SelStartMode"
Menu, Startmode, Add
Menu, Startmode, Add, % name := "上一个模式", % oMenu.Startmode[name] := "_SelStartMode"

Menu, View, Add, % name := "动态控件路径(低速)", % oMenu.View[name] := "_DynamicControlPath"
Menu, View, % DynamicControlPath ? "Check" : "UnCheck", % name
Menu, View, Add, % name := "动态acc路径 (低速,不推荐)", % oMenu.View[name] := "_DynamicAccPath"
Menu, View, % DynamicAccPath ? "Check" : "UnCheck", % name
Menu, View, Add
Menu, View, Add, % name := "使用UI自动化界面", % oMenu.View[name] := "_UseUIA"
Menu, View, % UseUIA ? "Check" : "UnCheck", % name
Menu, View, Add, % name := "UIA根据hwnd改变不同的背景", % oMenu.View[name] := "_UIAAlienDetect"
Menu, View, % UIAAlienDetect ? "Check" : "UnCheck", % name  
Menu, View, Add  
Menu, View, Add, % name := "暗主题 (需要重启)", % oMenu.View[name] := "_DarkTheme"
Menu, View, % DarkTheme ? "Check" : "UnCheck", % name 
Menu, View, Add, % name := "粗体 (需要重启)", % oMenu.View[name] := "_FontBold"
Menu, View, % FontBold ? "Check" : "UnCheck", % name 
Menu, View, Add, % name := "自动换行", % oMenu.View[name] := "_WordWrap"
Menu, View, % WordWrap ? "Check" : "UnCheck", % name
Menu, View, Add, % name := "视图坐标字符串扩展", % oMenu.View[name] := "_ViewStrPos"
Menu, View, % ViewStrPos ? "Check" : "UnCheck", % name
Menu, View, Add, % name := "闪烁边框", % oMenu.View[name] := "_MarkerInvertFrame"
Menu, View, % MarkerInvertFrame ? "Check" : "UnCheck", % name
Menu, View, Add, % name := "带有锚点的全滚动条", % oMenu.View[name] := "_AnchorFullScroll"
Menu, View, % AnchorFullScroll ? "Check" : "UnCheck", % name  
Menu, View, Add, % name := "移动的标题", % oMenu.View[name] := "_MoveTitles"
Menu, View, % MoveTitles ? "Check" : "UnCheck", % name
Menu, Sys, Add, 视图设置, :View

Menu, Overflow, Add, % name := "关掉", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 1", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 2", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 3", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 4", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 5", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 6", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 8", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 10", % oMenu.Overflow[name] := "_MenuOverflowLabel"
Menu, Overflow, Add, % name := "1 / 15", % oMenu.Overflow[name] := "_MenuOverflowLabel" 
Menu, Overflow, Check, %PreMaxHeightStr%
; Menu, Overflow, Color, % ColorBgOriginal
Menu, View, Add, Big text overflow hide, :Overflow

Menu, Sys, Add, 启动模式, :Startmode
Menu, Startmode, Check, % {"Win":"Window","Control":"Control","Hotkey":"Button","LastMode":"Last Mode"}[IniRead("StartMode", "Control")]

Menu, Script, Add, Reload, Reload
Menu, Script, Add, Exit, Exit
Menu, Script, Add
Menu, Script, Add, % name := "Open script dir", % oMenu.Script[name] := "Help_OpenScriptDir"
Menu, Script, Add, % name := "Open user dir", % oMenu.Script[name] := "Help_OpenUserDir"
Menu, Script, Add
Menu, Script, Add, % name := "记住位置", % oMenu.Script[name] := "_MemoryPos"
Menu, Script, % MemoryPos ? "Check" : "UnCheck", % name
Menu, Script, Add, % name := "记住大小", % oMenu.Script[name] := "_MemorySize"
Menu, Script, % MemorySize ? "Check" : "UnCheck", % name
Menu, Script, Add, % name := "记住字体大小", % oMenu.Script[name] := "_MemoryFontSize"
Menu, Script, % MemoryFontSize ? "Check" : "UnCheck", % name
Menu, Script, Add, % name := "记住缩放状态", % oMenu.Script[name] := "_MemoryStateZoom"
Menu, Script, % MemoryStateZoom ? "Check" : "UnCheck", % name
Menu, Script, Add, % name := "记住缩放大小", % oMenu.Script[name] := "_MemoryZoomSize"
Menu, Script, % MemoryZoomSize ? "Check" : "UnCheck", % name
Menu, Script, Add, % name := "记住锚点", % oMenu.Script[name] := "_MemoryAnchor"
Menu, Script, % MemoryAnchor ? "Check" : "UnCheck", % name
Menu, Script, Add
Menu, Script, Add, % name := "Active script allow change", % oMenu.Script[name] := "_ActiveScriptAllowChange"
Menu, Script, % ActiveScriptAllowChange ? "Check" : "UnCheck", % name 
Menu, Script, Add, % name := "Esc-最小化", % oMenu.Script[name] := "_MinimizeEscape"
Menu, Script, % MinimizeEscape ? "Check" : "UnCheck", % name 
Menu, Sys, Add, Script, :Script

Menu, Help, Add, % name := "Check updates AutoHotkey", % oMenu.Help[name] := "_CheckAhkNewVersion"
Menu, Help, % CheckAhkNewVersion ? "Check" : "UnCheck", % name
If CheckAhkNewVersion
	SetTimer, CheckAhkNewVersion, -3000 
Menu, Help, Add
If FileExist(SubStr(A_AhkPath,1,InStr(A_AhkPath,"\",,0,1)) "AutoHotkey.chm")
	Menu, Help, Add, % name := "AutoHotKey 帮助文档", % oMenu.Help[name] := "LaunchHelp"
Menu, Help, Add, % name := "AutoHotKey 官方在线帮助文档", % oMenu.Help[name] := "Sys_Help"
Menu, Help, Add, % name := "AutoHotKey 俄与帮助文档", % oMenu.Help[name] := "Sys_Help"
Menu, Help, Add
Menu, Help, Add, % name := "关于", % oMenu.Help[name] := "Sys_Help"
Menu, Help, Add, % name := "英版关于", % oMenu.Help[name] := "Sys_Help"
Menu, Sys, Add, 帮助, :Help

Menu, Sys, Add
Menu, Sys, Add, % name := "暂停", % oMenu.Sys[name] := "_PausedScript"
Menu, Sys, Add, % name := "暂停热键", % oMenu.Sys[name] := "_Suspend"
Menu, Sys, Add, % name := "默认大小", % oMenu.Sys[name] := "DefaultSize"
Menu, Sys, Add, % name := "全屏", % oMenu.Sys[name] := "FullScreenMode"
Menu, Sys, Add, % name := "找到页面", % oMenu.Sys[name] := "_FindView"


Menu, Sys, Add
Menu, Sys, Add, Open window from clipboard, Menu_LocalOpenWin
Menu, Sys, Add, Open control from clipboard, Menu_LocalOpenChild


; Menu, Sys, Color, % ColorBgOriginal

#Include *i %A_AppData%\AhkSpy\Include.ahk  ;;	Для продолжения выполнения кода используйте GoTo IncludeLabel
IncludeLabel:

Gui, Show, % "NA " (MemoryPos ? " x" IniRead("MemoryPosX", "Center") " y" IniRead("MemoryPosY", "Center") : "")
. (MemorySize ? " h" IniRead("MemorySizeH", HeightStart) " w" IniRead("MemorySizeW", widthTB) : " h" HeightStart " w" widthTB)
Gui, % "+MinSize" widthTB "x" 313

If ThisMode = Hotkey
	Gui, Show
Gosub, Mode_%ThisMode%

Hotkey_Init("Write_HotkeyHTML", "MLRJ")
 
If (MemoryStateZoom && IniRead("ZoomShow", 0))
	AhkSpyZoomShow()
	
WinGetPos, WinX, WinY, WinWidth, WinHeight, ahk_id %hGui%
If !DllCall("WindowFromPoint", "Int64", WinX & 0xFFFFFFFF | WinY << 32)
&& !DllCall("WindowFromPoint", "Int64", (WinX + WinWidth) & 0xFFFFFFFF | (WinY) << 32)
&& !DllCall("WindowFromPoint", "Int64", (WinX + WinWidth) & 0xFFFFFFFF | (WinY + WinHeight) << 32)
&& !DllCall("WindowFromPoint", "Int64", (WinX) & 0xFFFFFFFF | (WinY + WinHeight) << 32)
	Gui, Show, NA xCenter yCenter

If !UpdRegister
	SetTimer, UpdRegister, -1000 
	
WinSet, TransParent, 255, ahk_id %hGui%
DllCall("RedrawWindow", "UPtr", hGui, "Uint", 0, "Uint", 0, "Uint", 0x1|0x4)

; MsgBox % oDoc.documentMode  "`n" oDoc.compatMode  "`n" oDoc.designMode := "On"
Return 

	; ___________________________ Hotkey`s _________________________________________________

#If isAhkSpy && Sleep != 1 && OnlyShiftTab && !ActiveNoPause && !isPaused && ThisMode != "Hotkey" && IsHwndUnderMouse(hColorProgress) && !WinActive("ahk_id" hGui)

MButton:: SetTimer(Func("WM_RBUTTONDOWN").Bind(0, 0, 0, hColorProgress), "-" 1)  ; WM_RBUTTONDOWN(0, 0, 0, hColorProgress)

#If isAhkSpy && Sleep != 1 && OnlyShiftTab && !ActiveNoPause && !isPaused && ThisMode != "Hotkey" && IsHwndUnderMouse(hColorProgress)

MButton::
+MButton::
+RButton:: SetTimer(Func("WM_RBUTTONDOWN").Bind(0, 0, 0, hColorProgress), "-" 1)  ; WM_RBUTTONDOWN(0, 0, 0, hColorProgress)

#If Shift_Tab_Work

+Tab:: Return

#If isAhkSpy && Sleep != 1 && ActiveNoPause

+Tab:: Goto PausedScript

#If (isAhkSpy && Sleep != 1 && !isPaused && ThisMode != "Hotkey")

^Tab:: 
	If OnlyShiftTab 
		OnlyShiftTab := 0, oOther.OnlyShiftTabReset := 1 
	TransParent(0) 
	SetTimer, Mod_Up_Wait_And_TransParent, -1
	
+Tab:: 
SpotProc:
SpotProc2:  
	Shift_Tab_Work := 1 
	If (A_ThisHotkey != "")
		Shift_Tab_Down := 1 
	If (ThisMode = "Control")
		Spot_Control() && (Write_Control(), (StateAllwaysSpot ? Spot_Win() : 0))
	Else 
		Spot_Win() && (Write_Win(), (StateAllwaysSpot ? Spot_Control() : 0))
	If (!WinActive("ahk_id" hGui) && A_ThisLabel != "SpotProc2" && !OnlyShiftTab && !oOther.OnlyShiftTabReset)
	{
		WinActivate ahk_id %hGui%
		GuiControl, 1:Focus, oDoc
	}
	Else
		ZoomMsg(3)
	KeyWait, Tab, T0.1
	Sleep(10)
	Shift_Tab_Work := 0
	Return
	

#Tab Up::
F8 Up:: ChangeMode()

#If isAhkSpy && (StateLight = 3 || Shift_Tab_Down)

~*RShift Up::
~*LShift Up:: 
ShiftUpHide:
	HideAllMarkers(), Shift_Tab_Down := 0, CheckHideMarker()
	Return

#If isAhkSpy && Sleep != 1

Break::
Pause::
PausedScript:
_PausedScript:
	If isConfirm
		Return
	isPaused := !isPaused
	Try SetTimer, Loop_%ThisMode%, % isPaused ? "Off" : "On"
	ZoomMsg(2, isPaused)
	ColorBg := isPaused ? ColorBgPaused : ColorBgOriginal
	oBody.style.backgroundColor := "#" ColorBg
	ChangeCSS("css_ColorBg", ".title, .button, .divwork {background-color: #" ColorBg ";}")
	If (ThisMode = "Hotkey" && WinActive("ahk_id" hGui))
		Hotkey_Hook(!isPaused)
	If (isPaused && !WinActive("ahk_id" hGui))
		(ThisMode = "Control" ? Spot_Win() : ThisMode = "Win" ? Spot_Control() : 0)
	HideAllMarkers(), CheckHideMarker()
	Menu, Sys, % (isPaused ? "Check" : "UnCheck"), Pause
	isPaused ? TaskbarProgress(4, hGui, 100) : TaskbarProgress(0, hGui)
	TitleText := (TitleTextP1 := "AhkSpy - " ({"Win":"Window","Control":"Control","Hotkey":"Keys"}[ThisMode]))
	. (TitleTextP2 := (isPaused ? "                Paused..." : TitleTextP2_Reserved))
	SendMessage, 0xC, 0, &TitleText, , ahk_id %hGui%
	PausedTitleText()
	Return

#If isAhkSpy && Sleep != 1 && WinActive("ahk_id" hGui)

^WheelUp::
^WheelDown::
	FontSize := InStr(A_ThisHotkey, "Up") ? ++FontSize : --FontSize
	FontSize := FontSize < 10 ? 10 : FontSize > 64 ? 64 : FontSize 
	oDivWork1.Style.fontSize := FontSize "px"
	oDivWork2.Style.fontSize := FontSize "px"
	TitleText("文字大小: " FontSize)
	If MemoryFontSize
		IniWrite(FontSize, "FontSize") 
	SetTimer, AnchorScroll, -500
	Return

F1::
+WheelUp:: NextLink("-")

F2::
+WheelDown:: NextLink()

F3::
~!WheelUp:: WheelLeft

F4::
~!WheelDown:: WheelRight

F5:: Write_%ThisMode%()		;;  Return original HTML

F6::
^vk46:: _FindView()											;;  Ctrl+F

F7:: AnchorScroll()

F11:: 
	If oOther.ZoomShow && UnderControl(oOther.hZoomLW)
		Return
	FullScreenMode()
	Return

F12:: 
	If oOther.ZoomShow && UnderControl(oOther.hZoomLW)
		Return
	MouseGetPosScreen(x, y), ShowSys(x + 5, y + 5)
	Return

!Space:: SetTimer, ShowSys, -1

Esc::
	; oObjActive.ZoomMaximize
	If isFindView
		FindHide()
	Else If FullScreenMode
		FullScreenMode()
	Else
		GuiClose() 
	Return

+#Tab:: AhkSpyZoomShow()

#If isAhkSpy && Sleep != 1 && IsIEFocus() && (oDoc.selection.createRange().parentElement.isContentEditable)

^+vk41:: oDoc.execCommand("SelectAll")							;;  Ctrl+Shift+A

#If isAhkSpy && Sleep != 1 && IsIEFocus()

^vk41:: R := oBody.createTextRange(), R.moveToElementText(oDivNew), R.select()		;;  Ctrl+A
; ^vk41:: oBody.createTextRange().select()										;;  Ctrl+A

^vk5A:: oDoc.execCommand("Undo")							;;  Ctrl+Z

^vk59:: oDoc.execCommand("Redo")							;;  Ctrl+Y

^vk43:: GetSelected(CopyText) && ((Clipboard := CopyText), ToolTip("copy", 300))		;;  Ctrl+C

^vk56:: ClipPaste()																		;;  Ctrl+V

^vk58:: CutSelection()								;;  Ctrl+X

Del:: DeleteSelection()							;;  Delete

Tab:: PasteStrSelection("    ")							;;  &emsp	"	"  PasteStrSelection("	")

Enter:: PasteHTMLSelection("<br>")

#If isAhkSpy && Sleep != 1 && ThisMode != "Hotkey" && (IsIEFocus() || MS_IsSelection())

#RButton:: ClipPaste()

#If isAhkSpy && Sleep != 1 && ThisMode != "Hotkey" && (IsIEFocus() || MS_IsSelection()) && IsTextArea() && GetSelected(CopyText)

RButton::
^RButton::
	If (A_ThisHotkey = "^RButton")
		CopyText := CopyCommaParam(CopyText)
	Clipboard := CopyText
	ToolTip("copy", 300)
	Return

+RButton:: ClipAdd(CopyText, 1)
^+RButton:: ClipAdd(CopyCommaParam(CopyText), 1)

#If isAhkSpy && Sleep != 1 && ThisMode = "Hotkey" && (IsIEFocus() || MS_IsSelection()) && IsTextArea() && GetSelected(CopyText) ;;	Mode = Hotkey

RButton::
	KeyWait, RButton, T0.3
	If ErrorLevel
		ClipAdd(CopyText, 1)
	Else
		Clipboard := CopyText, ToolTip("copy", 300)
	Return

#If (isAhkSpy && Sleep != 1 && !isPaused && ThisMode != "Hotkey")

+#Up:: MouseStep(0, -1)
+#Down:: MouseStep(0, 1)
+#Left:: MouseStep(-1, 0)
+#Right:: MouseStep(1, 0)
^+#Up:: MouseStep(0, -10)
^+#Down:: MouseStep(0, 10)
^+#Left:: MouseStep(-10, 0)
^+#Right:: MouseStep(10, 0)

#If oJScript.ButtonOver

+LButton::
	oJScript.onmousedown(oJScript.ButtonOver)
	KeyWait LButton
	if !oJScript.ButtonOver
		return 
	obj := Func("ButtonClick").Bind(oJScript.ButtonOver)
	SetTimer, % obj, -100
	; ButtonClick(oJScript.ButtonOver)
	oJScript.onmouseup(oJScript.ButtonOver, 1)
	Return

#If !WinActive("ahk_id" hGui) && IsAhkSpyUnderMouse(hc)

+LButton::  
	If (hc = hButtonButton)
		SetTimer("Mode_Hotkey", -1)
	Else If (hc = hButtonControl)
		SetTimer("Mode_Control", -1)
	Else If (hc = hButtonWindow)
		SetTimer("Mode_Win", -1) 
	Else If (hc = hButtonZoom) 
		SetTimer("AhkSpyZoomShow", -1) 
	Return 
#If

IsAhkSpyUnderMouse(Byref hc) {
	MouseGetPos, , , hw, hc, 2
	Return (hw = hGui)
}

IsHwndUnderMouse(hwnd) {
	MouseGetPos, , , , hc, 2
	Return (hc = hwnd)
}
	; ___________________________ Mode_Win _________________________________________________
	
Mode_Win: 
	If A_GuiControl
		GuiControl, 1:Focus, oDoc
	ZoomMsg(10, 0)
	; oBody.createTextRange().execCommand("RemoveFormat")   
	ColorButton("Window") 
	
	If (ThisMode = "Hotkey")
		Hotkey_Hook(0)
		
	Try SetTimer, Loop_%ThisMode%, Off
	
	ScrollPos[ThisMode, 1] := oDivNew.scrollLeft
	ScrollPos[ThisMode, 2] := oDivNew.scrollTop
	
	If ThisMode != Win
		HTML_%ThisMode% := oDivNew.innerHTML, prNotThisMode := 1
		
	ThisMode := "Win"
	
	If (HTML_Win = "")
		Spot_Win(1)
	Write_Win(prNotThisMode) 
	
	TitleText := (TitleTextP1 := "AhkSpy - 窗口") . TitleTextP2
	SendMessage, 0xC, 0, &TitleText, , ahk_id %hGui%
	If isFindView
		FindNewText()
	

Loop_Win:
	If ((WinActive("ahk_id" hGui) && !ActiveNoPause) || Sleep = 1)
		GoTo Repeat_Loop_Win
	If !OnlyShiftTab && Spot_Win()
		Write_Win(), StateAllwaysSpot ? Spot_Control() : 0
Repeat_Loop_Win:
	If (!isPaused && ThisMode = "Win" && !OnlyShiftTab)
		SetTimer, Loop_Win, -%RangeTimer%
	Return 

Spot_Win(NotHTML = 0) {
	Static PrWinPID, ComLine, _ComLine, ProcessBitSize, IsAdmin, WinProcessPath, WinProcessName, ProcessUserName
	
	If NotHTML
		GoTo HTML_Win
	If !gLocalData
		MouseGetPos, , , WinID, hChild, 3
	Else {
		WinID := gLocalData.Win, hChild := gLocalData.Child
	}
	If (WinID = hGui || WinID = oOther.hZoom || WinID = oOther.hZoomLW)
		Return 0, HideAllMarkers()
		
	WinGetTitle, WinTitle, ahk_id %WinID%
	WinTitle := TransformHTML(WinTitle)
	WinGetPos, WinX, WinY, WinWidth, WinHeight, ahk_id %WinID%
	WinX2 := WinX + WinWidth - 1, WinY2 := WinY + WinHeight - 1
	WinGetClass, WinClass, ahk_id %WinID%
	oOther.WinClass := WinClass
	WinGet, WinPID, PID, ahk_id %WinID%
	If (WinPID != PrWinPID) {
		GetCommandLineProc(WinPID, _ComLine, ProcessBitSize, IsAdmin)
		ProcessUserName := GetProcessOwner(WinPID, "user")
		ComLine := TransformHTML(_ComLine), PrWinPID := WinPID
		WinGet, WinProcessPath, ProcessPath, ahk_id %WinID%
		Loop, %WinProcessPath%
			WinProcessPath = %A_LoopFileLongPath%
		SplitPath, WinProcessPath, WinProcessName
	}
	If (WinClass ~= "(Cabinet|Explore)WClass")
		CLSID := GetCLSIDExplorer(WinID)
	WinGet, WinCountProcess, Count, ahk_pid %WinPID%
	WinGet, WinStyle, Style, ahk_id %WinID%
	WinGet, WinExStyle, ExStyle, ahk_id %WinID% 
	{
		WinGet, WinTransparent, Transparent, ahk_id %WinID% 
		TransparentStr := _BP1 "id='set_button_Transparent'>Transparent:</span>" _BP2 "  <span id='get_win_Transparent' name='MS:'>"  (WinTransparent = "" ? "Off" : WinTransparent) "</span>"     
	
		WinGet, WinTransColor, TransColor, ahk_id %WinID% 
		TransColorStr := _BP1 "id='set_button_TransColor'>TransColor:</span>" _BP2 "  <span id='get_win_TransColor' name='MS:'>"  (WinTransColor = "" ? "Off" : WinTransColor) "</span>"
	
		OwnedId := DllCall("GetWindow", "UPtr", WinID, UInt, 4, "Ptr")
		If OwnedId
			OwnedIdStr := "<span class='param'>Owned Id:</span> <span name='MS:'>" Format("0x{:x}", OwnedId) "</span>"
			
		EX1Str := Add_DP(1, OwnedIdStr, TransparentStr, TransColorStr)
	} 
	WinGet, CountControl, ControlListHwnd, ahk_id %WinID%	
	If (CountControl != "")
		RegExReplace(CountControl, "m`a)$", "", CountControl)
	Else 
		CountControl := 0   
	GetClientPos(WinID, caX, caY, caW, caH)
	caWinRight := WinWidth - caW - caX , caWinBottom := WinHeight - caH - caY
	loop 1000
	{
		StatusBarGetText, SBFieldText, %A_Index%, ahk_id %WinID%
		if ErrorLevel
			Break
		(!sb_fields && sb_fields := []), sb_fields[A_Index] := SBFieldText
	}
	if sb_fields.maxindex()
	{
		while (sb_max := sb_fields.maxindex()) && (sb_fields[sb_max] = "")
			sb_fields.Delete(sb_max)
		for k, v in sb_fields
			SBText .= "<span class='param'>(" k "):</span> <span name='MS:' id='sb_field_" A_Index "'>" TransformHTML(v "") "</span>`n"
		If SBText !=
			SBText := _T1 " id='__StatusBarText'> ( 状态栏文本 ) </span>" _BT1 " id='copy_sbtext' name='" sb_max "'> 复制 " _BT2 _T2 _PRE1 "<span>" SBText "</span></span>" _PRE2
	}
	DetectHiddenText, % DetectHiddenText
	WinGetText, WinText, ahk_id %WinID%
	If WinText !=
		WinText := _T1 " id='__WindowText'> ( 窗口文本 ) </span><a></a>" _BT1 " id='copy_wintext'> 复制 " _BT2 _DB _BT1 " id='wintext_hidden'> hidden - " DetectHiddenText " " _BT2 _T2
		. _LPRE  "><pre id='wintextcon'>" TransformHTML(WinText) "</pre>" _PRE2
	MenuText := GetMenu(WinID)

	If ViewStrPos
		ViewStrPos1 := _DP "<span name='MS:'>" WinX ", " WinY ", " WinX2 ", " WinY2 "</span>" _DP "<span name='MS:'>" WinX ", " WinY ", " WinWidth ", " WinHeight "</span>"
 
	IsWindowUnicodeStr := _DP "<span class='param'>是否unicode:</span>  <span>" (DllCall("user32\IsWindowUnicode", "Ptr", WinID) ? "是" : "不是") "</span>"
	If (ProcessUserName != "")
		ProcessUserNameStr := _DP "<span class='param' name='MS:N'>User name:</span>  <span name='MS:'>" ProcessUserName "</span>"

	If !gLocalData
	{
		CoordMode, Mouse
		MouseGetPos, WinXS, WinYS, h 
	}
	Else { 
		h := WinID
		WinXS := WinX + WinWidth // 2, WinYS := WinY + WinHeight // 2
	}
	If (h = hGui || h = oOther.hZoom || h = oOther.hZoomLW)
		Return 0, HideAllMarkers()
		
	SetPosObject("Window", [WinX, WinY, WinWidth, WinHeight])   
	SetPosObject("Client", [WinX + caX, WinY + caY, caW, caH])   
	SetPosObject("AhkSpy", WinGetPosToArray(hActiveX))
	
	If !StateAllwaysSpot && !gLocalData
	{
		oObjActive.ScreenX := WinXS, oObjActive.ScreenY := WinYS
		PixelGetColor, ColorRGB, %WinXS%, %WinYS%, RGB
		GuiControl, TB: -Redraw, ColorProgress
		GuiControl, % "TB: +c" SubStr(ColorRGB, 3), ColorProgress
		GuiControl, TB: +Redraw, ColorProgress
	}
	If WinExist("ahk_class AutoHotkey ahk_pid" WinPID)
	{
		RegExMatch(StrReplace(_ComLine, WinProcessPath), "(.:\\([^""]+))", m)  ; "(.:[^:]+\\([^""]+))", m) 
		If (m1 != "")
			AhkScriptPAth := m1
		Else 
			AhkScriptPAth := WinProcessPath, IsAhkScriptExe := 1 
			
		AhkScriptStringCode := _T1 " id='__ahkscript'> ( AutoHotkey script " (IsAhkScriptExe ? "compiled" : "") ") </span>" _T2   
			. "<div>" _DN2 
			. (!IsAhkScriptExe ? _BP1 " id='ahkscript_edit'> edit " _BP2 _DB : "")
			. _BP1 " id='ahkscript_folder'> in folder " _BP2 _DB
			. _BP1 " id='ahkscript_copypath'> copy as file " _BP2 _DB
			. _BP1 " id='ahkscript_run'> run " _BP2 _DN2
			. _BP1 " id='ahkscript_suspend'> suspend " _BP2 _DB
			. _BP1 " id='ahkscript_pause'> pause " _BP2 _DB
			. _BP1 " id='ahkscript_reload'> reload " _BP2 _DB
			. _BP1 " id='ahkscript_exit'> exit " _BP2 _DN2
			. _BP1 " id='ahkscript_lines'> lines " _BP2 _DB
			. _BP1 " id='ahkscript_variables'> variables " _BP2 _DB
			. _BP1 " id='ahkscript_hotkeys'> hotkeys " _BP2 _DB
			. _BP1 " id='ahkscript_keyhistory'> key history " _BP2 _DN2 "</div>"
			. _PRE1 "<span id='ahkscriptpath' name='MS:'>" TransformHTML(AhkScriptPAth) "</span>" _PRE2
	}
	If (hParent := DllCall("GetAncestor", "UPtr", WinID, Uint, 1)) && (hParent != WinID)
	{
		WinGet, ParentProcessName, ProcessName, ahk_id %hParent% 
		WinGetClass, ParentClass, ahk_id %hParent%
		_ParentWindow := "`n<span class='param'>父窗口:</span>  <span name='MS:'>" ParentClass "</span>" 
			. _DP " <span name='MS:'>" ParentProcessName "</span>" _DP "<span name='MS:'>" Format("0x{:x}", hParent) "</span>"
	}
	DllCall("GetWindowBand", "Uptr", WinID, "uint*", band) 
	WindowBand := _DP "<span class='param'>WindowBand:</span>  <span name='MS:Q'>" oZBID[band] " := <span class='param' name='MS:'>" band "</span></span>"	

	; ___________________________ HTML_Win _________________________________________________

HTML_Win:
	If w_ShowStyles
		WinStyles := GetStyles(WinClass, WinStyle, WinExStyle, WinID)
		 
	If gLocalData
		back_openwin := _DB _BT1 " id='b_back_openwin'> return " _BT2
		
	HTML_Win := ""
	. _T1 " id='__Title'> ( 标题 ) </span>" _BT1 " id='pause_button'> 暂停 " _BT2 _T2  _BR 
	
	. _PRE1 "<span id='wintitle1' name='MS:'>" WinTitle "</span>" _PRE2 
	
	. _T1 " id='__Class'> ( 类 ) </span>" _T2 

	. _PRE1 "<span id='wintitle2'><span class='param' id='wintitle2_' name='MS:S'>ahk_class </span><span name='MS:'>" WinClass "</span></span>" _PRE2 
	
	. _T1 " id='__ProcessName'> ( 进程名 ) </span>" _BT1 " id='copy_alltitle'> 复制标题 " _BT2  _T2 
	
	. _PRE1 "<span id='wintitle3'><span class='param' name='MS:S' id='wintitle3_'>ahk_exe </span><span name='MS:'>" WinProcessName "</span></span>" _PRE2 
	
	. _T1 " id='__ProcessPath'> ( 进程路径 ) </span>" _BT1 " id='infolder'> 所在文件夹 " _BT2  _DB  _BT1 " id='paste_process_path'> 粘贴 " _BT2  _T2 
	
	. _PRE1 "<span><span class='param' name='MS:S'>ahk_exe </span><span id='copy_processpath' name='MS:'>" WinProcessPath "</span></span>" _PRE2 
	
	. _T1 " id='__CommandLine'> ( 命令行 ) </span>" _BT1 " id='w_command_line'> 启动 " _BT2  _DB  
		. _BT1 " id='paste_command_line'> 粘贴 " _BT2  _DB  _BT1 " id='clean_command_line'> 清理 " _BT2  _DB  _BT1 " id='command_line_infolder'> 所在文件夹 " _BT2  _T2 
	
	. _PRE1 "<span id='c_command_line' name='MS:'>" ComLine "</span>" _PRE2
	
	. AhkScriptStringCode
	
	. _T1 " id='__Position'> ( 位置 ) </span>" _T2 
	
	. _PRE1  _BP1 " id='set_button_pos'>位置:" _BP2 "  <span name='MS:'>x" WinX " y" WinY "</span>" 
		. _DP "<span name='MS:'>x²" WinX2 " y²" WinY2 "</span>"
		. _DP  _BP1 " id='set_button_pos'>大小:" _BP2 "  <span name='MS:'>w" WinWidth " h" WinHeight "</span>" ViewStrPos1 
	
	. "`n<span class='param'>客户区大小:</span>  <span name='MS:'>w" caW " h" caH "</span>" 
		. _DP "<span class='param'>左</span> " caX " <span class='param'>顶</span> " caY 
		. " <span class='param'>右</span> " caWinRight " <span class='param'>底</span> " caWinBottom  _PRE2 

	. _T1 " id='__Other'> ( 其他 ) </span>" _BT1 " id='flash_window'> 闪烁 " _BT2  _ButWindow_Detective  _T2 

	. _PRE1 "<span class='param' name='MS:N'>PID:</span>  <span name='MS:'>" WinPID "</span>" 
		. _DP  ProcessBitSize _BP1 " id='view_WindowCount'>窗口数量:" _BP2 "  <span name='MS:'>" WinCountProcess "</span>"    
		. _DP _BP1 " id='view_ControlCount'>控件数量:" _BP2 "  <span name='MS:'>" CountControl "</span>" 
		. _DP "<span class='param'>创建信息时间:  </span><span name='MS:'>" A_Hour ":" A_Min ":" A_Sec 
		. ".<span class='param' style='font-size: 0.75em'>" A_MSec "</span></span>"
		
	. "`n<span class='param' name='MS:N'>HWND:</span>  <span name='MS:'>" WinID "</span>" 
		. _DP  _BB1 " id='win_close'> close " _BB2   
		. _DP  _BB1 " id='process_close'> process close " _BB2 
		. _DP  _BB1 " id='window_show_hide'> show / hide " _BB2
		. _DP  _BB1 " id='window_minimize'> minimize " _BB2
		. _DP  _BB1 " id='window_restore'> restore " _BB2
	
	. "`n<span class='param' name='MS:N'>IsAdmin:</span>  <span name='MS:'>" IsAdmin "</span>"
		. IsWindowUnicodeStr ProcessUserNameStr WindowBand 
		. _ParentWindow EX1Str CLSID 
  
	. "`n<span class='param'>风格:  </span><span id='w_Style' name='MS:'>" WinStyle "</span>" 
		. _DP "<span class='param'>附加风格:  </span><span id='w_ExStyle' name='MS:'>" WinExStyle "</span>" 
		. _DP _BB1 " id='get_styles_w'> " (!w_ShowStyles ? "显示" : "隐藏" ) " 风格 " _BB2
		. _DP _BB1 " id='update_styles_w'> 更新风格 " _BB2 _PRE2 

	. "`n<span id=WinStyles>" WinStyles "</span>" 
	. "`n<span id='view_WindowCount_value'></span>"
	. "`n<span id='view_ControlCount_value'></span>"
	. SBText  WinText  MenuText "<a></a>" _T0  
 
	oOther.WinPID := WinPID
	oOther.WinID := WinID
	oOther.ChildID := hChild
	If !gLocalData 
	{ 
		If StateLightMarker && (ThisMode = "Win") && (StateLight = 1 || (StateLight = 3 && GetKeyState("Shift")))
			ShowMarker(WinX, WinY, WinWidth, WinHeight, 5) 
	}
	Return 1
}

Write_Win(scroll = 0) {
	If (ThisMode != "Win")
		Return 0  
	oDivOld := oDivWork%DivWorkIndex%
	DivWorkIndex := DivWorkIndex = 1 ? 2 : 1
	oDivNew := oDivWork%DivWorkIndex%  
	oDivNew.innerHTML := HTML_Win 
	If oOther.anchor[ThisMode]
		AnchorScroll(AnchorColor())
	Else
		oDivNew.scrollTop := scroll ? ScrollPos[ThisMode, 2] : (ScrollPos[ThisMode, 2] := oDivOld.scrollTop)
		
	If oDivNew.scrollLeft
		oDivNew.scrollLeft := 0 

	oDivNew.style.zIndex := 1 
	oDivOld.style.zIndex := 0 
	
	oDivNew.style.visibility := "visible"
	oDivOld.innerHTML := ""
	Return 1 
}

	; ___________________________ Mode_Control _________________________________________________

Mode_Control:
	If A_GuiControl
		GuiControl, 1:Focus, oDoc
	ZoomMsg(10, 0) 
	; oBody.createTextRange().execCommand("RemoveFormat")
	ColorButton("Control") 
	If (ThisMode = "Hotkey")
		Hotkey_Hook(0)
		
	Try SetTimer, Loop_%ThisMode%, Off
	
	ScrollPos[ThisMode, 1] := oDivNew.scrollLeft
	ScrollPos[ThisMode, 2] := oDivNew.scrollTop
	
	If ThisMode != Control
		HTML_%ThisMode% := oDivNew.innerHTML, prNotThisMode := 1
	Else 
		ZoomMsg(13)
		
	ThisMode := "Control"
	
	If (HTML_Control = "")
		Spot_Control(1)
		
	Write_Control(prNotThisMode)
	
	TitleText := (TitleTextP1 := "AhkSpy - 控件") . TitleTextP2
	SendMessage, 0xC, 0, &TitleText, , ahk_id %hGui%
	If isFindView
		FindNewText() 

Loop_Control:
	If (WinActive("ahk_id" hGui) && !ActiveNoPause) || Sleep = 1
		GoTo Repeat_Loop_Control
	If !OnlyShiftTab && Spot_Control()
		Write_Control(), StateAllwaysSpot ? Spot_Win() : 0
		
Repeat_Loop_Control:
	If (!isPaused && ThisMode = "Control" && !OnlyShiftTab) 
		SetTimer, Loop_Control, -%RangeTimer%  
	Return

Spot_Control(NotHTML = 0) {
	If NotHTML
		GoTo HTML_Control

	If !gLocalData
	{
		CoordMode, Mouse, Screen
		MouseGetPos, MXS, MYS, WinID, tControlNN 
	}
	Else {
		WinID := gLocalData.Win
		ControlID := gLocalData.Child
		tControlNN := gLocalData.ChildNN   
		WinGetPos, WinX, WinY, WinW, WinH, ahk_id %ControlID% 
		MXS := WinX + WinW // 2, MYS := WinY + WinH // 2
	}
	
	If (WinID = hGui || WinID = oOther.hZoom || WinID = oOther.hZoomLW)
		Return 0, HideAllMarkers()
		
	osCoords.MXS := MXS, osCoords.MYS := MYS
	oObjActive.ScreenX := MXS, oObjActive.ScreenY := MYS
	If !gLocalData
	{
		CoordMode, Mouse, Window
		MouseGetPos, MXWA, MYWA, , tControlID, 2
	}
	Else {
		tControlID := ControlID
	}
	osCoords.MXWA := MXWA, osCoords.MYWA := MYWA
	WinGet, ProcessName_A, ProcessName, A
	WinGet, HWND_A, ID, A
	WinGetClass, WinClass_A, A

	CtrlInfo := "", isIE := 0
	ControlNN := tControlNN, ControlID := tControlID
	WinGetPos, WinX, WinY, WinW, WinH, ahk_id %WinID%
	osCoords.WinW := WinW, osCoords.WinH := WinH
	WinGet, WinPID, PID, ahk_id %WinID%
	osCoords.RWinX := RWinX := MXS - WinX, osCoords.RWinY := RWinY := MYS - WinY
	GetClientPos(WinID, caX, caY, caW, caH)
	MXC := RWinX - caX, MYC := RWinY - caY
	osCoords.caW := caW, osCoords.caH := caH
	osCoords.MXC := MXC, osCoords.MYC := MYC
	 
	cc := _DP "" _BB1 " name='x" RWinX " y" RWinY "' id='control_click'> 点击控件 " _BB2  
	WithRespectWin := cc "`n" _BP1 " id='set_pos'>窗口比例:" _BP2 "  <span name='MS:' id='coord_rwin'>"
		. Round(RWinX / WinW, 4) ", " Round(RWinY / WinH, 4) "</span>  <span class='param'>窗口大小</span> <span name='MS:'>w" WinW " h" WinH "</span>" _DP
	WithRespectClient := _BP1 " id='set_pos'>客户端比例:" _BP2 "  <span name='MS:' id='coord_rclient'>" Round(MXC / caW, 4) ", " Round(MYC / caH, 4)
		. "</span>  <span class='param'>客户端大小</span> <span name='MS:'>w" caW " h" caH "</span>"

	ControlGetPos, CtrlX, CtrlY, CtrlW, CtrlH,, ahk_id %ControlID%
	
	AccText := AccInfoUnderMouse(MXS, MYS, WinX, WinY, CtrlX, CtrlY, caX, caY, WinID, ControlID, !!gLocalData)
	If AccText !=
		AccText := _T1 " id='__AccInfo'> ( Acc信息 ) </span><a></a>" _BT1 " id='flash_acc'> 闪烁 " _BT2 _ButAccViewer _T2 AccText
		
	If ControlID
	{
		CtrlCAX := CtrlX - caX, CtrlCAY := CtrlY - caY
		
		CtrlX2 := CtrlX + CtrlW - 1, CtrlY2 := CtrlY + CtrlH - 1
		CtrlCAX2 := CtrlX2 - caX, CtrlCAY2 := CtrlY2 - caY
		
		CtrlSCX := WinX + CtrlX, CtrlSCY := WinY + CtrlY
		CtrlSCX2 := CtrlSCX + CtrlW - 1, CtrlSCY2 := CtrlSCY + CtrlH - 1 
		
		ControlGetText, CtrlText, , ahk_id %ControlID%
		If CtrlText !=
			CtrlText := _T1 " id='__Control_Text'> ( 控件文本 ) </span><a></a>" _BT1 " id='copy_button_CtrlText'> 复制 " _BT2 
			. _DB _BT1 " id='settext_button' value=`" ControlID "`> set " _BT2 
			. _DB  _BT1 " id='paste_Control_Text'> 粘贴 " _BT2  _T2  _LPRE " id='content_Control_Text'>" TransformHTML(CtrlText) _PRE2
		
		ControlGet, CtrlStyle, Style,,, ahk_id %ControlID%
		ControlGet, CtrlExStyle, ExStyle,,, ahk_id %ControlID%
		WinGetClass, CtrlClass, ahk_id %ControlID%
		
		If (hParent := DllCall("GetParent", "UPtr", ControlID)) && (hParent != WinID)
		{
			WinGetClass, ParentClass, ahk_id %hParent%
			_ParentControl := _DP "<span class='param'>Parent control:</span>  <span name='MS:'>" ParentClass "</span>" _DP "<span name='MS:'>" Format("0x{:x}", hParent) "</span>"
		}
		
		If ViewStrPos
			ViewStrPos1 := _DP "<span name='MS:'>" CtrlX ", " CtrlY ", " CtrlX2 ", " CtrlY2 "</span>" _DP "<span name='MS:'>" CtrlX ", " CtrlY ", " CtrlW ", " CtrlH "</span>"
			, ViewStrPos2 := _DP "<span name='MS:'>" CtrlCAX ", " CtrlCAY ", " CtrlCAX2 ", " CtrlCAY2 "</span>" _DP "<span name='MS:'>" CtrlCAX ", " CtrlCAY ", " CtrlW ", " CtrlH "</span>"
			. _DP "<span name='MS:'>" CtrlSCX ", " CtrlSCY ", " CtrlSCX2 ", " CtrlSCY2 "</span>" _DP "<span name='MS:'>" CtrlSCX ", " CtrlSCY ", " CtrlW ", " CtrlH "</span>" 	
		
		If DynamicControlPath
			ChildToPath(ControlID), control_path_value := SaveChildPath()
		If (0 && view_control_child && ChildList(ControlID) = 1)
			control_child_value := oOther.ChildList
	} 
	If ControlNN !=
	{
		rmCtrlX := MXS - WinX - CtrlX, rmCtrlY := MYS - WinY - CtrlY
		ControlNN_Sub := RegExReplace(ControlNN, "S)\d+| ")
		
		;; Scintilla,Edit,SysListView,SysTreeView,ListBox,ComboBox,CtrlNotfySink,msctls_progress
		;; ,msctls_trackbar,msctls_updown,SysTabControl,ToolbarWindow,AtlAxWin,InternetExplorer_Server
		If IsFunc("GetInfo_" ControlNN_Sub)
			Func := ControlNN_Sub
		Else If RegExMatch(ControlNN_Sub, "i)(TreeView|ListView|ListBox|ComboBox|NotfySink|Edit|Scintilla|progress|trackbar|updown|Tab|Toolbar|RichEd)", Match) 
			Func := IsFunc("GetInfo_" Match) ? Match : {RichEd:"Scintilla",TreeView:"SysTreeView", ListView:"SysListView", NotfySink:"CtrlNotfySink"
				, progress:"msctls_progress", trackbar:"msctls_trackbar", updown:"msctls_updown", Tab:"SysTabControl", Toolbar:"ToolbarWindow"}[Match]
			
		If Func
		{
			CtrlInfo := GetInfo_%Func%(ControlID, ClassName)
			If CtrlInfo !=
			{
				If isIE
					CtrlInfo = %_T1% id='__Info_Class'> ( 信息 - %CtrlClass% ) </span><a></a>%_BT1% id='flash_IE'> flash %_BT2%%_ButiWB2Learner%%_T2%%CtrlInfo%
				Else
					CtrlInfo = %_T1% id='__Info_Class'> ( 信息 - %CtrlClass% ) </span><a></a>%_T2%%_PRE1%%CtrlInfo%%_PRE2%
			}
		} 
		osCoords.rmCtrlX := rmCtrlX, osCoords.rmCtrlY := rmCtrlY
		osCoords.CtrlW := CtrlW, osCoords.CtrlH := CtrlH
		WithRespectControl := _DP "<span name='MS:' id='coord_wrc'>" Round(rmCtrlX / CtrlW, 4) ", " Round(rmCtrlY / CtrlH, 4) "</span>"
	}
	Else
		rmCtrlX := rmCtrlY := ""
	
	ControlGetFocus, CtrlFocus, ahk_id %WinID%
	WinGet, ProcessName, ProcessName, ahk_id %WinID%
	WinGetClass, WinClass, ahk_id %WinID%

	If !gLocalData {
		MouseGetPos, , , h 
	}
	Else {
		h := WinID
	}
	
	If (h = hGui || h = oOther.hZoom || h = oOther.hZoomLW)
		Return 0, HideAllMarkers()
		
	If !isIE
		SetPosObject("Control", [CtrlSCX, CtrlSCY, CtrlW, CtrlH])  
 
	SetPosObject("AhkSpy", WinGetPosToArray(hActiveX)) 
	
	If UseUIA && exUIASub.Release()
		&& (gLocalData ? exUIASub.ElementFromHandle((ControlID ? ControlID : WinID)) : exUIASub.ElementFromPoint(MXS, MYS)) 
	{ 
		UIAPID := exUIASub.CurrentProcessId 
		UIACurrentName := exUIASub.CurrentName
		CurrentControlTypeIndex := Format("0x{:X}", exUIASub.CurrentControlType)
		CurrentControlTypeName := exUIASub.__ControlType(CurrentControlTypeIndex)
		CurrentAutomationId := exUIASub.CurrentAutomationId  
		CurrentLocalizedControlType := exUIASub.CurrentLocalizedControlType
		CurrentHelpText := exUIASub.CurrentHelpText
		UIAHWND := exUIASub.CurrentNativeWindowHandle
		 
		WinGet, UIAProcessName, ProcessName, ahk_pid %UIAPID%
		WinGet, UIAProcessPath, ProcessPath, ahk_pid %UIAPID%
		
		Loop, %UIAProcessPath%
			UIAProcessPath = %A_LoopFileLongPath%
			
		If UIAAlienDetect && ((UIAPID != WinPID) || (ControlID && ControlID != UIAHWND) || (!ControlID && WinID != UIAHWND))
			bc = style='background-color: #%ColorHighLightBckg%'
		
		UseUIAStr := "`n" _T1 " id='P__UIA_Object'> ( UIA Interface ) </span><a></a>" _T2
		. _PRE1 "<div " bc "><span class='param' name='MS:N'>PID:</span>  <span name='MS:'>" UIAPID "</span>" 
		
		. (UIAHWND ? _DP "<span class='param' name='MS:N'>HWND:</span>  <span name='MS:'>" Format("0x{:x}", UIAHWND) "</span>"
		. _DP "<span class='param' name='MS:N'>ClassName:</span>  <span name='MS:'>" TransformHTML(exUIASub.CurrentClassName) "</span>" : _DP "HWND undefined")
		
		. _DN (CurrentAutomationId != "" ? "<span class='param' name='MS:N'>AutomationId:</span>  <span name='MS:'>" CurrentAutomationId "</span>" : "AutomationId undefined")
			. _DP (CurrentControlTypeIndex != "" ? "<span class='param' name='MS:N'>ControlType:</span>  <span name='MS:'>" CurrentControlTypeName "</span>"
			. _DP " <span name='MS:'>" CurrentControlTypeIndex "</span>" : "ControlType undefined")
			. (CurrentLocalizedControlType != "" ? _DP
			. "<span class='param' name='MS:N'>LocalizedControlType:</span>  <span name='MS:'>" CurrentLocalizedControlType "</span>" : _DP "LocalizedControlType undefined")
		
		. (CurrentHelpText != "" ? _DN "<span class='param' name='MS:N'>HelpText:</span>  <span name='MS:'>" CurrentHelpText "</span>" : "")
		
		. (UIAProcessName != ""
			? _DN "<span class='param' name='MS:N'>ProcessName:</span>  <span name='MS:'>" TransformHTML(UIAProcessName) "</span>"
			. _DP "<span class='param' name='MS:N'>ProcessPath:</span>  <span name='MS:'>" TransformHTML(UIAProcessPath) "</span>" : "")
		. _PRE2
		
		. (UIACurrentName = "" ? ""
			 : _DN _T1 " id='P__UIACurrentName'" _T1P "> ( CurrentName ) </span><a></a>" _BT1 " id='copy_button'> copy " _BT2 _T2 
			 . _LPRE ">" TransformHTML(UIACurrentName) _PRE2)

		. "</div>"  
	}
	PixelGetColor, ColorBGR, %MXS%, %MYS%
	ColorRGB := Format("0x{:06X}", (ColorBGR & 0xFF) << 16 | (ColorBGR & 0xFF00) | (ColorBGR >> 16))

	sInvert_RGB := Format("{:06X}", ColorRGB ^ 0xFFFFFF)  
	sColorRGB := SubStr(ColorRGB, 3) 
	
	GuiControl, TB: -Redraw, ColorProgress
	GuiControl, % "TB: +c" sColorRGB, ColorProgress
	GuiControl, TB: +Redraw, ColorProgress
	If !gLocalData
	{
		If (!isIE && ThisMode = "Control" && (StateLight = 1 || (StateLight = 3 && GetKeyState("Shift"))))
		{
			If ControlID && StateLightMarker 
				ShowMarker(CtrlSCX, CtrlSCY, CtrlW, CtrlH)
			Else
				HideMarker()
			
			StateLightAcc ? ShowAccMarker(AccCoord[1], AccCoord[2], AccCoord[3], AccCoord[4]) : 0
		}
	}
	If ((S_CaretX := A_CaretX) != "")
		CaretPosStr = <span class='param'>Caret:</span>  <span name='MS:'>x%S_CaretX% y%A_CaretY%</span>
	Else 
		CaretPosStr = <span class='error'>Caret position undefined</span>
		 
	NCHITTESTStr :=_DP "<span class='param'>WM_NCHITTEST:</span>  <span name='MS:'>" WM_NCHITTEST(MXS, MYS, WinID) "</span>" 
		
	
	; ___________________________ HTML_Control _________________________________________________
 
HTML_Control:

	If ControlID
	{
		If c_ShowStyles
			ControlStyles := GetStyles(CtrlClass, CtrlStyle, CtrlExStyle, ControlID)
			
		HTML_ControlExist := ""
		. _T1 " id='__Control'> ( 控件 ) </span>" _BT1 " id='flash_control'> 闪烁 " _BT2  _ButWindow_Detective  _T2 
		
		. _PRE1 "<span class='param'>ClassNN:</span>  <span name='MS:'>" ControlNN "</span>"
			. _DP  "<span class='param'>Class:</span>  <span name='MS:'>" CtrlClass "</span>"
			
		. "`n" _BP1 " id='set_button_pos'>位置:" _BP2 "  <span name='MS:'>x" CtrlX " y" CtrlY "</span>" 
			. _DP "<span name='MS:'>x²" CtrlX2 " y²" CtrlY2 "</span>" _DP  _BP1 " id='set_button_pos'>大小:"  _BP2 
			. "  <span name='MS:'>w" CtrlW " h" CtrlH "</span>" ViewStrPos1 
			
		. "`n" "<span class='param'>相对客户端区域:</span>  <span name='MS:'>x" CtrlCAX " y" CtrlCAY "</span>" 
			. _DP "<span name='MS:'>x²" CtrlCAX2 " y²" CtrlCAY2 "</span>"
			. _DP "<span class='param'>相对屏:</span>  <span name='MS:'>x" CtrlSCX " y" CtrlSCY "</span>" 
			. _DP "<span name='MS:'>x²" CtrlSCX2 " y²" CtrlSCY2 "</span>"
			. ViewStrPos2 
			
		. "`n" _BP1 " id='set_pos'>鼠标相对控件:" _BP2 "  <span name='MS:' id='coord_mrc'>x" rmCtrlX " y" rmCtrlY "</span>" WithRespectControl 
		
		. "`n<span class='param'>HWND:</span>  <span name='MS:'>" ControlID "</span>" 
		. _DP "<span class='param'>Style:</span>  <span id='c_Style' name='MS:'>" CtrlStyle "</span>" 
		. _DP "<span class='param'>ExStyle:</span>  <span id='c_ExStyle' name='MS:'>" CtrlExStyle "</span>" 
		. _DP _BB1 " id='get_styles_c'> " (!c_ShowStyles ? "show styles" : "hide styles") " " _BB2
		. _DP _BB1 " id='update_styles_c'> update styles " _BB2  
		 
		. "`n" _BB1 " id='control_show_hide'> show / hide " _BB2 
		. _DP  _BB1 " id='control_destroy'> close " _BB2  
		. _DP  _BP1 " id='control_totree'> View to tree " _BP2
		. _DP  _BP1 " id='control_child'> Get child " _BP2 
		. _DP  _BP1 " id='control_path'> Get parent " _BP2 
		. "<span id='control_path_error'></span>" _ParentControl 
			  
		. _PRE2
		
		. "`n<span id=ControlStyles>" ControlStyles "</span>" 
		
		. "`n<span id='control_path_value'>" control_path_value "</span>" 
		
		. "`n<span id='control_child_value'>" control_child_value "</span>"
	} 
	If gLocalData
		back_openchild := _DB _BT1 " id='b_back_openchild'> return " _BT2
		
	HTML_Control := ""
	. _T1 " id='__Mouse'> ( 鼠标 ) </span>" _BT1 " id='pause_button'> 暂停 " _BT2 back_openchild _T2 
	
	. _PRE1  _BP1 " id='set_pos'>屏幕:" _BP2 "  <span name='MS:' id='coord_screen'>x" MXS " y" MYS "</span>" _DP  _BP1 " id='set_pos'>Window:" _BP2 
		. "  <span name='MS:' id='coord_win'>x" RWinX " y" RWinY "</span>" _DP  _BP1 " id='set_pos'>客户端:" _BP2 
		. "  <span name='MS:' id='coord_client'>x" MXC " y" MYC "</span>" WithRespectWin  WithRespectClient 
	
	. "`n<span class='param'>相对活动窗口:</span>  <span name='MS:' id='coord_awin'>x" MXWA " y" MYWA "</span>" 
		. _DP "<span class='param'>class</span> <span name='MS:'>" WinClass_A 
		. "</span> <span class='param'>exe</span> <span name='MS:'>" ProcessName_A 
		. "</span> <span class='param'>hwnd</span> <span name='MS:'>" HWND_A "</span>" _PRE2 
	
	. _T1 " id='__PixelColor'> ( 像素颜色 ) </span>" _T2 
	
	. _PRE1 "<span class='param'>RGB: </span> <span name='MS:' id='ColorRGB'>" ColorRGB "</span>" 
		. _DP "#<span name='MS:' id='sColorRGB'>" sColorRGB "</span>" _DP "<span class='param'>BGR: </span> <span name='MS:' id='ColorBGR'>" ColorBGR "</span>" 
		. _DP "#<span name='MS:' id='sColorBGR'>" SubStr(ColorBGR, 3) "</span>" 
		. _DP "<span class='param'>反色 RGB: </span> <span name='MS:' id='sInvert_RGB0'>0x" sInvert_RGB "</span>" 
		. _DP "#<span name='MS:' id='sInvert_RGB'>" sInvert_RGB "</span>" _DP "<span style='background-color: #" sInvert_RGB "' id='RenderInvert_RGB'>          </span>" _PRE2 
	
	. _T1 " id='__Window'> ( 窗口 ) </span>" _BT1 " id='flash_ctrl_window'> 闪烁 " _BT2  _T2 
	
	. _PRE1 "<span><span class='param' name='MS:S'>ahk_class</span> <span name='MS:'>" WinClass "</span></span> "
		. "<span><span class='param' name='MS:S'>ahk_exe</span> <span name='MS:'>" ProcessName "</span></span> "
		. "<span><span class='param' name='MS:S'>ahk_id</span> <span name='MS:'>" WinID "</span></span> "
		. "<span><span class='param' name='MS:S'>ahk_pid</span> <span name='MS:'>" WinPID "</span></span>"
		. _DP "<span class='param'>信息创建时间:  </span><span name='MS:'>" A_Hour ":" A_Min ":" A_Sec 
		. ".<span class='param' style='font-size: 0.75em'>" A_MSec "</span></span>"

	. "`n<span class='param'>指针:</span>  <span name='MS:'>" A_Cursor "</span>" 
		. _DP  CaretPosStr  _DP "<span class='param'>客户端区域:</span>  <span name='MS:'>x" caX " y" caY " w" caW " h" caH "</span>"

	. "`n" _BP1 " id='set_button_focus_ctrl'>焦点控件:" _BP2 "  <span name='MS:'>" CtrlFocus "</span>" _PRE2 

	. "`n" HTML_ControlExist 

	. "`n" CtrlInfo CtrlText UseUIAStr AccText "<a></a>" _T0
	
	oOther.ControlID := ControlID
	oOther.MouseWinID := WinID
	oOther.CtrlClass := CtrlClass
	oOther.ControlNN := ControlNN
	oOther.MouseWinClass := WinClass
	Return 1
}

Write_Control(scroll = 0) {
	If (ThisMode != "Control")
		Return 0  
	oDivOld := oDivWork%DivWorkIndex%
	DivWorkIndex := DivWorkIndex = 1 ? 2 : 1
	oDivNew := oDivWork%DivWorkIndex%  
	oDivNew.innerHTML := HTML_Control 

	If oOther.anchor[ThisMode]
		AnchorScroll(AnchorColor())
	Else
		oDivNew.scrollTop := scroll ? ScrollPos[ThisMode, 2] : (ScrollPos[ThisMode, 2] := oDivOld.scrollTop)
		
	If oDivNew.scrollLeft
		oDivNew.scrollLeft := 0 

	oDivNew.style.zIndex := 1 
	oDivOld.style.zIndex := 0 
	
	oDivNew.style.visibility := "visible"
	oDivOld.innerHTML := ""
	Return 1
} 

Menu_LocalOpenWin() {
	If !WinExist("ahk_id" Clipboard)
		Return ToolTip("Window not found", 700) 
	Gosub Mode_Win
	LocalOpenWin(Clipboard)
}

Menu_LocalOpenChild() {
	If !WinExist("ahk_id" Clipboard)
		Return ToolTip("Window not found", 700)  
	Gosub Mode_Control
	LocalOpenChild(Clipboard, GetClassNN(Clipboard))
}

LocalOpenWin(Win) {
	gLocalData := {}
	gLocalData.Win := Win 
	gLocalData.Child := oOther.ChildID
	gLocalOpen.Win.Push(HTML_Win) 
	Spot_Win() 
	Write_Win()
	gLocalData := ""  
	If oOther.ZoomShow
		ZoomMsg(14, Win) 
}

LocalOpenWinChild(ControlID, ChildNN) {
	gLocalData := {}
	gLocalData.Child := ControlID
	gLocalData.ChildNN := ChildNN
	gLocalData.Win := oOther.WinID 
	Gosub Mode_Control
	gLocalOpen.Control.Push(HTML_Control)
	Spot_Control()
	Write_Control()
	gLocalData := "" 
	If oOther.ZoomShow
		ZoomMsg(14, ControlID)
}

LocalOpenChild(ControlID, ChildNN) {
	gLocalData := {} 
	gLocalData.Child := ControlID
	gLocalData.ChildNN := ChildNN
	gLocalData.Win := oOther.MouseWinID   
	gLocalOpen.Control.Push(HTML_Control)
	Spot_Control()
	Write_Control()
	gLocalData := "" 
	If oOther.ZoomShow
		ZoomMsg(14, ControlID)
}

LocalBackWin() {   
	HTML_Win := gLocalOpen.Win.Pop()
	Write_Win() 
}

LocalBackChild() {    
	HTML_Control := gLocalOpen.Control.Pop()
	Write_Control() 
}

	; ___________________________ Get Menu _________________________________________________

GetMenu(hWnd) {
	;; Static prhWnd, MenuText
	;; If (hWnd = prhWnd)
		;; Return MenuText
	;; prhWnd := hWnd
	SendMessage, 0x1E1, 0, 0, , ahk_id %hWnd%	;;  MN_GETHMENU
	hMenu := ErrorLevel
	If !hMenu || (hMenu + 0 = "")
		Return
	Return _T1 " id='__Menu_text'> ( Menu text ) </span><a></a>" _BT1 " id='copy_menutext'> 复制 " _BT2 _DB
	. _BT1 " id='menu_idview'> id - " (MenuIdView ? "view" : "hide") " " _BT2 _T2 _LPRE " id='pre_menutext'>" RTrim(GetMenuText(hMenu), "`n")  _PRE2
}

GetMenuText(hMenu, child = 0)
{
	Loop, % DllCall("GetMenuItemCount", "UPtr", hMenu)
	{
		idx := A_Index - 1
		nSize++ := DllCall("GetMenuString", "Ptr", hMenu, "int", idx, "Uint", 0, "int", 0, "Uint", 0x400)   ;;  MF_BYPOSITION
		nSize := (nSize * (A_IsUnicode ? 2 : 1))
		VarSetCapacity(sString, nSize)
		DllCall("GetMenuString", "Ptr", hMenu, "int", idx, "str", sString, "int", nSize, "Uint", 0x400)   ;;  MF_BYPOSITION
		sString := TransformHTML(sString)
		idn := DllCall("GetMenuItemID", "Ptr", hMenu, "int", idx)
		IdItem := "<span class='param menuitemid' style='display: " (!MenuIdView ? "none" : "inline") ";;'>`t`t`t<span name='MS:'>" idn "</span></span>"
		isSubMenu := (idn = -1) && (hSubMenu := DllCall("GetSubMenu", "Ptr", hMenu, "int", idx)) ? 1 : 0
		If isSubMenu
			sContents .= AddTab(child) "<span class='param'>" idx + 1 ":  </span><span name='MS:' class='titleparam'>" sString "</span>" IdItem "`n"
		Else If (sString = "")
			sContents .= AddTab(child) "<span class='param'>" idx + 1 ":  — — — — — — —</span>" IdItem "`n"
		Else
			sContents .= AddTab(child) "<span class='param'>" idx + 1 ":  </span><span name='MS:'>" sString "</span>" IdItem "`n"
		If isSubMenu
			sContents .= GetMenuText(hSubMenu, ++child), --child
	}
	Return sContents
}

AddTab(c) {
	loop % c
		Tab .= "<span class='param';'>↓`t</span>"
	Return Tab
}

	; ___________________________ Get Info Control _________________________________________________

;; Scintilla,Edit,SysListView,SysTreeView,ListBox,ComboBox,CtrlNotfySink,msctls_progress
;; ,msctls_trackbar,msctls_updown,SysTabControl,ToolbarWindow,AtlAxWin,InternetExplorer_Server

;; TreeView, ListView, NotfySink, progress, trackbar, updown, Tab, Toolbar


GetInfo_SysListView(hwnd) { 
	ControlGet, ListText, List,,, ahk_id %hwnd%
	ControlGet, RowCount, List, Count,, ahk_id %hwnd%
	ControlGet, ColCount, List, Count Col,, ahk_id %hwnd%
	ControlGet, SelectedCount, List, Count Selected,, ahk_id %hwnd%
	ControlGet, FocusedCount, List, Count Focused,, ahk_id %hwnd%
	Return	"<span class='param' name='MS:N'>行数:</span> <span name='MS:'>" RowCount "</span>" _DP
			. "<span class='param' name='MS:N'>Column count:</span> <span name='MS:'>" ColCount "</span>`n"
			. "<span class='param' name='MS:N'>Selected count:</span> <span name='MS:'>" SelectedCount "</span>" _DP
			. "<span class='param' name='MS:N'>Focused row:</span> <span name='MS:'>" FocusedCount "</span>" _PRE2
			. _T1 " id='__Content_SysListView'> ( Content ) </span>" _BT1 " id='copy_button'> 复制 " _BT2 _T2 _LPRE ">" TransformHTML(ListText)
}

GetInfo_SysTreeView(hwnd) { 
	SendMessage 0x1105, 0, 0, , ahk_id %hwnd%   ;; TVM_GETCOUNT
	ItemCount := ErrorLevel
	Return	"<span class='param' name='MS:N'>条目数:</span> <span name='MS:'>" ItemCount "</span>"
}

GetInfo_ListBox(hwnd) { 
	Return GetInfo_ComboBox(hwnd, 1)
}

GetInfo_ComboBox(hwnd, ListBox = 0) { 
	ControlGet, ListText, List,,, ahk_id %hwnd%
	SendMessage, (ListBox ? 0x188 : 0x147), 0, 0, , ahk_id %hwnd%   ;; 0x188 - LB_GETCURSEL, 0x147 - CB_GETCURSEL
	SelPos := ErrorLevel
	SelPos := SelPos = 0xffffffff || SelPos < 0 ? "NoSelect" : SelPos + 1
	; SendMessage, 0x146, 0, 0, , ahk_id %hwnd%   ; CB_GETCOUNT 
	RegExReplace(ListText, "m`a)$", "", RowCount)
	Return	"<span class='param' name='MS:N'>行数:</span> <span name='MS:'>" RowCount "</span>" _DP
			. "<span class='param' name='MS:N'>Row selected:</span> <span name='MS:'>" SelPos "</span>" _PRE2
			. _T1 " id='__Content_ComboBox'> ( Content ) </span>" _BT1 " id='copy_button'> 复制 " _BT2 _T2 _LPRE ">" TransformHTML(ListText)
}

GetInfo_CtrlNotifySink(hwnd) { 
	Return GetInfo_Scintilla(hwnd)
}

	;;  http://forum.script-coding.com/viewtopic.php?pid=117128#p117128
	;;  https://msdn.microsoft.com/en-us/library/windows/desktop/ms645478(v=vs.85).aspx

GetInfo_Edit(hwnd) { 
	Edit_GetFont(hwnd, FName, FSize)
	Return GetInfo_Scintilla(hwnd) "`n<span class='param' name='MS:N'>字体大小:</span> <span name='MS:'>" FSize "</span>" 
		. _DP "<span class='param' name='MS:N'>FontName:</span> <span name='MS:'>" FName "</span>"
		. "`n<span class='param' name='MS:N'>DlgCtrlID:</span> <span name='MS:'>" DllCall("GetDlgCtrlID", "UPtr", hwnd) "</span>"
}

Edit_GetFont(hwnd, byref FontName, byref FontSize) {
	SendMessage 0x31, 0, 0, , ahk_id %hwnd% ;; WM_GETFONT
	If ErrorLevel = FAIL
		Return
	hFont := Errorlevel, VarSetCapacity(LF, szLF := 60 * (A_IsUnicode ? 2 : 1))
	DllCall("GetObject", UInt, hFont, Int, szLF, UInt, &LF)
	hDC := DllCall("GetDC", UInt, hwnd), DPI := DllCall("GetDeviceCaps", UInt, hDC, Int, 90)
	DllCall("ReleaseDC", Int, 0, UInt, hDC), FontSize := Round((-NumGet(LF, 0, "Int") * 72) / DPI)
	FontName := DllCall("MulDiv", Int, &LF + 28, Int, 1, Int, 1, Str)
}

GetInfo_Scintilla(hwnd) { 
	ControlGet, LineCount, LineCount,,, ahk_id %hwnd%
	ControlGet, CurrentCol, CurrentCol,,, ahk_id %hwnd%
	ControlGet, CurrentLine, CurrentLine,,, ahk_id %hwnd%
	ControlGet, Selected, Selected,,, ahk_id %hwnd%
	SendMessage, 0x00B0, , , , ahk_id %hwnd%			;;  EM_GETSEL
	EM_GETSEL := ErrorLevel >> 16
	SendMessage, 0x00CE, , , , ahk_id %hwnd%			;;  EM_GETFIRSTVISIBLELINE
	EM_GETFIRSTVISIBLELINE := ErrorLevel + 1
	Return	"<span class='param' name='MS:N'>行数:</span> <span name='MS:'>" LineCount "</span>" _DP
			. "<span class='param' name='MS:N'>选择的长度:</span> <span name='MS:'>" StrLen(Selected) "</span>"
			. "`n<span class='param' name='MS:N'>当前行:</span> <span name='MS:'>" CurrentLine "</span>" _DP
			. "<span class='param' name='MS:N'>当前列:</span> <span name='MS:'>" CurrentCol "</span>"
			. "`n<span class='param' name='MS:N'>当前选中:</span> <span name='MS:'>" EM_GETSEL "</span>" _DP
			. "<span class='param' name='MS:N'>第一个可见的线</span> <span name='MS:'>" EM_GETFIRSTVISIBLELINE "</span>"
}

GetInfo_msctls_progress(hwnd) { 
	SendMessage, 0x0400+7,"TRUE",,, ahk_id %hwnd%	;;  PBM_GETRANGE
	PBM_GETRANGEMIN := ErrorLevel
	SendMessage, 0x0400+7,,,, ahk_id %hwnd%			;;  PBM_GETRANGE
	PBM_GETRANGEMAX := ErrorLevel
	SendMessage, 0x0400+8,,,, ahk_id %hwnd%			;;  PBM_GETPOS
	PBM_GETPOS := ErrorLevel
	Return	"<span class='param' name='MS:N'>水平:</span> <span name='MS:'>" PBM_GETPOS "</span>" _DP
			. "<span class='param'>范围:  </span><span class='param' name='MS:N'>最小: </span><span name='MS:'>" PBM_GETRANGEMIN "</span>"
			. "  <span class='param' name='MS:N'>最大:</span> <span name='MS:'>" PBM_GETRANGEMAX "</span>"
}

GetInfo_msctls_trackbar(hwnd) { 
	SendMessage, 0x0400+1,,,, ahk_id %hwnd%			;;  TBM_GETRANGEMIN
	TBM_GETRANGEMIN := ErrorLevel
	SendMessage, 0x0400+2,,,, ahk_id %hwnd%			;;  TBM_GETRANGEMAX
	TBM_GETRANGEMAX := ErrorLevel
	SendMessage, 0x0400,,,, ahk_id %hwnd%			;;  TBM_GETPOS
	TBM_GETPOS := ErrorLevel
	ControlGet, CtrlStyle, Style,,, ahk_id %hwnd%
	(!(CtrlStyle & 0x0200)) ? (TBS_REVERSED := "No")
	: (TBM_GETPOS := TBM_GETRANGEMAX - (TBM_GETPOS - TBM_GETRANGEMIN), TBS_REVERSED := "Yes")
	Return	"<span class='param' name='MS:N'>水平:</span> <span name='MS:'>" TBM_GETPOS "</span>" _DP
			. "<span class='param'>Invert style:</span>" TBS_REVERSED
			. "`n<span class='param'>范围:  </span><span class='param' name='MS:N'>最小: </span><span name='MS:'>" TBM_GETRANGEMIN "</span>" _DP
			. "<span class='param' name='MS:N'>最大:</span> <span name='MS:'>" TBM_GETRANGEMAX "</span>"
}

GetInfo_msctls_updown(hwnd) { 
	SendMessage, 0x0400+102,,,, ahk_id %hwnd%		;;  UDM_GETRANGE
	UDM_GETRANGE := ErrorLevel
	SendMessage, 0x400+114,,,, ahk_id %hwnd%		;;  UDM_GETPOS32
	UDM_GETPOS32 := ErrorLevel
	Return	"<span class='param' name='MS:N'>水平:</span> <span name='MS:'>" UDM_GETPOS32 "</span>" _DP
			. "<span class='param'>范围:  </span><span class='param' name='MS:N'>最小: </span><span name='MS:'>" UDM_GETRANGE >> 16 "</span>"
			. "  <span class='param' name='MS:N'>最大: </span><span name='MS:'>" UDM_GETRANGE & 0xFFFF "</span>"
}

GetInfo_SysTabControl(hwnd) { 
	ControlGet, SelTab, Tab,,, ahk_id %hwnd%
	SendMessage, 0x1300+44,,,, ahk_id %hwnd%		;;  TCM_GETROWCOUNT
	TCM_GETROWCOUNT := ErrorLevel
	SendMessage, 0x1300+4,,,, ahk_id %hwnd%			;;  TCM_GETITEMCOUNT
	TCM_GETITEMCOUNT := ErrorLevel
	Return	"<span class='param' name='MS:N'>条目数:</span> <span name='MS:'>" TCM_GETITEMCOUNT "</span>" _DP
			. "<span class='param' name='MS:N'>行数:</span> <span name='MS:'>" TCM_GETROWCOUNT "</span>" _DP
			. "<span class='param' name='MS:N'>选择的条目:</span> <span name='MS:'>" SelTab "</span>"
}

GetInfo_ToolbarWindow(hwnd) { 
	SendMessage, 0x0418,,,, ahk_id %hwnd%		;;  TB_BUTTONCOUNT
	BUTTONCOUNT := ErrorLevel
	Return	"<span class='param' name='MS:N'>按键数量:</span> <span name='MS:'>" BUTTONCOUNT "</span>"
}

	; ___________________________ Get Internet Explorer Info _________________________________________________

	;;  http://www.autohotkey.com/board/topic/84258-iwb2-learner-iwebbrowser2/

GetInfo_AtlAxWin(hwnd) { 
	Return GetInfo_InternetExplorer_Server(hwnd)
}

GetInfo_InternetExplorer_Server(hwnd) {
	Static IID_IWebBrowserApp := "{0002DF05-0000-0000-C000-000000000046}"
	, ratios := [], IID_IHTMLWindow2 := "{332C4427-26CB-11D0-B483-00C04FD90119}"

	isIE := 1 
	MouseGetPos, , , , hwnd, 3
	If !(pwin := WBGet(hwnd))
		Return
	If !ratios[hwnd]
	{
		ratio := pwin.window.screen.deviceXDPI / pwin.window.screen.logicalXDPI
		Sleep 10 ;; при частом запросе deviceXDPI, возвращает пусто
		!ratio && (ratio := 1)
		ratios[hwnd] := ratio
	}
	ratio := ratios[hwnd]
	pelt := pwin.document.elementFromPoint(rmCtrlX / ratio, rmCtrlY / ratio)
	Tag := pelt.TagName
	If (Tag = "IFRAME" || Tag = "FRAME")
	{
		If pFrame := ComObjQuery(pwin.document.parentWindow.frames[pelt.id], IID_IHTMLWindow2, IID_IHTMLWindow2)
			iFrame := ComObject(9, pFrame, 1)
		Else
			iFrame := ComObj(9, ComObjQuery(pelt.contentWindow, IID_IHTMLWindow2, IID_IHTMLWindow2), 1)
		WB2 := ComObject(9, ComObjQuery(pelt.contentWindow, IID_IWebBrowserApp, IID_IWebBrowserApp), 1)
		If ((Var := WB2.LocationName) != "")
			Frame .= "`n<span class='param' name='MS:N'>标题:  </span><span name='MS:'>" TransformHTML(Var) "</span>"
		If ((Var := WB2.LocationURL) != "")
			Frame .= "`n<span class='param' name='MS:N'>URL:  </span><span name='MS:'>" TransformHTML(Var) "</span>"
		If (iFrame.length)
			Frame .= "`n<span class='param' name='MS:N'>Count frames:  </span><span name='MS:'>" TransformHTML(iFrame.length) "</span>"
		If (Tag != "")
			Frame .= "`n<span class='param' name='MS:N'>TagName:  </span><span name='MS:'>" TransformHTML(Tag) "</span>"
		If ((Var := pelt.id) != "")
			Frame .= "`n<span class='param' name='MS:N'>ID:  </span><span name='MS:'>" TransformHTML(Var) "</span>"
		If ((Var := pelt.className) != "")
			Frame .= "`n<span class='param' name='MS:N'>Class:  </span><span name='MS:'>" TransformHTML(Var) "</span>"
		If ((Var := pelt.sourceIndex - 1) != "")
			Frame .= "`n<span class='param' name='MS:N'>索引:  </span><span name='MS:'>" TransformHTML(Var) "</span>"
		If ((Var := pelt.name) != "")
			Frame .= "`n<span class='param' name='MS:N'>名字:  </span><span name='MS:'>" TransformHTML(Var) "</span>"

		If ((Var := pelt.OuterHtml) != "")
			HTML := _T1 " id='P__Outer_HTML_FRAME'" _T1P "> ( Outer HTML ) </span><a></a>" _BT1 " id='copy_button'> copy " _BT2 _T2 _LPRE ">" TransformHTML(Var) _PRE2
		If ((Var := pelt.OuterText) != "")
			Text := _T1 " id='P__Outer_Text_FRAME'" _T1P "> ( Outer Text ) </span><a></a>" _BT1 " id='copy_button'> copy " _BT2 _T2 _LPRE ">" TransformHTML(Var) _PRE2
		If Frame !=
			Frame := _T1 " id='__FrameInfo_FRAME'> ( FrameInfo ) </span>" _T2 "<a></a>" _PRE1 Frame _PRE2 HTML Text

		_pbrt := pelt.getBoundingClientRect()
		pelt := iFrame.document.elementFromPoint((rmCtrlX / ratio) - _pbrt.left, (rmCtrlY / ratio) - _pbrt.top)
		__pbrt := pelt.getBoundingClientRect(), pbrt := {}
		pbrt.left := __pbrt.left + _pbrt.left, pbrt.right := __pbrt.right + _pbrt.left
		pbrt.top := __pbrt.top + _pbrt.top, pbrt.bottom := __pbrt.bottom + _pbrt.top
	}
	Else
		pbrt := pelt.getBoundingClientRect()

	WB2 := ComObject(9, ComObjQuery(pwin, IID_IWebBrowserApp, IID_IWebBrowserApp), 1)

	If ((Location := WB2.LocationName) != "")
		Topic .= "<span class='param' name='MS:N'>标题:  </span><span name='MS:'>"  TransformHTML(Location) "</span>`n"
	If ((URL := WB2.LocationURL) != "")
		Topic .= "<span class='param' name='MS:N'>URL:  </span><span name='MS:'>"  TransformHTML(URL) "</span>"
	If Topic !=
		Topic := _PRE1 Topic _PRE2

	If ((Var := pelt.id) != "")
		Info .= "`n<span class='param' name='MS:N'>ID:  </span><span name='MS:'>" Var "</span>"
	If ((Var := pelt.className) != "")
		Info .= "`n<span class='param' name='MS:N'>Class:  </span><span name='MS:'>" Var "</span>"
	If ((Var := pelt.sourceIndex - 1) != "")
		Info .= "`n<span class='param' name='MS:N'>索引:  </span><span name='MS:'>" Var "</span>"
	If ((Var := pelt.name) != "")
		Info .= "`n<span class='param' name='MS:N'>名字:  </span><span name='MS:'>" TransformHTML(Var) "</span>"

	If ((Var := pelt.OuterHtml) != "")
		HTML := _T1 " id='P__Outer_HTML'" _T1P "> ( Outer HTML ) </span><a></a>" _BT1 " id='copy_button'> 复制 " _BT2 _T2 _LPRE ">" TransformHTML(Var) _PRE2
	If ((Var := pelt.OuterText) != "")
		Text := _T1 " id='P__Outer_Text'" _T1P "> ( Outer Text ) </span><a></a>" _BT1 " id='copy_button'> 复制 " _BT2 _T2 _LPRE ">" TransformHTML(Var) _PRE2

	x1 := pbrt.left * ratio, y1 := pbrt.top * ratio
	x2 := pbrt.right * ratio, y2 := pbrt.bottom * ratio
	ObjRelease(pwin), ObjRelease(pelt), ObjRelease(WB2), ObjRelease(iFrame), ObjRelease(pbrt)

	If (ThisMode = "Control") && (StateLight = 1 || (StateLight = 3 && GetKeyState("Shift")))
	{
		WinGetPos, sX, sY, , , ahk_id %hwnd%
		StateLightMarker ? ShowMarker(sX + x1, sY + y1, x2 - x1, y2 - y1) : 0
		StateLightAcc ? ShowAccMarker(AccCoord[1], AccCoord[2], AccCoord[3], AccCoord[4]) : 0
	} 
	; SetPosObject("Control", [Round(sX + x1), Round(sY + y1), Round(x2 - x1), Round(y2 - y1)])  
	SetPosObject("Control", [Format("{:d}", sX + x1), Format("{:d}", sY + y1), Format("{:d}", x2 - x1), Format("{:d}", y2 - y1)])  
	If (pelt.TagName)
		Info := _T1 " id='P__Tag_name' name='MS:N'> ( Tag name: <span name='MS:' style='color: #" ColorFont ";'>"
		. pelt.TagName "</span>" (Frame ? " - (in frame)" : "") " ) </span>" _T2
		. _PRE1  "<span class='param'>位置: </span><span name='MS:'>x" Round(x1) " y" Round(y1) "</span>"
		. _DP "<span name='MS:'>x²" Round(x2) - 1 " y²" Round(y2) - 1 "</span>"
		. _DP "<span class='param'>大小: </span><span name='MS:'>w" Round(x2 - x1) " h" Round(y2 - y1) "</span>" Info _PRE2

	oPubObj.IEElement := {Pos:[sX + x1, sY + y1, x2 - x1, y2 - y1], hwnd:hwnd}
	
	Return Topic Info HTML Text Frame 
}

WBGet(hwnd) {
	Static Msg := DllCall("RegisterWindowMessage", "Str", "WM_HTML_GETOBJECT")
	, IID_IHTMLWindow2 := "{332C4427-26CB-11D0-B483-00C04FD90119}", GUID, _ := VarSetCapacity(GUID,16,0)
	SendMessage, Msg, , , , ahk_id %hwnd%
	DllCall("oleacc\ObjectFromLresult", "Ptr", ErrorLevel, "Ptr", &GUID, "Ptr", 0, PtrP, pdoc)
	Return ComObj(9, ComObjQuery(pdoc, IID_IHTMLWindow2, IID_IHTMLWindow2), 1), ObjRelease(pdoc)
}

	; ___________________________ Get Acc Info _________________________________________________

	;;  http://www.autohotkey.com/board/topic/77888-accessible-info-viewer-alpha-release-2012-09-20/
	   
AccInfoUnderMouse(mx, my, wx, wy, cx, cy, caX, caY, WinID, ControlID, fromhandle = 0) {
	Static hLibrary, AccObj, WM_GETOBJECT := 0x003D, OBJID_CARET := 0xFFFFFFF8
	
	If (WinID = "") { 
		AccObj := ""
		Return
	}
	If !hLibrary
		hLibrary := DllCall("LoadLibrary", "Str", "oleacc", "Ptr")
	
	WinID := RealHwnd(WinID)
	ControlID := RealHwnd(ControlID)
	AccObj := ""
	If (oOther.AccCLOAKEDWinID != oPubObj.Acc.WinID && oPubObj.Acc.pAccObj)
		ObjRelease(oPubObj.Acc.pAccObj), oPubObj.Acc.pAccObj := 0 
	If !fromhandle
	{
			;;  https://docs.microsoft.com/en-us/windows/win32/api/oleacc/nf-oleacc-accessibleobjectfrompoint
		If DllCall("oleacc\AccessibleObjectFromPoint"
			, "Int64", mx & 0xFFFFFFFF | my << 32, "Ptr*", pAccObj
			, "Ptr", VarSetCapacity(varChild, 8 + 2 * A_PtrSize, 0) * 0 + &varChild) = 0
			AccObj := ComObject(9, pAccObj, 1)
			
		; http://forum.script-coding.com/viewtopic.php?pid=139109#p139109
		; Acc := ComObjEnwrap(9, pacc, 1), child := NumGet(varChild,8,"UInt")
	}
	Else 
		AccObj := Acc_ObjectFromWindow(ControlID ? ControlID : WinID) 
	 
	If !IsObject(AccObj)
		Return
		
	ObjAddRef(pAccObj) 
	child := NumGet(varChild, 8, "UInt")
	
	; SendMessage, WM_GETOBJECT, 0, 1, , % "ahk_id" (ControlID ? ControlID : WinID) 
	SendMessage, WM_GETOBJECT, 0, 1, Chrome_RenderWidgetHostHWND1, % "ahk_id " WinID
	
	oPubObj.Acc := {AccObj: Object(AccObj), child: child, WinID: WinID, ControlID: ControlID, pAccObj: pAccObj} 
	
	ChildCount := AccObj.accChildCount
	If child
		Var := "<span name='MS:'>Simple Element</span>" _DP "<span class='param' name='MS:N'>Id:  </span>" child
	Else If ChildCount
		Var := "<span name='MS:'>Container</span>" _DP "<span class='param' name='MS:N'>ChildCount:  </span>" ChildCount _DP "<span class='param' name='MS:N'>Id:  </span>" child 
	Else
		Var := "<span name='MS:'>Real Object</span>" _DP "<span class='param' name='MS:N'>Id:  </span>" child    ;;  _DP "<span class='param' name='MS:N'>Container child count:  </span>" ChildCount
		
	If DynamicAccPath
	{ 
		If acc_path_func(0)
			acc_path_value := SaveAccPath()
		Else 
			error := "<span style='color:#" ColorErrorAccPath "'>  路径未找到</span>"
	}
	pathbutton := _DP _BP1 " id='acc_path'> 获得路径 " _BP2 "</span><span id='acc_path_error'>" 错误 "</span>" 
	code := _PRE1 "<span class='param'>类型:</span>  " Var pathbutton 
	. _DP _BP1 " id='acc_DoDefaultAction2'> 执行默认操作 " _BP2 "</span>"
	. _PRE2 "<span id='acc_path_value'>" acc_path_value "</span>" 

	AccGetLocation(AccObj, child)
	x := AccCoord[1], y := AccCoord[2], w := AccCoord[3], h := AccCoord[4] 
	SetPosObject("accesible", [x, y, w, h])  

	code .= _T1 " id='P__Position_relative_Acc'" _T1P "> ( 相对位置 ) </span>" _T2
		. _PRE1 "<span class='param'>屏幕: </span>"
		. "<span name='MS:'>x" x " y" y "</span>"
		. _DP "<span name='MS:'>x²" x + w - 1 " y²" y + h - 1 "</span>"
		. _DP "<span class='param'>大小: </span><span name='MS:'>w" w " h" h "</span>"
		.  _DP  "<span class='param'>鼠标: </span><span name='MS:'>x" mx - AccCoord[1] " y" my - AccCoord[2] "</span>`n"

		. "<span class='param'>窗口: </span><span name='MS:'>x" x - wx " y" y - wy "</span>"
		. _DP "<span name='MS:'>x²" x - wx + w - 1 " y²" y - wy + h - 1 "</span>"
		
		. _DP "<span class='param'>客户端: </span><span name='MS:'>x" x - wx - caX " y" y - wy - caY "</span>"
		. _DP "<span name='MS:'>x²" x - wx + w - 1 - caX " y²" y - wy + h - 1 - caY "</span>"
		 
		. (cx != "" ? _DP "<span class='param'>控件: </span><span name='MS:'>x" (x - wx - cx) " y" (y - wy - cy) "</span>"
		. _DP "<span name='MS:'>x²" (x - wx - cx) + w - 1 " y²" (y - wy - cy) + h - 1 "</span>" : "")  _PRE2

	CaretPos := AccGetLocationToObj(Acc_ObjectFromWindow(WinID, OBJID_CARET))
	If (CaretPos.x != 0 || CaretPos.y != 0)
	{ 
		code .= _T1 " id='P__CaretPos_Acc'" _T1P "> ( Caret position relative ) </span>" _T2
			. _PRE1 "<span class='param'>Screen: </span>"
			. "<span name='MS:'>x" CaretPos.x " y" CaretPos.y "</span>"
			. _DP "<span class='param'>Window: </span>"
			. "<span name='MS:'>x" (CaretPos.x - wx) " y" (CaretPos.y - wy) "</span>"
			. _DP "<span class='param'>Client: </span>"
			. "<span name='MS:'>x" (CaretPos.x - wx - caX) " y" (CaretPos.y - wy - caY) "</span>"
			. _DP "<span class='param'>Size: </span>"
			. "<span name='MS:'>w" CaretPos.w " h" CaretPos.h "</span>" . _PRE2
	} 
	If (pAccObj && (Hwnd := AccWindowFromObject(pAccObj)) != ControlID && Hwnd != WinID) {   ;	можно Acc вместо pAccObj, then ComObjValue
		WinGetClass, CtrlClass, ahk_id %Hwnd%
		WinGet, WinProcess, ProcessName, ahk_id %Hwnd%
		WinGet, WinPID, PID, ahk_id %Hwnd%
		code .= _T1 " id='P__WindowFromObject'" _T1P "> ( WindowFromObject ) </span><a></a>" _T2 _PRE1
		. "<div style='background-color: #" ColorHighLightBckg "'><span class='param' name='MS:N'>HWND:</span>  <span name='MS:'>" Format("0x{:x}", Hwnd) "</span>"
		. _DP "<span class='param' name='MS:N'>Class:</span>  <span name='MS:'>" TransformHTML(CtrlClass) "</span>"
		. _DP "<span class='param' name='MS:N'>Exe:</span>  <span name='MS:'>" TransformHTML(WinProcess) "</span>"
		. _DP "<span class='param' name='MS:N'>PID:</span>  <span name='MS:'>" WinPID "</span></div>" _PRE2
	}
	If ((Var := AccObj.accName(child)) != "")
		code .= _T1 " id='P__Name_Acc'" _T1P "> ( 名字 ) </span><a></a>" _BT1 " id='copy_button'> 复制 " _BT2 _T2 _LPRE ">" TransformHTML(Var) _PRE2
		
	If ((Var := AccObj.accValue(child)) != "")
		code .= _T1 " id='P__Value_Acc'" _T1P "> ( 值 ) </span><a></a>" _BT1 " id='copy_button_Value_Acc'> 复制 " _BT2 
		. _DB _BT1 " id='set_accvalue'> set " _BT2 _T2 _LPRE " id='get_accvalue'>" TransformHTML(Var) _PRE2
		
	AccState(AccObj, child, style, strstyles)
	If (strstyles != "")
		code .= _T1 " id='P__State_Acc'" _T1P "> ( 状态: <span name='MS:' style='color: #" ColorFont ";'>" style "</span> ) </span>" _T2 _PRE1 strstyles _PRE2
		
	If ((Var := AccRole(AccObj, child)) != "")
		code .= _T1 " id='P__Role_Acc'" _T1P "> ( 角色 ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>"
		. _DP "<span class='param' name='MS:N'>code: </span><span name='MS:'>" AccObj.accRole(child) "</span>" _PRE2
		
	If (child &&(Var := AccRole(AccObj)) != "")
		code .= _T1 " id='P__Role_parent_Acc'" _T1P "> ( 父角色 ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>"
		. _DP "<span class='param' name='MS:N'>code: </span><span name='MS:'>" AccObj.accRole(0) "</span>" _PRE2
	
	; http://forum.script-coding.com/viewtopic.php?pid=146925#p146925	 ToolTip % Format("0x{:x}", RealHwnd(A_LastError))
	Var := AccObj.accDefaultAction(child)  
	If (!A_LastError)
		code .= _T1 " id='P__Action_Acc'" _T1P "> ( 动作 ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>" 
		. _DP _BP1 " id='acc_DoDefaultAction'> Execute " _BP2 _PRE2
		
	If ((Var := AccObj.accSelection) > 0)
		code .= _T1 " id='P__Selection_parent_Acc'" _T1P "> ( 父选区) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>" _PRE2
	
	If ((Var := AccObj.accDescription(child)) != "")
		code .= _T1 " id='P__Description_Acc'" _T1P "> ( 描述) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>" _PRE2
	
	If ((Var := AccObj.accKeyboardShortCut(child)) != "")
		code .= _T1 " id='P__ShortCut_Acc'" _T1P "> ( 快捷键 ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>" _PRE2
	
	If ((Var := AccObj.accHelp(child)) != "")
		code .= _T1 " id='P__Help_Acc'" _T1P "> ( 帮助 ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>" _PRE2
	
	If ((Var := AccObj.AccHelpTopic(child)))
		code .= _T1 " id='P__HelpTopic_Acc'" _T1P "> ( HelpTopic ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(Var) "</span>" _PRE2
		
	AccAccFocus(WinID, accFocusName, accFocusValue, role, irole)
	If (accFocusName != "")
		code .= _T1 " id='P__Focus_name_Acc'" _T1P "> ( 焦点名字 ) </span><a></a>" 
		. _BT1 " id='copy_button'> 复制 " _BT2 _T2 _LPRE ">" TransformHTML(accFocusName) _PRE2
	If (accFocusValue != "")
		code .= _T1 " id='P__Focus_value_Acc'" _T1P "> ( 焦点值 ) </span><a></a>"
		. _BT1 " id='copy_button'> 复制 " _BT2 _T2 _LPRE ">" TransformHTML(accFocusValue) _PRE2
	If (role != "" && irole != "")
		, code .= _T1 " id='P__Focus__Role_Acc'" _T1P "> ( 焦点角色 ) </span>" _T2 _PRE1 "<span name='MS:'>" TransformHTML(role) "</span>"
		. _DP "<span class='param' name='MS:N'>code: </span><span name='MS:'>" irole "</span>" _PRE2 
	 
	Return code
}


EVENT_OBJECT_CLOAKED(hWinEventHook, event, hwnd, idObject, idChild) { 
	Critical
	If (idObject || idChild) || (hwnd != oPubObj.Acc.WinID)
		Return
	; ToolTip % ComObjType(AccObj, "Name") "`n" A_ThisFunc
	oPubObj.Acc.CLOAKED := 1 
	AccInfoUnderMouse("", "", "", "", "", "", "", "", "", "")
	oOther.AccCLOAKEDpAccObj := oPubObj.Acc.pAccObj
	oOther.AccCLOAKEDWinID := oPubObj.Acc.WinID
}

EVENT_OBJECT_UNCLOAKED(hWinEventHook, event, hwnd, idObject, idChild) {
	Critical
	If (idObject || idChild) || (hwnd != oOther.AccCLOAKEDWinID)
		Return 
	; ToolTip % hwnd "`n" oOther.AccCLOAKEDpAccObj "`n" A_ThisFunc
	ObjRelease(oOther.AccCLOAKEDpAccObj)
	oPubObj.Acc.CLOAKED := 0
	oOther.AccCLOAKEDpAccObj := ""
	oOther.AccCLOAKEDWinID := ""
}

accset_accvalue() { 
	If oPubObj.Acc.CLOAKED
		Return 0, ToolTip("CLOAKED", 500)
	Acc := Object(oPubObj.Acc.AccObj)   
	Acc.accValue := oDoc.getElementById("get_accvalue").innerText 
} 

accDoDefaultAction() { 
	If oPubObj.Acc.CLOAKED
		Return 0, ToolTip("CLOAKED", 500)
	Acc := Object(oPubObj.Acc.AccObj) 
	Acc.accDoDefaultAction(oPubObj.Acc.child) 
	
	; https://learn.microsoft.com/ru-ru/windows/win32/winauto/selflag
	; Acc.accSelect(0x00000002, oPubObj.Acc.child) 
} 
	
	;;	https://docs.microsoft.com/ru-ru/windows/desktop/WinAuto/object-state-constants
	;;	http://forum.script-coding.com/viewtopic.php?pid=130762#p130762
AccState(Acc, child, byref style, byref str, i := 1) {
	style := Format("0x{1:08X}", Acc.accState(child))
	If (style = 0)
		Return "", str := "<span class='param' name='MS:'>" AccGetStateText(0) "</span>" _DP "<span name='MS:'>" 0x00000000 "</span>`n"
	While (i <= style) {
		if (i & style)
			str .= "<span class='param' name='MS:'>" AccGetStateText(i) "</span>" _DP "<span name='MS:'>" Format("0x{1:08X}", i) "</span>`n"
		i <<= 1
	}
}

AccWindowFromObject(pacc) {
	If DllCall("oleacc\WindowFromAccessibleObject", "Ptr", IsObject(pacc) ? ComObjValue(pacc) : pacc, "Ptr*", hWnd) = 0
		Return hWnd
}
	;;	http://forum.script-coding.com/viewtopic.php?pid=130762#p130762

AccAccFocus(hWnd, byref name, byref value, byref role, byref irole) {
	Acc := Acc_ObjectFromWindow(hWnd)
	While IsObject(Acc.accFocus)
		Acc := Acc.accFocus
	try 
	{
		child := Acc.accFocus
		name := Acc.accName(child)
		value := Acc.accValue(child)
		role := AccRole(Acc, child) 
		irole := Acc.accRole(0) 
	}
}

AccRole(Acc, ChildId=0) {
	Return ComObjType(Acc, "Name") = "IAccessible" ? AccGetRoleText(Acc.accRole(ChildId)) : ""
}

AccGetRoleText(nRole) {
	nSize := DllCall("oleacc\GetRoleText", "UInt", nRole, "Ptr", 0, "UInt", 0)
	VarSetCapacity(sRole, (A_IsUnicode?2:1)*nSize)
	DllCall("oleacc\GetRoleText", "UInt", nRole, "str", sRole, "UInt", nSize+1)
	Return sRole
}

AccGetStateText(nState) {
	nSize := DllCall("oleacc\GetStateText", "UInt", nState, "Ptr", 0, "UInt", 0)
	VarSetCapacity(sState, (A_IsUnicode?2:1)*nSize)
	DllCall("oleacc\GetStateText", "UInt", nState, "str", sState, "UInt", nSize+1)
	Return sState
}

SaveAccPath(Path = "") {
	Static p
	If Path =
		Return p
	p := Path
}

AddSpace(c) {
	loop % c
		Tab .= "<span class='param';'>↓    </span>"
	Return Tab
}

; accNavigate https://forum.script-coding.com/viewtopic.php?pid=152860#p152860

GetAccPath() { 
	if !Acc_GetPath(arr)
		Return 0  
	i := arr[1].Path = 0 ? 2 : 1
	If !CompareAcc(Acc_Get("Object", arr[i].Path, 0, "ahk_id " arr[i].hWnd), Object(oPubObj.Acc.AccObj))
		Return ""
		
	for k, v in arr
	{
		If (v.Path = 0) 
			tree .= AddSpace(k - 1) "<span><span style='color:#" ColorErrorAccPath "'>path not found</span>" _DP  "<span name='MS:'>" v.Hwnd "</span>" 
			. _DP "<span name='MS:'>" v.WinClass "</span>" _DP  "<span name='MS:'>" v.ProcessName "</span></span>"
			. _DP2 _BP1 " id='b_hwnd_flash' value='" v.Hwnd "'> flash " _BP2 "`n" 
		Else 
			tree .= AddSpace(k - 1) "<span><span name='MS:'>" v.Path "</span>" _DP  "<span name='MS:'>" v.Hwnd "</span>"
			. _DP2 _BP1 " id='b_hwnd_flash' value='" v.Hwnd "'> flash " _BP2 
			. _DP "<span name='MS:'>" v.WinClass "</span>" _DP  "<span name='MS:'>" v.ProcessName "</span></span>" "`n" 
	}
	tree := _T1 " id='P__Tree_Acc_Path'" _T1P "> ( Accessible path ) </span>" _T2 _PRE1 "<span>" tree "</span>" _PRE2
	SaveAccPath(tree)
	Return 1
}

Acc_GetPath(byref arr) {
    Static DesktopHwnd := DllCall("User32.dll\GetDesktopWindow", "ptr") 
	If oPubObj.Acc.CLOAKED
		Return 0
	Acc := Object(oPubObj.Acc.AccObj) 
	arr := [] 
	While Hwnd := Acc_WindowFromObject(Parent := Acc_Parent(Acc)) { 
		If (DesktopHwnd != Hwnd)
			t1 := GetEnumIndex(Acc)  
		If t1 = -1
			Return arr := ""
		If (PrHwnd != "" && Hwnd != PrHwnd)
		{ 
			PrHwnd := Format("0x{:06X}", PrHwnd)
			WinGetClass, WinClass, ahk_id %PrHwnd%
			WinGet, ProcessName, ProcessName, ahk_id %PrHwnd%
			arr.InsertAt(1, {Hwnd: PrHwnd, Path: SubStr(t2, 1, -1), WinClass: WinClass, ProcessName: ProcessName}) 
			if (t1 = "" && Hwnd != DesktopHwnd)
			{
				Hwnd := Format("0x{:06X}", Hwnd)
				WinGetClass, WinClass, ahk_id %Hwnd%
				WinGet, ProcessName, ProcessName, ahk_id %Hwnd%
				arr.InsertAt(1, {Hwnd: Hwnd, Path: "0", WinClass: WinClass, ProcessName: ProcessName}) 
			}
		}
		if (t1 = "" || Hwnd = DesktopHwnd)
		   break 
		PrHwnd := Hwnd
		Acc := Parent
		t2 := t1 "." t2
	}
	; If (arr[1].hWnd != oPubObj.Acc.WinID)
		; Return 0
		
		; MsgBox %  Format("0x{:06X}", Acc_WindowFromObject( Acc_Parent(Acc)))
	; SetFormat, IntegerFast, H
	; MsgBox % arr[1].Path "`n" arr[1].hWnd + 0  "`n" DesktopHwnd + 0 "`n" oPubObj.Acc.WinID + 0
	; "4.1.2.1.1.1.1.1.2.1.2.3.1.1".accName(0)    arr[1].Path
	; MsgBox %  Acc_Get("Object", "4.1.1.1.2.1.2.3.1.1", 0, "ahk_id " 0x030F50).accName(0)
	Return arr.Count()
}

GetEnumIndex(Acc) {	
	If oPubObj.Acc.CLOAKED
		Return -1
	For Each, child in Acc_Children(Acc_Parent(Acc))
	{ 
		if CompareAcc(child, Acc) 
			return A_Index
	}
}

CompareAcc(Acc1, Acc2) { 
	if IsObject(Acc1) && IsObject(Acc2)
	&& (Acc_Location(Acc1) = Acc_Location(Acc2))
	&& (Acc1.accDefaultAction(0) = Acc2.accDefaultAction(0)) 	
	&& (Acc1.accDescription(0) = Acc2.accDescription(0)) 	
	&& (Acc1.accHelp(0) = Acc2.accHelp(0)) 	
	&& (Acc1.accKeyboardShortcut(0) = Acc2.accKeyboardShortcut(0))
	&& (Acc1.accChildCount = Acc2.accChildCount) 
	&& (Acc1.accName(0) = Acc2.accName(0)) 	
	&& (Acc1.accRole(0) = Acc2.accRole(0)) 	
	&& (Acc1.accState(0) = Acc2.accState(0)) 
	&& (Acc1.accValue(0) = Acc2.accValue(0))
		return 1
}

Acc_Children(Acc) {
	if ComObjType(Acc, "Name") != "IAccessible"
		return
	else
	{
		cChildren := Acc.accChildCount, Children := [] 
		if DllCall("oleacc\AccessibleChildren"
		, "Ptr", ComObjValue(Acc)
		, "Int", 0, "Int", cChildren
		, "Ptr", VarSetCapacity(varChildren, cChildren * (8 + 2 * A_PtrSize), 0) * 0 + &varChildren
		, "Int*", cChildren) = 0 
		{
			Loop %cChildren%
				i := (A_Index - 1) * (A_PtrSize * 2 + 8) + 8
				, child := NumGet(varChildren, i)
				, Children.Insert(NumGet(varChildren, i - 8) = 9 ? Acc_Query(child) : child)
				, NumGet(varChildren, i - 8) = 9 ? ObjRelease(child) : ""
			return Children.MaxIndex() ? Children : ""
		}
	}
}
AccGetLocation(Acc, ChildId=0) {
	Static x := 0, y := 0, w := 0, h := 0
	try Acc.accLocation(ComObj(0x4003,&x), ComObj(0x4003,&y), ComObj(0x4003,&w), ComObj(0x4003,&h), ChildId)
	AccCoord[1]:=NumGet(x,0,"int"), AccCoord[2]:=NumGet(y,0,"int"), AccCoord[3]:=NumGet(w,0,"int"), AccCoord[4]:=NumGet(h,0,"int")
}
AccGetLocationToObj(Acc, ChildId=0) {
	Static x := 0, y := 0, w := 0, h := 0
	try Acc.accLocation(ComObj(0x4003,&x), ComObj(0x4003,&y), ComObj(0x4003,&w), ComObj(0x4003,&h), ChildId)
	Return {"x":NumGet(x,0,"int"),"y":NumGet(y,0,"int"),"w":NumGet(w,0,"int"),"h":NumGet(h,0,"int")}
} 
Acc_Location(Acc, ChildId=0) {
	Static x := 0, y := 0, w := 0, h := 0
	try Acc.accLocation(ComObj(0x4003,&x), ComObj(0x4003,&y), ComObj(0x4003,&w), ComObj(0x4003,&h), ChildId)
	return "x" NumGet(x, 0, "int") " y" NumGet(y, 0, "int") " w" NumGet(w, 0, "int") " h" NumGet(h, 0, "int")
}
Acc_ObjectFromPoint(ByRef _idChild_ = "", x = "", y = "") {
	If DllCall("oleacc\AccessibleObjectFromPoint", "Int64", x==""||y==""?0*DllCall("GetCursorPos","Int64*",pt)+pt:x&0xFFFFFFFF|y<<32
		, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
		Return ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}
Acc_ObjectFromWindow(hWnd, idObject = 0) {
	If DllCall("oleacc\AccessibleObjectFromWindow", "UPtr", hWnd, "UInt", idObject&=0xFFFFFFFF
		, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81
		,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0
		Return ComObjEnwrap(9,pacc,1)
}

Acc_WindowFromObject(pacc) {
	If DllCall("oleacc\WindowFromAccessibleObject", "Ptr", IsObject(pacc) ? ComObjValue(pacc) : pacc, "Ptr*", hWnd)=0
		Return	hWnd
} 
Acc_Parent(Acc) { 
	try parent := Acc.accParent 
	return parent ? Acc_Query(parent) : ""
}
Acc_Query(Acc) {
	try return ComObj(9, ComObjQuery(Acc, "{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
Acc_Error(p="") {
	static setting:=0
	return p=""?setting:setting:=p
}
Acc_Role(Acc, ChildId=0) {
	try return ComObjType(Acc,"Name")="IAccessible"?Acc_GetRoleText(Acc.accRole(ChildId)):"invalid object"
}
Acc_GetRoleText(nRole)
{
	nSize := DllCall("oleacc\GetRoleText", "Uint", nRole, "Ptr", 0, "Uint", 0)
	VarSetCapacity(sRole, (A_IsUnicode?2:1)*nSize)
	DllCall("oleacc\GetRoleText", "Uint", nRole, "str", sRole, "Uint", nSize+1)
	Return	sRole
}
Acc_ChildrenByRole(Acc, Role) {
	if ComObjType(Acc,"Name")!="IAccessible"
		ErrorLevel := "Invalid IAccessible Object"
	else {
		cChildren:=Acc.accChildCount, Children:=[]
		if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
			Loop %cChildren% {
				i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i)
				if NumGet(varChildren,i-8)=9
					AccChild:=Acc_Query(child), ObjRelease(child), Acc_Role(AccChild)=Role?Children.Insert(AccChild):
				else
					Acc_Role(Acc, child)=Role?Children.Insert(child):
			}
			return Children.MaxIndex()?Children:, ErrorLevel:=0
		} else
			ErrorLevel := "AccessibleChildren DllCall Failed"
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}
Acc_Get(Cmd, ChildPath="", ChildID=0, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="") {
	static properties := {Action:"DefaultAction", DoAction:"DoDefaultAction", Keyboard:"KeyboardShortcut"}
	AccObj :=   IsObject(WinTitle)? WinTitle
			:   Acc_ObjectFromWindow( WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText), 0 )
	if ComObjType(AccObj, "Name") != "IAccessible"
		ErrorLevel := "Could not access an IAccessible Object"
	else {
		StringReplace, ChildPath, ChildPath, _, %A_Space%, All
		AccError:=Acc_Error(), Acc_Error(true)
		Loop Parse, ChildPath, ., %A_Space%
			try {
				if A_LoopField is digit
					Children:=Acc_Children(AccObj), m2:=A_LoopField ; mimic "m2" output in else-statement
				else
					RegExMatch(A_LoopField, "(\D*)(\d*)", m), Children:=Acc_ChildrenByRole(AccObj, m1), m2:=(m2?m2:1)
				if Not Children.HasKey(m2)
					throw
				AccObj := Children[m2]
			} catch {
				ErrorLevel:="Cannot access ChildPath Item #" A_Index " -> " A_LoopField, Acc_Error(AccError)
				if Acc_Error()
					throw Exception("Cannot access ChildPath Item", -1, "Item #" A_Index " -> " A_LoopField)
				return   ; Acc_Error
			}
		Acc_Error(AccError)
		StringReplace, Cmd, Cmd, %A_Space%, , All
		properties.HasKey(Cmd)? Cmd:=properties[Cmd]:
		try {
			if (Cmd = "Location")
				AccObj.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
			  , ret_val := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")
			else if (Cmd = "Object")
				ret_val := AccObj
			else if Cmd in Role,State
				ret_val := Acc_%Cmd%(AccObj, ChildID+0)
			else if Cmd in ChildCount,Selection,Focus
				ret_val := AccObj["acc" Cmd]
			else
				ret_val := AccObj["acc" Cmd](ChildID+0)
		} catch {
			ErrorLevel := """" Cmd """ Cmd Not Implemented"
			if Acc_Error()
				throw Exception("Cmd Not Implemented", -1, Cmd)
			return
		}
		return ret_val, ErrorLevel:=0
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}

	; ___________________________ UIA _________________________________________________

class UIASub {
	__New() { 
		Try this.pUIA := ComObjCreate("{ff48dba4-60ef-4201-aa87-54103eef594e}","{30cbe57d-d9d0-452a-ab13-7ac5ac4825ee}")
		Catch
			Return 0
	}
	__Get(member) {  
		If !this.__Properties(member, PropI, PropW)
			Return 0
		If (PropW = "RECT")
			Return (this.__Hr(DllCall(this.__Vt(PropI, this.pElement), "ptr", this.pElement
			, "ptr", &(rect, VarSetCapacity(rect, 16)))) ? this.__RectToObject(&rect) : 0), VarSetCapacity(rect, 0)
		If !this.__Hr(DllCall(this.__Vt(PropI, this.pElement), "ptr", this.pElement, "ptr*", out))
			Return 0
		Return PropW = "BSTR" ? StrGet(out) : out   
	}
	__RectToObject(prect) { 
		Return {left: NumGet(prect + 0, 0, "Int"), top: NumGet(prect + 0, 4, "Int"), right: NumGet(prect + 0, 8, "Int"), bottom: NumGet(prect + 0, 12, "Int")
			, width: NumGet(prect + 0, 8, "Int") - NumGet(prect + 0, 0, "Int") + 0, height: NumGet(prect + 0, 12, "Int") - NumGet(prect + 0, 4, "Int") + 0}
	}
	__Delete() {
		ObjRelease(this.pUIA)
	}
	__Vt(n, p) {
		Return NumGet(NumGet(p + 0, "ptr") + n * A_PtrSize, "ptr")
	}
	__Hr(hr) {
		;~ http://blogs.msdn.com/b/eldar/archive/2007/04/03/a-lot-of-hresult-codes.aspx
		; Static err:={0x8000FFFF:"Catastrophic failure.",0x80004001:"Not implemented.",0x8007000E:"Out of memory."
		; ,0x80070057:"One or more arguments are not valid.",0x80004002:"Interface not supported.",0x80004003:"Pointer not valid."
		; ,0x80070006:"Handle not valid.",0x80004004:"Operation aborted.",0x80004005:"Unspecified error.",0x80070005:"General access denied."
		; ,0x800401E5:"The object identified by this moniker could not be found.",0x80040201:"UIA_E_ELEMENTNOTAVAILABLE"
		; ,0x80040200:"UIA_E_ELEMENTNOTENABLED",0x80131509:"UIA_E_INVALIDOPERATION",0x80040202:"UIA_E_NOCLICKABLEPOINT"
		; ,0x80040204:"UIA_E_NOTSUPPORTED",0x80040203:"UIA_E_PROXYASSEMBLYNOTLOADED"} ; //not completed
		if hr && (hr &= 0xFFFFFFFF) {
			Return 0
		}
		Return !hr
	}
	__Properties(name, byref index, byref word) {
		Static properties1 := {CurrentProcessId: [20,"int"],CurrentControlType: [21,"CONTROLTYPEID"],CurrentLocalizedControlType: [22,"BSTR"]
		,CurrentName: [23,"BSTR"],CurrentAcceleratorKey: [24,"BSTR"],CurrentAccessKey: [25,"BSTR"],CurrentHasKeyboardFocus: [26,"BOOL"]
		,CurrentIsKeyboardFocusable: [27,"BOOL"],CurrentIsEnabled: [28,"BOOL"],CurrentAutomationId: [29,"BSTR"],CurrentClassName: [30,"BSTR"]
		,CurrentHelpText: [31,"BSTR"],CurrentCulture: [32,"int"],CurrentIsControlElement: [33,"BOOL"],CurrentIsContentElement: [34,"BOOL"]
		,CurrentIsPassword: [35,"BOOL"],CurrentNativeWindowHandle: [36,"UIA_HWND"],CurrentItemType: [37,"BSTR"],CurrentIsOffscreen: [38,"BOOL"]
		,CurrentOrientation: [39,"OrientationType"],CurrentFrameworkId: [40,"BSTR"],CurrentIsRequiredForForm: [41,"BOOL"],CurrentItemStatus: [42,"BSTR"]
		,CurrentBoundingRectangle: [43,"RECT"],CurrentLabeledBy: [44,"IUIAutomationElement"],CurrentAriaRole: [45,"BSTR"]
		,CurrentAriaProperties: [46,"BSTR"],CurrentIsDataValidForForm: [47,"BOOL"],CurrentControllerFor: [48,"IUIAutomationElementArray"]
		,CurrentDescribedBy: [49,"IUIAutomationElementArray"], CurrentFlowsTo: [50,"IUIAutomationElementArray"],CurrentProviderDescription: [51,"BSTR"]}
		
		Static properties2 := {CachedProcessId: [52,"int"],CachedControlType: [53,"CONTROLTYPEID"],CachedLocalizedControlType: [54,"BSTR"]
		,CachedName: [55,"BSTR"],CachedAcceleratorKey: [56,"BSTR"],CachedAccessKey: [57,"BSTR"],CachedHasKeyboardFocus: [58,"BOOL"]
		,CachedIsKeyboardFocusable: [59,"BOOL"],CachedIsEnabled: [60,"BOOL"],CachedAutomationId: [61,"BSTR"],CachedClassName: [62,"BSTR"]
		,CachedHelpText: [63,"BSTR"],CachedCulture: [64,"int"],CachedIsControlElement: [65,"BOOL"],CachedIsContentElement: [66,"BOOL"]
		,CachedIsPassword: [67,"BOOL"],CachedNativeWindowHandle: [68,"UIA_HWND"],CachedItemType: [69,"BSTR"],CachedIsOffscreen: [70,"BOOL"]
		,CachedOrientation: [71,"OrientationType"],CachedFrameworkId: [72,"BSTR"],CachedIsRequiredForForm: [73,"BOOL"]
		,CachedItemStatus: [74,"BSTR"],CachedBoundingRectangle: [75,"RECT"],CachedLabeledBy: [76,"IUIAutomationElement"]
		,CachedAriaRole: [77,"BSTR"],CachedAriaProperties: [78,"BSTR"],CachedIsDataValidForForm: [79,"BOOL"]
		,CachedControllerFor: [80,"IUIAutomationElementArray"],CachedDescribedBy: [81,"IUIAutomationElementArray"]
		,CachedFlowsTo: [82,"IUIAutomationElementArray"],CachedProviderDescription: [83,"BSTR"]}	; (,)(\d+),(.*?)(`r`n)			: [$2,"$3"],
 
		If properties1.HasKey(name)
			Return 1, index := properties1[name][1], word := properties1[name][2]
		If properties2.HasKey(name)
			Return 1, index := properties2[name][1], word := properties2[name][2] 
	}
	__ControlType(n) {
		Static name := {50000:"Button",50001:"Calendar",50002:"CheckBox",50003:"ComboBox",50004:"Edit",50005:"Hyperlink",50006:"Image"
		,50007:"ListItem",50008:"List",50009:"Menu",50010:"MenuBar",50011:"MenuItem",50012:"ProgressBar",50013:"RadioButton"
		,50014:"ScrollBar",50015:"Slider",50016:"Spinner",50017:"StatusBar",50018:"Tab",50019:"TabItem",50020:"Text",50021:"ToolBar"
		,50022:"ToolTip",50023:"Tree",50024:"TreeItem",50025:"Custom",50026:"Group",50027:"Thumb",50028:"DataGrid",50029:"DataItem"
		,50030:"Document",50031:"SplitButton",50032:"Window",50033:"Pane",50034:"Header",50035:"HeaderItem",50036:"Table",50037:"TitleBar",50038:"Separator"}
		Return name[n]
	}
	Release() {
		Return 1, this.pElement && ObjRelease(this.pElement), this.pElement := 0
	} 
	ElementFromPoint(x = "", y = "") {  
		Return this.pElement := this.__Hr(DllCall(this.__Vt(7, this.pUIA), "ptr", this.pUIA, "int64"
			, x = "" ? 0 * DllCall("GetCursorPos", "Int64*", pt) + pt : x & 0xFFFFFFFF | y << 32, "ptr*", pElement)) ? pElement : 0 
	}
	ElementFromHandle(hwnd) {
		Return this.pElement := this.__Hr(DllCall(this.__Vt(6, this.pUIA), "ptr", this.pUIA, "Uptr", hwnd, "ptr*", pElement)) ? pElement : 0 
	}
}

	; ___________________________ Mode_Hotkey _________________________________________________

Mode_Hotkey:
	Try SetTimer, Loop_%ThisMode%, Off
	ZoomMsg(10, 1) 
	ShowMarker ? (HideAllMarkers()) : 0
	ColorButton("Button") 
	; oBody.createTextRange().execCommand("RemoveFormat")
	
	ScrollPos[ThisMode, 1] := oDivNew.scrollLeft
	ScrollPos[ThisMode, 2] := oDivNew.scrollTop
	
	If ThisMode != Hotkey
		HTML_%ThisMode% := oDivNew.innerHTML, prNotThisMode := 1
		
	ThisMode := "Hotkey"
	
	If A_GuiControl  ;;	WinActive("ahk_id" hGui)
		Hotkey_Hook(!isPaused)

	If (HTML_Hotkey = "")
		Write_HotkeyHTML({Mods:"等待按下的按键..."}, 1)
	Else 
		Write_Hotkey(prNotThisMode)
	
	TitleText := (TitleTextP1 := "AhkSpy - 按键") . TitleTextP2
	SendMessage, 0xC, 0, &TitleText, , ahk_id %hGui% 
	; WinActivate ahk_id %hGui%  
	If A_GuiControl
		GuiControl, 1:Focus, oDoc
	If isFindView
		FindNewText()		
	oDoc.getElementById("b_CASend").innerText := " send to " (oOther.ControlID ? "control" : "window")
	Return
	
Write_HotkeyHTML(K, scroll = 0, upd = 0) {
	Static PrHK1, PrHK2, PrHKCode, Name
	If upd 
	{
		K := oOther.HotkeyK 
		If !K.IsMouse
			K.IsCode := (SendCode != "name")
		K.HK := K.IsCode ? K[SendCode] : K.TK 
	}	
	Else 
		oOther.HotkeyK := K.Clone() 
	Mods := K.Mods, KeyName := K.Name
	Prefix := K.Pref 
	Hotkey := K.HK = "" ? K.TK : K.HK
	If !K.IsMouse
	K.IsCode := (SendCode != "name") ; 03:15 07.02.2021
	If (K.HK = "") && (K.IsCode) ; 03:15 07.02.2021
		Hotkey := K[SendCode]  ; 03:15 07.02.2021
	LRMods := K.LRMods, LRPref := TransformHTML(K.LRPref)
	ThisKey := K.TK, VKCode := K.VK, SCCode := K.SC
	If (K.NFP && Mods KeyName != "")
		NotPhysical	:= " " _DP "<span style='color:#" ColorDelimiter "'> Emulated</span>"
	
	HK1 := K.IsCode ? Hotkey : ThisKey
	If upd
	{
		PrHK1 := HK2 := PrHKCode[SendCode]  
	} Else  {
		HK2 := HK1 = PrHK1 ? PrHK2 : PrHK1
		PrHK1 := HK1
		PrHK2 := HK2
		PrHKCode := {vk : Format("vk{:X}", GetKeyVK(HK2)), sc : Format("sc{:X}", GetKeySC(HK2)), name : GetKeyName(HK2)}  
	}
	
	HKComm1 := "    `;  """ (StrLen(Name := GetKeyName(HK2)) = 1 ? Format("{:U}", Name) : Name)
	HKComm2 := (StrLen(Name := GetKeyName(HK1)) = 1 ? Format("{:U}", Name) : Name) """"

	If K.IsCode
		Comment := "<span class='param' name='MS:SP'>    `;  """ KeyName """</span>"
	If (Hotkey != "")
		FComment := "<span class='param' name='MS:SP'>    `;  """ (K.HK = "" ? K.TK : Mods KeyName) """</span>"
		, b_ASend := "  " _DP "  " _BP1 " id='b_ASend'> send " _BP2
		
	If (LRMods != "")
	{
		LRMStr := "<span name='MS:'>" LRMods KeyName "</span>"
		If (K.HK != "")
			LRPStr := "  " _DP "  <span><span name='MS:'>" LRPref Hotkey "::</span><span class='param' name='MS:SP'>    `;  """ LRMods KeyName """</span></span>"
	}
	If Prefix !=
		DUMods := (K.MLCtrl ? "{LCtrl Down}" : "") (K.MRCtrl ? "{RCtrl Down}" : "")
			. (K.MLShift ? "{LShift Down}" : "") (K.MRShift ? "{RShift Down}" : "")
			. (K.MLAlt ? "{LAlt Down}" : "") (K.MRAlt ? "{RAlt Down}" : "")
			. (K.MLWin ? "{LWin Down}" : "") (K.MRWin ? "{RWin Down}" : "") . "{" Hotkey "}"
			. (K.MLCtrl ? "{LCtrl Up}" : "") (K.MRCtrl ? "{RCtrl Up}" : "")
			. (K.MLShift ? "{LShift Up}" : "") (K.MRShift ? "{RShift Up}" : "")
			. (K.MLAlt ? "{LAlt Up}" : "") (K.MRAlt ? "{RAlt Up}" : "")
			. (K.MLWin ? "{LWin Up}" : "") (K.MRWin ? "{RWin Up}" : "")

	SendHotkey := Hotkey

	oOther.ControlSend := (DUMods = "" ? "{" SendHotkey "}" : DUMods)
	
	If (oOther.ControlID || oOther.MouseWinID || oOther.WinID)
		CASend := "  " _DP "  " _BP1 " id='b_CASend'> send to " (oOther.ControlID ? "control" : "window") " " _BP2 . "`n<span name='MS:P4'>        </span>" 
	Else 
		CASend := "`n<span name='MS:P'>        </span>"
	CtrlClass := (oOther.ControlID ? oOther.ControlNN : "ahk_parent")
  
	VKCode_ := "0x" SubStr(VKCode, 3)
	SCCode_ := "0x" SubStr(SCCode, 3)

	If DecimalCode
		(VKCode_ += 0), SCCode_ += 0
	s_DecimalCode := DecimalCode ? "dec" : "hex"
   
	If (DUMods != "") 
		LRSend := "  " _DP "  <span><span><span name='MS:P' id='h_SendMode1'>" SendMode "</span>  <span name='MS:'>" DUMods "</span></span>" Comment "</span>" 
	
	If SCCode !=
		ThisKeySC := "   " _DP "   <span name='MS:'>" VKCode "</span>   " _DP "   <span name='MS:'>" SCCode "</span>   "
		. _DP "   <span name='MS:' id='v_VKDHCode'>" VKCode_ "</span>   " _DP "   <span name='MS:' id='v_SCDHCode'>" SCCode_ "</span>"
	Else
		ThisKeySC := "   " _DP "   <span name='MS:' id='v_VKDHCode'>" VKCode_ "</span>"
	
	
	HTML_Hotkey := ""
	. _T1 "> ( 按下的按键 ) </span>" _BT1 " id='pause_button'> 暂停 " _BT2  _DB  _BT1 " id='LButton_Hotkey'> LButton " _BT2  _T2 
	
	. _PRE1 "<br><span name='MS:'>" Mods  KeyName "</span>" NotPhysical "<br><br>" LRMStr "<br>" _PRE2 

	. _T1 "> ( 命令语法 ) </span>" _BT1 " id='SendCode'> " SendCode " " _BT2  _DB  _BT1 " id='SendMode'> " SendModeStr " " _BT2  _T2 

	. _PRE1 "<br><span><span name='MS:'>" Prefix  Hotkey "::</span>" FComment "</span>" LRPStr 

	. "`n<span name='MS:P'>        </span>"

	. "`n<span><span><span name='MS:P' id='h_SendMode2'>" SendMode "</span> <span name='MS:'>" Prefix "{" SendHotkey "}</span></span>" Comment "</span>" b_ASend LRSend  

	. "`n<span name='MS:P'>        </span>"

	. "`n<span><span name='MS:'>ControlSend, " CtrlClass ", <span name='MS:'>" oOther.ControlSend "</span>, WinTitle</span>" Comment "</span>" . CASend
	
	. "`n<span><span name='MS:'>GetKeyState(""" SendHotkey """, ""P"")</span>" Comment "</span>   " 
		. _DP "   <span><span name='MS:'>KeyWait, " SendHotkey ", D T0.5</span>" Comment "</span>"
	
	. "`n<span name='MS:P'>        </span>"

	. "`n<span><span name='MS:'>" HK2 " & " HK1 "::</span><span class='param' name='MS:SP'>" HKComm1 " & " HKComm2 "</span></span>   " 
		. _DP "   <span><span name='MS:'>" HK2 "::" HK1 "</span><span class='param' name='MS:SP'>" HKComm1 " &#8250 &#8250 " HKComm2 "</span></span>"
	
	. "`n<span name='MS:P'>        </span>" _PRE2

	. _T1 "> ( 按键 ) </span>" _BT1 " id='numlock'> num " _BT2  _DB  _BT1 " id='locale_change'> locale " _BT2  
		. _DB  _BT1 " id='hook_reload'> hook reload " _BT2  _DB  _BT1 " id='b_DecimalCode'> " s_DecimalCode " " _BT2
		. _DB  _BT1 " id='hotkey_clip_cursor'> clip cursor " _BT2  _T2 
		
	. _PRE1 "<br><span name='MS:'>" ThisKey "</span>   " _DP "   <span name='MS:'>" VKCode  SCCode "</span>" ThisKeySC 
	
	. "`n`n" _PRE2

	. _T1 ">  ( 获取按键名字 ) </span>" _BT1 " id='paste_keyname'> 粘贴 " _BT2  _T2 
	. "<br>"
	. "<span id='hotkeybox'><input id='edithotkey' value='" oDoc.getElementById("edithotkey").value "'><button id='keyname'> &#8250 </button>"
		. "<input id='editkeyname' value='" oDoc.getElementById("editkeyname").value "'></span>"
	. "<br>"
	. "<br>"
	. "<span id='vkname'>" GetVKCodeNameStr "</span><span id='scname'>" GetSCCodeNameStr "</span>"
	. _T0


	HTML_Hotkey = %HTML_Hotkey%
	( 
		<style> 
		pre {
			line-height: 1.1em;
		}
		#SendCode, #SendMode {
			text-align: center;
			position: absolute;
		}
		#SendCode {
			width: 3em; left: 12em;
		}
		#SendMode {
			width: 5em; left: 16em;
		}
		#hotkeybox {
			position: relative;
			white-space: pre;
			left: 5px;
			display: inline;
		}
		#edithotkey, #keyname, #editkeyname {
			font-size: 1.2em;
			text-align: center;
			border: 1px dotted;
			border-color: #%ColorFont%;
		}
		#keyname {
			position: relative;
			background-color: #%ColorParam%;
			top: 0px; left: 2px; width: 3em;
			width: 3em;
		}
		#editkeyname {
			position: relative;
			left: 4px; top: 0px;
		} 
		</style>
	) 
	Write_Hotkey(scroll)
}

Write_Hotkey(scroll = 0) {
	oDivOld := oDivWork%DivWorkIndex%
	DivWorkIndex := DivWorkIndex = 1 ? 2 : 1
	oDivNew := oDivWork%DivWorkIndex%  
	oDivNew.innerHTML := HTML_Hotkey  
	oDivNew.scrollTop := scroll ? ScrollPos[ThisMode, 2] : (ScrollPos[ThisMode, 2] := oDivOld.scrollTop)
		
	If oDivNew.scrollLeft
		oDivNew.scrollLeft := 0 

	oDivNew.style.zIndex := 1 
	oDivOld.style.zIndex := 0 
	
	oDivNew.style.visibility := "visible"
	oDivOld.innerHTML := ""
	Return 1
}

	; ___________________________ Hotkey Functions _________________________________________________

	;;  http://forum.script-coding.com/viewtopic.php?pid=69765#p69765

Hotkey_Init(Func, Options = "") {
	#HotkeyInterval 0
	Hotkey_Arr("Func", Func)
	Hotkey_Arr("Up", !!InStr(Options, "U"))
	Hotkey_MouseAndJoyInit(Options)
	Hotkey_SetHook()
	Hotkey_Arr("Hook") ? (Hotkey_Hook(0), Hotkey_Hook(1)) : 0
}

Hotkey_Main(In) {
	Static Prefix := {"LCtrl":"<^","LShift":"<+","LAlt":"<!","LWin":"<#"
	,"RCtrl":">^","RShift":">+","RAlt":">!","RWin":">#"}, K := {}, ModsOnly
	Local IsMod, sIsMod
	IsMod := In.IsMod 
	If (In.Opt = "Down") {
		If (K["M" IsMod] != "")
			Return 1
		sIsMod := SubStr(IsMod, 2)
		K["M" sIsMod] := sIsMod "+", K["P" sIsMod] := SubStr(Prefix[IsMod], 2)
		K["M" IsMod] := IsMod "+", K["P" IsMod] := Prefix[IsMod]
	}
	Else If (In.Opt = "Up") {
		sIsMod := SubStr(IsMod, 2)
		K.ModUp := 1, K["M" IsMod] := K["P" IsMod] := ""
		If (K["ML" sIsMod] = "" && K["MR" sIsMod] = "")
			K["M" sIsMod] := K["P" sIsMod] := ""
		If (!Hotkey_Arr("Up") && K.HK != "")
			Return 1
	}
	Else If (In.Opt = "OnlyMods") {
		If !ModsOnly
			Return 0
		K.MCtrl := K.MShift := K.MAlt := K.MWin := K.Mods := ""
		K.PCtrl := K.PShift := K.PAlt := K.PWin := K.Pref := ""
		K.PRCtrl := K.PRShift := K.PRAlt := K.PRWin := ""
		K.PLCtrl := K.PLShift := K.PLAlt := K.PLWin := K.LRPref := ""
		K.MRCtrl := K.MRShift := K.MRAlt := K.MRWin := ""
		K.MLCtrl := K.MLShift := K.MLAlt := K.MLWin := K.LRMods := ""
		Func(Hotkey_Arr("Func")).Call(K)
		Return ModsOnly := 0
	}
	Else If (In.Opt = "GetMod")
		Return !!(K.PCtrl K.PShift K.PAlt K.PWin)
	Else If (In = "LButton")
		GoTo, Hotkey_PressLButton
	
	K.IsMouse := 0
	K.UP := In.UP, K.IsJM := 0, K.Time := In.Time, K.NFP := In.NFP, K.IsMod := IsMod
	K.Mods := K.MCtrl K.MShift K.MAlt K.MWin
	K.LRMods := K.MLCtrl K.MRCtrl K.MLShift K.MRShift K.MLAlt K.MRAlt K.MLWin K.MRWin
	K.VK := "vk" In.VK, K.SC := "sc" In.SC, K.TK := GetKeyName(K.VK K.SC)
	K.TK := K.TK = "" ? K.VK K.SC : (StrLen(K.TK) = 1 ? Format("{:U}", K.TK) : K.TK)
	(IsMod) ? (K.HK := K.Pref := K.LRPref := K.Name := K.IsCode := "", ModsOnly := K.Mods = "" ? 0 : 1)
	; : (K.IsCode := (SendCode != "name" && StrLen(K.TK) = 1)  ;;	 && !Instr("1234567890-=", K.TK) 
	: (K.IsCode := (SendCode != "name")  ; 03:15 07.02.2021  
	, K.HK := K.IsCode ? K[SendCode] : K.TK
	, K.Name := K.HK = "vkBF" ? "/" : K.TK
	, K.Pref := K.PCtrl K.PShift K.PAlt K.PWin
	, K.LRPref := K.PLCtrl K.PRCtrl K.PLShift K.PRShift K.PLAlt K.PRAlt K.PLWin K.PRWin
	, ModsOnly := 0)
	Func(Hotkey_Arr("Func")).Call(K)
	Return 1

Hotkey_PressLButton:
	ThisHotkey := "LButton"
	K.NFP := !GetKeyState(ThisHotkey, "P")
	GoTo, Hotkey_Drop

Hotkey_PressMouseRButton:
	If !WM_CONTEXTMENU() && !Hotkey_Hook(0)
		Return

Hotkey_PressJoy:
Hotkey_PressMouse:
	ThisHotkey := A_ThisHotkey
	K.NFP := !GetKeyState(ThisHotkey, "P")
Hotkey_Drop:
	K.IsMouse := 1
	K.Time := A_TickCount
	K.Mods := K.MCtrl K.MShift K.MAlt K.MWin
	K.LRMods := K.MLCtrl K.MRCtrl K.MLShift K.MRShift K.MLAlt K.MRAlt K.MLWin K.MRWin
	K.Pref := K.PCtrl K.PShift K.PAlt K.PWin
	K.LRPref := K.PLCtrl K.PRCtrl K.PLShift K.PRShift K.PLAlt K.PRAlt K.PLWin K.PRWin
	K.HK := K.Name := K.TK := ThisHotkey, ModsOnly := K.UP := K.IsCode := 0, K.IsMod := K.SC := ""
	K.IsJM := A_ThisLabel = "Hotkey_PressJoy" ? 1 : 2
	K.VK := A_ThisLabel = "Hotkey_PressJoy" ? "" : Format("vk{:X}", GetKeyVK(ThisHotkey))
	Func(Hotkey_Arr("Func")).Call(K)
	Return 1
}

#If Hotkey_Arr("Hook")
#If Hotkey_Arr("Hook") && GetKeyState("RButton", "P")
#If Hotkey_Arr("Hook") && !Hotkey_Main({Opt:"GetMod"})
#If

Hotkey_MouseAndJoyInit(Options) {
	Static MouseKey := "MButton|WheelDown|WheelUp|WheelRight|WheelLeft|XButton1|XButton2"
	Local S_FormatInteger, Option
	Option := InStr(Options, "M") ? "On" : "Off"
	Hotkey, IF, Hotkey_Arr("Hook")
	Loop, Parse, MouseKey, |
		Hotkey, %A_LoopField%, Hotkey_PressMouse, % Option
	Option := InStr(Options, "L") ? "On" : "Off"
	Hotkey, IF, Hotkey_Arr("Hook") && GetKeyState("RButton"`, "P")
	Hotkey, LButton, Hotkey_PressMouse, % Option
	Option := InStr(Options, "R") ? "On" : "Off"
	Hotkey, IF, Hotkey_Arr("Hook")
	Hotkey, RButton, Hotkey_PressMouseRButton, % Option
	Option := InStr(Options, "J") ? "On" : "Off"
	S_FormatInteger := A_FormatInteger
	SetFormat, IntegerFast, D
	Hotkey, IF, Hotkey_Arr("Hook") && !Hotkey_Main({Opt:"GetMod"})
	Loop, 128
		Hotkey % Ceil(A_Index / 32) "Joy" Mod(A_Index - 1, 32) + 1, Hotkey_PressJoy, % Option
	SetFormat, IntegerFast, %S_FormatInteger%
	Hotkey, IF
}

Hotkey_Hook(Val = 1) {
	Hotkey_Arr("Hook", Val)
	!Val && Hotkey_Main({Opt:"OnlyMods"})
}

Hotkey_Arr(P*) {
	Static Arr := {}
	Return P.MaxIndex() = 1 ? Arr[P[1]] : (Arr[P[1]] := P[2])
}

	;;  http://forum.script-coding.com/viewtopic.php?id=6350

Hotkey_LowLevelKeyboardProc(nCode, wParam, lParam) {
	Static Mods := {"A4":"LAlt","A5":"RAlt","A2":"LCtrl","A3":"RCtrl"
	,"A0":"LShift","A1":"RShift","5B":"LWin","5C":"RWin"}, oMem := []
	, HEAP_ZERO_MEMORY := 0x8, Size := 16, hHeap := DllCall("GetProcessHeap", "Ptr")
	Local pHeap, Lp, Ext, VK, SC, SC1, SC2, IsMod, Time, NFP, KeyUp
	Critical

	If !Hotkey_Arr("Hook")
		Return DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "UInt", wParam, "UInt", lParam)
	pHeap := DllCall("HeapAlloc", Ptr, hHeap, UInt, HEAP_ZERO_MEMORY, Ptr, Size, Ptr)
	DllCall("RtlMoveMemory", Ptr, pHeap, Ptr, lParam, Ptr, Size), oMem.Push(pHeap)
	SetTimer, Hotkey_HookProcWork, -10
	Return nCode < 0 ? DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "UInt", wParam, "UInt", lParam) : 1

	Hotkey_HookProcWork:
		While (oMem[1] != "") {
			If Hotkey_Arr("Hook") {
				Lp := oMem[1]
				VK := Format("{:X}", NumGet(Lp + 0, "UInt"))
				Ext := NumGet(Lp + 0, 8, "UInt")
				SC1 := NumGet(Lp + 0, 4, "UInt")
				NFP := (Ext >> 4) & 1				;;  Не физическое нажатие
				KeyUp := Ext >> 7
				;; Time := NumGet(Lp + 12, "UInt")
				IsMod := Mods[VK]
				If !SC1
					SC2 := GetKeySC("vk" VK), SC := SC2 = "" ? "" : Format("{:X}", SC2)
				Else
					SC := Format("{:X}", (Ext & 1) << 8 | SC1)
				If !KeyUp
					IsMod ? Hotkey_Main({VK:VK, SC:SC, Opt:"Down", IsMod:IsMod, NFP:NFP, Time:Time, UP:0})
					: Hotkey_Main({VK:VK, SC:SC, NFP:NFP, Time:Time, UP:0})
				Else
					IsMod ? Hotkey_Main({VK:VK, SC:SC, Opt:"Up", IsMod:IsMod, NFP:NFP, Time:Time, UP:1})
					: (Hotkey_Arr("Up") ? Hotkey_Main({VK:VK, SC:SC, NFP:NFP, Time:Time, UP:1}) : 0)
			}
			DllCall("HeapFree", Ptr, hHeap, UInt, 0, Ptr, Lp)
			oMem.RemoveAt(1)
		}
		Return
}

Hotkey_SetHook(On = 1) {
	Static hHook
	If (On = 1 && !hHook)
		hHook := DllCall("SetWindowsHookEx" . (A_IsUnicode ? "W" : "A")
				, "Int", 13   ;;  WH_KEYBOARD_LL
				, "Ptr", RegisterCallback("Hotkey_LowLevelKeyboardProc", "Fast")
				, "Ptr", DllCall("GetModuleHandle", "UInt", 0, "Ptr")
				, "UInt", 0, "Ptr")
	Else If !On
		DllCall("UnhookWindowsHookEx", "Ptr", hHook), hHook := "", Hotkey_Hook(0)
}

GetVKCodeName(id) {  
  ;;	https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes
  ;;	http://www.kbdedit.com/manual/low_level_vk_list.html

	Static Start, VK_, Chr, Num, Undefined, Reserved, Unassigned, VK_Names
	
	If !Start
	{
		Start := 1 
		VK_ := {01:"VK_LBUTTON",02:"VK_RBUTTON",03:"VK_CANCEL",04:"VK_MBUTTON",05:"VK_XBUTTON1",06:"VK_XBUTTON2",08:"VK_BACK",09:"VK_TAB"
		,0C:"VK_CLEAR",0D:"VK_RETURN",10:"VK_SHIFT",11:"VK_CONTROL",12:"VK_MENU",13:"VK_PAUSE",14:"VK_CAPITAL"
		,15:"VK_KANA := VK_HANGEUL := VK_HANGUL := VK_HANGUEL"
		,17:"VK_JUNJA",18:"VK_FINAL",19:"VK_HANJA := VK_KANJI",1B:"VK_ESCAPE",1C:"VK_CONVERT",1D:"VK_NONCONVERT",1E:"VK_ACCEPT"
		,1F:"VK_MODECHANGE",20:"VK_SPACE",21:"VK_PRIOR",22:"VK_NEXT",23:"VK_END",24:"VK_HOME",25:"VK_LEFT",26:"VK_UP",27:"VK_RIGHT"
		,28:"VK_DOWN",29:"VK_SELECT",2A:"VK_PRINT",2B:"VK_EXECUTE",2C:"VK_SNAPSHOT",2D:"VK_INSERT",2E:"VK_DELETE",2F:"VK_HELP"
		,30:"VK_KEY_0",31:"VK_KEY_1",32:"VK_KEY_2",33:"VK_KEY_3",34:"VK_KEY_4",35:"VK_KEY_5",36:"VK_KEY_6",37:"VK_KEY_7",38:"VK_KEY_8"
		,39:"VK_KEY_9",41:"VK_KEY_A",42:"VK_KEY_B",43:"VK_KEY_C",44:"VK_KEY_D",45:"VK_KEY_E",46:"VK_KEY_F",47:"VK_KEY_G",48:"VK_KEY_H"
		,49:"VK_KEY_I",4A:"VK_KEY_J",4B:"VK_KEY_K",4C:"VK_KEY_L",4D:"VK_KEY_M",4E:"VK_KEY_N",4F:"VK_KEY_O",50:"VK_KEY_P",51:"VK_KEY_Q"
		,52:"VK_KEY_R",53:"VK_KEY_S",54:"VK_KEY_T",55:"VK_KEY_U",56:"VK_KEY_V",57:"VK_KEY_W",58:"VK_KEY_X",59:"VK_KEY_Y",5A:"VK_KEY_Z"
		,5B:"VK_LWIN",5C:"VK_RWIN",5D:"VK_APPS",5F:"VK_SLEEP",60:"VK_NUMPAD0",61:"VK_NUMPAD1",62:"VK_NUMPAD2",63:"VK_NUMPAD3"
		,64:"VK_NUMPAD4",65:"VK_NUMPAD5",66:"VK_NUMPAD6",67:"VK_NUMPAD7",68:"VK_NUMPAD8",69:"VK_NUMPAD9",6A:"VK_MULTIPLY"
		,6B:"VK_ADD",6C:"VK_SEPARATOR",6D:"VK_SUBTRACT",6E:"VK_DECIMAL",6F:"VK_DIVIDE",70:"VK_F1",71:"VK_F2",72:"VK_F3",73:"VK_F4"
		,74:"VK_F5",75:"VK_F6",76:"VK_F7",77:"VK_F8",78:"VK_F9",79:"VK_F10",7A:"VK_F11",7B:"VK_F12",7C:"VK_F13",7D:"VK_F14",7E:"VK_F15"
		,7F:"VK_F16",80:"VK_F17",81:"VK_F18",82:"VK_F19",83:"VK_F20",84:"VK_F21",85:"VK_F22",86:"VK_F23",87:"VK_F24"}
	
		VK__ := {90:"VK_NUMLOCK",91:"VK_SCROLL",92:"VK_OEM_FJ_JISHO := VK_OEM_NEC_EQUAL",93:"VK_OEM_FJ_MASSHOU",94:"VK_OEM_FJ_TOUROKU"
		,95:"VK_OEM_FJ_LOYA",96:"VK_OEM_FJ_ROYA",A0:"VK_LSHIFT",A1:"VK_RSHIFT",A2:"VK_LCONTROL",A3:"VK_RCONTROL",A4:"VK_LMENU"
		,A5:"VK_RMENU",A6:"VK_BROWSER_BACK",A7:"VK_BROWSER_FORWARD",A8:"VK_BROWSER_REFRESH",A9:"VK_BROWSER_STOP",AA:"VK_BROWSER_SEARCH"
		,AB:"VK_BROWSER_FAVORITES",AC:"VK_BROWSER_HOME",AD:"VK_VOLUME_MUTE",AE:"VK_VOLUME_DOWN",AF:"VK_VOLUME_UP",B0:"VK_MEDIA_NEXT_TRACK"
		,B1:"VK_MEDIA_PREV_TRACK",B2:"VK_MEDIA_STOP",B3:"VK_MEDIA_PLAY_PAUSE",B4:"VK_LAUNCH_MAIL",B5:"VK_LAUNCH_MEDIA_SELECT"
		,B6:"VK_LAUNCH_APP1",B7:"VK_LAUNCH_APP2",BA:"VK_OEM_1",BB:"VK_OEM_PLUS",BC:"VK_OEM_COMMA",BD:"VK_OEM_MINUS",BE:"VK_OEM_PERIOD"
		,BF:"VK_OEM_2",C0:"VK_OEM_3",C1:"VK_ABNT_C1",C2:"VK_ABNT_C2",DB:"VK_OEM_4",DC:"VK_OEM_5",DD:"VK_OEM_6",DE:"VK_OEM_7",DF:"VK_OEM_8"
		,E1:"VK_OEM_AX",E2:"VK_OEM_102",E3:"VK_ICO_HELP",E4:"VK_ICO_00",E5:"VK_PROCESSKEY",E6:"VK_ICO_CLEAR",E7:"VK_PACKET",E9:"VK_OEM_RESET"
		,EA:"VK_OEM_JUMP",EB:"VK_OEM_PA1",EC:"VK_OEM_PA2",ED:"VK_OEM_PA3",EE:"VK_OEM_WSCTRL",EF:"VK_OEM_CUSEL",F0:"VK_OEM_ATTN"
		,F1:"VK_OEM_FINISH",F2:"VK_OEM_COPY",F3:"VK_OEM_AUTO",F4:"VK_OEM_ENLW",F5:"VK_OEM_BACKTAB",F6:"VK_ATTN",F7:"VK_CRSEL"
		,F8:"VK_EXSEL",F9:"VK_EREOF",FA:"VK_PLAY",FB:"VK_ZOOM",FC:"VK_NONAME",FD:"VK_PA1",FE:"VK_OEM_CLEAR",FF:"VK__none_"}
	 
		for k, v in VK__
			VK_[k] := v
		VK_Names := {}
		for k, v in VK_
			for a, b in StrSplit(v, ":=", " ")
				VK_Names[b] := k
			 
		Undefined := "07|0E|0F|16|1A|3A|3B|3C|3D|3E|3F|40"
		Reserved := "0A|0B|5E|B8|B9|C3|C4|C5|C6|C7|C8|C9|CA|CB|CC|CD|CE|CF|D0|D1|D2|D3|D4|D5|D6|D7|E0"
		Unassigned := "88|89|8A|8B|8C|8D|8E|8F|97|98|99|9A|9B|9C|9D|9E|9F|D8|D9|DA|E8"
	}
	If (id ~= "i)^vk_") && VK_Names.HasKey(id)
		Return QVK(oDoc.getElementById("edithotkey").value := Format("{:U}", id), "0x" VK_Names[id])  ;;	vK_EreOF
		
	If VK := GetKeyVK(id)  
		id := Format("0x{:02X}", VK)
	Else If (id ~= "i)^vk")
		id := "0x" RegExReplace(id, "i)(^vk([0-9a-f]+)).*", "$2")  
		
	If !(InStr(id, "0x") && id > 0 && id < 256)
		Return   ;;	"Is not virtual key code" 
	id := Format("{:02X}", id) 
	If VK_[id]
		Return  QVK(VK_[id], "0x" id)  
	If InStr("|" Undefined "|", "|" id "|")
		Return QVK("0x" id " is Undefined", "", 0)
	If InStr("|" Reserved "|", "|" id "|")
		Return QVK("0x" id " is Reserved", "", 0)
	If InStr("|" Unassigned "|", "|" id "|")
		Return QVK("0x" id " is Unassigned", "", 0) 
} 

QVK(key, value, VK = 1) {
	Static S, T, Description1, Description2
	If !S && S := 1 
		T := _T1 "> ( GetKeyVK ) </span>" _T2 "<br>"
		, Description1 := "<span style='color: #" ColorParam "'>Virtual-key code symbolic names:  </span>"
		, Description2 := "<span style='color: #" ColorDelimiter "'>Virtual-key code symbolic names:  </span>"
	If VK
		Return T _PRE1 Description1 "<span><span name='MS:'>" key "</span><span class='param' name='MS:SP'> := " value "</span></span><br>" _PRE2
	Return T _PRE1 Description2 "<span class='QStyle2'>" key "</span><br>" _PRE2
}

GetScanCode(id) { 
	If SC := GetKeySC(id) 
		Return _T1 "> ( GetKeySC ) </span>" _T2 "<br>" _PRE1 "<span name='MS:'>" Format("0x{:03X}", SC) "</span><br>" _PRE2 
}


	; ___________________________ Menu Labels _________________________________________________

ShowSys(x, y) {
ShowSys:
	ZoomMsg(9, 1)
	DllCall("SetTimer", "UPtr", A_ScriptHwnd, "Ptr", 1, "UInt", 116, "Ptr", RegisterCallback("MenuCheck", "Fast"))
	Menu, Sys, Show, % x, % y
	ZoomMsg(9, 0)
	Return
}

MenuCheck()  {
	DllCall("KillTimer", "UPtr", A_ScriptHwnd, "Ptr", 1)
	If !WinExist("ahk_class #32768 ahk_pid " oOther.CurrentProcessId)
		Return
	If GetKeyState("RButton")
	{
		MouseGetPos, , , WinID
		Menu := MenuGetName(GetMenuForMenu(WinID))
		If Menu && (F := oMenu[Menu][oOther.ThisMenuItem := AccUnderMouse(WinID, Id).accName(Id)]) && (F ~= "^_")
		{
			;; If !(F ~= "^_") ;; Return DllCall("mouse_event", "UInt", 0x0002|0x0004)  
			;;	WinClose("ahk_class #32768 ahk_pid " oOther.CurrentProcessId), SetTimer(F, -1)
			oOther.MenuItemExist := 1
			If IsLabel(F)
				GoSub, % F
			Else
				%F%()
			oOther.MenuItemExist := 0
		}
		KeyWait, RButton
	}
	DllCall("SetTimer", "UPtr", A_ScriptHwnd, "Ptr", 1, "UInt", 16, "Ptr", RegisterCallback("MenuCheck", "Fast"))
}

GetMenuForMenu(hWnd) {
	SendMessage, 0x1E1, 0, 0, , ahk_id %hWnd%	;;  MN_GETHMENU
	hMenu := ErrorLevel
	If (hMenu + 0)
		Return hMenu
}

AccUnderMouse(WinID, ByRef child) {
	Static h
	If Not h
		h := DllCall("LoadLibrary", "Str", "oleacc", "Ptr")
	If DllCall("oleacc\AccessibleObjectFromPoint"
		, "Int64", 0 * DllCall("GetCursorPos", "Int64*", pt) + pt, "Ptr*", pacc
		, "Ptr", VarSetCapacity(varChild, 8 + 2 * A_PtrSize, 0) * 0 + &varChild) = 0
	Acc := ComObjEnwrap(9, pacc, 1)
	If IsObject(Acc)
		Return Acc, child := NumGet(varChild, 8, "UInt")
}

MaxHeightStrToNum()  {
	Return Round(A_ScreenHeight / SubStr(PreMaxHeightStr, 5))
}

_DarkTheme: 
	IniWrite(DarkTheme := !DarkTheme, "DarkTheme")
	Menu, View, % DarkTheme ? "Check" : "UnCheck"
	, % oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	Return
	
_ActiveScriptAllowChange: 
	IniWrite(ActiveScriptAllowChange := !ActiveScriptAllowChange, "ActiveScriptAllowChange")
	Menu, Script, % ActiveScriptAllowChange ? "Check" : "UnCheck"
	, % oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	Return
	
_FontBold: 
	IniWrite(FontBold := !FontBold, "FontBold")
	Menu, View, % FontBold ? "Check" : "UnCheck"
	, % oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	Return

_ViewStrPos:
	IniWrite(ViewStrPos := !ViewStrPos, "ViewStrPos")
	Menu, View, % ViewStrPos ? "Check" : "UnCheck"
	, % oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	Return

_MenuOverflowLabel:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	PreOverflowHide := ThisMenuItem = "Switch off" ? 0 : 1
	IniWrite(ThisMenuItem, "MaxHeightOverFlow")
	for k, v in ["Switch off","1 / 1","1 / 2","1 / 3","1 / 4","1 / 5","1 / 6","1 / 8","1 / 10","1 / 15"]
		Menu, Overflow, UnCheck, % v
	Menu, Overflow, Check, % PreMaxHeightStr := ThisMenuItem
	PreMaxHeight := MaxHeightStrToNum()
	_PreOverflowHideCSS := ".lpre {max-width: 99`%; max-height: " PreMaxHeight "px; overflow: auto; border: 1px solid #" ColorPreOverflowHide ";}"
	ChangeCSS("css_PreOverflowHide", PreOverflowHide ? _PreOverflowHideCSS : "")
	AnchorFitScroll()
	Return

_Sys_Backlight:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	Menu, Sys, UnCheck, % BLGroup[StateLight]
	Menu, Sys, Check, % ThisMenuItem
	IniWrite((StateLight := InArr(ThisMenuItem, BLGroup)), "StateLight")
	Return

_MemoryAnchor:
	IniWrite(MemoryAnchor := !MemoryAnchor, "MemoryAnchor")
	If MemoryAnchor
		IniWrite(oOther.anchor["Win_text"], "Win_Anchor")
		, IniWrite(oOther.anchor["Control_text"], "Control_Anchor")
	Menu, Script, % MemoryAnchor ? "Check" : "UnCheck", Remember anchor
	Return

_AnchorFullScroll:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	IniWrite(AnchorFullScroll := !AnchorFullScroll, "AnchorFullScroll") 
	Menu, View, % AnchorFullScroll ? "Check" : "UnCheck", % ThisMenuItem 
	
	If AnchorFullScroll
		AnchorScroll()
	Else 
		oJScript.QS(oDivNew, "#id_T0").style.height := 0 "px" 
	oDivNew.scrollTop := oDivNew.scrollTop + oDoc.getElementById("anchor").getBoundingClientRect().top - 6
	Return

_DynamicControlPath:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	IniWrite(DynamicControlPath := !DynamicControlPath, "DynamicControlPath")
	Menu, View, % DynamicControlPath ? "Check" : "UnCheck", % ThisMenuItem
	Return

_DynamicAccPath:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	IniWrite(DynamicAccPath := !DynamicAccPath, "DynamicAccPath")
	Menu, View, % DynamicAccPath ? "Check" : "UnCheck", % ThisMenuItem
	Return

_UseUIA:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	IniWrite(UseUIA := !UseUIA, "UseUIA")
	If UseUIA && !IsObject(exUIASub)
		exUIASub := new UIASub
	Menu, View, % UseUIA ? "Check" : "UnCheck", % ThisMenuItem
	Return
	
_UIAAlienDetect:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	IniWrite(UIAAlienDetect := !UIAAlienDetect, "UIAAlienDetect") 
	Menu, View, % UIAAlienDetect ? "Check" : "UnCheck", % ThisMenuItem
	Return

_SelStartMode:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	for k, v in ["Window","Control","Button","Last Mode"]
		Menu, Startmode, UnCheck, % v
	IniWrite({"Window":"Win","Control":"Control","Button":"Hotkey","Last Mode":"LastMode"}[ThisMenuItem], "StartMode")
	LastModeSave := (ThisMenuItem = "Last Mode")
	Menu, Startmode, Check, % ThisMenuItem
	Return

_OnlyShiftTab:
	IniWrite(OnlyShiftTab := !OnlyShiftTab, "OnlyShiftTab")
	Menu, Sys, % (OnlyShiftTab ? "Check" : "UnCheck"), Spot only Shift+Tab
	ZoomMsg(12, OnlyShiftTab)
	If !OnlyShiftTab
		Try SetTimer, Loop_%ThisMode%, -100
	If OnlyShiftTab && ActiveNoPause
		GoSub _Active_No_Pause
	Return

_Active_No_Pause:
	ActiveNoPause := IniWrite(!ActiveNoPause, "ActiveNoPause")
	Menu, Sys, % (ActiveNoPause ? "Check" : "UnCheck"), Work with the active window
	ZoomMsg(6, ActiveNoPause)
	If OnlyShiftTab && ActiveNoPause
		GoSub _OnlyShiftTab
	Return

_Suspend:
	isAhkSpy := !isAhkSpy
	Menu, Sys, % !isAhkSpy ? "Check" : "UnCheck", Suspend hotkeys
	ZoomMsg(8, !isAhkSpy)
	Return

_CheckUpdate:
	SetTimer, UpdateAhkSpy, Off
	SetTimer, Upd_Verifi, Off
	StateUpdate := IniWrite(!StateUpdate, "StateUpdate")
	Menu, Sys, % (StateUpdate ? "Check" : "UnCheck"), Check updates
	If StateUpdate
		SetTimer, UpdateAhkSpy, -1 
	Return
	
_CheckAhkNewVersion:
	SetTimer, CheckAhkNewVersion, Off
	SetTimer, lCheckAhkNewVersion, Off
	CheckAhkNewVersion := IniWrite(!CheckAhkNewVersion, "CheckAhkNewVersion")
	Menu, Help, % (CheckAhkNewVersion ? "Check" : "UnCheck"), Check updates AutoHotkey
	If CheckAhkNewVersion
		SetTimer, CheckAhkNewVersion, -1 
	Return


_Sys_Acclight:
	StateLightAcc := IniWrite(!StateLightAcc, "StateLightAcc"), HideAccMarker()
	Menu, Sys, % (StateLightAcc ? "Check" : "UnCheck"), Acc object backlight
	Return

_Sys_WClight:
	StateLightMarker := IniWrite(!StateLightMarker, "StateLightMarker"), HideMarker()
	Menu, Sys, % (StateLightMarker ? "Check" : "UnCheck"), Window or control backlight
	Return

_Spot_Together:
	StateAllwaysSpot := IniWrite(!StateAllwaysSpot, "AllwaysSpot")
	Menu, Sys, % (StateAllwaysSpot ? "Check" : "UnCheck"), Spot together (low speed)
	Return

_MemoryPos:
	IniWrite(MemoryPos := !MemoryPos, "MemoryPos")
	Menu, Script, % MemoryPos ? "Check" : "UnCheck", Remember position
	SavePos()
	Return

_MemorySize:
	IniWrite(MemorySize := !MemorySize, "MemorySize")
	Menu, Script, % MemorySize ? "Check" : "UnCheck", Remember size
	SaveSize()
	Return

_MemoryFontSize:
	IniWrite(MemoryFontSize := !MemoryFontSize, "MemoryFontSize")
	Menu, Script, % MemoryFontSize ? "Check" : "UnCheck", Remember font size
	If MemoryFontSize
		IniWrite(FontSize, "FontSize")
	Return

_MemoryZoomSize:
	IniWrite(MemoryZoomSize := !MemoryZoomSize, "MemoryZoomSize")
	Menu, Script, % MemoryZoomSize ? "Check" : "UnCheck", Remember zoom size
	ZoomMsg(4, MemoryZoomSize)
	Return
	
_MinimizeEscape:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	IniWrite(MinimizeEscape := !MinimizeEscape, "MinimizeEscape")
	Menu, Script, % MinimizeEscape ? "Check" : "UnCheck", %ThisMenuItem%
	Return

_MoveTitles:
	IniWrite(MoveTitles := !MoveTitles, "MoveTitles")
	Menu, View, % MoveTitles ? "Check" : "UnCheck", Moving titles
	if oJScript.MoveTitles := MoveTitles
		oJScript.shift(0)
	else
		oDivNew.scrollLeft := 0, oJScript.conleft30()
	Return
	
_MarkerInvertFrame:
	IniWrite(MarkerInvertFrame := !MarkerInvertFrame, "MarkerInvertFrame")
	Menu, View, % MarkerInvertFrame ? "Check" : "UnCheck", Flash edge
	WinSet, Region, , ahk_id %hMarkerGui%
	Return

_MemoryStateZoom:
	IniWrite(MemoryStateZoom := !MemoryStateZoom, "MemoryStateZoom")
	Menu, Script, % MemoryStateZoom ? "Check" : "UnCheck", Remember state zoom
	IniWrite(oOther.ZoomShow, "ZoomShow")
	Return

_WordWrap:
	IniWrite(WordWrap := !WordWrap, "WordWrap")
	Menu, View, % WordWrap ? "Check" : "UnCheck", Word wrap
	If WordWrap
		oDivNew.scrollLeft := 0
	oJScript.WordWrap := WordWrap
	ChangeCSS("css_Body", WordWrap ? _BodyWrapCSS : "")
	Return

Sys_Help:
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	If ThisMenuItem = AutoHotKey official help online
		RunPath("http://ahkscript.org/docs/AutoHotkey.htm")
	Else If ThisMenuItem = AutoHotKey russian help online
		RunPath("http://www.script-coding.com/AutoHotkeyTranslation.html")
	Else If ThisMenuItem = About
		RunPath("http://forum.script-coding.com/viewtopic.php?pid=72459#p72459")
	Else If ThisMenuItem = About english
		RunPath("https://www.autohotkey.com/boards/viewtopic.php?f=6&t=52872") 
	Return

LaunchHelp:
	If !FileExist(SubStr(A_AhkPath,1,InStr(A_AhkPath,"\",,0,1)) "AutoHotkey.chm")
		Return
	IfWinNotExist AutoHotkey Help ahk_class HH Parent ahk_exe hh.exe
		Run % SubStr(A_AhkPath,1,InStr(A_AhkPath,"\",,0,1)) "AutoHotkey.chm"
	WinActivate
	Minimize()
	Return

DefaultSize:
	If FullScreenMode
	{
		FullScreenMode()
		Gui, 1: Restore
		Sleep 200
	}
	Gui, 1: Show, % "NA w" widthTB "h" HeightStart
	ZoomMsg(5)
	If !MemoryFontSize
		oDoc.getElementById("pre").style.fontSize := FontSize := 15
	Return

Reload:
	Reload
	Return

Help_OpenUserDir:
	RunPath(Path_User)
	Return

Help_OpenScriptDir:
	SelectFilePath(A_ScriptFullPath)
	Minimize()
	Return

	; ___________________________ Functions _________________________________________________

WM_ACTIVATE(wp, lp) {
	Critical
	If isConfirm
		Return
	If ((wp & 0xFFFF = 0) && lp != hGui)  ;;	Deactivated
	{
		ZoomMsg(7, 0)
		If Hotkey_Arr("Hook")
			Hotkey_Hook(0)
	}
	Else If (wp & 0xFFFF != 0 && WinActive("ahk_id" hGui)) ;;	Activated
	{
		ZoomMsg(7, 1)
		If (ThisMode = "Hotkey" && !isPaused)
			Hotkey_Hook(1)
		If !ActiveNoPause
			HideAllMarkers(), CheckHideMarker()
	}
}

WM_WINDOWPOSCHANGED(Wp, Lp) {
	Static PtrAdd := A_PtrSize = 8 ? 8 : 0
	; Critical
	If (NumGet(Lp + 0, 0, "Ptr") != hGui) || Sleep = 1
		Return  
		
	If oOther.ZoomShow
	{
		x := NumGet(Lp + 0, 8 + PtrAdd, "UInt")
		y := NumGet(Lp + 0, 12 + PtrAdd, "UInt")
		w := NumGet(Lp + 0, 16 + PtrAdd, "UInt")
		
		hDWP := DllCall("BeginDeferWindowPos", "Int", 2)
		
		; hDWP := DllCall("DeferWindowPos"
		; , "Ptr", hDWP, "Ptr", hGui, "UInt", -1  ;;	for +AlwaysOnTop
		; , "Int", 0, "Int", 0, "Int", 0, "Int", 0
		; , "UInt", 0x0003)    ;;  SWP_NOMOVE := 0x0002 | SWP_NOSIZE := 0x0001
		
		hDWP := DllCall("DeferWindowPos"
		, "Ptr", hDWP, "Ptr", oOther.hZoom, "UInt", 0
		, "Int", x + w, "Int", y, "Int", 0, "Int", 0
		, "UInt", 0x0011)    ;; 0x0010 := SWP_NOACTIVATE | 0x0001 := SWP_NOSIZE
		
		hDWP := DllCall("DeferWindowPos"
		, "Ptr", hDWP, "Ptr", oOther.hZoomLW, "UInt", 0
		, "Int", x + w + 1, "Int", y + 46, "Int", 0, "Int", 0
		, "UInt", 0x0211)    ;; 0x0010 := SWP_NOACTIVATE | 0x0001 := SWP_NOSIZE | SWP_NOOWNERZORDER := 0x0200
		
		DllCall("EndDeferWindowPos", "Ptr", hDWP)
	}
	If MemoryPos
		SetTimer, SavePos, -400  
} 

GuiSize:
	If A_Gui != 1
		Return
	If A_EventInfo = 1
		ZoomMsg(11, 1)
	Sleep := A_EventInfo  ;;	= 1 minimize
	If A_EventInfo != 1
	{
		ControlsMove(A_GuiWidth, A_GuiHeight)
		If MemorySize
			SetTimer, SaveSize, -400
	}
	Else
		HideAllMarkers(), CheckHideMarker()
	Try SetTimer, Loop_%ThisMode%, % A_EventInfo = 1 || isPaused ? "Off" : "On"
	Return

Minimize() {
	Sleep := 1
	Gui, 1: Minimize
}

GetNameFile(Folder, Name = "Myfile ", Ext = "txt", i = 1) {
	While FileExist(Folder "\" Name "(" i ")." Ext)
		i := A_Index
	Return Folder "\" Name "(" i ")." Ext
}

TimerFunc(hFunc, Time) {
	Try SetTimer, % hFunc, % Time
}

Exit() {
	Gui, %hGui%:, Hide
	Hotkey_SetHook(0)
	If LastModeSave
		IniWrite(ThisMode, "LastMode")  
	oDoc := ""
	DllCall("ReleaseDC", "UPtr", 0, "UPtr", hDCMarkerInvert)
	ExitApp
}

GuiClose() {
	If MinimizeEscape && GetKeyState("Esc", "P")
		Return 1, Minimize()  
	ExitApp
}

CheckAhkVersion:
	If A_AhkVersion < 1.1.33.02
	{
		MsgBox Requires AutoHotkey_L version 1.1.33.02+
		RunPath("http://ahkscript.org/download/")
		ExitApp
	}
	Return

ChangeMode() {
	Try SetTimer, Loop_%ThisMode%, Off
	HideAllMarkers(), MS_Cancel()
	GoSub % "Mode_" (ThisMode = "Control" ? "Win" : "Control")
}
	
WM_NCLBUTTONDOWN(wp) {
	Static HTMINBUTTON := 8

	If (wp = HTMINBUTTON)
	{
		SetTimer, Minimize, -10
		Return 0
	}
} 

TransParent(v) {
	oOther.TransParent := !v
	WinSet, TransParent, % v, % "ahk_id" hGui
	WinSet, TransParent, % v, % "ahk_id" oOther.hZoom
	If !v
		WinHide, % "ahk_id" oOther.hZoomLW
	Else
		WinShow, % "ahk_id" oOther.hZoomLW
} 
		
WM_RBUTTONDOWN(wp, lp, msg, hwnd, tp = 0) { 
	If (hwnd = hColorProgress && !ActiveNoPause && !isPaused && ThisMode != "Hotkey")
	{
		If GetKeyState("Shift")
			TransParent(0)
		ToolTip("Spot", 300)
		ZoomMsg(7, 0) 
		ActiveNoPause := 1
		If OnlyShiftTab 
			OnlyShiftTab := 0, oOther.OnlyShiftTabReset := 1, ZoomMsg(12, 0)
		SetTimer, Loop_%ThisMode%, -1 
		SetTimer, RButton_Up_Wait, -1
	}
} 

RButton_Up_Wait:
	If GetKeyState("RButton", "P") || GetKeyState("MButton", "P") {
		SetTimer, %A_ThisLabel%, -30
		Return
	}
	ActiveNoPause := 0 
	If oOther.OnlyShiftTabReset
		OnlyShiftTab := 1, oOther.OnlyShiftTabReset := 0, ZoomMsg(12, 1)
	If OnlyShiftTab
		SetTimer, Loop_%ThisMode%, Off 
	SetTimer, ShiftUpHide, -300
	Sleep 100
	If GetKeyState("LShift", "P")
	{ 
		ZoomMsg(2, 1)
		HideAllMarkers()
		oObjActive.Magnify.Call(2)
		oObjActive.Redraw.Call()  
	}   
	If oOther.TransParent
		TransParent("Off")  
	If !OnlyShiftTab  
	{
		WinActivate ahk_id %hGui%
		GuiControl, 1:Focus, oDoc
	}
	ToolTip("Stop", 300)
	ZoomMsg(2, 0)
	Return

Mod_Up_Wait_And_TransParent:
	If GetKeyState("LShift", "P") || GetKeyState("LControl", "P") {
		SetTimer, %A_ThisLabel%, -50
		Return
	}
	Sleep := 1
	; ZoomMsg(3) 
	If oOther.OnlyShiftTabReset
		OnlyShiftTab := 1, oOther.OnlyShiftTabReset := 0, ZoomMsg(12, 1)
	HideAllMarkers()
	ZoomMsg(2, 1)
	oObjActive.Magnify.Call(2)
	oObjActive.Redraw.Call()   
	TransParent("Off")
	If !OnlyShiftTab || oOther.OnlyShiftTabReset
	{
		WinActivate ahk_id %hGui%
		GuiControl, 1:Focus, oDoc 
	} 
	ToolTip("Stop", 300)  
	ZoomMsg(2, 0)
	Sleep := 0
	Return


ColorButton(name) {
	for k, v in ["Window", "Control", "Button"]
		ColorProgress("Color_" v, v = name ? ColorSelModeButton : ColorBgModeButton) 
}

ColorProgress(name, color) {  
	GuiControl, % "TB: +Background" color, %name% 
	Gui, TB: Color, %ColorBg%
}

WM_LBUTTONDOWN(wp, lp, msg, hwnd) { 
	If (A_GuiControl = "Color_Window")   
		Gosub Mode_Win
	Else If (A_GuiControl = "Color_Control")  
		Gosub Mode_Control
	Else If (A_GuiControl = "Color_Button")  
		Gosub Mode_Hotkey
	Else If (A_GuiControl = "Color_Zoom")  
		AhkSpyZoomShow() 
	Else If (hwnd = hFindGui)
	{
		MouseGetPos, , , , hControl, 2
		If (hControl = hFindAllText)
			SetTimer, FindAll, -250 
	}
	Else If A_GuiControl = ColorProgress
	{
		If ThisMode = Hotkey
			oDoc.execCommand("Paste"), ToolTip("Paste", 300)
		Else
		{ 
			SendInput {LAlt Down}{Escape}{LAlt Up}
			ToolTip("Alt+Escape", 300)
			ZoomMsg(7, 0)
			If (OnlyShiftTab && !isPaused)
			{
				ToolTip("Spot", 300) 
				OnlyShiftTab := 0
				ZoomMsg(12, 0)
				SetTimer, Loop_%ThisMode%, -1
				SetTimer, OnlyShiftTab_LButton_Up_Wait, -1
			}
		}
	}
}
 
OnlyShiftTab_LButton_Up_Wait:
	KeyWait, LButton 
	OnlyShiftTab := 1
	ZoomMsg(12, 1)
	SetTimer, Loop_%ThisMode%, Off
	SetTimer, ShiftUpHide, -300
	Sleep 100
	ToolTip("Stop", 300) 
	return
	
RealHwnd(hwnd) {
   varsetcapacity(var, 8, 0)
   numput(hwnd, var, 0, "uint64")
   return numget(var, 0, "uint")
}

GetClassNN(hc)   { 
	If !hp := DllCall("GetAncestor", "UPtr", hc, Uint, 2)
		Return
    WinGet, HwndList, ControlListHwnd, ahk_id %hp%
    WinGet, ControlNNList, ControlList, ahk_id %hp%
	cnl := StrSplit(ControlNNList,"`n")
    Loop, parse, HwndList, `n
    { 
		If (A_LoopField = hc)
			Return cnl[A_Index]
    }
	Return 
}

WM_NCHITTEST(x, y, hWnd) { 
	Static arr
	If !arr
		arr := {WM_NCHITTEST: 0x84, "FAIL": "", -2: "HTERROR", -1: "HTTRANSPARENT", 0: "HTNOWHERE", 1: "HTCLIENT"
		, 2: "HTCAPTION", 3: "HTSYSMENU", 4: ["HTGROWBOX", "HTSIZE"], 5: "HTMENU", 6: "HTHSCROLL"
		, 7: "HTVSCROLL", 8: ["HTMINBUTTON", "HTREDUCE"], 9: ["HTMAXBUTTON", "HTZOOM"]
		, 10: "HTLEFT", 11: "HTRIGHT", 12: "HTTOP", 13: "HTTOPLEFT", 14: "HTTOPRIGHT", 15: "HTBOTTOM"
		, 16: "HTBOTTOMLEFT", 17: "HTBOTTOMRIGHT", 18: "HTBORDER", 19: "undefined", 20: "HTCLOSE", 21: "HTHELP"}
			
	; CoordMode, Mouse
	; MouseGetPos, x, y, hWnd
	; SendMessage, WM_NCHITTEST := 0x84, 0, x | y << 16,, ahk_id %hWnd%  ; неправильно
	; https://www.autohotkey.com/board/topic/20431-wm-nchittest-wrapping-whats-under-a-screen-point/
	; https://docs.microsoft.com/ru-ru/windows/win32/inputdev/wm-nchittest
	SendMessage, arr.WM_NCHITTEST, 0, (x & 0xFFFF) | (y & 0xFFFF) << 16, , ahk_id %hWnd%   
	If ErrorLevel = FAIL
		Return "FAIL"
	If IsObject(arr[ErrorLevel])
		Return arr[ErrorLevel][1] " := " arr[ErrorLevel][2] " := " ErrorLevel
	Return arr[ErrorLevel] " := " ErrorLevel
}

	; ___________________________ List Window _________________________________________________


Window_CountList(PID) {
	Process, Exist, %PID%
	If !ErrorLevel
		Return -1
    WinGet, List, List, ahk_pid %PID% 
	If !List
		Return -2 
	WinGet, ProcessStart, ProcessName, ahk_pid %PID%
	Loop % List
	{
		Hwnd := List%A_Index% 
		WinGetClass, Class, ahk_id %Hwnd%   
		WinGetTitle, Title, ahk_id %Hwnd%
		WinGetPos, WinX, WinY, WinW, WinH, ahk_id %Hwnd%
		WinGet, ProcessName, ProcessName, % "ahk_id" Hwnd
		vis := DllCall("IsWindowVisible", "UPtr", Hwnd) ? "" : " class='QStyle2'" 
		tree .= "<span><span name='MS:' " vis ">" Class "</span>" 
			. _DP _BP1 " id='b_hwnd_flash' value='" Hwnd "'> flash " _BP2  
			. _BP1 " id='b_open_win' value='" Hwnd "'> > " _BP2  
			. _DP  "<span name='MS:' class='title2'>" Title "</span>"
			. _DP  "<span name='MS:' class='param'>x" WinX " y" WinY " w" WinW " h" WinH "</span>"
			. _DP  "<span name='MS:'>" Format("0x{:06X}", Hwnd) "</span>"
			. (ProcessStart = ProcessName ? "" : _DP  "<span name='MS:' class = 'error'>" ProcessName "</span>") 
			. "<span name='MS:P'>    </span></span>`n" 
	}
	tree := _T1 " id='P__Tree_Window_CountList'" _T1P "> ( Window list: <span name='MS:' style='color: #" ColorFont ";'>" List "</span> ) </span><a></a>" 
	. _BT1 " id='view_WindowCount2'> update " _BT2
	. _DB _BT1 " id='WindowCountList_roll'> roll up " _BT2
	. _DB _BT1 " id='copy__PRE1' name='pre_WindowCountList'> copy " _BT2 _T2 
	. _PRE " id='pre_WindowCountList'>" "<span>" tree "</span>" _PRE2 
	oOther.WindowCountList := tree
	Return 1    
}

Window_ControlCountList(Hwnd, find = 0) {
	If !WinExist("ahk_id" Hwnd)
		Return -1 
	oList := GetChildList(Hwnd)  
	If oList.Count() < 2
		Return -2 
	WinGet, PID, PID, ahk_id %Hwnd%
	WinGet, ProcessStart, ProcessName, ahk_pid %PID%  
	NN := {}
	
	for k, v in oList
	{  
		If k = 1
			Continue 
		ControlGetPos, WinX, WinY, WinW, WinH, , % "ahk_id" v.ID
		ControlGetText, Text, , % "ahk_id" v.ID
		WinGet, ProcessName, ProcessName, % "ahk_id" v.ID
		If StrLen(Text) > 100
			Text := SubStr(Text, 1, 100) "..."
		Text := RegExReplace(Text,  "\R+", " ") 
		If !NN[v.Class]
			NN[v.Class] := 0
		++NN[v.Class]	
		
		
		If (find && v.ID = find)
		{ 
			find_anch := "id='a_find_anch'" 
		}
		vis := DllCall("IsWindowVisible", "UPtr", v.ID) ? "" : " class='QStyle2'" 
		tree .= AddSpace2(v.depth - 2, "  ") "<span " find_anch "><span name='MS:' " vis ">" v.Class NN[v.Class] "</span>"  
			. _DP _BP1 " id='b_hwnd_flash' value='" v.ID "'> flash " _BP2 
			. _BP1 " id='b_open_win_ctrl' value='" v.ID "|" v.Class NN[v.Class] "'> > " _BP2    
			. _DP  "<span name='MS:' class='title2'>" Text "</span>"
			. _DP  "<span name='MS:' class='param'>x" WinX " y" WinY " w" WinW " h" WinH "</span>"
			. _DP  "<span name='MS:'>" v.ID "</span>"
			. (ProcessStart = ProcessName ? "" : _DP  "<span name='MS:' class = 'error'>" ProcessName "</span>") 
			. "<span name='MS:P'>    </span></span>`n" 
	}
	tree := _T1 " id='P__Tree_ControlCountList'" _T1P "> ( Control tree: <span name='MS:' style='color: #" ColorFont ";'>" oList.Count() - 1 "</span> ) </span><a></a>" 
	. _BT1 " id='view_ControlCount2'> update " _BT2
	. _DB _BT1 " id='ControlCountList_roll'> roll up " _BT2
	. _DB _BT1 " id='copy__PRE1' name='pre_ControlCountList'> copy " _BT2 _T2 
	. _PRE " id='pre_ControlCountList'>" "<span>" tree "</span>" _PRE2  
	oOther.ControlCountList := tree
	Return 1   
}

ChildList(Hwnd) {
	If !WinExist("ahk_id" Hwnd)
		Return -1
	oList := GetChildList(Hwnd)
	If oList.MaxIndex() <= 1
		Return -2
	NN := {}
	WinGet, PID, PID, ahk_id %Hwnd%
	WinGet, ProcessStart, ProcessName, ahk_pid %PID%
	
	for k, v in oList
	{  
		If k = 1
			Continue
		ControlGetPos, WinX, WinY, WinW, WinH, , % "ahk_id" v.ID
		WinGet, ProcessName, ProcessName, % "ahk_id" v.ID
		ControlGetText, Text, , % "ahk_id" v.ID 
		If StrLen(Text) > 100
			Text := SubStr(Text, 1, 100) "..."
		Text := RegExReplace(Text,  "\R+", " ") 
		If !NN[v.Class]
			NN[v.Class] := 0
		++NN[v.Class]	 
		vis := DllCall("IsWindowVisible", "UPtr", v.ID) ? "" : " class='QStyle2'" 
		tree .= AddSpace2(v.depth - 2, "  ") "<span><span name='MS:' " vis ">" v.Class NN[v.Class] "</span>"
			. _DP _BP1 " id='b_hwnd_flash' value='" v.ID "'> flash " _BP2
			. _BP1 " id='b_open_ctrl' value='" v.ID "|" v.Class NN[v.Class] "'> > " _BP2    
			. _DP  "<span name='MS:' class='title2'>" Text "</span>"
			. _DP  "<span name='MS:' class='param'>x" WinX " y" WinY " w" WinW " h" WinH "</span>"
			. _DP  "<span name='MS:'>" v.ID "</span>"
			. (ProcessStart = ProcessName ? "" : _DP  "<span name='MS:' class = 'error'>" ProcessName "</span>") 
			. "<span name='MS:P'>     </span></span>`n" 
	}  
	tree := _T1 " id='P__Tree_Control_Child'" _T1P "> ( Child tree: <span name='MS:' style='color: #" ColorFont ";'>" oList.Count() - 1 "</span> ) </span><a></a>" 
	. _BT1 " id='control_child2'> update " _BT2
	. _DB _BT1 " id='Control_Child_roll'> roll up " _BT2
	. _DB _BT1 " id='copy__PRE1' name='pre_Control_Child'> copy " _BT2 _T2 
	. _PRE " id='pre_Control_Child'>" "<span>" tree "</span>" _PRE2 
	oOther.ChildList := tree
	Return 1  
}

   ;;  http://forum.script-coding.com/viewtopic.php?pid=131490#p131490
/*
ChildFromPath(str, hwnd) 
{
	Static GW_HWNDNEXT := 2, GW_CHILD := 5
	hwnd := DllCall("GetWindow", "UPtr", hwnd, UInt, GW_CHILD, "Ptr")
	arr := StrSplit(str, "."), off := 1, i := 1
	Loop 
	{
		If (i = arr[off])
		{
			If (off = arr.Count())
				return hwnd
			hwnd := DllCall("GetWindow", "UPtr", hwnd, UInt, GW_CHILD, "Ptr"), ++off, i := 1 
		}
		Else If (++i) && !(hwnd := DllCall("GetWindow", "UPtr", hwnd, UInt, GW_HWNDNEXT, "Ptr"))
			return   
	}
} 
*/


ChildToPath(hwnd) {
	If !WinExist("ahk_id" hwnd)
		Return 0
	arr := []
 	_ChildToPath(hwnd, arr) 
	WinGet, PID, PID, ahk_id %Hwnd%
	WinGet, ProcessStart, ProcessName, ahk_pid %PID% 
	for k, v in arr
	{  
		Hwnd := Format("0x{:06X}", v.Hwnd)
		WinGetClass, WinClass, ahk_id %Hwnd%
		WinGet, ProcessName, ProcessName, ahk_id %Hwnd% 
		ControlGetPos, WinX, WinY, WinW, WinH, , % "ahk_id" Hwnd
		ControlGetText, Text, , % "ahk_id" Hwnd 
		If StrLen(Text) > 100
			Text := SubStr(Text, 1, 100) "..."
		Text := RegExReplace(Text,  "\R+", " ")
 
		vis := DllCall("IsWindowVisible", "UPtr", Hwnd) ? "" : " class='QStyle2'" 
		tree .= AddSpace2(k - 1) "<span><span name='MS:'>" v.Path "</span>" 
			. _DP "<span name='MS:' " vis ">" WinClass "</span>" 
			. _DP _BP1 " id='b_hwnd_flash' value='" Hwnd "'> 闪烁 " _BP2
			. _BP1 " id='b_open_ctrl' value='" Hwnd "|" WinClass "'> > " _BP2   
			. _DP  "<span name='MS:' class='title2'>" Text "</span>"
			. _DP  "<span name='MS:' class='param'>x" WinX " y" WinY " w" WinW " h" WinH "</span>"
			. _DP  "<span name='MS:'>" Hwnd "</span>" 
			. (ProcessStart = ProcessName ? "" : _DP  "<span name='MS:' class = 'error'>" ProcessName "</span>") 
			. "<span name='MS:P'>     </span></span>`n" 
	} 
	tree := _T1 " id='P__Tree_Control_Path'" _T1P "> ( Control parent ) </span><a></a>" _BT1 " id='copy__PRE1' name='pre_Control_Path'> copy " _BT2 _T2 
	. _LPRE " id='pre_Control_Path'>" "<span>" tree "</span>" _PRE2 
	SaveChildPath(tree)
	Return 1
}

_ChildToPath(hwnd, arr, i = 1) {
	Static GA_PARENT := 1, GA_ROOT := 2, GW_HWNDPREV := 3
	Static DesktopHwnd := DllCall("User32.dll\GetDesktopWindow", "ptr") 
	While hPrev := DllCall("GetWindow", "UPtr", hwnd, UInt, GW_HWNDPREV, "Ptr")
		++i, hwnd := hPrev
	   ;;  DllCall("GetParent", "UPtr", hwnd)
	hParent := DllCall("GetAncestor", "UPtr", hwnd, Uint, GA_PARENT)
	if !hParent || (hParent = DesktopHwnd)
		return
	arr.InsertAt(1, {Hwnd:hParent,Path: RTrim(i "." arr[1].Path, ".")})
	return _ChildToPath(hParent, arr, 1)
}

GetChildList(hwnd) {
	Static GW_HWNDNEXT := 2, GW_CHILD := 5    
	WinGetClass, WinClass, ahk_id %hwnd% 
	List := [{id: Format("0x{:x}", hwnd), depth: 1, Class: WinClass}]
	Stack := [hwnd] 
	GW := GW_CHILD
	
	While Stack.MaxIndex() > 1 || A_Index = 1
	{ 
		_hwnd := DllCall("GetWindow", "UPtr", hwnd, UInt, GW, "Ptr") 
		If _hwnd   
		{  
			hwnd := _hwnd 
			If (GW = GW_HWNDNEXT) 
				Stack.Pop()   
			WinGetClass, WinClass, ahk_id %hwnd%   
			Stack.Push(hwnd)
			List.Push({id: Format("0x{:x}", hwnd), depth: Stack.MaxIndex(), Class: WinClass})
			GW := GW_CHILD
		}
		Else 
		{
			If (GW = GW_CHILD)
			{
				GW := GW_HWNDNEXT
				Continue
			} 
			Stack.Pop()
			hwnd := Stack[Stack.MaxIndex()]
			GW := GW_HWNDNEXT 
		}		 
	}
	Return List 
} 

AddSpace2(c, pr = "") {
	loop % c
		Tab .= "<span class='param';'>" pr "↓  </span>"
	Return Tab
} 

SaveChildPath(Path = "") {
	Static p
	If Path =
		Return p
	p := Path
}

ActivateUnderMouse() {
	MouseGetPos, , , WinID
 	WinActivate, ahk_id %WinID%
}

MouseGetPosScreen(ByRef x, ByRef y) {
	VarSetCapacity(POINT, 8, 0)
	NumPut(x, &POINT, 0, "Int")
	NumPut(y, &POINT, 4, "Int")
	DllCall("GetCursorPos", "Ptr", &POINT)
	x := NumGet(POINT, 0, "Int"), y := NumGet(POINT, 4, "Int")
}

WM_CONTEXTMENU() {
	MouseGetPos, , , wid, cid, 2
	If (hColorProgress = cid) {
		Gosub, PausedScript
		ToolTip("Pause", 300)
		Return 0
	}
	Else If (cid != hActiveX && wid = hGui) {
		SetTimer, ShowSys, -1
		Return 0
	}
	Return 1
}

IsTextArea() {
	MouseGetPos, , , , cid, 3
	Return (DllCall("GetParent", "UPtr", cid) = hActiveX)
}

ControlsMove(Width, Height) { 
	hDWP := DllCall("BeginDeferWindowPos", "Int", isFindView ? 3 : 2)
	hDWP := DllCall("DeferWindowPos"
	, "Ptr", hDWP, "Ptr", hTBGui, "UInt", 0
	, "Int", (Width - widthTB) // 2.2, "Int", 0, "Int", 0, "Int", 0
	, "UInt", 0x0011)    ;; 0x0010 := SWP_NOACTIVATE | 0x0001 := SWP_NOSIZE
	hDWP := DllCall("DeferWindowPos"
	, "Ptr", hDWP, "Ptr", hActiveX, "UInt", 0
	, "Int", 0, "Int", HeigtButton
	, "Int", Width, "Int", Height - HeigtButton - (isFindView ? 28 : 0)
	, "UInt", 0x0010)    ;; 0x0010 := SWP_NOACTIVATE
	If isFindView
		hDWP := DllCall("DeferWindowPos"
		, "Ptr", hDWP, "Ptr", hFindGui, "UInt", 0
		, "Int", (Width - widthTB) // 2.2, "Int", (Height - (Height < HeigtButton * 2 ? -2 : 27))
		, "Int", 0, "Int", 0
		, "UInt", 0x0011)    ;; 0x0010 := SWP_NOACTIVATE | 0x0001 := SWP_NOSIZE
	DllCall("EndDeferWindowPos", "Ptr", hDWP)
	
	SetTimer, AnchorFitScroll, -500 
}

ZoomSpot() {
	If (!isPaused && Sleep != 1 && WinActive("ahk_id" hGui))
		(ThisMode = "Control" ? (Spot_Control() (StateAllwaysSpot ? Spot_Win() : 0) Write_Control()) : (Spot_Win() (StateAllwaysSpot ? Spot_Control() : 0) Write_Win()))
}

MsgZoom(wParam, lParam) {  ;;	получает
	If (wParam = 1)  ;;	шаг мыши
		SetTimer, ZoomSpot, -1
	Else If (wParam = 2)  ;;	ZoomShow
		oOther.ZoomShow := lParam, (MemoryStateZoom && IniWrite(lParam, "ZoomShow"))
	Else If (wParam = 0)  ;;	хэндл окна
		oOther.hZoom := lParam
	Else If (wParam = 3)  ;;	хэндл окна LW
		oOther.hZoomLW := lParam
}	

WM_COPYDATA(wParam, lParam) { 
    CopyOfData := StrGet(NumGet(lParam + 2 * A_PtrSize))   
	If (wParam = 1 && ThisMode = "Control") {
		arr := StrSplit(CopyOfData, "`n") 
		BGR := arr[1], offX := arr[2], offY := arr[3], reset := arr[4]
		ColorRGB := Format("0x{:06X}", (BGR & 0xFF) << 16 | (BGR & 0xFF00) | (BGR >> 16))
		ColorBGR := Format("0x{:06X}", BGR)
		oDoc.getElementById("ColorRGB").innerText := ColorRGB
		oDoc.getElementById("sColorRGB").innerText := SubStr(ColorRGB, 3)  
		oDoc.getElementById("ColorBGR").innerText := ColorBGR
		oDoc.getElementById("sColorBGR").innerText := SubStr(ColorBGR, 3)  
		sInvert_RGB := Format("{:06X}", ColorRGB ^ 0xFFFFFF)    
		oDoc.getElementById("sInvert_RGB0").innerText := "0x" sInvert_RGB
		oDoc.getElementById("sInvert_RGB").innerText := sInvert_RGB 
		oDoc.getElementById("RenderInvert_RGB").style.backgroundColor := "#" sInvert_RGB
		
		GuiControl, TB: -Redraw, ColorProgress
		GuiControl, % "TB: +c" SubStr(ColorRGB, 3), ColorProgress
		GuiControl, TB: +Redraw, ColorProgress  
		
		oDoc.getElementById("coord_screen").innerText := "x" (osCoords.MXS + offX) " y" (osCoords.MYS + offY)
		oDoc.getElementById("coord_win").innerText := "x" (osCoords.RWinX + offX) " y" (osCoords.RWinY + offY)
		oDoc.getElementById("coord_client").innerText := "x" (osCoords.MXC + offX) " y" (osCoords.MYC + offY)
		oDoc.getElementById("coord_awin").innerText := "x" (osCoords.MXWA + offX) " y" (osCoords.MYWA + offY)
		oDoc.getElementById("coord_rwin").innerText := Round((osCoords.RWinX + offX) / osCoords.WinW, 4) ", " Round((osCoords.RWinY + offY) / osCoords.WinH, 4)
		oDoc.getElementById("coord_rclient").innerText := Round((osCoords.MXC + offX) / osCoords.caW, 4) ", " Round((osCoords.MYC + offY) / osCoords.caH, 4)
		 
		oDoc.getElementById("coord_mrc").innerText := "x" (osCoords.rmCtrlX + offX) " y" (osCoords.rmCtrlY + offY)
		oDoc.getElementById("coord_wrc").innerText := Round((osCoords.rmCtrlX + offX) / osCoords.CtrlW, 4) ", " Round((osCoords.rmCtrlY + offY) / osCoords.CtrlH, 4)
  
		If reset
			HTML_Control := oDivNew.innerHTML
	}
    return true
}

ZoomMsg(wParam = -1, lParam = -1) {  ;;	отправляет
	If WinExist("AhkSpyZoom ahk_id" oOther.hZoom)
		SendMessage, % MsgAhkSpyZoom, wParam, lParam, , % "ahk_id" oOther.hZoom
}

ZoomSleep() {
	Sleep := 1
}
ZoomNoSleep() {
	Sleep := 0
}

AhkSpyZoomShow() {
	If !oPubObjGUID
		ObjRegisterActive(oObjActive, oPubObjGUID := CreateGUID())
		, oObjActive.AhkSpy_Minimize := Func("Minimize")
		, oObjActive.ZoomSleep := Func("ZoomSleep")
		, oObjActive.ZoomNoSleep := Func("ZoomNoSleep")
	If !WinExist("ahk_id" oOther.hZoom) {
		Hotkey := ThisMode = "Hotkey"
		Suspend := !isAhkSpy
		If A_IsCompiled
			Run "%A_ScriptFullPath%" "Zoom" "%hGui%" "%ActiveNoPause%" "%isPaused%" "%Suspend%" "%Hotkey%" "%OnlyShiftTab%" "%oPubObjGUID%" "%HeigtButton%", , , PID
		Else
			Run "%A_AHKPath%" "%A_ScriptFullPath%" "Zoom" "%hGui%" "%ActiveNoPause%" "%isPaused%" "%Suspend%" "%Hotkey%" "%OnlyShiftTab%" "%oPubObjGUID%" "%HeigtButton%", , , PID
		WinWait, % "ahk_pid" PID, , 1
	}
	Else If DllCall("IsWindowVisible", "UPtr", oOther.hZoom)
		ZoomMsg(0)
	Else
		ZoomMsg(1) 
	SetTimer(Func("ColorProgress").Bind("Color_Zoom", ColorSelModeButton), "-" 1)
	SetTimer(Func("ColorProgress").Bind("Color_Zoom", ColorBgModeButton), "-" 150)
} 

SetPosObject(Name, arr) {
	If !oOther.ZoomShow
		Return
	oObjActive["Coords" Name] := arr
} 

SavePos() {
	If FullScreenMode || !MemoryPos
		Return
	WinGet, Min, MinMax, ahk_id %hGui%
	If (Min = 0)
	{
		WinGetPos, WinX, WinY, , , ahk_id %hGui%
		IniWrite(WinX, "MemoryPosX"), IniWrite(WinY, "MemoryPosY")
	}
}

SaveSize() {
	If FullScreenMode || !MemorySize
		Return
	WinGet, Min, MinMax, ahk_id %hGui%
	If (Min = 0)
	{
		GetClientPos(hGui, _, _, WinWidth, WinHeight)
		IniWrite(WinWidth, "MemorySizeW"), IniWrite(WinHeight, "MemorySizeH")
	}
}

	;;  http://forum.script-coding.com/viewtopic.php?pid=87817#p87817
	;;  http://www.autohotkey.com/board/topic/93660-embedded-ie-shellexplorer-render-issues-fix-force-it-to-use-a-newer-render-engine/

   ; +1:: MsgBox % oDoc.compatMode "`n" oDoc.documentMode
   
FixIE() {
	Key := "Software\Microsoft\Internet Explorer\MAIN"
	. "\FeatureControl\FEATURE_BROWSER_EMULATION", ver := 8000
	If A_IsCompiled
		ExeName := A_ScriptName
	Else
		SplitPath, A_AhkPath, ExeName
	RegRead, value, HKCU, %Key%, %ExeName%
	If (value != ver)
		RegWrite, REG_DWORD, HKCU, %Key%, %ExeName%, %ver%
}

; так не работает  https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/ms537169%28v%3dvs.85%29
ActiveScriptAllow(Off = 0) {
	Static keyInternet := "Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3", IsAllow := 1
	If !ActiveScriptAllowChange
		Return
	If !Off
	{
		RegRead, value, HKCU, %KEYInternet%, 1400
		If (value = 0)   ; Включено
			Return 
		IsAllow := 0 
		RegWrite, REG_DWORD, HKCU, %KEYInternet%, 1400, 0   ; Включить
		Return
	}
	Else If !IsAllow 
		RegWrite, REG_DWORD, HKCU, %KEYInternet%, 1400, 3   ; Выключить
}

ObjRegisterActive(Object, CLSID, Flags := 0) {
   static cookieJar := {}
   if !CLSID  {
      if (( cookie := cookieJar.Delete(Object) ) != "")
         DllCall("oleaut32\RevokeActiveObject", UInt, cookie, Ptr, 0)
      Return
   }
   if cookieJar[Object]
      throw Exception("Object is already registered", -1)
   VarSetCapacity(_clsid, 16, 0)
   if (hr := DllCall("ole32\CLSIDFromString", WStr, CLSID, Ptr, &_clsid)) < 0
      throw Exception("Invalid CLSID", -1, CLSID)
   hr := DllCall("oleaut32\RegisterActiveObject", Ptr, &Object, Ptr, &_clsid, UInt, Flags, UIntP, cookie, UInt)
   if hr < 0
      throw Exception(format("Error 0x{:x}", hr), -1)
   cookieJar[Object] := cookie
}

CreateGUID()
{
   VarSetCapacity(pguid, 16, 0)
   if !DllCall("ole32.dll\CoCreateGuid", Ptr, &pguid)  {
      size := VarSetCapacity(sguid, (38 << !!A_IsUnicode) + 1, 0)
      if DllCall("ole32.dll\StringFromGUID2", Ptr, &pguid, Ptr, &sguid, UInt, size)
         Return StrGet(&sguid)
   }
}

RunPath(Link, WorkingDir = "", Option = "") {
	Run %Link%, %WorkingDir%, %Option%
	Minimize()
}

RunRealPath(Path) {
	SplitPath, Path, , Dir
	Dir := LTrim(Dir, """")
	While !InStr(FileExist(Dir), "D")
		Dir := SubStr(Dir, 1, -1)
	Run, %Path%, %Dir%
}

RunAhkPath(Path, Param = "") {
	SplitPath, Path, , , Extension
	If Extension = exe
		RunPath(Path)
	Else If (!A_IsCompiled && Extension = "ahk")
		RunPath("""" A_AHKPath """ """ Path """ """ Param """")
}

RunShell(Path) {
	ComObjCreate("WScript.Shell").Exec(Path)
}

ExtraFile(Name, GetNoCompile = 0) {
	If FileExist(Path_User "\" Name ".exe")
		Return Path_User "\" Name ".exe"
	If !A_IsCompiled && FileExist(Path_User "\" Name ".ahk")
		Return Path_User "\" Name ".ahk"
}

ShowMarker(x, y, w, h, b := 4) { 
	(w < 8 || h < 8) && (b := 2)
	ShowMarkers(oShowMarkers, x, y, w, h, b)
}

ShowAccMarker(x, y, w, h, b := 2) { 
	ShowMarkers(oShowAccMarkers, x, y, w, h, b)
}

ShowMarkerEx(x, y, w, h, b := 4) { 
	(w < 8 || h < 8) && (b := 2)
	ShowMarkers(oShowMarkersEx, x, y, w, h, b)
}

HideMarker() {
	HideMarkers(oShowMarkers)
}

HideAccMarker() {
	HideMarkers(oShowAccMarkers)
}

HideMarkerEx() {
	HideMarkers(oShowMarkersEx)
}

HideAllMarkers() {
	HideMarker(), HideAccMarker()
}

ShowMarkers(arr, x, y, w, h, b) {
	hDWP := DllCall("BeginDeferWindowPos", "Int", 4)
	for k, v in [[x, y, b, h],[x, y+h-b, w, b],[x+w-b, y, b, h],[x, y, w, b]]
		{
			hDWP := DllCall("DeferWindowPos"
			, "Ptr", hDWP, "Ptr", arr[k], "UInt", -1  ;;	-1 := HWND_TOPMOST
			, "Int", v[1], "Int", v[2], "Int", v[3], "Int", v[4]
			, "UInt", 0x0250)    ;; 0x0010 := SWP_NOACTIVATE | 0x0040 := SWP_SHOWWINDOW | SWP_NOOWNERZORDER := 0x0200
		}
	DllCall("EndDeferWindowPos", "Ptr", hDWP)
	ShowMarker := 1
}

HideMarkers(arr) {
	hDWP := DllCall("BeginDeferWindowPos", "Int", 4)
	Loop 4
		hDWP := DllCall("DeferWindowPos"
		, "Ptr", hDWP, "Ptr", arr[A_Index], "UInt", 0
		, "Int", 0, "Int", 0, "Int", 0, "Int", 0
		, "UInt", 0x0083)    ;; 0x0080 := SWP_HIDEWINDOW | SWP_NOMOVE := 0x0002 | SWP_NOSIZE := 0x0001
	DllCall("EndDeferWindowPos", "Ptr", hDWP)
	ShowMarker := 0
}

ShowMarkersCreate(arr, color) {
	Global WS_CHILDWINDOW, WS_EX_NOACTIVATE, WS_POPUP, WS_EX_TRANSPARENT
	If !!%arr%
		Return
	S_DefaultGui := A_DefaultGui, %arr% := {}
	
	loop 4
	{
		Gui, New
		Gui, Margin, 0, 0
		Gui, -DPIScale
		Gui, +Owner +HWNDHWND -Caption +%WS_CHILDWINDOW% +E%WS_EX_NOACTIVATE% +ToolWindow -%WS_POPUP% +AlwaysOnTop  +E%WS_EX_TRANSPARENT% 
		Gui, Color, %color% 
		WinSet, TransParent, 250, ahk_id %HWND%
		%arr%[A_Index] := HWND
		Gui, Show, NA Hide
	}
	Gui, %S_DefaultGui%:Default
}

CheckHideMarker() {
	Static Try
	Try := 0
	SetTimer, __CheckHideMarker, -50
	Return

	__CheckHideMarker:
		If (Sleep = 1 || (WinActive("ahk_id" hGui) && !ActiveNoPause) || isPaused)
			HideAllMarkers()
		If (Try := ++Try > 2 ? 0 : Try)
			SetTimer, __CheckHideMarker, -150
		Return
}

FlashArea(x, y, w, h, att = 1) {
	Static hFunc, max := 6
	If (att = 1)
		Try SetTimer, % hFunc, Off
	Mod(att, 2) ? ShowMarkerInvert(x, y, w, h, 5) : HideMarkerInvert()
	If (att = max)
		Return
	hFunc := Func("FlashArea").Bind(x, y, w, h, ++att)
	SetTimer, % hFunc, -100
}

CreateMarkerInvert() {    
	; Gui, MI: -DPIScale +Owner +HWNDhMarkerGui -Caption +%WS_CHILDWINDOW% +E%WS_EX_NOACTIVATE% +AlwaysOnTop +ToolWindow +E%WS_EX_TRANSPARENT%-%WS_POPUP% 
	Global WS_EX_TRANSPARENT
	Gui, MI: -DPIScale +Owner%hGui% +HWNDhMarkerGui -Caption +AlwaysOnTop +ToolWindow +E%WS_EX_TRANSPARENT% 
	hDCMarkerInvert := DllCall("GetDC", "UPtr", hMarkerGui)
	WinSet, TransParent, 0, ahk_id %hMarkerGui% 
}

HideMarkerInvert() {
	WinSet, TransParent, 0, ahk_id %hMarkerGui% 
 	Gui, MI: Show, Hide
}

ShowMarkerInvert(x, y, w, h, b := 6) {
	Try Gui, MI: Show, NA x%x% y%y% w%w% h%h% 
	If MarkerInvertFrame
	{
		w < 16 || h < 16 ? b := 2 : 0
		WinSet, Region, % "0-0 " w "-0 " w "-" h " 0-" h " 0-0 " b "-" b
			. " " w-b "-" b " " w-b "-" h-b " " b "-" h-b " " b "-" b, ahk_id %hMarkerGui%
	}
	hDC := DllCall("GetDC", "UPtr", 0, "Ptr") 
	
	DllCall("BitBlt", "Ptr", hDCMarkerInvert, "int", 0, "int", 0, "int", w, "int", h
			, "Ptr", hDC, "int", X, "int", Y, "Uint", 0x00330008)   ;; NOTSRCCOPY
	
	WinSet, TransParent, 255, ahk_id %hMarkerGui%
	Gui, MI: +AlwaysOnTop
	DllCall("ReleaseDC", "UPtr", 0, "UPtr", hDC)
}

SetEditColor(hwnd, BG, FG) {
	Edits[hwnd] := {BG:BG,FG:FG}
	WM_CTLCOLOREDIT(DllCall("GetDC", "UPtr", hwnd), hwnd)
	DllCall("RedrawWindow", "UPtr", hwnd, "Uint", 0, "Uint", 0, "Uint", 0x1|0x4)
}

WM_CTLCOLOREDIT(wParam, lParam) {
	If !Edits.HasKey(lParam)
		Return 0
	hBrush := DllCall("CreateSolidBrush", UInt, Edits[lParam].BG)
	DllCall("SetTextColor", "UPtr", wParam, UInt, Edits[lParam].FG)
	DllCall("SetBkColor", "UPtr", wParam, UInt, Edits[lParam].BG)
	DllCall("SetBkMode", "UPtr", wParam, UInt, 2)
	Return hBrush
}

InArr(Val, Arr) {
	For k, v in Arr
		If (v == Val)
			Return k
}

TransformHTML(str) {
	Transform, str, HTML, %str%, 3
	; StringReplace, str, str, <br>, , 1 
	str := strreplace(str, "`r")
	str := strreplace(str, "`n") 
	Return str
}

PausedTitleText() {
	Static i := 0, Str := "           Paused..."
 	If !isPaused
		Return i := 0
	i := i > 20 ? 2 : i + 1
	TitleTextP2 := "     " SubStr(Str, i) . SubStr(Str, 1, i - 1)
	TitleText := TitleTextP1 . TitleTextP2
	If !FreezeTitleText
		SendMessage, 0xC, 0, &TitleText, , ahk_id %hGui%
	SetTimer, PausedTitleText, -200
}

TitleText(Text, Time = 1000) {
	FreezeTitleText := 1
	StringReplace, Text, Text, `r`n, % Chr(8629), 1
	StringReplace, Text, Text, %A_Tab%, % "      ", 1
	SendMessage, 0xC, 0, &Text, , ahk_id %hGui%
	SetTimer, TitleShow, -%Time%
}

TitleShow:
	SendMessage, 0xC, 0, &TitleText, , ahk_id %hGui%
	FreezeTitleText := 0
	Return

ClipAdd(Text, AddTip = 0) {
	If ClipAdd_Before
		Clipboard := Text ClipAdd_Delimiter Clipboard
	Else
		Clipboard := Clipboard ClipAdd_Delimiter Text
	If AddTip
		ToolTip("add", 300)
}

ClipPaste() {
 	If oMS.ELSel && (oMS.ELSel.OuterText != "" || MS_Cancel())
		oMS.ELSel.innerHTML := TransformHTML(Clipboard), oMS.ELSel.Name := "MS:"
		, MoveCaretToSelection(0)
	Else
		oDoc.execCommand("Paste")
	ToolTip("paste", 300)
}

CutSelection() {
 	If MS_IsSelection()
		MoveCaretToSelection(0), Clipboard := oMS.ELSel.OuterText
		, oMS.ELSel.OuterText := "", MS_Cancel()
	Else
		oDoc.execCommand("Cut")
	ToolTip("cut", 300)
}

DeleteSelection() {
 	If MS_IsSelection()
		MoveCaretToSelection(0), oMS.ELSel.OuterText := "", MS_Cancel()
	Else
		oDoc.execCommand("Delete")
}

PasteStrSelection(Str) {
 	If MS_IsSelection()
		MoveCaretToSelection(0), oMS.ELSel.OuterText := TransformHTML(Str), MS_Cancel()
	Else
		oDoc.selection.createRange().text := Str
}

PasteTab() {
	TempClipboard := ClipboardAll
	Clipboard := "" A_Tab ""
	oDoc.execCommand("Paste")
	Clipboard := TempClipboard 
}

PasteHTMLSelection(Str) {
 	If MS_IsSelection()
		oMS.ELSel.innerHTML := Str, MoveCaretToSelection(0)
	Else
		oDoc.selection.createRange().pasteHTML(Str)
}

MoveCaretToSelection(start) {
	R := oBody.createTextRange(), R.moveToElementText(oMS.ELSel), R.collapse(start), R.select()
}

GetSelected(ByRef Text, ByRef IsoMS = "") {
	Text := oMS.ELSel.OuterText
 	If (Text != "")
		IsoMS := 1
	Else
		Text := oDoc.selection.createRange().text, IsoMS := 0
	Return (Text != "")
}

CopyCommaParam(Text) {
 	If !(Text ~= "(x|y|w|h|" Chr(178) ")-*\d+")
		Return Text
	Text := RegExReplace(Text, "i)(x|y|w|h|#|\s|" Chr(178) "|" Chr(9642) ")+", " ")
	Text := TRim(Text, " "), Text := RegExReplace(Text, "(\s|,)+", ", ")
	Return Text
}

Add_DP(addN, Items*) {
 	For k, v in Items 
		If v != 
			Ret .= v _DP
	If Ret =
		Return
	Return (addN ? "`n" : "") SubStr(Ret, 1, -StrLen(_DP))
}

	;;  http://forum.script-coding.com/viewtopic.php?pid=53516#p53516

;; GetCommandLineProc(pid) {
	;; ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process WHERE ProcessId = " pid)._NewEnum.next(X)
	;; Return Trim(X.CommandLine)
;; }

	;;  http://forum.script-coding.com/viewtopic.php?pid=111775#p111775

GetCommandLineProc(PID, ByRef Cmd, ByRef Bit, ByRef IsAdmin) {
	Static PROCESS_QUERY_INFORMATION := 0x400, PROCESS_VM_READ := 0x10, STATUS_SUCCESS := 0

	hProc := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, Int, 0, UInt, PID, Ptr)
	if A_Is64bitOS
		DllCall("IsWow64Process", Ptr, hProc, UIntP, IsWow64), Bit := (IsWow64 ? "32" : "64") " bit" _DP
	if (!A_Is64bitOS || IsWow64)
		PtrSize := 4, PtrType := "UInt", pPtr := "UIntP", offsetCMD := 0x40
	else
		PtrSize := 8, PtrType := "Int64", pPtr := "Int64P", offsetCMD := 0x70
	hModule := DllCall("GetModuleHandle", "str", "Ntdll", Ptr)
	if (A_PtrSize < PtrSize) {            ;; скрипт 32, целевой процесс 64
		if !QueryInformationProcess := DllCall("GetProcAddress", Ptr, hModule, AStr, "NtWow64QueryInformationProcess64", Ptr)
			failed := "NtWow64QueryInformationProcess64"
		if !ReadProcessMemory := DllCall("GetProcAddress", Ptr, hModule, AStr, "NtWow64ReadVirtualMemory64", Ptr)
			failed := "NtWow64ReadVirtualMemory64"
		info := 0, szPBI := 48, offsetPEB := 8
	}
	else  {
		if !QueryInformationProcess := DllCall("GetProcAddress", Ptr, hModule, AStr, "NtQueryInformationProcess", Ptr)
			failed := "NtQueryInformationProcess"
		ReadProcessMemory := "ReadProcessMemory"
		if (A_PtrSize > PtrSize)            ;; скрипт 64, целевой процесс 32
			info := 26, szPBI := 8, offsetPEB := 0
		else                                ;; скрипт и целевой процесс одной битности
			info := 0, szPBI := PtrSize * 6, offsetPEB := PtrSize
	}
	if failed  {
		DllCall("CloseHandle", Ptr, hProc)
		Return
	}
	VarSetCapacity(PBI, 48, 0)
	if DllCall(QueryInformationProcess, Ptr, hProc, UInt, info, Ptr, &PBI, UInt, szPBI, UIntP, bytes) != STATUS_SUCCESS  {
		DllCall("CloseHandle", Ptr, hProc)
		Return
	}
	pPEB := NumGet(&PBI + offsetPEB, PtrType)
	DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pPEB + PtrSize * 4, pPtr, pRUPP, PtrType, PtrSize, UIntP, bytes)
	DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pRUPP + offsetCMD, UShortP, szCMD, PtrType, 2, UIntP, bytes)
	DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pRUPP + offsetCMD + PtrSize, pPtr, pCMD, PtrType, PtrSize, UIntP, bytes)
	VarSetCapacity(buff, szCMD, 0)
	DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pCMD, Ptr, &buff, PtrType, szCMD, UIntP, bytes)
	Cmd := StrGet(&buff, "UTF-16")

	DllCall("advapi32\OpenProcessToken", "ptr", hProc, "uint", 0x0008, "ptr*", hToken)
	DllCall("advapi32\GetTokenInformation", "ptr", hToken, "int", 20, "uint*", IsAdmin, "uint", 4, "uint*", size)
	DllCall("CloseHandle", "ptr", hToken) 

	DllCall("CloseHandle", Ptr, hProc)
	IsAdmin := IsAdmin ? "true" : "false"
}

GetProcessOwner(PID, value)  { ; https://www.autohotkey.com/boards/viewtopic.php?t=38546#p176907
   static PROCESS_QUERY_INFORMATION := 0x400, TOKEN_QUERY := 0x8
        , TokenUser := 1, TokenOwner := 4, MAX_NAME := 32, isAdmin 
        
   if !hProcess := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION, UInt, false, UInt, PID, Ptr)
      Return 0 ;   ErrorHandling("OpenProcess")
   if !DllCall("Advapi32\OpenProcessToken", Ptr, hProcess, UInt, TOKEN_QUERY, PtrP, hToken)
      Return 0 ;   ErrorHandling("OpenProcessToken", hProcess)
   
   tokenType := value = "user" ? TokenUser : TokenOwner
   DllCall("Advapi32\GetTokenInformation", Ptr, hToken, Int, tokenType, Ptr, 0, Int, 0, UIntP, bites)
   VarSetCapacity(buff, bites, 0)
   if !DllCall("Advapi32\GetTokenInformation", Ptr, hToken, Int, tokenType, Ptr, &buff, Int, bites, UIntP, bites)
      Return 0 ;   ErrorHandling("GetTokenInformation", hProcess, hToken)
   
   VarSetCapacity(sName, MAX_NAME << !!A_IsUnicode, 0)
   VarSetCapacity(sDomainName, MAX_NAME << !!A_IsUnicode, 0)
   VarSetCapacity(szName, 4, 0), NumPut(MAX_NAME, szName)
   if !DllCall( "Advapi32\LookupAccountSid", Ptr, 0, Ptr, NumGet(buff), Str, sName, Ptr, &szName
                                           , Str, sDomainName, Ptr, &szName, IntP, SID_NAME_USE )
      Return 0 ;  ErrorHandling("LookupAccountSid", hProcess, hToken)
   DllCall("CloseHandle", Ptr, hProcess), DllCall("CloseHandle", Ptr, hToken)
   Return sName
}

SeDebugPrivilege() {
	Static PROCESS_QUERY_INFORMATION := 0x400, TOKEN_ADJUST_PRIVILEGES := 0x20, SE_PRIVILEGE_ENABLED := 0x2

	hProc := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION, Int, false, UInt, oOther.CurrentProcessId, Ptr)
	DllCall("Advapi32\OpenProcessToken", Ptr, hProc, UInt, TOKEN_ADJUST_PRIVILEGES, PtrP, token)
	DllCall("Advapi32\LookupPrivilegeValue", Ptr, 0, Str, "SeDebugPrivilege", Int64P, luid)
	VarSetCapacity(TOKEN_PRIVILEGES, 16, 0)
	NumPut(1, TOKEN_PRIVILEGES, "UInt")
	NumPut(luid, TOKEN_PRIVILEGES, 4, "Int64")
	NumPut(SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, 12, "UInt")
	DllCall("Advapi32\AdjustTokenPrivileges", Ptr, token, Int, false, Ptr, &TOKEN_PRIVILEGES, UInt, 0, Ptr, 0, Ptr, 0)
	res := A_LastError
	DllCall("CloseHandle", Ptr, token)
	DllCall("CloseHandle", Ptr, hProc)
	Return res  ;; в случае удачи 0
}

	;;  http://www.autohotkey.com/board/topic/69254-func-api-getwindowinfo-ahk-l/#entry438372

GetClientPos(hwnd, ByRef left, ByRef top, ByRef w, ByRef h) {
	Static _ := VarSetCapacity(pwi, 60, 0)
	DllCall("GetWindowInfo", "UPtr", hwnd, "Ptr", &pwi)
	left := NumGet(pwi, 20, "Int") - NumGet(pwi, 4, "Int")
	top := NumGet(pwi, 24, "Int") - NumGet(pwi, 8, "Int")
	w := NumGet(pwi, 28, "Int") - NumGet(pwi, 20, "Int")
	h := NumGet(pwi, 32, "Int") - NumGet(pwi, 24, "Int")
}

	;;  http://forum.script-coding.com/viewtopic.php?pid=81833#p81833

SelectFilePath(FilePath) { 
	FilePath := TRim(FilePath)
	FilePath := RegExReplace(FilePath, "(^""|""$)")
	FilePath := TRim(FilePath)
	
	If !FileExist(FilePath)
		Return 0
	SplitPath, FilePath,, Dir
	for window in ComObjCreate("Shell.Application").Windows  {
		ShellFolderView := window.Document
		Try If ((Folder := ShellFolderView.Folder).Self.Path != Dir)
			Continue
		Catch
			Continue
		for item in Folder.Items  {
			If (item.Path != FilePath)
				Continue
			ShellFolderView.SelectItem(item, 1|4|8|16)
			WinActivate, % "ahk_id" window.hwnd
			Return 1
		}
	}
	Run, %A_WinDir%\explorer.exe /select`, "%FilePath%", , UseErrorLevel
	Return 1
}

FileToClipboard(PathToCopy,Method="copy") {
	FileCount:=0
	PathLength:=0

	; Count files and total string length
	Loop,Parse,PathToCopy,`n,`r
	{
		FileCount++
		PathLength+=StrLen(A_LoopField)
	}

	pid:=DllCall("GetCurrentProcessId","uint")
	hwnd:=WinExist("ahk_pid " . pid)
	; 0x42 = GMEM_MOVEABLE(0x2) | GMEM_ZEROINIT(0x40)
	hPath := DllCall("GlobalAlloc","uint",0x42,"uint",20 + (PathLength + FileCount + 1) * 2,"UPtr")
	pPath := DllCall("GlobalLock","UPtr",hPath)
	NumPut(20,pPath+0),pPath += 16 ; DROPFILES.pFiles = offset of file list
	NumPut(1,pPath+0),pPath += 4 ; fWide = 0 -->ANSI,fWide = 1 -->Unicode
	Offset:=0
	Loop,Parse,PathToCopy,`n,`r ; Rows are delimited by linefeeds (`r`n).
		offset += StrPut(A_LoopField,pPath+offset,StrLen(A_LoopField)+1,"UTF-16") * 2

	DllCall("GlobalUnlock","UPtr",hPath)
	DllCall("OpenClipboard","UPtr",hwnd)
	DllCall("EmptyClipboard")
	DllCall("SetClipboardData","uint",0xF,"UPtr",hPath) ; 0xF = CF_HDROP

	; Write Preferred DropEffect structure to clipboard to switch between copy/cut operations
	; 0x42 = GMEM_MOVEABLE(0x2) | GMEM_ZEROINIT(0x40)
	mem := DllCall("GlobalAlloc","uint",0x42,"uint",4,"UPtr")
	str := DllCall("GlobalLock","UPtr",mem)

	if (Method="copy")
		DllCall("RtlFillMemory","UPtr",str,"uint",1,"UChar",0x05)
	else if (Method="cut")
		DllCall("RtlFillMemory","UPtr",str,"uint",1,"UChar",0x02)
	else
	{
		DllCall("CloseClipboard")
		return
	}

	DllCall("GlobalUnlock","UPtr",mem)

	cfFormat := DllCall("RegisterClipboardFormat","Str","Preferred DropEffect")
	DllCall("SetClipboardData","uint",cfFormat,"UPtr",mem)
	DllCall("CloseClipboard") 
}

ExecCommandAutoHotkey(Command, PID) {
    Static WM_COMMAND := 0x111
     , Commands := {"Reload Script": 65400
           , "Edit Script": 65401
           , "Suspend Hotkeys": 65404
           , "Pause Script": 65403
           , "Exit Script": 65405
           , "Recent Lines": 65406
           , "Variables": 65407
           , "Hotkeys": 65408
           , "Key history": 65409
           , "AHK User Manual": 65411}
	PostMessage WM_COMMAND, % Commands[Command],,, % "ahk_class AutoHotkey ahk_pid" . PID   
} 

GetCLSIDExplorer(hwnd) { 
	for window in ComObjCreate("Shell.Application").Windows
		If (window.hwnd = hwnd)
			Return (CLSID := window.Document.Folder.Self.Path) ~= "^::\{" ? "`n<span class='param'>CLSID: </span><span name='MS:'>" CLSID "</span>": ""
}

ChangeLocal(hWnd) {
	Static WM_INPUTLANGCHANGEREQUEST := 0x0050, INPUTLANGCHANGE_FORWARD := 0x0002
	SendMessage, WM_INPUTLANGCHANGEREQUEST, INPUTLANGCHANGE_FORWARD, , , % "ahk_id" hWnd
}

GetLangName(hWnd) {
	Static LOCALE_SENGLANGUAGE := 0x1001
	Locale := DllCall("GetKeyboardLayout", Ptr, DllCall("GetWindowThreadProcessId", "UPtr", hWnd, UInt, 0, Ptr), Ptr) & 0xFFFF
	Size := DllCall("GetLocaleInfo", UInt, Locale, UInt, LOCALE_SENGLANGUAGE, UInt, 0, UInt, 0) * 2
	VarSetCapacity(lpLCData, Size, 0)
	DllCall("GetLocaleInfo", UInt, Locale, UInt, LOCALE_SENGLANGUAGE, Str, lpLCData, UInt, Size)
	Return lpLCData
}

ConfirmAction(Action) {
	If !WinActive("ahk_id" hGui) || GetKeyState("Shift")
		Return
	If (!isPaused && bool := 1)
		Gosub, PausedScript
	isConfirm := 1
	bool2 := MsgConfirm(Action, "AhkSpy", hGui)
	isConfirm := 0
	If bool
		Gosub, PausedScript
	If !bool2
		Exit
	Return 1
}

MsgConfirm(Info, Title, hWnd) {
	Static hMsgBox, Text, Yes, No, WinW, WinH
	If !hMsgBox {
		Gui, MsgBox:+HWNDhMsgBox -DPIScale -SysMenu +Owner%hWnd% +AlwaysOnTop
		Gui, MsgBox:Font, % "s" FontDPI " c" ColorFont
		Gui, MsgBox:Color, %ColorBgOriginal%
		Gui, MsgBox:Add, Text, w200 vText r1 Center 
		Gui, MsgBox:Add, Button, w88 vYes xp+4 y+20 gMsgBoxLabel, Yes
		Gui, MsgBox:Add, Button, w88 vNo x+20 gMsgBoxLabel, No 
		WinSet, TransParent, 0, ahk_id %hMsgBox% 
		Gui, MsgBox:Show, NA AutoSize x-32000 y-32000
		WinGetPos, , , WinW, WinH, ahk_id %hMsgBox%
	}
	Gui, MsgBox:+Owner%hWnd% +AlwaysOnTop
	Gui, %hWnd%:+Disabled
	GuiControl, MsgBox:Text, Text, % Info
	CoordMode, Mouse
	MouseGetPos, X, Y
	x := X - (WinW / 2)
	y := Y - WinH - 10
	Gui, MsgBox: Show, NA x%x% y%y%, % Title
	Sleep 1
	WinSet, TransParent, 255, ahk_id %hMsgBox%
	Gui, MsgBox: Show, , % Title
	Gui MsgBox:+AlwaysOnTop
	GuiControl, MsgBox:+Default, No
	GuiControl, MsgBox:Focus, No
	While (RetValue = "")
		Sleep 30
	Gui, %hWnd%:-Disabled
	WinSet, TransParent, 0, ahk_id %hMsgBox% 
	Gui, MsgBox: Show, x-32000 y-32000
	Return RetValue

	MsgBoxLabel:
		RetValue := {Yes:1,No:0}[A_GuiControl]
		Return
}

UnderControl(h) { 
	MouseGetPos, , , Control, , 2
	Return (Control = h)
}

MouseStep(x, y) {
	MouseMove, x, y, 0, R
	If (WinActive("ahk_id" hGui) && !ActiveNoPause) || OnlyShiftTab
	{
		(ThisMode = "Control" ? (Spot_Control() (StateAllwaysSpot ? Spot_Win() : 0) Write_Control()) : (Spot_Win() (StateAllwaysSpot ? Spot_Control() : 0) Write_Win()))
		If DllCall("IsWindowVisible", "UPtr", oOther.hZoom)
			ZoomMsg(3)
	}
	Shift_Tab_Down := 1
}

IsIEFocus() {
	If !WinActive("ahk_id" hGui)
		Return 0
	ControlGetFocus, Focus
	Return InStr(Focus, "Internet")
}

NextLink(s = "") {
	curpos := oDivNew.scrollTop, oDivNew.scrollLeft := 0
	If (!curpos && s = "-")
		Return
	While (pos := oDoc.getElementsByTagName("a").item(A_Index-1).getBoundingClientRect().top) != ""
		(s 1) * pos - 12 > 0 && (!res || abs(res) > abs(pos)) ? res := pos : ""       ;; http://forum.script-coding.com/viewtopic.php?pid=82360#p82360
	If (res = "" && s = "")
		Return
	st := !res ? -curpos : res, co := abs(st) > 150 ? 20 : 10
	Loop % co
		oDivNew.scrollTop := curpos + (st*(A_Index/co))  
	oDivNew.scrollTop := curpos + res - 6
}  

AnchorColor() {
	If !oOther.anchor[ThisMode]
		Return 
	el := GetAnchor()
	el.parentElement.parentElement.firstChild.style.backgroundColor := "#" ColorSelAnchor
	Return el
}

GetAnchor() {
	If !oOther.anchor[ThisMode "_text"]
		Return
	Return oJScript.QS(oDivNew, "#" oOther.anchor[ThisMode "_text"]) ; .parentElement.parentElement.firstChild
}

AnchorScroll(EL = "") { 
	If !oOther.anchor[ThisMode]
		Return
	If !EL
		el := GetAnchor()
	_AnchorFitScroll(EL)  
	oDivNew.scrollTop := oDivNew.scrollTop + EL.getBoundingClientRect().top - 6
}  
 
_AnchorFitScroll(EL, off = 0) { 
	If !AnchorFullScroll
		Return 
	ta := EL.getBoundingClientRect().top   
	ELLast := oJScript.QS(oDivNew, "#id_T0") 
	tl := ELLast.getBoundingClientRect().top   
	clH := oDivNew.clientHeight   
	res := clH - (tl - ta)  
	If res < 0
		res := 0 
	; ToolTip % clH "`n" tl "`n" ba  "`n"  "`n" res, , , 2
	ELLast.style.height := res "px"
	Return 1
}
 
AnchorFitScroll() {
	_AnchorFitScroll(GetAnchor()) 
}

TaskbarProgress(state, hwnd, pct = "") {
	static tbl
	if !tbl {
		try tbl := ComObjCreate("{56FDF344-FD6D-11d0-958A-006097C9A090}", "{ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf}")
		catch
			tbl := "error"
	}
	if tbl = error
		Return
	DllCall(NumGet(NumGet(tbl+0)+10*A_PtrSize), "ptr", tbl, "UPtr", hwnd, "uint", state)
	if pct !=
		DllCall(NumGet(NumGet(tbl+0)+9*A_PtrSize), "ptr", tbl, "UPtr", hwnd, "int64", pct, "int64", 100)
}

/*
HighLight(elem, time = "", RemoveFormat = 1) {
	If (elem.OuterText = "")
		Return
	Try SetTimer, UnHighLight, % "-" time
	R := oBody.createTextRange()
	(RemoveFormat ? R.execCommand("RemoveFormat") : 0)
	R.collapse(1)
	R.select()
	R.moveToElementText(elem)
	
	; https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/hh801229(v=vs.85)#forecolor
	R.execCommand("ForeColor", 0, ColorBgOriginal) ; неработает 
	R.execCommand("BackColor", 0, ColorSelMouseHover)
	Return

	UnHighLight:
		oBody.createTextRange().execCommand("RemoveFormat")
		Return
}
*/

HighLight(elements, time = 500) {
	Static arr, ot
	R := oBody.createTextRange(), R.collapse(1), R.select()
	
	If elements
		(arr && SetTimer(ot, "Off") %A_ThisFunc%(0))
		, bc := "#" ColorSelMouseHover, tc := "#" ColorSelMouseHoverText 
	Else 
		elements := arr, delete := 1
		
	for k, el in elements
	{
		el.style.backgroundColor := bc
		el.style.color := tc
		Loop % el.all.length
			el.all[A_Index - 1].style.color := tc
	}
	If delete 
		Return 0, arr := 0 
	arr := elements 
	Return 1, SetTimer(ot := Func(A_ThisFunc).Bind(0), "-" time)
}

Hotkey_ClipCursor() { 
	Static lpRect, _ := VarSetCapacity(lpRect, 16, 0)  
	DllCall("GetClipCursor", "Ptr", &lpRect) 
	
	If NumGet(lpRect, 0, "uint") > 0xffff || NumGet(lpRect, 0, "uint") = 0
	{ 
		; WinGetPos, WinX, WinY, WinWidth, WinHeight, % "ahk_id" hActiveX 
		CoordMode, Mouse, Screen
		MouseGetPos, X, Y
		NumPut(X, lpRect, 0, "uint")
		NumPut(Y, lpRect, 4, "uint")
		NumPut(X, lpRect, 8, "uint")
		NumPut(Y, lpRect, 12, "uint") 
		DllCall("ClipCursor", "Ptr", &lpRect + 0)   
		ToolTip2("Cancel press down and up lbutton, and press lbutton 2 seconds, else Ctrl+Alt+Delete", -1, 0, -100, 2)
	}
	Else  
	{
		KeyWait LButton
		KeyWait LButton, D
		KeyWait LButton, T2
		If ErrorLevel
			DllCall("ClipCursor", "Ptr", 0), ToolTip2("", -1, , , 2)
	}
}
	; ___________________________ Command as function _________________________________________________
 
WinGetPosToArray(h) {
	WinGetPos, WinX, WinY, WinW, WinH, % "ahk_id " h
	return [WinX, WinY, WinW, WinH] 
}

IniRead(Key, Error := " ") {
	IniRead, Value, %A_AppData%\AhkSpy\Settings.ini, AhkSpy, %Key%, %Error%
	If (Value = "" && Error != " ")
		Value := Error
	Return Value
}

IniWrite(Value, Key) {
	IniWrite, %Value%, %A_AppData%\AhkSpy\Settings.ini, AhkSpy, %Key%
	Return Value
}

MsgBox(msg) {
	MsgBox %msg%
}

WinClose(title) {
	WinClose % title
}

Sleep(time) {
	Sleep time
}

SendInput(key) {
	SendInput % key
}

SetTimer(funcorlabel, time = -500) {
	SetTimer, % funcorlabel, % time
}

GuiControl(SubCommand, ControlID = "", Value = "") { 
	GuiControl, %SubCommand%, %ControlID%, %Value%
}

MouseMoveScreen(x, y) {
	CoordMode, Mouse, Screen
	SetMouseDelay, 0, 0
	SendEvent {Click %x%, %y%, 0}  
}

ToolTip(text, time = 500) {
	CoordMode, Mouse
	CoordMode, ToolTip
	MouseGetPos, X, Y
	ToolTip, %text%, X-10, Y-45
	If (time > 0)
		SetTimer, HideToolTip, -%time%
	Return 1

	HideToolTip:
		ToolTip
		Return
}

ToolTip2(text, time = 500, x = 0, y = 0, ex = 1, CoordMode = "Mouse") {
	If CoordMode = Mouse
	{
		CoordMode, Mouse
		CoordMode, ToolTip
		MouseGetPos, mX, mY
		X+=mX, Y+=mY
	}
	Else 
		CoordMode, ToolTip, %CoordMode%  ;	Screen, Window, Client  (if omitted, it defaults to Screen)
	ToolTip, %text%, x, y, ex
	If (time > 0)
		SetTimer, HideToolTip2, -%time%
	Return 1

	HideToolTip2:
		ToolTip
		Return
}
	; ___________________________ Update _________________________________________________

UpdateAhkSpy(in = 1) {
	Static att, Ver, req
		, url1 := "https://raw.githubusercontent.com/serzh82saratov/AhkSpy/master/Readme.txt"
		, url2 := "https://raw.githubusercontent.com/serzh82saratov/AhkSpy/master/AhkSpy.ahk"

	If !req
		req := ComObjCreate("WinHttp.WinHttpRequest.5.1"), req.Option(6) := 0
	req.open("GET", url%in%, 1), req.send(), att := 0
	SetTimer, Upd_Verifi, -3000
	Return

	Upd_Verifi:
		If (Status := req.Status) = 200
		{
			Text := req.responseText
			If (req.Option(1) = url1)
				Return (Ver := RegExReplace(Text, "i).*?version\s*(.*?)\R.*", "$1")) > AhkSpyVersion ? UpdateAhkSpy(2) : 0
			If (!InStr(Text, "AhkSpyVersion"))
				Return
			HideAllMarkers()
			If InStr(FileExist(A_ScriptFullPath), "R")
			{
				MsgBox, % 16+262144+8192, AhkSpy, Exist new version %Ver%!`n`nBut the file has an attribute "READONLY".`nUpdate imposible.
				Return
			}
			MsgBox, % 4+32+262144+8192, AhkSpy, Exist new version!`nUpdate v%AhkSpyVersion% to v%Ver%?
			IfMsgBox, No
				Return
			File := FileOpen(A_ScriptFullPath, "w", "UTF-8")
			File.Length := 0, File.Write(Text), File.Close()
			Reload
		}
		Error := (++att = 20 || Status != "")
		SetTimer, % Error ? "UpdateAhkSpy" : "Upd_Verifi", % Error ? -60000 : -3000
		Return
}

UpdRegister() {
	Static req, att := 0
	req := ComObjCreate("WinHttp.WinHttpRequest.5.1")
	req.open("post", UpdRegisterLink, 1), req.send()
	SetTimer, UpdRegister_Verifi, -2000
	Return

	UpdRegister_Verifi:
		++att
		If (req.Status = 200)
			IniWrite(1, "UpdRegister2")
		Else If (att <= 3)
			SetTimer, UpdRegister_Verifi, -2000
		Return
}

CheckAhkNewVersion() {
	Static req, att := 0
	req := ComObjCreate("WinHttp.WinHttpRequest.5.1")
	req.Option(6) := 0
	; req.open("GET", "https://www.autohotkey.com/download/", 1)
	req.open("GET", "https://www.autohotkey.com/download/1.1/version.txt", 1)
	req.send()
	SetTimer, lCheckAhkNewVersion, -3000
	Return

	lCheckAhkNewVersion:
		++att
		If (req.Status = 200)
		{  
			; RegExMatch(req.responseText, "O)<!--update-->v(.*?) - ", m), ver := m[1]
			ver := RegExReplace(req.responseText, "s).*?<!--update-->v(.*?) - .*", "$1")
			If StrReplace(ver, ".") <= StrReplace(A_AhkVersion, ".")
				Return
			MsgBox, % 4+32+262144+8192, AhkSpy, AutoHotkey new version!`nFor update v%A_AhkVersion% to v%Ver%, need to go autohotkey.com?
			IfMsgBox, No
				Return
			Run https://www.autohotkey.com/download/
			Return
		}
		If (att <= 3)
			SetTimer, lCheckAhkNewVersion, -2000
		Return 
}


	; ___________________________ WindowStyles _________________________________________________

ViewStylesWin(update = 0) {  ;;
	
	If update
	{
		WinGet, WinStyle, Style, % "ahk_id" oOther.WinID
		WinGet, WinExStyle, ExStyle, % "ahk_id" oOther.WinID
		
		If (WinStyle WinExStyle = "")
			Return ToolTip("Window not exist", 500)
		oDoc.getElementById("w_Style").innerText := WinStyle
		oDoc.getElementById("w_ExStyle").innerText := WinExStyle
		w_ShowStyles := 0
	}  
	oDoc.getElementById("get_styles_w").innerText := !(w_ShowStyles := !w_ShowStyles) ? " 显示风格 " : " 隐藏风格 "
	IniWrite(w_ShowStyles, "w_ShowStyles")
			
	If w_ShowStyles || update
		Styles := "<a></a>" GetStyles(oOther.WinClass
			, oDoc.getElementById("w_Style").innerText
			, oDoc.getElementById("w_ExStyle").innerText
			, oOther.WinID)

	oDoc.getElementById("WinStyles").innerHTML := Styles
	HTML_Win := oDivNew.innerHTML
}

ViewStylesControl(update = 0) {  ;;
	
	If update
	{
		ControlGet, CtrlStyle, Style,,, % "ahk_id" oOther.ControlID
		ControlGet, CtrlExStyle, ExStyle,,, % "ahk_id" oOther.ControlID
		
		If (CtrlStyle CtrlExStyle = "")
			Return ToolTip("Window not exist", 500)
		oDoc.getElementById("c_Style").innerText := CtrlStyle
		oDoc.getElementById("c_ExStyle").innerText := CtrlExStyle
		c_ShowStyles := 0
	} 
	oDoc.getElementById("get_styles_c").innerText := !(c_ShowStyles := !c_ShowStyles) ? " 显示风格 " : " 隐藏风格 "
	IniWrite(c_ShowStyles, "c_ShowStyles")  

	If c_ShowStyles
		Styles := "<a></a>" GetStyles(oOther.CtrlClass
			, oDoc.getElementById("c_Style").innerText
			, oDoc.getElementById("c_ExStyle").innerText
			, oOther.ControlID)
	oDoc.getElementById("ControlStyles").innerHTML := Styles
	HTML_Control := oDivNew.innerHTML
} 

GetStyles(Class, Style, ExStyle, hWnd, IsChild = 0, IsChildInfoExist = 0) {
	;;	http://msdn.microsoft.com/en-us/library/windows/desktop/ms632600(v=vs.85).aspx			Styles
	;;	http://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx			ExStyles
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25880#p25880							Forum Constants
	;;	https://github.com/AHK-just-me/AHK_Gui_Constants/tree/master/Sources			GitHub Constants
	
	;;	http://www.frolov-lib.ru/books/bsp/v11/ch3_2.htm   русский фак по стилям
	;;	https://github.com/strobejb/winspy/blob/master/src/DisplayStyleInfo.c			Логика WinSpy++
	;;	http://forum.script-coding.com/viewtopic.php?pid=130846#p130846
	
	Static Styles, ExStyles, ClassStyles, DlgStyles, ToolTipStyles, GCL_STYLE := -26 
	
	If !hWnd
		Return
	If !Styles
		   ;;  В массивах стили без условий
		Styles := {"WS_BORDER":"0x00800000", "WS_SYSMENU":"0x00080000", "WS_CLIPCHILDREN":"0x02000000"
		, "WS_CLIPSIBLINGS":"0x04000000", "WS_DISABLED":"0x08000000"
		, "WS_HSCROLL":"0x00100000", "WS_MAXIMIZE":"0x01000000"
		, "WS_VISIBLE":"0x10000000", "WS_VSCROLL":"0x00200000"}

		, ExStyles := {"WS_EX_ACCEPTFILES":"0x00000010", "WS_EX_APPWINDOW":"0x00040000", "WS_EX_CLIENTEDGE":"0x00000200"
		, "WS_EX_CONTROLPARENT":"0x00010000", "WS_EX_DLGMODALFRAME":"0x00000001", "WS_EX_LAYOUTRTL":"0x00400000"
		, "WS_EX_LEFTSCROLLBAR":"0x00004000", "WS_EX_WINDOWEDGE":"0x00000100"
		, "WS_EX_MDICHILD":"0x00000040", "WS_EX_NOACTIVATE":"0x08000000", "WS_EX_NOINHERITLAYOUT":"0x00100000"
		, "WS_EX_NOPARENTNOTIFY":"0x00000004", "WS_EX_NOREDIRECTIONBITMAP":"0x00200000", "WS_EX_RIGHT":"0x00001000"
		, "WS_EX_RTLREADING":"0x00002000", "WS_EX_STATICEDGE":"0x00020000"
		, "WS_EX_TOOLWINDOW":"0x00000080", "WS_EX_TOPMOST":"0x00000008", "WS_EX_TRANSPARENT":"0x00000020"}

		, ClassStyles := {"CS_BYTEALIGNCLIENT":"0x00001000", "CS_BYTEALIGNWINDOW":"0x00002000", "CS_CLASSDC":"0x00000040", "CS_IME":"0x00010000"
		, "CS_DBLCLKS":"0x00000008", "CS_DROPSHADOW":"0x00020000", "CS_GLOBALCLASS":"0x00004000", "CS_HREDRAW":"0x00000002"
		, "CS_NOCLOSE":"0x00000200", "CS_OWNDC":"0x00000020", "CS_PARENTDC":"0x00000080", "CS_SAVEBITS":"0x00000800", "CS_VREDRAW":"0x00000001"}
	
	orStyle := Style
	Style := sStyle := Style & 0xffff0000  
		 
	Ret .= QStyle("WS_CAPTION", "0x00C00000", ""  ;;	WS_CAPTION && WS_BORDER 
	, (Style & 0x00C00000) = 0x00C00000  && (WS_CAPTION := 1, WS_BORDER := 1, Style -= 0x00C00000)) 
	
	; Ret .= QStyle("WS_BORDER", "0x00800000", "", !!(WS_CAPTION))  
		
	Ret .= QStyle("WS_DLGFRAME", "0x00400000", "!(WS_CAPTION)"
	, !WS_CAPTION && ((Style & 0x00400000) = 0x00400000) && (WS_DLGFRAME := 1, Style -= 0x00400000))  ;;	WS_DLGFRAME 
		
	For K, V In Styles 
		Ret .= QStyle(K, V, "", (Style & V) = V && (%K% := 1, Style -= V))

	Ret .= QStyle("WS_SIZEBOX := WS_THICKFRAME", "0x00040000", ""
	, (Style & 0x00040000) && (WS_SIZEBOX := 1, WS_THICKFRAME := 1, Style -= 0x00040000))  ;;	WS_SIZEBOX := WS_THICKFRAME 

	Ret .= QStyle("WS_CHILD := WS_CHILDWINDOW", "0x40000000", ""
	, (Style & 0x40000000) && (WS_CHILD := 1, Style -= 0x40000000))  ;;	WS_CHILD := WS_CHILDWINDOW := 0x40000000 
	 
	Ret .= QStyle("WS_TABSTOP", "0x00010000", ""
	, (Style & 0x00010000) && (WS_TABSTOP := 1, Style -= 0x00010000))  ;;	WS_TABSTOP
	 
	Ret .= QStyle("WS_GROUP", "0x00020000", "(WS_CHILD)"
	, (Style & 0x00020000) && WS_CHILD && (WS_GROUP := 1, Style -= 0x00020000))  ;;	WS_GROUP  

	Ret .= QStyle("WS_MINIMIZE := WS_ICONIC", "0x20000000", ""
	, (Style & 0x20000000) && (WS_MINIMIZE := 1, Style -= 0x20000000))  ;;	WS_MINIMIZE := WS_ICONIC   

	Ret .= QStyle("WS_POPUP", "0x80000000", "!(WS_CHILD)"
	, (Style & 0x80000000) && !WS_CHILD && (WS_POPUP := 1, Style -= 0x80000000))  ;;	WS_POPUP  
	
	Ret .= QStyle("WS_POPUPWINDOW", "0x80880000", "(WS_POPUP | WS_BORDER | WS_SYSMENU)"
	, (WS_POPUP && WS_BORDER && WS_SYSMENU) && (WS_POPUPWINDOW := 1))  ;;	WS_POPUPWINDOW

	Ret .= QStyle("WS_OVERLAPPED := WS_TILED", "0x00000000", "(WS_BORDER | WS_CAPTION) & !(WS_POPUP | WS_CHILD)"
	, !WS_POPUP && !WS_CHILD && WS_BORDER && WS_CAPTION && (WS_OVERLAPPED := 1))  ;;	WS_OVERLAPPED := WS_TILED

	Ret .= QStyle("WS_MINIMIZEBOX", "0x00020000", "(WS_SYSMENU)"  ;;	WS_MINIMIZEBOX
	, WS_SYSMENU && (sStyle & 0x00020000) && (WS_MINIMIZEBOX := 1, (Style & 0x00020000) && (Style -= 0x00020000))) 

	Ret .= QStyle("WS_MAXIMIZEBOX", "0x00010000", "(WS_SYSMENU)"
	, WS_SYSMENU && (sStyle & 0x00010000) && (WS_MAXIMIZEBOX := 1))  ;;	WS_MAXIMIZEBOX

	Ret .= QStyle("WS_OVERLAPPEDWINDOW := WS_TILEDWINDOW", "0x00CF0000"
		, "(WS_OVERLAPPED | WS_SIZEBOX | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)"
		, (WS_OVERLAPPED && WS_SIZEBOX && WS_SYSMENU && WS_MINIMIZEBOX && WS_MAXIMIZEBOX) )   ;;	WS_OVERLAPPEDWINDOW := WS_TILEDWINDOW

	If IsFunc("GetStyle_" Class)
		ChildStyles := GetStyle_%Class%(orStyle, hWnd, ChildExStyles)
				
	sExStyle := ExStyle
	For K, V In ExStyles 
		RetEx .= QStyle(K, V, "", (ExStyle & V) && (%K% := 1, ExStyle -= V))  

	RetEx .= QStyle("WS_EX_COMPOSITED", "0x02000000", "!(CS_OWNDC | CS_CLASSDC)"
	, !CS_OWNDC && !CS_CLASSDC && (ExStyle & 0x02000000) && (1, ExStyle -= 0x02000000))  ;;	WS_EX_COMPOSITED  

	RetEx .= QStyle("WS_EX_CONTEXTHELP", "0x00000400", "!(WS_MAXIMIZEBOX | WS_MINIMIZEBOX)"
	, !WS_MAXIMIZEBOX && !WS_MINIMIZEBOX && (ExStyle & 0x00000400) && (1, ExStyle -= 0x00000400))  ;;	WS_EX_CONTEXTHELP   
	 
	RetEx .= QStyle("WS_EX_LAYERED", "0x00080000", "!(CS_OWNDC | CS_CLASSDC)"
	, !CS_OWNDC && !CS_CLASSDC && (ExStyle & 0x00080000) && (1, ExStyle -= 0x00080000))  ;;	WS_EX_LAYERED   

	RetEx .= QStyle("WS_EX_LEFT", "0x00000000", "!(WS_EX_RIGHT)", !WS_EX_RIGHT)  ;;	WS_EX_LEFT    

	RetEx .= QStyle("WS_EX_RIGHTSCROLLBAR", "0x00000000"
	, "!(WS_EX_LEFTSCROLLBAR)", !WS_EX_LEFTSCROLLBAR)  ;;	WS_EX_RIGHTSCROLLBAR     

	RetEx .= QStyle("WS_EX_LTRREADING", "0x00000000", "!(WS_EX_RTLREADING)", !WS_EX_RTLREADING)  ;;	WS_EX_LTRREADING      

	RetEx .= QStyle("WS_EX_OVERLAPPEDWINDOW", "0x00000300"
	, "(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE)", WS_EX_WINDOWEDGE && WS_EX_CLIENTEDGE)  ;;	WS_EX_OVERLAPPEDWINDOW       

	RetEx .= QStyle("WS_EX_PALETTEWINDOW", "0x00000188", "(WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST)"
	, WS_EX_WINDOWEDGE && WS_EX_TOOLWINDOW && WS_EX_TOPMOST)  ;;	WS_EX_PALETTEWINDOW 

	IF Style
		Ret .= QStyleRest(8, Style) 
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Win'>" QStyleTitle("Styles", "", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2  
	Res .= ChildStyles
	IF ExStyle
		RetEx .= QStyleRest(8, ExStyle)  
	If RetEx !=
		Res .= "<a></a>" _T1 " id='__ExStyles_Win'>" QStyleTitle("ExStyles", "", 8, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2 
	Res .= ChildExStyles 
		
	;;  https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setclasslongw
	StyleBits := DllCall("GetClassLong", "UPtr", hWnd, "int", GCL_STYLE)	
	For K, V In ClassStyles 
		RetClass .= QStyleNB(K, V, "", (StyleBits & V) && (%K% := 1)) 
	
	If RetClass !=
		Res .= "<a></a>" _T1 " id='__ClassStyles_Win'>" QStyleTitle("Class Styles", "", 8, StyleBits) "</span>" _T2 _PRE1 RetClass _PRE2

	Return Res
}

QStyleTitle(Title, Name, F, V) {
	If Name !=
		Return " ( " Title " - <span name='MS:' style='color: #" ColorParam ";'>" Name "</span>: <span name='MS:' style='color: #" ColorFont ";'>" Format("0x{:0" F "X}", V) "</span> ) " 
	Return " ( " Title ": <span name='MS:' style='color: #" ColorFont ";'>" Format("0x{:0" F "X}", V) "</span> ) "  
}
QStyleRest(F, V) {
	Return "<span style='color: #" ColorDelimiter ";' name='MS:'>" Format("0x{1:0" F "X}", V) "</span>`n"
}
QStyle(k, v, q = "", e = "") { 
	Return " " (e ? _BP1 " id='___WStyleChange'>&#10004" _BP2 : _BPE1 " id='___WStyleChange'>&#10006" _BPE2)    
		. "  <span name='MS:Q'" (e ? "" : " class='QStyle4'") ">" k " := <span class='param' name='MS:'>" v "</span></span>" 
		. (q != "" ? _StIf q "</span>`n" : "`n")  
} 
QStyleNB(k, v, q = "", e = "") { 
	Return "<span name='MS:Q'" (e ? "" : " class='QStyle4'") ">" k " := <span class='param' name='MS:'>" v "</span></span>" 
		. (q != "" ? _StIf q "</span>`n" : "`n")  
} 

	; ___________________________ ControlStyles _________________________________________________

/*
	Added:
	Button, Edit, Static, SysListView32, SysTabControl32, SysDateTimePick32, SysMonthCal32, ComboBox, ListBox
	, msctls_trackbar32, msctls_statusbar32, msctls_progress32, msctls_updown32, SysLink, SysHeader32
	, ToolbarWindow32, SysTreeView32, ReBarWindow32, SysAnimate32, SysPager, #32770, tooltips_class32
*/  
	
GetStyle_#32770(Style, hWnd)  {
	;;	https://docs.microsoft.com/en-us/windows/desktop/dlgbox/dialog-box-styles
	Static oStyles
	If !oStyles
		oStyles := {"DS_3DLOOK":"0x00000004","DS_ABSALIGN":"0x00000001","DS_CENTER":"0x00000800","DS_CENTERMOUSE":"0x00001000","DS_CONTEXTHELP":"0x00002000"
		,"DS_CONTROL":"0x00000400","DS_FIXEDSYS":"0x00000008","DS_LOCALEDIT":"0x00000020","DS_MODALFRAME":"0x00000080","DS_NOFAILCREATE":"0x00000010"
		,"DS_NOIDLEMSG":"0x00000100","DS_SETFONT":"0x00000040","DS_SETFOREGROUND":"0x00000200","DS_SHELLFONT":"0x00000048","DS_SYSMODAL":"0x00000002"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (1, Style -= V))   
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "#32770", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}


GetStyle_tooltips_class32(Style, hWnd)  {
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/tooltip-styles
	Static oStyles
	If !oStyles
		oStyles := {"TTS_ALWAYSTIP":"0x00000001","TTS_BALLOON":"0x00000040","TTS_CLOSE":"0x00000080","TTS_NOANIMATE":"0x00000010","TTS_NOFADE":"0x00000020"
		,"TTS_NOPREFIX":"0x00000002","TTS_USEVISUALSTYLE":"0x00000100"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (1, Style -= V))   
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "tooltips_class32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}



GetStyle_Static(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25869#p25869
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/static-control-styles
	Static oStyles, oEx
	If !oStyles
		oStyles := {"SS_ELLIPSISMASK":"0xC000"
		,"SS_REALSIZECONTROL":"0x0040","SS_NOPREFIX":"0x0080","SS_NOTIFY":"0x0100","SS_CENTERIMAGE":"0x0200","SS_RIGHTJUST":"0x0400"
		,"SS_REALSIZEIMAGE":"0x0800","SS_SUNKEN":"0x1000","SS_EDITCONTROL":"0x2000","SS_ENDELLIPSIS":"0x4000","SS_PATHELLIPSIS":"0x8000"
		,"SS_WORDELLIPSIS":"0xC000"}

		, oEx := {"SS_CENTER":"0x0001","SS_RIGHT":"0x0002","SS_ICON":"0x0003","SS_BLACKRECT":"0x0004"
		,"SS_GRAYRECT":"0x0005","SS_WHITERECT":"0x0006","SS_BLACKFRAME":"0x0007","SS_GRAYFRAME":"0x0008","SS_WHITEFRAME":"0x0009"
		,"SS_USERITEM":"0x000A","SS_SIMPLE":"0x000B","SS_LEFTNOWORDWRAP":"0x000C","SS_OWNERDRAW":"0x000D","SS_BITMAP":"0x000E"
		,"SS_ENHMETAFILE":"0x000F","SS_ETCHEDHORZ":"0x0010","SS_ETCHEDVERT":"0x0011","SS_ETCHEDFRAME":"0x0012","SS_TYPEMASK":"0x001F"}

	Style := sStyle := Style & 0xffff
	For K, V In oEx
		If ((Style & 0x1F) = V) && (%K% := 1, Style -= V)
		{ 
			Ret .= QStyle(K, V, "", 1)
			Break
		}
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", Style && ((Style & V) = V) && (%K% := 1, Style -= V) )
	Ret .= QStyle("SS_LEFT", "0x0000", "!(SS_CENTER | SS_RIGHT)", !SS_CENTER && !SS_RIGHT)  ;;	SS_LEFT
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "Static", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_Button(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25841#p25841
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/button-styles
	Static oStyles, oEx
	If !oStyles
		oStyles := {"BS_ICON":"0x0040","BS_BITMAP":"0x0080","BS_LEFT":"0x0100","BS_RIGHT":"0x0200","BS_CENTER":"0x0300"
		,"BS_TOP":"0x0400","BS_BOTTOM":"0x0800","BS_VCENTER":"0x0C00","BS_PUSHLIKE":"0x1000","BS_MULTILINE":"0x2000"
		,"BS_NOTIFY":"0x4000","BS_FLAT":"0x8000"}

		, oEx := {"BS_DEFPUSHBUTTON":"0x0001","BS_CHECKBOX":"0x0002","BS_AUTOCHECKBOX":"0x0003"
		,"BS_RADIOBUTTON":"0x0004","BS_3STATE":"0x0005","BS_AUTO3STATE":"0x0006","BS_GROUPBOX":"0x0007","BS_USERBUTTON":"0x0008"
		,"BS_AUTORADIOBUTTON":"0x0009","BS_PUSHBOX":"0x000A","BS_OWNERDRAW":"0x000B","BS_COMMANDLINK":"0x000E"
		,"BS_DEFCOMMANDLINK":"0x000F","BS_SPLITBUTTON":"0x000C","BS_DEFSPLITBUTTON":"0x000D","BS_PUSHBUTTON":"0x0000","BS_TEXT":"0x0000"}
		  ;; "BS_TYPEMASK":"0x000F"

	Style := sStyle := Style & 0xffff
	For K, V In oEx
		If ((Style & 0xF) = V) && (%K% := 1, Style -= V)
		{
			Ret .= QStyle(K, V, "", 1)
			Break
		} 
	Ret .= QStyle("BS_LEFTTEXT := BS_RIGHTBUTTON", "0x0020"
	, "", (Style & 0x0020) = 0x0020)  ;;	BS_LEFTTEXT  ;;	BS_RIGHTBUTTON

	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (%K% := 1, Style -= V))
 
	Ret .= QStyle("BS_TEXT", "0x0000"  ;;	BS_TEXT
	, "!(BS_ICON | BS_BITMAP | BS_AUTOCHECKBOX | BS_AUTORADIOBUTTON | BS_CHECKBOX | BS_RADIOBUTTON)"
	, !BS_ICON && !BS_BITMAP && !BS_AUTOCHECKBOX && !BS_AUTORADIOBUTTON && !BS_CHECKBOX && !BS_RADIOBUTTON)
 
	Ret .= QStyle("BS_PUSHBUTTON", "0x0000"  ;;	BS_PUSHBUTTON
	, "!(BS_DEFPUSHBUTTON | BS_CHECKBOX | BS_AUTOCHECKBOX | BS_RADIOBUTTON | BS_GROUPBOX | BS_AUTORADIOBUTTON)"
	, !BS_DEFPUSHBUTTON && !BS_CHECKBOX && !BS_AUTOCHECKBOX && !BS_RADIOBUTTON && !BS_GROUPBOX && !BS_AUTORADIOBUTTON)

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "Button", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_Edit(Style, hWnd, byref ResEx)  {
	; https://www.autohotkey.com/boards/viewtopic.php?p=25848#p25848
	; https://docs.microsoft.com/en-us/windows/desktop/controls/edit-control-styles
	; https://docs.microsoft.com/en-us/windows/win32/controls/edit-control-window-extended-styles
	; https://docs.microsoft.com/en-us/windows/win32/controls/em-setextendedstyle
	Static oStyles, oExStyles, EM_GETEXTENDEDSTYLE := 0x1500 + 11
	If !oStyles
		oStyles := {"ES_CENTER":"0x0001","ES_RIGHT":"0x0002","ES_MULTILINE":"0x0004"
		,"ES_UPPERCASE":"0x0008","ES_LOWERCASE":"0x0010","ES_PASSWORD":"0x0020","ES_AUTOVSCROLL":"0x0040"
		,"ES_AUTOHSCROLL":"0x0080","ES_NOHIDESEL":"0x0100","ES_OEMCONVERT":"0x0400","ES_READONLY":"0x0800"
		,"ES_WANTRETURN":"0x1000","ES_NUMBER":"0x2000"}
		
		, oExStyles := {"ES_EX_ALLOWEOL_CR":"0x0001","ES_EX_ALLOWEOL_LF":"0x0002"
		,"ES_EX_CONVERT_EOL_ON_PASTE":"0x0004","ES_EX_ZOOMABLE":"0x0010"}

	SendMessage, EM_GETEXTENDEDSTYLE, 0, 0, , ahk_id %hWnd%
	ExStyle := sExStyle := ErrorLevel
	
	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (%K% := 1, Style -= V))
 
	Ret .= QStyle("ES_LEFT", "0x0000", "!(ES_CENTER | ES_RIGHT)", !ES_CENTER && !ES_RIGHT)  ;;	ES_LEFT

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "Edit", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2

	IF ExStyle
	{ 
		For K, V In oExStyles 
			RetEx .= QStyle(K, V, "", ((ExStyle & V) = V) && (%K% := 1, ExStyle -= V))  
		 
		RetEx .= QStyle("ES_EX_ALLOWEOL_ALL", "0x0003", "(ES_EX_ALLOWEOL_CR && ES_EX_ALLOWEOL_LF)", (sExStyle & 3))  
		IF ExStyle
			RetEx .= QStyleRest(4, ExStyle)
		
		If RetEx !=
			ResEx := "<a></a>" _T1 " id='__ExStyles_Control'>" QStyleTitle("ExStyles", "Edit", 4, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2
	} 
	
	Return Res
}

GetStyle_ComboLBox(Style, hWnd)  {
	Return GetStyle_ListBox(Style, hWnd)
}

GetStyle_ListBox(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25855#p25855
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/list-box-styles
	Static oStyles
	If !oStyles
		oStyles := {"LBS_NOTIFY":"0x0001","LBS_SORT":"0x0002","LBS_NOREDRAW":"0x0004","LBS_MULTIPLESEL":"0x0008"
		,"LBS_OWNERDRAWFIXED":"0x0010","LBS_OWNERDRAWVARIABLE":"0x0020","LBS_HASSTRINGS":"0x0040"
		,"LBS_USETABSTOPS":"0x0080","LBS_NOINTEGRALHEIGHT":"0x0100","LBS_MULTICOLUMN":"0x0200"
		,"LBS_WANTKEYBOARDINPUT":"0x0400","LBS_EXTENDEDSEL":"0x0800","LBS_DISABLENOSCROLL":"0x1000","LBS_NODATA":"0x2000"
		,"LBS_NOSEL":"0x4000","LBS_COMBOBOX":"0x8000"}
		, WS_VSCROLL := 0x200000, WS_BORDER := 0x800000

	wStyle := Style, Style := sStyle := Style & 0xffff

	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (%K% := 1, Style -= V)) 

	Ret .= QStyle("LBS_STANDARD", "0xA00003"  ;;	LBS_STANDARD 
	, "(LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER)"
	, LBS_NOTIFY && LBS_SORT && (wStyle & WS_VSCROLL) && (wStyle & WS_BORDER) && (1, Style -= 0x0003))

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "ListBox", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_SysAnimate32(Style, hWnd)  {
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/animation-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"ACS_CENTER":"0x0001","ACS_TRANSPARENT":"0x0002","ACS_AUTOPLAY":"0x0004","ACS_TIMER":"0x0008"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (1, Style -= V))  
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysAnimate32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_SysPager(Style, hWnd)  {
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/pager-control-styles
	Static oStyles, oEx
	If !oStyles
		oStyles := {"PGS_HORZ":"0x0001","PGS_AUTOSCROLL":"0x0002","PGS_DRAGNDROP":"0x0004"}
		, oEx := {"PGS_VERT":"0x0000"}
	Style := sStyle := Style & 0xffff
	If !(Style & oStyles.PGS_HORZ)
		Ret .= "<span name='MS:'>PGS_VERT := <span class='param' name='MS:'>0x0000   !(PGS_HORZ)</span></span>`n"
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (1, Style -= V))
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysPager", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_msctls_updown32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25878#p25878
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/up-down-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"UDS_WRAP":"0x0001","UDS_SETBUDDYINT":"0x0002","UDS_ALIGNRIGHT":"0x0004","UDS_ALIGNLEFT":"0x0008"
		,"UDS_AUTOBUDDY":"0x0010","UDS_ARROWKEYS":"0x0020","UDS_HORZ":"0x0040","UDS_NOTHOUSANDS":"0x0080","UDS_HOTTRACK":"0x0100"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (1, Style -= V) ) 
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "msctls_updown32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_SysDateTimePick32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25878#p25878
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/date-and-time-picker-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"DTS_UPDOWN":"0x0001","DTS_SHOWNONE":"0x0002","DTS_LONGDATEFORMAT":"0x0004","DTS_TIMEFORMAT":"0x0009"
			,"DTS_SHORTDATECENTURYFORMAT":"0x000C","DTS_APPCANPARSE":"0x0010","DTS_RIGHTALIGN":"0x0020"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (%K% := 1, Style -= V))  
	Ret .= QStyle("DTS_SHORTDATEFORMAT", "0x0000"  ;;	DTS_SHORTDATEFORMAT
	, "!(DTS_LONGDATEFORMAT)", !DTS_LONGDATEFORMAT)

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysDateTimePick32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_SysMonthCal32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25861#p25861
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/month-calendar-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"MCS_DAYSTATE":"0x0001","MCS_MULTISELECT":"0x0002","MCS_WEEKNUMBERS":"0x0004","MCS_NOTODAYCIRCLE":"0x0008"
		,"MCS_NOTODAY":"0x0010","MCS_NOTRAILINGDATES":"0x0040","MCS_SHORTDAYSOFWEEK":"0x0080","MCS_NOSELCHANGEONNAV":"0x0100"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (1, Style -= V)) 
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style) 
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysMonthCal32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_msctls_trackbar32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25875#p25875
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/trackbar-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"TBS_AUTOTICKS":"0x0001","TBS_VERT":"0x0002"
		,"TBS_BOTH":"0x0008","TBS_NOTICKS":"0x0010","TBS_ENABLESELRANGE":"0x0020"
		,"TBS_FIXEDLENGTH":"0x0040","TBS_NOTHUMB":"0x0080","TBS_TOOLTIPS":"0x0100","TBS_REVERSED":"0x0200"
		,"TBS_DOWNISLEFT":"0x0400","TBS_NOTIFYBEFOREMOVE":"0x0800","TBS_TRANSPARENTBKGND":"0x1000"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (%K% := 1, Style -= V))

	IF !TBS_VERT
	{
		Ret .= QStyle("TBS_HORZ", "0x0000", "!(TBS_VERT)", 1)  ;;	TBS_HORZ 
		Ret .= QStyle("TBS_TOP", "0x0004", "(TBS_HORZ)" ;;	TBS_TOP 
		, ((Style & 0x0004) = 0x0004) && (1, Style -= 0x0004)) 
		Ret .= QStyle("TBS_BOTTOM", "0x0000", "!(TBS_TOP) && (TBS_HORZ)"
		, !TBS_TOP)  ;;	TBS_BOTTOM 
	}
	Else
	{ 
		Ret .= QStyle("TBS_LEFT", "0x0004", "(TBS_VERT)"  ;;	TBS_LEFT
		,  ((Style & 0x0004) = 0x0004) && (TBS_LEFT := 1, Style -= 0x0004))
 
		Ret .= QStyle("TBS_RIGHT", "0x0000", "!(TBS_LEFT) && (TBS_VERT)"
		, !TBS_LEFT)  ;;	TBS_RIGHT 
	}
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "msctls_trackbar32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_msctls_statusbar32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25870#p25870
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/status-bar-styles
	Static oStyles
	If !oStyles
		oStyles := {"SBARS_SIZEGRIP":"0x0100","SBARS_TOOLTIPS":"0x0800"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (1, Style -= V))
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "msctls_statusbar32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_msctls_progress32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25864#p25864
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/progress-bar-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"PBS_SMOOTH":"0x0001","PBS_VERTICAL":"0x0004","PBS_MARQUEE":"0x0008","PBS_SMOOTHREVERSE":"0x0010"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (1, Style -= V) ) 
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "msctls_progress32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_SysHeader32(Style, hWnd)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25850#p25850
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/header-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"HDS_BUTTONS":"0x0002","HDS_CHECKBOXES":"0x0400","HDS_DRAGDROP":"0x0040","HDS_FILTERBAR":"0x0100","HDS_FLAT":"0x0200"
		,"HDS_FULLDRAG":"0x0080","HDS_HIDDEN":"0x0008","HDS_HORZ":"0x0000","HDS_HOTTRACK":"0x0004","HDS_NOSIZING":"0x0800","HDS_OVERFLOW":"0x1000"}

	;; Style := DllCall("GetWindowLong", "Ptr", hWnd, "int", GWL_STYLE := -16)

	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (1, Style -= V))
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysHeader32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_SysLink(Style, hWnd) {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25859#p25859
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/syslink-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"LWS_IGNORERETURN":"0x0002","LWS_NOPREFIX":"0x0004","LWS_RIGHT":"0x0020"
		,"LWS_TRANSPARENT":"0x0001","LWS_USECUSTOMTEXT":"0x0010","LWS_USEVISUALSTYLE":"0x0008"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (1, Style -= V))
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style) 
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysLink", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	
	Return Res
}

GetStyle_ReBarWindow32(Style, hWnd) {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25865#p25865
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/rebar-control-styles
	Static oStyles
	If !oStyles
		oStyles := {"RBS_AUTOSIZE":"0x2000","RBS_BANDBORDERS":"0x0400","RBS_DBLCLKTOGGLE":"0x8000","RBS_FIXEDORDER":"0x0800"
		,"RBS_REGISTERDROP":"0x1000","RBS_TOOLTIPS":"0x0100","RBS_VARHEIGHT":"0x0200","RBS_VERTICALGRIPPER":"0x4000"}

	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (1, Style -= V))
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "ReBarWindow32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	Return Res
}

GetStyle_CommonControl(Style, ByRef NewStyle) {   ;;	Остаток от стилей контролов
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25846#p25846
	Static oStyles, oEx
	If !oStyles
		oStyles := {"CCS_ADJUSTABLE":"0x0020","CCS_BOTTOM":"0x0003","CCS_NODIVIDER":"0x0040","CCS_NOMOVEY":"0x0002"
		,"CCS_NOPARENTALIGN":"0x0008","CCS_NORESIZE":"0x0004","CCS_TOP":"0x0001","CCS_VERT":"0x0080"}

		,oEx := {"CCS_LEFT":"0x0081","CCS_NOMOVEX":"0x0082","CCS_RIGHT":"0x0083"}

	NewStyle := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((NewStyle & V) = V) && (%K% := 1, NewStyle -= V)) 
	Ret .= QStyle("CCS_LEFT", "0x0081", "!(CCS_VERT | CCS_TOP)"  ;;	CCS_LEFT
	, !CCS_VERT && !CCS_TOP && (NewStyle & oEx.CCS_LEFT) && (1, NewStyle -= oEx.CCS_LEFT)) 
	Ret .= QStyle("CCS_NOMOVEX", "0x0082", "!(CCS_VERT | CCS_NOMOVEY)"  ;;	CCS_NOMOVEX
	, !CCS_VERT && !CCS_NOMOVEY && (NewStyle & oEx.CCS_NOMOVEX) && (1, NewStyle -= oEx.CCS_NOMOVEX))  
	Ret .= QStyle("CCS_RIGHT", "0x0083", "!(CCS_VERT | CCS_BOTTOM)"  ;;	CCS_RIGHT
	, !CCS_VERT && !CCS_BOTTOM && (NewStyle & oEx.CCS_RIGHT) && (1, NewStyle -= oEx.CCS_RIGHT)) 
	Return Ret
}




GetStyle_SysListView32(Style, hWnd, byref ResEx)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25857#p25857
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/list-view-window-styles
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/extended-list-view-styles
	Static oStyles, oExStyles, oEx, LVM_GETEXTENDEDLISTVIEWSTYLE := 0x1037
	If !oStyles
		oStyles := {"LVS_AUTOARRANGE":"0x0100","LVS_EDITLABELS":"0x0200"
		,"LVS_NOLABELWRAP":"0x0080","LVS_NOSCROLL":"0x2000"
		,"LVS_OWNERDRAWFIXED":"0x0400","LVS_SHAREIMAGELISTS":"0x0040","LVS_SHOWSELALWAYS":"0x0008","LVS_SINGLESEL":"0x0004"
		,"LVS_OWNERDATA":"0x1000","LVS_SORTASCENDING":"0x0010","LVS_SORTDESCENDING":"0x0020"}

		, oExStyles := {"LVS_EX_AUTOAUTOARRANGE":"0x01000000","LVS_EX_AUTOCHECKSELECT":"0x08000000","LVS_EX_AUTOSIZECOLUMNS":"0x10000000"
		,"LVS_EX_BORDERSELECT":"0x00008000","LVS_EX_CHECKBOXES":"0x00000004","LVS_EX_COLUMNOVERFLOW":"0x80000000","LVS_EX_COLUMNSNAPPOINTS":"0x40000000"
		,"LVS_EX_DOUBLEBUFFER":"0x00010000","LVS_EX_FLATSB":"0x00000100","LVS_EX_FULLROWSELECT":"0x00000020","LVS_EX_GRIDLINES":"0x00000001"
		,"LVS_EX_HEADERDRAGDROP":"0x00000010","LVS_EX_HEADERINALLVIEWS":"0x02000000","LVS_EX_HIDELABELS":"0x00020000"
		,"LVS_EX_INFOTIP":"0x00000400","LVS_EX_JUSTIFYCOLUMNS":"0x00200000","LVS_EX_LABELTIP":"0x00004000","LVS_EX_MULTIWORKAREAS":"0x00002000"
		,"LVS_EX_ONECLICKACTIVATE":"0x00000040","LVS_EX_REGIONAL":"0x00000200","LVS_EX_SIMPLESELECT":"0x00100000","LVS_EX_SINGLEROW":"0x00040000"
		,"LVS_EX_SNAPTOGRID":"0x00080000","LVS_EX_SUBITEMIMAGES":"0x00000002","LVS_EX_TRACKSELECT":"0x00000008","LVS_EX_TRANSPARENTBKGND":"0x00400000"
		,"LVS_EX_TRANSPARENTSHADOWTEXT":"0x00800000","LVS_EX_TWOCLICKACTIVATE":"0x00000080"
		,"LVS_EX_UNDERLINECOLD":"0x00001000","LVS_EX_UNDERLINEHOT":"0x00000800"}

		,oEx := {"LVS_TYPEMASK":"0x0003","LVS_ICON":"0x0000","LVS_REPORT":"0x0001","LVS_SMALLICON":"0x0002","LVS_LIST":"0x0003"
		,"LVS_ALIGNMASK":"0x0C00","LVS_ALIGNTOP":"0x0000","LVS_ALIGNLEFT":"0x0800"
		,"LVS_TYPESTYLEMASK":"0xFC00","LVS_NOSORTHEADER":"0x8000","LVS_NOCOLUMNHEADER":"0x4000"}

	SendMessage, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0,, ahk_id %hWnd%
	ExStyle := sExStyle := ErrorLevel
	Style := sStyle := Style & 0xffff

	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((sStyle & V) = V) && (%K% := 1, Style -= V)) 
 
		Ret .= QStyle("LVS_REPORT", "0x0001", "(LVS_TYPEMASK = 0x0001)"   ;;	LVS_REPORT 
		, ((sStyle & oEx.LVS_TYPEMASK) = oEx.LVS_REPORT) && (LVS_REPORT := 1, Style -= oEx.LVS_REPORT)) 
		Ret .= QStyle("LVS_SMALLICON", "0x0002", "(LVS_TYPEMASK = 0x0002)"   ;;	LVS_SMALLICON
		, ((sStyle & oEx.LVS_TYPEMASK) = oEx.LVS_SMALLICON) && (LVS_SMALLICON := 1, Style -= oEx.LVS_SMALLICON)) 
		Ret .= QStyle("LVS_LIST", "0x0003", "(LVS_TYPEMASK = 0x0003)"   ;;	LVS_LIST
		, ((sStyle & oEx.LVS_TYPEMASK) = oEx.LVS_LIST) && (LVS_LIST := 1, Style -= oEx.LVS_LIST) )
		Ret .= QStyle("LVS_ICON", "0x0000", "!(LVS_REPORT | LVS_SMALLICON | LVS_LIST)"   ;;	LVS_ICON
		, ((sStyle & oEx.LVS_TYPEMASK) = oEx.LVS_ICON) && !LVS_REPORT && !LVS_SMALLICON && !LVS_LIST && (LVS_ICON := 1))
		Ret .= QStyle("LVS_ALIGNLEFT", "0x0800", "(LVS_ALIGNMASK = 0x0800)"    ;;	LVS_ALIGNLEFT
		, ((sStyle & oEx.LVS_ALIGNMASK) = oEx.LVS_ALIGNLEFT) && (LVS_ALIGNLEFT := 1, Style -= oEx.LVS_ALIGNLEFT))
		Ret .= QStyle("LVS_ALIGNTOP", "0x0000", "(LVS_SMALLICON || LVS_ICON)"    ;;	LVS_ALIGNTOP
		,((sStyle & oEx.LVS_ALIGNMASK) = oEx.LVS_ALIGNTOP) && (LVS_SMALLICON || LVS_ICON) && (LVS_ALIGNTOP := 1, Style -= oEx.LVS_ALIGNTOP) )
		Ret .= QStyle("LVS_NOSORTHEADER", "0x8000", "(LVS_TYPEMASK = 0x0003)"   ;;	LVS_NOSORTHEADER
		, ((sStyle & oEx.LVS_NOSORTHEADER) = oEx.LVS_NOSORTHEADER) && (LVS_NOSORTHEADER := 1, Style -= oEx.LVS_NOSORTHEADER))
		Ret .= QStyle("LVS_NOCOLUMNHEADER", "0x4000"  ;;	LVS_NOCOLUMNHEADER
		, ((sStyle & oEx.LVS_NOCOLUMNHEADER) = oEx.LVS_NOCOLUMNHEADER) && (LVS_NOCOLUMNHEADER := 1, Style -= oEx.LVS_NOCOLUMNHEADER))

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysListView32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
	 
	For K, V In oExStyles 
		RetEx .= QStyle(K, V, "", ((ExStyle & V) = V) && (%K% := 1, ExStyle -= V))

	IF ExStyle
		RetEx .= QStyleRest(8, ExStyle)  
	If RetEx !=
		ResEx := "<a></a>" _T1 " id='__ExStyles_Control'>" QStyleTitle("ExStyles", "SysListView32", 8, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2
	 
	 Return Res
}

GetStyle_SysTreeView32(Style, hWnd, byref ResEx)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25876#p25876
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/tree-view-control-window-styles
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/tree-view-control-window-extended-styles
	Static oStyles, oExStyles, TVM_GETEXTENDEDSTYLE := 0x112D
	If !oStyles
		oStyles := {"TVS_CHECKBOXES":"0x0100","TVS_DISABLEDRAGDROP":"0x0010","TVS_EDITLABELS":"0x0008","TVS_FULLROWSELECT":"0x1000","TVS_HASBUTTONS":"0x0001"
		,"TVS_HASLINES":"0x0002","TVS_INFOTIP":"0x0800","TVS_LINESATROOT":"0x0004","TVS_NOHSCROLL":"0x8000","TVS_NONEVENHEIGHT":"0x4000","TVS_NOSCROLL":"0x2000"
		,"TVS_NOTOOLTIPS":"0x0080","TVS_RTLREADING":"0x0040","TVS_SHOWSELALWAYS":"0x0020","TVS_SINGLEEXPAND":"0x0400","TVS_TRACKSELECT":"0x0200"}

		, oExStyles := {"TVS_EX_AUTOHSCROLL":"0x0020","TVS_EX_DIMMEDCHECKBOXES":"0x0200","TVS_EX_DOUBLEBUFFER":"0x0004","TVS_EX_DRAWIMAGEASYNC":"0x0400"
		,"TVS_EX_EXCLUSIONCHECKBOXES":"0x0100","TVS_EX_FADEINOUTEXPANDOS":"0x0040","TVS_EX_MULTISELECT":"0x0002","TVS_EX_NOINDENTSTATE":"0x0008"
		,"TVS_EX_NOSINGLECOLLAPSE":"0x0001","TVS_EX_PARTIALCHECKBOXES":"0x0080","TVS_EX_RICHTOOLTIP":"0x0010"}

	SendMessage, TVM_GETEXTENDEDSTYLE, 0, 0,, ahk_id %hWnd%
	ExStyle := sExStyle := ErrorLevel
	Style := sStyle := Style & 0xffff

	For K, V In oStyles
		Ret .= QStyle(K, V, "", ((sStyle & V) = V) && (1, Style -= V))

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysTreeView32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
 
	For K, V In oExStyles 
		RetEx .= QStyle(K, V, "", ((ExStyle & V) = V) && (1, ExStyle -= V))

	IF ExStyle
		RetEx .= QStyleRest(8, ExStyle)  
	If RetEx !=
		ResEx := "<a></a>" _T1 " id='__ExStyles_Control'>" QStyleTitle("ExStyles", "SysTreeView32", 8, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2
	
	Return Res
}

GetStyle_SysTabControl32(Style, hWnd, byref ResEx)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25871#p25871
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/tab-control-styles
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/tab-control-extended-styles
	Static oStyles, TCM_GETEXTENDEDSTYLE := 0x1335
	If !oStyles
		oStyles := {"TCS_SCROLLOPPOSITE":"0x0001","TCS_MULTISELECT":"0x0004","TCS_FLATBUTTONS":"0x0008"
		,"TCS_FORCELABELLEFT":"0x0020","TCS_HOTTRACK":"0x0040","TCS_BUTTONS":"0x0100","TCS_MULTILINE":"0x0200"
		,"TCS_FORCEICONLEFT":"0x0010","TCS_FIXEDWIDTH":"0x0400","TCS_RAGGEDRIGHT":"0x0800","TCS_FOCUSONBUTTONDOWN":"0x1000"
		,"TCS_OWNERDRAWFIXED":"0x2000","TCS_TOOLTIPS":"0x4000","TCS_FOCUSNEVER":"0x8000"}

	SendMessage, TCM_GETEXTENDEDSTYLE, 0, 0,, ahk_id %hWnd%
	ExStyle := sExStyle := ErrorLevel
	Style := sStyle := Style & 0xffff
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (%K% := 1, Style -= V))
 
		Ret .= QStyle("TCS_TABS", "0x0000", "!(TCS_BUTTONS)", !TCS_BUTTONS)  ;;	TCS_TABS 
		Ret .= QStyle("TCS_SINGLELINE", "0x0000", "!(TCS_MULTILINE)", !TCS_MULTILINE)  ;;	TCS_SINGLELINE
		Ret .= QStyle("TCS_RIGHTJUSTIFY", "0x0000", "(TCS_MULTILINE)", TCS_MULTILINE)   ;;	TCS_RIGHTJUSTIFY
		Ret .= QStyle("TCS_VERTICAL", "0x0080", "(TCS_MULTILINE)"  ;;	"TCS_VERTICAL":"0x0080"
		, TCS_MULTILINE && ((Style & 0x0080) = 0x0080) && (TCS_VERTICAL := 1, Style -= 0x0080))
	;;	"TCS_BOTTOM":"0x0002","TCS_RIGHT":"0x0002" 
		Ret .= QStyle("TCS_RIGHT", "0x0002", "(TCS_VERTICAL)"
		, ((Style & 0x0002) = 0x0002) && (1, Style -= 0x0002)) 
		Ret .= QStyle("TCS_BOTTOM", "0x0002", "!(TCS_VERTICAL)"
		, ((Style & 0x0002) = 0x0002) && (1, Style -= 0x0002))  
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style)  
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "SysTabControl32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2
  
		RetEx .= QStyle("TCS_EX_FLATSEPARATORS", "0x00000001"   ;;	TCS_EX_FLATSEPARATORS
		, ((ExStyle & 0x00000001) = 0x00000001) && (1, ExStyle -= 0x00000001))
		RetEx .= QStyle("TCS_EX_REGISTERDROP", "0x00000002"   ;;	TCS_EX_REGISTERDROP
		, ((ExStyle & 0x00000002) = 0x00000002) && (1, ExStyle -= 0x00000002))

	IF ExStyle
		RetEx .= QStyleRest(8, ExStyle)  
	If RetEx !=
		ResEx := "<a></a>" _T1 " id='__ExStyles_Control'>" QStyleTitle("ExStyles", "SysTabControl32", 8, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2
	
	Return Res
}

GetStyle_ComboBox(Style, hWnd, byref ResEx)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25842#p25842
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/combo-box-styles
	Static oStyles, oExStyles, oEx, CBEM_GETEXTENDEDSTYLE := 0x0409
	If !oStyles
		oStyles := {"CBS_SIMPLE":"0x0001","CBS_DROPDOWN":"0x0002","CBS_OWNERDRAWFIXED":"0x0010"
		,"CBS_OWNERDRAWVARIABLE":"0x0020","CBS_AUTOHSCROLL":"0x0040","CBS_OEMCONVERT":"0x0080","CBS_SORT":"0x0100"
		,"CBS_HASSTRINGS":"0x0200","CBS_NOINTEGRALHEIGHT":"0x0400","CBS_DISABLENOSCROLL":"0x0800"
		,"CBS_UPPERCASE":"0x2000","CBS_LOWERCASE":"0x4000"}
		, oEx := {"CBS_DROPDOWNLIST":"0x0003"}
		, oExStyles := {"CBES_EX_CASESENSITIVE":"0x0010","CBES_EX_NOEDITIMAGE":"0x0001","CBES_EX_NOEDITIMAGEINDENT":"0x0002"
		,"CBES_EX_NOSIZELIMIT":"0x0008","CBES_EX_PATHWORDBREAKPROC":"0x0004","CBES_EX_TEXTENDELLIPSIS":"0x0020"}
	
	If (hParent := DllCall("GetParent", "UPtr", hWnd))
	{
		WinGetClass, ParentClass, ahk_id %hParent%
		If ParentClass = ComboBoxEx32
		{
			SendMessage, CBEM_GETEXTENDEDSTYLE, 0, 0, , ahk_id %hParent%
			ExStyle := sExStyle := ErrorLevel
			For K, V In oExStyles 
				RetEx .= QStyle(K, V, "", ((ExStyle & V) = V) && (1, ExStyle -= V) )
			IF ExStyle
				RetEx .= QStyleRest(4, ExStyle) 
		} 
	}
	Style := sStyle := Style & 0xffff 
		Ret .= QStyle("CBS_DROPDOWNLIST", oEx.CBS_DROPDOWNLIST, ""    ;;	CBS_DROPDOWNLIST
		, ((Style & oEx.CBS_DROPDOWNLIST) = oEx.CBS_DROPDOWNLIST) && (1, Style -= oEx.CBS_DROPDOWNLIST))
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((Style & V) = V) && (1, Style -= V))
	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(4, Style) 
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "ComboBox", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2 
	If RetEx !=
		ResEx := "<a></a>" _T1 " id='__ExStyles_Control'>" QStyleTitle("ExStyles", "ComboBoxEx32", 4, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2
	Return Res
}

GetStyle_ToolbarWindow32(Style, hWnd, byref ResEx)  {
	;;	https://www.autohotkey.com/boards/viewtopic.php?p=25872#p25872
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/toolbar-control-and-button-styles
	;;	https://docs.microsoft.com/en-us/windows/desktop/controls/toolbar-extended-styles
	;;	https://docs.microsoft.com/en-us/windows/desktop/api/Commctrl/ns-commctrl-_tbbutton
	Static oStyles, oExStyles, TB_GETSTYLE := 0x0439, TB_GETEXTENDEDSTYLE := 0x0455
	If !oStyles
		oStyles := {"TBSTYLE_ALTDRAG":"0x0400","TBSTYLE_CUSTOMERASE":"0x2000","TBSTYLE_FLAT":"0x0800","TBSTYLE_LIST":"0x1000"
		,"TBSTYLE_REGISTERDROP":"0x4000","TBSTYLE_TOOLTIPS":"0x0100","TBSTYLE_TRANSPARENT":"0x8000","TBSTYLE_WRAPABLE":"0x0200"}

		, oExStyles := {"TBSTYLE_EX_DOUBLEBUFFER":"0x80","TBSTYLE_EX_DRAWDDARROWS":"0x01","TBSTYLE_EX_HIDECLIPPEDBUTTONS":"0x10"
		,"TBSTYLE_EX_MIXEDBUTTONS":"0x08","TBSTYLE_EX_MULTICOLUMN":"0x02","TBSTYLE_EX_VERTICAL":"0x04"}

	SendMessage, TB_GETSTYLE, 0, 0, , ahk_id %hWnd%
	Style := sStyle := ErrorLevel & 0xffff

	SendMessage, TB_GETEXTENDEDSTYLE, 0, 0, , ahk_id %hWnd%
	ExStyle := sExStyle := ErrorLevel 
	
	For K, V In oStyles 
		Ret .= QStyle(K, V, "", ((sStyle & V) = V) && (1, Style -= V))

	IF Style
		Ret .= GetStyle_CommonControl(Style, Style)
	IF Style
		Ret .= QStyleRest(8, Style)   
	If Ret !=
		Res .= "<a></a>" _T1 " id='__Styles_Control'>" QStyleTitle("Styles", "ToolbarWindow32", 4, sStyle) "</span>" _T2 _PRE1 Ret _PRE2 
	For K, V In oExStyles 
		RetEx .= QStyle(K, V, "", ((ExStyle & V) = V) && (1, ExStyle -= V))

	IF ExStyle
		RetEx .= QStyleRest(4, ExStyle)  
	If RetEx !=
		ResEx := "<a></a>" _T1 " id='__ExStyles_Control'>" QStyleTitle("ExStyles", "ToolbarWindow32", 4, sExStyle) "</span>" _T2 _PRE1 RetEx _PRE2 
		
	Return Res
	
/*
		oBTNS := {"BTNS_BUTTON":"0x00","BTNS_SEP":"0x01","BTNS_CHECK":"0x02","BTNS_GROUP":"0x04","BTNS_CHECKGROUP":"0x06","BTNS_DROPDOWN":"0x08"
		,"BTNS_AUTOSIZE":"0x10","BTNS_NOPREFIX":"0x20","BTNS_SHOWTEXT":"0x40","BTNS_WHOLEDROPDOWN":"0x80"}

		VarSetCapacity(TBBUTTON, A_PtrSize == 8 ? 32 : 20, 0)

		iBitmap := NumGet(TBBUTTON, 0, "Int")
		idCommand := NumGet(TBBUTTON, 4, "Int")
		fsState := NumGet(TBBUTTON, 8, "UChar")
		fsStyle := NumGet(TBBUTTON, 9, "UChar")
		bReserved := NumGet(TBBUTTON, 10, "UChar")
		;;bReserved := NumGet(TBBUTTON, 10, "UChar")
		dwData := NumGet(TBBUTTON, A_PtrSize == 8 ? 16 : 12, "UPtr")
		iString := NumGet(TBBUTTON, A_PtrSize == 8 ? 24 : 16, "Ptr")
*/
}

	; ___________________________ FullScreen _________________________________________________

FullScreenMode() {
	Static Max, hFunc
	hwnd := WinExist("ahk_id" hGui)
	If !FullScreenMode
	{
		FullScreenMode := 1
		Menu, Sys, Check, Full screen
		WinGetNormalPos(hwnd, X, Y, W, H)
		WinGet, Max, MinMax, ahk_id %hwnd%
		If Max = 1
			WinSet, Style, -0x01000000	;;	WS_MAXIMIZE
		Gui, 1: -ReSize -Caption
		Gui, 1: Show, x0 y0 w%A_ScreenWidth% h%A_ScreenHeight%
		Gui, 1: Maximize
		WinSetNormalPos(hwnd, X, Y, W, H)
		hFunc := Func("ControlsMove").Bind(A_ScreenWidth, A_ScreenHeight)
	}
	Else
	{
		Gui, 1: +ReSize +Caption
		If Max = 1
		{
			WinGetNormalPos(hwnd, X, Y, W, H)
			Gui, 1: Maximize
			WinSetNormalPos(hwnd, X, Y, W, H)
		}
		Else
			Gui, 1: Restore
		Sleep 20
		GetClientPos(hwnd, _, _, Width, Height)
		hFunc := Func("ControlsMove").Bind(Width, Height)
		FullScreenMode := 0
		Menu, Sys, UnCheck, Full screen
	}
	SetTimer, % hFunc, -10
}

WinGetNormalPos(hwnd, ByRef x, ByRef y, ByRef w, ByRef h) {
	VarSetCapacity(wp, 44), NumPut(44, wp)
	DllCall("GetWindowPlacement", "UPtr", hwnd, "Ptr", &wp)
	x := NumGet(wp, 28, "int"), y := NumGet(wp, 32, "int")
	w := NumGet(wp, 36, "int") - x,  h := NumGet(wp, 40, "int") - y
}

WinSetNormalPos(hwnd, x, y, w, h) {
	VarSetCapacity(wp, 44, 0), NumPut(44, wp, 0, "uint")
	DllCall("GetWindowPlacement", "UPtr", hWnd, "Ptr", &wp)
	NumPut(x, wp, 28, "int"), NumPut(y, wp, 32, "int")
	NumPut(w + x, wp, 36, "int"), NumPut(h + y, wp, 40, "int")
	DllCall("SetWindowPlacement", "UPtr", hWnd, "Ptr", &wp)
}

	; ___________________________ Find _________________________________________________

_FindView() {
	If isFindView
		Return FindHide(), AnchorFitScroll()
	GuiControlGet, p, 1:Pos, %hActiveX%
	GuiControl, 1:Move, %hActiveX%, % "x" pX " y" pY " w" pW " h" pH - 28
	Gui, F: Show, % "NA x" (pW - widthTB) // 2.2 " h26 y" (pY + pH - 27)
	isFindView := 1
	GuiControl, F:Focus, Edit1
	Menu, Sys, Check, Find to page
	FindSearch(1) 
	AnchorFitScroll()
}

FindHide() {
	Gui, F: Show, Hide
	GuiControlGet, a, 1:Pos, %hActiveX%
	GuiControl, 1:Move, %hActiveX%, % "x" aX "y" aY "w" aW "h" aH + 28
	isFindView := 0
	GuiControl, Focus, %hActiveX%
	Menu, Sys, UnCheck, Find to page
}

FindOption(Hwnd) {
	GuiControlGet, p, Pos, %Hwnd%
	If pX =
		Return
	ControlGet, Style, Style,, , ahk_id %Hwnd%
	ControlGetText, Text, , ahk_id %Hwnd%
	DllCall("DestroyWindow", "UPtr", Hwnd)
	; BS_PUSHLIKE := 0x1000
	Gui, %A_Gui%: Add, Text, % "x" pX " y" pY " w" pW " h" pH " g" A_ThisFunc " c" ColorFont " " (Style & 0x1000 ? "+0x0201" : "+Border +0x1201"), % Text
	InStr(Text, "sensitive") ? (oFind.Registr := !(Style & 0x1000)) : (oFind.Whole := !(Style & 0x1000))
	FindSearch(1)
	FindAll()
}

FindNew(Hwnd) {
	ControlGetText, Text, , ahk_id %Hwnd%
	oFind.Text := Text
	hFunc := Func("FindSearch").Bind(1)
	SetTimer, FindAll, -150
	SetTimer, % hFunc, -150
}

FindNewText() {
	hFunc := Func("FindSearch").Bind(1)
	SetTimer, % hFunc, -1
	SetTimer, FindAll, -150
}

FindNext(Hwnd) {
	SendMessage, 0x400+114,,,, ahk_id %Hwnd%		;;  UDM_GETPOS32
	Back := !ErrorLevel
	FindSearch(0, Back)
}

FindAll() {
	If (oFind.Text = "")
	{
		GuiControl, F:Text, FindMatches
		Return
	}
	R := oBody.createTextRange()
	Matches := 0
	R.collapse(1)
	Option := (oFind.Whole ? 2 : 0) ^ (oFind.Registr ? 4 : 0)
	Loop
	{
		F := R.findText(oFind.Text, 1, Option)
		If (F = 0)
			Break
		El := R.parentElement()
		If (El.TagName = "INPUT" || El.className ~= "^(button|title|param)$") && !R.collapse(0)  ;;	https://msdn.microsoft.com/en-us/library/ff976065(v=vs.85).aspx
			Continue
		; R.execCommand("BackColor", 0, "EF0FFF")
		; R.execCommand("ForeColor", 0, "FFEEFF")
		R.collapse(0), ++Matches
	}
	GuiControl, F:Text, FindMatches, % Matches ? Matches : ""
}

FindSearch(New, Back = 0) {
	Global hFindEdit
	R := oDoc.selection.createRange()
	sR := R.duplicate()
	R.collapse(New || Back ? 1 : 0)
	If (oFind.Text = "" && !R.select()) 
		SetEditColor(hFindEdit, "0x" ColorBgOriginal, "0x" ColorFont)
	Else {
		Option := (Back ? 1 : 0) ^ (oFind.Whole ? 2 : 0) ^ (oFind.Registr ? 4 : 0)
		Loop {
			F := R.findText(oFind.Text, 1, Option)
			If (F = 0) {
				If !A {
					R.moveToElementText(oBody), R.collapse(!Back), A := 1
					Continue
				}
				If New
					sR.collapse(1), sR.select()
				Break
			}
			If (!New && R.isEqual(sR)) {
				If A {
					hFunc := Func("SetEditColor").Bind(hFindEdit, "0x" ColorBgOriginal, "0x" ColorFont)
					SetTimer, % hFunc, -200
				}
				Break
			}
			El := R.parentElement()

			If (El.TagName = "INPUT" || El.className ~= "^(button|title|param)$") && !R.collapse(Back)
				Continue
			R.select(), F := 1
			Break
		}
		If (F != 1)
			SetEditColor(hFindEdit, "0x" ColorSelectedFind, "0x" ColorFont)
		Else
			SetEditColor(hFindEdit, "0x" ColorBgOriginal, "0x" ColorFont)
	}
}
	; ___________________________ Mouse hover selection _________________________________________________

MS_Cancel() {
	If !oMS.ELSel
		Return
	oMS.ELSel.style.backgroundColor := "" 
	oMS.ELSel.style.color := "" 
	Loop % oMS.ELSel.all.length 
		oMS.ELSel.all[A_Index-1].style.color := ""
	oMS.ELSel := ""	
}

MS_SelectionCheck() {
	Selection := oDoc.selection.createRange().text != ""
	If Selection
		(!oMS.Selection && MS_Cancel())
	Else If oMS.Selection && MS_IsSelect(EL := oDoc.elementFromPoint(oMS.SCX, oMS.SCY))
		MS_Select(EL)
	oMS.Selection := Selection
}

MS_MouseOver() {
	EL := oMS.EL 
	If !MS_IsSelect(EL)
		Return
	MS_Select(EL)
}

MS_IsSelect(EL) {
	If InStr(EL.Name, "MS:")
		Return 1
}

MS_IsSelection() {
	Return oMS.ELSel.OuterText != ""
}

MS_Select(EL) { 
	If EL.Name = "MS:S" || EL.Name = "MS:SP"
		oMS.ELSel := EL.ParentElement 
	Else If EL.Name = "MS:N"
		oMS.ELSel := oDoc.all.item(EL.sourceIndex + 1)
	Else If EL.Name = "MS:P"
		oMS.ELSel := oDoc.all.item(EL.sourceIndex - 1).ParentElement
	Else If EL.Name = "MS:P4"
		oMS.ELSel := oDoc.all.item(EL.sourceIndex - 4).ParentElement
	Else
		oMS.ELSel := EL
		
	oMS.ELSel.style.backgroundColor := "#" ColorSelMouseHover
	oMS.ELSel.style.color := "#" ColorSelMouseHoverText
	
	Loop % oMS.ELSel.all.length 
		oMS.ELSel.all[A_Index-1].style.color := "#" ColorSelMouseHoverText
		 
	; ToolTip % oMS.ELSel.all.length "`n" oMS.TextColor2.OuterText "`n" EL.Name "`n" el.style.color 
}
 
	; ___________________________ Load JScripts _________________________________________________
 
ChangeCSS(id, css) {	;;  https://webo.in/articles/habrahabr/68-fast-dynamic-css/ 
	oDoc.getElementById(id).styleSheet.cssText := css
}

LoadJScript() {
	Static onhkinput, ontooltip 
	PreOver_ := PreOverflowHide ? _PreOverflowHideCSS : ""
	BodyWrap_ := WordWrap ? _BodyWrapCSS : ""
html =
(
<head> 
	<style id='css_ColorBg' type="text/css">body, .title, .button, .divwork {background-color: #%ColorBg%;}</style>
	<style id='css_PreOverflowHide' type="text/css">%PreOver_%</style>
	<style id='css_Body' type="text/css">%BodyWrap_%</style>
	<style id='css_Test' type="text/css"></style>
<style>

* {
	margin: 0;
	background: none;
	font-family: %FontFamily%;
	font-weight: %FontWeight%;
	color: #%ColorFont%; 
	// word-spacing: 0.5em;
}
body {  
	overflow: hidden; 
}
.divwork {
	position: absolute; 
	top: 5px;
	left: 5px;
	right: 1px;
	bottom: 1px; 
	font-size: %FontSize%px;
	visibility: hidden;
	overflow: auto;
	scrollbar-face-color: #%ColorScrollFace%;			/* Цвет ползунка  */
    scrollbar-arrow-color: #%ColorScrollArrows%;		/* Цвет стрелок */
    scrollbar-base-color: #%ColorScrollBack%; 	/* Цвет полосы */
	scrollbar-highlight-color: #%ColorScrollBack%;
    scrollbar-shadow-color: #%ColorScrollBack%; /* Цвет тени */
	scrollbar-track-color: #%ColorScrollBack%;
}
.br {
	height:0.1em;
} 
.box {
	position: absolute;
	overflow: hidden; 
	width: 100`%;
	height: 1.5em;
	background: transparent;
	left: 0px;
}
.line {
	position: absolute;
	width: 100`%;
	top: 1px;
}
.con {
	position: absolute;
	left: 30`%;
}
.title {
	margin-right: 50px;
	white-space: pre;
	color: #%ColorTitle%;
}
.title2 {
	color: #%ColorTitle%;
}
.hr {
	position: absolute;
	width: 100`%;
	border-bottom: 0.2em dashed;
	border-color: #%ColorLineTitles%;
	height: 0.5em;
}
pre {
	margin-bottom: 0.1em;
	margin-top: 0.1em;
	line-height: 1.4em;
}
.button {
	cursor: hand;
	position: relative;
	border: 1px dotted;
	border-color: #%ColorFont%;
	white-space: pre;
}
.BB {
	display: inline-block; 
} 
.param {
	color: #%ColorParam%;
}
.QStyle1 {
	color: #%ColorStyleComment1%;
}
.QStyle2 {
	color: #%ColorStyleComment2%;
} 
.QStyle3 {
	color: #%ColorSelAnchor%;
} 
.QStyle4 {
	color: #%ColorStyleNoApply%;
} 
.error {
	color: #%ColorDelimiter%;
}  
.titleparam {
	color: #%ColorTitle%;
}
#anchor {
	background-color: #%ColorSelAnchor%;
} 
</style>

</head>

<body contenteditable='false' id='body'>
	<div id='divwork1' class='divwork' onscroll='scrolldiv(this)' onresize='resizediv(this)'></div>
	<div id='divwork2' class='divwork' onscroll='scrolldiv(this)' onresize='resizediv(this)'></div>
</body>

<script type="text/javascript">
	var prWidth, WordWrap, MoveTitles, key1, key2, ButtonOver, ButtonOverColor; 
	
	function shift(el, scroll) {
		var col, Width, clientWidth, scrollLeft, Offset;
		
		clientWidth = el.clientWidth;
		// tooltip(el.id + "   " + el.style.width);
		// alert(clientWidth);
		if (clientWidth < 0)
			return
		scrollLeft = el.scrollLeft;
		Width = (clientWidth + scrollLeft);
		if (scroll && Width == prWidth)
			return
		if (MoveTitles == 1) {
			Offset = ((clientWidth / 100 * 30) + scrollLeft);
			col = el.querySelectorAll('.con');
			for (var i = 0; i < col.length; i++) {
				col[i].style.left = Offset + "px";
			}
		}
		col = el.querySelectorAll('.box');
		for (var i = 0; i < col.length; i++) {
			col[i].style.width = Width + 'px';
		}
		prWidth = Width;
	}
	function conleft30() {
		col = document.querySelectorAll('.con');
		for (var i = 0; i < col.length; i++) {
			col[i].style.left = "30`%";
		}
	}
	function menuitemdisplay(param) {
		col = document.querySelectorAll('.menuitemid');
		for (var i = 0; i < col.length; i++) {
			col[i].style.display = param;
		}
	}
	function getname(el) {
		alert(el.className);
	}
	function removemenuitem(parent, selector) {
		col = parent.querySelectorAll(selector);
		for (var i = 0; i < col.length; i++) {
			parent.removeChild(col[i])
		}
	}
	function resizediv(el) {
		shift(el, 0);
	} 
	function scrolldiv(el) {
		if (WordWrap == 1)
			return 
		shift(el, 1);
	}
	function onmousedown(el) {  // строка 57  
		el.style.backgroundColor = "#%ColorSelButton%";
		ButtonOverColor = el.style.color; 
		el.style.color = "#%ColorBgOriginal%";
		el.style.border = "1px solid"; 
		el.style.borderColor = "#%ColorFont%";
	}
	function onmouseup(el, man) { 
		el.style.backgroundColor = "";
		// el.style.color = (el.name != "pre" ? "#%ColorFont%" : "#%ColorParam%");
		el.style.color = ButtonOverColor;
		if (!man && window.event.button == 2 && el.parentElement.className == 'BB')
			document.documentElement.focus();
	}
	function onmouseover(el) {   
		ButtonOverColor = el.style.color;
		el.style.zIndex = "2";
		el.style.border = "1px solid"; 
		el.style.borderColor = "#%ColorFont%"; 
		ButtonOver = el;
		return 0;
	}
	function onmouseout(el) {  
		el.style.zIndex = "0";
		el.style.backgroundColor = "";
		// el.style.color = (el.name != "pre" ? "#%ColorFont%" : "#%ColorParam%"); 
		el.style.color = ButtonOverColor; 
		el.style.border = "1px dotted";
		el.style.borderColor = "#%ColorFont%";
		ButtonOver = 0;
	} 
	function Assync (param) {
		setTimeout(param, 1);
	}
	function ElementName (param) {
		try {
			el = document.querySelector("[name=" + param + "]");
		} catch (e) {
			return
		}
		return el
	}
	function QS(el, param) {
		return el.querySelector(param); 
	}
	
	//	alert(value);
	//	tooltip(value);
	
</script> 

<script id='tooltipevent' type="text/javascript">
	function tooltip(text) {
		key1 = text;
		tooltipevent.click();
	}
</script>
) 
oDoc.Write("<!DOCTYPE html><head><meta http-equiv=""X-UA-Compatible"" content=""IE=8""></head>" html)
oDoc.Close() 
oDivWork1 := oDoc.getElementById("divwork1")
oDivWork2 := oDoc.getElementById("divwork2") 
 
ComObjConnect(ontooltip := oDoc.getElementById("tooltipevent"), "tooltip_") 
} 

	; ___________________________ Doc Events _________________________________________________

tooltip_onclick() {
	ToolTip(oJScript.key1, 500)
}

BodyExistCheck() { 
	If (oDivNew.innerHTML != "")
		return 
	LoadJScript()
	DivWorkIndex := 2
	oBody := oDoc.body 
	Write_%ThisMode%()  
} 


Class Events {  ;;	http://forum.script-coding.com/viewtopic.php?pid=82283#p82283
	onclick() {
		oevent := oDoc.parentWindow.event.srcElement
		If (oevent.className = "button" || oevent.tagname = "button")
			Return ButtonClick(oevent)
		If (ThisMode = "Hotkey" && !Hotkey_Arr("Hook") && !isPaused && oevent.tagname ~= "PRE|SPAN")
			Hotkey_Hook(1)
	}
	ondblclick() {
		Static wordchar := "(*UCP)[_²#\.\w]"
		oevent := oDoc.parentWindow.event.srcElement
		
		If (oevent.className = "button" || oevent.tagname = "button")
			Return ButtonClick(oevent)
			
		If (oevent.tagname != "input" && (rng := oDoc.selection.createRange()).text != "" && oevent.isContentEditable)
		{ 
			While len != StrLen(rng.text) { 
				len := StrLen(rng.text)
				(SubStr(rng.text, 0) ~= wordchar ? rng.moveEnd("character", 1) 
				: (rng.moveEnd("character", -1), len := StrLen(rng.text))) 
			} 
			While !b {
				rng.moveStart("character", -1) 
				(SubStr(rng.text, 1, 1) ~= wordchar ? 0
				: (rng.moveStart("character", 1), b := 1)) 
			}
			sel := rng.text, rng.moveEnd("character", StrLen(RTrim(sel)) - StrLen(sel)), rng.select()   
		}
		Else If (ThisMode != "Hotkey" && (oevent.className = "title" || oevent.className = "con" || oevent.className = "hr" || oevent.className = "box"))  ;;	anchor
		{
			R := oDoc.selection.createRange(), R.collapse(1), R.select()
			
			If oevent.className = "con"
				_text := oevent.firstChild.id, EL := oevent.parentElement.firstChild
			Else If oevent.className = "hr"
				_text := oevent.parentElement.childNodes[1].firstChild.id, EL := oevent
			Else If oevent.className = "box"
				_text := oevent.firstChild.childNodes[1].firstChild.id, EL := oevent.firstChild.firstChild
			Else If oevent.className = "title"
				_text := oevent.id, EL := oevent.parentElement.parentElement.firstChild
				
			If (_text = "P__Tree_Acc_Path" || _text = "")
				Return
				
			If oOther.anchor[ThisMode]
			{
				pEL := GetAnchor().parentElement.parentElement.firstChild
				pEL.style.background := "'none'"
				pEL.Id := ""
				
				If (_text = oOther.anchor[ThisMode "_text"])
				{
					If AnchorFullScroll 
						oJScript.QS(oDivNew, "#id_T0").style.height := 0
					If MemoryAnchor
						IniWrite("", ThisMode "_Anchor")
					Return oOther.anchor[ThisMode] := 0, oOther.anchor[ThisMode "_text"] := "" 
				}
			}
			
			oOther.anchor[ThisMode] := 1
			oOther.anchor[ThisMode "_text"] := _text
			EL.Id := "anchor"
			EL.style.backgroundColor := "#" ColorSelAnchor
			
			_AnchorFitScroll(EL)
			
			oDivNew.scrollTop := oDivNew.scrollTop + EL.getBoundingClientRect().top - 6
			
			If MemoryAnchor
				IniWrite(oOther.anchor[ThisMode "_text"], ThisMode "_Anchor") 
		}
	}
	onfocusin() { 
		If !(oDoc.parentWindow.event.srcElement.id = "editkeyname" || oDoc.parentWindow.event.srcElement.id = "edithotkey") 
			Return 
		oDoc.parentWindow.event.srcElement.style.border := "1px solid #" ColorBorderHoverInput
		Sleep(1), Hotkey_Hook(0) 
	} 
	onfocusout() {
		If !(oDoc.parentWindow.event.srcElement.id = "editkeyname" || oDoc.parentWindow.event.srcElement.id = "edithotkey") 
			Return
		oDoc.parentWindow.event.srcElement.style.border := "1px dotted"
		oDoc.parentWindow.event.srcElement.style.borderColor :=  "#" ColorFont
		
		If (WinActive("ahk_id" hGui) && !isPaused && ThisMode = "Hotkey")
			Sleep(1), Hotkey_Hook(1)
	}
	onmouseup() {   
		if (oDoc.parentWindow.event.srcElement.className != "button")
			return
		oJScript.onmouseup(oDoc.parentWindow.event.srcElement, 0)
    }
	onmousedown() {   
		if oDoc.parentWindow.event.button != 1		;   only left button https://msdn.microsoft.com/en-us/library/aa703876(v=vs.85).aspx
			return
		if (oDoc.parentWindow.event.srcElement.className != "button")
			return 
		oJScript.onmousedown(oDoc.parentWindow.event.srcElement)
    }
    onmouseover() {   
		if (oDoc.parentWindow.event.srcElement.className = "button")
			return oJScript.onmouseover(oDoc.parentWindow.event.srcElement) 
		If oMS.Selection
			Return
		oMS.EL := oDoc.parentWindow.event.srcElement
		SetTimer, MS_MouseOver, -50
    }
	onmouseout() {
		if (oDoc.parentWindow.event.srcElement.className = "button")
			return oJScript.onmouseout(oDoc.parentWindow.event.srcElement) 
		MS_Cancel()
    }
	onselectionchange() { 
		e := oDoc.parentWindow.event
		oMS.SCX := e.clientX, oMS.SCY := e.clientY
		SetTimer, MS_SelectionCheck, -70
		SetTimer, BodyExistCheck, -1000
    }
	onselectstart() {
		SetTimer, MS_Cancel, -8
    } 
	
	SendMode() {
		IniWrite(SendMode := {Send:"SendInput",SendInput:"SendPlay",SendPlay:"SendEvent",SendEvent:"Send"}[SendMode], "SendMode")
		SendModeStr := Format("{:L}", SendMode)
		oDoc.getElementById("SendMode").innerText := " " SendModeStr " "
		oDoc.getElementById("h_SendMode1").innerText := SendMode 
		oDoc.getElementById("h_SendMode2").innerText := SendMode 
	}
	SendCode() {
		IniWrite(SendCode := {vk:"sc",sc:"name",name:"vk"}[SendCode], "SendCode")
		oDoc.getElementById("SendCode").innerText := " " SendCode " " 
		Write_HotkeyHTML(oOther.HotkeyK, 0, 1)
	}
	LButton_Hotkey() {
		If Hotkey_Arr("Hook")
			Hotkey_Main("LButton")
	}
	num_scroll(thisid) {
		(OnHook := Hotkey_Arr("Hook")) ? Hotkey_Hook(0) : 0
		SendInput, {%thisid%}
		(OnHook ? Hotkey_Hook(1) : 0)
		ToolTip(thisid " " (GetKeyState(thisid, "T") ? "On" : "Off"), 500)
	}
	NextChangeLocal() {
		(OnHook := Hotkey_Arr("Hook")) ? Hotkey_Hook(0) : 0
		ChangeLocal(hActiveX)
		ToolTip(GetLangName(hActiveX), 500)
		(OnHook ? Hotkey_Hook(1) : 0)
	}
	clean_command_line() { 
		cl := oDoc.getElementById("c_command_line").OuterText
		StringReplace, cl, cl, ", , 1 
		process := oDoc.getElementById("copy_processpath").OuterText
		cl := RegExReplace(cl, "i)\Q" process "\E(.*)", "$1", , 1)
		StringReplace, cl, cl, /CP65001, , 1  
		cl := Trim(cl, " ")
		oDoc.getElementById("c_command_line").innerText :=  RegExReplace(cl, "i)\Q" process "\E(.*)", "$1", , 1)
	}
}

ButtonClick(oevent) { 
	thisid := oevent.id
	If (thisid = "copy_wintext")
		o := oDoc.getElementById("wintextcon")
		, GetKeyState("Shift") ? ClipAdd(o.OuterText, 1) : (Clipboard := o.OuterText), HighLight([o])
	Else If (thisid = "wintext_hidden")
	{
		R := oBody.createTextRange(), R.collapse(1), R.select()
		oDoc.getElementById("wintextcon").disabled := 1
		DetectHiddenText, % DetectHiddenText := (DetectHiddenText = "on" ? "off" : "on")
		IniWrite(DetectHiddenText, "DetectHiddenText")
		If !WinExist("ahk_id" oOther.WinID) && ToolTip("Window not exist", 500)
			Return oDoc.getElementById("wintext_hidden").innerText := " hidden - " DetectHiddenText " "
		WinGetText, WinText, % "ahk_id" oOther.WinID
		oDoc.getElementById("wintextcon").innerHTML := "<pre>" TransformHTML(WinText) "</pre>"
		HTML_Win := oDivNew.innerHTML
		Sleep 200
		oDoc.getElementById("wintextcon").disabled := 0
		oDoc.getElementById("wintext_hidden").innerText := " hidden - " DetectHiddenText " "
	}
	Else If (thisid = "menu_idview")
	{
		IniWrite(MenuIdView := !MenuIdView, "MenuIdView")
		oJScript.menuitemdisplay(!MenuIdView ? "none" : "inline")
		oDoc.getElementById("menu_idview").innerText :=  " id - " (MenuIdView ? "view" : "hide") " "
	}
	Else If (thisid = "copy__PRE1")
	{
		item := oDoc.getElementById(oevent.name)
		preclone := item.cloneNode(true)
		oJScript.removemenuitem(preclone, ".menuitemsub")
		If !MenuIdView
			oJScript.removemenuitem(preclone, ".menuitemid")  
		OuterText := RegExReplace(preclone.OuterText, "m)  ▪   flash   ▪  ")
		OuterText := RegExReplace(OuterText, "m)\s+$") 
		GetKeyState("Shift") ? ClipAdd(OuterText, 1) : (Clipboard := OuterText)
		HighLight([item]), preclone := ""
	}  
	Else If (thisid = "Control_Child_roll")
	{
		view_control_child := 0, IniWrite(view_control_child, "view_control_child") 
		oDoc.getElementById("control_child_value").innerHTML := ""
		HTML_Control := oDivNew.innerHTML
	}
	Else If (thisid = "ControlCountList_roll")
	{ 
		oDoc.getElementById("view_ControlCount_value").innerHTML := ""
		HTML_Win := oDivNew.innerHTML
	} 
	Else If (thisid = "WindowCountList_roll")
	{ 
		oDoc.getElementById("view_WindowCount_value").innerHTML := ""
		HTML_Win := oDivNew.innerHTML
	} 
	Else If (thisid = "copy_menutext")
	{
		pre_menutext := oDoc.getElementById("pre_menutext")
		preclone := pre_menutext.cloneNode(true)
		oJScript.removemenuitem(preclone, ".menuitemsub")
		If !MenuIdView
			oJScript.removemenuitem(preclone, ".menuitemid")
		GetKeyState("Shift") ? ClipAdd(preclone.OuterText, 1) : (Clipboard := preclone.OuterText)
		HighLight([pre_menutext]), preclone := ""
	}
	Else If (thisid = "copy_button")
	{
		o := oDoc.all.item(oevent.sourceIndex + 2) 
		GetKeyState("Shift") ? ClipAdd(o.OuterText, 1) : (Clipboard := o.OuterText), HighLight([o])
	}
	Else If (thisid = "copy_button_CtrlText")
	{
		o := oDoc.all.item(oevent.sourceIndex + 6) 
		GetKeyState("Shift") ? ClipAdd(o.OuterText, 1) : (Clipboard := o.OuterText), HighLight([o])
	}  
	Else If (thisid = "copy_button_Value_Acc")
	{
		o := oDoc.getElementById("get_accvalue")
		GetKeyState("Shift") ? ClipAdd(o.OuterText, 1) : (Clipboard := o.OuterText), HighLight([o])
	}  
	Else If (thisid = "settext_button")
		ControlSetText, , % oDoc.getElementById("content_Control_Text").OuterText, % "ahk_id" oevent.value 
	Else If thisid = copy_alltitle
	{
		HighLight([oDoc.getElementById("wintitle1")
			, oDoc.getElementById("wintitle2")
			, oDoc.getElementById("wintitle3")])  
		Text := (t:=oDoc.getElementById("wintitle1").OuterText) . (t = "" ? "" : " ")
		. oDoc.getElementById("wintitle2").OuterText " " oDoc.getElementById("wintitle3").OuterText
		GetKeyState("Shift") ? ClipAdd(Text, 1) : (Clipboard := Text)
	}
	Else If thisid = copy_sbtext
	{
		elements := []
		Loop % oDoc.getElementById("copy_sbtext").name
			el := oDoc.getElementById("sb_field_" A_Index), elements.Push(el), Text .= el.OuterText "`r`n"
		HighLight(elements)
		Text := RTrim(Text, "`r`n"), GetKeyState("Shift") ? ClipAdd(Text, 1) : (Clipboard := Text)
	}
	Else If thisid = keyname
	{ 
		edithotkey := oDoc.getElementById("edithotkey"), editkeyname := oDoc.getElementById("editkeyname")
		value := edithotkey.value   
		
		If (value = "    " || value = A_Tab)
			value := A_Tab
		Else If (value != " ")
			value := RegExReplace(value, "^\s*(.*?)\s*$", "$1")		
		
		If RegExMatch(value, "i)^[0x]*([0-9a-f]+)$", M)
			key := ((SendCode = "name" || SendCode = "vk") ? "vk" : "sc") . Format("{:U}", M1)
		Else
			key := value  
		oDoc.getElementById("edithotkey").value := key  
		name := GetKeyName(key)
		If (name = key)
			editkeyname.value := Format("vk{:X}", GetKeyVK(key)) (!(sc := GetKeySC(key)) ? "" : Format("sc{:X}", sc))
		Else
			editkeyname.value := (StrLen(name) = 1 ? (Format("{:U}", name)) : name)
			
		o := name = "" ? edithotkey : editkeyname
		o.focus(), o.createTextRange().select()
		oDoc.getElementById("vkname").innerHTML := GetVKCodeNameStr := GetVKCodeName(key)
		oDoc.getElementById("scname").innerHTML := GetSCCodeNameStr := GetScanCode(key)
		HTML_Hotkey := oDivNew.innerHTML 
	}
	Else If thisid = hook_reload
	{
		Suspend On
		Suspend Off
		bool := Hotkey_Arr("Hook"), Hotkey_SetHook(0), Hotkey_SetHook(1), Hotkey_Arr("Hook", bool), ToolTip("Ok", 300)
	}
	Else If thisid = hotkey_clip_cursor
		Hotkey_ClipCursor()
	Else If thisid = pause_button
		Gosub, PausedScript
	Else If (thisid = "infolder" || thisid = "command_line_infolder")
	{	
		If (thisid = "command_line_infolder")
			FilePath := oDoc.getElementById("c_command_line").OuterText
		Else 
			FilePath := oDoc.getElementById("copy_processpath").OuterText

		SelectFilePath(FilePath) ? Minimize() : ToolTip("File not exist", 500)		 
	}
	Else If (thisid = "flash_window" || thisid = "flash_control" || thisid = "flash_ctrl_window")
	{
		hwnd := thisid = "flash_window" ? oOther.WinID : thisid = "flash_ctrl_window" ? oOther.MouseWinID : oOther.ControlID

		If !WinExist("ahk_id" hwnd)
			Return ToolTip("Window not exist", 500)
		WinGetPos, WinX, WinY, WinWidth, WinHeight, % "ahk_id" hwnd
		FlashArea(WinX, WinY, WinWidth, WinHeight)
	}
	Else If (thisid = "flash_acc")
	{
		If oPubObj.Acc.CLOAKED
			Return 0, ToolTip("CLOAKED", 500)
		Acc := Object(oPubObj.Acc.AccObj)
		AccGetLocation(Acc, oPubObj.Acc.child)
		FlashArea(AccCoord[1], AccCoord[2], AccCoord[3], AccCoord[4])
	}
	Else If (thisid = "flash_IE")
	{
		If !WinExist("ahk_id" oPubObj.IEElement.hwnd)
			Return ToolTip("Parent window not exist", 500)
		FlashArea(oPubObj.IEElement.Pos[1], oPubObj.IEElement.Pos[2], oPubObj.IEElement.Pos[3], oPubObj.IEElement.Pos[4])
	}
	Else If thisid = paste_process_path
		oDoc.getElementById("copy_processpath").innerHTML := TransformHTML(Trim(Trim(Clipboard), """"))
	Else If thisid = w_command_line
		RunRealPath(oDoc.getElementById("c_command_line").OuterText)
	Else If thisid = clean_command_line
		Events.clean_command_line()
	Else If thisid = paste_command_line
		oDoc.getElementById("c_command_line").innerHTML := TransformHTML(Clipboard)
	Else If thisid = paste_Control_Text
		oDoc.getElementById("content_Control_Text").innerText := Clipboard
	Else If (thisid = "process_close" && (oOther.WinPID || !ToolTip("Invalid parametrs", 500)) && ConfirmAction("Process close?"))
		Process, Close, % oOther.WinPID
	Else If (thisid = "win_close" && (oOther.WinPID || !ToolTip("Invalid parametrs", 500)) && ConfirmAction("Window close?"))
		WinClose, % "ahk_id" oOther.WinID
	Else If (thisid = "control_destroy" && (WinExist("ahk_id" oOther.ControlID) || !ToolTip("window not exist", 500)) && ConfirmAction("Window close?"))
			WinClose, % "ahk_id" oOther.ControlID     ;; DllCall("DestroyWindow", "Ptr", oOther.ControlID)   ;;  не работает
	Else If (thisid = "control_show_hide" || thisid = "window_show_hide")
	{
		Hwnd := thisid = "window_show_hide" ? oOther.WinID : oOther.ControlID
		If !WinExist("ahk_id" Hwnd)  
			Return ToolTip("window not exist", 500)
		If b := DllCall("IsWindowVisible", "UPtr", Hwnd) 
			WinHide, % "ahk_id" Hwnd
		Else 
			WinShow, % "ahk_id" Hwnd
		ToolTip(b ? "Hide" : "Show" , 500)
	}
	Else If (thisid = "___WStyleChange") {
		caption := oDoc.all.item(oevent.parentElement.parentElement.sourceIndex - 3).id 
		style := oDoc.all.item(oevent.sourceIndex + 2).OuterText   
		 ; 0x2716 ✖ ; 0x2714 ✔
		add := (oevent.OuterText = Chr(0x2716)) 
		color := (add ? ColorParam : ColorStyleNoApply) 
		If (ThisMode = "Win")
		{ 
			hwnd := oOther.WinID			
			If (!WinExist("ahk_id" hwnd))
				Return ToolTip("Window not exist", 500)
			If 1
			{  
				If (caption = "__Styles_Win") 
					WinSet, Style, % (add ? "+" : "-") style, % "ahk_id" hwnd
				Else If (caption = "__ExStyles_Win") 
					WinSet, ExStyle, % (add ? "+" : "-") style, % "ahk_id" hwnd
				If (style = 0x00000008) 
					WinSet, AlwaysOnTop, % (add ? "On" : "Off"), % "ahk_id" hwnd
				
				Else If (caption = "__ClassStyles_Win") 
				{
					; StyleBits := DllCall("GetClassLong", "UPtr", hWnd, "int", -26) ; GCL_STYLE
					; ToolTip % (StyleBits & style) 
					If add
						DllCall("SetClassLong", "UPtr", hWnd, "int", -26
						, "int", DllCall("GetClassLong", "UPtr", hWnd, "int", -26) | style)
					Else 
						DllCall("SetClassLong", "UPtr", hWnd, "int", -26
						, "int", DllCall("GetClassLong", "UPtr", hWnd, "int", -26) ^ style) 
				}
				oDoc.all.item(oevent.sourceIndex - 0).style.color := color
				oJScript.ButtonOverColor := "#" color 
				oevent.innerText := (add ? Chr(0x2714) : Chr(0x2716))  
				oDoc.all.item(oevent.sourceIndex  + 1).className := (add ? "" : "QStyle4")  
				
				Sleep 200
				
				ViewStylesWin(1)  
				; WinGet, WinStyle, Style, % "ahk_id" oOther.WinID
				; WinGet, WinExStyle, ExStyle, % "ahk_id" oOther.WinID
				
				; If (WinStyle WinExStyle = "")
					; Return ToolTip("Window not exist", 500)
				; oDoc.getElementById("w_Style").innerText := WinStyle
				; oDoc.getElementById("w_ExStyle").innerText := WinExStyle 

				; Styles := "<a></a>" GetStyles(oOther.WinClass
					; , oDoc.getElementById("w_Style").innerText
					; , oDoc.getElementById("w_ExStyle").innerText
					; , oOther.WinID)

				; oDoc.getElementById("WinStyles").innerHTML := Styles
				; HTML_Win := oDivNew.innerHTML 
			}  
		} 
		Else 
		{
			hwnd := oOther.ControlID	
			If (!WinExist("ahk_id" hwnd))
				Return ToolTip("Window not exist", 500)
			If caption = 
				caption := oDoc.all.item(oevent.parentElement.parentElement.sourceIndex - 4).id  
			If 1
			{ 
				If (caption = "__Styles_Win") 
					WinSet, Style, % (add ? "+" : "-") style, % "ahk_id" hwnd
				Else If (caption = "__ExStyles_Win") 
					WinSet, ExStyle, % (add ? "+" : "-") style, % "ahk_id" hwnd
				Else If (caption = "__Styles_Control")  
					Control, Style, % (add ? "+" : "-") style, , % "ahk_id" hwnd
				Else If (caption = "__ExStyles_Control") 
					Control, ExStyle, % (add ? "+" : "-") style, , % "ahk_id" hwnd 
				Else If (caption = "__ClassStyles_Win") 
				{ 
					If add
						DllCall("SetClassLong", "UPtr", hWnd, "int", -26
						, "int", DllCall("GetClassLong", "UPtr", hWnd, "int", -26) | style)
					Else 
						DllCall("SetClassLong", "UPtr", hWnd, "int", -26
						, "int", DllCall("GetClassLong", "UPtr", hWnd, "int", -26) ^ style) 
				}
				oDoc.all.item(oevent.sourceIndex - 0).style.color := color
				oJScript.ButtonOverColor := "#" color 
				oevent.innerText := (add ? Chr(0x2714) : Chr(0x2716))  
				oDoc.all.item(oevent.sourceIndex  + 1).className := (add ? "" : "QStyle4")   
				
				Sleep 200
				ViewStylesControl(1)
				; ControlGet, CtrlStyle, Style,,, % "ahk_id" oOther.ControlID
				; ControlGet, CtrlExStyle, ExStyle,,, % "ahk_id" oOther.ControlID
				
				; If (CtrlStyle CtrlExStyle = "")
					; Return ToolTip("Window not exist", 500)
				; oDoc.getElementById("c_Style").innerText := CtrlStyle
				; oDoc.getElementById("c_ExStyle").innerText := CtrlExStyle
		
				; Styles := "<a></a>" GetStyles(oOther.CtrlClass
					; , CtrlStyle
					; , CtrlExStyle
					; , oOther.ControlID)
				; oDoc.getElementById("ControlStyles").innerHTML := Styles
				; HTML_Control := oDivNew.innerHTML 
			}
		}
	}
	Else If (thisid = "window_minimize" && (WinExist("ahk_id" oOther.WinID) || !ToolTip("window not exist", 500))) 
		WinMinimize, % "ahk_id" oOther.WinID
	Else If (thisid = "window_restore" && (WinExist("ahk_id" oOther.WinID) || !ToolTip("window not exist", 500)))   
		WinRestore, % "ahk_id" oOther.WinID 
	Else If (thisid = "SendCode")
		Events.SendCode()
	Else If (thisid = "SendMode")
		Events.SendMode()
	Else If (thisid = "LButton_Hotkey")
		Events.LButton_Hotkey()
	Else If (thisid = "numlock" || thisid = "scrolllock")
		Events.num_scroll(thisid)
	Else If thisid = locale_change
		Events.NextChangeLocal()
	Else If thisid = paste_keyname 
	{ 
		If (StrLen(Clipboard) > 40)
			Return ToolTip("Long string", 500)  
		edithotkey := oDoc.getElementById("edithotkey"), edithotkey.value := "", edithotkey.focus()
		oDoc.execCommand("Paste"), oDoc.getElementById("keyname").click() 
	}
	Else If thisid = get_styles_w
		ViewStylesWin()
	Else If thisid = update_styles_w
		ViewStylesWin(1) 
	Else If thisid = get_styles_c
		ViewStylesControl()
	Else If thisid = update_styles_c
		ViewStylesControl(1) 
	Else If thisid = run_AccViewer
		RunAhkPath(ExtraFile("AccViewer Source"), oPubObjGUID)
	Else If thisid = run_iWB2Learner
		RunAhkPath(ExtraFile("iWB2 Learner"))
	Else If (thisid = "run_Window_Detective" && ConfirmAction("Run Window Detective?"))
	{
		Minimize()
		If WinExist("Window Detective ahk_class Qt5QWindowIcon ahk_exe Window Detective.exe")
			WinActivate
		Else
			Run % Path_User "\Window Detective.lnk"
		TimerFunc(Func("MyWindowDetectiveStart").Bind(ThisMode = "Win" ? oOther.WinID : oOther.ControlID, WinExist() ? 1 : 0), -300)
	}
	Else If (thisid = "set_button_Transparent" && ToolTip((v := oDoc.getElementById("get_win_Transparent").innerText), 500)) 
		WinSet, Transparent, % v, % "ahk_id" oOther.WinID
	Else If (thisid = "set_button_TransColor" && ToolTip((v := oDoc.getElementById("get_win_TransColor").innerText), 500))  
		WinSet, TransColor, % oDoc.getElementById("get_win_TransColor").innerText, % "ahk_id" oOther.WinID
	Else If thisid = set_button_pos
	{
		HayStack := oevent.OuterText = "Pos:"
		? oDoc.all.item(oevent.sourceIndex + 1).OuterText " " oDoc.all.item(oevent.sourceIndex + 7).OuterText
		: oDoc.all.item(oevent.sourceIndex - 5).OuterText " " oDoc.all.item(oevent.sourceIndex + 1).OuterText
		RegExMatch(HayStack, "(-*\d+[\.\d+]*).*\s+.*?(-*\d+[\.\d+]*).*\s+.*?(-*\d+[\.\d+]*).*\s+.*?(-*\d+[\.\d+]*)", p)
		If (p1 + 0 = "" || p2 + 0 = "" || p3 + 0 = "" || p4 + 0 = "")
			Return ToolTip("Invalid parametrs", 500)
		If (ThisMode = "Win")
			WinMove, % "ahk_id " oOther.WinID, , p1, p2, p3, p4
		Else
			ControlMove, , p1, p2, p3, p4, % "ahk_id " oOther.ControlID
	}
	Else If thisid = control_click
	{
		KeyWait, Shift
		KeyWait, LButton
		Sleep 10 
		ControlClick, % oDoc.getElementById("coord_win").innerText, % "ahk_id" oOther.MouseWinID, , , , Pos
	}
	Else If thisid = set_button_focus_ctrl
	{ 
		WinActivate, % "ahk_id " oOther.WinID
		hWnd := oOther.ControlID 
		ControlFocus, , ahk_id %hWnd%
		WinGetPos, X, Y, W, H, ahk_id %hWnd%
		FlashArea(x, y, w, h)
		If GetKeyState("Shift") && (X + Y != "") 
			MouseMoveScreen(X + W // 2, Y + H // 2)
	}
	Else If thisid = set_pos
	{ 
		thisbutton := oevent.OuterText
		If thisbutton != 屏幕:
		{
			hWnd := oOther.MouseWinID
			If !WinExist("ahk_id " hwnd)
				Return ToolTip("Window not exist", 500)
			WinGet, Min, MinMax, % "ahk_id " hwnd
			If Min = -1
				Return ToolTip("Window minimize", 500)
			WinGetPos, X, Y, W, H, ahk_id %hWnd%
		}
		If thisbutton = 窗口比例:
		{
			RegExMatch(oDoc.all.item(oevent.sourceIndex + 1).OuterText, "(-*\d+[\.\d+]*).*\s+.*?(-*\d+[\.\d+]*)", p)
			If (p1 + 0 = "" || p2 + 0 = "")
				Return ToolTip("Invalid parametrs", 500)
			BlockInput, MouseMove  
			MouseMoveScreen(X + Round(W * p1), Y + Round(H * p2))
		}
		Else If thisbutton = 客户端比例:
		{
			RegExMatch(oDoc.all.item(oevent.sourceIndex + 1).OuterText, "(-*\d+[\.\d+]*).*\s+.*?(-*\d+[\.\d+]*)", p)
			If (p1 + 0 = "" || p2 + 0 = "")
				Return ToolTip("Invalid parametrs", 500)
			GetClientPos(hWnd, caX, caY, caW, caH) 
			MouseMoveScreen(X + Round(caW * p1) + caX, Y + Round(caH * p2) + caY)
		}
		Else
		{
			RegExMatch(oDoc.all.item(oevent.sourceIndex + 1).OuterText, "(-*\d+[\.\d+]*).*\s+.*?(-*\d+[\.\d+]*)", p)
			If (p1 + 0 = "" || p2 + 0 = "")
				Return ToolTip("Invalid parametrs", 500)
			BlockInput, MouseMove
			If thisbutton = 屏幕:  
				MouseMoveScreen(p1, p2)
			Else If thisbutton = 窗口:  
				MouseMoveScreen(X + p1, Y + p2)
			Else If thisbutton = 鼠标相对控件:
			{
				hWnd := oOther.ControlID
				If !WinExist("ahk_id " hwnd)
					Return ToolTip("Control not exist", 500)
				WinGetPos, X, Y, W, H, ahk_id %hWnd%  
				MouseMoveScreen(X + p1, Y + p2)
			}
			Else If thisbutton = 客户端:
			{
				GetClientPos(hWnd, caX, caY, caW, caH)  
				MouseMoveScreen(X + p1 + caX, Y + p2 + caY) 
			}
		}
		If isPaused
		{
			BlockInput, MouseMoveOff
			Return
		}
		If Shift := GetKeyState("Shift")
			ActivateUnderMouse() 
		GoSub, SpotProc2
		BlockInput, MouseMoveOff
		If !Shift
			Sleep(500), HideAllMarkers(), CheckHideMarker()
	} 
	Else If thisid = b_DecimalCode
	{
		oDoc.getElementById("b_DecimalCode").innerText := (DecimalCode := !DecimalCode) ? " dec " : " hex "
		str := oDoc.getElementById("v_SCDHCode").innerText
		oDoc.getElementById("v_SCDHCode").innerText := (DecimalCode) ? Format("{:d}", str) : Format("0x{:X}", str)
		str := oDoc.getElementById("v_VKDHCode").innerText
		oDoc.getElementById("v_VKDHCode").innerText := (DecimalCode) ? Format("{:d}", str) : Format("0x{:X}", str)
	}
	Else If (thisid = "set_accvalue")
		accset_accvalue()  
	Else If (thisid = "acc_DoDefaultAction" || thisid = "acc_DoDefaultAction2")
		accDoDefaultAction()   
	Else If thisid = b_hwnd_flash
	{ 
		WinGetPos, X, Y, W, H, % "ahk_id" oevent.value
		FlashArea(x, y, w, h)
	} 
	Else If thisid = b_open_win
	{ 
		LocalOpenWin(oevent.value) 
	}
	Else If thisid = b_open_win_ctrl
	{ 
		o := StrSplit(oevent.value, "|")
		LocalOpenWinChild(o[1], o[2]) 
	}
	Else If thisid = b_open_ctrl
	{  
		o := StrSplit(oevent.value, "|")
		LocalOpenChild(o[1], o[2]) 
	} 
	Else If thisid = b_back_openchild
	{  
		LocalBackChild()
	} 
	Else If thisid = b_back_openwin
	{  
		LocalBackWin()
	}   
	Else If thisid = acc_path 
		acc_path_func(1)
	Else If thisid = control_path 
		control_path_func()
	Else If thisid = control_totree 
		control_totree() 
	Else If (thisid = "control_child" || thisid = "control_child2")
		control_child_func() 
	Else If (thisid = "view_WindowCount" || thisid = "view_WindowCount2")
		Window_Count_func() 
	Else If (thisid = "view_ControlCount" || thisid = "view_ControlCount2")
		Window_ControlCount_func() 
	Else If thisid = b_CASend
	{  
		h := (oOther.ControlID ? oOther.ControlID 
			: oOther.MouseWinID ? oOther.MouseWinID 
			: oOther.WinID ? oOther.WinID : 0)
		If !WinExist("ahk_id " h)
			Return ToolTip("Window not found!", 500) 
		KeyWait Shift  
		KeyWait LButton
		Sleep 300
		SetKeyDelay 50, 50
		ControlSend, , % oOther.ControlSend, ahk_id %h%
		
		ToolTip("send to " 
		. (oOther.ControlID ? "control: " oOther.ControlNN  
		: oOther.MouseWinID ? "window: " oOther.MouseWinClass
		: oOther.WinID ? "window: " oOther.WinClass) "`n" oOther.ControlSend, 700)
	} 
	Else If thisid = b_ASend
	{   
		a := WinActive("ahk_id" hGui)
		If !a
			h := WinActive("A")
		Else 
			h := (oOther.ControlID ? oOther.ControlID 
				: oOther.MouseWinID ? oOther.MouseWinID 
				: oOther.WinID ? oOther.WinID : 0) 
		KeyWait Shift  
		KeyWait LButton 
		Sleep 300
		If a
		{
			If oOther.ControlID
				WinActivate, % "ahk_id" DllCall("GetAncestor", "UPtr", oOther.WinID, Uint, 1) 
			WinShow, ahk_id %h% 
			ControlFocus, , ahk_id %h%
			Sleep 300
		}	
		WinActivate, ahk_id %h%
		Sleep 400
		If (SendMode = "Send")
			Send % oOther.ControlSend
		Else If (SendMode = "SendEvent")
			SendEvent % oOther.ControlSend
		Else If (SendMode = "SendPlay") 
			SendPlay % oOther.ControlSend
		Else If (SendMode = "SendInput")
			SendInput % oOther.ControlSend  
		WinGetClass, WinClass, ahk_id %h%
		ToolTip(WinClass "`n" SendMode " " oOther.ControlSend, 750) 
	}  
	Else If InStr(thisid, "ahkscript_")
	{
		ToolTip("Ok", 300)
		ahkscriptpath := oDoc.getElementById("ahkscriptpath").innerText 
		If !FileExist(ahkscriptpath)
			Return ToolTip("File not exist!", 500)
		If (thisid = "ahkscript_folder")
			SelectFilePath(ahkscriptpath) ? Minimize() : ToolTip("Invalide path", 500)
		Else If (thisid = "ahkscript_copypath")
			FileToClipboard(ahkscriptpath) 
		Else If (thisid = "ahkscript_run")
			RunRealPath(ahkscriptpath) 
		Else If (thisid = "ahkscript_edit")
			RunRealPath("*Edit " ahkscriptpath)
		Else 
		{ 
			If !WinExist("ahk_class AutoHotkey ahk_pid" . oOther.WinPID)	  
				Return ToolTip("Script not found!", 500)
			If (thisid = "ahkscript_suspend")
				ExecCommandAutoHotkey("Suspend Hotkeys", oOther.WinPID)
			Else If (thisid = "ahkscript_pause")
				ExecCommandAutoHotkey("Pause Script", oOther.WinPID)
			Else If (thisid = "ahkscript_reload")
				ExecCommandAutoHotkey("Reload Script", oOther.WinPID)
			Else If (thisid = "ahkscript_exit")
				ExecCommandAutoHotkey("Exit Script", oOther.WinPID)
			Else If (thisid = "ahkscript_lines")
				ExecCommandAutoHotkey("Recent Lines", oOther.WinPID)
			Else If (thisid = "ahkscript_variables")
				ExecCommandAutoHotkey("Variables", oOther.WinPID)
			Else If (thisid = "ahkscript_hotkeys")
				ExecCommandAutoHotkey("Hotkeys", oOther.WinPID)
			Else If (thisid = "ahkscript_keyhistory")
				ExecCommandAutoHotkey("Key history", oOther.WinPID)
			Else If (thisid = "ahkscript_edit")
				ExecCommandAutoHotkey("Edit Script", oOther.WinPID) 
		}
	}  
}

control_totree() {
	If !WinExist("ahk_id" oOther.MouseWinID)
		Return ToolTip("Window not found", 800)
	
	If (oOther.WinID != oOther.MouseWinID) 
	{
		gLocalData := {}
		gLocalData.Win := oOther.MouseWinID 
		gLocalData.Child := oOther.ControlID 
		Spot_Win() 
		Write_Win()
		gLocalData := ""   
	} 
	Gosub Mode_Win

	r := Window_ControlCountList(oOther.MouseWinID, oOther.ControlID) 
	If r = -2
		Return ToolTip("Window not children", 800)
	oDoc.getElementById("view_ControlCount_value").innerHTML := oOther.ControlCountList
	HTML_Win := oDivNew.innerHTML
	oDivNew.scrollTop := oDivNew.scrollTop + oDoc.getElementById("a_find_anch").getBoundingClientRect().top - 6	 
	; HighLight([oDoc.all.item(oDoc.getElementById("a_find_anch").sourceIndex + 4)], 1000)
	HighLight([oDoc.getElementById("a_find_anch").firstChild.parentElement], 1000) 
}

control_path_func() {
	If !ChildToPath(oOther.ControlID)
		oDoc.getElementById("control_path_error").outerHTML := "<span style='color:#" ColorErrorAccPath "'>  control not found</span>" 
	oDoc.getElementById("control_path_value").innerHTML := SaveChildPath()
	HTML_Control := oDivNew.innerHTML
}

Window_Count_func() { 
	r := Window_CountList(oOther.WinPID)
	If r = -1
		Return ToolTip("Process not found", 800)
	If r = -2
		Return ToolTip("Process not window", 800)
	oDoc.getElementById("view_WindowCount_value").innerHTML := oOther.WindowCountList
	HTML_Win := oDivNew.innerHTML
}

Window_ControlCount_func() {  
	r := Window_ControlCountList(oOther.WinID)
	If r = -1
		Return ToolTip("Window not found", 800)
	If r = -2
		Return ToolTip("Window not children", 800)
	oDoc.getElementById("view_ControlCount_value").innerHTML := oOther.ControlCountList
	HTML_Win := oDivNew.innerHTML
}

control_child_func() {
	If !view_control_child
		view_control_child := 1, IniWrite(view_control_child, "view_control_child") 
	r := ChildList(oOther.ControlID)
	If r = -1
		Return ToolTip("control not found", 800)
	If r = -2
		Return ToolTip("control not children", 800)
	oDoc.getElementById("control_child_value").innerHTML := oOther.ChildList
	HTML_Control := oDivNew.innerHTML
}

acc_path_func(manual) {
	;; If (manual && oOther.anchor[ThisMode "_text"] = "P__Tree_Acc_Path")
		;; MsgBox %  oDoc.getElementById("P__Tree_Acc_Path").innerHTML
	If !Malcev_AccPathNotBlink && manual
	{
		oDoc.getElementById("acc_path").disabled := 1
		, oDoc.getElementById("acc_path_value").disabled := 1 
		w := oDoc.getElementById("acc_path").offsetWidth
		marquee = 
		( 
			<marquee behavior='scroll' direction='right' bgcolor='#" ColorErrorAccMarquee "' width="%w%px"> • • • 
			</marquee>
		)
		oDoc.getElementById("acc_path").innerHTML := marquee   
	}
	b := GetAccPath() 
	If !manual
		Return b
	If b
	{ 
		oDoc.getElementById("acc_path_error").innerHTML := ""
		oDoc.getElementById("acc_path_value").innerHTML := SaveAccPath() 
	}
	If !b
	{
		oDoc.getElementById("acc_path_error").innerHTML := "<span style='color:#" ColorErrorAccPath "'>  "
			. (oPubObj.Acc.CLOAKED ? "CLOAKED" : (b = 0 ? "path not found" : "path not correct"))  "  </span>" 
		oDoc.getElementById("acc_path_value").innerHTML := ""
	}
	Else 
		oDoc.getElementById("acc_path_value").disabled := 0
	
	oDoc.getElementById("acc_path").innerHTML := ""
	oDoc.getElementById("acc_path").innerText := " 获取路径 "
	oDoc.getElementById("acc_path").disabled := 0
	HTML_Control := oDivNew.innerHTML
}

	; ___________________________ SingleInstance _________________________________________________

SingleInstance(Icon = 0) {
	#NoTrayIcon
	#SingleInstance Off
	DetectHiddenWindows, On
	WinGetTitle, MyTitle, ahk_id %A_ScriptHWND%
	WinGet, id, List, %MyTitle% ahk_class AutoHotkey
	Loop, %id%
	{
		this_id := id%A_Index%
		If (this_id != A_ScriptHWND)
			WinClose, ahk_id %this_id%
	}
	Loop, %id%
	{
		this_id := id%A_Index%
		If (this_id != A_ScriptHWND)
		{
			Start := A_TickCount
			While WinExist("ahk_id" this_id)
			{
				If (A_TickCount - Start > 1500)
				{
					MsgBox, 8196, , Could not close the previous instance of this script.  Keep waiting?
					IfMsgBox, Yes
					{
						WinClose, ahk_id %this_id%
						Sleep 200
						WinGet, WinPID, PID, ahk_id %this_id%
						Process, Close, %WinPID%
						Start := A_TickCount + 200
						Continue
					}
					OnExit
					ExitApp
				}
				Sleep 1
			}
		}
	}
	If Icon
		Menu, Tray, Icon
}

	; __________________________________________________________________________________
	; ___________________________ Zoom _________________________________________________
	; __________________________________________________________________________________

ShowZoom:
hAhkSpy = %2%
If !WinExist("ahk_id" hAhkSpy)
	ExitApp
ActiveNoPause = %3%
AhkSpyPause = %4%
Suspend = %5%
Hotkey = %6%
OnlyShiftTab = %7%
GUID = %8%
HeigtButton = %9%

ListLines Off
SetBatchLines,-1
DetectHiddenWindows On
CoordMode, Mouse, Screen
CoordMode, ToolTip, Screen

Global ObjActive := ComObjActive(GUID), oZoom := {}, isZoom := 1, hAhkSpy, oMenu := {}, oOther := {}
, MsgAhkSpyZoom, ActiveNoPause, SpyActive, GuiColor, TextColor, GuiColorDisp, HeigtButton
If IniRead("DarkTheme", 0)
	GuiColor := "0A0A0A", TextColor := "F5F5F5", GuiColorDisp := "263FA4"
Else 
	GuiColor := "F5F5F5", TextColor := "0A0A0A", GuiColorDisp := "FFE891"
If !oZoom.pToken := GdipStartup()
{
	MsgBox, 4112, Gdiplus Error, Gdiplus failed to start. Please ensure you have Gdiplus on your system.
	ExitApp
}
Z_MsgZoom(8, Suspend)
Z_MsgZoom(2, AhkSpyPause)
Z_MsgZoom(6, ActiveNoPause)
Z_MsgZoom(7, !!WinActive("ahk_id" hAhkSpy))
Z_MsgZoom(10, Hotkey)
Z_MsgZoom(12, OnlyShiftTab)

oZoom.CurrentProcessId := DllCall("GetCurrentProcessId")
OnMessage(MsgAhkSpyZoom := DllCall("RegisterWindowMessage", "Str", "MsgAhkSpyZoom"), "Z_MsgZoom")
OnMessage(0x0020, "WM_SETCURSOR")
OnExit("ZoomOnClose")
OnMessage(0x201, "LBUTTONDOWN") ;; WM_LBUTTONDOWN
OnMessage(0x204, "RBUTTONDOWN") ;; WM_RBUTTONDOWN
OnMessage(0xA1, "LBUTTONDOWN") ;; WM_NCLBUTTONDOWN
 
SetWinEventHook("EVENT_OBJECT_DESTROY", 0x8001)
SetWinEventHook("EVENT_SYSTEM_MINIMIZESTART", 0x0016)
SetWinEventHook("EVENT_SYSTEM_MINIMIZEEND", 0x0017)
SetWinEventHook("EVENT_SYSTEM_MOVESIZESTART", 0x000A)
SetWinEventHook("EVENT_SYSTEM_MOVESIZEEND", 0x000B)			

ObjActive.Magnify := Func("Magnify")
ObjActive.Redraw := Func("Redraw") 

ZoomCreate()  
Send_AhkSpy(0, oZoom.hGui)  
Send_AhkSpy(3, oZoom.hLW) 

WinGet, Min, MinMax, % "ahk_id " hAhkSpy
If Min != -1
	ZoomShow()

MenuAdd("Zoom", "Save to temp file and edit", "_gSave_to_file")
MenuAdd("Zoom", "Save to clipboard", "_gSave_to_Clipboard")
MenuAdd("Zoom", "Save to clipboard as Base64", "_gSave_as_Base64") 
MenuAdd("Zoom")
MenuAdd("Zoom", "Save as file", "_gSave_as_file") 
MenuAdd("Zoom", "Save to desktop", "_gSave_to_file")
MenuAdd("Zoom", "Save to desktop and edit", "_gSave_to_file") 
MenuAdd("Zoom", "Select window", "_gMenuZoom", "+BarBreak")
MenuAdd("Zoom", "Select client", "_gMenuZoom", "")
MenuAdd("Zoom", "Select control", "_gMenuZoom")
MenuAdd("Zoom", "Select accesible", "_gMenuZoom")
MenuAdd("Zoom")
MenuAdd("Zoom", "Select AhkSpy", "_gMenuZoom") 
Return 

#If isZoom && oZoom.Show && UnderRender()
Up::MoveStep(0, -1)
Down::MoveStep(0, 1)
Left::MoveStep(-1, 0)
Right::MoveStep(1, 0)
+Up::MoveStep(0, -10)
+Down::MoveStep(0, 10)
+Left::MoveStep(-10, 0)
+Right::MoveStep(10, 0)

#If isZoom && oZoom.Show && oZoom.Crop && UnderRender()
Home::
MButton:: CoupCrop()
+Home::
+MButton:: CircleCoupCrop()
#If isZoom && oZoom.Show && UnderRender()
End::CropToggle()
PgUp::
PgDn::
WheelUp::
WheelDown:: ChangeZoom(FastZoom(InStr(A_ThisHotKey, "Up")))

Tab::
F1::
F11:: ZoomMaximize()

F12:: 
AppsKey::ZoomMenu()

#If isZoom && oZoom.Show && GetMinMax(oZoom.hGui) = 1
Esc:: ZoomMaximize() 
#If

; 1::Gui, Zoom: +Caption  -E%WS_EX_NOACTIVATE%   

; 2::Gui, Zoom: -Caption +E%WS_EX_NOACTIVATE%

ZoomCreate() { 
	Global WS_EX_NOACTIVATE, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_CHILDWINDOW, WS_POPUP, WS_EX_TRANSPARENT
	oZoom.Zoom := IniRead("MagnifyZoom", 4)
	oZoom.Mark := IniRead("MagnifyMark", "Cross")
	oZoom.MemoryZoomSize := IniRead("MemoryZoomSize", 0)
	oZoom.GuiMinW := 380
	oZoom.GuiMinH := 351
	FontSize := {96:12,120:10,144:8,168:6}[A_ScreenDPI]
	
	If oZoom.MemoryZoomSize
		GuiW := IniRead("MemoryZoomSizeW", oZoom.GuiMinW), GuiH := IniRead("MemoryZoomSizeH", oZoom.GuiMinH)
	Else
		GuiW := oZoom.GuiMinW, GuiH := oZoom.GuiMinH
	Gui, Zoom: -Caption -DPIScale +Border +LabelZoomOn +HWNDhGuiZoom +AlwaysOnTop +E%WS_EX_NOACTIVATE%    ;;	+Owner%hAhkSpy%
	Gui, Zoom: Color, %GuiColor%
	Gui, Zoom: Add, Text, hwndhStatic +Border
	; DllCall("SetClassLong", "UPtr", hGuiZoom, "int", -26
	; , "int", DllCall("GetClassLong", "UPtr", hGuiZoom, "int", -26) | 0x20000)

	Gui, LW: -Caption +E%WS_EX_LAYERED% +AlwaysOnTop +ToolWindow +HWNDhLW +E%WS_EX_NOACTIVATE% +Owner%hGuiZoom% ;;	++E%WS_EX_NOACTIVATE% +E%WS_EX_TRANSPARENT%

	Gui, ZoomTB: +HWNDhTBGui -Caption -DPIScale +Parent%hGuiZoom% +E%WS_EX_NOACTIVATE% +%WS_CHILDWINDOW% -%WS_POPUP%
	Gui, ZoomTB: Color, %GuiColor%
	h := 32
	Gui, ZoomTB: Add, Slider, % "hwndhSliderZoom gSliderZoom x8 Range1-50 w152 y" (44-h)/2 " h" h " Center AltSubmit NoTicks", % oZoom.Zoom
	Gui, ZoomTB: Font, % "s" FontSize + 2
	Gui, ZoomTB: Add, Text, hwndhTextZoom +0x201 x+10 yp w36 hp c%TextColor%, % oZoom.Zoom
	Gui, ZoomTB: Font, % "s" FontSize + 4
	Gui, ZoomTB: Add, Button, hwndhZoomHideBut gZoomHide x+10 ys h%h% w22, % Chr(0x00D7)
	Gui, ZoomTB: Font, % "s" FontSize - 2
	Gui, ZoomTB: Add, Button, hwndhChangeMark gChangeMark x+10 yp hp w62, % oZoom.Mark
	Gui, ZoomTB: Add, Text, % "hwndhCropWidth hidden Border Section c" TextColor " xp yp wp h" h / 2
	Gui, ZoomTB: Add, Text, % "hwndhCropHeight hidden Border c" TextColor " xs y+0 wp hp"
	Gui, ZoomTB: Font, % "s" FontSize + 4
	Gui, ZoomTB: Add, Button, gZoomMenu hwndhZoomMenu x+10 ys h%h% w22, % Chr(0x2261)
	Gui, ZoomTB: Add, Button, gZoomMaximize x+10 yp hp wp, % Chr(0x1F791) 
	Gui, ZoomTB: Show, NA x0 y0
	Gui, Zoom: Show, % "NA Hide w" GuiW " h" GuiH, AhkSpyZoom
	Gui, Zoom: +MinSize
	
	WinSet, TransParent, 255, ahk_id %hGuiZoom%
	
	oZoom.hdcSrc := DllCall("GetDC", "UPtr", 0, "UPtr")
	oZoom.hDCBuf := CreateCompatibleDC()
	oZoom.hdcMemory := CreateCompatibleDC()

	oZoom.hGui := hGuiZoom
	oZoom.hStatic := hStatic
	oZoom.hTBGui := hTBGui
	oZoom.hLW := hLW

	oZoom.vTextZoom := hTextZoom
	oZoom.vChangeMark := hChangeMark
	oZoom.vCropWidth := hCropWidth
	oZoom.vCropHeight := hCropHeight 
	
	oZoom.vZoomHideBut := hZoomHideBut
	oZoom.vSliderZoom := hSliderZoom
	oZoom.vZoomMenu := hZoomMenu
}

SetSize() {
	Static Top := 45, Left := 0, Right := 6, Bottom := 6

	Width := oZoom.LWWidth := oZoom.GuiWidth - Left - Right
	Height := oZoom.LWHeight := oZoom.GuiHeight - Top - Bottom

	Zoom := oZoom.Zoom
	conW := Mod(Width, Zoom) ? Width - Mod(Width, Zoom) + Zoom : Width
	conW := Mod(conW // Zoom, 2) ? conW : conW + Zoom

	conH := Mod(Height, Zoom) ? Height - Mod(Height, Zoom) + Zoom : Height
	conH := Mod(conH // Zoom, 2) ? conH : conH + Zoom

	oZoom.conX := (((conW - Width) // 2)) * -1
	oZoom.conY :=  (((conH - Height) // 2)) * -1
	
	hDWP := DllCall("BeginDeferWindowPos", "Int", 2)
	hDWP := DllCall("DeferWindowPos"
	, "Ptr", hDWP, "Ptr", oZoom.hStatic, "UInt", 0
	, "Int", Left - 1, "Int", Top - 1, "Int", Width + 2, "Int", Height + 2
	, "UInt", 0x0010)    ;; 0x0010 := SWP_NOACTIVATE
	hDWP := DllCall("DeferWindowPos"
	, "Ptr", hDWP, "Ptr", oZoom.hTBGui, "UInt", 0
	, "Int", (oZoom.GuiWidth - oZoom.GuiMinW) / 2
	, "Int", 0, "Int", 0, "Int", 0
	, "UInt", 0x0011)    ;; 0x0010 := SWP_NOACTIVATE | 0x0001 := SWP_NOSIZE
	DllCall("EndDeferWindowPos", "Ptr", hDWP)

	oZoom.nWidthSrc := conW // Zoom
	oZoom.nHeightSrc := conH // Zoom
	oZoom.nXOriginSrcOffset := oZoom.nWidthSrc//2
	oZoom.nYOriginSrcOffset := oZoom.nHeightSrc//2
	oZoom.nWidthDest := conW
	oZoom.nHeightDest := conH
	oZoom.xCenter := Round(Width / 2 - Zoom / 2)
	oZoom.yCenter := Round(Height / 2 - Zoom / 2)

	ChangeMarker()

	If oZoom.MemoryZoomSize
		SetTimer, ZoomCheckSize, -100
}

ChangeMarker() {
	Try GoTo % "Marker" oZoom.Mark

	MarkerCross:
		oZoom.oMarkers["Cross"] := [{x:0,y:oZoom.yCenter - 1,w:oZoom.nWidthDest,h:1}
		, {x:0,y:oZoom.yCenter + oZoom.Zoom,w:oZoom.nWidthDest,h:1}
		, {x:oZoom.xCenter - 1,y:0,w:1,h:oZoom.nHeightDest}
		, {x:oZoom.xCenter + oZoom.Zoom,y:0,w:1,h:oZoom.nHeightDest}]
		Return

	MarkerSquare:
		oZoom.oMarkers["Square"] := [{x:oZoom.xCenter - 1,y:oZoom.yCenter,w:oZoom.Zoom + 2,h:1}
		, {x:oZoom.xCenter - 1,y:oZoom.yCenter + oZoom.Zoom + 1,w:oZoom.Zoom + 2,h:1}
		, {x:oZoom.xCenter - 1,y:oZoom.yCenter + 1,w:1,h:oZoom.Zoom}
		, {x:oZoom.xCenter + oZoom.Zoom,y:oZoom.yCenter + 1,w:1,h:oZoom.Zoom}]
		Return

	MarkerGrid:
		If (oZoom.Zoom = 1) {
			Gosub MarkerSquare
			oZoom.oMarkers["Grid"] := oZoom.oMarkers["Square"]
			Return
		}
		oZoom.oMarkers["Grid"] := [{x:oZoom.xCenter - oZoom.Zoom,y:oZoom.yCenter - oZoom.Zoom,w:oZoom.Zoom * 3,h:1}
		, {x:oZoom.xCenter - oZoom.Zoom,y:oZoom.yCenter,w:oZoom.Zoom * 3,h:1}
		, {x:oZoom.xCenter - oZoom.Zoom,y:oZoom.yCenter + oZoom.Zoom,w:oZoom.Zoom * 3,h:1}
		, {x:oZoom.xCenter - oZoom.Zoom,y:oZoom.yCenter + oZoom.Zoom * 2,w:oZoom.Zoom * 3,h:1}
		, {x:oZoom.xCenter - oZoom.Zoom,y:oZoom.yCenter - oZoom.Zoom,w:1,h:oZoom.Zoom * 3}
		, {x:oZoom.xCenter,y:oZoom.yCenter - oZoom.Zoom,w:1,h:oZoom.Zoom * 3}
		, {x:oZoom.xCenter + oZoom.Zoom,y:oZoom.yCenter - oZoom.Zoom,w:1,h:oZoom.Zoom * 3}
		, {x:oZoom.xCenter + oZoom.Zoom * 2,y:oZoom.yCenter - oZoom.Zoom,w:1,h:oZoom.Zoom * 3}]
		Return
}

ZoomCheckSize() {
	Static PrWidth, PrHeight
	If (PrWidth = oZoom.GuiWidth && PrHeight = oZoom.GuiHeight)
		Return
	PrWidth := oZoom.GuiWidth, PrHeight := oZoom.GuiHeight
	IniWrite(PrWidth, "MemoryZoomSizeW"), IniWrite(PrHeight, "MemoryZoomSizeH")
}

SliderZoom() {
	SetTimer, ChangeZoom, -1
}

ChangeZoom(Val = "")  {
	If Val =
		GuiControlGet, Val, ZoomTB:, % oZoom.vSliderZoom
	If (Val < 1 || Val > 50)
		Return
	GuiControl, ZoomTB:, % oZoom.vSliderZoom, % oZoom.Zoom := Val
	GuiControl, ZoomTB:, % oZoom.vTextZoom, % oZoom.Zoom
	SetSize()
	Redraw()
	SetTimer, MagnifyZoomSave, -200
}

FastZoom(Add) {
 	Z := oZoom.Zoom, R := Mod(Z, 5)
	If Add
		Z := Z >= 10 ? Z + (5 - R) : Z + 1
	Else	
		Z := Z > 10 ? Z - (!R ? 5 : R) : Z - 1
	Return Z
}

MagnifyZoomSave() {
	IniWrite(oZoom.Zoom, "MagnifyZoom")
}

MoveStep(StepX, StepY) { 
	oZoom.nXOriginSrc += StepX
	oZoom.nYOriginSrc += StepY
	LimitsOriginSrc(), Redraw(), SendCoords()
}

ChangeMark()  {
	Static Mark := {"Cross":"Square","Square":"Grid","Grid":"None","None":"Cross","":"None"}
	oZoom.Mark := Mark[oZoom.Mark], ChangeMarker(), Redraw()
	GuiControl, ZoomTB:, % oZoom.vChangeMark, % oZoom.Mark
	GuiControl, ZoomTB:, -0x0001, % oZoom.vChangeMark
	GuiControl, ZoomTB:, Focus, % oZoom.vTextZoom
	SetTimer, MagnifyMarkSave, -300
}

MagnifyMarkSave() {
	IniWrite(oZoom.Mark, "MagnifyMark")
}

SetWinEventHook(EventProc, eventMin, eventMax = 0)  {
	; DllCall("CoInitialize", UInt, 0)
	Return DllCall("SetWinEventHook"
				, "UInt", eventMin, "UInt", eventMax := !eventMax ? eventMin : eventMax
				, "Ptr", hmodWinEventProc := 0, "Ptr", lpfnWinEventProc := RegisterCallback(EventProc, "F")
				, "UInt", idProcess := 0, "UInt", idThread := 0
				, "UInt", dwflags := 0x0|0x2, "Ptr")	;;	WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS
}

UnhookWinEvent(hWinEventHook) {  
	DllCall("UnhookWinEvent", "Ptr", hWinEventHook)
	DllCall("GlobalFree", "Ptr", &hWinEventHook) ; free up allocated memory for RegisterCallback
}

ZoomShow() {
	ShowZoom(1) 
	Send_AhkSpy(2, 1)
	ZoomRules("ZoomHide", 0)
	GuiControl, ZoomTB:, Focus, % oZoom.vTextZoom
}

ZoomHide() {
	ZoomRules("ZoomHide", 1)
	ShowZoom(0) 
	Send_AhkSpy(2, 0)
	GuiControl, ZoomTB:, -0x0001, % oZoom.vZoomHideBut
	GuiControl, ZoomTB:, Focus, % oZoom.vTextZoom
}

ShowZoom(Show) {
	oZoom.Show := Show
	If Show {
		WinGetPos, WinX, WinY, WinW, , ahk_id %hAhkSpy%
		oZoom.LWX := WinX + WinW + 1, oZoom.LWY := WinY + 46
		Gui,  Zoom: Show, % "NA Hide x" WinX + WinW " y" WinY
		Gui,  LW: Show, % "NA x" oZoom.LWX " y" oZoom.LWY " w" 0 " h" 0
		Gui,  Zoom: Show, NA
		try Gui, LW: Show, % "NA x" oZoom.LWX " y" oZoom.LWY " w" oZoom.LWWidth " h" oZoom.LWHeight 
	}
	Else 
	{
		Gui,  LW: Show, % "NA w" 0 " h" 0  ;;	нельзя применять Hide, иначе после появления и ресайза остаётся прозрачный след
		Gui,  Zoom: Show, NA Hide
	}
}

MenuAdd(MenuName, Name = "", Label = "", Options = "") {
	Menu, %MenuName%, Add, %Name%, % oMenu.Zoom[Name] := Label, %Options%
}

	; ___________________________ Zoom Events _________________________________________________

ZoomOnSize() {
	Critical
	If A_EventInfo != 0
		Return
	oZoom.GuiWidth := A_GuiWidth
	oZoom.GuiHeight := A_GuiHeight
	SetSize()
	Redraw()
}

ZoomMaximize() { 
	WinGet, Min, MinMax, % "ahk_id " oZoom.hGui
	ObjActive.ZoomMaximize := !Min
	If Min = 1
		WinRestore, % "ahk_id " oZoom.hGui
	Else 
		WinMaximize, % "ahk_id " oZoom.hGui   
	WinGetPos, WinX, WinY, WinW, WinH, % "ahk_id " oZoom.hGui 
	oZoom.GuiWidth := WinW
	oZoom.GuiHeight := WinH
	SetSize()
	oZoom.LWWidth := oZoom.GuiWidth - 6
	oZoom.LWHeight := oZoom.GuiHeight - 51 
	oZoom.LWX := WinX + 1, oZoom.LWY := WinY + 46 
	Gui,  LW: Show, % "NA x" oZoom.LWX " y" oZoom.LWY " w" oZoom.LWWidth " h" oZoom.LWHeight  
	Redraw() 
	If Min = 1
		WinActivate, % "ahk_id " hAhkSpy
}

ZoomOnClose() {
	ReleaseDC(oZoom.hdcSrc)
	DeleteDC(oZoom.hdcSrc)
	DeleteDC(oZoom.hDCBuf)
	DeleteDC(oZoom.hdcMemory)
	GdipShutdown(oZoom.pToken)
	RestoreCursors()
	ExitApp
}

	; wParam: 0 hide, 1 show, 2 пауза AhkSpy, 3 однократный зум, 4 MemoryZoomSize, 5 MinSize, 6 ActiveNoPause
	; , 7 WinActive AhkSpy, 8 Suspend, 9 Menu, 10 Hotkey, 11 MIN, 12 ShiftTab, 13 ZoomResetCoords, 14 MagnifyHWND 

Zoom_Msg(wParam, lParam) {
	If wParam = 0  ;;	hide
		ZoomHide()
	Else If wParam = 1  ;;	show
		ZoomShow()
	If wParam = 2  ;;	пауза AhkSpy
		ZoomRules("Pause", lParam)
	Else If wParam = 3  ;;	однократный зум  ;;	AhkSpy отвечает за контекст вызова
		Magnify(1)
	Else If wParam = 4  ;;	MemoryZoomSize
	{
		If (oZoom.MemoryZoomSize := lParam)
			IniWrite(oZoom.GuiWidth, "MemoryZoomSizeW"), IniWrite(oZoom.GuiHeight, "MemoryZoomSizeH")
	}
	Else If (wParam = 5 && DllCall("IsWindowVisible", "UPtr", oZoom.hGui))  ;;	MinSize
		Gui, Zoom:Show, % "NA w" oZoom.GuiMinW " h" oZoom.GuiMinH
	Else If wParam = 6  ;;	ActiveNoPause
		ActiveNoPause := lParam, ZoomRules("Win", ActiveNoPause ? 0 : SpyActive)
	Else If wParam = 7  ;;	WinActive AhkSpy
		SpyActive := lParam, ZoomRules("Win", ActiveNoPause ? 0 : SpyActive)
	Else If wParam = 8  ;;	Suspend
		Suspend % lParam ? "On" : "Off"
	Else If wParam = 9  ;;	Menu
		ZoomRules("Menu", lParam)
	Else If wParam = 10  ;;	Menu
		ZoomRules("Hotkey", lParam)
	Else If wParam = 11  ;;	MIN
		ZoomRules("MIN", 1)
	Else If wParam = 12  ;;	ShiftTab
		ZoomRules("ShiftTab", lParam)
	Else If wParam = 13  ;;	ZoomResetCoords
		ZoomResetCoords() 
	Else If wParam = 14  ;;	MagnifyHWND
		MagnifyHWND(lParam)
}

Z_MsgZoom(wParam, lParam) {
	obj := Func("Zoom_Msg").Bind(wParam, lParam)
	SetTimer, % obj, -1
	Return 0
}

ZoomRules(Rule, value) {
	Static IsStart, Rules, Arr, Len
	If !IsStart
	{
		Arr := {"ZoomHide":1, "Pause":2, "Win":3, "Sleep":4, "Menu":5, "MIN":6, "MOVE":7, "SIZE":8, "Hotkey":9, "ShiftTab":10}, Len := Arr.Count()
		Loop % VarSetCapacity(Rules, Len - 1)
			StrPut(0, &Rules + A_Index - 1, 1, "CP0")
		IsStart := 1
	}
	StrPut(!!value, &Rules + Arr[Rule] - 1, 1, "CP0")
	If oZoom.Work := !(StrGet(&Rules, Len, "CP0") + 0)
		SetTimer, Magnify, -1
	; ToolTip % Rule "`n" Arr[Rule] "`n" value "`n`n`n"  (StrGet(&Rules, Len, "CP0")) "`n123456789" "`n" oZoom.Work,4,55,6
}

EVENT_OBJECT_DESTROY(hWinEventHook, event, hwnd, idObject, idChild) {
	If (idObject || idChild)
		Return
	If (hwnd = hAhkSpy)
		ExitApp
}

EVENT_SYSTEM_MINIMIZESTART(hWinEventHook, event, hwnd, idObject, idChild) {
	If (idObject || idChild)
		Return
	If (hwnd != hAhkSpy)
		Return
	ZoomRules("MIN", 1)
	If oZoom.Show
		oZoom.Minimize := 1, ShowZoom(0)
}

EVENT_SYSTEM_MINIMIZEEND(hWinEventHook, event, hwnd, idObject, idChild) {
	If (idObject || idChild)
		Return
	If (hwnd != hAhkSpy)
		Return
	If oZoom.Minimize
	{
		isEnabled := false, DllCall("dwmapi.dll\DwmIsCompositionEnabled", "UInt", &isEnabled)
		Sleep % !!isEnabled ? 300 : 10
		ShowZoom(1)
		oZoom.Minimize := 0
	}
	ZoomRules("MIN", 0)
}

EVENT_SYSTEM_MOVESIZESTART(hWinEventHook, event, hwnd, idObject, idChild) {
	If (idObject || idChild)
		Return
	If (hwnd != hAhkSpy)
		Return
	ZoomRules("MOVE", 1)
}

EVENT_SYSTEM_MOVESIZEEND(hWinEventHook, event, hwnd, idObject, idChild) {
	If (idObject || idChild)
		Return
	If (hwnd != hAhkSpy)
		Return
	ZoomRules("MOVE", 0)
}

	; ___________________________ Zoom Sizing _________________________________________________

  ;;	https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadcursora
WM_SETCURSOR(W, L, M, H) {
	Static SIZENWSE := DllCall("User32.dll\LoadCursor", "Ptr", NULL, "Int", 32642, "UPtr")
			, SIZENS := DllCall("User32.dll\LoadCursor", "Ptr", NULL, "Int", 32645, "UPtr")
			, SIZEWE := DllCall("User32.dll\LoadCursor", "Ptr", NULL, "Int", 32644, "UPtr")
	If (oZoom.SIZING = 2)
		Return
	If (W = oZoom.hGui)
	{
		MouseGetPos, mX, mY
		WinGetPos, WinX, WinY, WinW, WinH, % "ahk_id " oZoom.hLW
		If (mX > WinX && mY > WinY)
		{
			If (mX < WinX + WinW - 10)
				DllCall("User32.dll\SetCursor", "Ptr", SIZENS), oZoom.SIZINGType := "NS"
			Else If (mY < WinY + WinH - 10)
				DllCall("User32.dll\SetCursor", "Ptr", SIZEWE), oZoom.SIZINGType := "WE"
			Else
				DllCall("User32.dll\SetCursor", "Ptr", SIZENWSE), oZoom.SIZINGType := "NWSE"
			Return oZoom.SIZING := 1
		}
	}
	Else
		oZoom.SIZING := 0, oZoom.SIZINGType := ""
}

LBUTTONDOWN(W, L, M, H) { 
	If oZoom.SIZING
	{
		ZoomRules("SIZE", 1)
		oZoom.SIZING := 2
		SetSystemCursor("SIZE" oZoom.SIZINGType)
		SetTimer, Sizing, -10
		KeyWait LButton
		SetTimer, Sizing, Off
		RestoreCursors()
		ZoomRules("SIZE", 0)
		oZoom.SIZING := 0, oZoom.SIZINGType := ""
	}
	Else If (H = oZoom.hLW)
	{
		SetTimer, Hand, -1
	}
}

RBUTTONDOWN(W, L, M, H) { 
	If (H = oZoom.vZoomMenu)
		Return ZoomMenu()
	If !(H = oZoom.hLW)
		Return 
	SetTimer CropToggle, -100
}

CropToggle() {
	If !oZoom.Crop
		oZoom.Crop := 1, oZoom.CropX := oZoom.nXOriginSrc, oZoom.CropY := oZoom.nYOriginSrc
	Else 
		oZoom.Crop := 0
	CropMarkToggle()
	Redraw()
	CropChangeControls() 
}

CropMarkToggle() { 
	If (oZoom.Crop && (oZoom.CropPrMark := oZoom.Mark) && oZoom.Mark != "Cross")
		oZoom.Mark := "Cross", ChangeMarker()
	Else If (!oZoom.Crop && oZoom.Mark != oZoom.CropPrMark)
		oZoom.Mark := oZoom.CropPrMark, ChangeMarker()  
}

CropChangeControls() { 
	GuiControl("ZoomTB:", oZoom.vChangeMark, oZoom.Mark)
	GuiControl("ZoomTB:Hide" oZoom.Crop, oZoom.vChangeMark)
	GuiControl("ZoomTB:Show" oZoom.Crop, oZoom.vCropWidth)
	GuiControl("ZoomTB:Show" oZoom.Crop, oZoom.vCropHeight) 
} 

ZoomMenu() { 
	ObjActive.ZoomSleep()
	WinActivate, % "ahk_id " oZoom.hGui
	ZoomRules("Win", 0)
	DllCall("SetTimer", "UPtr", A_ScriptHwnd, "Ptr", 1, "UInt", 333, "Ptr", RegisterCallback("ZoomMenuCheck", "Fast"))
	CoordMode, Menu, Screen 
	If A_GuiControl =
	{
		MouseGetPosScreen(x, y)
		Menu, Zoom, Show, % x - 200, % y + 20
	}
	Else 
	{ 
		WinGetPos, WinX, WinY, WinW, WinH, % "ahk_id " oZoom.vZoomMenu  
		Menu, Zoom, Show, % WinX - 200, % WinY + WinH
	}
	ObjActive.ZoomNoSleep()
}

ZoomMenuCheck()  {
	DllCall("KillTimer", "UPtr", A_ScriptHwnd, "Ptr", 1) 
	If !WinExist("ahk_class #32768 ahk_pid " oZoom.CurrentProcessId)
		Return
	If GetKeyState("RButton")
	{
		MouseGetPos, , , WinID
		Menu := MenuGetName(GetMenuForMenu(WinID)) 
		If Menu && (F := oMenu[Menu][oOther.ThisMenuItem := AccUnderMouse(WinID, Id).accName(Id)])
		{
			oOther.MenuItemExist := 1
			If  !(F ~= "^_")
			{
				KeyWait, RButton
				WinClose % "ahk_id " WinID
			}
			If IsLabel(F)
				GoSub, % F
			Else
				%F%()
			oOther.MenuItemExist := 0
		}
		KeyWait, RButton
	}
	DllCall("SetTimer", "UPtr", A_ScriptHwnd, "Ptr", 1, "UInt", 64, "Ptr", RegisterCallback("ZoomMenuCheck", "Fast"))
}

_gMenuZoom() { 
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem 
	p := ObjActive["Coords" SubStr(ThisMenuItem, 8)]	; SetPosObject
	If p[1] = "" || p[2] = "" || p[3] = "" || p[4] = ""
		Return ToolTip("Coordinates not found!", 800)
	oZoom.Crop := 1
	x := p[1] + 0, y := p[2] + 0, w := p[3] + 0, h := p[4] + 0
	If ThisMenuItem = Select AhkSpy
		y -= HeigtButton, h += HeigtButton
	oZoom.nXOriginSrc := x - oZoom.VSX, oZoom.nYOriginSrc := y - oZoom.VSY
	oZoom.CropX := x + w - 1 - oZoom.VSX, oZoom.CropY := y + h - 1 - oZoom.VSY 
	CropMarkToggle()
	Redraw()
	CropChangeControls()
	SendCoords()
}

_gSave_to_Clipboard() { 
	If !pBitmap := GetBitmap()
		Return ToolTip("Bitmap not found!", 800)
	SetBitmapToClipboard(pBitmap) 
	DllCall("gdiplus\GdipDisposeImage", "UPtr", pBitmap) 
	ToolTip("Copy to clipboard", 800)
}

_gSave_as_Base64() {
	If GetKeyState("Control", "P")
		tovar := 1
	If GetKeyState("Shift", "P")
		nocrlf := 1
	If !pBitmap := GetBitmap()
		Return ToolTip("Bitmap not found!", 800)  
		
	If BitmapToBase64(pBitmap, tovar || nocrlf ? 1 : 0, Base64) != 0
		Return DllCall("gdiplus\GdipDisposeImage", "UPtr", pBitmap), ToolTip("Error BitmapToBase64!", 1200) 

	DllCall("gdiplus\GdipDisposeImage", "UPtr", pBitmap) 
	DllCall("OpenClipboard", "Ptr", 0)
	DllCall("EmptyClipboard")
	DllCall("CloseClipboard")
	If tovar
		Base64 := FormatBase64ToVaribles(Base64, "Base64", nocrlf ? 0 : 128) 
	Clipboard := Base64
	ToolTip("Copy to clipboard as Base64" (tovar ? " and format AHK variable" : "") (nocrlf ? " and no CRLF" : ""), 800)
		
	; File := A_Temp "\AhkSpy picture for Base64.png"
	; SaveBitmapToFile(pBitmap, File) 
	; DllCall("gdiplus\GdipDisposeImage", "UPtr", pBitmap) 
	; FileGetSize, nSize, %File%
	; FileRead, buff, *c %File% 
	; If Control
		; Base64 := CryptBinaryToStringBASE64(&buff, nSize, 1)
		; , Base64 := FormatBase64ToVaribles(Base64, "Base64", 128) 
	; Else
		; Base64 := CryptBinaryToStringBASE64(&buff, nSize, 0)
	; VarSetCapacity(buff, 0)
	; DllCall("OpenClipboard", Ptr, 0)
	; DllCall("EmptyClipboard")
	; DllCall("CloseClipboard")
	; Clipboard := Base64
	; ToolTip("Copy to clipboard as Base64" (Control ? " and format AHK variable" : ""), 800)
}  

_gSave_as_file() {  
	If !pBitmap := GetBitmap()
		Return ToolTip("Bitmap not found!", 800) 
	Name := "\AhkSpy picture " A_YYYY "-" A_MM "-" A_DD " " A_Hour "." A_Min "." A_Sec ".png" 
	Dir := IniRead("MemoryZoomSaveFolder")
	ObjActive.AhkSpy_Minimize()
	FileSelectFile, SelectedFile, S 16, %Dir%\%Name%, Сохранение изображения, Изображения (*.png)	
	If SelectedFile =
	{  
		Return
	}
	SplitPath, SelectedFile, , Dir, Ext
	IniWrite(Dir, "MemoryZoomSaveFolder")
	SelectedFile := Ext = "png" ? SelectedFile : SelectedFile ".png"
	SaveBitmapToFile(pBitmap, SelectedFile)
	DllCall("gdiplus\GdipDisposeImage", "UPtr", pBitmap)
	SelectFilePath(SelectedFile)
}

_gSave_to_file() {
	If !pBitmap := GetBitmap()
		Return ToolTip("Bitmap not found!", 800)
	ThisMenuItem := oOther.MenuItemExist ? oOther.ThisMenuItem : A_ThisMenuItem
	
	file := (ThisMenuItem = "Save to temp file and edit") 
	? A_Temp "\AhkSpy picture.png"
	: A_Desktop "\AhkSpy picture " A_YYYY "-" A_MM "-" A_DD " " A_Hour "." A_Min "." A_Sec ".png"
	
	; GetNameFile(A_Desktop, "AhkSpy picture ", "png")
	
	SaveBitmapToFile(pBitmap, file)
	DllCall("gdiplus\GdipDisposeImage", "UPtr", pBitmap)
	If (ThisMenuItem = "Save to desktop and edit") || (ThisMenuItem = "Save to temp file and edit")
	{ 
		WinClose % "ahk_class #32768 ahk_pid " oZoom.CurrentProcessId
		If GetMinMax(oZoom.hGui) = 1
			ZoomMaximize()
		Run edit %file%
		ObjActive.AhkSpy_Minimize()
	}
	Else
		ToolTip("Save file to desktop", 800)
}

GetBitmap() {
	If oZoom.Crop
		w := oZoom.CropWidth, h := oZoom.CropHeight
		, sx := Min(oZoom.CropX, oZoom.nXOriginSrc)
		, sy := Min(oZoom.CropY, oZoom.nYOriginSrc)
	Else
		w := oZoom.VirtualScreenWidth
		, h := oZoom.VirtualScreenHeight
		, sx := 0, sy := 0
	
	chdc := CreateCompatibleDC()
	hbm := CreateDIBSection(w, h, chdc)
	obm := SelectObject(chdc, hbm)
	DllCall("BitBlt", "Ptr", chdc, "int", 0, "int", 0, "int", w, "int", h
			, "Ptr", oZoom.hdcMemory, "int", sx, "int", sy, "Uint", 0x00CC0020) 
	DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "UPtr", hbm, "UPtr", 0, "UPtr*", pBitmap)
	SelectObject(chdc, obm), DeleteObject(hbm), DeleteDC(chdc)
	return pBitmap
}

CircleCoupCrop() {
	If oZoom.CropWidth = 1 && oZoom.CropHeight = 1
		Return
	x := oZoom.CropX, y := oZoom.CropY
	If oZoom.nXOriginSrc > oZoom.CropX && oZoom.nYOriginSrc > oZoom.CropY ; RD - текущее правее и ниже диагонали Crop
		oZoom.CropX := oZoom.nXOriginSrc, oZoom.nXOriginSrc := x
	Else If oZoom.nXOriginSrc < oZoom.CropX && oZoom.nYOriginSrc > oZoom.CropY ; LD
		oZoom.CropY := oZoom.nYOriginSrc, oZoom.nYOriginSrc := y
	Else If oZoom.nXOriginSrc < oZoom.CropX && oZoom.nYOriginSrc < oZoom.CropY ; LU 
		oZoom.CropX := oZoom.nXOriginSrc, oZoom.nXOriginSrc := x
	Else If oZoom.nXOriginSrc > oZoom.CropX && oZoom.nYOriginSrc < oZoom.CropY ; RU
		oZoom.CropY := oZoom.nYOriginSrc, oZoom.nYOriginSrc := y
	Else
		Return CoupCrop()
	Redraw()
	SendCoords()
} 

CoupCrop() {
	x := oZoom.CropX, y := oZoom.CropY
	oZoom.CropX := oZoom.nXOriginSrc, oZoom.CropY := oZoom.nYOriginSrc
	oZoom.nXOriginSrc := x, oZoom.nYOriginSrc := y
	Redraw()
	SendCoords()
}

SendCoords() {  
	OffX := (oZoom.nXOriginSrc - oZoom.sXOriginSrc)
	OffY := (oZoom.nYOriginSrc - oZoom.sYOriginSrc)
	If (oZoom.displaced && OffX OffY = "00" && (1, oZoom.displaced := 0))
		Gui, Zoom: Color, %GuiColor%
	Else If (!oZoom.displaced && OffX OffY != "00" && (1, oZoom.displaced := 1)) 
		Gui, Zoom: Color, %GuiColorDisp% 
	BGR := DllCall("gdi32.dll\GetPixel", "Ptr", oZoom.hdcMemory, "int", oZoom.nXOriginSrc, "int", oZoom.nYOriginSrc)
	Send_WM_COPYDATA(1, BGR "`n" OffX "`n" OffY, hAhkSpy)
} 

ZoomResetCoords() { 
	If !oZoom.displaced 
		Return
	oZoom.nXOriginSrc := oZoom.sXOriginSrc
	oZoom.nYOriginSrc := oZoom.sYOriginSrc
	oZoom.displaced := 0
	Gui, Zoom: Color, %GuiColor% 
	Redraw()
	BGR := DllCall("gdi32.dll\GetPixel", "Ptr", oZoom.hdcMemory, "int", oZoom.nXOriginSrc, "int", oZoom.nYOriginSrc)
	Send_WM_COPYDATA(1, BGR "`n" 0 "`n" 0 "`n" 1, hAhkSpy)
}
	
Hand() {
	SetTimer, Magnify, Off
	DllCall("GetCursorPos", "int64P", pt)
	oZoom.MoveHandX := pt << 32 >> 32, oZoom.MoveHandY := pt >> 32
	oZoom.MoveXSrc := oZoom.nXOriginSrc
	oZoom.MoveYSrc := oZoom.nYOriginSrc
	SetSystemCursor("HAND")
	SetTimer, MoveHand, 10
	KeyWait, LButton
	SetTimer, MoveHand, Off
	RestoreCursors()
	oZoom.SIZING := 0
	If oZoom.Work
		SetTimer, Magnify, -10
}
	
MoveHand() {
	Static PrnXOriginSrc, PrnYOriginSrc
	PrnXOriginSrc := oZoom.nXOriginSrc
	PrnYOriginSrc := oZoom.nYOriginSrc
	DllCall("GetCursorPos", "int64P", pt)
	MouseX := pt << 32 >> 32, MouseY := pt >> 32 
	XOdds := oZoom.MoveHandX - MouseX
	XOff := XOdds > 0 ? Floor(XOdds / oZoom.Zoom) : Ceil(XOdds / oZoom.Zoom)
	oZoom.nXOriginSrc := oZoom.MoveXSrc + XOff
	YOdds := oZoom.MoveHandY - MouseY
	YOff := YOdds > 0 ? Floor(YOdds / oZoom.Zoom) : Ceil(YOdds / oZoom.Zoom)
	oZoom.nYOriginSrc := oZoom.MoveYSrc + YOff
	If (PrnXOriginSrc <> oZoom.nXOriginSrc || PrnYOriginSrc <> oZoom.nYOriginSrc)
	{
		LimitsOriginSrc()
		SendCoords()
	} 
	Redraw() 
}

LimitsOriginSrc() {
	X := oZoom.nXOriginSrc
	oZoom.nXOriginSrc := X < 0 ? 0 : X > oZoom.VirtualScreenWidth - 1 ? oZoom.VirtualScreenWidth - 1 : X
	Y := oZoom.nYOriginSrc
	oZoom.nYOriginSrc := Y < 0 ? 0 : Y > oZoom.VirtualScreenHeight - 1 ? oZoom.VirtualScreenHeight - 1 : Y
}

UnderRender() { 
	MouseGetPos, , , Control, , 2
	Return (Control = oZoom.hLW)
}

GetMinMax(h) {
	WinGet, Min, MinMax, % "ahk_id " h
	Return Min
}

Sizing() {
	MouseGetPos, mX, mY
	WinGetPos, WinX, WinY, , , % "ahk_id " oZoom.hGui
	If (oZoom.SIZINGType = "NWSE" || oZoom.SIZINGType = "WE")
		Width := " w" (mX - WinX < oZoom.GuiMinW ? oZoom.GuiMinW : mX - WinX)
	If (oZoom.SIZINGType = "NWSE" || oZoom.SIZINGType = "NS")
		Height := " h" (mY - WinY < oZoom.GuiMinH ? oZoom.GuiMinH : mY - WinY)
	Gui, Zoom:Show, % "NA" Width . Height
	SetTimer, Sizing, -1
}

SetSystemCursor(CursorName, cx = 0, cy = 0) {
	Static SystemCursors := {ARROW:32512, IBEAM:32513, WAIT:32514, CROSS:32515, UPARROW:32516, SIZE:32640, ICON:32641, SIZENWSE:32642
					, SIZENESW:32643, SIZEWE:32644 ,SIZENS:32645, SIZEALL:32646, NO:32648, HAND:32649, APPSTARTING:32650, HELP:32651}
	Local CursorHandle, hImage, Name, ID
	If (CursorHandle := DllCall("LoadCursor", Uint, 0, Int, SystemCursors[CursorName]))
		For Name, ID in SystemCursors
			hImage := DllCall("CopyImage", Ptr, CursorHandle, Uint, 0x2, Int, cx, Int, cy, Uint, 0)
			, DllCall("SetSystemCursor", Ptr, hImage, Int, ID)
}

RestoreCursors() {
	DllCall("SystemParametersInfo", UInt, 0x57, UInt, 0, UInt, 0, UInt, 0)  ;;	SPI_SETCURSORS := 0x57
}

Send_AhkSpy(i, Param) { 
	PostMessage, % MsgAhkSpyZoom, i, % Param, , ahk_id %hAhkSpy%
}

Send_WM_COPYDATA(ByRef WParam, ByRef StringToSend, ByRef hwnd) {
    Static TimeOutTime := 0, WM_COPYDATA := 0x4a
    VarSetCapacity(CopyDataStruct, 3*A_PtrSize, 0)   
    SizeInBytes := (StrLen(StringToSend) + 1) * (A_IsUnicode ? 2 : 1)
    NumPut(SizeInBytes, CopyDataStruct, A_PtrSize)   
    NumPut(&StringToSend, CopyDataStruct, 2*A_PtrSize)  
    Prev_DetectHiddenWindows := A_DetectHiddenWindows 
    DetectHiddenWindows On  
    SendMessage, WM_COPYDATA, WParam, &CopyDataStruct,, ahk_id %hwnd%,,,, %TimeOutTime%
    DetectHiddenWindows %Prev_DetectHiddenWindows%   
    return ErrorLevel
}

	; ___________________________ Zoom Magnify _________________________________________________

Magnify(one = 0) { 
	If (a := oZoom.Work) || one
	{
		MouseGetPos, , , WinID
		If b := (WinID != oZoom.hLW && WinID != oZoom.hGui && WinID != hAhkSpy)
		{ 
			oZoom.NewSpot := 1, oZoom.MouseX := ObjActive.ScreenX, oZoom.MouseY := ObjActive.ScreenY
			If oZoom.Crop
				oZoom.Crop := 0, CropChangeControls()
			UpdateWindow(oZoom.hdcSrc, oZoom.MouseX - oZoom.nXOriginSrcOffset, oZoom.MouseY - oZoom.nYOriginSrcOffset)
		}
	}
	If oZoom.NewSpot && (!a || one && b || a && !b)
		Memory()
	If a
		SetTimer, Magnify, -10
	;; ToolTip % A_TickCount "`nMagnify", 4, 4, 4
}

; в режиме перехода по окнам

MagnifyHWND(hwnd) {  
	; Gdip_BitmapFromHWND(hwnd) 
	WinGetPos,,, Width, Height, ahk_id %hwnd%
	hbm := CreateDIBSection2(Width, Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm)
 
	ok := PrintWindow(hwnd, hdc, 1) 
	; If !ok
	; {
		; Return 0, SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc) 
	; } 
	oZoom.NewSpot := 1, oZoom.MouseX := ObjActive.ScreenX, oZoom.MouseY := ObjActive.ScreenY 
	
	oZoom.nXOriginSrc := oZoom.sXOriginSrc := Width // 2 
	oZoom.nYOriginSrc := oZoom.sYOriginSrc := Height // 2   
	
	UpdateWindow(hdc, Width // 2 - oZoom.nXOriginSrcOffset,  Height // 2 - oZoom.nYOriginSrcOffset)   
	MemoryHWND(hdc, Width, Height)
	SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
}

MemoryHWND(hdc, Width, Height) { 
	oZoom.VSX := VSX := 0
	oZoom.VSY := VSY := 0
	VirtualScreenWidth := Width
	VirtualScreenHeight := Height
	hBM := DllCall("Gdi32.Dll\CreateCompatibleBitmap", "Ptr", hdc, "Int", VirtualScreenWidth, "Int", VirtualScreenHeight)
	DllCall("Gdi32.Dll\SelectObject", "Ptr", oZoom.hdcMemory, "Ptr", hBM), DllCall("DeleteObject", "Ptr", hBM)
	StretchBlt(oZoom.hdcMemory, 0, 0, VirtualScreenWidth, VirtualScreenHeight, hdc, VSX, VSY, VirtualScreenWidth, VirtualScreenHeight)
	oZoom.VirtualScreenWidth := VirtualScreenWidth, oZoom.VirtualScreenHeight := VirtualScreenHeight
	oZoom.NewSpot := 0
	If oZoom.displaced && (1, oZoom.displaced := 0)
		Gui, Zoom: Color, %GuiColor% 
} 		

Redraw() {
	UpdateWindow(oZoom.hdcMemory, oZoom.nXOriginSrc - oZoom.nXOriginSrcOffset , oZoom.nYOriginSrc - oZoom.nYOriginSrcOffset)
}

Memory() {
	SysGet, VSX, 76
	SysGet, VSY, 77
	oZoom.VSX := VSX
	oZoom.VSY := VSY
	SysGet, VirtualScreenWidth, 78
	SysGet, VirtualScreenHeight, 79
	oZoom.nXOriginSrc := oZoom.sXOriginSrc := oZoom.MouseX - VSX
	oZoom.nYOriginSrc := oZoom.sYOriginSrc := oZoom.MouseY - VSY 
	hBM := DllCall("Gdi32.Dll\CreateCompatibleBitmap", "Ptr", oZoom.hdcSrc, "Int", VirtualScreenWidth, "Int", VirtualScreenHeight)
	DllCall("Gdi32.Dll\SelectObject", "Ptr", oZoom.hdcMemory, "Ptr", hBM), DllCall("DeleteObject", "Ptr", hBM)
	StretchBlt(oZoom.hdcMemory, 0, 0, VirtualScreenWidth, VirtualScreenHeight, oZoom.hdcSrc, VSX, VSY, VirtualScreenWidth, VirtualScreenHeight)
	oZoom.VirtualScreenWidth := VirtualScreenWidth, oZoom.VirtualScreenHeight := VirtualScreenHeight
	oZoom.NewSpot := 0
	If oZoom.displaced && (1, oZoom.displaced := 0)
		Gui, Zoom: Color, %GuiColor% 
} 		

	; ___________________________ Zoom Gdip _________________________________________________

UpdateWindow(Src, X, Y) {
	hbm := CreateDIBSection(oZoom.nWidthDest, oZoom.nHeightDest, oZoom.hDCBuf)
	DllCall("SelectObject", "UPtr", oZoom.hDCBuf, "UPtr", hbm)
	StretchBlt(oZoom.hDCBuf, oZoom.conX, oZoom.conY, oZoom.nWidthDest, oZoom.nHeightDest
	, Src, X, Y, oZoom.nWidthSrc, oZoom.nHeightSrc)
	For k, v In oZoom.oMarkers[oZoom.Mark]
		StretchBlt(oZoom.hDCBuf, v.x, v.y, v.w, v.h, oZoom.hDCBuf, v.x, v.y, v.w, v.h, 0x5A0049)	;; PATINVERT
	CropRender()	  
	DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "UPtr", hbm, "UPtr", 0, "UPtr*", pBitmap)
	; DllCall("SelectObject", "UPtr", oZoom.hDCBuf, "UPtr", hbm)
	DllCall("gdiplus\GdipCreateFromHDC", "UPtr", oZoom.hDCBuf, "UPtr*", G)
	; DllCall("gdiplus\GdipSetInterpolationMode", "UPtr", G, "int", 5)
	DrawImage(G, pBitmap, 0, 0, oZoom.LWWidth, oZoom.LWHeight)
	If oZoom.Show
		UpdateLayeredWindow(oZoom.hLW, oZoom.hDCBuf, oZoom.LWWidth, oZoom.LWHeight)
	DllCall("DeleteObject", "UPtr", hbm)
	DllCall("gdiplus\GdipDeleteGraphics", "UPtr", G)
	DllCall("gdiplus\GdipDisposeImage", "UPtr", pBitmap)
}

CropRender() {
	Static thickness := 2
	If !oZoom.Crop
		Return 
	x := (oZoom.nXOriginSrc - oZoom.CropX) * oZoom.Zoom
	y := (oZoom.nYOriginSrc - oZoom.CropY) * oZoom.Zoom
	xoff := x < 0 ? oZoom.Zoom : 0
	yoff := y < 0 ? oZoom.Zoom : 0  
	oZoom.oMarkers["CropCross"] := [] 
	If y
		oZoom.oMarkers["CropCross"].Push({x:oZoom.xCenter - x + xoff,y:oZoom.yCenter - y - 1,w:x + oZoom.Zoom + -xoff * 2,h:thickness} 
										, {x:oZoom.xCenter - x + xoff,y:oZoom.yCenter - y + oZoom.Zoom,w:x + oZoom.Zoom + -xoff * 2,h:thickness})
	If x
		oZoom.oMarkers["CropCross"].Push({x:oZoom.xCenter - x - 1,y:oZoom.yCenter - y + yoff,h:y + oZoom.Zoom + -yoff * 2,w:thickness} 
								, {x:oZoom.xCenter - x + oZoom.Zoom,y:oZoom.yCenter - y + yoff,h:y + oZoom.Zoom + -yoff * 2,w:thickness})
	For k, v In oZoom.oMarkers["CropCross"]
		StretchBlt(oZoom.hDCBuf, v.x, v.y, v.w, v.h, oZoom.hDCBuf, v.x, v.y, v.w, v.h, 0x5A0049)	;; PATINVERT
	
	oZoom.CropWidth := Abs(oZoom.nXOriginSrc - oZoom.CropX) + 1
	oZoom.CropHeight := Abs(oZoom.nYOriginSrc - oZoom.CropY) + 1
	GuiControl("ZoomTB:", oZoom.vCropWidth, "W: " oZoom.CropWidth)
	GuiControl("ZoomTB:", oZoom.vCropHeight, "H: " oZoom.CropHeight) 
}

GdipStartup() {
	if !DllCall("GetModuleHandle", "str", "gdiplus", UPtr)
		DllCall("LoadLibrary", "str", "gdiplus")
	VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
	DllCall("gdiplus\GdiplusStartup", A_PtrSize ? "UPtr*" : "uint*", pToken, UPtr, &si, UPtr, 0)
	Return pToken
}

GdipShutdown(pToken) {
	DllCall("gdiplus\GdiplusShutdown", UPtr, pToken)
	if hModule := DllCall("GetModuleHandle", "str", "gdiplus", UPtr)
		DllCall("FreeLibrary", UPtr, hModule)
	Return 0
}

SelectObject(hdc, hgdiobj) {
   Ptr := A_PtrSize ? "UPtr" : "UInt"
   return DllCall("SelectObject", Ptr, hdc, Ptr, hgdiobj)
} 

DeleteObject(hObject) {
   return DllCall("DeleteObject", A_PtrSize ? "UPtr" : "UInt", hObject)
}

UpdateLayeredWindow(hwnd, hdc, w, h) {
	Return DllCall("UpdateLayeredWindow"
					, UPtr, hwnd
					, UPtr, 0
					, UPtr, 0
					, "int64*", w|h<<32
					, UPtr, hdc
					, "int64*", 0
					, "uint", 0
					, "UInt*", 33488896  ;;	(Alpha := 255)<<16|1<<24
					, "uint", 2)
}

StretchBlt(ddc, dx, dy, dw, dh, sdc, sx, sy, sw, sh, Raster=0x40CC0020) {  ;;	0x00CC0020|0x40000000
	Return DllCall("gdi32\StretchBlt"
					, UPtr, ddc
					, "int", dx
					, "int", dy
					, "int", dw
					, "int", dh
					, UPtr, sdc
					, "int", sx
					, "int", sy
					, "int", sw
					, "int", sh
					, "uint", Raster)
}

CreateDIBSection(w, h, hdc) {
	Static bi, _ := VarSetCapacity(bi, 40, 0)
	NumPut(w, bi, 4, "uint")
	NumPut(h, bi, 8, "uint")
	NumPut(40, bi, 0, "uint")
	NumPut(1, bi, 12, "ushort")
	NumPut(0, bi, 16, "uInt")
	NumPut(32, bi, 14, "ushort")
	Return DllCall("CreateDIBSection"
					, "UPtr", hdc
					, "UPtr", &bi
					, "uint", 0
					, "UPtr*",
					, "UPtr", 0
					, "uint", 0, "UPtr")
}

GetDC(hwnd=0)
{
	return DllCall("GetDC", A_PtrSize ? "UPtr" : "UInt", hwnd)
}

CreateDIBSection2(w, h, hdc="", bpp=32, ByRef ppvBits=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	hdc2 := hdc ? hdc : GetDC()
	VarSetCapacity(bi, 40, 0)
	
	NumPut(w, bi, 4, "uint")
	, NumPut(h, bi, 8, "uint")
	, NumPut(40, bi, 0, "uint")
	, NumPut(1, bi, 12, "ushort")
	, NumPut(0, bi, 16, "uInt")
	, NumPut(bpp, bi, 14, "ushort")
	
	hbm := DllCall("CreateDIBSection"
					, Ptr, hdc2
					, Ptr, &bi
					, "uint", 0
					, A_PtrSize ? "UPtr*" : "uint*", ppvBits
					, Ptr, 0
					, "uint", 0, Ptr)

	if !hdc
		ReleaseDC(hdc2)
	return hbm
}

PrintWindow(hwnd, hdc, Flags=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	return DllCall("PrintWindow", Ptr, hwnd, Ptr, hdc, "uint", Flags)
}

DrawImage(pGraphics, pBitmap, dx, dy, dw, dh) {
	Return DllCall("gdiplus\GdipDrawImageRectRect"
				, "UPtr", pGraphics
				, "UPtr", pBitmap
				, "float", dx
				, "float", dy
				, "float", dw
				, "float", dh
				, "float", dx
				, "float", dy
				, "float", dw
				, "float", dh
				, "int", 2
				, "UPtr",
				, "UPtr", 0
				, "UPtr", 0)
} 

ReleaseDC(hdc, hwnd=0) {
	Return DllCall("ReleaseDC", "UPtr", hwnd, "UPtr", hdc)
}

DeleteDC(hdc) {
	Return DllCall("DeleteDC", "UPtr", hdc)
}

CreateCompatibleDC(hdc=0) {
	Return DllCall("CreateCompatibleDC", "UPtr", hdc)
}

CreateHBITMAPFromBitmap(pBitmap, Background:=0xffffffff) {
; background should be zero, to not alter the semi-transparent areas of the image
   hBitmap := 0
   DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", A_PtrSize ? "UPtr" : "UInt", pBitmap, A_PtrSize ? "UPtr*" : "uint*", hBitmap, "int", Background)
   return hBitmap
}

SetBitmapToClipboard(pBitmap) {
; modified by Marius Șucan to have this function report errors

   Ptr := A_PtrSize ? "UPtr" : "UInt"
   off1 := A_PtrSize = 8 ? 52 : 44
   off2 := A_PtrSize = 8 ? 32 : 24
   r1 := DllCall("OpenClipboard", Ptr, 0)
   If !r1
      Return -1

   hBitmap := CreateHBITMAPFromBitmap(pBitmap, 0)
   If !hBitmap
   {
      DllCall("CloseClipboard")
      Return -3
   }

   r2 := DllCall("EmptyClipboard")
   If !r2
   {
      DeleteObject(hBitmap)
      DllCall("CloseClipboard")
      Return -2
   }

   DllCall("GetObject", Ptr, hBitmap, "int", VarSetCapacity(oi, A_PtrSize = 8 ? 104 : 84, 0), Ptr, &oi)
   hdib := DllCall("GlobalAlloc", "uint", 2, Ptr, 40+NumGet(oi, off1, "UInt"), Ptr)
   pdib := DllCall("GlobalLock", Ptr, hdib, Ptr)
   DllCall("RtlMoveMemory", Ptr, pdib, Ptr, &oi+off2, Ptr, 40)
   DllCall("RtlMoveMemory", Ptr, pdib+40, Ptr, NumGet(oi, off2 - (A_PtrSize ? A_PtrSize : 4), Ptr), Ptr, NumGet(oi, off1, "UInt"))
   DllCall("GlobalUnlock", Ptr, hdib)
   DeleteObject(hBitmap)
   r3 := DllCall("SetClipboardData", "uint", 8, Ptr, hdib) ; CF_DIB = 8
   DllCall("CloseClipboard")
   DllCall("GlobalFree", Ptr, hdib)
   E := r3 ? 0 : -4    ; 0 - success
   Return E
}

SaveBitmapToFile(pBitmap, sOutput)  {
	SplitPath, sOutput,,, Extension
	if Extension not in PNG
		return -1
	DllCall("gdiplus\GdipGetImageEncodersSize", UIntP, nCount, UIntP, nSize)
	VarSetCapacity(ci, nSize)
	DllCall("gdiplus\GdipGetImageEncoders", UInt, nCount, UInt, nSize, Ptr, &ci)
	if !(nCount && nSize)
		return -2 
	Loop, % nCount  {
		sString := StrGet(NumGet(ci, (idx := (48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize), "UTF-16")
		if !InStr(sString, "*." Extension)
			continue

		pCodec := &ci+idx
		break
	} 
	if !pCodec
		return -3
	if A_IsUnicode
		pOutput := &sOutput
	else  {
		VarSetCapacity(wOutput, StrPut(sOutput, "UTF-16")*2, 0)
		StrPut(sOutput, &wOutput, "UTF-16")
		pOutput := &wOutput
	}
	E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, pOutput, Ptr, pCodec, UInt, 0)
	return E ? -5 : 0
}

BitmapToBase64(pBitmap, NOCRLF, byref Base64) {  
	DllCall("gdiplus\GdipGetImageEncodersSize", UintP, nCount, UintP, nSize) 
	VarSetCapacity(ci, nSize)
	DllCall("gdiplus\GdipGetImageEncoders", UInt, nCount, UInt, nSize, Ptr, &ci)
	if !(nCount && nSize)
		return -2 
	Loop, % nCount  {
		sString := StrGet(NumGet(ci, (idx := (48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize), "UTF-16")
		if !InStr(sString, "*." "PNG")
			continue
		pCodec := &ci+idx
		break
	} 
	if !pCodec
		return -3  
	DllCall( "ole32\CreateStreamOnHGlobal", UInt, 0, Int, 1, PtrP, pStream )
	if !E := DllCall( "gdiplus\GdipSaveImageToStream", Ptr, pBitmap, Ptr, pStream, Ptr, pCodec, UInt, 0)  {
		DllCall( "ole32\GetHGlobalFromStream", Ptr, pStream, PtrP, hData )
		pData := DllCall( "GlobalLock", Ptr, hData, Ptr )
		nSize := DllCall( "GlobalSize", Ptr, hData, Ptr )
		VarSetCapacity( buff, 0), VarSetCapacity( buff, nSize, 0 )
		DllCall( "RtlMoveMemory", Ptr, &buff, Ptr, pData, UInt, nSize )
		DllCall( "GlobalUnlock", Ptr, hData )
		DllCall( "GlobalFree", Ptr, hData )
	}
	ObjRelease(pStream)  
	Base64 := CryptBinaryToStringBASE64(&buff, nSize, NOCRLF)
	return 0
}  

FormatBase64ToVaribles(Base64, Name, LenRow = 128) {
	DATALen := StrLen(Base64)
	RowLen := !LenRow ? 16000 : LenRow
	If (RowLen = 16000) || (RowLen >= DATALen)
		Return DataToVarExp(Base64, Name, DATALen)
	Step := 0, Pos := 1  
	If !LenRow
	{
		Loop % Ceil(DATALen / RowLen)
		{
			Str .= SubStr(Base64, Pos, RowLen)
			Pos += RowLen
			If (Pos < DATALen)
				Str .= "`n" Name " = %" Name "%"
		}
		Return Name " = " Str
	} 
	Loop % Ceil(DATALen / RowLen)
	{   
		Str .= SubStr(Base64, Pos, RowLen) "`n" 
		Pos += RowLen, ++Step
		If (Pos >= DATALen || Step * RowLen >= 16000)
			Step := 0, Str .= ")" . (Pos < DATALen ? "`n" Name " = %" Name "%`n(`n" : "")
	}
	Return Name " = `n(`n" Str
}	

DataToVarExp(Base64, Name, DATALen) {
	RowLen := 16000, Pos := 1   
	If (RowLen >= DATALen)
		Return Name " := """ Base64 """"
	Loop % Ceil(DATALen / RowLen)
	{
		p := SubStr(Base64, Pos, RowLen) 
		Pos += RowLen
		Str .= "`n" Name " .= """ p """"
	}
	Return StrReplace(Str, " .= """, " := """, , 1) 
}	

CryptBinaryToStringBASE64(pData, Bytes, NOCRLF = "")  {
   static CRYPT_STRING_BASE64 := 1, CRYPT_STRING_NOCRLF := 0x40000000
   CRYPT := CRYPT_STRING_BASE64 | (NOCRLF ? CRYPT_STRING_NOCRLF : 0)
   
   DllCall("Crypt32\CryptBinaryToString", Ptr, pData, UInt, Bytes, UInt, CRYPT, Ptr, 0, UIntP, Chars)
   VarSetCapacity(OutData, Chars * (A_IsUnicode ? 2 : 1), 0)
   DllCall("Crypt32\CryptBinaryToString", Ptr, pData, UInt, Bytes, UInt, CRYPT, Str, OutData, UIntP, Chars)
   Return OutData
}
	; ___________________________ End _________________________________________________

	;;)
	
	
	
	
	
	
	
	
/*
инжект
		http://forum.script-coding.com/viewtopic.php?pid=154638#p154638
		
DllCall\(.*Ptr\*


comobjerror(false)
loop
	{
		Acc_test(child).accName(child)
	   tooltip %  "`n" Acc_test(child).accDefaultAction(child) "`n" A_LastError
	}


Acc_test(ByRef _idChild_ = "", x = "", y = "")
{
	Static	h
	If Not	h
		h:=DllCall("LoadLibrary","Str","oleacc","Ptr")
	If	DllCall("oleacc\AccessibleObjectFromPoint", "Int64", x==""||y==""?0*DllCall("GetCursorPos","Int64*",pt)+pt:x&0xFFFFFFFF|y<<32, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
	Return	ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}


01:58 20.01.2021
Добавить кнопку обновить данные
	
	
	

#If isAhkSpy && Sleep != 1 && WinActive("ahk_id" hGui)

1::
  

WinSet, ExStyle, +%WS_EX_TRANSPARENT%, ahk_id %hGui%
Return
2::
  

WinSet, ExStyle, -%WS_EX_TRANSPARENT%, ahk_id %hGui%
Return



*/

  

 

;
; Window Spy
;

#NoEnv
#NoTrayIcon
#SingleInstance Ignore
SetWorkingDir, %A_ScriptDir%
SetBatchLines, -1
CoordMode, Pixel, Screen

txtNotFrozen := "(Hold Ctrl or Shift to suspend updates)"
txtFrozen := "(Updates suspended)"
txtMouseCtrl := "Control Under Mouse Position"
txtFocusCtrl := "Focused Control"

Gui, New, hwndhGui AlwaysOnTop Resize MinSize
Gui, Add, Text,, Window Title, Class and Process:
Gui, Add, Checkbox, yp xp+200 w120 Right vCtrl_FollowMouse, Follow Mouse
Gui, Add, Edit, xm w320 r4 ReadOnly -Wrap vCtrl_Title
Gui, Add, Text,, Mouse Position:
Gui, Add, Edit, w320 r4 ReadOnly vCtrl_MousePos
Gui, Add, Text, w320 vCtrl_CtrlLabel, % txtFocusCtrl ":"
Gui, Add, Edit, w320 r4 ReadOnly vCtrl_Ctrl
Gui, Add, Text,, Active Window Position:
Gui, Add, Edit, w320 r2 ReadOnly vCtrl_Pos
Gui, Add, Text,, Status Bar Text:
Gui, Add, Edit, w320 r2 ReadOnly vCtrl_SBText
Gui, Add, Checkbox, vCtrl_IsSlow, Slow TitleMatchMode
Gui, Add, Text,, Visible Text:
Gui, Add, Edit, w320 r2 ReadOnly vCtrl_VisText
Gui, Add, Text,, All Text:
Gui, Add, Edit, w320 r2 ReadOnly vCtrl_AllText
Gui, Add, Text, w320 r1 vCtrl_Freeze, % txtNotFrozen
Gui, Show, NoActivate, Window Spy
GetClientSize(hGui, temp)
horzMargin := temp*96//A_ScreenDPI - 320
SetTimer, Update, 250
return

GuiSize:
Gui %hGui%:Default
if !horzMargin
	return
SetTimer, Update, % A_EventInfo=1 ? "Off" : "On" ; Suspend on minimize
ctrlW := A_GuiWidth - horzMargin
list = Title,MousePos,Ctrl,Pos,SBText,VisText,AllText,Freeze
Loop, Parse, list, `,
	GuiControl, Move, Ctrl_%A_LoopField%, w%ctrlW%
return

Update:
Gui %hGui%:Default
GuiControlGet, Ctrl_FollowMouse
CoordMode, Mouse, Screen
MouseGetPos, msX, msY, msWin, msCtrl
actWin := WinExist("A")
if Ctrl_FollowMouse
{
	curWin := msWin
	curCtrl := msCtrl
	WinExist("ahk_id " curWin)
}
else
{
	curWin := actWin
	ControlGetFocus, curCtrl
}
WinGetTitle, t1
WinGetClass, t2
if (curWin = hGui || t2 = "MultitaskingViewFrame") ; Our Gui || Alt-tab
{
	UpdateText("Ctrl_Freeze", txtFrozen)
	return
}
UpdateText("Ctrl_Freeze", txtNotFrozen)
WinGet, t3, ProcessName
WinGet, t4, PID
UpdateText("Ctrl_Title", t1 "`nahk_class " t2 "`nahk_exe " t3 "`nahk_pid " t4)
CoordMode, Mouse, Relative
MouseGetPos, mrX, mrY
CoordMode, Mouse, Client
MouseGetPos, mcX, mcY
PixelGetColor, mClr, %msX%, %msY%, RGB
mClr := SubStr(mClr, 3)
UpdateText("Ctrl_MousePos", "Screen:`t" msX ", " msY " (less often used)`nWindow:`t" mrX ", " mrY " (default)`nClient:`t" mcX ", " mcY " (recommended)"
	. "`nColor:`t" mClr " (Red=" SubStr(mClr, 1, 2) " Green=" SubStr(mClr, 3, 2) " Blue=" SubStr(mClr, 5) ")")
UpdateText("Ctrl_CtrlLabel", (Ctrl_FollowMouse ? txtMouseCtrl : txtFocusCtrl) ":")
if (curCtrl)
{
	ControlGetText, ctrlTxt, %curCtrl%
	cText := "ClassNN:`t" curCtrl "`nText:`t" textMangle(ctrlTxt)
    ControlGetPos cX, cY, cW, cH, %curCtrl%
    cText .= "`n`tx: " cX "`ty: " cY "`tw: " cW "`th: " cH
    WinToClient(curWin, cX, cY)
	ControlGet, curCtrlHwnd, Hwnd,, % curCtrl
    GetClientSize(curCtrlHwnd, cW, cH)
    cText .= "`nClient:`tx: " cX "`ty: " cY "`tw: " cW "`th: " cH
}
else
	cText := ""
UpdateText("Ctrl_Ctrl", cText)
WinGetPos, wX, wY, wW, wH
GetClientSize(curWin, wcW, wcH)
UpdateText("Ctrl_Pos", "`tx: " wX "`ty: " wY "`tw: " wW "`th: " wH "`nClient:`tx: 0`ty: 0`tw: " wcW "`th: " wcH)
sbTxt := ""
Loop
{
	StatusBarGetText, ovi, %A_Index%
	if ovi =
		break
	sbTxt .= "(" A_Index "):`t" textMangle(ovi) "`n"
}
StringTrimRight, sbTxt, sbTxt, 1
UpdateText("Ctrl_SBText", sbTxt)
GuiControlGet, bSlow,, Ctrl_IsSlow
if bSlow
{
	DetectHiddenText, Off
	WinGetText, ovVisText
	DetectHiddenText, On
	WinGetText, ovAllText
}
else
{
	ovVisText := WinGetTextFast(false)
	ovAllText := WinGetTextFast(true)
}
UpdateText("Ctrl_VisText", ovVisText)
UpdateText("Ctrl_AllText", ovAllText)
return

GuiClose:
ExitApp

WinGetTextFast(detect_hidden)
{
	; WinGetText ALWAYS uses the "Slow" mode - TitleMatchMode only affects the
	; WinText/ExcludeText parameters.  In "Fast" mode, GetWindowText() is used
	; to retrieve the text of each control.
	WinGet controls, ControlListHwnd
	static WINDOW_TEXT_SIZE := 32767 ; Defined in AutoHotkey source.
	VarSetCapacity(buf, WINDOW_TEXT_SIZE * (A_IsUnicode ? 2 : 1))
	text := ""
	Loop Parse, controls, `n
	{
		if !detect_hidden && !DllCall("IsWindowVisible", "ptr", A_LoopField)
			continue
		if !DllCall("GetWindowText", "ptr", A_LoopField, "str", buf, "int", WINDOW_TEXT_SIZE)
			continue
		text .= buf "`r`n"
	}
	return text
}

UpdateText(ControlID, NewText)
{
	; Unlike using a pure GuiControl, this function causes the text of the
	; controls to be updated only when the text has changed, preventing periodic
	; flickering (especially on older systems).
	static OldText := {}
	global hGui
	if (OldText[ControlID] != NewText)
	{
		GuiControl, %hGui%:, % ControlID, % NewText
		OldText[ControlID] := NewText
	}
}

GetClientSize(hWnd, ByRef w := "", ByRef h := "")
{
	VarSetCapacity(rect, 16)
	DllCall("GetClientRect", "ptr", hWnd, "ptr", &rect)
	w := NumGet(rect, 8, "int")
	h := NumGet(rect, 12, "int")
}

WinToClient(hWnd, ByRef x, ByRef y)
{
    WinGetPos wX, wY,,, ahk_id %hWnd%
    x += wX, y += wY
    VarSetCapacity(pt, 8), NumPut(y, NumPut(x, pt, "int"), "int")
    if !DllCall("ScreenToClient", "ptr", hWnd, "ptr", &pt)
        return false
    x := NumGet(pt, 0, "int"), y := NumGet(pt, 4, "int")
    return true
}

textMangle(x)
{
	if pos := InStr(x, "`n")
		x := SubStr(x, 1, pos-1), elli := true
	if StrLen(x) > 40
	{
		StringLeft, x, x, 40
		elli := true
	}
	if elli
		x .= " (...)"
	return x
}

~*Ctrl::
~*Shift::
SetTimer, Update, Off
UpdateText("Ctrl_Freeze", txtFrozen)
return

~*Ctrl up::
~*Shift up::
SetTimer, Update, On
return

  

  

 

posted @ 2025-04-01 13:38  QQ595076941  阅读(114)  评论(1)    收藏  举报
595076941@qq.com