Orion9

|
Posted: Tue Jan 06, 2026 00:38 Post subject: |
|
|
FallenAngel
Мда. Как всегда легко и просто только на бумаге, а берешься делать сразу вслывает куча нюансов. С одними проверками загребешься: тут надо учесть, там надо учесть. Но все-таки доделал, раз уж взялся, тем более что кому-то тоже может пригодится.
Небольшой подвох с сервером: он очень плохо откликается, иногда погода вообще может не обновиться по таймауту. Пришлось немного по-другому сделать отображение процесса обновления, что по сути и отняло больше всего времени.
При наведении на заголовок всплывает посказка. Alt - добавляет информацию о файлах. Ctrl - отображает подсказку о погоде и прогнозе из дополнительно указанной ссылки. Правый клик вызывает меню.
Настройки должны храниться в файле Header.ini в подкаталоге Ini. Т.е. %COMMANDER_INI%\Ini\Header.ini
 Hidden text [Title]
ShowTitle=1
Wttr=1
[Wttr]
Name=Zurich
Interval=3600
Url=https://wttr.in/47.37,8.55?format=%C+%t
Hint=https://wttr.in/47.37,8.55?T
; Examples:
; wttr.in/London?format=3
; wttr.in/London?format="%l:+%c+%t\n"
; Refer to the link below for the details:
; https://github.com/chubin/wttr.in?tab=readme-ov-file#one-line-output
;
; c Weather condition,
; C Weather condition textual name,
; x Weather condition, plain-text symbol,
; h Humidity,
; t Temperature (Actual),
; f Temperature (Feels Like),
; w Wind,
; l Location,
; m Moon phase,
; M Moon day,
; p Precipitation (mm/3 hours),
; P Pressure (hPa),
; u UV index (1-12),
;
; D Dawn*,
; S Sunrise*,
; z Zenith*,
; s Sunset*,
; d Dusk*,
; T Current time*,
; Z Local timezone.
;
;(*times are shown in the local timezone)
Поскольку все эти "города, координаты и прочее" довольно приватная вещь, есть возможность сохранить информацию в дополнительном файле пользователя Wttr.ini, который расположен по умолчанию в LocalAppData\GHISLER\Wttr.ini.
Соответственно, если файл пользователя существует, настройки прежде всего будут считываться с него, кроме двух ключей секции [Title], т.е. ShowTitle и Wttr. Последний отключает погоду в заголоке при Wttr=0
 Пример Wttr.ini [Wttr]
Name=
Interval=1800
Url=https://wttr.in/47.37,8.55?format=%t
Hint=https://wttr.in/47.37,8.55?T
Строку запроса можно настроить по-разному, все зависит от ключей сайта wttr.in.
Ошибки, конечно, могут быть: все сделать и протестировать за один день невозможно. Но радует, что кроме самого Autorun с последним модулем RegExp, для работы больше ничего не требуется.
 InfoHeader.aucfg | Code: | Sleep(200)
