Страница 46 из 46

Добавлено: Сб май 23, 2026 12:59
Orion9
Кнопка для загрузки иконок текущего файла под курсором на главную панель инструментов. Поддерживаются любые типы файлов - ico, icl, dll и exe.

Требуются плагин Autorun
https://total.darkhost.ru/wiki/doku.php?id=ru:autorun
Плагин IconLibrary
http://wincmd.ru/plugring/iconlibrary.html

Кнопка создает временную панель инструментов и загружает ее на главную панель. Файл панели сохраняется в %COMMANDER_PATH%\Bars\Auto_icons.bar. Путь можно изменить в функции CreateIconsBar.

Для работы скрипта необходимо добавить пользовательскую команду em_open_icons_panel в файл usercmd.ini

Код: Выделить всё

[em_open_icons_panel]
cmd=OPENBAR1
param=%|COMMANDER_PATH|\Bars\Auto_icons.bar
Пользуясь этой командой, можно вызывать последнюю созданную панель в любой момент времени без создания новой.

Код кнопки 62005 можно изменить или привязать к em_команде

Код: Выделить всё

[em_load_icons]
cmd=62005
Полученной em_команде можно назначить горячую клавишу стандартными средствами ТС.

В кнопке действую два модификатора: Ctrl и Shift
[cut]TOTALCMD#BAR#DATA
62005

%COMMANDER_EXE%
Загрузить иконки файла|CTRL - Загрузить Shell32.dll|SHIFT - Перейти к Shell32.dll

0
-1
[/cut]
Код Autorun можно добавить к главной конфигурации плагина или в любой другой модуль
[cut="aucfg"]

Код: Выделить всё

RegisterCommand 62005 "LoadIconsToPanel"
#RegisterCommand 62006 "Reserved"

Func LoadIconsToPanel()
     Local sPath, sName, sFile, sHint, nIcons
     Local bCtrl = IsPressed(0x11), bShift = IsPressed(0x10)
     
     # файл под курсором
     sPath = RequestCopyDataInfo("SP")
     sName = RequestCopyDataInfo("SN")
     sFile = sPath & sName

     # модификаторы
     If bCtrl Or bShift Then 
        sFile = GetKnownFolderPath("System") & "\shell32.dll"
     Endif
     
     # переход к shell32.dll
     If bShift Then 
        CommandExec /CD:S %sFile%      
        Return
     Endif

     # проверка существования     
     If Not FileExist(sFile) Then 
        DarkHint("Файл не существует " & sFile)
        Return 
     Endif

     # каталог под курсором     
     If StrPos(FileGetAttr(sFile), "D") Then
        DarkHint("Нет иконок" & auCRLF & "Каталог " & sFile)
        Return 
     Endif

     # загрузка плагина    
     Local obj = Plugin("IconLibrary")
     If ERROR <> 0 then
        Return DarkHint("Plugin Error " & ERROR)
     EndIf

     # получение данных для текущего файла     
     obj.FileName = sFile
     nIcons = obj.GetValue(0)

     # освобождение объекта 
     Free(obj)     
     
     If nIcons > 0 then
        sHint = "Иконок: " & nIcons
        CreateIconsBar(sFile, nIcons)   # создание панели
     Else
        sHint = "Нет иконок"
     Endif

     # добавление имени файла к подсказке     
     sHint &= auCRLF & "Файл " & sFile
        
     If nIcons = 0 Then DarkHint(sHint)
EndFunc

Func CreateIconsBar(FileName, Icons)    
    Local sName = "Auto_icons"
    Local sPath = COMMANDER_PATH & "\Bars\"
    
    Local sFile = sPath & sName & ".bar"
    
    DarkHint("Загрузка иконок")
    
    If Not CreateNewBarFile(sPath, sName) Then
       DarkHint("Отмена операции")
       Return 
    EndIf
    
    For i = 2 to Icons + 1
        IniWrite %sFile% "Buttonbar" %"'Cmd'    & i"  "100000"
        IniWrite %sFile% "Buttonbar" %"'Menu'   & i"  %"i-2"
        IniWrite %sFile% "Buttonbar" %"'Button' & i"  %"FileName & ',' & i-2"
    Next
    
    IniWrite %sFile% "Buttonbar" "Buttoncount"  %"Icons+1"    
    DarkHint("Панель иконок:" & auCRLF & i-1 & " кнопок создано.")  
    CommandExec("em_open_icons_panel")
EndFunc

# создание новой панели (путь, имя, кнопка возврата)
Func CreateNewBarFile(BarDir, BarName, BackButton = true) 
    Local bar, br2, def
    
    bar = BarDir & BarName & ".bar"
    br2 = BarDir & BarName & ".br2"   
    
    ShellExec /SW_HIDE /WAIT:2000 %COMSPEC% "/c del /f /q ""%bar%"""
    ShellExec /SW_HIDE /WAIT:2000 %COMSPEC% "/c del /f /q ""%br2%"""
    
    If FileExist(bar) Then   
       DarkHint("Ошибка удаления " & bar)
       Return false
    Endif
     
    IniWrite %bar% "Buttonbar" "Buttoncount"  "0"
    If ERROR = 1 Then
       DarkHint("Ошибка создания " & bar)
       Return false
    EndIf
    
    IniRead def %COMMANDER_INI% "Buttonbar" "Buttonbar" "%COMMANDER_PATH%\DEFAULT.BAR"   
    
    If BackButton Then
       IniWrite %bar% "Buttonbar" "Button1" "wcmicons.dll,15"
       IniWrite %bar% "Buttonbar" "Cmd1"     %def%
       IniWrite %bar% "Buttonbar" "Menu1"   "Вернуться"
    Endif
      
   Return true
