51

Re: AHK: Переводчик онлайн

Нет, не показывает.

52

Re: AHK: Переводчик онлайн

А в переменных до выхода из TrackToolTip()

BallonTip[1 of 3]: 0
DHW[3 of 3]: Off
H[2 of 3]: 32
h_icon[1 of 3]: 0
hWnd[7 of 7]: 2032904
nColorBack[8 of 63]: 16777185
nColorText[1 of 3]: 0
sText[14 of 63]: Тестовый текст
sTitle[9 of 63]: Заголовок
TOOLINFO[1 of 30]: <
TTS_ALWAYSTIP[1 of 3]: 1
TTS_BALLOON[4 of 7]: 0x40
TTS_CLOSE[4 of 7]: 0x80
TTS_NOPREFIX[1 of 3]: 2
w[3 of 3]: 126
WS_EX_TOPMOST[1 of 3]: 8
x[0 of 0]:  
xtt[2 of 3]: 43
y[0 of 0]:  
ytt[3 of 3]: 129

53

Re: AHK: Переводчик онлайн

А вот эти переменные я не понимаю куда вписывать.

54

Re: AHK: Переводчик онлайн

Ненужно их вписывать, это лишь для информации, мол, hWnd есть, видимо sendmessage не доходят

55

Re: AHK: Переводчик онлайн

Ну ладно, временно оставим TrackToolTip(). Проверим другое. Следующий код должен дать перевод слова "test" в обычном тултипе. Проверяем на win64.

#Persistent
URL := "http://translate.google.com/translate_a/t?client=x&sl=en&tl=ru&text=test"
ToolTip, % GetTranslate(URL, from)

GetTranslate(Url, byref from, ReadDict = 1)
{
   if !JsonTrans := UrlDownloadToVar(Url, "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.8.131 Version/11.10")
   {
      TrackToolTip("Нет ответа от сервера.`nПроверьте соединение с интернетом!", "Ошибка!", 3)
      Return
   }

   from:=JSON(JsonTrans, "src")

   While Sentence := JSON(JsonTrans, "sentences[" A_Index - 1 "].trans")
      TransText .= Sentence

   if (ReadDict && JSON(JsonTrans, "dict[0].terms[0]"))
   {
      While JSON(JsonTrans, "dict[" A_Index - 1 "]")
      {
         i := A_Index - 1
         While d := JSON(JsonTrans, "dict[" i "].terms[" A_Index - 1 "]")
            if (d != TransText)
               dict .= d . "; " . (!Mod(A_Index, 3) ? "`n" : "")
      }
      StringTrimRight, dict, dict, 2
   }

   dict ? TransText.= "`n+`n" dict

   StringReplace, TransText, TransText, \r\n,`r`n, All
   StringReplace, TransText, TransText, \", ", All
   StrPutVar(TransText, Buff)
   Return StrGet(&Buff, "UTF-8")
}

StrPutVar(string, ByRef var, encoding = "CP0")
{
    ; Ensure capacity.
    VarSetCapacity( var, StrPut(string, encoding)
        ; StrPut returns char count, but VarSetCapacity needs bytes.
        * ((encoding="utf-16"||encoding="cp1200") ? 2 : 1) )
    ; Copy or convert the string.
    return StrPut(string, &var, encoding)
}

UrlDownloadToVar(URL, UserAgent = "", Proxy = "", ProxyBypass = "") {
    ; Requires Windows Vista, Windows XP, Windows 2000 Professional, Windows NT Workstation 4.0,
    ; Windows Me, Windows 98, or Windows 95.
    ; Requires Internet Explorer 3.0 or later.
    pFix:=a_isunicode ? "W" : "A"
    hModule := DllCall("LoadLibrary", "Str", "wininet.dll")

    AccessType := Proxy != "" ? 3 : 1
    ;INTERNET_OPEN_TYPE_PRECONFIG                    0   // use registry configuration
    ;INTERNET_OPEN_TYPE_DIRECT                       1   // direct to net
    ;INTERNET_OPEN_TYPE_PROXY                        3   // via named proxy
    ;INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY  4   // prevent using java/script/INS

    io := DllCall("wininet\InternetOpen" . pFix
    , "Str", UserAgent ;lpszAgent
    , "UInt", AccessType
    , "Str", Proxy
    , "Str", ProxyBypass
    , "UInt", 0) ;dwFlags

    iou := DllCall("wininet\InternetOpenUrl" . pFix
    , "UInt", io
    , "Str", url
    , "Str", "" ;lpszHeaders
    , "UInt", 0 ;dwHeadersLength
    , "UInt", 0x80000000 ;dwFlags: INTERNET_FLAG_RELOAD = 0x80000000 // retrieve the original item
    , "UInt", 0) ;dwContext

    If (ErrorLevel != 0 or iou = 0) {
        DllCall("FreeLibrary", "UInt", hModule)
        return 0
    }

    VarSetCapacity(buffer, 10240, 0)
    VarSetCapacity(BytesRead, 4, 0)

    Loop
    {
        ;http://msdn.microsoft.com/library/en-us/wininet/wininet/internetreadfile.asp
        irf := DllCall("wininet\InternetReadFile", "UInt", iou, Ptr, &buffer, "UInt", 10240, Ptr, &BytesRead)
        VarSetCapacity(buffer, -1) ;to update the variable's internally-stored length

        BytesRead_ = 0 ; reset
        Loop, 4  ; Build the integer by adding up its bytes. (From ExtractInteger-function)
            BytesRead_ += *(&BytesRead + A_Index-1) << 8*(A_Index-1) ;Bytes read in this very DllCall

        ; To ensure all data is retrieved, an application must continue to call the
        ; InternetReadFile function until the function returns TRUE and the lpdwNumberOfBytesRead parameter equals zero.
        If (irf = 1 and BytesRead_ = 0)
            break
        Else ; append the buffer's contents
        {
            a_isunicode ? buffer:=StrGet(&buffer, "CP0")
            Result .= SubStr(buffer, 1, BytesRead_ * (a_isunicode ? 2 : 1))
        }

        /* optional: retrieve only a part of the file
        BytesReadTotal += BytesRead_
        If (BytesReadTotal >= 30000) ; only read the first x bytes
        break                      ; (will be a multiple of the buffer size, if the file is not smaller; trim if neccessary)
        */
    }

    DllCall("wininet\InternetCloseHandle",  "UInt", iou)
    DllCall("wininet\InternetCloseHandle",  "UInt", io)
    DllCall("FreeLibrary", "UInt", hModule)
   Return Result
}