# наведение на заголовок
ControlSetHint /F /D:350 /H:2 0 "InfoHeaderHint"
# правый клик
ControlSetMouseAction /R /H:2 0 "InfoHeaderMenu"
# Shift + клик по заголовку
ControlSetMouseAction /L /K:S /H:2 0 "ToggleInfoHeader"
Global gTitle = WinGetText(), gInfoHeader = gTitle, gShowTitle = 1, gTitleThread = 0
Global gWttr = 1, gWttrUrl, gWttrHint, gWttrName, gWttrInterval = 3600
Global gWttrSec = 0, gWttrData, gWttrTip = "", gWttrFile = TEMP & "\wttr.txt", gWttrDataUpdate = 0
Global gWttrIni = COMMANDER_PATH & "\Ini\Header.ini"
Global gWttrIniApp = GetKnownFolderPath("LocalAppData") & "\GHISLER\Wttr.ini"
# запуск
LaunchInfoHeader()
# WM_WINDOWPOSCHANGING
# реагирование заголовка на изменение позиции окна
SetMessageAction 70 "SetInfoHeader"
Func ToggleInfoHeader()
# переключение переменной
gShowTitle = Not gShowTitle
# запись нового значения в Header.ini
IniWrite %gWttrIni% "Title" "ShowTitle" %"gShowTitle"
Sleep(100)
LaunchInfoHeader()
EndFunc
Func SetInfoHeader()
WinSetText(gShowTitle ? gInfoHeader : gTitle)
EndFunc
Func LaunchInfoHeader()
# чтение ключа
IniRead gShowTitle %gWttrIni% "Title" "ShowTitle" 1
# запуск заголовка, если он еще не запущен
If gShowTitle And Not gTitleThread Then
gInfoHeader = gTitle & ' ' & "Booting..."
WinSetText(gInfoHeader)
# подготовка конфигурации
InfoHeaderReadIni()
Sleep(200)
RunThread InfoHeader
EndIf
EndFunc
Func InfoHeaderReadIni()
Local sWttrIni = gWttrIni, sUrl
# чтение из Header.ini
IniRead gWttr %gWttrIni% "Title" "Wttr" 1
IniRead sUrl %sWttrIni% "Wttr" "Url" ""
# чтение из AppData\Wttr.ini
If FileExist(gWttrIniApp) Then
sWttrIni = gWttrIniApp
EndIf
IniRead gWttrUrl %sWttrIni% "Wttr" "Url" ""
IniRead gWttrHint %sWttrIni% "Wttr" "Hint" ""
IniRead gWttrName %sWttrIni% "Wttr" "Name" ""
IniRead gWttrInterval %sWttrIni% "Wttr" "Interval" 3600
# нет данных в AppData
# откат к значению из Header.ini
If gWttrUrl = "" Then gWttrUrl = sUrl
# проверка корректности значения интервала
If Not IsInt(gWttrInterval) Then gWttrInterval = 0
if gWttrInterval < 900 Then gWttrInterval = 900
# по умолчанию интервал считается законченным
gWttrSec = gWttrInterval
# проверка существования локального файла
If FileExist(gWttrFile) Then
# количество секунд с последнего обновления
gWttrSec = Round((Now() - FileGetTime(gWttrFile)) / 10000000)
# прошло меньше секунд, чем отведенный интервал
If gWttrSec < gWttrInterval Then gWttrData = StrTrim(FileRead(gWttrFile))
If gWttrName <> "" Then gWttrData = gWttrName & " " & gWttrData
EndIf
EndFunc
Func InfoHeader
Local nRecvSpeed, nSendSpeed, T1, lst = List(" | "," / ","—"," \ ")
Static c = 0
# поток запущен
gTitleThread = 1
# выполнять пока gShowTitle = true
While gShowTitle
T1 = GetUptime()
# погода включена и требуется обновление
If gWttr And gWttrSec >= gWttrInterval Then
# сброс счетчика
gWttrSec = 0
# запуск обновления в отдельном потоке
RunThread "GetWttrData"
EndIf
GetNetSpeed(nRecvSpeed, nSendSpeed)
# идет процесс обновления
If gWttrDataUpdate Then
c += 1
If c > lst.Count Then c = 1
#gWttrData = Weather updating: " & lst[c-1]
gWttrData = "Weather updating: " & gWttrSec & ' sec.'
EndIf
gInfoHeader = gTitle & ' ' & (gWttr ? gWttrData & ' ' : '') & Date("d MMMM, ddd") & '. CPU: ' & StrFormat("%02d", GetCPUUsage()) & '% RAM: ' & GetMemStats() & '% NET: ↓ ' & Round(nRecvSpeed / 1000, 1) & ' ↑ ' & Round(nSendSpeed / 1000, 1) & ' mb/s'
WinSetText(gInfoHeader)
# разбитие секунды на более мелкие интервалы
# для лучшего отклика при изменении переменной
While GetUptime() < T1 + 1000
If Not gShowTitle Then Break
Sleep(50)
Wend
# увеличение счетчика до следующего обновления погоды
gWttrSec += 1
Wend
Free(lst)
# поток остановлен
gTitleThread = 0
# обновление заголовка
SetInfoHeader()
EndFunc
Func GetWttrData()
Local msg, sData
# флаг операции
gWttrDataUpdate = true
gWttrTip = "Соединение..."
# загрузка файла в тихом режиме
Local code = WinInetDownloadFile(gWttrUrl, gWttrFile, 1)
# снятие флага операции для заголовка
gWttrDataUpdate = false
If code = -1 Then
msg = "WinInet Error: " & code
ElseIf code > 0 Then
msg = "WinInet Error: " & code
gWttrTip = msg & auCRLF & GetWinInetError(code)
EndIf
If code = 0 Then
gWttrTip = "Обновлено"
msg = FileRead(gWttrFile)
If ERROR = 1 Then msg = "FileRead Error: "
EndIf
sData = StrTrim(msg)
gWttrData = sData
# добавление имени местоположения если указано
If code = 0 And gWttrName <> "" Then gWttrData = gWttrName & " " & sData
If code = 0 Then
gWttrSec = 0
Else
# повтор через 30 секунд
gWttrSec = gWttrInterval - 30
EndIf
# загрузка данных для подсказки в тихом режиме
code = WinInetDownloadFile(gWttrHint, TEMP & "\wttr.html", 1)
If code <> 0 Then
msg = "WinInet Error: " & code
gWttrTip &= auCRLF & "Хинт: " & msg & auCRLF & GetWinInetError(code)
EndIf
EndFunc
Func InfoHeaderHint()
Local txt, file = TEMP & "\wttr.html"
If Not IsPressed (0x11) Then
If Not gShowTitle Then Return "Заголовок выключен"
txt &= "Работает" & auCRLF
txt &= "Погода " & (gWttr? "включена" : "отключена") & auCRLF
txt &= "Интервал: " & gWttrInterval & " сек." & auCRLF
txt &= "Обновление через: " & gWttrInterval - gWttrSec & " сек." & auCRLF
If gWttrTip <> "" Then txt &= "Статус: " & gWttrTip & auCRLF
If IsPressed (0x12) Then
txt &= "Файлы конфигурации:" & auCRLF
txt &= gWttrIni & auCRLF
txt &= gWttrIniApp & auCRLF
txt &= "Временные файлы:" & auCRLF
txt &= gWttrFile & auCRLF
txt &= file & auCRLF
EndIf
Return StrTrim(txt)
Endif
txt = FileRead(file)
If ERROR = 1 Then Return "Ошибка чтения " & file
# стиль подсказки
SetHintParam("csh", "Font", 10, "Consolas")
SetHintParam("csh", "BackColor", 0x001C1C1C)
SetHintParam("csh", "Text", 0xF9F9F9)
# извлечение текста из html
txt = StrReplace(txt, '"', '"')
Static lst = List()
lst.Count = 0
lst.Text = RegExpGet(txt, '<pre>(.*?)</pre>', "$1")
For i = 0 To lst.Count - 1
If StrLen(lst[i]) > 125 Then lst[i] = StrLeft(lst[i], 122) & ".."
Next
# вернуть предыдущий стиль через 1 сек.
RunThread InfoHeaderHintReload
Return lst.Text
EndFunc
Func InfoHeaderHintReload()
Sleep(1000)
SetHintParam("sh", "Reload")
SetHintParam("csh", "Reload")
EndFunc
Func InfoHeaderMenu()
ShowPopupMenu /D /F "InfoHeaderCreateMenu"
EndFunc
Func InfoHeaderCreateMenu()
Local txt
txt &= 'MENUITEM "Включить", em_aucmd "%COMMANDER_EXE%,37" InfoHeaderStart' & auCRLF
txt &= 'MENUITEM "Выключить", em_aucmd "%COMMANDER_EXE%,36" InfoHeaderStop' & auCRLF
txt &= 'MENUITEM "Обновить погоду", em_aucmd "shell32.dll,13" InfoHeaderUpdate' & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Настройки...", em_aucmd -1 InfoHeaderEditIni' & auCRLF
txt &= 'MENUITEM "Пользователь...", em_aucmd -1 InfoHeaderEditIniApp' & auCRLF
txt &= 'MENUITEM "Даты и время", em_aucmd "timedate.cpl,0" ShellExec rundll32.exe "shell32.dll,Control_RunDLL timedate.cpl"' & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Перейти к Wttr.ini", em_aucmd "WCMICONS.DLL,19" InfoHeaderGotoIniApp' & auCRLF
txt &= 'MENUITEM "Перейти к Wttr.txt", em_aucmd -1 InfoHeaderGotoTemp "Wttr.txt"' & auCRLF
txt &= 'MENUITEM "Перейти к Wttr.html", em_aucmd -1 InfoHeaderGotoTemp "Wttr.html"' & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Перейти к Header.ini", em_aucmd "WCMICONS.DLL,19" InfoHeaderGotoIni' & auCRLF
Return txt
EndFunc
Func InfoHeaderStart()
# запись значения в Header.ini
IniWrite %gWttrIni% "Title" "ShowTitle" 1
Sleep(100)
LaunchInfoHeader()
EndFunc
Func InfoHeaderStop()
IniWrite %gWttrIni% "Title" "ShowTitle" 0
Sleep(100)
LaunchInfoHeader()
EndFunc
Func InfoHeaderUpdate()
# обновление через 1 сек.
gWttrSec = gWttrInterval - 1
EndFunc
Func InfoHeaderEditIni()
If FileExist(gWttrIni) Then
ShellExec(gWttrIni)
Else
MsgBox("Файл не существует " & gWttrIni, "Autorun", 16)
EndIf
EndFunc
Func InfoHeaderGotoIni()
CommandExec("~/CD:S", gWttrIni)
EndFunc
Func InfoHeaderEditIniApp()
If FileExist(gWttrIniApp) Then
ShellExec(gWttrIniApp)
Else
MsgBox("Файл не существует " & gWttrIniApp, "Autorun", 16)
EndIf
EndFunc
Func InfoHeaderGotoIniApp()
CommandExec("~/CD:S", gWttrIniApp)
EndFunc
Func InfoHeaderGotoTemp(Filename)
Local sFile = TEMP & "\" & Filename
If FileExist(sFile) Then
CommandExec("~/CD:S", sFile)
Else
MsgBox("Файл не существует " & sFile, "Autorun", 16)
EndIf
EndFunc
Func GetNetSpeed(ByRef nRecvSpeed, ByRef nSendSpeed)
Static nIntfIdx = GetNetInterface()
If nIntfIdx = -1 Then Return
Static nPrevRecv = GetNetInterfaceInfo(nIntfIdx, 'Recv')
Static nPrevSend = GetNetInterfaceInfo(nIntfIdx, 'Sent')
Static nPrevTime = GetUptime()
Local nRecv = GetNetInterfaceInfo(nIntfIdx, 'Recv')
Local nSend = GetNetInterfaceInfo(nIntfIdx, 'Sent')
Local nTime = GetUptime()
Local nTimeDiff = nTime - nPrevTime
nRecvSpeed = Round(Abs(nRecv - nPrevRecv) / nTimeDiff)
nSendSpeed = Round(Abs(nSend - nPrevSend) / nTimeDiff)
nPrevRecv = nRecv
nPrevSend = nSend
nPrevTime = nTime
EndFunc |
Нужны только еще две дополнительные функции, которые можно найти 1-2 страницы назад, но я лучше их еще раз приложу.
 Hidden text | Code: | Func WinInetDownloadFile(URL, FileName, Silent = 0, Style = 0)