EndFunc

Func DarkHint(Hint, Delay = 0, Flags = 0)
    # формат подсказки
    SetHintParam("ShowHint", "Font", 10, "Arial")
    SetHintParam("ShowHint", "BackColor", 0x001C1C1C)
    SetHintParam("ShowHint", "Text", 0xFFFFFF)   
    # отображение подсказки
    ShowHint(Hint, "", "", Delay, Flags)
    # возвращение формата по умолчанию
    Sleep(100)
    SetHintParam("ShowHint", "Reload")    
EndFunc
[/cut]

Добавлено: Ср июн 17, 2026 23:15
Orion9
Кнопка для смены фона файловых панелей. Поддерживается темный режим.

[cut="Лирика"]Собственно, это все, что делает кнопка :) Хорошо, но мало )

Возможно, кому-то пригодится код на Autorun для своих нужд и идей.[/cut]
[cut="Autorun"]Для работы рекомендуется установить последнюю версию плагина. На данный момент это 2.2.21.3 (15.10.2025)

Инструкция по установке плагина
https://total.darkhost.ru/wiki/doku.php?id=ru:autorun

Особенности последней версии. Для версии 2.2.21.3 нет полного архива с дополнительными модулями (субплагинами) и файлами справки, установку придется проводить в два этапа. Сначала нужно установить версию 2.2.21 от 28.09.2025
https://total.darkhost.ru/files/autorun ... 1_beta.zip
Поверх неё накатить последний модуль от 15.10.2025
https://total.darkhost.ru/files/temp/au ... 251015.zip[/cut]
[cut="autorun.cfg"]

Код: Выделить всё

# смена фона панелей
RegisterCommand 70053 "BackColorSelect"

Func BackColorSelect(lParam)
    Local bkg1, bkg2
    Local dark = IniRead("~/R", COMMANDER_INI, "Configuration", "DarkMode", 0)
    Local sect = (Not dark ? "Colors" : "ColorsDark")    
    IniRead /R bkg1 %COMMANDER_INI% %"sect" "BackColor" -1
    IniRead /R bkg2 %COMMANDER_INI% %"sect" "BackColor2" -1
    Local occ = Callback("ColorChooseProc", "hwnd;uint;wparam;lparam")
    Local cls = Buffer(64), buf = Buffer(auX64 ? 72 : 36)
    cls.Zero()
    cls.SetNum(0, "dword", 0x000000FF, _
                  "dword", 0x0000FF00, _
                  "dword", 0x00FF0000, _
                  "dword", 0x00FFFFFF, _                  
                  "dword", 0x00808080)
    buf.Zero()                    
    If auX64 Then
        buf.SetNum(0,  "dword", buf.size)
        buf.SetNum(8,  "hwnd", AUTORUN_TCHANDLE)
        buf.SetNum(16, "hwnd", 0, _
                       "uint", bkg1)
        buf.SetNum(32, "ptr", cls.ptr, _                      
                       "dword", 0x00000113)
        buf.SetNum(48, "lparam", 0, _
                        "ptr", occ.ptr)
    Else
        buf.SetNum(0, "dword", buf.size, _   
                      "hwnd", AUTORUN_TCHANDLE, _         
                      "hwnd", 0, _
                      "uint", bkg1, _
                      "ptr", cls.ptr, _
                      "dword", 0x00000113, _
                      "lparam", 0, _
                      "ptr", occ.ptr)
    EndIf    
    If Not DllCall("comdlg32.dll\ChooseColorW", "ptr", buf.ptr, "bool") Then
       WriteBackColor(bkg1, bkg2)
    EndIf    
    Free(buf, cls, occ)
EndFunc

Func WriteBackColor(Color1, Color2)
    # темный режим
    Local dark = IniRead("~/R", COMMANDER_INI, "Configuration", "DarkMode", 0)
    # выбор секции    
    Local Section = (Not dark ? "Colors" : "ColorsDark")
    # запись значений
    IniWrite("~/R", COMMANDER_INI, Section, "BackColor", Color1)
    IniWrite("~/R", COMMANDER_INI, Section, "BackColor2", Color2)   
    # обновление панелей
    SendCommand 2957
    SendCommand 2957
EndFunc

Func ColorChooseProc(hWnd, uMsg, wParam, lParam)
    Static IDOK = 1, IDCANCEL = 2, WM_COMMAND = 0x0111
    Static r, g, b, c, max = 1*255 + 256*255 + 65536*255, last = -2
    If uMsg = WM_COMMAND Then
       If wParam = IDOK Or wParam = IDCANCEL Then Return 0
       r = WinGetText(WinFind(hWnd, "Edit", 4))
       g = WinGetText(WinFind(hWnd, "Edit", 5))
       b = WinGetText(WinFind(hWnd, "Edit", 6))
       If StrLen(r) = 0 Then r = 0
       If StrLen(g) = 0 Then g = 0
       If StrLen(b) = 0 Then b = 0
       c = 1*r + 256*g + 65536*b     
       WinSetText("RGB: " & r & ", " & g & ", " & b, hWnd)
       If Not IsInt(c) Then Return 0
       If c = last Then Return 0       
       If c >= -1 And c <= max Then
          WriteBackColor(c, c)
          last = c
       Endif       
    EndIf 
    Return 0
EndFunc

[/cut]
[cut="Кнопка"]TOTALCMD#BAR#DATA
70053

%COMMANDER_EXE%
Смена фона

1
-1[/cut]
[cut="Скриншот"]https://www.upload.ee/image/18789255/BackColor.gif[/cut]

Добавлено: Пн сен 07, 2026 13:09
Orion9
Кнопка для отображения погоды по заданным координатам.