JSON(ByRef js, s, v = "") {
   j = %js%
   Loop, Parse, s, .
   {
      p = 2
      RegExMatch(A_LoopField, "([+\-]?)([^[]+)((?:\[\d+\])*)", q)
      Loop {
         If (!p := RegExMatch(j
            , "(?<!\\)(""|')([^\1]+?)(?<!\\)(?-1)\s*:\s*((\{(?:[^{}]++|(?-1))*\})|(\[(?:[^[\]]++|(?-1))*\])|"
            . "(?<!\\)(""|')[^\7]*?(?<!\\)(?-1)|[+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:,|$|\})", x, p))
            Return
         Else If (x2 == q2 or q2 == "*") {
            j = %x3%
            z += p + StrLen(x2) - 2
            If (q3 != "" and InStr(j, "[") == 1) {
               StringTrimRight, q3, q3, 1
               Loop, Parse, q3, ], [
               {
                  z += 1 + RegExMatch(SubStr(j, 2, -1)
                     , "^(?:\s*((\[(?:[^[\]]++|(?-1))*\])|(\{(?:[^{\}]++|(?-1))*\})|[^,]*?)\s*(?:,|$)){"
                     . SubStr(A_LoopField, 1) + 1 . "}", x)
                  j = %x1%
               }
            }
            Break
         }
         Else p += StrLen(x)
      }
   }
   If v !=
   {
      vs = "
      If (RegExMatch(v, "^\s*(?:""|')*\s*([+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:""|')*\s*$", vx)
         and (vx1 + 0 or vx1 == 0 or vx1 == "true" or vx1 == "false" or vx1 == "null" or vx1 == "nul"))
         vs := "", v := vx1
      StringReplace, v, v, ", \", All
      js := SubStr(js, 1, z := RegExMatch(js, ":\s*", zx, z) + StrLen(zx) - 1)
         . vs . v . vs . SubStr(js, z + StrLen(x3) + 1)
   }
   Return, j == "false" ? 0 : j == "true" ? 1 : j == "null" or j == "nul"
      ? "" : SubStr(j, 1, 1) == """" ? SubStr(j, 2, -1) : j
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

56

Re: AHK: Переводчик онлайн

Да, ToolTip присутствует, перевод отображается.

57

Re: AHK: Переводчик онлайн

Нашёл ещё ошибку в TrackToolTip(). Проверьте:

#Persistent
TrackToolTip("Тест", "Заголовок")

TrackToolTip( sText
            , sTitle = ""
            , h_icon = 0   ; h_icon — 0: None, 1:Info, 2: Warning, 3: Error, n > 3: предполагается hIcon
            , nColorBack = 0xFFFFE1
            , nColorText = 0
            , BallonTip = 0   ; BalloonTip — это ToolTip с хвостиком
            , x = ""   ; если не указаны, то вблизи курсора
            , y = ""
            , w = 400)  ; максимальная ширина
{
   TTS_NOPREFIX := 2, TTS_ALWAYSTIP := 1, TTS_BALLOON := 0x40, TTS_CLOSE := 0x80

   hWnd := DllCall("CreateWindowEx", UInt, WS_EX_TOPMOST := 8
                                   , Str, "tooltips_class32", Str, ""
                                   , UInt, TTS_NOPREFIX|TTS_ALWAYSTIP|TTS_CLOSE|(BallonTip ? TTS_BALLOON : 0)
                                   , Int, 0, Int, 0, Int, 0, Int, 0
                                   , UInt, 0, UInt, 0, UInt, 0, UInt, 0)
   if (x = "" || y = "")
   {
      CoordMode, Mouse
      MouseGetPos, xtt, ytt
      xtt := x = "" ? xtt + 10 : x
      ytt := y = "" ? ytt + 10 : y
   }
   Else
      xtt := x, ytt := y

   NumPut(VarSetCapacity(TOOLINFO, A_PtrSize = 4 ? 48 : 60, 0), TOOLINFO)
   NumPut(0x20, TOOLINFO, 4)      ; TTF_TRACK = 0x20
   NumPut(&sText, TOOLINFO, A_PtrSize = 4 ? 36 : 40)

   DHW := A_DetectHiddenWindows
   DetectHiddenWindows, On
   WinWait, ahk_id %hWnd%

   WM_USER := 0x400
   SendMessage, WM_USER + 24,, w         ; TTM_SETMAXTIPWIDTH
   SendMessage, WM_USER + (A_IsUnicode ? 50 : 4),, &TOOLINFO   ; TTM_ADDTOOL
   SendMessage, WM_USER + 19, RGB_to_BGR(nColorBack)   ; TTM_SETTIPBKCOLOR
   SendMessage, WM_USER + 20, RGB_to_BGR(nColorText)   ; TTM_SETTIPTEXTCOLOR
   SendMessage, WM_USER + (A_IsUnicode ? 33 : 32), h_icon, &sTitle      ; TTM_SETTITLEA и TTM_SETTITLEW
   SendMessage, WM_USER + (A_IsUnicode ? 57 : 12),, &TOOLINFO     ; TTM_UPDATETIPTEXTA и TTM_UPDATETIPTEXTW
   SendMessage, WM_USER + 18,, xtt|(ytt<<16)   ; TTM_TRACKPOSITION
   SendMessage, WM_USER + 17, 1, &TOOLINFO ; TTM_TRACKACTIVATE

   WinGetPos,,, W, H
   if (xtt + W + 10 > A_ScreenWidth || ytt + H + 10 > A_ScreenHeight)
   {
      WinHide
      xtt := xtt + W + 10 > A_ScreenWidth ? A_ScreenWidth - W - 10 : xtt
      ytt := ytt + H + 10 > A_ScreenHeight ? A_ScreenHeight - H - 10 : ytt
      SendMessage, 1042,, xtt|(ytt<<16)   ; TTM_TRACKPOSITION
      WinShow
   }

   DetectHiddenWindows, % DHW
   Return hWnd
}

RGB_to_BGR(RGB)
{
   CurrentFormat := A_FormatInteger
   SetFormat, IntegerFast, H
   C := SubStr("0x000000", 1, -(StrLen(RGB+0) - 2)) . SubStr(RGB+0, 3)
   BGR := RegExReplace(C, "0x(..)(..)(..)", "0x$3$2$1")
   SetFormat, IntegerFast, %CurrentFormat%
   Return BGR
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

58

Re: AHK: Переводчик онлайн

Проверено, ToolTip не отобразился.

59 (изменено: Someone, 2012-03-12 19:43:00)

Re: AHK: Переводчик онлайн

Просто у кого-то с математикой плохо.

http://i.imgur.com/ja6Sm.png

Вот так все отображается и в x86 и в x64:


#Persistent
TrackToolTip("Тест", "Заголовок")
 
TrackToolTip( sText
            , sTitle = ""
            , h_icon = 0   ; h_icon — 0: None, 1:Info, 2: Warning, 3: Error, n > 3: предполагается hIcon
            , nColorBack = 0xFFFFE1
            , nColorText = 0
            , BallonTip = 0   ; BalloonTip — это ToolTip с хвостиком
            , x = ""   ; если не указаны, то вблизи курсора
            , y = ""
            , w = 400)  ; максимальная ширина
{
   TTS_NOPREFIX := 2, TTS_ALWAYSTIP := 1, TTS_BALLOON := 0x40, TTS_CLOSE := 0x80
 
   hWnd := DllCall("CreateWindowEx", UInt, WS_EX_TOPMOST := 8
                                   , Str, "tooltips_class32", Str, ""
                                   , UInt, TTS_NOPREFIX|TTS_ALWAYSTIP|TTS_CLOSE|(BallonTip ? TTS_BALLOON : 0)
                                   , Int, 0, Int, 0, Int, 0, Int, 0
                                   , Ptr, 0, Ptr, 0, Ptr, 0, Ptr, 0)

   if (x = "" || y = "")
   {
      CoordMode, Mouse
      MouseGetPos, xtt, ytt
      xtt := x = "" ? xtt + 10 : x
      ytt := y = "" ? ytt + 10 : y
   }
   Else
      xtt := x, ytt := y
 
   NumPut(VarSetCapacity(TOOLINFO, A_PtrSize = 4 ? 48 : 72, 0), TOOLINFO)
   NumPut(0x20, TOOLINFO, 4)      ; TTF_TRACK = 0x20
   NumPut(&sText, TOOLINFO, A_PtrSize = 4 ? 36 : 48)
 
   DHW := A_DetectHiddenWindows
   DetectHiddenWindows, On
   WinWait, ahk_id %hWnd%
 
   WM_USER := 0x400
   SendMessage, WM_USER + 24,, w         ; TTM_SETMAXTIPWIDTH
   SendMessage, WM_USER + (A_IsUnicode ? 50 : 4),, &TOOLINFO   ; TTM_ADDTOOL
   SendMessage, WM_USER + 19, RGB_to_BGR(nColorBack)   ; TTM_SETTIPBKCOLOR
   SendMessage, WM_USER + 20, RGB_to_BGR(nColorText)   ; TTM_SETTIPTEXTCOLOR
   SendMessage, WM_USER + (A_IsUnicode ? 33 : 32), h_icon, &sTitle      ; TTM_SETTITLEA и TTM_SETTITLEW
   SendMessage, WM_USER + (A_IsUnicode ? 57 : 12),, &TOOLINFO     ; TTM_UPDATETIPTEXTA и TTM_UPDATETIPTEXTW
   SendMessage, WM_USER + 18,, xtt|(ytt<<16)   ; TTM_TRACKPOSITION
   SendMessage, WM_USER + 17, 1, &TOOLINFO ; TTM_TRACKACTIVATE
 
   WinGetPos,,, W, H
   if (xtt + W + 10 > A_ScreenWidth || ytt + H + 10 > A_ScreenHeight)
   {
      WinHide
      xtt := xtt + W + 10 > A_ScreenWidth ? A_ScreenWidth - W - 10 : xtt
      ytt := ytt + H + 10 > A_ScreenHeight ? A_ScreenHeight - H - 10 : ytt
      SendMessage, 1042,, xtt|(ytt<<16)   ; TTM_TRACKPOSITION
      WinShow
   }
 
   DetectHiddenWindows, % DHW
   Return hWnd
}
 
RGB_to_BGR(RGB)
{
   CurrentFormat := A_FormatInteger
   SetFormat, IntegerFast, H
   C := SubStr("0x000000", 1, -(StrLen(RGB+0) - 2)) . SubStr(RGB+0, 3)
   BGR := RegExReplace(C, "0x(..)(..)(..)", "0x$3$2$1")
   SetFormat, IntegerFast, %CurrentFormat%
   Return BGR
}

60

Re: AHK: Переводчик онлайн

Вот и замечательно. Вариант ниже проверен на AHK_L x64 & x86 Unicode.


global ColorToolTip := 0xFFFFE1
global ColorText := 0x002288
 
#NoEnv
SetBatchLines, -1
 
; Menu, Tray, Icon, google.ico
OnMessage(0x201, "WM_LBUTTONDOWN")
Return
 
~^vk43:: DoublePress()
 
~LButton Up::
   MouseGetPos,,, ID
   WinGetClass, Class, ahk_id %ID%
   if (Class != "tooltips_class32")
      Return
 
   SendInput, {LButton Up}{LButton Down}{LButton Up}
   Return
 
DoublePress()
{
   static pressed1 = 0
   if pressed1 and A_TimeSincePriorHotkey <= 400
      pressed1 := 0, Translate()
   else
      pressed1 = 1
}
 
Translate(_from="", _to="")
{
   if Clipboard =
       return
 
   INTERNET_MAX_SCHEME_LENGTH := 32
   INTERNET_MAX_PATH_LENGTH := 2048
   INTERNET_MAX_URL_LENGTH := INTERNET_MAX_SCHEME_LENGTH + StrLen("://")+ INTERNET_MAX_PATH_LENGTH
 
   if (_from = "" && _to = "")
   {
      cyr := RegExMatch(Clipboard, "[А-Яа-я]")
      from := cyr ? "ru" : "auto", to := cyr ? "en" : "ru"
   }
   else
      from := _from, to := _to
 
   PreUrl := "http://translate.google.com/translate_a/t?client=x&sl=" . from . "&tl=" . to . "&text="
   Url := PreUrl . URIEncode(Clipboard)
 
   if StrLen(Url) > INTERNET_MAX_URL_LENGTH
   {
      StartPos := 1
      While RegExMatch(Clipboard, "O)(.*?[\.\?!])(([^\.\?!]*?)[^ \t\n\r]|$)", Found, StartPos)
      {
         StartPos := Found.Pos(1) + Found.Len(1)
         Url := PreUrl . URIEncode(Found.Value(1))
         Delimiter := Found.Value(3)
         if StrLen(Url) > INTERNET_MAX_URL_LENGTH
         {
            MsgBox, 20, Ошибка!, % "Предложение """ Text%A_Index% . "." . """ слишком велико.`nПродолжить?"
            IfMsgBox, Yes
               Continue
            Else
               Break
         }
         TransText .= GetTranslate(Url, from, 0) . Delimiter
      }
   }
   Else
      TransText := GetTranslate(Url, from)
 
   TrackToolTip(TransText, from ">" to, 0, ColorToolTip, ColorText)
}
 
URIEncode(Str)
{
   b_Format:=A_FormatInteger
   SetFormat, Integer, Hex
   Loop, % StrPutVar(Str, Var, "UTF-8")
   {
      Ch:=NumGet(Var, A_Index-1, "UChar")
      If Ch=0
         Break
      If (Ch>0x7f Or Ch<0x30 Or Ch=0x3d)
         s.="%"((StrLen(c:=SubStr(Ch, 3))<2) ? "0"c:c)
      Else
         s.=Chr(Ch)
   }
   SetFormat, Integer, % b_Format
   Return, s
}
 
GetTranslate(Url, byref from, ReadDict = 1)
{
   if !JsonTrans := UrlDownloadToVar(Url, "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.8.131 Version/11.10")
   {
      TrackToolTip("Нет ответа от сервера.`nПроверьте соединение с интернетом!", "Ошибка!", 3)
      Return
   }
 
   from:=JSON(JsonTrans, "src")
 
   While Sentence := JSON(JsonTrans, "sentences[" A_Index - 1 "].trans")
      TransText .= Sentence
 
   if (ReadDict && JSON(JsonTrans, "dict[0].terms[1]"))
   {
      While JSON(JsonTrans, "dict[" A_Index - 1 "]")
      {
         i := A_Index - 1
         While d := JSON(JsonTrans, "dict[" i "].terms[" A_Index - 1 "]")
            if (d != TransText)
               dict .= d . "; "
      }
      StringTrimRight, dict, dict, 2
   }
 
   dict ? TransText.= "`n+`n" dict
 
   StringReplace, TransText, TransText, \r\n,`r`n, All
   StringReplace, TransText, TransText, \", ", All
   StrPutVar(TransText, Buff)
   Return StrGet(&Buff, "UTF-8")
}
 
WM_LBUTTONDOWN()
{
   PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}
 
 
TrackToolTip( sText
            , sTitle = ""
            , h_icon = 0   ; h_icon — 0: None, 1:Info, 2: Warning, 3: Error, n > 3: предполагается hIcon
            , nColorBack = 0xFFFFE1
            , nColorText = 0
            , BallonTip = 0   ; BalloonTip — это ToolTip с хвостиком
            , x = ""   ; если не указаны, то вблизи курсора
            , y = ""
            , w = 400)  ; максимальная ширина
{
   TTS_NOPREFIX := 2, TTS_ALWAYSTIP := 1, TTS_BALLOON := 0x40, TTS_CLOSE := 0x80
 
   hWnd := DllCall("CreateWindowEx", UInt, WS_EX_TOPMOST := 8
                                   , Str, "tooltips_class32", Str, ""
                                   , UInt, TTS_NOPREFIX|TTS_ALWAYSTIP|TTS_CLOSE|(BallonTip ? TTS_BALLOON : 0)
                                   , Int, 0, Int, 0, Int, 0, Int, 0
                                   , Ptr, 0, Ptr, 0, Ptr, 0, Ptr, 0)
 
   if (x = "" || y = "")
   {
      CoordMode, Mouse
      MouseGetPos, xtt, ytt
      xtt := x = "" ? xtt + 10 : x
      ytt := y = "" ? ytt + 10 : y
   }
   Else
      xtt := x, ytt := y
 
   NumPut(VarSetCapacity(TOOLINFO, A_PtrSize = 4 ? 48 : 72, 0), TOOLINFO)
   NumPut(0x20, TOOLINFO, 4)      ; TTF_TRACK = 0x20
   NumPut(&sText, TOOLINFO, A_PtrSize = 4 ? 36 : 48)
 
   DHW := A_DetectHiddenWindows
   DetectHiddenWindows, On
   WinWait, ahk_id %hWnd%
 
   WM_USER := 0x400
   SendMessage, WM_USER + 24,, w         ; TTM_SETMAXTIPWIDTH
   SendMessage, WM_USER + (A_IsUnicode ? 50 : 4),, &TOOLINFO   ; TTM_ADDTOOL
   SendMessage, WM_USER + 19, RGB_to_BGR(nColorBack)   ; TTM_SETTIPBKCOLOR
   SendMessage, WM_USER + 20, RGB_to_BGR(nColorText)   ; TTM_SETTIPTEXTCOLOR
   SendMessage, WM_USER + (A_IsUnicode ? 33 : 32), h_icon, &sTitle      ; TTM_SETTITLEA и TTM_SETTITLEW
   SendMessage, WM_USER + (A_IsUnicode ? 57 : 12),, &TOOLINFO     ; TTM_UPDATETIPTEXTA и TTM_UPDATETIPTEXTW
   SendMessage, WM_USER + 18,, xtt|(ytt<<16)   ; TTM_TRACKPOSITION
   SendMessage, WM_USER + 17, 1, &TOOLINFO ; TTM_TRACKACTIVATE
 
   WinGetPos,,, W, H
   if (xtt + W + 10 > A_ScreenWidth || ytt + H + 10 > A_ScreenHeight)
   {
      WinHide
      xtt := xtt + W + 10 > A_ScreenWidth ? A_ScreenWidth - W - 10 : xtt
      ytt := ytt + H + 10 > A_ScreenHeight ? A_ScreenHeight - H - 10 : ytt
      SendMessage, 1042,, xtt|(ytt<<16)   ; TTM_TRACKPOSITION
      WinShow
   }
 
   DetectHiddenWindows, % DHW
   Return hWnd
}
 
RGB_to_BGR(RGB)
{
   CurrentFormat := A_FormatInteger
   SetFormat, IntegerFast, H
   C := SubStr("0x000000", 1, -(StrLen(RGB+0) - 2)) . SubStr(RGB+0, 3)
   BGR := RegExReplace(C, "0x(..)(..)(..)", "0x$3$2$1")
   SetFormat, IntegerFast, %CurrentFormat%
   Return BGR
}
 
StrPutVar(string, ByRef var, encoding = "CP0")
{
    ; Ensure capacity.
    VarSetCapacity( var, StrPut(string, encoding)
        ; StrPut returns char count, but VarSetCapacity needs bytes.
        * ((encoding="utf-16"||encoding="cp1200") ? 2 : 1) )
    ; Copy or convert the string.
    return StrPut(string, &var, encoding)
}
 
UrlDownloadToVar(URL, UserAgent = "", Proxy = "", ProxyBypass = "") {
    ; Requires Windows Vista, Windows XP, Windows 2000 Professional, Windows NT Workstation 4.0,
    ; Windows Me, Windows 98, or Windows 95.
    ; Requires Internet Explorer 3.0 or later.
    pFix:=a_isunicode ? "W" : "A"
    hModule := DllCall("LoadLibrary", "Str", "wininet.dll")
 
    AccessType := Proxy != "" ? 3 : 1
    ;INTERNET_OPEN_TYPE_PRECONFIG                    0   // use registry configuration
    ;INTERNET_OPEN_TYPE_DIRECT                       1   // direct to net
    ;INTERNET_OPEN_TYPE_PROXY                        3   // via named proxy
    ;INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY  4   // prevent using java/script/INS
 
    io := DllCall("wininet\InternetOpen" . pFix
    , "Str", UserAgent ;lpszAgent
    , "UInt", AccessType
    , "Str", Proxy
    , "Str", ProxyBypass
    , "UInt", 0) ;dwFlags
 
    iou := DllCall("wininet\InternetOpenUrl" . pFix
    , "UInt", io
    , "Str", url
    , "Str", "" ;lpszHeaders
    , "UInt", 0 ;dwHeadersLength
    , "UInt", 0x80000000 ;dwFlags: INTERNET_FLAG_RELOAD = 0x80000000 // retrieve the original item
    , "UInt", 0) ;dwContext
 
    If (ErrorLevel != 0 or iou = 0) {
        DllCall("FreeLibrary", "UInt", hModule)
        return 0
    }
 
    VarSetCapacity(buffer, 10240, 0)
    VarSetCapacity(BytesRead, 4, 0)
 
    Loop
    {
        ;http://msdn.microsoft.com/library/en-us/wininet/wininet/internetreadfile.asp
        irf := DllCall("wininet\InternetReadFile", "UInt", iou, Ptr, &buffer, "UInt", 10240, Ptr, &BytesRead)
        VarSetCapacity(buffer, -1) ;to update the variable's internally-stored length
 
        BytesRead_ = 0 ; reset
        Loop, 4  ; Build the integer by adding up its bytes. (From ExtractInteger-function)
            BytesRead_ += *(&BytesRead + A_Index-1) << 8*(A_Index-1) ;Bytes read in this very DllCall
 
        ; To ensure all data is retrieved, an application must continue to call the
        ; InternetReadFile function until the function returns TRUE and the lpdwNumberOfBytesRead parameter equals zero.
        If (irf = 1 and BytesRead_ = 0)
            break
        Else ; append the buffer's contents
        {
            a_isunicode ? buffer:=StrGet(&buffer, "CP0")
            Result .= SubStr(buffer, 1, BytesRead_ * (a_isunicode ? 2 : 1))
        }
 
        /* optional: retrieve only a part of the file
        BytesReadTotal += BytesRead_
        If (BytesReadTotal >= 30000) ; only read the first x bytes
        break                      ; (will be a multiple of the buffer size, if the file is not smaller; trim if neccessary)
        */
    }
 
    DllCall("wininet\InternetCloseHandle",  "UInt", iou)
    DllCall("wininet\InternetCloseHandle",  "UInt", io)
    DllCall("FreeLibrary", "UInt", hModule)
   Return Result
}
 
JSON(ByRef js, s, v = "") {
   j = %js%
   Loop, Parse, s, .
   {
      p = 2
      RegExMatch(A_LoopField, "([+\-]?)([^[]+)((?:\[\d+\])*)", q)
      Loop {
         If (!p := RegExMatch(j
            , "(?<!\\)(""|')([^\1]+?)(?<!\\)(?-1)\s*:\s*((\{(?:[^{}]++|(?-1))*\})|(\[(?:[^[\]]++|(?-1))*\])|"
            . "(?<!\\)(""|')[^\7]*?(?<!\\)(?-1)|[+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:,|$|\})", x, p))
            Return
         Else If (x2 == q2 or q2 == "*") {
            j = %x3%
            z += p + StrLen(x2) - 2
            If (q3 != "" and InStr(j, "[") == 1) {
               StringTrimRight, q3, q3, 1
               Loop, Parse, q3, ], [
               {
                  z += 1 + RegExMatch(SubStr(j, 2, -1)
                     , "^(?:\s*((\[(?:[^[\]]++|(?-1))*\])|(\{(?:[^{\}]++|(?-1))*\})|[^,]*?)\s*(?:,|$)){"
                     . SubStr(A_LoopField, 1) + 1 . "}", x)
                  j = %x1%
               }
            }
            Break
         }
         Else p += StrLen(x)
      }
   }
   If v !=
   {
      vs = "
      If (RegExMatch(v, "^\s*(?:""|')*\s*([+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:""|')*\s*$", vx)
         and (vx1 + 0 or vx1 == 0 or vx1 == "true" or vx1 == "false" or vx1 == "null" or vx1 == "nul"))
         vs := "", v := vx1
      StringReplace, v, v, ", \", All
      js := SubStr(js, 1, z := RegExMatch(js, ":\s*", zx, z) + StrLen(zx) - 1)
         . vs . v . vs . SubStr(js, z + StrLen(x3) + 1)
   }
   Return, j == "false" ? 0 : j == "true" ? 1 : j == "null" or j == "nul"
      ? "" : SubStr(j, 1, 1) == """" ? SubStr(j, 2, -1) : j
}