Static GENERIC_WRITE = 0x40000000, _
CREATE_ALWAYS = 2, FILE_ATTRIBUTE_NORMAL = 128
Static INTERNET_OPEN_TYPE_PRECONFIG = 0, _
INTERNET_FLAG_RELOAD = 0x80000000, _
INTERNET_FLAG_NO_CACHE_WRITE = 0x04000000
# Static INVALID_HANDLE_VALUE = auX64 ? 0xFFFFFFFFFFFFFFFF : 0xFFFFFFFF
Static INVALID_HANDLE_VALUE = auX64 ? 18446744073709551615 : 4294967295
Local hInt, hUrl, nSysErr, sAgent = "Autorun Downloader"
If Not Silent Then
tip("Internet connection.", 1, "Download", Style)
Sleep(200)
EndIf
hInt = DllCall("Wininet.dll\InternetOpenW", _
"wstr", sAgent, "dword", INTERNET_OPEN_TYPE_PRECONFIG, _
"ptr", 0, "ptr", 0, "ptr", 0, "handle")
nSysErr = SYSERROR
If Not (hInt > 0) Then
If Not Silent Then
tip("Error: " & nSysErr & auCRLF & _
"Message: " & GetWinInetError(nSysErr) & auCRLF & URL, 3, "Download", Style)
EndIf
Return nSysErr
EndIf
hUrl = DllCall("Wininet.dll\InternetOpenUrlW", _
"handle", hInt, "wstr", URL, "ptr", 0, _
"dword", 0, "dword", INTERNET_FLAG_RELOAD, _
"dword_ptr", 0, "handle")
nSysErr = SYSERROR
If Not (hUrl > 0) Then
DllCall("Wininet.dll\InternetCloseHandle", "handle", hInt)
If Not Silent Then
tip("Error: " & nSysErr & auCRLF & _
"Message: " & GetWinInetError(nSysErr) & auCRLF & URL, 3, "Download", Style)
EndIf
Return nSysErr
EndIf
# HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER
Local flags = BitOR(5, 0x20000000)
Local size, sz = 8
Local buf = Buffer(sz)
buf.Zero()
If DllCall("Wininet.dll\HttpQueryInfoW", _
"handle", hUrl, "dword", flags, "ptr", buf.ptr, "dword*", @sz, "ptr", 0) Then
size = buf.GetNum(0, "int64")
EndIf
Free(buf)
hFile = DllCall("CreateFileW", _
"wstr", FileName, "dword", GENERIC_WRITE, _
"dword", 0, "ptr", 0, "dword", CREATE_ALWAYS, _
"dword", FILE_ATTRIBUTE_NORMAL, "ptr", 0, "handle")
nSysErr = SYSERROR
If hFile <= 0 Or hFile = INVALID_HANDLE_VALUE Then
DllCall("Wininet.dll\InternetCloseHandle", "handle", hUrl)
DllCall("Wininet.dll\InternetCloseHandle", "handle", hInt)
If Not Silent Then
tip("File can't be created. Error: " & nSysErr & auCRLF & _
GetWinInetError(nSysErr) & auCRLF & FileName, 3, "Download", Style)
EndIf
Return nSysErr
EndIf
Local buf = Buffer(1024*2), bytes, written, total, prc
buf.Zero()
Local T1 = GetUptime(), T2 = T1, T3, nStyle = BitOR(Style, 1)
Do
bRes = DllCall("Wininet.dll\InternetReadFile", _
"handle", hUrl, "ptr", buf.ptr, "dword", buf.size, "dword*", @bytes)
If bRes And bytes > 0 Then
DllCall("WriteFile", "handle", hFile, _
"ptr", buf.ptr, "dword", bytes, "dword*", @written, "ptr", 0)
total += bytes
If Not Silent And size > buf.size Then
T3 = GetUptime()
If Round(T3 - T2, 0) > 500 Then
prc = "Download " & Round(total/size*100,0) & '%'
tip('Загружено: ' & SizeFormat(total, 1, 'M', 2) & ' ' & _
'из ' & SizeFormat(size, 1, 'M', 2), 1, prc, nStyle)
Sleep(10)
T2 = T3
EndIf
EndIf
EndIf
If IsPressed(0x1B) Then bRes = false
Until Not (bRes And bytes > 0)
DllCall("CloseHandle", "handle", hFile)
DllCall("Wininet.dll\InternetCloseHandle", "handle", hUrl)
DllCall("Wininet.dll\InternetCloseHandle", "handle", hInt)
T3 = Round(GetUptime() - T1, 0) / 1000
T3 = "Время операции: " & StrFormat("%.3f", T3) & " sec"
If Not Silent Then
If bRes Then
txt = "Download successful." & auCRLF & FileName & auCRLF & T3
tip(txt, 1, "Download", nStyle)
Else
txt = "Download failed or ended with an error." & auCRLF & T3
tip(txt, 3, "Download", nStyle)
EndIf
EndIf
Return (bRes ? 0 : -1)
EndFunc
Func GetWinInetError(nCode)
Local sMsg
Local hModule = DllCall("GetModuleHandleW", "Wstr", "wininet.dll", "handle")
If Not (hModule > 0) Then
Return "GetModuleHandle failed for wininet.dll. Error: " & SYSERROR
EndIf
Local FORMAT_MESSAGE_FROM_HMODULE = 0x00000800
Local FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100
Local FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
Local FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
Local flags = BitOR(FORMAT_MESSAGE_FROM_HMODULE, _
FORMAT_MESSAGE_IGNORE_INSERTS, _
FORMAT_MESSAGE_FROM_SYSTEM)
Local buf = Buffer(1024)
buf.Zero()
If DllCall("FormatMessageW", "dword", flags, "ptr", hModule, _
"dword", nCode, "dword", 0, "ptr", buf.ptr, "dword", buf.size, "ptr", 0) Then
sMsg = StrTrim(buf.GetStr())
Else
sMsg = "Failed to find error description"
EndIf
Free(buf)
Return sMsg
EndFunc
Global gTipText, gTipX, gTipY, gTipMenuItems
Global gTipWndProc, gTipWP = Callback("tipwp", "hwnd;uint;wparam;lparam")
#{
nFlags:
1 - Previous window position
2 - Square tooltip window
4 - Inactive tooltip window
0 - Default
#}
Func tip(sText, nIcon = 0, sTitle = "Tip", nFlags = 0, sMenuItems = "")
Static TTM_TRACKACTIVATE = 1041, _
TTM_TRACKPOSITION = 1042, _
TTM_SETMAXTIPWIDTH = 1048, _
TTM_SETTITLE = 1057, _
TTM_ADDTOOL = 1074, _
TTM_UPDATETIPTEXT = 1081
Static txt = Buffer(1024*2)
Static hTip = 0, buf = Buffer(auX64 ? 56 : 40)
Local nMaxWidth = 200
If hTip = 0 Then
# TTS_BALLOON | TTS_CLOSE | TTS_NOPREFIX
hTip = DllCall("CreateWindowExW", _
"dword", 8, _
"wstr", "tooltips_class32", _
"wstr", "", "dword", 0x00000c2, _
"int", 0, "int", 0, "int", 0, "int", 0, _
"handle", 0, _
"handle", 0, "handle", 0, "ptr", 0, "handle")
If hTip = 0 Then
MsgBox("Не удалось создать окно подсказки")
Return 0
EndIf
gTipWndProc = DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
"hwnd", hTip, "int", -4, "long_ptr", gTipWP.Ptr, "ptr")
txt.Zero()
txt.SetStr(sTitle & Chr(0))
SendMessage(hTip, TTM_SETTITLE, nIcon, txt.ptr)
buf.Zero()
# TTF_TRACK | TTF_ABSOLUTE | TTF_PARSELINKS
buf.SetNum(0, "uint", buf.size, "uint", 0x10a0, "hwnd", hTip)
buf.SetNum(auX64 ? 48 : 36, "ptr", txt.ptr)
SendMessage(hTip, TTM_ADDTOOL, 0, buf.ptr)
SendMessage(hTip, TTM_SETMAXTIPWIDTH, 0, nMaxWidth)
EndIf
If sText = "" Then
SendMessage(hTip, TTM_TRACKACTIVATE, 0, buf.ptr)
Return hTip
EndIf
# additional menu items
gTipMenuItems = sMenuItems
# cartoon or square
Local op = (BitAND(nFlags, 2) ? 4 : 2)
WinSetStyle(0x0000040, op, hTip)
txt.Zero()
txt.SetStr(sTitle & Chr(0))
SendMessage(hTip, TTM_SETTITLE, nIcon, txt.ptr)
txt.Zero()
txt.SetStr(sText & Chr(0))
# the next call won't fail if the tip is not visible
If WinGetState(2, hTip) = 0 Then
SendMessage(hTip, TTM_TRACKACTIVATE, 0, buf.ptr)
EndIf
SendMessage(hTip, TTM_UPDATETIPTEXT, 0, buf.ptr)
SendMessage(hTip, TTM_TRACKACTIVATE, 1, buf.ptr)
WinGetPos("x", "y", "w", "h", hTip)
# the tip will appear at the mouse pointer by default
If Not BitAND(nFlags, 1) Then MouseGetPos("x","y")
# preventing the tip from going off screen
If x + w > SYSINFO_DESKTOPWIDTH Then x = SYSINFO_DESKTOPWIDTH - w
If y + h > SYSINFO_DESKTOPHEIGHT Then y = SYSINFO_DESKTOPHEIGHT - h
SendMessage(hTip, TTM_TRACKPOSITION, 0, MakeInt(x, y, 0))
gTipX = x
gTipY = y
If Not BitAND(nFlags, 4) Then WinSetState(23, hTip)
Return hTip
EndFunc
Func tipwp(hWnd, uMsg, wParam, lParam)
Static MK_LBUTTON = 0x0001, TTM_TRACKPOSITION = 1042
Static DragWidth = GetSystemMetrics(68) #SM_CXDRAG
Static DragHeight = GetSystemMetrics(69) #SM_CYDRAG
Static IsDrag = 0, StartX = 0, StartY = 0
Local x, y
Static tx, ty, buf = Buffer(8)
#OutputDebugString("uMsg " & uMsg)
Switch uMsg
Case 0x004E # WM_NOTIFY
Static tag = 16 + _
48*2 + _
(2048 + 32 + 3)*2
hdr = Buffer(tag + (auX64 ? 24 : 12), lParam)
code = hdr.GetNum(auX64 ? 16 : 8, "uint")
If code = 0xFFFFFDF5 Then
link = hdr.GetStr(auX64 ? 136 : 124)
If StrPos(link, "://") Then
# MsgBox("Open the link?" & auCRLF & auCRLF & link, "Autorun", 3+32+0+262144)
# If EXTENDED <> 6 Then Return
ShellExec(link)
Else
Eval(link)
EndIf
EndIf
Case 0x0018 # WM_SHOWWINDOW
If wParam = 0 Then gTipMenuItems = ""
Case 0x0201 # WM_LBUTTONDOWN
If IsDrag = 0 Then
buf.Zero()
x = BitAND(lParam, 0xFFFF)
y = BitAND(BitShift(lParam,16), 0xFFFF)
StartX = x
StartY = y
buf.SetNum(0, "int", x, "int", y)
DllCall("ClientToScreen", "hwnd", hWnd, "ptr", buf.ptr)
tx = buf.GetNum(0)
ty = buf.GetNum(4)
IsDrag = 1
DllCall("SetCapture", "hwnd", hWnd, "hwnd")
EndIf
Case 0x0202 # WM_LBUTTONUP
If IsDrag = 1 Then
WinGetPos("gTipX", "gTipY", "", "", hWnd)
IsDrag = 0
DllCall("ReleaseCapture")
EndIf
Case 0x0200 # WM_MOUSEMOVE
If IsDrag = 1 And BitAND(wParam, MK_LBUTTON) Then
x = BitAND(lParam, 0xFFFF)
y = BitAND(BitShift(lParam,16), 0xFFFF)
If Abs(x - startX) > DragWidth Or Abs(y - startY) > DragHeight Then
buf.Zero()
buf.SetNum(0, "int", x, "int", y)
DllCall("ClientToScreen", "hwnd", hWnd, "ptr", buf.ptr)
x = buf.GetNum(0)
y = buf.GetNum(4)
SendMessage(hWnd, TTM_TRACKPOSITION, 0, MakeInt(gTipX+(x-tx), gTipY+(y-ty), 0))
EndIf
EndIf
Case 0x0205 # WM_RBUTTONUP
gTipText = WinGetText(hWnd)
ShowPopupMenu /D /F /I:0 "tipmnu"
Case 0x0100 # WM_KEYDOWN
If wParam = 0x1B Then WinSetState(0, hWnd)
EndSwitch
Return DllCall("CallWindowProcW", _
"ptr", gTipWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndFunc
Func tipmnu()
Local txt
txt &= 'MENUITEM "Copy text", em_aucmd ' & (gTipText <> "" ? "" : "/D") & ' -1 tipcopy' & auCRLF
If gTipMenuItems <> "" Then
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= gTipMenuItems
EndIf
Return txt
EndFunc
Func tipcopy()
#ClipPut %"gTipText"
ClipPut(gTipText)
EndFunc |
P.S.
Заголовок мне понравился, очень понравился. Даже завидую тем, кто первый раз его подключит ) |
|