[cut]TOTALCMD#BAR#DATA
%COMMANDER_PATH%\Scripts\Ahk\AutoHotkey32.exe
Meteo.ahk -tooltip-gps 55.75 37.62 Москва
%COMMANDER_PATH%\Scripts\Ahk\AutoHotkey32.exe,2
Москва
%COMMANDER_PATH%\Ini\Title\

-1[/cut]
Для работы требуется Autohotkey второй версии:
https://www.autohotkey.com/download/

Путь к исполняемому файлу и каталогу скрипта можно заменить на свои.

Скрипт делает запрос к сайту open-meteo.com (открытый и бесплатный API для получения данных о погоде):
https://open-meteo.com/en/docs

Чтобы определить местоположение и координаты, можно воспользоваться:
https://open-meteo.com/en/docs/geocoding-api

Скрипт принимает четыре параметра: -gps, latitude, longitude, name (широта, долгота и имя). Имя может быть любым, т.к. оно используется только для обозначения местоположения.

Пятый параметр -forcast необязательный. Он используется для отображения прогноза на 24 часа и на 48 часов соответственно, и может быть только двух значений: либо -forcast24, либо -forcast48. Если этот параметр не задан, подсказка будет выглядеть стандартно, т.е. с прогнозом на 8 часов и 7 дней недели. В скрипте этими значениями можно управлять через HourVar и WeekVar.

Параметр -gps может присоединить к себе либо -tooltip, -msgbox. Если ни один из них не указан, вывод будет осуществлен в стандартное устройство вывода (например, для использования в других скриптах). Стиль подсказки в пределах допустимого можно изменить в ToolTipOptions.

Пример параметров:

Код: Выделить всё

Meteo.ahk -msgbox-gps 40.71 -74.00 "New York"
Будет показан MsgBox с информацией о погоде в Нью-Йорке по местному времени.

Код: Выделить всё

Meteo.ahk -msgbox-gps 40.71 -74.00 "New York" -forecast24
То же самое, только прогноз на 24 часа.

Код: Выделить всё

Meteo.ahk -tooltip-gps 55.75 37.62 Москва
Будет отображен тултип (подсказка) о погоде в Москве:

[cut]Изображение[/cut]

Код: Выделить всё

Meteo.ahk -tooltip-gps 55.75 37.62 Москва -forecast24
То же самое, но с прогнозом на 24 часа:

[cut]Изображение[/cut]
Кроме параметров, возможно использование клавиш-модификаторов, где CTRL - прогноз на 24 часа, CTRL+Shift - прогноз на 48 часов, Win - MsgBox, Alt - использовать локальный файл (т.е. не загружать из интернета)

Локальный файл сохраняется во временном каталоге с именем forecast.json

Для корректной работы скрипт нужно сохранить в кодировке UTF-8:

[cut="Meteo.ahk"]

Код: Выделить всё

#Requires AutoHotkey v2

#NoTrayIcon

Global IsAlt := GetKeyState("Alt", "P"), IsShift := GetKeyState("Shift", "P")
Global IsWin := GetKeyState("LWin", "P"), IsControl := GetKeyState("Control", "P")

Global MeteoFormat := "{Temperature}  Wind: {Wind}  {Direction}"

Global STDOUT := "", WEATHER := ""
Global Forecast := 0, HourVar := 8, WeekVar := 1

Global Latitude, Longitude, MeteoName, IsMeteoName := 0

Global ActiveToolTip := false, LocalFile := IsAlt

Global meteo_url := "", meteo_api := "&current=temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code,cloud_cover,surface_pressure,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=temperature_2m,relative_humidity_2m,surface_pressure,weather_code,wind_speed_10m,wind_direction_10m&daily=weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset,precipitation_sum&wind_speed_unit=ms&timezone=auto"

if A_Args.Length < 1 
{
   MsgBox "Недостаточно аргументов"
   ExitApp
}

if !InStr(A_Args[1],'-gps')
{
   MsgBox "Не найден аргумент -gps"
   ExitApp
}

if A_Args.Length > 3
{
    Latitude  := A_Args[2]
    Longitude := A_Args[3]
    MeteoName := A_Args[4]
}
else
{
    MsgBox "Недостаточно аргументов"
    ExitApp
}

;MeteoName := MeteoName <> "" ? MeteoName : "Unknown"      
Latitude  := IsNumber(Latitude)  ? Latitude  : 0
Longitude := IsNumber(Longitude) ? Longitude : 0        

if Latitude = 0 or Longitude = 0
{
    MsgBox "Неверное значение Latitude или Longitude"
    ExitApp
}

meteo_url := "https://api.open-meteo.com/v1/forecast?latitude=" Latitude "&longitude=" Longitude . meteo_api

if A_Args.Length > 4 and InStr(A_Args[5],'-forecast')
{
   Forecast := InStr(A_Args[5],'48') ? 48 : 24
}

if IsControl
{
   if IsShift
      Forecast := 48
   else
      Forecast := 24   
}

fMeteo()

STDOUT := MeteoName ": " WEATHER "`n" STDOUT

If IsAlt
   STDOUT := "(L) " . STDOUT
   
if IsWin
{
   MsgBox STDOUT
   ExitApp
}

if InStr(A_Args[1],'-tooltip')
{
   ToolTipOptions.Init()
   ToolTipOptions.SetFont("s8", "Tahoma")
   ToolTipOptions.SetMargins(1, 1, 1, 1)
   ;ToolTipOptions.SetTitle("Meteo" , 1)
   ToolTipOptions.SetColors("FFFFE1", "BLACK")
   ToolTip STDOUT
   ActiveToolTip := true
   KeyWait "LButton", "D"
   ExitApp
}

if InStr(A_Args[1],'-msgbox')
{
   MsgBox STDOUT
   ExitApp
}

try FileAppend RTrim(LTrim(STDOUT), "`n"), "*", "CP0"
ExitApp  
  
ESC::
{
   if ActiveToolTip
   {
      ExitApp
   }
}
   
fMeteo()
{
   json_file := meteo_url
   json_temp := A_Temp . "\forecast.json"
   
   Global bMeteo := 1
   
   try
   {
      if !LocalFile
         Download json_file, json_temp      
   }  
   catch 
   {
      Global STDOUT .= "Meteo #Download Error`n"
   }
   else
   {
      ParseMeteo()
   }
     
   ParseMeteo()
   {
      try 
         file := FileRead(json_temp, "UTF-8")
      catch 
      { 
         Global STDOUT .= "Meteo #Error Reading File:`n" . json_temp . "`n"
         Return
      }
      try
         json := Jxon_load(&file)
      catch
      {
         Global STDOUT .= "Meteo #Json File Corrupt:`n" . json_temp . "`n"
         Return
      }
      out := ''
      try
      {
         cord := Round(json["latitude"],2) '° N ' Round(json["longitude"],2) '° E'
         time := json["current"]["time"]
         temp := ValueSign(Round(json["current"]["temperature_2m"])) . json["current_units"]["temperature_2m"]
         feel := ValueSign(Round(json["current"]["apparent_temperature"])) . json["current_units"]["apparent_temperature"]
         humd := Round(json["current"]["relative_humidity_2m"]) . json["current_units"]["relative_humidity_2m"]
         prec := Format("{:.2f}", json["current"]["precipitation"]) . ' ' . json["current_units"]["precipitation"]
         code := json["current"]["weather_code"]
         clod := json["current"]["cloud_cover"] . json["current_units"]["cloud_cover"]
         pres := Round(json["current"]["surface_pressure"] * 0.75) . ' mm'
         wind := Round(json["current"]["wind_speed_10m"]) . ' ' . json["current_units"]["wind_speed_10m"]
         from := Round(json["current"]["wind_direction_10m"]) . json["current_units"]["wind_direction_10m"]
         gust := Round(json["current"]["wind_gusts_10m"]) . ' ' . json["current_units"]["wind_gusts_10m"]
         
         ;if Forecast = 0
            out .= '---------------------------------------------------------------------------`n'
            
         out .=  'GPS ' . cord . (IsMeteoName = 1 ? ' ' MeteoName '': "") . '`n' 
         out .= 'Высота ' Round(json["elevation"]) ' м.`n'
         out .=  'Погода на ' . StrReplace(time, "T", " / ") . '`n'
         out .= '---------------------------------------------------------------------------`n'
         out .= 'Температура ' . temp .  '`n'
         out .= 'Ощущается как ' . feel . '`n'
         
         if Forecast = 0
         {
            out .= 'Влажность ' . humd . '`n'
            out .= GetWeatherCode(code) . ', Облака ' . clod  . '`n' 
            out .= json["current"]["precipitation"] > 0 ? 'Осадки ' . prec . '`n' : 'Без осадков`n' 
            out .= 'Давление ' . pres . '`n'
            out .= 'Ветер ' . wind . '`n'
            out .= 'Направление ' . from . ', ' . WindDirection(Round(json["current"]["wind_direction_10m"])) . '`n'
            out .= 'Порывы ветра ' . gust . '`n'
         }
         
         try 
         {
            t := SubStr(time, InStr(time, "T"), 4)
            d := f7 := ''
            if Forecast = 0 
               day .= 'Прогноз на ' . HourVar . ' часов:`n'
            else   
               day .= 'Прогноз на ' (Forecast = 48 ? '48 часов' : '24 часа') ':`n'
            day .= '---------------------------------------------------------------------------`n'
            day .= 'Дата  Время  Темп  Ветер  Нап  Дав  Влаж  Погода`n'
            day .= '---------------------------------------------------------------------------`n'
            j := 0
            f := 0
            h := (Forecast = 48) ? 3 : 2
            for i in json["hourly"]["time"]
            {
                if j > 0 and j < h
                {
                   d := SubStr(StrReplace(json["hourly"]["time"][A_Index], "T", "  "), 6)  . 
                        '  ' Round(json["hourly"]["temperature_2m"][A_Index]) json["hourly_units"]["temperature_2m"] . 
                        '  ' Round(json["hourly"]["wind_speed_10m"][A_Index]) ' ' json["hourly_units"]["wind_speed_10m"] . 
                        '  ' Round(json["hourly"]["wind_direction_10m"][A_Index]) json["hourly_units"]["wind_direction_10m"] .
                        '  ' Round(json["hourly"]["surface_pressure"][A_Index] * 0.75) .
                        '  ' Round(json["hourly"]["relative_humidity_2m"][A_Index]) json["hourly_units"]["relative_humidity_2m"] .
                        '  ' GetWeatherCode(json["hourly"]["weather_code"][A_Index]) . '`n'
                   if StrLen(d) > 59
                   {
                       d := SubStr(d, 1, 58) . "`n"
                   }                   
                   day .= d
                   
                   if ++f = HourVar and Forecast = 0
                      f7 := day
                }
                
                if InStr(i, t) and ++j=2
                {  
                   out .= 'Завтра в это время ' .
                           ValueSign(Round(json["hourly"]["temperature_2m"][A_Index])) . 
                           json["hourly_units"]["temperature_2m"] ', ' . 
                           GetWeatherCode(json["hourly"]["weather_code"][A_Index]) . '`n'
                }
            }
            day := out . day            
            out .= (Forecast = 0) ? f7 : day
         }
         catch
             out .= '# Error getting hourly data...`n'
             
         o := ''
         if WeekVar > 0
         {
            try
            {
               out .= 'Прогноз на неделю:`n'
               out .= '---------------------------------------------------------------------------`n'
               out .= 'Осд  Всхд  Закат  Макс  Мин  Дата  Погода`n'
               out .= '---------------------------------------------------------------------------`n'
               Loop json["daily"]["time"].Length
               {
                  i := A_Index
                  for k, v in json["daily"] 
                  {   
                      if InStr(k,'temp') {
                         if Round(v[i]) < 10 and Round(v[i]) > -10
                            o .= ""
                         o .= Round(v[i]) ;json["daily_units"][k]   
                      }   
                      else if InStr(k,'code')
                         o .= GetWeatherCode(v[i])
                         
                      else if InStr(k,'sun')
                         o .= StrSplit(v[i],'T')[2]
                      
                      else if InStr(k,'prec')
                         o .= Round(v[i],1)
                      
                      else
                         o .= v[i]
                      
                      o .= '  '
                  }               
                  o .= '`n' 
               }
               c := ''
               Loop Parse, o, '`n'
               {
                  if StrLen(A_LoopField) > 58 {
                     c .= SubStr(A_LoopField, 1, 57) . "`n"
                  }
                  else if StrLen(A_LoopField) > 0 {
                     c .= A_LoopField . '`n'
                  }   
               }   
               out.=c
            }
            catch   
               out.='# Error parcing daily data...`n'
         }
      }   
      catch   
      {
         ;Throw
         Global STDOUT .= "Meteo #Error Parcing Json File:`n" . json_temp . "`nRequired Values Not Found`n"
         Return
      }
      else
      {
         Global STDOUT  .= (Forecast > 0) ? day : out
         Global MeteoFormat := StrReplace(MeteoFormat, "{Temperature}", temp)
         Global MeteoFormat := StrReplace(MeteoFormat, "{Wind}", wind)
         Global MeteoFormat := StrReplace(MeteoFormat, "{Direction}", from)                  
         ;Global WEATHER := 'Meteo: ' . temp . '  Wind: ' . wind . '  ' . from
         Global WEATHER := MeteoFormat
      }  
   }
    
   ValueSign(Val)
   {
      if Val > -1 
         Val := '+' . Val
      return Val
   }
   
   GetWeatherCode(Code)
   {
      sWeather:=""
    
      Switch Code
    	{
      case  0:
        sWeather:= "Ясно" ;"Clear"
      case  1:
        sWeather:= "Малооблачно" ;"Mainly clear"
      case  2:
        sWeather:= Random(1) = 1 ? "Облачно с прояснениями" : "Переменная облачность" ;"Partly cloudy"
      case  3:
        sWeather:= "Пасмурно" ;"Overcast"
      case  45:
        sWeather:= "Туман" ;"Fog"
      case  48:
        sWeather:= "Изморозь" ;"Depositing rime fog"
      case  51:
        sWeather:= "Слабый моросящий дождь" ;"Light drizzle"
      case  53:
        sWeather:= "Моросящий дождь" ;"Moderate drizzle"
      case  55:
        sWeather:= "Сильный моросящий дождь" ;"Dense intensity drizzle"
      case  56:
        sWeather:= "Замерзающая морось" ;"Freezing Drizzle: Light"
      case  57:
        sWeather:= "Замерзающая морось" ;"Freezing Drizzle: dense intensity"
      case  61:
        sWeather:= "Слабый дождь" ;"Rain: Slight"
      case  63:
        sWeather:= "Дождь" ;"Rain: moderate"
      case  65:
        sWeather:= "Сильный дождь" ;"Rain: heavy intensity"
      case  66:
        sWeather:= "Слабый ледяной дождь" ;"Freezing Rain: Light"
      case  67:
        sWeather:= "Ледяной дождь" ;"Freezing Rain: heavy intensity"
      case  71:
        sWeather:= "Слабый снег" ;"Snow fall: Slight"
      case  73:
        sWeather:= "Снег" ;"Snow fall: moderate"
      case  75:
        sWeather:= "Сильный снег" ;"Snow fall: heavy intensity"
      case  77:
        sWeather:= "Зернистый снег" ;"Snow grains"
      case  80:
        sWeather:= "Проливной дождь" ;"Rain showers: Slight"
      case  81:
        sWeather:= "Ливень" ;"Rain showers: moderate"
      case  82:
        sWeather:= "Сильный ливень" ;"Rain showers: violent"
      case  85:
        sWeather:= "Мокрый снег" ;"Snow showers slight"
      case  86:
        sWeather:= "Дождь со снегом" ;"Snow showers heavy"
      case  95:
        sWeather:= "Гроза" ;"Thunderstorm: Slight or moderate"
      case  96:
        sWeather:= "Гроза, град" ;"Thunderstorm with slight and heavy hail"
      case  99:
        sWeather:= "Гроза, град" ;"Thunderstorm with slight and heavy hail"
      Default:
        sWeather:= "Не найден код " . Code
      	}
      Return sWeather
    }
    WindDirection(wd)
    {
       Switch
       {
          case wd < 12:  Wind := "Северный" 
          case wd < 33:  Wind := "Северо-Северо-Восточный"
          case wd < 57:  Wind := "Северо-Восточный"
          case wd < 78:  Wind := "Восточно-Северо-Восточный"
          case wd < 101: Wind := "Восточный" 
          case wd < 123: Wind := "Восточно-Юго-Восточный"
          case wd < 147: Wind := "Юго-Восточный"
          case wd < 169: Wind := "Юго-Юго-Восточный"
          case wd < 192: Wind := "Южный"
          case wd < 215: Wind := "Юго-Юго-Западный"
          case wd < 238: Wind := "Юго-Западный"
          case wd < 260: Wind := "Западно-Юго-Западный"
          case wd < 283: Wind := "Западный"
          case wd < 305: Wind := "Западно-Северо-Западный"
          case wd < 328: Wind := "Северо-Западный"
          case wd < 350: Wind := "Северо-Северо-Западный"
          case wd < 361: Wind := "Северный"            
          Default:       Wind := "Не известно"
      }
      Return Wind     
    }
}

;https://github.com/cocobelgica/AutoHotkey-JSON/blob/master/Jxon.ahk

Jxon_Load(&src, args*) {
	key := "", is_key := false
	stack := [ tree := [] ]
	next := '"{[01234567890-tfn'
	pos := 0
	
	while ( (ch := SubStr(src, ++pos, 1)) != "" ) {
		if InStr(" `t`n`r", ch)
			continue
		if !InStr(next, ch, true) {
			testArr := StrSplit(SubStr(src, 1, pos), "`n")
			
			ln := testArr.Length
			col := pos - InStr(src, "`n",, -(StrLen(src)-pos+1))

			msg := Format("{}: line {} col {} (char {})"
			,   (next == "")      ? ["Extra data", ch := SubStr(src, pos)][1]
			  : (next == "'")     ? "Unterminated string starting at"
			  : (next == "\")     ? "Invalid \escape"
			  : (next == ":")     ? "Expecting ':' delimiter"
			  : (next == '"')     ? "Expecting object key enclosed in double quotes"
			  : (next == '"}')    ? "Expecting object key enclosed in double quotes or object closing '}'"
			  : (next == ",}")    ? "Expecting ',' delimiter or object closing '}'"
			  : (next == ",]")    ? "Expecting ',' delimiter or array closing ']'"
			  : [ "Expecting JSON value(string, number, [true, false, null], object or array)"
			    , ch := SubStr(src, pos, (SubStr(src, pos)~="[\]\},\s]|$")-1) ][1]
			, ln, col, pos)

			throw Error(msg, -1, ch)
		}
		
		obj := stack[1]
        is_array := (obj is Array)
		
		if i := InStr("{[", ch) { ; start new object / map?
			val := (i = 1) ? Map() : Array()	; ahk v2
			
			is_array ? obj.Push(val) : obj[key] := val
			stack.InsertAt(1,val)
			
			next := '"' ((is_key := (ch == "{")) ? "}" : "{[]0123456789-tfn")
		} else if InStr("}]", ch) {
			stack.RemoveAt(1)
            next := (stack[1]==tree) ? "" : (stack[1] is Array) ? ",]" : ",}"
		} else if InStr(",:", ch) {
			is_key := (!is_array && ch == ",")
			next := is_key ? '"' : '"{[0123456789-tfn'
		} else { ; string | number | true | false | null
			if (ch == '"') { ; string
				i := pos
				while i := InStr(src, '"',, i+1) {
					val := StrReplace(SubStr(src, pos+1, i-pos-1), "\\", "\u005C")
					if (SubStr(val, -1) != "\")
						break
				}
				if !i ? (pos--, next := "'") : 0
					continue

				pos := i ; update pos

				val := StrReplace(val, "\/", "/")
				val := StrReplace(val, '\"', '"')
				, val := StrReplace(val, "\b", "`b")
				, val := StrReplace(val, "\f", "`f")
				, val := StrReplace(val, "\n", "`n")
				, val := StrReplace(val, "\r", "`r")
				, val := StrReplace(val, "\t", "`t")

				i := 0
				while i := InStr(val, "\",, i+1) {
					if (SubStr(val, i+1, 1) != "u") ? (pos -= StrLen(SubStr(val, i)), next := "\") : 0
						continue 2

					xxxx := Abs("0x" . SubStr(val, i+2, 4)) ; \uXXXX - JSON unicode escape sequence
					if (xxxx < 0x100)
						val := SubStr(val, 1, i-1) . Chr(xxxx) . SubStr(val, i+6)
				}
				
				if is_key {
					key := val, next := ":"
					continue
				}
			} else { ; number | true | false | null
				val := SubStr(src, pos, i := RegExMatch(src, "[\]\},\s]|$",, pos)-pos)
				
                if IsInteger(val)
                    val += 0
                else if IsFloat(val)
                    val += 0
                else if (val == "true" || val == "false")
                    val := (val == "true")
                else if (val == "null")
                    val := ""
                else if is_key {
                    pos--, next := "#"
                    continue
                }
				
				pos += i-1
			}
			
			is_array ? obj.Push(val) : obj[key] := val
			next := obj == tree ? "" : is_array ? ",]" : ",}"
		}
	}
	
	return tree[1]
}

;https://www.autohotkey.com/boards/viewtopic.php?t=113308

;======================================================================================================================
; ToolTipOptions        -  additional options for ToolTips
;
; Tooltip control       -> https://learn.microsoft.com/en-us/windows/win32/controls/tooltip-control-reference
; TTM_SETMARGIN         = 1050
; TTM_SETTIPBKCOLOR     = 1043
; TTM_SETTIPTEXTCOLOR   = 1044
; TTM_SETTITLEW         = 1057
; WM_SETFONT            = 0x30
; SetClassLong()        -> https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setclasslongw
; ======================================================================================================================
Class ToolTipOptions {
   ; -------------------------------------------------------------------------------------------------------------------
   Static HTT := DllCall("User32.dll\CreateWindowEx", "UInt", 8, "Str", "tooltips_class32", "Ptr", 0, "UInt", 3
                       , "Int", 0, "Int", 0, "Int", 0, "Int", 0, "Ptr", A_ScriptHwnd, "Ptr", 0, "Ptr", 0, "Ptr", 0)
   Static SWP := CallbackCreate(ObjBindMethod(ToolTipOptions, "_WNDPROC_"), , 4) ; subclass window proc
   Static OWP := 0                                                               ; original window proc
   Static ToolTips := Map()
   ; -------------------------------------------------------------------------------------------------------------------
   Static BkgColor := ""
   Static TktColor := ""
   Static Icon := ""
   Static Title := ""
   Static HFONT := 0
   Static Margins := ""
   ; -------------------------------------------------------------------------------------------------------------------
   Static Call(*) => False ; do not create instances
   ; -------------------------------------------------------------------------------------------------------------------
   ; Init()          -  Initialize some class variables and subclass the tooltip control.
   ; -------------------------------------------------------------------------------------------------------------------
   Static Init() {
      If (This.OWP = 0) {
         This.BkgColor := ""
         This.TktColor := ""
         This.Icon := ""
         This.Title := ""
         This.Margins := ""
         If (A_PtrSize = 8)
            This.OWP := DllCall("User32.dll\SetClassLongPtr", "Ptr", This.HTT, "Int", -24, "Ptr", This.SWP, "UPtr")
         Else
            This.OWP := DllCall("User32.dll\SetClassLongW", "Ptr", This.HTT, "Int", -24, "Int", This.SWP, "UInt")
         OnExit(ToolTipOptions._EXIT_, -1)
         Return This.OWP
      }
      Else
         Return False
   }
   ; -------------------------------------------------------------------------------------------------------------------
   ;  Reset()        -  Close all existing tooltips, delete the font object, and remove the tooltip's subclass.
   ; -------------------------------------------------------------------------------------------------------------------
   Static Reset() {
      If (This.OWP != 0) {
         For HWND In This.ToolTips.Clone()
            DllCall("DestroyWindow", "Ptr", HWND)
         This.ToolTips.Clear()
         If This.HFONT
            DllCall("DeleteObject", "Ptr", This.HFONT)
         This.HFONT := 0
         If (A_PtrSize = 8)
            DllCall("User32.dll\SetClassLongPtrW", "Ptr", This.HTT, "Int", -24, "Ptr", This.OWP, "UPtr")
         Else
            DllCall("User32.dll\SetClassLongW", "Ptr", This.HTT, "Int", -24, "Int", This.OWP, "UInt")
         This.OWP := 0
         Return True
      }
      Else
         Return False
   }
   ; -------------------------------------------------------------------------------------------------------------------
   ; SetColors()     -  Set or remove the text and/or the background color for the tooltip.
   ; Parameters:
   ;     BkgColor    -  color value like used in Gui.BackColor(...)
   ;     TxtColor    -  see above.
   ; -------------------------------------------------------------------------------------------------------------------
   Static SetColors(BkgColor := "", TxtColor := "") {
      This.BkgColor := BkgColor = "" ? "" : BGR(BkgColor)
      This.TxtColor := TxtColor = "" ? "" : BGR(TxtColor)
      BGR(Color, Default := "") { ; converts colors to BGR
         ; HTML Colors (BGR)
         Static HTML := {AQUA:   0xFFFF00, BLACK: 0x000000, BLUE:   0xFF0000, FUCHSIA: 0xFF00FF, GRAY:  0x808080,
                         GREEN:  0x008000, LIME:  0x00FF00, MAROON: 0x000080, NAVY:    0x800000, OLIVE: 0x008080,
                         PURPLE: 0x800080, RED:   0x0000FF, SILVER: 0xC0C0C0, TEAL:    0x808000, WHITE: 0xFFFFFF,
                         YELLOW: 0x00FFFF}
         If HTML.HasProp(Color)
            Return HTML.%Color%
         If (Color Is String) && IsXDigit(Color) && (StrLen(Color) = 6)
            Color := Integer("0x" . Color)
         If IsInteger(Color)
            Return ((Color >> 16) & 0xFF) | (Color & 0x00FF00) | ((Color & 0xFF) << 16)
         Return Default
      }
   }
   ; -------------------------------------------------------------------------------------------------------------------
   ; SetFont()       -  Set or remove the font used by the tooltip.
   ; Parameters:
   ;     FntOpts     -  font options like Gui.SetFont(Options, ...)
   ;     FntName     -  font name like Gui.SetFont(..., Name)
   ; -------------------------------------------------------------------------------------------------------------------
   Static SetFont(FntOpts := "", FntName := "") {
      Static HDEF := DllCall("GetStockObject", "Int", 17, "UPtr") ; DEFAULT_GUI_FONT
      Static LOGFONTW := 0
      If (FntOpts = "") && (FntName = "") {
         If This.HFONT
            DllCall("DeleteObject", "Ptr", This.HFONT)
         This.HFONT := 0
         LOGFONTW := 0
      }
      Else {
         If (LOGFONTW = 0) {
            LOGFONTW := Buffer(92, 0)
            DllCall("GetObject", "Ptr", HDEF, "Int", 92, "Ptr", LOGFONTW)
         }
         HDC := DllCall("GetDC", "Ptr", 0, "UPtr")
         LOGPIXELSY := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 90, "Int")
         DllCall("ReleaseDC", "Ptr", HDC, "Ptr", 0)
         If (FntOpts != "") {
            For Opt In StrSplit(RegExReplace(Trim(FntOpts), "\s+", " "), " ") {
               Switch StrUpper(Opt) {
                  Case "BOLD":      NumPut("Int", 700, LOGFONTW, 16)
                  Case "ITALIC":    NumPut("Char",  1, LOGFONTW, 20)
                  Case "UNDERLINE": NumPut("Char",  1, LOGFONTW, 21)
                  Case "STRIKE":    NumPut("Char",  1, LOGFONTW, 22)
                  Case "NORM":      NumPut("Int", 400, "Char", 0, "Char", 0, "Char", 0, LOGFONTW, 16)
                  Default:
                     O := StrUpper(SubStr(Opt, 1, 1))
                     V := SubStr(Opt, 2)
                     Switch O {
                        Case "C":
                           Continue ; ignore the color option
                        Case "Q":
                           If !IsInteger(V) || (Integer(V) < 0) || (Integer(V) > 5)
                              Throw ValueError("Option Q must be an integer between 0 and 5!", -1, V)
                           NumPut("Char", Integer(V), LOGFONTW, 26)
                        Case "S":
                           If !IsNumber(V) || (Number(V) < 1) || (Integer(V) > 255)
                              Throw ValueError("Option S must be a number between 1 and 255!", -1, V)
                           NumPut("Int", -Round(Integer(V + 0.5) * LOGPIXELSY / 72), LOGFONTW)
                        Case "W":
                           If !IsInteger(V) || (Integer(V) < 1) || (Integer(V) > 1000)
                              Throw ValueError("Option W must be an integer between 1 and 1000!", -1, V)
                           NumPut("Int", Integer(V), LOGFONTW, 16)
                        Default:
                           Throw ValueError("Invalid font option!", -1, Opt)
                     }
                  }
               }
            }
         NumPut("Char", 1, "Char", 4, "Char", 0, LOGFONTW, 23) ; DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS
         NumPut("Char", 0, LOGFONTW, 27) ; FF_DONTCARE
         If (FntName != "")
            StrPut(FntName, LOGFONTW.Ptr + 28, 32)
         If !(HFONT := DllCall("CreateFontIndirectW", "Ptr", LOGFONTW, "UPtr"))
            Throw OSError()
         If This.HFONT
            DllCall("DeleteObject", "Ptr", This.HFONT)
         This.HFONT := HFONT
      }
   }
   ; -------------------------------------------------------------------------------------------------------------------
   ; SetMargins()    -  Set or remove the margins used by the tooltip
   ; Parameters:
   ;     L, T, R, B  -  left, top, right, and bottom margin in pixels.
   ; -------------------------------------------------------------------------------------------------------------------
   Static SetMargins(L := 0, T := 0, R := 0, B := 0) {
      If ((L + T + R + B) = 0)
         This.Margins := 0
      Else {
         This.Margins := Buffer(16, 0)
         NumPut("Int", L, "Int", T, "Int", R, "Int", B, This.Margins)
      }
   }
   ; -------------------------------------------------------------------------------------------------------------------
   ; SetTitle()      -  Set or remove the title and/or the icon displayed on the tooltip.
   ; Parameters:
   ;     Title       -  string to be used as title.
   ;     Icon        -  icon to be shown in the ToolTip.
   ;                    This can be the number of a predefined icon (1 = info, 2 = warning, 3 = error
   ;                    (add 3 to display large icons on Vista+) or a HICON handle.
   ; -------------------------------------------------------------------------------------------------------------------
   Static SetTitle(Title := "", Icon := "") {
      Switch {
         Case (Title = "") && (Icon != ""):
            This.Icon := Icon
            This.Title := " "
         Case (Title != "") && (Icon = ""):
            This.Icon := 0
            This.Title := Title
         Default:
            This.Icon := Icon
            This.Title := Title
      }
   }
   ; -------------------------------------------------------------------------------------------------------------------
   ; For internal use only!
   ; -------------------------------------------------------------------------------------------------------------------
   Static _WNDPROC_(hWnd, uMsg, wParam, lParam) {
      ; WNDPROC -> https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-wndproc
      Switch uMsg {
         Case 0x0411: ; TTM_TRACKACTIVATE - just handle the first message after the control has been created
            If This.ToolTips.Has(hWnd) && (This.ToolTips[hWnd] = 0) {
               If (This.BkgColor != "")
                  SendMessage(1043, This.BkgColor, 0, hWnd)                ; TTM_SETTIPBKCOLOR
               If (This.TxtColor != "")
                  SendMessage(1044, This.TxtColor, 0, hWnd)                ; TTM_SETTIPTEXTCOLOR
               If This.HFONT
                  SendMessage(0x30, This.HFONT, 0, hWnd)                   ; WM_SETFONT
               If (Type(This.Margins) = "Buffer")
                  SendMessage(1050, 0, This.Margins.Ptr, hWnd)             ; TTM_SETMARGIN
               If (This.Icon != "") || (This.Title != "")
                  SendMessage(1057, This.Icon, StrPtr(This.Title), hWnd)   ; TTM_SETTITLE
               This.ToolTips[hWnd] := 1
            }
         Case 0x0001: ; WM_CREATE
            DllCall("UxTheme.dll\SetWindowTheme", "Ptr", hWnd, "Ptr", 0, "Ptr", StrPtr(""))
            This.ToolTips[hWnd] := 0
         Case 0x0002: ; WM_DESTROY
            This.ToolTips.Delete(hWnd)
      }
      Return DllCall(This.OWP, "Ptr", hWnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam, "UInt")
   }
   ; -------------------------------------------------------------------------------------------------------------------
   Static _EXIT_(*) {
      If (ToolTipOptions.OWP != 0)
         ToolTipOptions.Reset()
   }
}
[/cut]