61

Re: AHK: Переводчик онлайн

Тогда уже так:


global ColorToolTip := 0xFFFFE1
global ColorText := 0x002288

#NoEnv
SetBatchLines, -1

; Menu, Tray, Icon, google.ico
OnMessage(0x201, "WM_LBUTTONDOWN")
Return

~^vk43:: DoublePress()

~LButton Up::
   MouseGetPos,,, ID
   WinGetClass, Class, ahk_id %ID%
   if (Class != "tooltips_class32")
      Return

   SendInput, {LButton Up}{LButton Down}{LButton Up}
   Return

DoublePress()
{
   static pressed1 = 0
   if pressed1 and A_TimeSincePriorHotkey <= 400
      pressed1 := 0, Translate()
   else
      pressed1 = 1
}

Translate(_from="", _to="")
{
   if Clipboard =
       return

   INTERNET_MAX_SCHEME_LENGTH := 32
   INTERNET_MAX_PATH_LENGTH := 2048
   INTERNET_MAX_URL_LENGTH := INTERNET_MAX_SCHEME_LENGTH + StrLen("://")+ INTERNET_MAX_PATH_LENGTH

   if (_from = "" && _to = "")
   {
      cyr := RegExMatch(Clipboard, "[А-Яа-я]")
      from := cyr ? "ru" : "auto", to := cyr ? "en" : "ru"
   }
   else
      from := _from, to := _to

   PreUrl := "http://translate.google.com/translate_a/t?client=x&sl=" . from . "&tl=" . to . "&text="
   Url := PreUrl . URIEncode(Clipboard)

   if StrLen(Url) > INTERNET_MAX_URL_LENGTH
   {
      StartPos := 1
      While RegExMatch(Clipboard, "O)(.*?[\.\?!])(([^\.\?!]*?)[^ \t\n\r]|$)", Found, StartPos)
      {
         StartPos := Found.Pos(1) + Found.Len(1)
         Url := PreUrl . URIEncode(Found.Value(1))
         Delimiter := Found.Value(3)
         if StrLen(Url) > INTERNET_MAX_URL_LENGTH
         {
            MsgBox, 20, Ошибка!, % "Предложение """ Text%A_Index% . "." . """ слишком велико.`nПродолжить?"
            IfMsgBox, Yes
               Continue
            Else
               Break
         }
         TransText .= GetTranslate(Url, from, 0) . Delimiter
      }
   }
   Else
      TransText := GetTranslate(Url, from)

   TrackToolTip(TransText, from ">" to, 0, ColorToolTip, ColorText)
}

URIEncode(Str)
{
   b_Format:=A_FormatInteger
   SetFormat, Integer, Hex
   Loop, % StrPutVar(Str, Var, "UTF-8")
   {
      Ch:=NumGet(Var, A_Index-1, "UChar")
      If Ch=0
         Break
      If (Ch>0x7f Or Ch<0x30 Or Ch=0x3d)
         s.="%"((StrLen(c:=SubStr(Ch, 3))<2) ? "0"c:c)
      Else
         s.=Chr(Ch)
   }
   SetFormat, Integer, % b_Format
   Return, s
}

GetTranslate(Url, byref from, ReadDict = 1)
{
   if !JsonTrans := UrlDownloadToVar(Url, "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.8.131 Version/11.10")
   {
      TrackToolTip("Нет ответа от сервера.`nПроверьте соединение с интернетом!", "Ошибка!", 3)
      Return
   }

   from:=JSON(JsonTrans, "src")

   While Sentence := JSON(JsonTrans, "sentences[" A_Index - 1 "].trans")
      TransText .= Sentence

   if (ReadDict && JSON(JsonTrans, "dict[0].terms[1]"))
   {
      While JSON(JsonTrans, "dict[" A_Index - 1 "]")
      {
         i := A_Index - 1
         While d := JSON(JsonTrans, "dict[" i "].terms[" A_Index - 1 "]")
            if (d != TransText)
               dict .= d . "; "
      }
      StringTrimRight, dict, dict, 2
   }

   dict ? TransText.= "`n+`n" dict

   StringReplace, TransText, TransText, \r\n,`r`n, All
   StringReplace, TransText, TransText, \", ", All
   StrPutVar(TransText, Buff)
   Return StrGet(&Buff, "UTF-8")
}

WM_LBUTTONDOWN()
{
   PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

TrackToolTip( sText
            , sTitle = ""
            , h_icon = 0   ; h_icon — 0: None, 1:Info, 2: Warning, 3: Error, n > 3: предполагается hIcon
            , nColorBack = 0xFFFFE1
            , nColorText = 0
            , BallonTip = 0   ; BalloonTip — это ToolTip с хвостиком
            , x = ""   ; если не указаны, то вблизи курсора
            , y = ""
            , w = 400)  ; максимальная ширина
{
   TTS_NOPREFIX := 2, TTS_ALWAYSTIP := 1, TTS_BALLOON := 0x40, TTS_CLOSE := 0x80

   hWnd := DllCall("CreateWindowEx", UInt, WS_EX_TOPMOST := 8
                                   , Str, "tooltips_class32", Str, ""
                                   , UInt, TTS_NOPREFIX|TTS_ALWAYSTIP|TTS_CLOSE|(BallonTip ? TTS_BALLOON : 0)
                                   , Int, 0, Int, 0, Int, 0, Int, 0
                                   , Ptr, 0, Ptr, 0, Ptr, 0, Ptr, 0)

   if (x = "" || y = "")
   {
      CoordMode, Mouse
      MouseGetPos, xtt, ytt
      xtt := x = "" ? xtt + 10 : x
      ytt := y = "" ? ytt + 10 : y
   }
   Else
      xtt := x, ytt := y

   NumPut(VarSetCapacity(TOOLINFO, A_PtrSize = 4 ? 48 : 72, 0), TOOLINFO)
   NumPut(0x20, TOOLINFO, 4)      ; TTF_TRACK = 0x20
   NumPut(&sText, TOOLINFO, A_PtrSize = 4 ? 36 : 48)

   DHW := A_DetectHiddenWindows
   DetectHiddenWindows, On
   WinWait, ahk_id %hWnd%

   WM_USER := 0x400
   SendMessage, WM_USER + 24,, w         ; TTM_SETMAXTIPWIDTH
   SendMessage, WM_USER + (A_IsUnicode ? 50 : 4),, &TOOLINFO   ; TTM_ADDTOOL
   SendMessage, WM_USER + 19, RGB_to_BGR(nColorBack)   ; TTM_SETTIPBKCOLOR
   SendMessage, WM_USER + 20, RGB_to_BGR(nColorText)   ; TTM_SETTIPTEXTCOLOR
   SendMessage, WM_USER + (A_IsUnicode ? 33 : 32), h_icon, &sTitle      ; TTM_SETTITLEA и TTM_SETTITLEW
   SendMessage, WM_USER + (A_IsUnicode ? 57 : 12),, &TOOLINFO     ; TTM_UPDATETIPTEXTA и TTM_UPDATETIPTEXTW
   SendMessage, WM_USER + 18,, xtt|(ytt<<16)   ; TTM_TRACKPOSITION
   SendMessage, WM_USER + 17, 1, &TOOLINFO ; TTM_TRACKACTIVATE

   WinGetPos,,, W, H
   if (xtt + W + 10 > A_ScreenWidth || ytt + H + 10 > A_ScreenHeight)
   {
      WinHide
      xtt := xtt + W + 10 > A_ScreenWidth ? A_ScreenWidth - W - 10 : xtt
      ytt := ytt + H + 10 > A_ScreenHeight ? A_ScreenHeight - H - 10 : ytt
      SendMessage, 1042,, xtt|(ytt<<16)   ; TTM_TRACKPOSITION
      WinShow
   }

   DetectHiddenWindows, % DHW
   Return hWnd
}

RGB_to_BGR(RGB)
{
   CurrentFormat := A_FormatInteger
   SetFormat, IntegerFast, H
   C := SubStr("0x000000", 1, -(StrLen(RGB+0) - 2)) . SubStr(RGB+0, 3)
   BGR := RegExReplace(C, "0x(..)(..)(..)", "0x$3$2$1")
   SetFormat, IntegerFast, %CurrentFormat%
   Return BGR
}

StrPutVar(string, ByRef var, encoding = "CP0")
{
    ; Ensure capacity.
    VarSetCapacity( var, StrPut(string, encoding)
        ; StrPut returns char count, but VarSetCapacity needs bytes.
        * ((encoding="utf-16"||encoding="cp1200") ? 2 : 1) )
    ; Copy or convert the string.
    return StrPut(string, &var, encoding)
}

UrlDownloadToVar(URL, UserAgent = "", Proxy = "", ProxyBypass = "")
{
    ; Requires Windows Vista, Windows XP, Windows 2000 Professional, Windows NT Workstation 4.0,
    ; Windows Me, Windows 98, or Windows 95.
    ; Requires Internet Explorer 3.0 or later.
    pFix:=a_isunicode ? "W" : "A"
    hModule := DllCall("LoadLibrary" . pFix, "Str", "wininet.dll")

    AccessType := Proxy != "" ? 3 : 1
    ;INTERNET_OPEN_TYPE_PRECONFIG                    0   // use registry configuration
    ;INTERNET_OPEN_TYPE_DIRECT                       1   // direct to net
    ;INTERNET_OPEN_TYPE_PROXY                        3   // via named proxy
    ;INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY  4   // prevent using java/script/INS

    io := DllCall("wininet\InternetOpen" . pFix
    , "Str", UserAgent ;lpszAgent
    , "UInt", AccessType
    , "Str", Proxy
    , "Str", ProxyBypass
    , "UInt", 0) ;dwFlags

    iou := DllCall("wininet\InternetOpenUrl" . pFix
    , "Ptr", io
    , "Str", url
    , "Str", "" ;lpszHeaders
    , "UInt", 0 ;dwHeadersLength
    , "UInt", 0x80000000 ;dwFlags: INTERNET_FLAG_RELOAD = 0x80000000 // retrieve the original item
    , "Ptr", 0) ;dwContext

    If (ErrorLevel != 0 or iou = 0) {
        DllCall("FreeLibrary", "Ptr", hModule)
        return 0
    }

    VarSetCapacity(buffer, 10240, 0)
    ;VarSetCapacity(BytesRead, 4, 0)

    Loop
    {
        ;http://msdn.microsoft.com/library/en-us/wininet/wininet/internetreadfile.asp
        irf := DllCall("wininet\InternetReadFile", Ptr, iou, Ptr, &buffer, "UInt", 10240, "Int*", BytesRead)
        VarSetCapacity(buffer, -1) ;to update the variable's internally-stored length

        ;BytesRead_ = 0 ; reset
        ;Loop, 4  ; Build the integer by adding up its bytes. (From ExtractInteger-function)
        ;    BytesRead_ += *(&BytesRead + A_Index-1) << 8*(A_Index-1) ;Bytes read in this very DllCall

        ; To ensure all data is retrieved, an application must continue to call the
        ; InternetReadFile function until the function returns TRUE and the lpdwNumberOfBytesRead parameter equals zero.
        If (irf = 1 and BytesRead = 0)
            break
        Else ; append the buffer's contents
        {
            a_isunicode ? buffer:=StrGet(&buffer, "CP0")
            Result .= SubStr(buffer, 1, BytesRead * (a_isunicode ? 2 : 1))
        }

        /* optional: retrieve only a part of the file
        BytesReadTotal += BytesRead_
        If (BytesReadTotal >= 30000) ; only read the first x bytes
        break                      ; (will be a multiple of the buffer size, if the file is not smaller; trim if neccessary)
        */
    }

    DllCall("wininet\InternetCloseHandle", "Ptr", iou)
    DllCall("wininet\InternetCloseHandle", "Ptr", io)
    DllCall("FreeLibrary", "Ptr", hModule)
    Return Result
}

JSON(ByRef js, s, v = "")
{
   j = %js%
   Loop, Parse, s, .
   {
      p = 2
      RegExMatch(A_LoopField, "([+\-]?)([^[]+)((?:\[\d+\])*)", q)
      Loop {
         If (!p := RegExMatch(j
            , "(?<!\\)(""|')([^\1]+?)(?<!\\)(?-1)\s*:\s*((\{(?:[^{}]++|(?-1))*\})|(\[(?:[^[\]]++|(?-1))*\])|"
            . "(?<!\\)(""|')[^\7]*?(?<!\\)(?-1)|[+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:,|$|\})", x, p))
            Return
         Else If (x2 == q2 or q2 == "*") {
            j = %x3%
            z += p + StrLen(x2) - 2
            If (q3 != "" and InStr(j, "[") == 1) {
               StringTrimRight, q3, q3, 1
               Loop, Parse, q3, ], [
               {
                  z += 1 + RegExMatch(SubStr(j, 2, -1)
                     , "^(?:\s*((\[(?:[^[\]]++|(?-1))*\])|(\{(?:[^{\}]++|(?-1))*\})|[^,]*?)\s*(?:,|$)){"
                     . SubStr(A_LoopField, 1) + 1 . "}", x)
                  j = %x1%
               }
            }
            Break
         }
         Else p += StrLen(x)
      }
   }
   If v !=
   {
      vs = "
      If (RegExMatch(v, "^\s*(?:""|')*\s*([+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:""|')*\s*$", vx)
         and (vx1 + 0 or vx1 == 0 or vx1 == "true" or vx1 == "false" or vx1 == "null" or vx1 == "nul"))
         vs := "", v := vx1
      StringReplace, v, v, ", \", All
      js := SubStr(js, 1, z := RegExMatch(js, ":\s*", zx, z) + StrLen(zx) - 1)
         . vs . v . vs . SubStr(js, z + StrLen(x3) + 1)
   }
   Return, j == "false" ? 0 : j == "true" ? 1 : j == "null" or j == "nul"
      ? "" : SubStr(j, 1, 1) == """" ? SubStr(j, 2, -1) : j
}

И вообще запомните: размер указателя в 64-битных процессах - 8 байт, это так же относится ко всем видам хэндлов (HWND, HMODULE, HINTERNET и пр.).

62

Re: AHK: Переводчик онлайн

Запомним, запомним! Я был уверен, что только указатель изменился. Хотя, вот даже справка пишет:

Also note that handles (including types like HWND and HBITMAP) are essentially pointer-types.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

63

Re: AHK: Переводчик онлайн

Windows Data Types. В типах вида UINT_PTR, "PTR" означает размер. Т.е. UINT размером с PTR, а не указатель на UINT. HFILE и HRESULT —  4-байтные, несмотря на первую букву.

В 64-битных структурах надо ещё учитывать выравнивание. Все члены должны лежать на своей естественной границе. Например, 8-байтные должны начинаться на границе 8 байт, т.е. если первый член DWORD, а второй HANDLE, то первый фактически тоже займёт 8 байт, т.к. второй будет сдвинут на 8-байтную границу. Начало и конец структуры тоже должны будут лежать на 8-байтной границе. Вообще они должны выравниваться на естественную границу самого большого из членов, но, насколько понимаю, тут имеются в виду только базовые типы. Например, формально в TOOLINFO самый большой член — структура RECT, величиной в 16 байт, но TOOLINFO по ней не выравнивается, т.е. она считается просто за 4 DWORD'a. Если конец структуры выравнивается путём добавления байтов, система может использовать эти байты для своих нужд — что-то в них сохранять своё, так что лучше про них не забывать, иначе могут быть переписаны данные, которые идут сразу за структурой. Возможно, выравнивающие байты внутри структуры тоже могут быть так использованы, но об этом я упоминаний не встречал.

В общем, размер 64-битной структуры кратен самому большому члену базового типа.

64

Re: AHK: Переводчик онлайн

YMP, спасибо за разъяснения.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

65

Re: AHK: Переводчик онлайн

Некоторые исправления, касающиеся перевода больших кусков текста.

global ColorToolTip := 0xFFFFE1
global ColorText := 0x002288

#NoEnv
SetBatchLines, -1

; Menu, Tray, Icon, google.ico
OnMessage(0x201, "WM_LBUTTONDOWN")
Return

~^vk43:: DoublePress()

~LButton Up::
   MouseGetPos,,, ID
   WinGetClass, Class, ahk_id %ID%
   if (Class != "tooltips_class32")
      Return

   SendInput, {LButton Up}{LButton Down}{LButton Up}
   Return

DoublePress()
{
   static pressed1 = 0
   if pressed1 and A_TimeSincePriorHotkey <= 400
      pressed1 := 0, Translate()
   else
      pressed1 = 1
}

Translate(_from="", _to="")
{
   if Clipboard =
       return

   INTERNET_MAX_SCHEME_LENGTH := 32
   INTERNET_MAX_PATH_LENGTH := 2048
   INTERNET_MAX_URL_LENGTH := INTERNET_MAX_SCHEME_LENGTH + StrLen("://")+ INTERNET_MAX_PATH_LENGTH

   if (_from = "" && _to = "")
   {
      cyr := RegExMatch(Clipboard, "[А-Яа-я]")
      from := cyr ? "ru" : "auto", to := cyr ? "en" : "ru"
   }
   else
      from := _from, to := _to

   PreUrl := "http://translate.google.com/translate_a/t?client=x&sl=" . from . "&tl=" . to . "&text="
   Url := PreUrl . URIEncode(Clipboard)

   if StrLen(Url) > INTERNET_MAX_URL_LENGTH
   {
      StartPos := 1
      While RegExMatch(Clipboard, "O)(.*?[\.\?!])(([^\.\?!]*?)[^ \t\n\r]|$)", Found, StartPos)
      {
         StartPos := Found.Pos(1) + Found.Len(1)
         Url := PreUrl . URIEncode(Found.Value(1))
         Delimiter := Found.Value(3), d := SubStr(Delimiter, 1, 1)
         if d not in `n,`r, ,%A_Tab%
            Delimiter := ""
         if StrLen(Url) > INTERNET_MAX_URL_LENGTH
         {
            MsgBox, 20, Ошибка!, % "Предложение """ . Found.Value(1) . """ слишком велико.`nПродолжить?"
            IfMsgBox, Yes
               Continue
            Else
               Break
         }
         TransText .= GetTranslate(Url, from, 0) . Delimiter
      }
   }
   Else
      TransText := GetTranslate(Url, from)

   TrackToolTip(TransText, from ">" to, 0, ColorToolTip, ColorText)
}

URIEncode(Str)
{
   b_Format:=A_FormatInteger
   SetFormat, Integer, Hex
   Loop, % StrPutVar(Str, Var, "UTF-8")
   {
      Ch:=NumGet(Var, A_Index-1, "UChar")
      If Ch=0
         Break
      If (Ch>0x7f Or Ch<0x30 Or Ch=0x3d)
         s.="%"((StrLen(c:=SubStr(Ch, 3))<2) ? "0"c:c)
      Else
         s.=Chr(Ch)
   }
   SetFormat, Integer, % b_Format
   Return, s
}

GetTranslate(Url, byref from, ReadDict = 1)
{
   if !JsonTrans := UrlDownloadToVar(Url, "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.8.131 Version/11.10")
   {
      TrackToolTip("Нет ответа от сервера.`nПроверьте соединение с интернетом!", "Ошибка!", 3)
      Return
   }

   from:=JSON(JsonTrans, "src")

   While Sentence := JSON(JsonTrans, "sentences[" A_Index - 1 "].trans")
      TransText .= Sentence

   if (ReadDict && JSON(JsonTrans, "dict[0]"))
   {
      While JSON(JsonTrans, "dict[" A_Index - 1 "]")
      {
         i := A_Index - 1
         While d := JSON(JsonTrans, "dict[" i "].terms[" A_Index - 1 "]")
            if (d != TransText)
               dict .= d . "; "
      }
      StringTrimRight, dict, dict, 2
   }

   dict ? TransText.= "`n+`n" dict

   StringReplace, TransText, TransText, \r\n,`r`n, All
   StringReplace, TransText, TransText, \", ", All
   StrPutVar(TransText, Buff)
   Return StrGet(&Buff, "UTF-8")
}

WM_LBUTTONDOWN()
{
   PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

TrackToolTip( sText
            , sTitle = ""
            , h_icon = 0   ; h_icon — 0: None, 1:Info, 2: Warning, 3: Error, n > 3: предполагается hIcon
            , nColorBack = 0xFFFFE1
            , nColorText = 0
            , BallonTip = 0   ; BalloonTip — это ToolTip с хвостиком
            , x = ""   ; если не указаны, то вблизи курсора
            , y = ""
            , w = 400)  ; максимальная ширина
{
   TTS_NOPREFIX := 2, TTS_ALWAYSTIP := 1, TTS_BALLOON := 0x40, TTS_CLOSE := 0x80

   hWnd := DllCall("CreateWindowEx", UInt, WS_EX_TOPMOST := 8
                                   , Str, "tooltips_class32", Str, ""
                                   , UInt, TTS_NOPREFIX|TTS_ALWAYSTIP|TTS_CLOSE|(BallonTip ? TTS_BALLOON : 0)
                                   , Int, 0, Int, 0, Int, 0, Int, 0
                                   , Ptr, 0, Ptr, 0, Ptr, 0, Ptr, 0)

   if (x = "" || y = "")
   {
      CoordMode, Mouse
      MouseGetPos, xtt, ytt
      xtt := x = "" ? xtt + 10 : x
      ytt := y = "" ? ytt + 10 : y
   }
   Else
      xtt := x, ytt := y

   NumPut(VarSetCapacity(TOOLINFO, A_PtrSize = 4 ? 48 : 72, 0), TOOLINFO)
   NumPut(0x20, TOOLINFO, 4)      ; TTF_TRACK = 0x20
   NumPut(&sText, TOOLINFO, A_PtrSize = 4 ? 36 : 48)

   DHW := A_DetectHiddenWindows
   DetectHiddenWindows, On
   WinWait, ahk_id %hWnd%

   WM_USER := 0x400
   SendMessage, WM_USER + 24,, w         ; TTM_SETMAXTIPWIDTH
   SendMessage, WM_USER + (A_IsUnicode ? 50 : 4),, &TOOLINFO   ; TTM_ADDTOOL
   SendMessage, WM_USER + 19, RGB_to_BGR(nColorBack)   ; TTM_SETTIPBKCOLOR
   SendMessage, WM_USER + 20, RGB_to_BGR(nColorText)   ; TTM_SETTIPTEXTCOLOR
   SendMessage, WM_USER + (A_IsUnicode ? 33 : 32), h_icon, &sTitle      ; TTM_SETTITLEA и TTM_SETTITLEW
   SendMessage, WM_USER + (A_IsUnicode ? 57 : 12),, &TOOLINFO     ; TTM_UPDATETIPTEXTA и TTM_UPDATETIPTEXTW
   SendMessage, WM_USER + 18,, xtt|(ytt<<16)   ; TTM_TRACKPOSITION
   SendMessage, WM_USER + 17, 1, &TOOLINFO ; TTM_TRACKACTIVATE

   WinGetPos,,, W, H
   if (xtt + W + 10 > A_ScreenWidth || ytt + H + 10 > A_ScreenHeight)
   {
      WinHide
      xtt := xtt + W + 10 > A_ScreenWidth ? A_ScreenWidth - W - 10 : xtt
      ytt := ytt + H + 10 > A_ScreenHeight ? A_ScreenHeight - H - 10 : ytt
      SendMessage, 1042,, xtt|(ytt<<16)   ; TTM_TRACKPOSITION
      WinShow
   }

   DetectHiddenWindows, % DHW
   Return hWnd
}

RGB_to_BGR(RGB)
{
   CurrentFormat := A_FormatInteger
   SetFormat, IntegerFast, H
   C := SubStr("0x000000", 1, -(StrLen(RGB+0) - 2)) . SubStr(RGB+0, 3)
   BGR := RegExReplace(C, "0x(..)(..)(..)", "0x$3$2$1")
   SetFormat, IntegerFast, %CurrentFormat%
   Return BGR
}

StrPutVar(string, ByRef var, encoding = "CP0")
{
    ; Ensure capacity.
    VarSetCapacity( var, StrPut(string, encoding)
        ; StrPut returns char count, but VarSetCapacity needs bytes.
        * ((encoding="utf-16"||encoding="cp1200") ? 2 : 1) )
    ; Copy or convert the string.
    return StrPut(string, &var, encoding)
}

UrlDownloadToVar(URL, UserAgent = "", Proxy = "", ProxyBypass = "")
{
    ; Requires Windows Vista, Windows XP, Windows 2000 Professional, Windows NT Workstation 4.0,
    ; Windows Me, Windows 98, or Windows 95.
    ; Requires Internet Explorer 3.0 or later.
    pFix:=a_isunicode ? "W" : "A"
    hModule := DllCall("LoadLibrary" . pFix, "Str", "wininet.dll")

    AccessType := Proxy != "" ? 3 : 1
    ;INTERNET_OPEN_TYPE_PRECONFIG                    0   // use registry configuration
    ;INTERNET_OPEN_TYPE_DIRECT                       1   // direct to net
    ;INTERNET_OPEN_TYPE_PROXY                        3   // via named proxy
    ;INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY  4   // prevent using java/script/INS

    io := DllCall("wininet\InternetOpen" . pFix
    , "Str", UserAgent ;lpszAgent
    , "UInt", AccessType
    , "Str", Proxy
    , "Str", ProxyBypass
    , "UInt", 0) ;dwFlags

    iou := DllCall("wininet\InternetOpenUrl" . pFix
    , "Ptr", io
    , "Str", url
    , "Str", "" ;lpszHeaders
    , "UInt", 0 ;dwHeadersLength
    , "UInt", 0x80000000 ;dwFlags: INTERNET_FLAG_RELOAD = 0x80000000 // retrieve the original item
    , "Ptr", 0) ;dwContext

    If (ErrorLevel != 0 or iou = 0) {
        DllCall("FreeLibrary", "Ptr", hModule)
        return 0
    }

    VarSetCapacity(buffer, 10240, 0)
    ;VarSetCapacity(BytesRead, 4, 0)

    Loop
    {
        ;http://msdn.microsoft.com/library/en-us/wininet/wininet/internetreadfile.asp
        irf := DllCall("wininet\InternetReadFile", Ptr, iou, Ptr, &buffer, "UInt", 10240, "Int*", BytesRead)
        VarSetCapacity(buffer, -1) ;to update the variable's internally-stored length

        ;BytesRead_ = 0 ; reset
        ;Loop, 4  ; Build the integer by adding up its bytes. (From ExtractInteger-function)
        ;    BytesRead_ += *(&BytesRead + A_Index-1) << 8*(A_Index-1) ;Bytes read in this very DllCall

        ; To ensure all data is retrieved, an application must continue to call the
        ; InternetReadFile function until the function returns TRUE and the lpdwNumberOfBytesRead parameter equals zero.
        If (irf = 1 and BytesRead = 0)
            break
        Else ; append the buffer's contents
        {
            a_isunicode ? buffer:=StrGet(&buffer, "CP0")
            Result .= SubStr(buffer, 1, BytesRead * (a_isunicode ? 2 : 1))
        }

        /* optional: retrieve only a part of the file
        BytesReadTotal += BytesRead_
        If (BytesReadTotal >= 30000) ; only read the first x bytes
        break                      ; (will be a multiple of the buffer size, if the file is not smaller; trim if neccessary)
        */
    }

    DllCall("wininet\InternetCloseHandle", "Ptr", iou)
    DllCall("wininet\InternetCloseHandle", "Ptr", io)
    DllCall("FreeLibrary", "Ptr", hModule)
    Return Result
}

JSON(ByRef js, s, v = "")
{
   j = %js%
   Loop, Parse, s, .
   {
      p = 2
      RegExMatch(A_LoopField, "([+\-]?)([^[]+)((?:\[\d+\])*)", q)
      Loop {
         If (!p := RegExMatch(j
            , "(?<!\\)(""|')([^\1]+?)(?<!\\)(?-1)\s*:\s*((\{(?:[^{}]++|(?-1))*\})|(\[(?:[^[\]]++|(?-1))*\])|"
            . "(?<!\\)(""|')[^\7]*?(?<!\\)(?-1)|[+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:,|$|\})", x, p))
            Return
         Else If (x2 == q2 or q2 == "*") {
            j = %x3%
            z += p + StrLen(x2) - 2
            If (q3 != "" and InStr(j, "[") == 1) {
               StringTrimRight, q3, q3, 1
               Loop, Parse, q3, ], [
               {
                  z += 1 + RegExMatch(SubStr(j, 2, -1)
                     , "^(?:\s*((\[(?:[^[\]]++|(?-1))*\])|(\{(?:[^{\}]++|(?-1))*\})|[^,]*?)\s*(?:,|$)){"
                     . SubStr(A_LoopField, 1) + 1 . "}", x)
                  j = %x1%
               }
            }
            Break
         }
         Else p += StrLen(x)
      }
   }
   If v !=
   {
      vs = "
      If (RegExMatch(v, "^\s*(?:""|')*\s*([+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:""|')*\s*$", vx)
         and (vx1 + 0 or vx1 == 0 or vx1 == "true" or vx1 == "false" or vx1 == "null" or vx1 == "nul"))
         vs := "", v := vx1
      StringReplace, v, v, ", \", All
      js := SubStr(js, 1, z := RegExMatch(js, ":\s*", zx, z) + StrLen(zx) - 1)
         . vs . v . vs . SubStr(js, z + StrLen(x3) + 1)
   }
   Return, j == "false" ? 0 : j == "true" ? 1 : j == "null" or j == "nul"
      ? "" : SubStr(j, 1, 1) == """" ? SubStr(j, 2, -1) : j
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

66 (изменено: Крепыш, 2012-09-06 16:44:59)

Re: AHK: Переводчик онлайн

teadrinker пишет:

Некоторые исправления, касающиеся перевода больших кусков текста.

Добрый день!
Подскажите, пожалуйста, как скомпилировать рабочий исполняемый файл?
Скопировал вышеприведённый текст скрипта. Далее беру дистрибутив отсюда: http://www.autohotkey.com/download/AutoHotkey.zip. С помощью Ahk2Exe.exe делаю исполняемый файл. Запускаю его и получаю вот такое сообщение:
http://s1.ipicture.ru/uploads/20120906/OkVeSJQm.png
Что я сделал не так?

67

Re: AHK: Переводчик онлайн

Эта версия autohotkey устарела, и больше не развивается. Скрипт рассчитан на Autohotkey_L by Lexicos, брать тут:  http://l.autohotkey.net/

68 (изменено: Крепыш, 2012-09-06 18:38:09)

Re: AHK: Переводчик онлайн

Спасибо большое!
Так намного лучше. Как сделать, чтобы при открытии нового окна с переводом закрывалось старое?

А вот теперь версия http://forum.script-coding.com/viewtopi … 544#p57544 при двойном нажатии на RCtrl в Windows XP вылетает с ошибкой. Можно в последнюю версию добавить озвучку?

69

Re: AHK: Переводчик онлайн

Подскажите пожалуйста - что где надо изменить чтобы скрипт работал из под прокси?
192.168.206.230:3128
login: mikki
pass: 1

Жизнь стоит того чтобы не быть сволочью. (с) Разные Люди

70 (изменено: teadrinker, 2012-10-31 13:12:23)

Re: AHK: Переводчик онлайн

Большое спасибо за скрипт, очень полезен.
PS. Было бы не плохо, чтобы текст можно было копировать.

71

Re: AHK: Переводчик онлайн

Планирую выложить новую версию с текстом в поле Edit и с озвучкой. kilzar, у нас принято пользоваться шифтом. Не надо использовать "зы", здесь не вконтактик.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

72

Re: AHK: Переводчик онлайн

Mikki, вопрос ещё актуален?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

73 (изменено: teadrinker, 2012-11-11 19:28:47)

Re: AHK: Переводчик онлайн

Новая версия:

#NoEnv
SetBatchLines, -1

if (!A_IsCompiled && FileExist(A_ScriptDir "\Google.ico"))
   Menu, Tray, Icon, %A_ScriptDir%\Google.ico
else
   Menu, Tray, Icon, Shell32.dll, 161

global ColorGui := "Default"
   , INTERNET_MAX_SCHEME_LENGTH := 32, INTERNET_MAX_PATH_LENGTH := 2048
   , INTERNET_MAX_URL_LENGTH := INTERNET_MAX_SCHEME_LENGTH + INTERNET_MAX_PATH_LENGTH
   , BS_ICON := 0x40, IMAGE_ICON := 1, BM_SETIMAGE := 0xF7, ES_NOHIDESEL := 0x100
   , LangArray := {}, Player, Voice := [], ScriptPID
   , PlaylistOpenNoMedia := 6, Stopped := 1

Process, Exist
ScriptPID := ErrorLevel

InitLangArray()

OnMessage(0x201, "WM_LBUTTONDOWN")
Return

~^vk43:: DoublePress()

#IfWinActive Google Translate ahk_class AutoHotkeyGUI
Esc::WinClose, A

DoublePress()
{
   static pressed1 = 0
   if pressed1 and A_TimeSincePriorHotkey <= 400 And Clipboard
      pressed1 := 0, Translate(RegExReplace(Clipboard, "\R", "`r`n"))
   else
      pressed1 := 1
}

Translate(Sourse, _from="", _to="", NewWindow = 1)
{
   if !Ping("translate.google.com")
   {
      MsgBox, 16, Ошибка!, Нет ответа от сервера.`nПроверьте соединение с интернетом!
      Return
   }

   if (_from = "" && _to = "")
   {
      cyr := RegExMatch(Sourse, "[А-Яа-я]")
      from := cyr ? "ru" : "auto", to := cyr ? "en" : "ru"
   }
   else
      from := _from, to := _to

   PreUrl := "http://translate.google.com/translate_a/t?client=x&sl=" . from . "&tl=" . to . "&text="
   Url := PreUrl . URIEncode(Sourse)

   if StrLen(Url) > INTERNET_MAX_URL_LENGTH
   {
      if RegExMatch(Sourse, "[\.\?!\n]")
      {
         StartPos := 1
         While StartPos := RegExMatch(Sourse, ".+?([\.\?!\r\n]+([ \t\r\n]*)|$)", Found, StartPos) + StrLen(Found)
         {
            Delimiter := Found2 ? Found2 : RegExReplace(Found, ".*(\s*)", "$1")
            Text := RegExReplace(Found, "(.*)\s*", "$1")
            Url := PreUrl . URIEncode(Text)
            if StrLen(Url) > INTERNET_MAX_URL_LENGTH
            {
               If RegExMatch(Text, "[,;:—\r\n]")
               {
                  PrevText := "", StartPos_ := 1

                  While StartPos_ := RegExMatch(Text, "(.+?)(([,;:—\.]+\s*)|$)", Found_, StartPos_) + StrLen(Found_)
                  {
                     txt := Found_1, dlmtr := Found_2

                     If StrLen(PreUrl . URIEncode(txt . dlmtr)) > INTERNET_MAX_URL_LENGTH
                        TransText .= GetTranslate(PreUrl . URIEncode(PrevText), from) . RegExReplace(PrevText, ".*(\s+)$", "$1")
                           . BreakdownByGaps(txt, PreUrl, from) . dlmtr, PrevText := ""

                     Else If StrLen(PreUrl . URIEncode(txt . dlmtr . PrevText)) > INTERNET_MAX_URL_LENGTH
                        TransText .= GetTranslate(PreUrl . URIEncode(PrevText), from)
                           . RegExReplace(PrevText, ".*(\s+)$", "$1"), PrevText := txt . dlmtr

                     Else
                        PrevText .= txt . dlmtr
                  }
                  TransText .= GetTranslate(PreUrl . URIEncode(PrevText), from)
               }
               Else
                  TransText .= BreakdownByGaps(Text, PreUrl, ByRef from)
               TransText .= Delimiter
            }
            Else
               TransText .= GetTranslate(Url, from, 0) . Delimiter
         }
      }
      Else
         TransText := BreakdownByGaps(Sourse, PreUrl, ByRef from)
   }
   Else
      TransText := GetTranslate(Url, from)

   TransText := RegExReplace(TransText, " ``(.)", "$1" Chr(0x301))   ; обработка знака ударения
   If NewWindow
      ShowTranslation(Clipboard, TransText, from, to, ColorGui, ColorText)
   Else
      Return TransText
}

BreakdownByGaps(Text, PreUrl, ByRef from)
{
   StartPos := 1
   While StartPos := RegExMatch(Text, "(.+?)([ \t]+|$)", Found, StartPos) + StrLen(Found)
   {
      txt := Found1, dlmtr := Found2
      If StrLen(PreUrl . URIEncode(txt . dlmtr)) > INTERNET_MAX_URL_LENGTH
         TransText .= txt . dlmtr, PrevText := ""

      Else If StrLen(PreUrl . URIEncode(PrevText . txt . dlmtr)) > INTERNET_MAX_URL_LENGTH
         TransText .= GetTranslate(PreUrl . URIEncode(PrevText), from)
            . RegExReplace(PrevText, ".*(\s+)$", "$1"), PrevText := txt . dlmtr

      Else
         PrevText .= txt . dlmtr
   }
   Return TransText .= GetTranslate(PreUrl . URIEncode(PrevText), from)
}

URIEncode(Str)
{
   b_Format:=A_FormatInteger
   SetFormat, Integer, Hex
   Loop, % StrPutVar(Str, Var, "UTF-8")
   {
      Ch:=NumGet(Var, A_Index-1, "UChar")
      If Ch=0
         Break
      If (Ch>0x7f Or Ch<0x30 Or Ch=0x3d)
         s.="%"((StrLen(c:=SubStr(Ch, 3))<2) ? "0"c:c)
      Else
         s.=Chr(Ch)
   }
   SetFormat, Integer, % b_Format
   Return, s
}

GetTranslate(Url, byref from, ReadDict = 1)
{
   if !JsonTrans := UrlDownloadToVar(Url, "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.8.131 Version/11.10")
   {
      MsgBox, 16, Ошибка!, Нет ответа от сервера.`nПроверьте соединение с интернетом!
      Return
   }

   from:=JSON(JsonTrans, "src")

   While Sentence := JSON(JsonTrans, "sentences[" A_Index - 1 "].trans")
      TransText .= Sentence

   if (ReadDict && JSON(JsonTrans, "dict[0]"))
   {
      Pos := 0
      While Pos := RegExMatch(JsonTrans, """terms"":\[(.*?)]", Found, ++pos)
         dict .= RegExReplace(RegExReplace(Found1, """,""", "; "), """") . "`n`n"
      StringTrimRight, dict, dict, 2
   }

   dict ? TransText.= "`n+`n" dict

   StringReplace, TransText, TransText, \r\n,`r`n, All
   StringReplace, TransText, TransText, \", ", All
   Return TransText
}

WM_LBUTTONDOWN()
{
   PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

StrPutVar(string, ByRef var, encoding = "CP0")
{
    ; Ensure capacity.
    VarSetCapacity( var, StrPut(string, encoding)
        ; StrPut returns char count, but VarSetCapacity needs bytes.
        * ((encoding="utf-16"||encoding="cp1200") ? 2 : 1) )
    ; Copy or convert the string.
    return StrPut(string, &var, encoding)
}

UrlDownloadToVar(URL, UserAgent = "")
{
   WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
   WebRequest.Open("GET", Url)
   WebRequest.Option(WinHttpRequestOption_UserAgentString := 0) := UserAgent
   WebRequest.Send()
   Text := WebRequest.ResponseText
   WebRequest := ""
   return Text
}

JSON(ByRef js, s, v = "")
{
   j = %js%
   Loop, Parse, s, .
   {
      p = 2
      RegExMatch(A_LoopField, "([+\-]?)([^[]+)((?:\[\d+\])*)", q)
      Loop {
         If (!p := RegExMatch(j
            , "(?<!\\)(""|')([^\1]+?)(?<!\\)(?-1)\s*:\s*((\{(?:[^{}]++|(?-1))*\})|(\[(?:[^[\]]++|(?-1))*\])|"
            . "(?<!\\)(""|')[^\7]*?(?<!\\)(?-1)|[+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:,|$|\})", x, p))
            Return
         Else If (x2 == q2 or q2 == "*") {
            j = %x3%
            z += p + StrLen(x2) - 2
            If (q3 != "" and InStr(j, "[") == 1) {
               StringTrimRight, q3, q3, 1
               Loop, Parse, q3, ], [
               {
                  z += 1 + RegExMatch(SubStr(j, 2, -1)
                     , "^(?:\s*((\[(?:[^[\]]++|(?-1))*\])|(\{(?:[^{\}]++|(?-1))*\})|[^,]*?)\s*(?:,|$)){"
                     . SubStr(A_LoopField, 1) + 1 . "}", x)
                  j = %x1%
               }
            }
            Break
         }
         Else p += StrLen(x)
      }
   }
   If v !=
   {
      vs = "
      If (RegExMatch(v, "^\s*(?:""|')*\s*([+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:""|')*\s*$", vx)
         and (vx1 + 0 or vx1 == 0 or vx1 == "true" or vx1 == "false" or vx1 == "null" or vx1 == "nul"))
         vs := "", v := vx1
      StringReplace, v, v, ", \", All
      js := SubStr(js, 1, z := RegExMatch(js, ":\s*", zx, z) + StrLen(zx) - 1)
         . vs . v . vs . SubStr(js, z + StrLen(x3) + 1)
   }
   Return, j == "false" ? 0 : j == "true" ? 1 : j == "null" or j == "nul"
      ? "" : SubStr(j, 1, 1) == """" ? SubStr(j, 2, -1) : j
}

ShowTranslation(SourceText, TransText, from, to, ColorGui=0xDAD6CA, ColorText=0)
{
   static ButtonPos, EditPos, PlayPause1, PlayPause2, Stop1, Stop2, hGui, Control
          , hIcon1, hIcon2, hIcon3, hIcon4, hIcon5, ExtractIcon

   Gui, New, +AlwaysOnTop +LastFound +Resize +hwndhGui +Owner
   Gui, Color, %ColorGui%
   Gui, Font, q5 s8, Verdana
   Gui, Add, Text, x10 y20, Исходный язык:

   For k,v In LangArray
      SourceLangNames .= (A_Index = 1 ? "" : "|") . k . (v = from ? "|" : "")
    , TargetLangNames .= (A_Index = 1 ? "" : "|") . k . (v = to   ? "|" : "")

   SourceLangNames := RegExReplace(SourceLangNames, "\|$", "||")

   Gui, Add, DDL, x112 yp-4 w207 gChangeLang, % SourceLangNames

   TextLen := StrLen(SourceText)
   StrCount := Ceil(TextLen/50) + StrLen(RegExReplace(SourceText, "[^\n]")) + 1
   If StrCount > 20
      StrCount := 20
   Gui, Add, Edit, x10 y+10 w310 Multi r%StrCount% %ES_NOHIDESEL%, % SourceText

   Gui, Add, Button, x10 y+5 w52 h23 %BS_ICON% hwndhButt1 gPlayPause vPlayPause1
   Gui, Add, Button, % "x+3 yp w52 h23 " BS_ICON " hwndhButt2 gStop vStop1" (Player ? "" : " Disabled")
   Gui, Add, Button, x250 yp w70 h23 %BS_ICON% hwndhButt3 gTranslate

   Gui, Add, Text, x10 y+20, Язык перевода:

   Gui, Add, DDL, x112 yp-4 w207 gChangeLang, % TargetLangNames

   TextLen := StrLen(TransText)
   StrCount := Ceil(TextLen/50) + StrLen(RegExReplace(TransText, "[^\n]")) + 1
   If StrCount > 20
      StrCount := 20

   Gui, Add, Edit, x10 y+10 w310 Multi r%StrCount% %ES_NOHIDESEL%, % TransText
   GuiControlGet, Edit2, Pos

   Gui, Add, Button, x10 y+5 w52 h23 %BS_ICON% hwndhButt4 gPlayPause vPlayPause2
   Gui, Add, Button, % "x+3 yp w52 h23 " BS_ICON " hwndhButt5 gStop vStop2" (Player ? "" : " Disabled")
   Gui, Add, Button, x250 yp w70 h23 %BS_ICON% hwndhButt6 gGuiClose
   GuiControlGet, Button6, Pos

   if !ExtractIcon
   {
      hIcon1 := A_IsCompiled ? ExtractIcon(A_ScriptFullPath,  9, 16) : ExtractIcon("Shell32.dll", 218, 16)
      hIcon2 := A_IsCompiled ? ExtractIcon(A_ScriptFullPath, 10, 16) : ExtractIcon("Shell32.dll", 216, 16)
      hIcon3 := A_IsCompiled ? ExtractIcon(A_ScriptFullPath, 11, 16) : ExtractIcon("Shell32.dll", 177, 16)
      hIcon4 := A_IsCompiled ? ExtractIcon(A_ScriptFullPath, 12, 16) : ExtractIcon("Shell32.dll", 132, 16)
      hIcon5 := A_IsCompiled ? ExtractIcon(A_ScriptFullPath
         , 1, 24) : FileExist(A_ScriptDir "\Google.ico") ? ExtractIcon(A_ScriptDir "\Google.ico", 0, 24) : ""
      ExtractIcon := 1
   }

   SendMessage, BM_SETIMAGE, IMAGE_ICON, hIcon1,, ahk_id %hButt1%
   SendMessage, BM_SETIMAGE, IMAGE_ICON, hIcon1,, ahk_id %hButt4%
   SendMessage, BM_SETIMAGE, IMAGE_ICON, hIcon2,, ahk_id %hButt2%
   SendMessage, BM_SETIMAGE, IMAGE_ICON, hIcon2,, ahk_id %hButt5%
   SendMessage, BM_SETIMAGE, IMAGE_ICON, hIcon3,, ahk_id %hButt3%
   SendMessage, BM_SETIMAGE, IMAGE_ICON, hIcon4,, ahk_id %hButt6%
   if hIcon5
      DllCall("SendMessage", Ptr, hGui, UInt, WM_SETICON := 0x80, UInt, 0, Ptr, hIcon5)
   Gui, Show, hide, Google Translate

   VarSetCapacity(Rect, 16)
   DllCall("GetClientRect", Ptr, WinExist(), Ptr, &Rect)
   ClientW := NumGet(Rect, 8, "UInt"), ClientH := NumGet(Rect, 12, "UInt")

   EditPos := ClientH - Edit2H
   ButtonPos := ClientH - Button6Y
   
   GuiControl, Focus, Edit1
   Gui, Show, w330 h%ClientH%
   Return

GuiSize:
   SetWinDelay, 0
   p := A_GuiHeight - ButtonPos, q := A_GuiHeight - EditPos
   GuiControl, Move, Edit1, % "w" A_GuiWidth - 20
   GuiControl, Move, Edit2, % "w" A_GuiWidth - 20 " h" (q > 29 ? q : 29)
   GuiControl, Move, Static1, % "x" (A_GuiWidth > 330 ? 10 + (A_GuiWidth - 330)//2 : 10)
   GuiControl, Move, Static2, % "x" (A_GuiWidth > 330 ? 10 + (A_GuiWidth - 330)//2 : 10)
   GuiControl, Move, ComboBox1, % "x" (A_GuiWidth > 330 ? 112 + (A_GuiWidth - 330)//2 : 112)
   GuiControl, Move, ComboBox2, % "x" (A_GuiWidth > 330 ? 112 + (A_GuiWidth - 330)//2 : 112)
   GuiControl, MoveDraw, Button3, % "x" (A_GuiWidth > 200 ? A_GuiWidth - 80 : 120)
   GuiControl, MoveDraw, Button4, % "y" yp := (p > EditPos ?  p : EditPos)
   GuiControl, MoveDraw, Button5, % "y" yp
   GuiControl, MoveDraw, Button6, % "x" (A_GuiWidth > 200 ? A_GuiWidth - 80 : 120) " y" yp
   return

PlayPause:
   if IsObject(Player)
   {
      if Playing := !Playing
         Player.Controls.pause()
      else
         Player.Controls.play()
   }
   else
   {
      hGui := A_Gui, Control := A_GuiControl
      SetTimer, PlayPauseTimer, -1
   }
   return

PlayPauseTimer:
   n := SubStr(Control, 0)
   ControlGet, Text, Selected,, Edit%n%, ahk_id %hGui%
   if (Text = "")
      ControlGetText, Text, Edit%n%, ahk_id %hGui%
   ControlGetText, lng, ComboBox%n%, ahk_id %hGui%
   Say(RegExReplace(Text, "\R+", "`n"), LangArray[lng])
   return

Stop:
   Player.close()
   Playing := Player := ""
   StopButtonEnableDisable(0)
   return

Translate:
ChangeLang:
   FontSize := "s8"
   GuiControlGet, from,, ComboBox1
   from := LangArray[from]
   GuiControlGet, to,, ComboBox2
   to := LangArray[to]
   GuiControlGet, SourseText,, Edit1
   TransText := Translate(RegExReplace(SourseText, "\R", "`r`n"), from, to, 0)

   Loop, parse, TransText
      If Asc(A_LoopField) > 1300
         FontSize := "s11"
   until A_Index = 50 || FontSize = "s11"

   Gui, Font, %FontSize% q5
   GuiControl, Font, Edit2

   GuiControl,, Edit2, % TransText
   Return

GuiClose:
   Gui, %A_Gui%: Destroy
   IfWinNotExist, Google Translate ahk_class AutoHotkeyGUI ahk_pid %ScriptPID%
   {
      Player.close(), Player := "", Voice.Remove(1, Voice.MaxIndex())
      FileDelete, % A_ScriptDir "\mp3\*.mp3"
   }
   return
}

InitLangArray()
{
   Languages =
   (LTrim C
      Азербайджанский|az
      Албанский|sq
      Английский|en
      Арабский|ar
      Армянский|hy
      Африкаанс|af
      Баскский|eu
      Белорусский|be
      Болгарский|bg
      Венгерский|hu
      Вендский|sb
      Вьетнамский|vi
      Голландский|nl
      Греческий|el
      Грузинский|ka
      Датский|da
      Иврит|he
      Идиш|ji
      Индонезийский|in
      Исландский|is
      Испанский|es
      Итальянский|it
      Каталонский|ca
      Китайский|zh
      Китайский (Аомынь)|zh-cn
      Китайский (Тайвань)|zh-tw
      Корейский|ko
      Латынь|la
      Латышский|lv
      Литовский|lt
      Македонский|mk
      Малайский|ms
      Мальтийский|mt
      Немецкий|de
      Норвежский|no
      Польский|pl
      Португальский|pt
      Румынский|ro
      Русский|ru
      Сербский|sr
      Словацкий|sk
      Словенский|sl
      Суахили|sw
      Тайский|th
      Турецкий|tr
      Украинский|uk
      Урду|ur
      Фарси|fa
      Финский|fi
      Французский|fr
      Хинди|hi
      Хорватский|hr
      Чешский|cs
      Шведский|sv
      Эсперанто|eo
      Эстонский|et
      Японский|ja
   )

   Loop, parse, Languages, `n, `r
   {
      Key := RegExReplace(A_LoopField, "(.*)\|.*", "$1")
      Value := RegExReplace(A_LoopField, ".*\|(.*)", "$1")
      LangArray[Key] := Value
   }
}

ExtractIcon(sFile, IconNumber, IconSize)
{
   coding := A_IsUnicode ? "W" : "A"

   SplitPath, sFile,,, ext
   if (ext = "ico")
      IconNumber := 0

   if PrivateExtractIcons := DllCall("GetProcAddress"
                              , Ptr, DllCall("LoadLibrary", Str, "User32", Ptr)
                              , AStr, "PrivateExtractIcons" . coding, Ptr)
   {
      Result := DllCall(PrivateExtractIcons, Str, sFile, Int, IconNumber-1
                  , Int, IconSize, Int, IconSize, PtrP, hIcon, UIntP, 0, UInt, 1, UInt, 0)
      if !Result
         MsgBox, 16,, % "Не удалось извлечь иконку.`nОшибка " A_LastError "."
      else if (Result = 0xFFFFFFFF || Result = -1)
         MsgBox, 16,, Указанный файл не найден!
   }

   else
   {
      if !DllCall("Shell32\ExtractIconEx" . coding, Str, sFile, Int, IconNumber-1, PtrP, hIconLarge, PtrP, hIconSmall, UInt, 1)
      {
         MsgBox, 16,, % "Не удалось извлечь иконку.`nОшибка " A_LastError "."
         return
      }
      SysGet, SmallIconSize, % SM_CXSMICON
      if (IconSize <= SmallIconSize)
         DllCall("DestroyIcon", Ptr, hIconLarge)
         , hIcon := hIconSmall
      else
         DllCall("DestroyIcon", Ptr, hIconSmall)
         , hIcon := hIconLarge

      hIcon := DllCall("CopyImage", Ptr, hIcon, UInt, IMAGE_ICON
         , Int, IconSize, Int, IconSize, UInt, LR_COPYRETURNORG := 0x4|LR_COPYDELETEORG := 0x8, Ptr)
   }

   Return hIcon
}

Ping(strHost)
{
   Loop 4
      bRet := ComObjGet("winmgmts:").Get("Win32_PingStatus.address='" . strHost . "'").StatusCode = 0
   until bRet
   return bRet
}

Say(Text, lng)
{
   Player := ComObjCreate("WMPlayer.OCX")
   objPlaylist := Player.currentPlaylist

   for k,v in Voice
      if (v.Text = RegExReplace(Text, "^\s*(\S.+\S)(\s+$|$)", "$1") && v.lng = lng)
      {
         var := 1
         break
      }

   if var
   {
      Loop % v.mp3.MaxIndex()
         objPlaylist.appendItem(Player.newMedia(v.mp3[A_Index]))
   }
   else
   {
      if !Ping("translate.google.com")
      {
         MsgBox, 16, Ошибка!, Нет ответа от сервера.`nПроверьте соединение с интернетом!
         Return
      }

      PreUrl := "http://translate.google.com/translate_tts?ie=UTF-8&tl=" lng "&q="
      Strings := []
      If StrLen(Text) > 100
      {
         StartPos := 1
         While StartPos := RegExMatch(Text, ".+?(\.|$)", Found, StartPos) + StrLen(Found)
         {
            if StrLen(Found) > 100
            {
               StartPos_ := 1
               While StartPos_ := RegExMatch(Found, "(.{1,99}([ ,\t\n]|$))|(.{1,100})", Found_, StartPos_) + StrLen(Found_)
                  Strings.Insert(Found_)
            }
            else
               Strings.Insert(Found)
         }
      }
      else
         Strings.1 := Text

      if !FileExist(A_ScriptDir "\mp3")
         FileCreateDir, %A_ScriptDir%\mp3

      Voice.Insert(o := {Text: RegExReplace(Text, "^\s*(\S.+\S)(\s+$|$)", "$1"), lng: lng, mp3: []})
      Loop % count := Strings.MaxIndex()
      {
         URLDownloadToFile, % PreUrl . URIEncode(RegExReplace(Strings[A_Index], "^\s*([^\s]+)\s*$", "$1"))
            , % mp3file := A_ScriptDir "\mp3\" A_TickCount ".mp3"
         objPlaylist.appendItem(Player.newMedia(mp3file))
         o.mp3.Insert(mp3file)
      }
   }
   StopButtonEnableDisable(1)
   Player.Controls.play()
   While Player.PlayState != Stopped && Player.OpenState != PlaylistOpenNoMedia && IsObject(Player)
      Sleep, 100
   Player.close(), Player := objPlaylist := ""
   StopButtonEnableDisable(0)
}

StopButtonEnableDisable(key)
{
   WinGet, List, List, Google Translate ahk_class AutoHotkeyGUI ahk_pid %ScriptPID%
   Loop % List
   {
      Control , % key ? "Enable" : "Disable",, Button2, % "ahk_id" List%A_Index%
      Control , % key ? "Enable" : "Disable",, Button5, % "ahk_id" List%A_Index%
   }
}

По нажатию Ctrl+C+C появляется окно (resizable) с исходным текстом из буфера обмена и с его переводом. По умолчанию, если в исходном тексте присутствует кириллица, переводит с русского на английский, если нет, то язык исходного текста определяется автоматически и переводится на русский. В окне можно сменить языки источника и перевода. В том же окне можно осуществить новый перевод, изменив исходный текст вручную и нажав кнопку http://i.imgur.com/fD3K9.jpg или сменив язык.

Текст в любом из полей Edit можно озвучить, нажав кнопку http://i.imgur.com/lkBH2.jpg. Сначала ищется выделенный текст, при его отсутствии озвучивается весь. После загрузки mp3 файла (или нескольких, если текст большой) активируется кнопка http://i.imgur.com/dfLB2.jpg Stop и начинается озвучивание. Пока активна кнопка Stop, кнопка http://i.imgur.com/lkBH2.jpg работает в режиме Play/Pause. После проигрывания кнопка Stop деактивируется. Озвучка есть не для всех языков. В таком случае кнопка Stop активируется на короткое время и сразу деактивируется без озвучки.

Окно закрывается по Esc или нажатию на крестик.

Ограничение для Windows XP — в контролах Edit отображаются только ANSI-символы, по-крайней мере у меня так.

Буду рад замечаниям и дополнениям.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

74 (изменено: creature.ws, 2012-11-09 15:22:29)

Re: AHK: Переводчик онлайн

Спасибо.
В последней версии ahk доступны без кавычек юникод-имена полей массива

global LangArray
InitLangArray()

MsgBox % LangArray.Английский  " " LangArray["Китайский (Аомынь)"]

InitLangArray()
{
    LangArray := {
    (Join,
        Азербайджанский: "az"
        Албанский: "sq"
        Английский: "en"
        Арабский: "ar"
        Армянский: "hy"
        Африкаанс: "af"
        Баскский: "eu"
        Белорусский: "be"
        Болгарский: "bg"
        Венгерский: "hu"
        Вендский: "sb"
        Вьетнамский: "vi"
        Голландский: "nl"
        Греческий: "el"
        Грузинский: "ka"
        Датский: "da"
        Иврит: "he"
        Идиш: "ji"
        Индонезийский: "in"
        Исландский: "is"
        Испанский: "es"
        Итальянский: "it"
        Каталонский: "ca"
        Китайский: "zh"
        "Китайский (Аомынь)": "zh-cn"
        "Китайский (Тайвань)": "zh-tw"
        Корейский: "ko"
        Латынь: "la"
        Латышский: "lv"
        Литовский: "lt"
        Македонский: "mk"
        Малайский: "ms"
        Мальтийский: "mt"
        Немецкий: "de"
        Норвежский: "no"
        Польский: "pl"
        Португальский: "pt"
        Румынский: "ro"
        Русский: "ru"
        Сербский: "sr"
        Словацкий: "sk"
        Словенский: "sl"
        Суахили: "sw"
        Тайский: "th"
        Турецкий: "tr"
        Украинский: "uk"
        Урду: "ur"
        Фарси: "fa"
        Финский: "fi"
        Французский: "fr"
        Хинди: "hi"
        Хорватский: "hr"
        Чешский: "cs"
        Шведский: "sv"
        Эсперанто: "eo"
        Эстонский: "et"
        Японский: "ja"
    )}
}

75

Re: AHK: Переводчик онлайн

Спасибо, буду знать. У меня в коде сначала в переменную, а потом в массив только потому, что я в таком виде этот список скопировал откуда-то, лень было двоеточия и кавычки расставлять.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg