Тема: AHK: удобный скрипт для сохранения скриншотов
Скрипт является развитием этой разработки.
ScreenCatcher - скрипт для быстрых скриншотов на AutoHotkey v1
ScreenCatcher делает снимки всего экрана, активного окна или выбранной области. Результат можно сохранить в файл, скопировать в буфер обмена или отправить на Imgbb.
Скрипт пригодится, если нужно быстро вырезать фрагмент экрана, повторно снимать одну и ту же область, подогнать рамку выделения с точностью до пикселя, посмотреть снимок перед сохранением и при необходимости сразу получить ссылку на изображение.
Скрипт управляется через меню иконки в трее. Также свои контекстные меню есть у окна выделения и у окна предпросмотра скриншота.
Основные возможности
снимок всего экрана
снимок активного окна
снимок области под окном выделения
быстрое выделение области мышью
сохранение снимка в файл
копирование снимка в буфер обмена
отправка снимка на Imgbb
предпросмотр снимков перед сохранением
перемещение и изменение размера окон предпросмотра
контекстное меню предпросмотра: сохранить, сохранить в текущем размере, удалить
точная подгонка границ окна выделения колесом мыши с модификаторами
настройка формата файла: png, jpg, bmp, tif, gif
настройка качества JPEG
выбор папки для сохранения файлов
захват курсора мыши на скриншоте
уведомления после сохранения
запуск вместе с Windows
настройка цвета и прозрачности окна выделения
два варианта подсказок при изменении размера окна выделения: измененные курсоры или цветные маркеры
настраиваемые горячие клавиши
Два способа выбрать область для скриншота
В ScreenCatcher есть два разных сценария для снимка области.
1. Окно выделения
Это полупрозрачная окно, которое можно показать, скрыть, переместить, центрировать и точно изменить в размере, растягивая мышью. Скриншот делается с области, которая находится под этим окном. Скриншот можно делать по двойному клику по окну выделения, либо, если окно скрыто, по горячей клавише (по умолчанию F12)
Для точной подгонки окна можно использовать колесо мыши с модификаторами, когда окно выделения активно (кликните по нему, чтобы сделать активным):
Ctrl + колесо - сдвиг левой границы
Shift + колесо - сдвиг верхней границы
Alt + колесо - сдвиг правой границы
Win + колесо - сдвиг нижней границы
Каждый шаг колеса меняет выбранную границу на 1 пиксель, поэтому так удобно выставлять область скриншота точно по краям нужного элемента.
Такой способ удобен, когда нужно:
несколько раз снимать одну и ту же область
заранее выставить точный размер кадра
аккуратно подогнать рамку по границам окна, изображения или элемента интерфейса
быстро повторять снимки без нового выделения мышью каждый раз
2. Быстрое выделение мышью поверх экрана
Это режим одноразового выбора прямоугольника прямо поверх экрана. После вызова режима появляется крестик курсора; область выбирается протягиванием мыши. При выборе через F4 сначала включается режим ожидания, рядом с курсором показываются координаты. После нажатия левой кнопки начинается выделение. При быстром варианте через Ctrl+Alt+ЛКМ выделение начинается сразу, без предварительной плашки координат.
Такой способ удобен, когда нужно:
быстро снять произвольный фрагмент экрана
не двигать основное окно выделения
один раз выбрать область и сразу отправить ее в общий механизм сохранения, буфера обмена, предпросмотра или Imgbb
Отменить выбор можно клавишей Esc или правой кнопкой мыши.
Предпросмотр
Если включена опция предпросмотра, после захвата открывается окно со снимком. Его можно перемещать и менять в размере колесом мыши. Через контекстное меню можно сохранить изображение, сохранить его в текущем размере после масштабирования или удалить окно предпросмотра.
Это удобно, если перед сохранением нужно проверить кадр, подогнать размер или оставить на экране несколько сделанных снимков.
Вывод снимков
В настройках можно выбрать один или несколько способов вывода:
в файл
в буфер обмена
на Imgbb.com
Способы можно комбинировать. Например, снимок может одновременно сохраняться в файл, копироваться в буфер обмена и отправляться на Imgbb.
Настройка отправки на Imgbb
Чтобы отправка на Imgbb работала, нужно получить API key.
Для этого:
1. Зарегистрироваться на Imgbb:
https://imgbb.com/
2. Открыть страницу API:
https://api.imgbb.com/
3. Получить ключ API.
4. Открыть файл ScreenCatcher.ini рядом со скриптом.
5. Вписать ключ в секцию [Imgbb]:
[Imgbb]
ClientID=YOUR_IMGBB_API_KEY6. В настройках ScreenCatcher на вкладке "Вывод" включить Imgbb.com.
Горячие клавиши по умолчанию
F12 - скриншот области под окном выделения
Right Shift + PrintScreen - скриншот активного окна
PrintScreen - скриншот всего экрана
Pause - показать или скрыть окно выделения
ScrollLock - переместить окно выделения в центр экрана
Left Ctrl + Space - выделить окно предпросмотра
F4 - выбрать область для скриншота мышью поверх экрана
Ctrl + Alt + ЛКМ - быстро выбрать область для скриншота мышью
Все горячие клавиши можно изменить в настройках. Если горячая клавиша не нужна, ее можно очистить.
Настройки
В окне настроек доступны вкладки:
"Цвет" - цвет и прозрачность окна выделения
"Вывод" - куда отправлять скриншоты, формат файла, качество JPEG и папка сохранения
"Настройки" - захват курсора, предпросмотр, уведомления, запуск вместе с Windows и режим подсказок при изменении размера рамки
"Горячие клавиши" - назначение сочетаний клавиш и мыши
Во время открытия окна настроек рабочие горячие клавиши ScreenCatcher временно отключаются, чтобы они не мешали вводу новых сочетаний в поля настройки.
Трей-меню и меню окна выделения
Основные действия доступны из меню в трее и из контекстного меню окна выделения:
открыть настройки
сделать скриншот
показать или скрыть окно выделения
переместить окно выделения в центр экрана
открыть папку вывода
открыть справку
выйти из скрипта
#NoEnv
#SingleInstance, force
#MaxHotkeysPerInterval 200
SetWinDelay, 0
SetBatchLines, -1
SetTitleMatchMode, 3
CoordMode, Mouse
OnExit("ShutdownApplication")
global App := {Config: {}, Settings: {}, Menu: {}, Selection: {}, Windows: {}}
hIcon16 := CreateIconFromBase64(GetBase64String(16), 16)
Menu, Tray, Icon, HICON:*%hIcon16%
hIcon32 := CreateIconFromBase64(GetBase64String(32), 32)
DllCall("SendMessage", "Ptr", A_ScriptHwnd, "UInt", WM_SETICON := 0x80, "Ptr", ICON_BIG := 1, "Ptr", hIcon32)
App.GdipToken := GdipStartup()
; секция ключ имя переменной умолчание
IniReadConfigSect("Color-Transparent", "ARGB" , "ARGB" , 0x82FFC700)
IniReadConfigSect("Output_Settings" , "Output" , "Output" , "File"
, "Extension" , "Ext" , "png"
, "JPEG_Quality" , "JPEGQuality" , 100
, "Out_Directory" , "OutDirectory" , A_ScriptDir)
IniReadConfigSect("Program_Settings" , "Capture_Cursor" , "CaptureCursor" , 0
, "Show_Preview" , "ShowPreview" , 1
, "Notify" , "Notify" , 1
, "Resize_Pointers" , "ResizePointers" , "Cursors"
, "InterpolationMode", "InterpolationMode", 3)
IniReadHotkeysSect("Hotkeys" , "GetArea" , "GetArea" , "$F12"
, "GetActiveWindow" , "GetActiveWindow" , ">+PrintScreen"
, "GetScreen" , "GetScreen" , "PrintScreen"
, "ShowHideSelWindow", "ShowHideSelWindow", "Pause"
, "SelWindowToCenter", "SelWindowToCenter", "ScrollLock"
, "SelectPreview" , "SelectPreview" , "<^Space"
, "OpenOutputFolder" , "OpenOutputFolder" , " "
, "SelectAreaOverlay", "SelectAreaOverlay", "F4"
, "QuickSelectAreaOverlay", "QuickSelectAreaOverlay", "^LButton")
NormalizeLoadedSettings()
Menu, Tray, NoStandard
Menu, Tray, Add, Справка, ShowHelp
Menu, Tray, Add
Menu, Tray, Add, Вывод, ShowSettingsFromMenu
Menu, Tray, Add, Настройки, ShowSettingsFromMenu
Menu, Tray, Add
App.Menu.TrayHide := MenuHotkeyCaption("Скрыть окно выделения", App.Hotkeys.ShowHideSelWindow)
App.Menu.TrayShow := MenuHotkeyCaption("Показать окно выделения", App.Hotkeys.ShowHideSelWindow)
App.Menu.TrayCenter := MenuHotkeyCaption("Окно выделения в центр экрана", App.Hotkeys.SelWindowToCenter)
App.Menu.TrayOpenOutDir := MenuHotkeyCaption("Открыть папку вывода", App.Hotkeys.OpenOutputFolder)
Menu, Tray, Add, % App.Menu.TrayShow, ToggleSelectionWindow
Menu, Tray, Add, % App.Menu.TrayCenter, CenterSelectionWindow
Menu, Tray, Add, % App.Menu.TrayOpenOutDir, OpenOutputDirectory
if !A_IsCompiled {
Menu, Tray, Add
Menu, Tray, Add, Редактировать скрипт, EditScript
Menu, Tray, Add, Перезагрузка, ReloadScript
}
Menu, Tray, Add
Menu, Tray, Add, Выход, ShutdownApplication
Menu, MainMenu, Add, Вывод, ShowSettingsFromMenu
Menu, MainMenu, Add, Настройки, ShowSettingsFromMenu
Menu, MainMenu, Add
App.Menu.MainArea := MenuHotkeyCaption("Сделать скриншот", App.Hotkeys.GetArea)
App.Menu.MainHide := MenuHotkeyCaption("Скрыть окно выделения", App.Hotkeys.ShowHideSelWindow)
App.Menu.MainOpenOutDir := MenuHotkeyCaption("Открыть папку вывода", App.Hotkeys.OpenOutputFolder)
Menu, MainMenu, Add, % App.Menu.MainArea, CaptureAreaScreenshot
Menu, MainMenu, Add, % App.Menu.MainHide, ToggleSelectionWindow
Menu, MainMenu, Add, % App.Menu.MainOpenOutDir, OpenOutputDirectory
Menu, MainMenu, Add
Menu, MainMenu, Add, Справка, ShowHelp
Menu, Interpolation, Add, Default, SetInterpolationMode
Menu, Interpolation, Add, LowQuality, SetInterpolationMode
Menu, Interpolation, Add, HighQuality, SetInterpolationMode
Menu, Interpolation, Add, Bilinear, SetInterpolationMode
Menu, Interpolation, Add, Bicubic, SetInterpolationMode
Menu, Interpolation, Add, NearestNeighbor, SetInterpolationMode
Menu, Interpolation, Add, HighQualityBilinear, SetInterpolationMode
Menu, Interpolation, Add, HighQualityBicubic, SetInterpolationMode
InterpolationModeString := "Default|LowQuality|HighQuality|Bilinear|"
. "Bicubic|NearestNeighbor|HighQualityBilinear|HighQualityBicubic"
App.Menu.InterpolationItems := StrSplit(InterpolationModeString, "|")
Menu, Interpolation, Check, % App.Menu.InterpolationItems[App.Config.InterpolationMode]
Menu, PreviewSaveToMenu, Add, файл, PreviewSaveToMenuHandling
Menu, PreviewSaveToMenu, Add, буфер обмена, PreviewSaveToMenuHandling
Menu, PreviewSaveToMenu, Add, imgbb.com, PreviewSaveToMenuHandling
Menu, PreviewSaveOriginalToMenu, Add, файл, PreviewSaveToMenuHandling
Menu, PreviewSaveOriginalToMenu, Add, буфер обмена, PreviewSaveToMenuHandling
Menu, PreviewSaveOriginalToMenu, Add, imgbb.com, PreviewSaveToMenuHandling
Menu, PreviewSaveCurrentToMenu, Add, файл, PreviewSaveCurrentToMenuHandling
Menu, PreviewSaveCurrentToMenu, Add, буфер обмена, PreviewSaveCurrentToMenuHandling
Menu, PreviewSaveCurrentToMenu, Add, imgbb.com, PreviewSaveCurrentToMenuHandling
Menu, ScreenShotMenu, Add, Сохранить в первоначальном размере, ScreenShotMenuHandling
Menu, ScreenShotMenu, Add, Сохранить в первоначальном размере в, :PreviewSaveOriginalToMenu
Menu, ScreenShotMenu, Add, Сохранить в текущем размере, ScreenShotMenuHandling
Menu, ScreenShotMenu, Add, Сохранить в текущем размере в, :PreviewSaveCurrentToMenu
Menu, ScreenShotMenu, Add, Удалить, ScreenShotMenuHandling
Menu, ScreenShotMenu2, Add, Интерполяция при изменении размеров, :Interpolation
Menu, ScreenShotMenu2, Add, Сохранить в, :PreviewSaveToMenu
Menu, ScreenShotMenu2, Add, Сохранить, ScreenShotMenuHandling
Menu, ScreenShotMenu2, Add, Удалить, ScreenShotMenuHandling
Gui, +LastFound -Caption +AlwaysOnTop +Owner
StoreSelectionWindowHwnd()
WinSet, Transparent, 0, % "ahk_id " App.Selection.Hwnd
Gui, Color, % Format("{:X}", App.Config.ARGB & 0xFFFFFF)
Locations = x190 y190|x0 y190|x0 y0|x190 y0|x190 y95|x95 y190|x0 y95|x95 y0
App.Selection.MarkerHwnds := []
Loop, parse, Locations, | ; SS_BITMAP = 0xE
{
Gui, Add, Text, % "w10 h10 +0xE hidden hwndMarkerHwnd " A_LoopField
App.Selection.MarkerHwnds.Push(MarkerHwnd)
}
UpdateMarkerColor()
SetResizeHotkeyState("Off")
if !A_Args.Length() {
CenterSelectionWindow()
} else {
opts := "x" (A_ScreenWidth - 200)//2 " y" (A_ScreenHeight - 200)//2 " h200 w200 Hide"
Gui, Show, % opts, ScreenСatcher
}
SetScriptHotkeys(1)
Esc := DllCall("RegisterWindowMessage", "Str", "Esc")
Wheel := DllCall("RegisterWindowMessage", "Str", "Wheel")
OnMessage( Esc, "WM_ESC")
OnMessage(Wheel, "WM_WHEEL")
OnMessage(0x018, "WM_SHOWWINDOW")
OnMessage(0x020, "WM_OVERLAY_SETCURSOR")
OnMessage(0x201, "WM_LBUTTONDOWN")
OnMessage(0x203, "WM_LBUTTONDBLCLK")
OnMessage(0x204, "WM_RBUTTONDOWN")
OnMessage(0x404, "AHK_NOTIFYICON")
return
;###########################################################################################################
;*************************************** Окно Настроек *****************************************************
;###########################################################################################################
OpenSettingsWindow(ThisMenuItemPos) {
HideHelpWindow()
App.Config.RunOnWinStart := IsRunOnWindowsStartEnabled()
SelectionHwnd := App.Selection.Hwnd
Gui, 2:Default
if WindowExistsByHwnd(App.Settings.WindowHwnd) {
if WindowExistsByHwnd(App.Settings.HotkeysHwnd)
Gui, 4:Hide
GuiControl, Choose, % App.Settings.TabHwnd, % ThisMenuItemPos
SuspendScriptHotkeysForSettings()
Gui, 2:Show
UpdateHotkeysTabVisibility()
return
}
SavePreviousSettingsState()
SuspendScriptHotkeysForSettings()
Width := 310, Height := 230
Gui, 2:+LastFound +hwndSettingsHwnd
App.Settings.WindowHwnd := SettingsHwnd
App.Windows[2] := Object("Hwnd", SettingsHwnd)
Gui, Font, s10 q5, Calibri
Gui, Add, Tab3, gUpdateHotkeysTabVisibility x0 y0 w%Width% h%Height% hwndSettingsTabHwnd AltSubmit -Wrap
, % " Цвет| Вывод|Настройки|Горячие клавиши"
App.Settings.TabHwnd := SettingsTabHwnd
GuiControl, Choose, % App.Settings.TabHwnd, % ThisMenuItemPos
;********************************** Первая вкладка "Цвет" ***********************************
Gui, Add, Pic, % "x10 y+10 h184 +0x8 w" Width - 21 ; SS_GRAYFRAME = 0x8
Gui, Font, s10, Segoe UI
Gui, Add, Text, % "Center c5021AC x15 yp+10 w" Width-30, Настройки цвета и прозрачности
Gui, Font, s8 q5, Verdana
Gui, Add, Text, x25 yp+37 w30 cRed Center, Red
Gui, Add, Text, xp-2 yp+30 wp cGreen Center, Green
Gui, Add, Text, xp yp+30 wp cBlue Center, Blue
Gui, Add, Text, xp yp+30 wp cEECC00 Center, Trans
ColorState := App.Settings.Color := Object()
ColorState.Red := (App.Config.ARGB & 0xFF0000)>>16
ColorState.Green := (App.Config.ARGB & 0xFF00)>>8
ColorState.Blue := App.Config.ARGB & 0xFF
ColorState.Trans := App.Config.ARGB>>24
Options := "x65 w" Width - 115 " h20 Range0-255 ToolTip AltSubmit"
Gui, Add, Slider, gUpdateSelectionColorFromGui %Options% yp-91 hwndRedSliderHwnd, % ColorState.Red
Gui, Add, Slider, gUpdateSelectionColorFromGui %Options% yp+30 hwndGreenSliderHwnd, % ColorState.Green
Gui, Add, Slider, gUpdateSelectionColorFromGui %Options% yp+30 hwndBlueSliderHwnd, % ColorState.Blue
Gui, Add, Slider, gUpdateSelectionTransparencyFromGui %Options% yp+30 hwndTransSliderHwnd, % ColorState.Trans
Gui, Add, Text, xp+195 yp-89 w30 cRed Center hwndRedValueHwnd, % ColorState.Red
Gui, Add, Text, xp yp+30 wp cGreen Center hwndGreenValueHwnd, % ColorState.Green
Gui, Add, Text, xp yp+30 wp cBlue Center hwndBlueValueHwnd, % ColorState.Blue
Gui, Add, Text, xp yp+30 wp cEECC00 Center hwndTransValueHwnd, % ColorState.Trans
App.Settings.RedSliderHwnd := RedSliderHwnd
App.Settings.GreenSliderHwnd := GreenSliderHwnd
App.Settings.BlueSliderHwnd := BlueSliderHwnd
App.Settings.TransSliderHwnd := TransSliderHwnd
App.Settings.RedValueHwnd := RedValueHwnd
App.Settings.GreenValueHwnd := GreenValueHwnd
App.Settings.BlueValueHwnd := BlueValueHwnd
App.Settings.TransValueHwnd := TransValueHwnd
;********************************* Вторая вкладка "Вывод" ************************************
Gui, Tab, 2
Gui, Font, s10, Segoe UI
Gui, Add, Text, % "Center c5021AC x5 y+6 w" Width-10, Как сохранять скриншоты:
Gui, Font, s8 q5, Verdana
Gui, Add, Checkbox
, % "gUpdateOutputTargetFromGui x15 yp+25 hwndOutputFileHwnd" (InStr(App.Config.Output, "File") ? " Checked" : ""), В файл
Gui, Add, Checkbox
, % "gUpdateOutputTargetFromGui xp+75 yp hwndOutputClipHwnd" (InStr(App.Config.Output, "Clip") ? " Checked" : ""), В буфер обмена
Gui, Add, Checkbox
, % "gUpdateOutputTargetFromGui xp+125 yp hwndOutputImgbbHwnd" (InStr(App.Config.Output, "Imgbb") ? " Checked" : ""), Imgbb.com
App.Settings.OutputFileHwnd := OutputFileHwnd
App.Settings.OutputClipHwnd := OutputClipHwnd
App.Settings.OutputImgbbHwnd := OutputImgbbHwnd
Gui, Add, Pic, % "x2 yp+26 h2 +0x8 w" Width - 4 ; SS_GRAYFRAME = 0x8
Gui, Font, s10, Segoe UI
Gui, Add, Text, % "Center c5021AC x5 yp+9 w" Width-10, Тип файлов для вывода
Gui, Font, s8 q5, Verdana
Gui, Add, Radio, % "gSetOutputExtensionFromGui x25 yp+23 hwndExtensionPngHwnd" (App.Config.Ext = "png" ? " Checked" : ""), png
Gui, Add, Radio, % "gSetOutputExtensionFromGui xp+55 yp hwndExtensionJpgHwnd" (App.Config.Ext = "jpg" ? " Checked" : ""), jpg
Gui, Add, Radio, % "gSetOutputExtensionFromGui xp+55 yp hwndExtensionBmpHwnd" (App.Config.Ext = "bmp" ? " Checked" : ""), bmp
Gui, Add, Radio, % "gSetOutputExtensionFromGui xp+55 yp hwndExtensionTifHwnd" (App.Config.Ext = "tif" ? " Checked" : ""), tif
Gui, Add, Radio, % "gSetOutputExtensionFromGui xp+55 yp hwndExtensionGifHwnd" (App.Config.Ext = "gif" ? " Checked" : ""), gif
App.Settings.ExtensionPngHwnd := ExtensionPngHwnd
App.Settings.ExtensionJpgHwnd := ExtensionJpgHwnd
App.Settings.ExtensionBmpHwnd := ExtensionBmpHwnd
App.Settings.ExtensionTifHwnd := ExtensionTifHwnd
App.Settings.ExtensionGifHwnd := ExtensionGifHwnd
Gui, Font, s10, Segoe UI
Gui, Add, Text, Left c5021AC x20 yp+23, Качество jpg:
Gui, Add, Slider
, gSetJpegQuality xp+107 yp w128 h20 Range50-100 ToolTip AltSubmit hwndJpegQualitySliderHwnd, % App.Config.JPEGQuality
Gui, Font, s8 q5, Verdana
Gui, Add, Text, Center c5021AC xp+132 yp+2 w30 hwndJpegQualityPercentHwnd, % App.Config.JPEGQuality "`%"
App.Settings.JpegQualitySliderHwnd := JpegQualitySliderHwnd
App.Settings.JpegQualityPercentHwnd := JpegQualityPercentHwnd
Gui, Add, Pic, % "x2 yp+26 h2 +0x8 w" Width - 4 ; SS_GRAYFRAME = 0x8
Gui, Font, s10, Segoe UI
Gui, Add, Text, % "Center c5021AC x5 yp+9 w" Width-10, Папка для сохранения файлов
Gui, Font, s8 q5, Verdana
Gui, Add, Edit, % "hwndOutDirectoryEditHwnd x10 yp+24 h21 w" Width-50, % App.Config.OutDirectory
App.Settings.OutDirectoryEditHwnd := OutDirectoryEditHwnd
Gui, Font, s10
Gui, Add, Button, % "gSelectOutputDirectory x" Width-35 " yp hp w23", ...
;************************** Третья вкладка "Настройки программы" ****************************
Gui, Tab, 3
Gui, Font, s8 q5, Verdana
Gui, Add, Checkbox
, % "x20 y+15 hwndCaptureCursorHwnd" (App.Config.CaptureCursor ? " Checked" : "")
, Включать курсор в скриншот
Gui, Add, Checkbox, % "xp yp+25 hwndShowPreviewHwnd" (App.Config.ShowPreview ? " Checked" : "")
, Показывать скриншот перед сохранением
Gui, Add, Checkbox, % "xp yp+25 hwndNotifyHwnd" (App.Config.Notify ? " Checked" : "")
, Уведомлять о сохранении скриншота
Gui, Add, Checkbox
, % "xp yp+25 hwndRunOnWinStartHwnd" (App.Config.RunOnWinStart ? " Checked" : "")
, Запускать программу при загрузке системы
App.Settings.CaptureCursorHwnd := CaptureCursorHwnd
App.Settings.ShowPreviewHwnd := ShowPreviewHwnd
App.Settings.NotifyHwnd := NotifyHwnd
App.Settings.RunOnWinStartHwnd := RunOnWinStartHwnd
Gui, Add, Checkbox, xp yp+25, Проверять обновления при запуске
; Gui, Add, Pic, % "x2 yp+30 h2 +0x8 w" Width - 4 ; SS_GRAYFRAME = 0x8
Gui, Font, s10, Segoe UI
Gui, Add, Text, % "Center c5021AC x5 yp+25 w" Width-10
, Индикаторы при изменении размеров`nокна выделения
Gui, Font, s8 q5, Verdana
Gui, Add, Radio, xp+14 yp+40 hwndResizeCursorsHwnd, Изменённые курсоры
Gui, Add, Radio, xp+153 yp hwndResizeMarkersHwnd, Цветные маркеры
GuiControl,, % (App.Config.ResizePointers = "Cursors" ? ResizeCursorsHwnd : ResizeMarkersHwnd), 1
App.Settings.ResizeCursorsHwnd := ResizeCursorsHwnd
App.Settings.ResizeMarkersHwnd := ResizeMarkersHwnd
Gui, Tab
;*************************** Четвёртая вкладка "Горячие клавиши" *****************************
HotkeysTabPageHwnd := DllCall("GetWindow", "Ptr", App.Settings.TabHwnd, "UInt", GW_HWNDNEXT := 2)
WinGetPos,,, W, H, ahk_id %HotkeysTabPageHwnd%
Gui, 4: Default
Gui, +Parent%HotkeysTabPageHwnd% -Caption +ToolWindow +hwndHotkeysHwnd
App.Settings.HotkeysHwnd := HotkeysHwnd
Gui, Add, Tab3, % "gFocusSettingsSafeButton x" 5 " y" 5 " w" W - 8 " h" H - 9 " hwndHotkeysSubTabHwnd", Скриншоты|Окна скрипта|Служебные
App.Settings.HotkeysSubTabHwnd := HotkeysSubTabHwnd
Handles := []
HotkeyControls := []
HotkeyNames := ScreenCatcherHotkeyNames()
for k, v in [ "Скриншот под окном выделения"
, "Скриншот активного окна"
, "Скриншот всего экрана"
, "Скрыть/показать окно выделения"
, "Окно выделения в центр экрана"
, "Выделить превью скриншота"
, "Открыть папку вывода"
, "Выбрать область для скриншота"
, "Быстро выделить область для скриншота" ]
{
if k = 4
Gui, Tab, 2
if k = 7
Gui, Tab, 3
Gui, Font, s10, Segoe UI
Gui, Add, Text, % "x0 y+8 w" . (Width - 6) . " Center c5021AC", %v%:
Gui, Font, s11, calibri
Gui, Add, Edit, % "Center ReadOnly x15 y+5 h23 w" . (Width-36) . " hwndhHotkey" . k
SetStaticColor(hHotkey%k%, 0xFFFFFF)
Handles.Push(hHotkey%k%)
Options := "KDMLR"
HotkeyControls.Push([HotkeyNames[k], hHotkey%k%, Options])
}
Hotkey_Register(HotkeyControls*)
SetHotkeyControlsFromVars()
Gui, Show, Hide x0 y0 w%W% h%H%
App.Settings.MessageHandlers := {}
App.Settings.MessageHandlers.WM_COMMAND := Func("WM_COMMAND").Bind(Handles)
App.Settings.MessageHandlers.WM_SETCURSOR := Func("WM_SETCURSOR").Bind(Handles)
OnMessage( 0x111, App.Settings.MessageHandlers.WM_COMMAND )
OnMessage( 0x20, App.Settings.MessageHandlers.WM_SETCURSOR )
;***********************************************************************************************
Gui, 2:Default
Gui, Font, s8 q5, Verdana
Gui, Add, Button, % "gConfirmSettingsFromGui x" Width - 286 " y" Height + 14 " w85 h23", OK
Gui, Add, Button, gApplySettingsFromGui xp+90 yp wp hp, Применить
Gui, Add, Button, gCancelSettingsFromGui xp+90 yp wp hp, Отмена
if WinExist("ahk_id " SelectionHwnd) {
WinGetPos, X1, Y1, W1, H1, ahk_id %SelectionHwnd%
Gui, Show, % "w" Width-1 " h" Height+51 " Hide", Настройки
DetectHiddenWindows, On
WinGetPos,,, W2, H2, % "ahk_id " App.Settings.WindowHwnd
X := ((X2 := X1 + (W1 - W2)//2) + W2 > A_ScreenWidth) ? A_ScreenWidth - W2 : X2 < 0 ? 0 : X2
Y := ((Y2 := Y1 + H1 + 20) + H2 < A_ScreenHeight) ? Y2 : (Y2 := Y1 - 20 - H2) < 0 ? 0 : Y2
Gui, Show, x%X% y%Y%, Настройки
DetectHiddenWindows, Off
} else {
Gui, Show, % "w" Width-1 " h" Height+51, Настройки
}
return
}
2GuiEscape() {
CancelSettingsFromGui()
}
2GuiClose() {
CancelSettingsFromGui()
}
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Конец окна Настроек ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ScreenShotMenu() {
ScreenShotMenuHandling()
}
SetInterpolationMode() {
SetInterpolationModeFromMenu(A_ThisMenuItemPos)
}
ReloadScript() {
SelectionHwnd := App.Selection.Hwnd
if WinExist("ahk_id " SelectionHwnd) {
Reload
return
}
Run, % """" A_AhkPath """ /restart """ A_ScriptFullPath """ HideSelection", % A_ScriptDir
ExitApp
}
EditScript() {
Edit
}
ShowHelp() {
HideSettingsWindow()
if !IsObject(App.Help)
App.Help := {}
HelpText := BuildHelpText()
if WindowExistsByHwnd(App.Help.WindowHwnd) {
GuiControl, 6:, % App.Help.TextHwnd, % HelpText
Gui, 6:Show,, Справка
return
}
Width := 520, TextHeight := 410, Margin := 14, ButtonWidth := 90
TextWidth := Width - Margin * 2
WindowHeight := TextHeight + 62
Gui, 6:+LastFound +hwndHelpHwnd
App.Help.WindowHwnd := HelpHwnd
Gui, 6:Margin, %Margin%, %Margin%
Gui, 6:Font, s10 q5, Segoe UI
Gui, 6:Add, Edit, % "ReadOnly +VScroll w" TextWidth " h" TextHeight " hwndHelpTextHwnd", % HelpText
SetStaticColor(HelpTextHwnd, 0xFFFFFF, 0x000000)
App.Help.TextHwnd := HelpTextHwnd
Gui, 6:Add, Button, % "gCloseHelpWindow Default x" (Width - Margin - ButtonWidth) " y+10 w" ButtonWidth " h24", OK
Gui, 6:Show, % "w" Width " h" WindowHeight, Справка
PostMessage, 0x00B1, 0, 0, , ahk_id %HelpTextHwnd% ; EM_SETSEL
return
}
6GuiEscape() {
HideHelpWindow()
}
6GuiClose() {
HideHelpWindow()
}
CloseHelpWindow(CtrlHwnd := "", GuiEvent := "", EventInfo := "", EventErrorLevel := "") {
HideHelpWindow()
}
HideHelpWindow() {
if !IsObject(App.Help)
return
if WindowExistsByHwnd(App.Help.WindowHwnd)
Gui, 6:Hide
}
HideSettingsWindow() {
if WindowExistsByHwnd(App.Settings.HotkeysHwnd)
Gui, 4:Hide
if WindowExistsByHwnd(App.Settings.WindowHwnd) {
Gui, 2:Hide
ResumeScriptHotkeysAfterSettings()
}
}
BuildHelpText() {
Text =
(
ScreenCatcher
ScreenCatcher делает снимки экрана, активного окна и выбранной области. Снимок можно сохранить в файл, скопировать в буфер обмена, открыть в предпросмотре или загрузить на Imgbb.
Возможности:
- снимок всего экрана, активного окна или выбранной области;
- выбор области рамкой или быстрым выделением мышью поверх экрана;
- точное позиционирование, центрирование и изменение размера окна выделения;
- предпросмотр снимков: окна можно перемещать, изменять в размере и открывать по ним контекстное меню;
- настройка формата файла, качества JPEG и папки сохранения;
- захват курсора, уведомления и запуск вместе с Windows;
- настройка цвета, прозрачности и маркеров окна выделения.
)
Text .= "`r`n`r`nГорячие клавиши:`r`n" . BuildHelpHotkeysText()
Text .= "`r`n`r`nПодсказки:`r`n"
Text .= "- Если горячая клавиша не назначена, действие можно вызвать из меню трея.`r`n"
Text .= "- При быстром выделении мышью выберите нужную область; Esc или правая кнопка отменяют выбор.`r`n"
Text .= "- Горячие клавиши можно изменить в настройках."
return Text
}
BuildHelpHotkeysText() {
Labels := ScreenCatcherHotkeyLabels()
Text := ""
for k, HotkeyName in ScreenCatcherHotkeyNames()
Text .= Labels[HotkeyName] ": " HelpHotkeyText(App.Hotkeys[HotkeyName]) "`r`n"
return RTrim(Text, "`r`n")
}
HelpHotkeyText(HotkeyValue) {
Text := Hotkey_HKToStr(HotkeyValue)
return (Text = "Нет" || !IsHotkeyEnabled(HotkeyValue)) ? "не назначена" : Text
}
WindowExistsByHwnd(Hwnd) {
if !Hwnd
return false
DetectHiddenWindowsWasOn := A_DetectHiddenWindows
DetectHiddenWindows, On
Exists := WinExist("ahk_id " Hwnd)
DetectHiddenWindows, %DetectHiddenWindowsWasOn%
return Exists
}
ShowSettingsFromMenu(ItemName := "", ItemPos := "", MenuName := "") {
OpenSettingsWindow(SettingsTabFromMenu(MenuName, ItemPos))
}
SettingsTabFromMenu(MenuName, ItemPos) {
if (MenuName = "Tray")
return ItemPos - 1
return ItemPos + 1
}
StoreSelectionWindowHwnd() {
WinGet, SelectionHwnd
App.Selection.Hwnd := SelectionHwnd
}
ShutdownApplication() {
SelectionHwnd := App.Selection.Hwnd
Loop {
if (MaxIndex := App.Windows.MaxIndex()) {
Gui, %MaxIndex%:Destroy
App.Windows.Remove(MaxIndex, "")
Sleep, 50
}
} until !MaxIndex
if WinExist("ahk_id " SelectionHwnd)
Melt(SelectionHwnd, App.Config.ARGB>>24, 0)
if IsObject(App.Selection.Overlay)
App.Selection.Overlay.Dispose()
RestoreCursors()
GdipShutdown(App.GdipToken)
SaveSettings()
ExitApp
}
MenuHotkeyCaption(Text, HotkeyValue) {
hk := Hotkey_HKToStr(HotkeyValue)
return Text . (hk = "Нет" ? "" : A_Tab . hk)
}
UpdateMenuHotkeyCaptions() {
SelectionHwnd := App.Selection.Hwnd
NewTrayMenuHide := MenuHotkeyCaption("Скрыть окно выделения", App.Hotkeys.ShowHideSelWindow)
NewTrayMenuShow := MenuHotkeyCaption("Показать окно выделения", App.Hotkeys.ShowHideSelWindow)
NewTrayMenuCenter := MenuHotkeyCaption("Главное окно в центр экрана", App.Hotkeys.SelWindowToCenter)
NewTrayMenuOpenOutDir := MenuHotkeyCaption("Открыть папку вывода", App.Hotkeys.OpenOutputFolder)
NewMainMenuArea := MenuHotkeyCaption("Сделать скриншот", App.Hotkeys.GetArea)
NewMainMenuHide := MenuHotkeyCaption("Скрыть окно выделения", App.Hotkeys.ShowHideSelWindow)
NewMainMenuOpenOutDir := MenuHotkeyCaption("Открыть папку вывода", App.Hotkeys.OpenOutputFolder)
if WinExist("ahk_id " SelectionHwnd)
Menu, Tray, Rename, % App.Menu.TrayHide, % NewTrayMenuHide
else
Menu, Tray, Rename, % App.Menu.TrayShow, % NewTrayMenuShow
Menu, Tray, Rename, % App.Menu.TrayCenter, % NewTrayMenuCenter
Menu, Tray, Rename, % App.Menu.TrayOpenOutDir, % NewTrayMenuOpenOutDir
Menu, MainMenu, Rename, % App.Menu.MainArea, % NewMainMenuArea
Menu, MainMenu, Rename, % App.Menu.MainHide, % NewMainMenuHide
Menu, MainMenu, Rename, % App.Menu.MainOpenOutDir, % NewMainMenuOpenOutDir
App.Menu.TrayHide := NewTrayMenuHide
App.Menu.TrayShow := NewTrayMenuShow
App.Menu.TrayCenter := NewTrayMenuCenter
App.Menu.TrayOpenOutDir := NewTrayMenuOpenOutDir
App.Menu.MainArea := NewMainMenuArea
App.Menu.MainHide := NewMainMenuHide
App.Menu.MainOpenOutDir := NewMainMenuOpenOutDir
}
SaveSettings() {
S_FormatInteger := A_FormatInteger
SetFormat, IntegerFast, H
; секция ключ значение
IniWriteSect("Color-Transparent", "ARGB" , App.Config.ARGB)
SetFormat, IntegerFast, D
IniWriteSect("Output_Settings" , "Output" , App.Config.Output
, "Extension" , App.Config.Ext
, "JPEG_Quality" , App.Config.JPEGQuality
, "Out_Directory" , App.Config.OutDirectory)
IniWriteSect("Program_Settings" , "Capture_Cursor" , App.Config.CaptureCursor
, "Show_Preview" , App.Config.ShowPreview
, "Notify" , App.Config.Notify
, "Resize_Pointers" , App.Config.ResizePointers
, "InterpolationMode", App.Config.InterpolationMode)
IniWriteSect("Hotkeys" , "GetArea" , App.Hotkeys.GetArea
, "GetActiveWindow" , App.Hotkeys.GetActiveWindow
, "GetScreen" , App.Hotkeys.GetScreen
, "ShowHideSelWindow", App.Hotkeys.ShowHideSelWindow
, "SelWindowToCenter", App.Hotkeys.SelWindowToCenter
, "SelectPreview" , App.Hotkeys.SelectPreview
, "OpenOutputFolder" , App.Hotkeys.OpenOutputFolder
, "SelectAreaOverlay", App.Hotkeys.SelectAreaOverlay
, "QuickSelectAreaOverlay", App.Hotkeys.QuickSelectAreaOverlay)
SetFormat, IntegerFast, %S_FormatInteger%
}
SettingsStateVars() {
return "ARGB|Output|ext|JPEGQuality|OutDirectory|CaptureCursor|ShowPreview|Notify|"
. "RunOnWinStart|ResizePointers|GetArea|GetActiveWindow|GetScreen|"
. "ShowHideSelWindow|SelWindowToCenter|SelectPreview|OpenOutputFolder|"
. "SelectAreaOverlay|QuickSelectAreaOverlay"
}
SavePreviousSettingsState(StateVars := "") {
if (StateVars = "")
StateVars := SettingsStateVars()
App.Settings.Previous := {}
Loop, parse, StateVars, |
App.Settings.Previous[A_LoopField] := SettingsStateValue(A_LoopField)
}
RestorePreviousSettingsState(StateVars := "") {
SelectionHwnd := App.Selection.Hwnd
Previous := App.Settings.Previous
if !IsObject(Previous)
return
if (App.Config.ARGB != Previous.ARGB)
ColorChange := App.Config.ARGB
if WinExist("ahk_id " SelectionHwnd)
SetResizePointerTimer("Off")
if (StateVars = "")
StateVars := SettingsStateVars()
Loop, parse, StateVars, |
SetSettingsStateValue(A_LoopField, Previous[A_LoopField])
App.Config.ResizePointers := NormalizeResizePointersValue(App.Config.ResizePointers)
SyncSettingsColorFromARGB()
SetHotkeyControlsFromVars()
if WinExist("ahk_id " SelectionHwnd)
SetResizePointerTimer(50)
if ColorChange {
if WinExist("ahk_id " SelectionHwnd)
Melt(SelectionHwnd, ColorChange>>24, 0), PrevExist := 1
Gui, 1:Color, % Format("{:X}", App.Config.ARGB & 0xFFFFFF)
UpdateMarkerColor()
if PrevExist
PrevExist := "", Melt(SelectionHwnd, App.Config.ARGB>>24, 1)
ColorChange := ""
}
}
SyncSettingsColorFromARGB() {
if !IsObject(App.Settings.Color)
App.Settings.Color := {}
App.Settings.Color.Red := (App.Config.ARGB & 0xFF0000)>>16
App.Settings.Color.Green := (App.Config.ARGB & 0xFF00)>>8
App.Settings.Color.Blue := App.Config.ARGB & 0xFF
App.Settings.Color.Trans := App.Config.ARGB>>24
}
SettingsStateValue(Name) {
for index, HotkeyName in ScreenCatcherHotkeyNames()
if (Name = HotkeyName)
return App.Hotkeys[HotkeyName]
for index, ConfigName in SettingsConfigNames()
if (Name = ConfigName)
return App.Config[ConfigName]
if (Name = "ResizePointers")
return NormalizeResizePointersValue(App.Config.ResizePointers)
if (Name = "InterpolationMode")
return App.Config.InterpolationMode
return ""
}
SetSettingsStateValue(Name, Value) {
for index, HotkeyName in ScreenCatcherHotkeyNames() {
if (Name = HotkeyName) {
App.Hotkeys[HotkeyName] := Value
return
}
}
for index, ConfigName in SettingsConfigNames() {
if (Name = ConfigName) {
App.Config[ConfigName] := Value
return
}
}
if (Name = "ResizePointers")
App.Config.ResizePointers := NormalizeResizePointersValue(Value)
else if (Name = "InterpolationMode")
App.Config.InterpolationMode := Value
}
SettingsConfigNames() {
return [ "ARGB", "Output", "ext", "JPEGQuality", "OutDirectory"
, "CaptureCursor", "ShowPreview", "Notify", "RunOnWinStart" ]
}
CloseSettingsWindow() {
if IsObject(App.Settings.MessageHandlers) {
OnMessage( 0x111, App.Settings.MessageHandlers.WM_COMMAND, 0 )
OnMessage( 0x20, App.Settings.MessageHandlers.WM_SETCURSOR, 0 )
App.Settings.MessageHandlers := ""
}
Gui, 2:Destroy
ResumeScriptHotkeysAfterSettings()
}
SuspendScriptHotkeysForSettings() {
if App.Settings.ScriptHotkeysSuspended
return
SetScriptHotkeys(0)
App.Settings.ScriptHotkeysSuspended := true
}
ResumeScriptHotkeysAfterSettings() {
if !App.Settings.ScriptHotkeysSuspended
return
App.Settings.ScriptHotkeysSuspended := false
SetScriptHotkeys(1)
}
ApplySettingsFromGui(CtrlHwnd := "", GuiEvent := "", EventInfo := "", EventErrorLevel := "") {
if !ApplyHotkeySettings()
return false
ApplyProgramSettings()
CheckImgbbClientIdOnApply()
SaveSettings()
SavePreviousSettingsState()
return true
}
CheckImgbbClientIdOnApply() {
if !InStr(App.Config.Output, "Imgbb")
return
EnsureImgbbClientId()
}
EnsureImgbbClientId() {
IniPath := IniFilePath()
MissingValue := Chr(1) . "__ScreenCatcherMissing__"
IniRead, ClientID, % IniPath, Imgbb, ClientID, % MissingValue
if (ClientID = MissingValue) {
EmptyValue := ""
IniWrite, % EmptyValue, % IniPath, Imgbb, ClientID
ClientID := ""
}
if (Trim(ClientID) != "")
return ClientID
Message := "Для отправки скриншотов на Imgbb нужен API key.`n`n"
. "Зарегистрируйтесь: https://imgbb.com/`n"
. "Получите ключ: https://api.imgbb.com/`n`n"
. "Впишите ключ в файл ScreenCatcher.ini:`n"
. "[Imgbb]`nClientID=..."
SetOwnDialogsForOpenWindows()
MsgBox, 48, Нужен ключ Imgbb, %Message%
Run, % "notepad.exe """ IniPath """"
return ""
}
SetOwnDialogsForOpenWindows() {
if WindowExistsByHwnd(App.Selection.Hwnd)
Gui, 1:+OwnDialogs
if WindowExistsByHwnd(App.Settings.WindowHwnd)
Gui, 2:+OwnDialogs
if WindowExistsByHwnd(App.Settings.HotkeysHwnd)
Gui, 4:+OwnDialogs
if WindowExistsByHwnd(App.Menu.HighlightHwnd) || WinExist("Imgbb.com ahk_class AutoHotkeyGUI")
Gui, 5:+OwnDialogs
if IsObject(App.Help) && WindowExistsByHwnd(App.Help.WindowHwnd)
Gui, 6:+OwnDialogs
if IsObject(App.Selection.Overlay) && IsObject(App.Selection.Overlay.overlay)
&& WindowExistsByHwnd(App.Selection.Overlay.overlay.hwnd)
Gui, SelectionOverlay:+OwnDialogs
for GuiNumber, WindowData in App.Windows {
if IsObject(WindowData) && WindowExistsByHwnd(WindowData.Hwnd)
Gui, %GuiNumber%:+OwnDialogs
}
}
ConfirmSettingsFromGui(CtrlHwnd := "", GuiEvent := "", EventInfo := "", EventErrorLevel := "") {
if !ApplySettingsFromGui()
return false
CloseSettingsWindow()
return true
}
CancelSettingsFromGui(CtrlHwnd := "", GuiEvent := "", EventInfo := "", EventErrorLevel := "") {
RestorePreviousSettingsState()
CloseSettingsWindow()
}
ScreenCatcherHotkeyNames() {
return ["GetArea", "GetActiveWindow", "GetScreen", "ShowHideSelWindow"
, "SelWindowToCenter", "SelectPreview", "OpenOutputFolder"
, "SelectAreaOverlay", "QuickSelectAreaOverlay"]
}
ScreenCatcherHotkeyLabels() {
return { GetArea: "Скриншот под окном выделения"
, GetActiveWindow: "Скриншот активного окна"
, GetScreen: "Скриншот всего экрана"
, ShowHideSelWindow: "Скрыть/показать окно выделения"
, SelWindowToCenter: "Окно выделения в центр экрана"
, SelectPreview: "Выделить превью скриншота"
, OpenOutputFolder: "Открыть папку вывода"
, SelectAreaOverlay: "Начать выделение мышью"
, QuickSelectAreaOverlay: "Быстро выделить область мышью" }
}
ScreenCatcherHotkeyIndex(Name) {
for k, v in ScreenCatcherHotkeyNames() {
if (v = Name)
return k
}
return 0
}
GetScriptHotkeys() {
return { GetArea: App.Hotkeys.GetArea
, GetActiveWindow: App.Hotkeys.GetActiveWindow
, GetScreen: App.Hotkeys.GetScreen
, ShowHideSelWindow: App.Hotkeys.ShowHideSelWindow
, SelWindowToCenter: App.Hotkeys.SelWindowToCenter
, SelectPreview: App.Hotkeys.SelectPreview
, OpenOutputFolder: App.Hotkeys.OpenOutputFolder
, SelectAreaOverlay: App.Hotkeys.SelectAreaOverlay
, QuickSelectAreaOverlay: App.Hotkeys.QuickSelectAreaOverlay }
}
SetHotkeyControlsFromVars() {
for k, name in ScreenCatcherHotkeyNames()
Hotkey_Set(name, App.Hotkeys[name])
}
ApplyHotkeySettings() {
if (Duplicate := FindDuplicateHotkey()) {
ShowDuplicateHotkey(Duplicate)
return false
}
oldHotkeys := GetScriptHotkeys()
for k, name in ScreenCatcherHotkeyNames()
App.Hotkeys[name] := Hotkey_Value(name)
if !ScriptHotkeysEqual(oldHotkeys, GetScriptHotkeys()) {
SetScriptHotkeys(0, oldHotkeys)
if !App.Settings.ScriptHotkeysSuspended
SetScriptHotkeys(1)
UpdateMenuHotkeyCaptions()
}
return true
}
ScriptHotkeysEqual(a, b) {
for k, v in a
if (v != b[k])
return false
return true
}
IsHotkeyEnabled(HotkeyValue) {
return Trim(HotkeyValue) != ""
}
UpdateHotkeysTabVisibility(CtrlHwnd := "", GuiEvent := "", EventInfo := "", EventErrorLevel := "") {
ControlGet, NTab, Tab,,, % "ahk_id " App.Settings.TabHwnd
if NTab = 4
Gui, 4:Show, NA
else
Gui, 4:Show, Hide
}
UpdateSelectionColorFromGui(CtrlHwnd := "", GuiEvent := "", EventInfo := "", EventErrorLevel := "") {
ReadColorControls()
UpdateSelectionColor()
UpdateColorValueLabels()
UpdateMarkerColor()
}
ReadColorControls() {
GuiControlGet, Red, 2:, % App.Settings.RedSliderHwnd
GuiControlGet, Green, 2:, % App.Settings.GreenSliderHwnd
GuiControlGet, Blue, 2:, % App.Settings.BlueSliderHwnd
GuiControlGet, Trans, 2:, % App.Settings.TransSliderHwnd
App.Settings.Color.Red := Red
App.Settings.Color.Green := Green
App.Settings.Color.Blue := Blue
App.Settings.Color.Trans := Trans
}
UpdateColorValueLabels() {
ColorState := App.Settings.Color
GuiControl, 2:, % App.Settings.RedValueHwnd, % ColorState.Red
GuiControl, 2:, % App.Settings.GreenValueHwnd, % ColorState.Green
GuiControl, 2:, % App.Settings.BlueValueHwnd, % ColorState.Blue
GuiControl, 2:, % App.Settings.TransValueHwnd, % ColorState.Trans
}
UpdateSelectionColor() {
ColorState := App.Settings.Color
ColorValue := (ColorState.Red<<16)|(ColorState.Green<<8)|ColorState.Blue
App.Config.ARGB := (App.Config.ARGB & 0xFF000000)|ColorValue
SetFormat, IntegerFast, H
Gui, 1:Color, % ColorValue
SetFormat, IntegerFast, D
}
UpdateSelectionTransparencyFromGui(CtrlHwnd := "", GuiEvent := "", EventInfo := "", EventErrorLevel := "") {
GuiControlGet, Trans, 2:, % App.Settings.TransSliderHwnd
App.Settings.Color.Trans := Trans
UpdateSelectionTransparency()
UpdateColorValueLabels()
}
UpdateMarkerColor() {
MarkerColor := (App.Config.ARGB & 0xFFFFFF)^0xFFFFFF
for index, MarkerHwnd in App.Selection.MarkerHwnds
SetColorToControl(MarkerHwnd, MarkerColor)
}
UpdateSelectionTransparency() {
SelectionHwnd := App.Selection.Hwnd
Trans := App.Settings.Color.Trans
WinSet, Transparent, % Trans, ahk_id %SelectionHwnd%
App.Config.ARGB := Trans<<24|(App.Config.ARGB & 0xFFFFFF)
}
UpdateOutputTargetFromGui(CtrlHwnd := "", GuiEvent := "", EventInfo := "", EventErrorLevel := "") {
UpdateOutputTarget(OutputControlName(CtrlHwnd), CtrlHwnd)
}
OutputControlName(CtrlHwnd) {
switch CtrlHwnd {
case App.Settings.OutputFileHwnd : return "File"
case App.Settings.OutputClipHwnd : return "Clip"
case App.Settings.OutputImgbbHwnd : return "Imgbb"
default: return ""
}
}
UpdateOutputTarget(ControlName, CtrlHwnd := "") {
if (ControlName = "")
return
GuiControlGet, OutVar, 2:, %CtrlHwnd%
if OutVar
App.Config.Output .= ControlName
else {
Output := App.Config.Output
StringReplace, Output, Output, % ControlName,, 1
App.Config.Output := Output
}
}
SetOutputExtensionFromGui(CtrlHwnd := "", GuiEvent := "", EventInfo := "", EventErrorLevel := "") {
SetOutputExtension(OutputExtensionFromHwnd(CtrlHwnd))
}
OutputExtensionFromHwnd(CtrlHwnd) {
switch CtrlHwnd {
case App.Settings.ExtensionPngHwnd: return "png"
case App.Settings.ExtensionJpgHwnd: return "jpg"
case App.Settings.ExtensionBmpHwnd: return "bmp"
case App.Settings.ExtensionTifHwnd: return "tif"
case App.Settings.ExtensionGifHwnd: return "gif"
default: return ""
}
}
SetOutputExtension(Extension) {
if (Extension != "")
App.Config.Ext := Extension
}
SetJpegQuality() {
GuiControlGet, JPEGQualityValue, 2:, % App.Settings.JpegQualitySliderHwnd
App.Config.JPEGQuality := JPEGQualityValue
GuiControl, 2:, % App.Settings.JpegQualityPercentHwnd, % App.Config.JPEGQuality "`%"
}
FocusSettingsSafeButton() {
GuiControl, 2:Focus, Button17
}
ApplyProgramSettings() {
SelectionHwnd := App.Selection.Hwnd
OldResizePointers := App.Config.ResizePointers
OldRunOnWinStart := App.Config.RunOnWinStart
GuiControlGet, CaptureCursorChecked, 2:, % App.Settings.CaptureCursorHwnd
App.Config.CaptureCursor := CaptureCursorChecked
GuiControlGet, ShowPreviewChecked, 2:, % App.Settings.ShowPreviewHwnd
App.Config.ShowPreview := ShowPreviewChecked
GuiControlGet, NotifyChecked, 2:, % App.Settings.NotifyHwnd
App.Config.Notify := NotifyChecked
GuiControlGet, RunOnWinStartChecked, 2:, % App.Settings.RunOnWinStartHwnd
App.Config.RunOnWinStart := RunOnWinStartChecked
GuiControlGet, CursorsChecked, 2:, % App.Settings.ResizeCursorsHwnd
App.Config.ResizePointers := CursorsChecked ? "Cursors" : "Markers"
if (OldRunOnWinStart != App.Config.RunOnWinStart)
SetRunOnWindowsStart(App.Config.RunOnWinStart)
if (OldResizePointers != App.Config.ResizePointers && WinExist("ahk_id " SelectionHwnd)) {
SetResizePointerTimer("Off", OldResizePointers)
SetResizePointerTimer(50, App.Config.ResizePointers)
}
}
SelectOutputDirectory() {
SelectionHwnd := App.Selection.Hwnd
Old_OutDirectory := App.Config.OutDirectory
SelectionWasVisible := WinExist("ahk_id " SelectionHwnd)
if (SelectionWasVisible)
ToggleSelectionWindow()
Gui, 2:+OwnDialogs
CurrentOutDirectory := App.Config.OutDirectory
FileSelectFolder, OutDir, *%CurrentOutDirectory%, 3, Выберите папку для вывода:
App.Config.OutDirectory := OutDir ? OutDir : App.Config.OutDirectory
if (App.Config.OutDirectory != Old_OutDirectory)
GuiControl, 2:, % App.Settings.OutDirectoryEditHwnd, % App.Config.OutDirectory
if (SelectionWasVisible && !WinExist("ahk_id " SelectionHwnd))
ToggleSelectionWindow()
}
IsRunOnWindowsStartEnabled() {
FileGetShortcut, % GetRunOnWindowsStartShortcutPath(), OutTarget,, OutArgs
return (OutTarget = A_ScriptFullPath && OutArgs = 1)
}
SetRunOnWindowsStart(Enable) {
ShortcutPath := GetRunOnWindowsStartShortcutPath()
if (Enable)
FileCreateShortcut, % A_ScriptFullPath, % ShortcutPath, % A_ScriptDir, 1
else
FileDelete, % ShortcutPath
}
GetRunOnWindowsStartShortcutPath() {
return A_Startup "\" RegExReplace(A_ScriptName, "(.*)\..*", "$1.lnk")
}
OpenOutputDirectory() {
Run, % App.Config.OutDirectory
}
UpdateResizePointerHover(Mode) {
if (Mode = "Cursors")
App.Selection.ResizeHandle := Cursors1()
else
App.Selection.ResizeHandle := Markers1()
}
GuiSize() {
MoveSelectionResizeMarkers(A_GuiWidth, A_GuiHeight)
}
MoveSelectionResizeMarkers(Width, Height) {
GuiControl, Move, Static1, % "x" Width - 10 "y" Height - 10
GuiControl, Move, Static2, % "x0 y" Height - 10
GuiControl, Move, Static3, % "x0 y0"
GuiControl, Move, Static4, % "x" Width - 10 "y0"
GuiControl, Move, Static5, % "x" Width - 10 "y" (Height - 10)/2
GuiControl, Move, Static6, % "x" (Width - 10)/2 "y" Height - 10
GuiControl, Move, Static7, % "x0 y" (Height - 10)/2
GuiControl, Move, Static8, % "x" (Width - 10)/2 "y0"
}
GuiContextMenu() {
RestoreCursors()
Menu, MainMenu, Show
}
; Окно выделения в центр экрана
CenterSelectionWindow() {
SelectionHwnd := App.Selection.Hwnd
if WinExist("ahk_id " SelectionHwnd)
Melt(SelectionHwnd, App.Config.ARGB>>24, 0)
else {
Menu, Tray, Rename, % App.Menu.TrayShow, % App.Menu.TrayHide
SetResizePointerTimer(50)
}
Gui, 1:Show, % "x" (A_ScreenWidth - 200)//2 " y" (A_ScreenHeight - 200)//2 " h200 w200 Hide"
Melt(SelectionHwnd, App.Config.ARGB>>24, 1)
}
GuiClose() {
ToggleSelectionWindow()
}
GuiEscape() {
ToggleSelectionWindow()
}
HideShow() {
ToggleSelectionWindow()
}
ToggleSelectionWindow() {
SelectionHwnd := App.Selection.Hwnd
Exist := WinExist("ahk_id " SelectionHwnd)
Melt(SelectionHwnd, App.Config.ARGB>>24, !Exist)
Menu, Tray, Rename, % Exist ? App.Menu.TrayHide : App.Menu.TrayShow
, % Exist ? App.Menu.TrayShow : App.Menu.TrayHide
SetResizePointerTimer(Exist ? "Off" : 50)
( Exist && NormalizeResizePointersValue(App.Config.ResizePointers) = "Cursors" && RestoreCursors() )
}
CaptureAreaScreenshot() {
CoordMode, Pixel, Screen
MouseGetPos, mx, my
prev_color := 0
Loop {
PixelGetColor, cur_color, %mx%, %my%
if (cur_color = prev_color)
break
prev_color := cur_color
Sleep, 30
}
GetScreenshot("Area")
}
SetInterpolationModeFromMenu(MenuItemPos) {
Menu, Interpolation, UnCheck, % App.Menu.InterpolationItems[App.Config.InterpolationMode]
App.Config.InterpolationMode := MenuItemPos
Menu, Interpolation, Check, % App.Menu.InterpolationItems[App.Config.InterpolationMode]
}
FindDuplicateHotkey() {
Names := ScreenCatcherHotkeyNames()
Loop % Names.MaxIndex() {
Name1 := Names[A_Index]
Value1 := Hotkey_Value(Name1)
if !IsHotkeyEnabled(Value1)
continue
i := A_Index + 1
Loop % Names.MaxIndex() - A_Index {
Name2 := Names[i]
Value2 := Hotkey_Value(Name2)
if (IsHotkeyEnabled(Value2) && Hotkey_Equal(Value1, Value2))
return {Name: Name2, OtherName: Name1, Hwnd: Hotkey_ID(Name2), Value: Value2}
i++
}
}
return ""
}
ShowDuplicateHotkey(Duplicate) {
Labels := ScreenCatcherHotkeyLabels()
ActivateHotkeyControl(Duplicate.Name)
Hwnd := Duplicate.Hwnd
WinGetPos, X, Y, W, H, ahk_id %Hwnd%
Text := "Эта горячая клавиша уже назначена:`n" Labels[Duplicate.OtherName]
new ToolTip({ text: Text, x: X, y: Y + H + 8, TimeOut: -3500
, BackColor: 0x0055aa, TextColor: "white", FontSize: 10, FontName: "calibri" })
BlinkWindow(Hwnd)
}
ActivateHotkeyControl(Name) {
Index := ScreenCatcherHotkeyIndex(Name)
if !Index
return
SubTab := Index < 4 ? 1 : Index < 7 ? 2 : 3
GuiControl, 2:Choose, % App.Settings.TabHwnd, 4
Gui, 4:Show, NA
GuiControl, 4:Choose, % App.Settings.HotkeysSubTabHwnd, %SubTab%
Hwnd := Hotkey_ID(Name)
ControlFocus,, ahk_id %Hwnd%
Sleep, 50
}
BlinkWindow(Hwnd) {
Loop 6 {
DllCall("ShowWindowAsync", "Ptr", Hwnd, "Int", Mod(A_Index, 2) ? 0 : 4)
Sleep, 70
}
DllCall("ShowWindowAsync", "Ptr", Hwnd, "Int", 4)
}
SetScriptHotkeys(Enable, Values := "") {
if !IsObject(Values)
Values := GetScriptHotkeys()
Hotkey, IfWinActive
if IsHotkeyEnabled(Values.GetArea) {
if Enable {
obj := Func("GetScreenshot").Bind("Area")
Hotkey, % Values.GetArea, % obj, On
} else {
Hotkey, % Values.GetArea, Off
}
}
if IsHotkeyEnabled(Values.GetActiveWindow) {
if Enable {
obj := Func("GetScreenshot").Bind("ActiveWindow")
Hotkey, % Values.GetActiveWindow, % obj, On
} else {
Hotkey, % Values.GetActiveWindow, Off
}
}
if IsHotkeyEnabled(Values.GetScreen) {
if Enable {
obj := Func("GetScreenshot").Bind("Screen")
Hotkey, % Values.GetScreen, % obj, On
} else {
Hotkey, % Values.GetScreen, Off
}
}
if IsHotkeyEnabled(Values.ShowHideSelWindow) {
if Enable
Hotkey, % Values.ShowHideSelWindow, HideShow, On
else
Hotkey, % Values.ShowHideSelWindow, Off
}
if IsHotkeyEnabled(Values.SelWindowToCenter) {
if Enable
Hotkey, % Values.SelWindowToCenter, CenterSelectionWindow, On
else
Hotkey, % Values.SelWindowToCenter, Off
}
if IsHotkeyEnabled(Values.OpenOutputFolder) {
if Enable
Hotkey, % Values.OpenOutputFolder, OpenOutputDirectory, On
else
Hotkey, % Values.OpenOutputFolder, Off
}
if IsHotkeyEnabled(Values.SelectAreaOverlay) {
if Enable {
obj := Func("StartOverlaySelection").Bind("Arm")
Hotkey, % Values.SelectAreaOverlay, % obj, On
} else {
Hotkey, % Values.SelectAreaOverlay, Off
}
}
if IsHotkeyEnabled(Values.QuickSelectAreaOverlay) {
if Enable {
obj := Func("StartOverlaySelection").Bind("Quick")
Hotkey, % Values.QuickSelectAreaOverlay, % obj, On
} else {
Hotkey, % Values.QuickSelectAreaOverlay, Off
}
}
if IsHotkeyEnabled(Values.SelectPreview) {
Hotkey, if, WinExist("ScreenShot ahk_class AutoHotkeyGUI")
if Enable
Hotkey, % Values.SelectPreview, FindHighlight, On
else
Hotkey, % Values.SelectPreview, Off
}
Hotkey, if
}
SetResizeHotkeyState(State) {
Hotkey, IfWinActive
Hotkey, LButton, WinResize, %State%
Hotkey, if
}
Cursors1() {
static
SelectionHwnd := App.Selection.Hwnd
S = 10
MouseGetPos, X_M, Y_M, ID_Win
for index, value in App.Windows {
if (value.Hwnd = ID_Win) {
if Cursor {
RestoreCursors()
SetResizeHotkeyState("Off")
Cursor := ""
}
return
}
}
WinGetPos, X, Y, W, H, ahk_id %SelectionHwnd%
XW := X + W, YH := Y + H
if ((X_M <= XW) && (X_M > XW - 2*S) && (Y_M <= YH) && (Y_M > YH - S))
|| ((X_M <= XW) && (X_M > XW - S) && (Y_M <= YH) && (Y_M > YH - 2*S))
Var := 1
else if ((X_M < X + 2*S) && (X_M >= X) && (Y_M <= YH) && (Y_M > YH - S))
|| ((X_M < X + S) && (X_M >= X) && (Y_M <= YH) && (Y_M > YH - 2*S))
Var := 2
else if ((X_M < X + 2*S) && (X_M >= X) && (Y_M < Y + S) && (Y_M >= Y))
|| ((X_M < X + S) && (X_M >= X) && (Y_M < Y + 2*S) && (Y_M >= Y))
Var := 3
else if ((X_M <= XW ) && (X_M > XW - 2*S) && (Y_M < Y + S) && (Y_M >= Y))
|| ((X_M <= XW ) && (X_M > XW - S) && (Y_M < Y + 2*S) && (Y_M >= Y))
Var := 4
else if (X_M <= XW) && (X_M > XW - S) && (Y_M <= YH - S) && (Y_M >= Y + S)
Var := 5
else if (X_M <= XW - S) && (X_M >= X + S) && (Y_M <= YH) && (Y_M > YH - S)
Var := 6
else if (X_M < X + S) && (X_M >= X) && (Y_M <= YH - S) && (Y_M >= Y + S)
Var := 7
else if (X_M <= XW - S) && (X_M >= X + S) && (Y_M < Y + S) && (Y_M >= Y)
Var := 8
else
Var := ""
if Var {
SetResizeHotkeyState("On")
if (Var = 1 || Var = 3) && (Cursor != "IDC_SIZENWSE")
RestoreCursors(), SetSystemCursor("IDC_SIZENWSE"), Cursor := "IDC_SIZENWSE"
if (Var = 2 || Var = 4) && (Cursor != "IDC_SIZENESW")
RestoreCursors(), SetSystemCursor("IDC_SIZENESW"), Cursor := "IDC_SIZENESW"
if (Var = 5 || Var = 7) && (Cursor != "IDC_SIZEWE")
RestoreCursors(), SetSystemCursor("IDC_SIZEWE"), Cursor := "IDC_SIZEWE"
if (Var = 6 || Var = 8) && (Cursor != "IDC_SIZENS")
RestoreCursors(), SetSystemCursor("IDC_SIZENS"), Cursor := "IDC_SIZENS"
} else {
SetResizeHotkeyState("Off")
RestoreCursors(), Cursor := ""
}
return Var
}
Markers1() {
SelectionHwnd := App.Selection.Hwnd
MouseGetPos, X_M, Y_M, ID_Win
for index, value in App.Windows {
if (value.Hwnd = ID_Win) {
SetResizeHotkeyState("Off")
Loop 8
GuiControl, Hide, static%a_index%
return
}
}
WinGetPos, X, Y, W, H, ahk_id %SelectionHwnd%
XW := X + W, YH := Y + H
if (X_M <= XW + 20) && (X_M >= XW - 10) && (Y_M <= YH + 20) && (Y_M >= YH - 10)
Var := 1
else if (X_M <= X + 10) && (X_M >= X - 20) && (Y_M <= YH + 20) && (Y_M >= YH - 10)
Var := 2
else if (X_M <= X + 10) && (X_M >= X - 20) && (Y_M <= Y + 10) && (Y_M >= Y - 20)
Var := 3
else if (X_M <= XW + 20) && (X_M >= XW - 10) && (Y_M <= Y + 10) && (Y_M >= Y - 20)
Var := 4
else if (X_M <= XW + 20) && (X_M >= XW - 10) && (Y_M < YH - 10) && (Y_M > Y + 10)
Var := 5
else if (X_M < XW - 10) && (X_M > X + 10) && (Y_M <= YH + 20) && (Y_M >= YH - 10)
Var := 6
else if (X_M <= X + 10) && (X_M >= X - 20) && (Y_M < YH - 10) && (Y_M > Y + 10)
Var := 7
else if (X_M < XW - 10) && (X_M > X + 10) && (Y_M <= Y + 10) && (Y_M >= Y - 20)
Var := 8
else Var := ""
if Var {
SetResizeHotkeyState("On")
GuiControl, Show, static%Var%
Loop 8 {
if (a_index != Var)
GuiControl, Hide, static%a_index%
}
} else {
SetResizeHotkeyState("Off")
Loop 8 {
GuiControl, Hide, static%a_index%
}
}
return Var
}
WinResize() {
SelectionHwnd := App.Selection.Hwnd
ResizeVar := App.Selection.ResizeHandle
SetResizePointerTimer("Off")
MouseGetPos, X_M_Old, Y_M_Old
WinGetPos, X, Y, W, H, ahk_id %SelectionHwnd%
while GetKeyState("LButton", "P") {
MouseGetPos, X_M, Y_M
dX := X_M - X_M_Old, dY := Y_M - Y_M_Old
IfEqual, ResizeVar, 1, WinMove, ahk_id %SelectionHwnd%,,,, W + dX, H + dY
IfEqual, ResizeVar, 2, WinMove, ahk_id %SelectionHwnd%,, X + dX,, W - dX, H + dY
IfEqual, ResizeVar, 3, WinMove, ahk_id %SelectionHwnd%,, X + dX, Y + dY, W - dX, H - dY
IfEqual, ResizeVar, 4, WinMove, ahk_id %SelectionHwnd%,,, Y + dY, W + dX, H - dY
IfEqual, ResizeVar, 5, WinMove, ahk_id %SelectionHwnd%,,,, W + dX
IfEqual, ResizeVar, 6, WinMove, ahk_id %SelectionHwnd%,,,,, H + dY
IfEqual, ResizeVar, 7, WinMove, ahk_id %SelectionHwnd%,, X + dX,, W - dX
IfEqual, ResizeVar, 8, WinMove, ahk_id %SelectionHwnd%,,, Y + dY,, H - dY
Sleep, 10
}
SetResizePointerTimer("On")
}
IsSelectionWindowActive() {
SelectionHwnd := App.Selection.Hwnd
return (SelectionHwnd && WinActive("ahk_id " SelectionHwnd))
}
NudgeSelectionEdge(Edge, Delta) {
static MinSize := 1
SelectionHwnd := App.Selection.Hwnd
if !WinExist("ahk_id " SelectionHwnd)
return
WinGetPos, X, Y, W, H, ahk_id %SelectionHwnd%
if (Edge = "Left") {
if (W - Delta < MinSize)
return
WinMove, ahk_id %SelectionHwnd%,, X + Delta, Y, W - Delta, H
} else if (Edge = "Top") {
if (H - Delta < MinSize)
return
WinMove, ahk_id %SelectionHwnd%,, X, Y + Delta, W, H - Delta
} else if (Edge = "Right") {
if (W + Delta < MinSize)
return
WinMove, ahk_id %SelectionHwnd%,, X, Y, W + Delta, H
} else if (Edge = "Bottom") {
if (H + Delta < MinSize)
return
WinMove, ahk_id %SelectionHwnd%,, X, Y, W, H + Delta
}
}
NormalizeLoadedSettings() {
if !IsIntegerSetting(App.Config.ARGB)
App.Config.ARGB := 0x82FFC700
if !RegExMatch(App.Config.Output, "^(File|Clip|Imgbb)+$")
App.Config.Output := "File"
if !RegExMatch(App.Config.Ext, "^(png|jpg|bmp|tif|gif)$")
App.Config.Ext := "png"
if (!IsIntegerSetting(App.Config.JPEGQuality) || App.Config.JPEGQuality < 50 || App.Config.JPEGQuality > 100)
App.Config.JPEGQuality := 100
if (App.Config.OutDirectory = "" || App.Config.OutDirectory = "OutDirectory")
App.Config.OutDirectory := A_ScriptDir
if !IsBooleanSetting(App.Config.CaptureCursor)
App.Config.CaptureCursor := 0
if !IsBooleanSetting(App.Config.ShowPreview)
App.Config.ShowPreview := 1
if !IsBooleanSetting(App.Config.Notify)
App.Config.Notify := 1
App.Config.ResizePointers := NormalizeResizePointersValue(App.Config.ResizePointers)
if (!IsIntegerSetting(App.Config.InterpolationMode) || App.Config.InterpolationMode < 1 || App.Config.InterpolationMode > 8)
App.Config.InterpolationMode := 3
}
NormalizeResizePointersValue(Value) {
return Value = "Markers" ? "Markers" : "Cursors"
}
SetResizePointerTimer(State, Value := "") {
TimerName := NormalizeResizePointersValue(Value = "" ? App.Config.ResizePointers : Value)
SetTimer, %TimerName%, %State%
}
Cursors() {
UpdateResizePointerHover(A_ThisFunc)
}
Markers() {
UpdateResizePointerHover(A_ThisFunc)
}
IsIntegerSetting(Value) {
return RegExMatch(Value, "i)^\s*(?:0x[0-9a-f]+|\d+)\s*$")
}
IsBooleanSetting(Value) {
return Value = 0 || Value = 1
}
IniReadConfigSect(Section, params*) {
; Читает секцию Section ini-файла в App.Config
ConfigNames := [ "ARGB", "Output", "Ext", "JPEGQuality", "OutDirectory", "CaptureCursor"
, "ShowPreview", "Notify", "ResizePointers", "InterpolationMode" ]
IniReadObjectSect(Section, App.Config, ConfigNames, params*)
}
IniReadHotkeysSect(Section, params*) {
; Читает секцию Section ini-файла в App.Hotkeys.
if !IsObject(App.Hotkeys)
App.Hotkeys := {}
IniReadObjectSect(Section, App.Hotkeys, ScreenCatcherHotkeyNames(), params*)
}
IniReadObjectSect(Section, Target, AllowedNames, params*) {
; Читает секцию Section ini-файла в объект Target.
IniName := IniFilePath()
for index, param in params {
if Mod(index, 3) = 1
Key := param
else if Mod(index, 3) = 2
Name := param
else {
IniRead, Value, % IniName, % Section, % Key, % param
SetObjectValue(Target, AllowedNames, Name, Value)
}
}
}
SetObjectValue(Target, AllowedNames, Name, Value) {
for index, AllowedName in AllowedNames {
if (Name = AllowedName) {
Target[AllowedName] := Value
return
}
}
}
IniWriteSect(Section, params*) {
; Пишет секцию Section ini-файла в директории скрипта.
IniName := IniFilePath()
for index, param in params {
if Mod(index, 2)
Key := param
else
IniWrite, % param, % IniName, % Section, % Key
}
}
IniFilePath() {
return RegExReplace(A_ScriptFullPath, "(.*)\..*", "$1.ini")
}
Melt(hWnd, Trans, Appear, N = 20) {
WinShow, ahk_id %hWnd%
while (i := A_Index * N) < Trans {
WinSet, Transparent, % Appear ? i : Trans - i, ahk_id %hWnd%
Sleep, 10
}
if Appear
WinSet, Transparent, % Trans, ahk_id %hWnd%
else
WinHide, ahk_id %hWnd%
}
SetSystemCursor(IDC) {
static IDC_SIZENWSE := 32642, IDC_SIZENESW := 32643, IDC_SIZEWE := 32644
, IDC_SIZENS := 32645, IDC_ARROW := 32512
, sys_cursors := [32512,32513,32514,32516,32642,32643,32644,32645,32646,32648,32649,32650]
hCursor := DllCall("LoadCursor", "UInt", 0, "Int", %IDC%)
for k, v in sys_cursors {
hCopy := DllCall("CopyImage", "Ptr", hCursor, "UInt", 2, "Int", 0, "Int", 0, "UInt", 0)
DllCall("SetSystemCursor", "UInt", hCopy, "Int", v)
}
}
RestoreCursors() {
DllCall("SystemParametersInfo", "UInt", SPI_SETCURSORS:=0x57, "UInt", 0, "UInt", 0, "UInt", 0)
}
SetColorToControl(hwnd, Color) { ; окрашивает static-контрол со стилем SS_BITMAP = 0xE в цвет Color
WinGetPos,,, w, h, ahk_id %hwnd%
DllCall("gdiplus\GdipCreateSolidFill", "UInt", 0xFF000000|Color, "Ptr*", pBrush)
DllCall("gdiplus\GdipCreateBitmapFromScan0", "Int", w, "Int", h, "Int", 0, "Int", 0x26200A, "Ptr", 0, "Ptr*", pBitmap)
DllCall("gdiplus\GdipGetImageGraphicsContext", "Ptr", pBitmap, "Ptr*", G)
DllCall("gdiplus\GdipFillRectangle", "Ptr", G, "Ptr", pBrush, "Float", 0, "Float", 0, "Float", w, "Float", h)
DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "Ptr", pBitmap, "Ptr*", hBitmap, "Int", 0xFFFFFFFF)
SendMessage, STM_SETIMAGE := 0x172,, hBitmap,, ahk_id %hwnd%
DllCall("DeleteObject", "Ptr", ErrorLevel)
DllCall("gdiplus\GdipDeleteBrush", "Ptr", pBrush)
DllCall("gdiplus\GdipDeleteGraphics", "Ptr", G)
DllCall("gdiplus\GdipDisposeImage", "Ptr", pBitmap)
DllCall("DeleteObject", "Ptr", hBitmap)
}
DDLCreate(N) {
Loop % N
String .= A_Index-1 "|"
return SubStr(String, 1, -1)
}
WM_LBUTTONDOWN(wParam, lParam, msg, hwnd) {
if IsOverlaySelectionHwnd(hwnd)
return
if (A_Gui = 1 || A_Gui > 9) {
if (A_Gui > 9) {
App.Menu.CancelPreviewIntroHwnd := hwnd
HidePreviewHighlight()
}
PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2,,, % "ahk_id " hwnd
}
else if (A_Gui = 2 && WhichPageOfTab(App.Settings.TabHwnd) = 4)
{
MouseGetPos,,,, Control
if InStr(Control, "ComboBox")
{
GuiControlGet, OutputVar, 3:Enabled, % Control
if OutputVar
return
else
GuiControl, 3:Focus, TextT
}
else
GuiControl, 3:Focus, TextT
}
}
WM_LBUTTONDBLCLK(wParam, lParam, msg, hwnd) {
if IsOverlaySelectionHwnd(hwnd)
return
(A_Gui = 1) && GetScreenshot("Area")
}
WM_RBUTTONDOWN(wParam, lParam, msg, hwnd) {
if IsOverlaySelectionHwnd(hwnd)
return
if (A_Gui < 10 || A_Gui = "Imgbb")
return
App.Menu.CurrentPreviewGui := A_Gui
Menu, % App.Windows[A_Gui].Scale = 1 ? "ScreenShotMenu" : "ScreenShotMenu2", Show
}
AHK_NOTIFYICON(wp, lp) {
static WM_LBUTTONDOWN := 0x201
(lp = WM_LBUTTONDOWN) && ToggleSelectionWindow()
}
WhichPageOfTab(SettingsTabHwnd) {
ControlGet, NTab, Tab,,, ahk_id %SettingsTabHwnd%
return NTab
}
GetControlFocus(NGui) {
GuiControlGet, Focus, %NGui%:Focus
return Focus
}
GetOverlaySelection() {
if !IsObject(App.Selection.Overlay) {
gap := 5
labelSpecs := [{style: {fontStyle: 1}
, provider: Func("OverlayTopLabelProvider").Bind(gap)}
, {style: {fontStyle: 1}
, provider: Func("OverlayBottomLabelProvider").Bind(gap)}]
armedStyle := {fontStyle: 1, offsetX: 12, offsetY: 12}
App.Selection.Overlay := new OverlaySelection(2, 0xFFAA00, labelSpecs, armedStyle)
Gui, 1:Default
}
return App.Selection.Overlay
}
StartOverlaySelection(Mode) {
Overlay := GetOverlaySelection()
Callback := Func("CaptureOverlaySelection")
if (Mode = "Quick")
Overlay.Quick(Callback)
else
Overlay.Arm(Callback)
}
CaptureOverlaySelection(Rect) {
if (Rect.w < 1 || Rect.h < 1)
return
GetScreenshot("Area", Rect)
}
OverlayTopLabelProvider(Gap, Context) {
Rect := Context.r
return {text: Rect.x . ", " . Rect.y . " " . Rect.w . "x" . Rect.h
, ax: Rect.x
, ay: Rect.y - Context.t - Round(Gap * Context.scale)
, side: "top"}
}
OverlayBottomLabelProvider(Gap, Context) {
Rect := Context.r
return {text: (Rect.x + Rect.w) . ", " . (Rect.y + Rect.h)
, ax: Rect.x + Rect.w
, ay: Rect.y + Rect.h + Context.t + Round(Gap * Context.scale)
, side: "bottom"}
}
IsOverlaySelectionState(State) {
return IsObject(App.Selection.Overlay) && App.Selection.Overlay.state = State
}
BeginOverlaySelectionDrag() {
if IsObject(App.Selection.Overlay)
App.Selection.Overlay.BeginDrag()
}
CancelOverlaySelection() {
if IsObject(App.Selection.Overlay)
App.Selection.Overlay.Cancel()
}
FinishOverlaySelection() {
if IsObject(App.Selection.Overlay)
App.Selection.Overlay.Finish()
}
GetScreenshot(Area, SelectionRect := "") {
SelectionHwnd := App.Selection.Hwnd
SRCCOPY := 0x00CC0020, CAPTUREBLT := 0x40000000
Critical
if (Area = "Area") {
IfWinExist, ahk_id %SelectionHwnd%
{
Vis = 1
WinHide ; Melt(SelectionHwnd, App.Config.ARGB>>24, 0, 50)
}
if IsObject(SelectionRect) {
X := SelectionRect.x
Y := SelectionRect.y
W := SelectionRect.w
H := SelectionRect.h
} else {
DetectHiddenWindows, On
WinGetPos, X, Y, W, H, ahk_id %SelectionHwnd%
}
Rect := X "|" Y "|" W "|" H
pBitmap := BitmapFromScreen(Rect, App.Config.CaptureCursor, SRCCOPY|CAPTUREBLT)
if Vis
{
Sleep, 50
WinShow ; Melt(SelectionHwnd, App.Config.ARGB>>24, 1, 50)
}
} else if (Area = "ActiveWindow") {
WinGet, hwnd, ID, A
if !GetVisibleWindowRect(hwnd, X, Y, W, H)
WinGetPos, X, Y, W, H, ahk_id %hwnd%
pBitmap := BitmapFromScreen(X "|" Y "|" W "|" H, App.Config.CaptureCursor, SRCCOPY|CAPTUREBLT)
} else {
X := Y := 0
W := A_ScreenWidth
H := A_ScreenHeight
pBitmap := BitmapFromScreen(0, App.Config.CaptureCursor, SRCCOPY|CAPTUREBLT)
}
Critical, Off ; capture is done; let the message queue flow for preview/notification
Time := A_Year "." A_MM "." A_DD "-" A_Hour "." A_Min "." A_Sec "." SubStr(A_MSec, 1, 1)
if (App.Config.ShowPreview) {
ShowPreview(pBitmap, Time, X, Y, W, H)
} else {
SaveScreenshot(pBitmap, Time)
}
}
BitmapFromHWND(hwnd) {
WinGetPos,,, Width, Height, ahk_id %hwnd%
hbm := CreateDIBSection(Width, Height)
hdc := DllCall("CreateCompatibleDC", "Ptr", 0)
obm := DllCall("SelectObject", "Ptr", hdc, "Ptr", hbm)
DllCall("PrintWindow", "Ptr", hwnd, "Ptr", hdc, "UInt", PW_RENDERFULLCONTENT := 2)
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "Ptr", hbm, "Ptr", 0, "Ptr*", pBitmap)
DllCall("SelectObject", "Ptr", hdc, "Ptr", obm)
DllCall("DeleteObject", "Ptr", hbm)
DllCall("DeleteDC", "Ptr", hdc)
return pBitmap
}
GetBitmapFromWindow(hwnd) {
WinGetPos,,, W, H, ahk_id %hwnd%
hWDC := DllCall("GetWindowDC", "Ptr", hwnd, "Ptr")
hdc := DllCall("CreateCompatibleDC", "Ptr", hWDC, "Ptr")
hbm := DllCall("CreateCompatibleBitmap", "Ptr", hWDC, "Int", W, "Int", H)
obm := DllCall("SelectObject", "Ptr", hdc, "Ptr", hbm)
DllCall("BitBlt", "Ptr", hdc, "Int", 0, "Int", 0, "Int", W, "Int", H, "Ptr", hWDC, "Int", 0, "Int", 0, "UInt", 0x00CC0020)
DllCall("ReleaseDC", "Ptr", hwnd, "Ptr", hWDC)
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "Ptr", hbm, "Ptr", 0, "Ptr*", pBitmap)
DllCall("SelectObject", "Ptr", hdc, "Ptr", obm)
DllCall("DeleteObject", "Ptr", hbm)
DllCall("DeleteDC", "Ptr", hdc)
return pBitmap
}
ShowPreview(pBitmap, Time, X, Y, W, H) {
static WS_EX_LAYERED := 0x80000
SelectionHwnd := App.Selection.Hwnd
while App.Windows[i := A_Index+9]
continue
Gui, %i%: -Caption +E%WS_EX_LAYERED% +LastFound +AlwaysOnTop +ToolWindow +Owner
WinGet, PreviewHwnd
Gui, %i%: Show, NA, ScreenShot
hbm := CreateDIBSection(W, H)
hdc := DllCall("CreateCompatibleDC", "Ptr", 0)
obm := DllCall("SelectObject", "Ptr", hdc, "Ptr", hbm)
DllCall("gdiplus\GdipCreateFromHDC", "Ptr", hdc, "Ptr*", G)
DrawImage(G, pBitmap, 0, 0, W, H, 0, 0, W, H)
UpdateLayeredWindow(PreviewHwnd, hdc, X, Y, W, H)
WinActivate, ahk_id %PreviewHwnd%
App.Windows[i] := Object("Hwnd", PreviewHwnd, "Time", Time, "pBM", pBitmap)
DllCall("SelectObject", "Ptr", hdc, "Ptr", obm)
DllCall("DeleteObject", "Ptr", hbm)
DllCall("DeleteDC", "Ptr", hdc), DllCall("gdiplus\GdipDeleteGraphics", "Ptr", G)
SetWinDelay, 10
Loop 10 {
if (App.Menu.CancelPreviewIntroHwnd = PreviewHwnd)
break
WinMove, ahk_id %PreviewHwnd%,, X+A_Index, Y-A_Index
}
DetectHiddenWindows, Off
if !WinExist("ahk_id " SelectionHwnd)
ShowPreviewHighlight(PreviewHwnd)
if (App.Menu.CancelPreviewIntroHwnd = PreviewHwnd)
App.Menu.CancelPreviewIntroHwnd := ""
}
ShowPreviewHighlight(PreviewHwnd) {
Critical
if (App.Menu.CancelPreviewIntroHwnd = PreviewHwnd) {
Critical, Off
return
}
Highlight(PreviewHwnd)
Critical, Off
Sleep, 300
HidePreviewHighlight()
}
Highlight(TargetHwnd) {
HidePreviewHighlight()
WinActivate, ahk_id %TargetHwnd%
; WS_EX_LAYERED := 0x80000, WS_EX_TRANSPARENT := 0x20
Gui, 5:-Caption +E0x80020 +LastFound +AlwaysOnTop +ToolWindow +Owner
WinGet, HighlightHwnd
App.Menu.HighlightHwnd := HighlightHwnd
Gui, 5:Show, NA
WinGetPos, X, Y, W, H, ahk_id %TargetHwnd%
hbm := CreateDIBSection(W, H)
hdc := DllCall("CreateCompatibleDC", "Ptr", 0)
obm := DllCall("SelectObject", "Ptr", hdc, "Ptr", hbm)
DllCall("gdiplus\GdipCreateFromHDC", "Ptr", hdc, "Ptr*", G)
DllCall("gdiplus\GdipCreateSolidFill", "UInt", 0xffffaa00, "Ptr*", pBrush)
TH := 5 ; толщина линии подсветки
Points := "0,0|" W ",0|" W "," H "|0," H "|0," TH "|" TH ","
. TH "|" TH "," H - TH "|" W - TH "," H - TH "|" W - TH "," TH "|0," TH
FillPolygon(G, pBrush, Points)
DllCall("gdiplus\GdipDeleteBrush", "Ptr", pBrush)
UpdateLayeredWindow(HighlightHwnd, hdc, X, Y, W, H)
DllCall("SelectObject", "Ptr", hdc, "Ptr", obm)
DllCall("DeleteObject", "Ptr", hbm), DllCall("DeleteDC", "Ptr", hdc)
DllCall("gdiplus\GdipDeleteGraphics", "Ptr", G)
}
HidePreviewHighlight() {
HighlightHwnd := App.Menu.HighlightHwnd
if (HighlightHwnd && WinExist("ahk_id " HighlightHwnd))
Gui, 5:Destroy
App.Menu.HighlightHwnd := ""
}
FindHighlight() {
static CurrentScr
if !CurrentScr
CurrentScr := App.Windows.MaxIndex()
else {
while !App.Windows[CurrentScr := CurrentScr = 10 ? App.Windows.MaxIndex() : CurrentScr - 1]
continue
}
Highlight(App.Windows[CurrentScr].Hwnd)
KeyWait, Space
HidePreviewHighlight()
}
SaveScreenshot(pBitmap, OutFileName, OutputOverride := "") {
Output := OutputOverride = "" ? App.Config.Output : OutputOverride
OutDirectory := App.Config.OutDirectory
Ext := App.Config.Ext
JPEGQuality := App.Config.JPEGQuality
ImgbbSent := false
MissingImgbbClientID := false
if (File := InStr(Output, "File")) {
Critical
IfNotExist, % OutDirectory
{
FileCreateDir, % OutDirectory
if ErrorLevel {
File := ""
MsgBox, 48, Невозможно создать папку
, Невозможно создать папку вывода.`nОшибка %A_LastError%
}
}
if (Result := SaveBitmap(pBitmap, OutDirectory "\" OutFileName "." Ext, JPEGQuality)) {
File := ""
Errors := { 2: "Could not get a list of encoders on system"
, 3: "Could not find matching encoder for specified file format"
, 4: "Could not save file to disk" }
MsgBox, 48, Ошибка записи в файл, % Errors[-Result]
}
}
if Clip := InStr(Output, "Clip")
SetBitmapToClipboard(pBitmap)
if InStr(Output, "Imgbb") {
ClientID := EnsureImgbbClientId()
if (ClientID = "")
MissingImgbbClientID := true
else {
SendImageToImgbb(pBitmap, ClientID)
ImgbbSent := true
}
}
if (App.Config.Notify) {
if File && Clip && ImgbbSent
NotifyText := "Скриншот сохранён в файл,`nпомещён в буфер обмена`nи отправлен на imgbb.com"
else {
NotifyText := "Скриншот "
if File
NotifyText .= (NotifyText = "Скриншот " ? "" : "`nи ") . "сохранён в файл"
if Clip
NotifyText .= (NotifyText = "Скриншот " ? "" : "`nи ") . "помещён в буфер обмена"
if ImgbbSent
NotifyText .= (NotifyText = "Скриншот " ? "" : "`nи ") . "отправлен на imgbb.com"
if MissingImgbbClientID {
if (NotifyText = "Скриншот ")
NotifyText .= "не отправлен на Imgbb!`nВпишите ClientID в ScreenCatcher.ini"
else
NotifyText .= "`nно не отправлен на Imgbb"
}
}
if (NotifyText = "Скриншот ")
NotifyText := MissingImgbbClientID
? "Скриншот не отправлен на Imgbb!`nВпишите ClientID в ScreenCatcher.ini"
: "Скриншот не сохранён!`nУкажите в настройках во вкладке ""Вывод""`nвариант сохранения скриншота!"
new ToolTip({ text: NotifyText, FontSize: 14, FontName: "calibri", TrayTip: true
, TimeOut: -3500, BackColor: 0x0055aa, TextColor: "white"
, Margin: [10, 5, 10, 5] })
}
DllCall("gdiplus\GdipDisposeImage", "Ptr", pBitmap)
}
SendImageToImgbb(pBitmap, apiKey) {
Ext := App.Config.Ext
JPEGQuality := App.Config.JPEGQuality
buff := Ext
if ( (size := SaveBitmap(pBitmap, buff, JPEGQuality, 1)) < 0 ) {
Errors := { 2: "Could not get a list of encoders on system"
, 3: "Could not find matching encoder for specified file format"
, 4: "Не удалось сохранить битмап в буфер" }
MsgBox, 48, Ошибка записи в буфер, % Errors[-size]
return
}
strBase64 := EncodeDecodeURI(CryptBinaryToStringBASE64(&buff, size, 1))
http := ComObjCreate("WinHttp.WinHttpRequest.5.1")
http.open("POST", "https://api.imgbb.com/1/upload", true)
http.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
body := "key=" . apiKey . "&image=" . strBase64
http.send(body)
http.WaitForResponse()
if (http.status != 200)
throw "failed to upload image. Status: " . http.status
responsetext := http.responsetext
RegExMatch(responsetext, """url"":""(.*?)""", match)
link := StrReplace(match1, "\")
Gui, 5: Default
try Gui, Destroy
Gui, Font, s9
Gui, Add, Edit, % "w250 h" . (link ? 24 : 120), % link ? link : responsetext
Gui, Font
Gui, Add, Button, x+-80 y+7 w80 h24 gCopyResponse Default, Copy
GuiControl, Focus, Button1
Gui, Show,, Imgbb.com
VarSetCapacity(strBase64, 0), VarSetCapacity(buff, 0)
}
EncodeDecodeURI(str, encode := true, component := true) {
static document := "", JS := ""
if !document {
document := ComObjCreate("htmlfile")
document.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
JS := document.parentWindow
(document.documentMode < 9 && JS.execScript())
}
return JS[(encode ? "en" : "de") . "codeURI" . (component ? "Component" : "")](str)
}
CopyResponse() {
GuiControlGet, Clipboard, 5:, Edit1
Gui, 5: Destroy
}
WM_SHOWWINDOW(wp, lp, msg, hwnd) {
if IsOverlaySelectionHwnd(hwnd)
return
if (A_Gui < 10 || wp || A_Gui = "Imgbb") ; окно показывается — wp = true, скрывается — wp = false
return
Gui, %A_Gui%:Destroy
DllCall("gdiplus\GdipDisposeImage", "Ptr", App.Windows[A_Gui].pBM)
App.Windows.Remove(A_Gui, "")
}
WM_COMMAND(info, wp, lp) {
static EN_SETFOCUS := 0x100, EN_KILLFOCUS := 0x200
notify := wp >> 16
if !(notify = EN_SETFOCUS || notify = EN_KILLFOCUS)
return
for k, v in info {
if (v = lp) {
( notify = EN_SETFOCUS && DllCall("HideCaret", "Ptr", v) )
SetStaticColor(v, notify = EN_SETFOCUS ? 0xFECC53 : 0xFFFFFF, 0)
}
}
}
WM_SETCURSOR(info, wp) {
static hCursor, OCR_NORMAL := 32512
( !hCursor && hCursor := LoadCursor(OCR_NORMAL) )
for k, v in info {
if (v = wp)
return DllCall("SetCursor", "Ptr", hCursor)
}
}
WM_OVERLAY_SETCURSOR(wParam, lParam, msg, hwnd) {
static hCross := DllCall("LoadCursor", "Ptr", 0, "Ptr", 32515, "Ptr")
if !IsOverlaySelectionHwnd(hwnd)
return
DllCall("SetCursor", "Ptr", hCross)
return true
}
IsOverlaySelectionHwnd(hwnd) {
return hwnd && IsObject(App.Selection.Overlay)
&& IsObject(App.Selection.Overlay.overlay)
&& hwnd = App.Selection.Overlay.overlay.hwnd
}
LoadCursor(cursorId) {
static IMAGE_CURSOR := 2, LR_DEFAULTSIZE := 0x40, LR_SHARED := 0x8000
return DllCall("LoadImage", "Ptr", 0
, "UInt", cursorId
, "UInt", IMAGE_CURSOR
, "Int", 0, "Int", 0
, "UInt", LR_DEFAULTSIZE|LR_SHARED, "Ptr")
}
WM_ESC() {
Gui, %A_Gui%:Cancel
}
WM_WHEEL(wp, lp, msg, hwnd) {
static PrevTime = 0
Critical
App.Windows[A_Gui].Scale := 1 ; значит, размер скриншота изменён
pBitmap := App.Windows[A_Gui].pBM
GetImageDimensions(pBitmap, WidthBM, HeightBM)
RatioBM := WidthBM/HeightBM
SquareBM := WidthBM*HeightBM
WinGetPos, X, Y, W, H, A
DeltaW := Round(W/(!wp ? 10 : 11))
CtrlState := GetKeyState("Ctrl", "P")
DeltaW := !wp ? (CtrlState ? 1 : DeltaW) : -(CtrlState ? 1 : DeltaW)
ResultW := W + DeltaW
ResultH := Round(ResultW/RatioBM)
ResultX := X - (CtrlState ? 0 : Round(DeltaW/2))
ResultY := Y - (CtrlState ? 0 : Round((ResultH - H)/2))
SquareWin := ResultW*ResultH
if (!wp && SquareWin > 13000000) || (wp && SquareWin < 1000 && SquareWin < SquareBM) {
if (A_TickCount - PrevTime > 200) {
SoundBeep
PrevTime := A_TickCount
}
return
}
hbm := CreateDIBSection(ResultW, ResultH)
hdc := DllCall("CreateCompatibleDC", "Ptr", 0)
obm := DllCall("SelectObject", "Ptr", hdc, "Ptr", hbm)
DllCall("gdiplus\GdipCreateFromHDC", "Ptr", hdc, "Ptr*", G)
DllCall("gdiplus\GdipSetInterpolationMode", "Ptr", G, "Int", App.Config.InterpolationMode-1)
DrawImage(G, pBitmap, 0, 0, ResultW, ResultH, 0, 0, WidthBM, HeightBM)
UpdateLayeredWindow(hwnd, hdc, ResultX, ResultY, ResultW, ResultH)
DllCall("SelectObject", "Ptr", hdc, "Ptr", obm)
DllCall("DeleteObject", "Ptr", hbm), DllCall("DeleteDC", "Ptr", hdc), DllCall("gdiplus\GdipDeleteGraphics", "Ptr", G)
}
GetImageDimensions(pBitmap, ByRef Width, ByRef Height) {
DllCall("gdiplus\GdipGetImageWidth", "Ptr", pBitmap, "UInt*", Width)
DllCall("gdiplus\GdipGetImageHeight", "Ptr", pBitmap, "UInt*", Height)
}
GetVisibleWindowRect(hwnd, ByRef X, ByRef Y, ByRef W, ByRef H) {
static DWMWA_EXTENDED_FRAME_BOUNDS := 9
VarSetCapacity(rect, 16, 0)
if DllCall("dwmapi\DwmGetWindowAttribute", "Ptr", hwnd, "UInt", DWMWA_EXTENDED_FRAME_BOUNDS
, "Ptr", &rect, "UInt", 16)
return false
left := NumGet(rect, 0, "Int")
top := NumGet(rect, 4, "Int")
right := NumGet(rect, 8, "Int")
bottom := NumGet(rect, 12, "Int")
if (right <= left || bottom <= top)
return false
X := left, Y := top, W := right - left, H := bottom - top
return true
}
FillPolygon(pGraphics, pBrush, Points, FillMode=0) {
StringSplit, Points, Points, |
VarSetCapacity(PointF, 8*Points0)
Loop, %Points0%
{
StringSplit, Coord, Points%A_Index%, `,
NumPut(Coord1, PointF, 8*(A_Index-1), "float"), NumPut(Coord2, PointF, (8*(A_Index-1))+4, "float")
}
return DllCall("gdiplus\GdipFillPolygon", "Ptr", pGraphics, "Ptr", pBrush, "Ptr", &PointF, "Int", Points0, "Int", FillMode)
}
DrawImage(pGraphics, pBitmap, dx="", dy="", dw="", dh="", sx="", sy="", sw="", sh="") {
if (sx = "" && sy = "" && sw = "" && sh = "") {
if (dx = "" && dy = "" && dw = "" && dh = "") {
sx := dx := 0, sy := dy := 0
GetImageDimensions(pBitmap, sw, sh)
dw := sw, dh := sh
} else {
sx := sy := 0
GetImageDimensions(pBitmap, sw, sh)
}
}
E := DllCall("gdiplus\GdipDrawImageRectRect", "Ptr", pGraphics, "Ptr", pBitmap, "Float", dx, "Float", dy, "Float", dw, "Float", dh
, "Float", sx, "Float", sy, "Float", sw, "Float", sh, "int", 2, "Ptr", 0, "Ptr", 0, "Ptr", 0)
return E
}
BitmapFromScreen(Screen, Cursor, Raster="") {
if (Screen = 0) {
Sysget, x, 76
Sysget, y, 77
Sysget, w, 78
Sysget, h, 79
} else {
StringSplit, S, Screen, |
x := S1, y := S2, w := S3, h := S4
}
chdc := DllCall("CreateCompatibleDC", "Ptr", 0, "Ptr")
VarSetCapacity(bi, 40, 0)
NumPut(w, bi, 4, "UInt"), NumPut(h, bi, 8, "UInt"), NumPut(40, bi, 0, "UInt"), NumPut(1, bi, 12, "UShort")
NumPut(0, bi, 16), NumPut(32, bi, 14, "UShort")
hbm := DllCall("CreateDIBSection", "Ptr" , chdc, "Ptr" , &bi, "UInt" , 0, "Ptr*", 0, "Ptr" , 0, "UInt" , 0, "Ptr")
obm := DllCall("SelectObject", "Ptr", chdc, "Ptr", hbm, "Ptr")
hhdc := DllCall("GetDC", "Ptr", 0, "Ptr")
DllCall("BitBlt", "Ptr", chdc, "Int", 0, "Int", 0, "Int", w, "Int", h, "Ptr", hhdc, "Int", x, "Int", y, "UInt", Raster)
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hhdc)
( Cursor && CaptureCursor(chdc, x, y) )
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "Ptr", hbm, "Ptr", 0, "Ptr*", pBitmap)
DllCall("SelectObject", "Ptr", chdc, "Ptr", obm, "Ptr")
DllCall("DeleteObject", "Ptr", hbm)
DllCall("DeleteDC", "Ptr", hhdc)
DllCall("DeleteDC", "Ptr", chdc)
return pBitmap
}
CaptureCursor(hDC, x, y) {
VarSetCapacity(CURSORINFO, szCI := 4*2 + A_PtrSize + 8, 0)
NumPut(szCI, CURSORINFO)
DllCall("GetCursorInfo", "Ptr", &CURSORINFO)
bShow := NumGet(CURSORINFO, 4, "UInt")
hCursor := NumGet(CURSORINFO, 4*2)
xCursor := NumGet(CURSORINFO, 4*2 + A_PtrSize, "Int")
yCursor := NumGet(CURSORINFO, 4*2 + A_PtrSize + 4, "Int")
if bShow && hCursor := DllCall("CopyIcon", "Ptr", hCursor, "Ptr") {
VarSetCapacity(ICONINFO, 4*2 + A_PtrSize*3, 0)
DllCall("GetIconInfo", "Ptr", hCursor, "Ptr", &ICONINFO)
bIcon := NumGet(ICONINFO, "UInt")
xHotspot := NumGet(ICONINFO, 4, "UInt")
yHotspot := NumGet(ICONINFO, 4*2, "UInt")
hBMMask := NumGet(ICONINFO, 4*2 + A_PtrSize)
hBMColor := NumGet(ICONINFO, 4*2 + A_PtrSize*2)
DllCall("DrawIcon", "Ptr", hDC, "Int", xCursor - xHotspot - x, "Int", yCursor - yHotspot - y, "Ptr", hCursor)
DllCall("DestroyIcon", "Ptr", hCursor)
( hBMMask && DllCall("DeleteObject", "Ptr", hBMMask) )
( hBMColor && DllCall("DeleteObject", "Ptr", hBMColor) )
}
}
ScreenShotMenuHandling() {
CurrentGui := App.Menu.CurrentPreviewGui
pBitmap := App.Windows[CurrentGui].pBM
Time := App.Windows[CurrentGui].Time
if (A_ThisMenuItem = "Сохранить" || A_ThisMenuItem = "Сохранить в первоначальном размере")
SaveScreenshot(pBitmap, Time)
else if (A_ThisMenuItem = "Сохранить в текущем размере")
SavePreviewCurrentSize(CurrentGui, pBitmap, Time)
Gui, %CurrentGui%:Cancel
}
PreviewSaveToMenuHandling() {
CurrentGui := App.Menu.CurrentPreviewGui
pBitmap := App.Windows[CurrentGui].pBM
Time := App.Windows[CurrentGui].Time
Output := PreviewSaveToOutput(A_ThisMenuItem)
if (Output != "")
SaveScreenshot(pBitmap, Time, Output)
Gui, %CurrentGui%:Cancel
}
PreviewSaveCurrentToMenuHandling() {
CurrentGui := App.Menu.CurrentPreviewGui
pBitmap := App.Windows[CurrentGui].pBM
Time := App.Windows[CurrentGui].Time
Output := PreviewSaveToOutput(A_ThisMenuItem)
if (Output != "")
SavePreviewCurrentSize(CurrentGui, pBitmap, Time, Output)
Gui, %CurrentGui%:Cancel
}
SavePreviewCurrentSize(CurrentGui, pBitmap, Time, OutputOverride := "") {
WinGetPos,,, W, H, % "ahk_id " App.Windows[CurrentGui].Hwnd
DllCall("gdiplus\GdipCreateBitmapFromScan0", "Int", W, "Int", H, "Int", 0, "Int", 0x26200A, "Ptr", 0, "Ptr*", pBM)
DllCall("gdiplus\GdipGetImageGraphicsContext", "Ptr", pBM, "Ptr*", G)
DllCall("gdiplus\GdipSetInterpolationMode", "Ptr", G, "Int", App.Config.InterpolationMode-1)
GetImageDimensions(pBitmap, WidthBM, HeightBM)
DrawImage(G, pBitmap, -Round(W/400), -Round(H/400)
, Ceil(W*1.005), Ceil(H*1.005), 0, 0, WidthBM, HeightBM)
DllCall("gdiplus\GdipDeleteGraphics", "Ptr", G)
SaveScreenshot(pBM, Time, OutputOverride)
}
PreviewSaveToOutput(MenuItem) {
if (MenuItem = "файл")
return "File"
if (MenuItem = "буфер обмена")
return "Clip"
if (MenuItem = "imgbb.com")
return "Imgbb"
return ""
}
SaveBitmap(pBitmap, ByRef info, Quality := 75, tobuff := "") {
if tobuff
Extension := info
else
SplitPath, info,,, Extension
if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
return -1
DllCall("gdiplus\GdipGetImageEncodersSize", "UInt*", nCount, "UInt*", nSize)
VarSetCapacity(ci, nSize)
DllCall("gdiplus\GdipGetImageEncoders", "UInt", nCount, "UInt", nSize, "Ptr", &ci)
if !(nCount && nSize)
return -2
Loop, % nCount {
sString := StrGet(NumGet(ci, (idx := (48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize), "UTF-16")
if !InStr(sString, "*." Extension)
continue
pCodec := &ci+idx
break
}
if !pCodec
return -3
if RegExMatch(Extension, "i)^J(PG|PEG|PE|FIF)$") && Quality != 75 {
DllCall("gdiplus\GdipGetEncoderParameterListSize", "Ptr", pBitmap, "Ptr", pCodec, "UInt*", nSize)
VarSetCapacity(EncoderParameters, nSize, 0)
DllCall("gdiplus\GdipGetEncoderParameterList", "Ptr", pBitmap, "Ptr", pCodec, "UInt", nSize, "Ptr", &EncoderParameters)
Loop, % NumGet(EncoderParameters, "UInt") {
elem := (24+A_PtrSize)*(A_Index-1) + 4 + (pad := A_PtrSize = 8 ? 4 : 0)
if (NumGet(EncoderParameters, elem+16, "UInt") = 1) && (NumGet(EncoderParameters, elem+20, "UInt") = 6) {
p := elem+&EncoderParameters-pad-4
NumPut(Quality, NumGet(NumPut(4, NumPut(1, p+0)+20, "UInt")), "UInt")
break
}
}
}
if !tobuff {
if A_IsUnicode
pOutput := &info
else {
VarSetCapacity(wOutput, StrPut(info, "UTF-16")*2, 0)
StrPut(info, &wOutput, "UTF-16")
pOutput := &wOutput
}
E := DllCall("gdiplus\GdipSaveImageToFile", "Ptr", pBitmap, "Ptr", pOutput, "Ptr", pCodec, "UInt", p ? p : 0)
}
else {
DllCall( "ole32\CreateStreamOnHGlobal", "UInt", 0, "Int", 1, "Ptr*", pStream )
if E := DllCall( "gdiplus\GdipSaveImageToStream", "Ptr", pBitmap, "Ptr", pStream, "Ptr", pCodec, "UInt", p ? p : 0 )
DllCall( NumGet( NumGet( 1*pStream ) + A_PtrSize*2 ), "Ptr", pStream )
else {
DllCall( "ole32\GetHGlobalFromStream", "Ptr", pStream, "Ptr*", hData )
pData := DllCall( "GlobalLock", "Ptr", hData )
nSize := DllCall( "GlobalSize", "Ptr", hData )
VarSetCapacity( info, 0), VarSetCapacity( info, nSize, 0 )
DllCall( "RtlMoveMemory", "Ptr", &info, "Ptr", pData, "UInt", nSize )
DllCall( "GlobalUnlock", "Ptr", hData )
DllCall( NumGet( NumGet( 1*pStream ) + A_PtrSize*2 ), "Ptr", pStream )
DllCall( "GlobalFree", "Ptr", hData )
}
}
return E ? -4 : tobuff ? nSize : 0
}
SetBitmapToClipboard(pBitmap) {
off1 := A_PtrSize = 8 ? 52 : 44, off2 := A_PtrSize = 8 ? 32 : 24
DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "Ptr", pBitmap, "Ptr*", hBitmap, "Int", 0xFFFFFFFF)
DllCall("GetObject", "Ptr", hBitmap, "int", VarSetCapacity(oi, A_PtrSize = 8 ? 104 : 84, 0), "Ptr", &oi)
hdib := DllCall("GlobalAlloc", "UInt", 2, "Ptr", 40+NumGet(oi, off1, "UInt"), "Ptr")
pdib := DllCall("GlobalLock", "Ptr", hdib, "Ptr")
DllCall("RtlMoveMemory", "Ptr", pdib, "Ptr", &oi+off2, "Ptr", 40)
DllCall("RtlMoveMemory", "Ptr", pdib+40, "Ptr", NumGet(oi, off2 - A_PtrSize, "Ptr"), "Ptr", NumGet(oi, off1, "UInt"))
DllCall("GlobalUnlock", "Ptr", hdib)
DllCall("DeleteObject", "Ptr", hBitmap)
DllCall("OpenClipboard", "Ptr", 0)
DllCall("EmptyClipboard")
DllCall("SetClipboardData", "UInt", 8, "Ptr", hdib)
DllCall("CloseClipboard")
}
CreateDIBSection(w, h, hdc="", bpp=32, ByRef ppvBits=0) {
hdc2 := hdc ? hdc : DllCall("GetDC", "Ptr", 0)
VarSetCapacity(bi, 40, 0)
NumPut(w, bi, 4, "uint")
NumPut(h, bi, 8, "uint")
NumPut(40, bi, 0, "uint")
NumPut(1, bi, 12, "ushort")
NumPut(0, bi, 16, "uInt")
NumPut(bpp, bi, 14, "ushort")
hbm := DllCall("CreateDIBSection", "Ptr", hdc2, "Ptr", &bi, "UInt", 0, "Ptr*", ppvBits, "Ptr", 0, "UInt", 0, "Ptr")
( !hdc && DllCall("ReleaseDC", "Ptr", 0, "Ptr", hdc2) )
return hbm
}
UpdateLayeredWindow(hwnd, hdc, x="", y="", w="", h="", Alpha=255) {
if ((x != "") && (y != ""))
VarSetCapacity(pt, 8), NumPut(x, pt, 0, "UInt"), NumPut(y, pt, 4, "UInt")
if (w = "") ||(h = "")
WinGetPos,,, w, h, ahk_id %hwnd%
return DllCall( "UpdateLayeredWindow", "Ptr", hwnd, "Ptr", 0, "Ptr", ((x = "") && (y = "")) ? 0 : &pt, "Int64*", w|h<<32
, "Ptr", hdc, "Int64*", 0, "UInt", 0, "UInt*", Alpha<<16|1<<24, "UInt", 2 )
}
GdipStartup() {
if !DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr")
DllCall("LoadLibrary", "Str", "gdiplus")
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", "Ptr*", pToken, "Ptr", &si, "Ptr", 0)
return pToken
}
GdipShutdown(pToken) {
DllCall("gdiplus\GdiplusShutdown", "Ptr", pToken)
if hModule := DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr")
DllCall("FreeLibrary", "Ptr", hModule)
return 0
}
SetStaticColor(hStatic, b_color, f_color := 0) {
static arr := [], GWL_WNDPROC := -4
b_color := DllCall("Ws2_32\ntohl", "UInt", b_color << 8, "UInt")
f_color := DllCall("Ws2_32\ntohl", "UInt", f_color << 8, "UInt")
hGui := DllCall("GetParent", "Ptr", hStatic, "Ptr")
if !arr.HasKey(hGui) {
arr[hGui] := {}, arr[hGui].Statics := []
arr[hGui].ProcOld := DllCall("SetWindowLong" . (A_PtrSize = 8 ? "Ptr" : ""), "Ptr", hGui, "Int", GWL_WNDPROC
, "Ptr", RegisterCallback("WindowProc", "", 4, Object(arr[hGui])), "Ptr")
}
else if arr[hGui].Statics.HasKey(hStatic)
DllCall("DeleteObject", "Ptr", arr[hGui].Statics[hStatic].hBrush)
arr[hGui].Statics[hStatic] := { b_color: b_color, f_color: f_color
, hBrush: DllCall("CreateSolidBrush", "UInt", b_color, "Ptr") }
WinSet, Redraw,, ahk_id %hStatic%
}
WindowProc(hwnd, uMsg, wParam, lParam) {
Critical
static WM_CTLCOLORSTATIC := 0x138
obj := Object(A_EventInfo)
if (uMsg = WM_CTLCOLORSTATIC && k := obj.Statics[lParam]) {
DllCall("SetBkColor", "Ptr", wParam, "UInt", k.b_color)
DllCall("SetTextColor", "Ptr", wParam, "UInt", k.f_color)
return k.hBrush
}
return DllCall("CallWindowProc", "Ptr", obj.ProcOld, "Ptr", hwnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam)
}
CryptBinaryToStringBASE64(pData, Bytes, NOCRLF = "") {
static CRYPT_STRING_BASE64 := 1, CRYPT_STRING_NOCRLF := 0x40000000
CRYPT := CRYPT_STRING_BASE64 | (NOCRLF ? CRYPT_STRING_NOCRLF : 0)
DllCall("Crypt32\CryptBinaryToString", "Ptr", pData, "UInt", Bytes, "UInt", CRYPT, "Ptr", 0, "UInt*", Chars)
VarSetCapacity(OutData, Chars * (A_IsUnicode ? 2 : 1))
DllCall("Crypt32\CryptBinaryToString", "Ptr", pData, "UInt", Bytes, "UInt", CRYPT, "Str", OutData, "UInt*", Chars)
return OutData
}
CreateIconFromBase64(StringBASE64, Size) {
DllCall("Crypt32.dll\CryptStringToBinary", "Ptr", &StringBase64
, "UInt", StrLen(StringBase64), "UInt", CRYPT_STRING_BASE64 := 1, "UInt", 0, "UInt*", Bytes, "UInt*", 0, "UInt*", 0)
VarSetCapacity(IconData, Bytes)
DllCall("Crypt32.dll\CryptStringToBinary", "Ptr", &StringBase64
, "UInt", StrLen(StringBase64), "UInt", CRYPT_STRING_BASE64, "Str", IconData, "UInt*", Bytes, "UInt*", 0, "UInt*", 0)
return DllCall("CreateIconFromResourceEx", "Ptr", &IconData + 4
, "UInt", NumGet(&IconData, "UInt"), "UInt", true, "UInt", 0x30000, "Int", Size, "Int", Size, "UInt", 0, "Ptr")
}
GetBase64String(Size) {
Icon16 =
(RTrim Join
aAQAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAD///+3
////////////////////////////////////////////////////////////////
//////////////+3/////8H2/v865Pz/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/zLi/P+u9P7///////////8w4vz/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/H+D8////////////
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P///////////xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z///////////8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8////////////
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P///////////xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z///////////8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8////////////
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P///////////xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z///////////8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8////////////
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P///////////zDi/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8f4Pz////////////G9/7/Sub9/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P9A5Pz/tPT+//////////+3
////////////////////////////////////////////////////////////////
//////////////+3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
)
Icon32 =
(RTrim Join
qBAAACgAAAAgAAAAQAAAAAEAIAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAAAAC9vr5avb6+5L2+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/
vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7kvb6+Wr2+vvO9vr7/vb6+/72+vv+9vr7/
vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/
vb6+/72+vv+9vr7zvb6+/72+vv+LyNH/Ldv1/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/y3b9f+LyNH/vb6+/72+vv+9vr7/vb6+/ybd+P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/ybd+P+9vr7/vb6+/72+vv+zwML/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/7PAwv+9vr7/vb6+/7PAwv8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/s8DC/72+vv+9vr7/s8DC/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P+zwML/vb6+/72+vv+zwML/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/7PAwv+9vr7/vb6+/7PAwv8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/s8DC/72+vv+9vr7/s8DC/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P+zwML/vb6+/72+vv+zwML/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/7PAwv+9vr7/vb6+/7PAwv8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/s8DC/72+vv+9vr7/s8DC/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P+zwML/vb6+/72+vv+zwML/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/7PAwv+9vr7/vb6+/7PAwv8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/s8DC/72+vv+9vr7/s8DC/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P+zwML/vb6+/72+vv+zwML/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/7PAwv+9vr7/vb6+/7PAwv8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/s8DC/72+vv+9vr7/s8DC/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P+zwML/vb6+/72+vv+zwML/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/7PAwv+9vr7/vb6+/7PAwv8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/s8DC/72+vv+9vr7/s8DC/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P+zwML/vb6+/72+vv+zwML/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/7PAwv+9vr7/vb6+/7PAwv8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/s8DC/72+vv+9vr7/s8DC/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P+zwML/vb6+/72+vv+zwML/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/7PAwv+9vr7/vb6+/7PAwv8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/s8DC/72+vv+9vr7/s8DC/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P+zwML/vb6+/72+vv+9vr7/Jt34/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Jt34/72+vv+9vr7/vb6+/72+vv+NyND/O9jw/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/
Gt/8/xrf/P8a3/z/Gt/8/xrf/P8a3/z/Gt/8/zvY8P+NyND/vb6+/72+vv+9vr72vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/
vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+9r2+vmC9vr7wvb6+/72+vv+9vr7/
vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/vb6+/72+vv+9vr7/
vb6+/72+vvC9vr5gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
)
return Icon%Size%
}
; Full-screen mouse selection overlay.
class OverlaySelection {
static WM_MOUSEMOVE := 0x0200
__New(thickness := 2, color := 0x00FF00, labelSpecs := "", armedStyle := "") {
this.scale := A_ScreenDPI / 96
this.overlay := new SelectionOverlayFrame(thickness, color, this.scale)
this.state := "idle"
this.busy := false
this.startX := 0
this.startY := 0
this.curX := 0
this.curY := 0
this.callback := ""
this.callbackTimer := ""
this.disposed := false
this.onMove := ObjBindMethod(this, "OnMouseMove")
this.labels := []
this.providers := []
specs := IsObject(labelSpecs) ? labelSpecs : OverlaySelection.DefaultSpecs()
for index, spec in specs {
style := spec.HasKey("style") ? spec.style : {}
this.labels.Push(new SelectionOverlayLabel(style, this.scale))
this.providers.Push(spec.provider)
}
if !IsObject(armedStyle)
armedStyle := {}
this.armedLabel := new SelectionOverlayLabel(armedStyle, this.scale)
this.armedOffsetX := armedStyle.HasKey("offsetX") ? armedStyle.offsetX : 12
this.armedOffsetY := armedStyle.HasKey("offsetY") ? armedStyle.offsetY : 12
}
DefaultSpecs() {
gap := 5
return [ {style: {}, provider: Func("OverlayTopLabelProvider").Bind(gap)}
, {style: {}, provider: Func("OverlayBottomLabelProvider").Bind(gap)} ]
}
Arm(callback, showArmedLabel := true) {
if (this.state != "idle" || this.busy)
return
this.callback := callback
this.overlay.ClearFrame()
this.overlay.Show()
this.state := "armed"
OnMessage(this.WM_MOUSEMOVE, this.onMove)
MouseGetPos, mx, my
this.curX := mx
this.curY := my
if showArmedLabel
this.UpdateArmed()
}
BeginDrag() {
if (this.state != "armed")
return
MouseGetPos, mx, my
this.startX := mx
this.startY := my
this.curX := mx
this.curY := my
this.overlay.ClearFrame()
this.state := "dragging"
this.Update()
}
Quick(callback) {
if (this.state != "idle" || this.busy)
return
this.Arm(callback, false)
this.BeginDrag()
if !GetKeyState("LButton", "P")
this.Finish()
}
Cancel() {
if (this.state != "armed" && this.state != "dragging")
return
OnMessage(this.WM_MOUSEMOVE, this.onMove, 0)
this.overlay.Hide()
this.state := "idle"
}
OnMouseMove(wParam, lParam, msg, hwnd) {
if (hwnd != this.overlay.hwnd)
return
pt := this.ClientPoint(lParam)
this.curX := pt.x
this.curY := pt.y
if (this.state = "dragging")
this.Update()
else if (this.state = "armed")
this.UpdateArmed()
}
ClientPoint(lParam) {
x := lParam & 0xFFFF
y := (lParam >> 16) & 0xFFFF
if (x > 0x7FFF)
x -= 0x10000
if (y > 0x7FFF)
y -= 0x10000
VarSetCapacity(pt, 8, 0)
NumPut(x, pt, 0, "Int")
NumPut(y, pt, 4, "Int")
DllCall("ClientToScreen", "Ptr", this.overlay.hwnd, "Ptr", &pt)
return {x: NumGet(pt, 0, "Int"), y: NumGet(pt, 4, "Int")}
}
Rect() {
x := Min(this.startX, this.curX)
y := Min(this.startY, this.curY)
w := Abs(this.curX - this.startX)
h := Abs(this.curY - this.startY)
return {x: x, y: y, w: w, h: h}
}
Update() {
r := this.Rect()
ctx := {r: r, t: this.overlay.PhysT(), scale: this.scale}
for index, provider in this.providers {
spec := provider.Call(ctx)
this.labels[index].SetText(spec.text, spec.ax, spec.ay, spec.side)
}
this.overlay.Render(r, this.labels)
}
UpdateArmed() {
x := this.curX
y := this.curY
anchorX := x - Round(this.armedOffsetX * this.scale)
anchorY := y - Round(this.armedOffsetY * this.scale)
this.armedLabel.SetText(x . ", " . y, anchorX, anchorY, "topLeft")
this.overlay.RenderLabels([this.armedLabel])
}
Finish() {
if (this.state != "dragging")
return
this.state := "idle"
OnMessage(this.WM_MOUSEMOVE, this.onMove, 0)
this.overlay.Hide()
callback := this.callback
if IsObject(callback) {
this.busy := true
r := this.Rect()
this.callbackTimer := ObjBindMethod(this, "InvokeCallback", callback, r)
timer := this.callbackTimer
SetTimer, % timer, -1
}
}
InvokeCallback(callback, r) {
try callback.Call(r)
finally {
this.busy := false
this.callbackTimer := ""
}
}
Dispose() {
if (this.disposed)
return
this.disposed := true
if (this.state = "armed" || this.state = "dragging")
OnMessage(this.WM_MOUSEMOVE, this.onMove, 0)
if IsObject(this.callbackTimer) {
timer := this.callbackTimer
SetTimer, % timer, Delete
this.callbackTimer := ""
}
for index, label in this.labels
label.Dispose()
if IsObject(this.armedLabel)
this.armedLabel.Dispose()
if IsObject(this.overlay)
this.overlay.Dispose()
this.state := "idle"
}
__Delete() {
this.Dispose()
}
}
class SelectionOverlayFrame {
__New(thickness, color, scale := 1) {
this.t := thickness
this.scale := scale
this.color := 0xFF000000 | color
this.w := A_ScreenWidth
this.h := A_ScreenHeight
this.prev := ""
this.disposed := false
this.guiName := "SelectionOverlay"
Gui, % this.guiName . ":New", +AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x80000 +hwndOverlayHwnd
this.hwnd := OverlayHwnd
this.hArrow := DllCall("LoadCursor", "Ptr", 0, "Ptr", 32512, "Ptr")
this.CreateBuffer()
}
CreateBuffer() {
this.hdcMem := DllCall("CreateCompatibleDC", "Ptr", 0, "Ptr")
VarSetCapacity(bi, 40, 0)
NumPut(40, bi, 0, "UInt")
NumPut(this.w, bi, 4, "Int")
NumPut(-this.h, bi, 8, "Int")
NumPut(1, bi, 12, "UShort")
NumPut(32, bi, 14, "UShort")
NumPut(0, bi, 16, "UInt")
this.hbm := DllCall("CreateDIBSection", "Ptr", this.hdcMem, "Ptr", &bi
, "UInt", 0, "Ptr*", pBits, "Ptr", 0, "UInt", 0, "Ptr")
this.pBits := pBits
this.oldBm := DllCall("SelectObject", "Ptr", this.hdcMem, "Ptr", this.hbm, "Ptr")
DllCall("gdiplus\GdipCreateBitmapFromScan0", "Int", this.w, "Int", this.h
, "Int", this.w * 4, "Int", 0xE200B, "Ptr", this.pBits, "Ptr*", pBitmap)
this.pBitmap := pBitmap
DllCall("gdiplus\GdipGetImageGraphicsContext", "Ptr", this.pBitmap, "Ptr*", pGraphics)
this.pGraphics := pGraphics
DllCall("gdiplus\GdipSetCompositingMode", "Ptr", this.pGraphics, "Int", 1)
DllCall("gdiplus\GdipSetTextRenderingHint", "Ptr", this.pGraphics, "Int", 4)
DllCall("gdiplus\GdipSetSmoothingMode", "Ptr", this.pGraphics, "Int", 3)
DllCall("gdiplus\GdipCreateSolidFill", "UInt", this.color, "Ptr*", pBrush)
this.pBrush := pBrush
DllCall("gdiplus\GdipCreateSolidFill", "UInt", 0x01000000, "Ptr*", pErase)
this.pErase := pErase
DllCall("gdiplus\GdipGraphicsClear", "Ptr", this.pGraphics, "UInt", 0x01000000)
}
Show() {
options := "NA x0 y0 w" . this.w . " h" . this.h
Gui, % this.guiName . ":Show", % options
}
Hide() {
if (this.disposed)
return
DllCall("gdiplus\GdipGraphicsClear", "Ptr", this.pGraphics, "UInt", 0x01000000)
this.prev := ""
this.Flush()
Gui, % this.guiName . ":Hide"
DllCall("SetCursor", "Ptr", this.hArrow)
}
ClearFrame() {
DllCall("gdiplus\GdipGraphicsClear", "Ptr", this.pGraphics, "UInt", 0x01000000)
this.prev := ""
this.Flush()
}
SetRect(x, y, w, h) {
cur := {x: x, y: y, w: w, h: h}
if IsObject(this.prev)
this.Strips(this.prev, this.pErase)
this.Strips(cur, this.pBrush)
this.prev := cur
this.Flush()
}
Render(rect, labels) {
for index, label in labels
label.Erase(this.pGraphics, this.pErase)
if IsObject(this.prev)
this.Strips(this.prev, this.pErase)
cur := {x: rect.x, y: rect.y, w: rect.w, h: rect.h}
this.Strips(cur, this.pBrush)
this.prev := cur
for index, label in labels
label.Draw(this.pGraphics, this.w, this.h)
this.Flush()
for index, label in labels
label.Commit()
}
RenderLabels(labels) {
for index, label in labels
label.Erase(this.pGraphics, this.pErase)
for index, label in labels
label.Draw(this.pGraphics, this.w, this.h)
this.Flush()
for index, label in labels
label.Commit()
}
PhysT() {
return Max(1, Round(this.t * this.scale))
}
Strips(r, brush) {
t := this.PhysT()
this.Fill(brush, r.x - t, r.y - t, r.w + 2 * t, t)
this.Fill(brush, r.x - t, r.y + r.h, r.w + 2 * t, t)
this.Fill(brush, r.x - t, r.y, t, r.h)
this.Fill(brush, r.x + r.w, r.y, t, r.h)
}
Fill(brush, x, y, w, h) {
if (w < 1 || h < 1)
return
DllCall("gdiplus\GdipFillRectangle", "Ptr", this.pGraphics
, "Ptr", brush, "Float", x, "Float", y, "Float", w, "Float", h)
}
Flush() {
VarSetCapacity(pt, 8, 0)
VarSetCapacity(sz, 8, 0)
NumPut(this.w, sz, 0, "Int")
NumPut(this.h, sz, 4, "Int")
VarSetCapacity(src, 8, 0)
VarSetCapacity(blend, 4, 0)
NumPut(255, blend, 2, "UChar")
NumPut(1, blend, 3, "UChar")
DllCall("UpdateLayeredWindow", "Ptr", this.hwnd, "Ptr", 0
, "Ptr", &pt, "Ptr", &sz, "Ptr", this.hdcMem, "Ptr", &src
, "UInt", 0, "Ptr", &blend, "UInt", 2)
}
Dispose() {
if (this.disposed)
return
this.disposed := true
if (this.pBrush)
DllCall("gdiplus\GdipDeleteBrush", "Ptr", this.pBrush)
if (this.pErase)
DllCall("gdiplus\GdipDeleteBrush", "Ptr", this.pErase)
if (this.pGraphics)
DllCall("gdiplus\GdipDeleteGraphics", "Ptr", this.pGraphics)
if (this.pBitmap)
DllCall("gdiplus\GdipDisposeImage", "Ptr", this.pBitmap)
if (this.hbm) {
DllCall("SelectObject", "Ptr", this.hdcMem, "Ptr", this.oldBm)
DllCall("DeleteObject", "Ptr", this.hbm)
}
if (this.hdcMem)
DllCall("DeleteDC", "Ptr", this.hdcMem)
if (this.hwnd && DllCall("IsWindow", "Ptr", this.hwnd))
Gui, % this.guiName . ":Destroy"
this.pBrush := 0
this.pErase := 0
this.pGraphics := 0
this.pBitmap := 0
this.hbm := 0
this.hdcMem := 0
this.hArrow := 0
this.hwnd := 0
}
__Delete() {
this.Dispose()
}
}
class SelectionOverlayLabel {
__New(style := "", scale := 1) {
if !IsObject(style)
style := {}
fontName := this.StyleValue(style, "fontName", "Segoe UI")
fontSize := this.StyleValue(style, "fontSize", 14) * scale
fontStyle := this.StyleValue(style, "fontStyle", 0)
textColor := this.StyleValue(style, "textColor", 0xFFFFFF)
backColor := this.StyleValue(style, "backColor", 0x202020)
this.padX := Round(this.StyleValue(style, "padX", 6) * scale)
this.padY := Round(this.StyleValue(style, "padY", 3) * scale)
this.radius := Round(this.StyleValue(style, "radius", 6) * scale)
this.text := ""
this.box := ""
this.eraseBox := ""
this.prevErase := ""
this.disposed := false
DllCall("gdiplus\GdipCreateFontFamilyFromName", "WStr", fontName
, "Ptr", 0, "Ptr*", family)
this.family := family
DllCall("gdiplus\GdipCreateFont", "Ptr", this.family, "Float", fontSize
, "Int", fontStyle, "Int", 2, "Ptr*", font)
this.font := font
DllCall("gdiplus\GdipCreateStringFormat", "Int", 0, "Int", 0, "Ptr*", fmt)
this.fmt := fmt
DllCall("gdiplus\GdipSetStringFormatAlign", "Ptr", this.fmt, "Int", 0)
DllCall("gdiplus\GdipSetStringFormatLineAlign", "Ptr", this.fmt, "Int", 1)
DllCall("gdiplus\GdipCreateSolidFill", "UInt", 0xFF000000 | textColor, "Ptr*", textBrush)
this.textBrush := textBrush
DllCall("gdiplus\GdipCreateSolidFill", "UInt", 0xFF000000 | backColor, "Ptr*", backBrush)
this.backBrush := backBrush
}
StyleValue(style, key, defaultValue) {
return style.HasKey(key) ? style[key] : defaultValue
}
SetText(text, anchorX, anchorY, side := "top") {
this.text := text
this.ax := anchorX
this.ay := anchorY
this.side := side
}
Measure(pGraphics) {
VarSetCapacity(layout, 16, 0)
NumPut(0, layout, 0, "Float")
NumPut(0, layout, 4, "Float")
NumPut(9999, layout, 8, "Float")
NumPut(9999, layout, 12, "Float")
VarSetCapacity(bounds, 16, 0)
DllCall("gdiplus\GdipMeasureString", "Ptr", pGraphics, "WStr", this.text
, "Int", -1, "Ptr", this.font, "Ptr", &layout, "Ptr", this.fmt
, "Ptr", &bounds, "Int*", chars, "Int*", lines)
return {w: NumGet(bounds, 8, "Float"), h: NumGet(bounds, 12, "Float")}
}
ComputeBox(pGraphics, screenW, screenH) {
metrics := this.Measure(pGraphics)
bw := Ceil(metrics.w) + this.padX * 2
bh := Ceil(metrics.h) + this.padY * 2
if (this.side = "top") {
bx := this.ax
by := this.ay - bh - 1
} else if (this.side = "bottom") {
bx := this.ax - bw
by := this.ay
} else if (this.side = "left") {
bx := this.ax - bw
by := this.ay - bh // 2
} else if (this.side = "right") {
bx := this.ax
by := this.ay - bh // 2
} else if (this.side = "topLeft") {
bx := this.ax - bw
by := this.ay - bh - 1
} else {
bx := this.ax - bw // 2
by := this.ay - bh // 2
}
bx := Max(0, Min(bx, screenW - bw))
by := Max(0, Min(by, screenH - bh))
return {x: bx, y: by, w: bw, h: bh}
}
Draw(pGraphics, screenW, screenH) {
if (this.text = "") {
this.box := ""
this.eraseBox := ""
return
}
box := this.ComputeBox(pGraphics, screenW, screenH)
this.box := box
ex := Max(0, box.x - 1)
ey := Max(0, box.y - 1)
er := Min(screenW, box.x + box.w + 1)
eb := Min(screenH, box.y + box.h + 1)
this.eraseBox := {x: ex, y: ey, w: er - ex, h: eb - ey}
DllCall("gdiplus\GdipSetCompositingMode", "Ptr", pGraphics, "Int", 0)
this.FillRoundRect(pGraphics, box.x, box.y, box.w, box.h, this.radius, this.backBrush)
VarSetCapacity(rect, 16, 0)
NumPut(box.x + this.padX, rect, 0, "Float")
NumPut(box.y, rect, 4, "Float")
NumPut(box.w, rect, 8, "Float")
NumPut(box.h, rect, 12, "Float")
DllCall("gdiplus\GdipDrawString", "Ptr", pGraphics, "WStr", this.text
, "Int", -1, "Ptr", this.font, "Ptr", &rect, "Ptr", this.fmt
, "Ptr", this.textBrush)
DllCall("gdiplus\GdipSetCompositingMode", "Ptr", pGraphics, "Int", 1)
}
FillRoundRect(pGraphics, x, y, w, h, radius, brush) {
radius := Min(radius, Min(w // 2, h // 2))
diameter := radius * 2
DllCall("gdiplus\GdipCreatePath", "Int", 0, "Ptr*", path)
if (radius > 0) {
DllCall("gdiplus\GdipAddPathArc", "Ptr", path, "Float", x
, "Float", y, "Float", diameter, "Float", diameter, "Float", 180, "Float", 90)
DllCall("gdiplus\GdipAddPathArc", "Ptr", path, "Float", x + w - diameter
, "Float", y, "Float", diameter, "Float", diameter, "Float", 270, "Float", 90)
DllCall("gdiplus\GdipAddPathArc", "Ptr", path, "Float", x + w - diameter
, "Float", y + h - diameter, "Float", diameter, "Float", diameter, "Float", 0, "Float", 90)
DllCall("gdiplus\GdipAddPathArc", "Ptr", path, "Float", x
, "Float", y + h - diameter, "Float", diameter, "Float", diameter, "Float", 90, "Float", 90)
DllCall("gdiplus\GdipClosePathFigure", "Ptr", path)
} else {
DllCall("gdiplus\GdipAddPathRectangle", "Ptr", path
, "Float", x, "Float", y, "Float", w, "Float", h)
}
DllCall("gdiplus\GdipSetSmoothingMode", "Ptr", pGraphics, "Int", 4)
DllCall("gdiplus\GdipFillPath", "Ptr", pGraphics, "Ptr", brush, "Ptr", path)
DllCall("gdiplus\GdipSetSmoothingMode", "Ptr", pGraphics, "Int", 3)
DllCall("gdiplus\GdipDeletePath", "Ptr", path)
}
Erase(pGraphics, eraseBrush) {
if !IsObject(this.prevErase)
return
box := this.prevErase
DllCall("gdiplus\GdipFillRectangle", "Ptr", pGraphics, "Ptr", eraseBrush
, "Float", box.x, "Float", box.y, "Float", box.w, "Float", box.h)
}
Commit() {
this.prevErase := this.eraseBox
}
Dispose() {
if (this.disposed)
return
this.disposed := true
if (this.textBrush)
DllCall("gdiplus\GdipDeleteBrush", "Ptr", this.textBrush)
if (this.backBrush)
DllCall("gdiplus\GdipDeleteBrush", "Ptr", this.backBrush)
if (this.fmt)
DllCall("gdiplus\GdipDeleteStringFormat", "Ptr", this.fmt)
if (this.font)
DllCall("gdiplus\GdipDeleteFont", "Ptr", this.font)
if (this.family)
DllCall("gdiplus\GdipDeleteFontFamily", "Ptr", this.family)
this.textBrush := 0
this.backBrush := 0
this.fmt := 0
this.font := 0
this.family := 0
}
__Delete() {
this.Dispose()
}
}
class ToolTip {
; Default options. Any option omitted by the caller falls back to the value here.
; Color options use "" to mean "leave the system default" (0 is a valid black).
DefaultOptions() {
return { text: "", title: "", icon: 0
, x: "", y: "", TimeOut: "", ShowNow: true
, FontName: "", FontSize: 0, FontStyle: ""
, BackColor: "", TextColor: "", Margin: ""
, BalloonTip: false, CloseButton: false
, transparent: true, RightBottom: false, TrayTip: false }
}
__New( options ) {
defaults := this.DefaultOptions()
for k, v in defaults
this[k] := options.HasKey(k) ? options[k] : v
this._CreateToolTip()
( this.ShowNow && this.Show(this.x, this.y, this.TimeOut) )
}
_CreateToolTip() {
static WS_POPUP := 0x80000000, WS_EX_TOPMOST := 8, WS_EX_TRANSPARENT := 0x20
, TTS_NOPREFIX := 2, TTS_ALWAYSTIP := 1, TTS_BALLOON := 0x40, TTS_CLOSE := 0x80
, TTF_TRACK := 0x20, TTF_ABSOLUTE := 0x80, szTI := A_PtrSize = 4 ? 48 : 72
VarSetCapacity(TOOLINFO, szTI, 0)
this.pTI := &TOOLINFO
NumPut(szTI, TOOLINFO)
(this.TrayTip && this.BalloonTip := true)
(this.CloseButton && this.transparent := false)
NumPut(TTF_TRACK|(this.BalloonTip ? 0 : TTF_ABSOLUTE), &TOOLINFO + 4)
this.hwnd := DllCall("CreateWindowEx", "UInt", WS_EX_TOPMOST|(this.transparent ? WS_EX_TRANSPARENT : 0)
, "Str", "tooltips_class32", "Str", ""
, "UInt", WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP | (this.CloseButton ? TTS_CLOSE : 0) | (this.BalloonTip ? TTS_BALLOON : 0)
, "Int", 0, "Int", 0, "Int", 0, "Int", 0, "Ptr", 0, "Ptr", 0, "Ptr", 0, "Ptr", 0)
if (this.FontName || this.FontSize || this.FontStyle)
this._SetFont()
if (this.TextColor != "" || this.BackColor != "")
this._SetColor()
this._SetInfo()
}
_SetFont() {
static WM_GETFONT := 0x31, mult := A_IsUnicode ? 2 : 1, szLF := 28 + 32 * mult
, LOGPIXELSY := 90, ANTIALIASED_QUALITY := 4
, styles := { bold: {value: 700, offset: 16, size: "Int"}
, italic: {value: 1, offset: 20, size: "Char"}
, underline: {value: 1, offset: 21, size: "Char"}
, strikeout: {value: 1, offset: 22, size: "Char"} }
hPrevFont := this._SendMessage(WM_GETFONT)
VarSetCapacity(LOGFONT, szLF, 0)
DllCall("GetObject", "Ptr", hPrevFont, "Int", szLF, "Ptr", &LOGFONT)
DllCall("DeleteObject", "Ptr", hPrevFont)
if this.FontSize {
hDC := DllCall("GetDC", "Ptr", this.hwnd, "Ptr")
picH := DllCall("GetDeviceCaps", "Ptr", hDC, "Int", LOGPIXELSY)
height := -DllCall("MulDiv", "Int", this.FontSize, "Int", picH, "Int", 72)
DllCall("ReleaseDC", "Ptr", this.hwnd, "Ptr", hDC)
NumPut(height, LOGFONT, "Int")
}
FontStyle := this.FontStyle
Loop, parse, FontStyle, %A_Space%
{
if obj := styles[A_LoopField]
NumPut(obj.value, &LOGFONT + obj.offset, obj.size)
}
(this.FontSize > 24 && NumPut(ANTIALIASED_QUALITY, &LOGFONT + 26, "Char"))
this.FontName && StrPut(this.FontName, &LOGFONT + 28, StrLen(this.FontName) * mult, A_IsUnicode ? "UTF-16" : "CP0")
this.hFont := DllCall("CreateFontIndirect", "Ptr", &LOGFONT, "Ptr")
}
_SetColor() {
static WM_USER := 0x400, TTM_SETTIPBKCOLOR := WM_USER + 19, TTM_SETTIPTEXTCOLOR := WM_USER + 20
VarSetCapacity(empty, 2, 0)
DllCall("UxTheme\SetWindowTheme", "Ptr", this.hwnd, "Ptr", 0, "Ptr", &empty)
( this.TextColor != "" && this._SendMessage(TTM_SETTIPTEXTCOLOR, this._GetColor(this.TextColor)) )
( this.BackColor != "" && this._SendMessage(TTM_SETTIPBKCOLOR, this._GetColor(this.BackColor)) )
}
_GetColor(color) {
static WS_CHILD := 0x40000000, WM_CTLCOLORSTATIC := 0x138
Gui, New, +hwndhGui +%WS_CHILD%
Gui, Color, % color + 0 = "" ? color : Format("{:x}", color)
Gui, Add, Text, hwndhText
hdc := DllCall("GetDC", "Ptr", hText, "Ptr")
SendMessage, WM_CTLCOLORSTATIC, hdc, hText,, ahk_id %hGui%
clr := DllCall("GetBkColor", "Ptr", hdc)
DllCall("ReleaseDC", "Ptr", hText, "Ptr", hdc)
Gui, Destroy
return clr
}
_SetInfo() {
static WM_USER := 0x400, TTM_SETMAXTIPWIDTH := WM_USER + 24
, TTM_ADDTOOL := WM_USER + (A_IsUnicode ? 50 : 4), WM_SETFONT := 0x30
this._SendMessage(WM_SETFONT, this.hFont, 1)
this._SendMessage(TTM_ADDTOOL, 0, this.pTI)
this.SetTitle(this.icon, this.title)
this._SendMessage(TTM_SETMAXTIPWIDTH, 0, A_ScreenWidth)
this._SetMargin()
this.SetText(this.text)
}
_SetMargin() {
static WM_USER := 0x400, TTM_SETMARGIN := WM_USER + 26
margin := this.Margin
if !(IsObject(margin) && margin.MaxIndex() = 4)
return
VarSetCapacity(RECT, 16, 0)
for i, offset in margin
NumPut(offset, &RECT + (i - 1) * 4, "Int")
this._SendMessage(TTM_SETMARGIN, 0, &RECT)
}
SetText(text) {
static WM_USER := 0x400, TTM_UPDATETIPTEXT := WM_USER + (A_IsUnicode ? 57 : 12)
NumPut(&text, this.pTI + (A_PtrSize = 4 ? 36 : 48))
this._SendMessage(TTM_UPDATETIPTEXT, 0, this.pTI)
}
SetTitle(icon := "", title := "") {
static WM_USER := 0x400, TTM_SETTITLE := WM_USER + (A_IsUnicode ? 33 : 32), TTM_UPDATE := WM_USER + 29
((icon || this.CloseButton) && title = "") && title := " "
this._SendMessage(TTM_SETTITLE, icon, &title)
(icon > 3 && DllCall("DestroyIcon", "Ptr", icon))
this._SendMessage(TTM_UPDATE)
}
Show(x := "", y := "", timeout := "") {
static WM_USER := 0x400, TTM_TRACKACTIVATE := WM_USER + 17, TTM_TRACKPOSITION := WM_USER + 18
SysGet, MonPrimary, MonitorPrimary
SysGet, Mon, MonitorWorkArea, %MonPrimary%
xTT := x, yTT := y
; TrayTip mode: anchor the balloon to the script's tray icon (one-shot)
if this.TrayTip {
this._GetTrayIconCoords(xTT, yTT)
; RightBottom mode: push beyond the work area so the post-activation
; clamp below pins the tip to the bottom-right corner, above the taskbar
} else if this.RightBottom {
xTT := MonRight, yTT := MonBottom
} else if (xTT = "" || yTT = "") {
CoordMode, Mouse
MouseGetPos, xm, ym
(xTT = "" && xTT := xm + 10)
(yTT = "" && yTT := ym + 10)
}
this._SendMessage(TTM_TRACKPOSITION, 0, xTT|(yTT<<16))
this._SendMessage(TTM_TRACKACTIVATE, 1, this.pTI)
if this.BalloonTip
xMax := MonRight, yMax := MonBottom
else {
WinGetPos,,, W, H, % "ahk_id" this.hwnd
xMax := MonRight - W - 10
yMax := MonBottom - H - 10
}
if (xTT > xMax || yTT > yMax) {
(xTT > xMax && xTT := xMax)
(yTT > yMax && yTT := yMax)
this._SendMessage(TTM_TRACKPOSITION, 0, xTT|(yTT<<16))
}
if timeout {
timer := this.timer
try SetTimer, % timer, Delete
this.timer := timer := ObjBindMethod(this, timeout > 0 ? "Hide" : "Destroy")
SetTimer % timer, % "-" . Abs(timeout)
}
}
Hide() {
static WM_USER := 0x400, TTM_TRACKACTIVATE := WM_USER + 17
this._SendMessage(TTM_TRACKACTIVATE, 0, this.pTI)
}
Destroy() {
this.__Delete()
this.SetCapacity(0)
this.base := ""
}
_SendMessage(msg, wp := 0, lp := 0) {
return DllCall("SendMessage", "Ptr", this.hwnd, "UInt", msg, "Ptr", wp, "Ptr", lp, "Ptr")
}
_GetTrayIconCoords(ByRef x, ByRef y) {
static AHK_NOTIFYICON := 0x404, szNII := 16 + 3 * A_PtrSize
; Modern, Win11-safe way: ask the shell for the icon's screen rect directly.
VarSetCapacity(NII, szNII, 0)
NumPut(szNII, NII, 0, "UInt")
NumPut(A_ScriptHwnd, NII, A_PtrSize, "Ptr")
NumPut(AHK_NOTIFYICON, NII, A_PtrSize * 2, "UInt")
VarSetCapacity(RECT, 16, 0)
if (DllCall("Shell32\Shell_NotifyIconGetRect", "Ptr", &NII, "Ptr", &RECT, "UInt") = 0) {
xL := NumGet(RECT, 0, "Int"), yT := NumGet(RECT, 4, "Int")
xR := NumGet(RECT, 8, "Int")
x := (xL + xR) // 2 ; balloon anchors its tail at this point
y := yT
} else {
; Fallback: aim at the tray notification area as a whole.
for k, v in ["TrayNotifyWnd", "SysPager", "ToolbarWindow32"]
hTray := DllCall("FindWindowEx", "Ptr", k = 1 ? WinExist("ahk_class Shell_TrayWnd") : hTray, "Ptr", 0, "Str", v, "UInt", 0, "Ptr")
WinGetPos, xTray, yTray, wTray,, % "ahk_id" hTray
x := xTray + wTray // 2, y := yTray
}
}
__Delete() {
(this.hFont && DllCall("DeleteObject", "Ptr", this.hFont))
(this.Icon > 3 && DllCall("DestroyIcon", "Ptr", this.Icon))
DllCall("DestroyWindow", "Ptr", this.hwnd)
}
}
;*************************************************************** HotKeys ***************************************************************
; Автор - serzh82saratov
; E-Mail: serzh82saratov@mail.ru
; Описание - http://forum.script-coding.com/viewtopic.php?id=8343
Hotkey_Register(Controls*) {
static IsStart
for k, v in Controls
{
Hotkey_ID(v[2], v[1]), Hotkey_ID(v[1], v[2])
Hotkey_Options(v[2], v[3] = "" ? "K" : v[3])
Hotkey_Value(v[2], Hotkey_Value(v[1]))
PostMessage, 0x00CF, 1, , , % "ahk_id" v[2] ; EM_SETREADONLY
if RegExMatch(v[3], "i)G(\d+)", g)
Hotkey_Group("Set", v[1], g1)
}
if IsStart
return Hotkey_IsRegFocus()
#HotkeyInterval 0
Hotkey_SetWinEventHook(0x8005, 0x8005, 0, RegisterCallback("Hotkey_EventFocus", "F"), 0, 0, 0) ; EVENT_OBJECT_FOCUS := 0x8005
Hotkey_InitHotkeys(), Hotkey_IsRegFocus(), IsStart := 1
}
Hotkey_Main(Param1, Param2 = "") {
static OnlyMods, ControlHandle, Hotkey, KeyName, K := {}
, Prefix := {"LAlt":"<!","LCtrl":"<^","LShift":"<+","LWin":"<#"
,"RAlt":">!","RCtrl":">^","RShift":">+","RWin":">#"
,"Alt":"!","Ctrl":"^","Shift":"+","Win":"#"}
, EngSym := {"sc2":"1","sc3":"2","sc4":"3","sc5":"4","sc6":"5","sc7":"6"
,"sc8":"7","sc9":"8","scA":"9","scB":"0","scC":"-","scD":"="
,"sc10":"Q","sc11":"W","sc12":"E","sc13":"R","sc14":"T","sc15":"Y"
,"sc16":"U","sc17":"I","sc18":"O","sc19":"P","sc1A":"[","sc1B":"]"
,"sc1E":"A","sc1F":"S","sc20":"D","sc21":"F","sc22":"G","sc23":"H"
,"sc24":"J","sc25":"K","sc26":"L","sc27":"`;","sc28":"'","sc29":"``"
,"sc2B":"\","sc2C":"Z","sc2D":"X","sc2E":"C","sc2F":"V","sc30":"B"
,"sc31":"N","sc32":"M","sc33":",","sc34":".","sc35":"/"}
if Param1 = GetMod
return K.MLCtrl K.MRCtrl K.MLAlt K.MRAlt K.MLShift K.MRShift K.MLWin K.MRWin K.MCtrl K.MAlt K.MShift K.MWin
if Param2
{
if OnlyMods
{
SendMessage, 0xC, 0, "" Hotkey_Arr("Empty"), , ahk_id %ControlHandle%
OnlyMods := 0, K := {}
}
ControlHandle := Param2
Hotkey_Arr("Hook", Hotkey_Options(ControlHandle))
PostMessage, 0x00B1, -1, -1, , ahk_id %ControlHandle% ; EM_SETSEL
}
else if Hotkey_Arr("Hook")
{
Hotkey_Arr("Hook", 0), K := {}
if OnlyMods
SendMessage, 0xC, 0, "" Hotkey_Arr("Empty"), , ahk_id %ControlHandle%
SetTimer, Hotkey_IsRegFocus, -200
}
return
Hotkey_Mods:
if InStr(Hotkey_Arr("Hook"), "S")
GoTo Hotkey_View
IsMod := InStr(Hotkey_Arr("Hook"), "D") ? A_ThisHotkey : SubStr(A_ThisHotkey, 2)
if (K["M" IsMod] != "")
return
K["M" IsMod] := IsMod "+", K["P" IsMod] := Prefix[IsMod]
GoTo Hotkey_ViewMod
Hotkey_ModsUp:
if InStr(Hotkey_Arr("Hook"), "S")
return
IsMod := InStr(Hotkey_Arr("Hook"), "D") ? SubStr(A_ThisHotkey, 1, -3) : SubStr(A_ThisHotkey, 2, -3)
K["M" IsMod] := "", K["P" IsMod] := ""
if (Hotkey != "")
return
Hotkey_ViewMod:
Hotkey := "", OnlyMods := 1, Hotkey_Value(Hotkey_ID(ControlHandle), K.Prefix Hotkey), Hotkey_Value(ControlHandle, K.Prefix Hotkey)
K.Mods := K.MLCtrl K.MRCtrl K.MLAlt K.MRAlt K.MLShift K.MRShift K.MLWin K.MRWin K.MCtrl K.MAlt K.MShift K.MWin
Text := K.Mods = "" ? Hotkey_Arr("Empty") : K.Mods
SendMessage, 0xC, 0, &Text, , ahk_id %ControlHandle%
return
Hotkey_ViewNum:
if InStr(Hotkey_Arr("Hook"), "N")
KeyName := Hotkey := GetKeyName(A_ThisHotkey)
else
KeyName := GetKeyName(A_ThisHotkey), Hotkey := Format("sc{:x}", GetKeySC(A_ThisHotkey))
GoTo, Hotkey_Put
Hotkey_ViewSC:
KeyName := Hotkey_Arr("OnlyEngSym") ? EngSym[A_ThisHotkey] : Format("{:U}", GetKeyName(A_ThisHotkey))
Hotkey := A_ThisHotkey
GoTo, Hotkey_Put
Hotkey_View:
if (A_ThisHotkey = "Backspace")
GoTo, Hotkey_Clear
if Hotkey_IsMouseInput(A_ThisHotkey)
Hotkey_SyncPhysicalModifiers(K)
KeyName := Hotkey := A_ThisHotkey
Hotkey_Put:
OnlyMods := 0
K.Prefix := K.PLCtrl K.PRCtrl K.PLAlt K.PRAlt K.PLShift K.PRShift K.PLWin K.PRWin K.PCtrl K.PAlt K.PShift K.PWin
Hotkey_Value(Hotkey_ID(ControlHandle), K.Prefix Hotkey), Hotkey_Value(ControlHandle, K.Prefix Hotkey)
K.Mods := K.MLCtrl K.MRCtrl K.MLAlt K.MRAlt K.MLShift K.MRShift K.MLWin K.MRWin K.MCtrl K.MAlt K.MShift K.MWin
Text := K.Mods KeyName = "" ? Hotkey_Arr("Empty") : K.Mods KeyName
SendMessage, 0xC, 0, &Text, , ahk_id %ControlHandle%
if Hotkey_Group("Get", Hotkey_ID(ControlHandle)) && Hotkey_Group("SaveCheck", ControlHandle)
SetTimer, Hotkey_Group, -70
return
Hotkey_Clear:
OnlyMods := 0, K := {}
Hotkey_Value(Hotkey_ID(ControlHandle), " "), Hotkey_Value(ControlHandle, " ")
Text := Hotkey_Arr("Empty")
SendMessage, 0xC, 0, &Text, , ahk_id %ControlHandle%
if Hotkey_Group("Get", Hotkey_ID(ControlHandle)) && Hotkey_Group("SaveCheck", ControlHandle)
SetTimer, Hotkey_Group, -70
return
}
Hotkey_InitHotkeys() {
static nmMods := "LAlt|RAlt|LCtrl|RCtrl|LShift|RShift|LWin|RWin"
, nmMouse := "MButton|WheelDown|WheelUp|WheelRight|WheelLeft|XButton1|XButton2"
, scSymb := "2|3|4|5|6|7|8|9|A|B|C|D|10|11|12|13|14|15|16|17|18|19|1A|1B|"
. "1E|1F|20|21|22|23|24|25|26|27|28|29|2B|2C|2D|2E|2F|30|31|32|33|34|35"
; , scNumSymb := "53|52|4F|50|51|4B|4C|4D|47|48|49"
, scOther := "1|E|F|1C|37|39|3A|3B|3C|3D|3E|3F|40|41|42|43|44|45|46|4A|4E|54|57|58|63|64|65|"
. "66|67|68|69|6A|6B|6C|6D|6E|76|11C|135|147|148|149|14B|14D|14F|150|151|152|153|15D"
, vkNum := "2E|6E|60|2D|61|23|62|28|63|22|64|25|65|C|66|27|67|24|68|26|69"
, vkOther := "3|13|5F|A6|A7|A8|A9|AA|AB|AC|AD|AE|AF|B0|B1|B2|B3|B4|B5|B6|B7"
S_BatchLines := A_BatchLines
SetBatchLines, -1
#IF Hotkey_IsRegControl()
#IF Hotkey_Hook("K")
#IF Hotkey_Hook("M")
#IF Hotkey_Hook("L") && Hotkey_HasKeyboardModifier()
#IF Hotkey_Hook("R") && Hotkey_HasKeyboardModifier()
#IF Hotkey_Hook("J") && !Hotkey_Main("GetMod")
#IF Hotkey_Arr("Hook") && !Hotkey_Hook("K")
#IF
Hotkey, IF, Hotkey_Hook("M")
Loop, Parse, nmMouse, |
Hotkey, % A_LoopField, Hotkey_View
Hotkey, IF, Hotkey_Hook("K")
Loop, Parse, nmMods, |
{
Hotkey, % A_LoopField, Hotkey_Mods
Hotkey, % A_LoopField " Up", Hotkey_ModsUp
}
Loop, Parse, scSymb, |
Hotkey, % "sc" A_LoopField, Hotkey_ViewSC
Loop, Parse, scOther, |
Hotkey, % GetKeyName("sc" A_LoopField), Hotkey_View
Loop, Parse, vkNum, |
Hotkey, % "vk" A_LoopField, Hotkey_ViewNum
Loop, Parse, vkOther, |
Hotkey, % GetKeyName("vk" A_LoopField), Hotkey_View
Hotkey, IF, Hotkey_Hook("L") && Hotkey_HasKeyboardModifier()
Hotkey, LButton, Hotkey_View
Hotkey, IF, Hotkey_Hook("R") && Hotkey_HasKeyboardModifier()
Hotkey, RButton, Hotkey_View
S_FormatInteger := A_FormatInteger
SetFormat, IntegerFast, D
Hotkey, IF, Hotkey_Hook("J") && !Hotkey_Main("GetMod")
Loop, 128
Hotkey % Ceil(A_Index / 32) "Joy" Mod(A_Index - 1, 32) + 1, Hotkey_View
SetFormat, IntegerFast, %S_FormatInteger%
Hotkey, IF, Hotkey_IsRegControl()
Hotkey, RButton, Hotkey_RButton
Hotkey, RButton Up, Hotkey_Return
Hotkey, IF, Hotkey_Arr("Hook") && !Hotkey_Hook("K")
Hotkey, AppsKey Up, Hotkey_Return
Hotkey, +F10, Hotkey_Return
Hotkey, IF
SetBatchLines, %S_BatchLines%
return
Hotkey_RButton:
Click
Hotkey_Return:
return
}
Hotkey_IsRegControl() {
MouseGetPos,,,, Control, 2
return Hotkey_ID(Control) != ""
}
Hotkey_IsMouseInput(Key) {
static MouseInputs := "|LButton|RButton|MButton|WheelDown|WheelUp|WheelRight|WheelLeft|XButton1|XButton2|"
return InStr(MouseInputs, "|" Key "|")
}
Hotkey_HasKeyboardModifier() {
return GetKeyState("Ctrl", "P") || GetKeyState("Shift", "P")
|| GetKeyState("Alt", "P") || GetKeyState("LWin", "P")
|| GetKeyState("RWin", "P")
}
Hotkey_SyncPhysicalModifiers(K) {
static Modifiers := { LCtrl: "<^", RCtrl: ">^", LAlt: "<!", RAlt: ">!"
, LShift: "<+", RShift: ">+", LWin: "<#", RWin: ">#" }
for Name, Prefix in Modifiers {
IsDown := GetKeyState(Name, "P")
K["M" Name] := IsDown ? Name "+" : ""
K["P" Name] := IsDown ? Prefix : ""
}
K.MCtrl := K.MAlt := K.MShift := K.MWin := ""
K.PCtrl := K.PAlt := K.PShift := K.PWin := ""
}
Hotkey_IsRegFocus() {
ControlGetFocus, ControlNN, A
ControlGet, hFocus, Hwnd, , %ControlNN%, A
Hotkey_ID(hFocus) != "" ? Hotkey_Main("Control", hFocus) : 0
}
Hotkey_EventFocus(hWinEventHook, event, hwnd) {
Hotkey_ID(hwnd) != "" ? Hotkey_Main("Control", hwnd) : Hotkey_Main("Control")
}
Hotkey_SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags) {
return DllCall("SetWinEventHook" , "UInt", eventMin, "UInt", eventMax, "Ptr", hmodWinEventProc
, "Ptr", lpfnWinEventProc, "UInt", idProcess, "UInt", idThread, "UInt", dwFlags, "Ptr")
}
; -------------------------------------- Save and get --------------------------------------
Hotkey_Arr(P*) {
static Arr := {"Empty":"Нет"}
return P.MaxIndex() = 1 ? Arr[P[1]] : (Arr[P[1]] := P[2])
}
Hotkey_ID(P*) {
static Arr := {}
return P.MaxIndex() = 1 ? Arr[P[1]] : P.MaxIndex() = 2 ? (Arr[P[1]] := P[2]) : Arr.Delete(P[1])
}
Hotkey_Value(P*) {
static Arr := {}
return P.MaxIndex() = 1 ? Arr[P[1]] : P.MaxIndex() = 2 ? (Arr[P[1]] := P[2]) : Arr.Delete(P[1])
}
Hotkey_Options(P*) {
static Arr := {}
return P.MaxIndex() = 1 ? Arr[P[1]] : P.MaxIndex() = 2 ? (Arr[P[1]] := P[2]) : Arr.Delete(P[1])
}
Hotkey_ChangeOption(ID, Option) {
(ID + 0 = "") ? (Hwnd := Hotkey_ID(ID), Name := ID) : (Hwnd := ID, Name := Hotkey_ID(ID))
if RegExMatch(Hotkey_Options(Hwnd), "i)G(\d+)", g)
Hotkey_Group("Delete", Name)
if RegExMatch(Option, "i)G(\d+)", g)
Hotkey_Group("Set", Name, g1)
return Hotkey_Options(Hwnd, Option)
}
Hotkey_Hook(Option) {
return Hotkey_Arr("Hook") && !!InStr(Hotkey_Arr("Hook"), Option)
}
Hotkey_Delete(ID, Destroy = 0) {
(ID + 0 = "") ? (Hwnd := Hotkey_ID(ID), Name := ID) : (Hwnd := ID, Name := Hotkey_ID(ID))
Hotkey_Group("Delete", Name)
Hotkey_ID(Hwnd, "", 1), Hotkey_ID(Name, "", 1)
Hotkey_Value(Hwnd, "", 1), Hotkey_Value(Name, "", 1)
Hotkey_Options(Hwnd, "", 1)
ControlGetFocus, ControlNN, A
ControlGet, hFocus, Hwnd, , %ControlNN%, A
(hFocus = Hwnd ? Hotkey_Main("Control") : 0)
if Destroy
DllCall("DestroyWindow", "Ptr", Hwnd)
else
PostMessage, 0x00CF, 0, , , % "ahk_id" Hwnd ; EM_SETREADONLY
return Hwnd
}
Hotkey_Set(Name, Value = "") {
Text := Hotkey_HKToStr(Value)
SendMessage, 0xC, 0, &Text, , % "ahk_id" Hotkey_ID(Name)
return Text, Hotkey_Value(Name, Value), Hotkey_Value(Hotkey_ID(Name), Value)
}
Hotkey_Read(Name, Section = "", FilePath = "") {
HK := Hotkey_IniRead(Name, Section, FilePath), Hotkey_Value(Name, HK)
return Hotkey_HKToStr(HK)
}
Hotkey_IniPath(Path = "") {
return Path = "" ? Hotkey_Arr("IniPath") : Hotkey_Arr("IniPath", Path)
}
Hotkey_IniSection(Section = "") {
return Section = "" ? Hotkey_Arr("IniSection") : Hotkey_Arr("IniSection", Section)
}
Hotkey_IniRead(Name, Section = "", FilePath = "") {
IniRead, Data, % FilePath = "" ? Hotkey_IniPath() : FilePath, % Section = "" ? Hotkey_IniSection() : Section, % Name, % A_Space
return Data
}
Hotkey_IniWrite(ID, Section = "", FilePath = "") {
Key := (ID + 0 = "") ? ID : Hotkey_ID(ID)
if (Key != "")
IniWrite, % Hotkey_Value(ID), % FilePath = "" ? Hotkey_IniPath() : FilePath, % Section = "" ? Hotkey_IniSection() : Section, % Key
}
; -------------------------------------- Group --------------------------------------
Hotkey_Group(Key = "", p1 = "", p2 = "") {
static NG := {}, GN := [], Blink := [], SaveCheck := [], i := 0
if (Key = "") {
for k, Name in SaveCheck {
if ((Value := Hotkey_Value(Name)) != "") {
(f := Hotkey_Arr("GroupEvents")) != "" && (r := {}, r.names := [])
for m, n in GN[NG[Name]] {
if (n != Name && Hotkey_Equal(Value, Hotkey_Value(n))) {
Hotkey_Set(Name)
(f != "") && (r.names.Push(n), r.this := Name, r.value := Value, r.group := NG[Name])
if !DllCall("IsWindowVisible", "Ptr", Hotkey_ID(n))
continue
DllCall("ShowWindowAsync", "Ptr", Hotkey_ID(n), "Int", 0)
Blink[Hotkey_ID(n)] := 1, i := 3
SetTimer, Hotkey_BlinkControl, -50
}
}
}
SaveCheck.Delete(k)
}
(f != "") && (r.this != "") && %f%(r)
}
else if (Key = "Set")
NG[p1] := p2, IsObject(GN[p2]) ? GN[p2].Push(p1) : GN[p2] := [p1]
else if (Key = "SaveCheck")
return 1, SaveCheck[p1] := Hotkey_ID(p1)
else if (Key = "Get")
return NG[p1] != ""
else if (Key = "CheckAll") {
for k, v in GN {
for k, n in v {
if ((Value := Hotkey_Value(n)) != "") {
for k, m in v {
if (n != m && Hotkey_Equal(Value, Hotkey_Value(m)))
Hotkey_Set(m)
}
}
}
}
}
else if (Key = "Delete") {
for k, v in GN[NG[p1]] {
if (v = p1) {
GN[NG[p1]].RemoveAt(k)
break
}
}
NG.Delete(p1)
}
return
Hotkey_BlinkControl:
for k in Blink
DllCall("ShowWindowAsync", "Ptr", k, "Int", Mod(i, 2) ? 4 : 0)
if (--i > 0) || !(Blink := [])
SetTimer, Hotkey_BlinkControl, -50
return
}
Hotkey_Equal(HK1, HK2) {
if (HK2 = "")
return 0
if (HK1 = HK2)
return 1
if !(HK1 ~= "S)[\^\+!#]") || !(HK2 ~= "S)[\^\+!#]")
return 0
if (HK1 ~= "S)[<>]") && (HK2 ~= "S)[<>]")
return 0
return (Hotkey_ModsSub(HK1) = Hotkey_ModsSub(HK2))
}
Hotkey_ModsSub(Value) {
if !(Value ~= "[<>]")
return Value
Value := StrReplace(Value, "<")
Value := StrReplace(Value, ">")
Value := StrReplace(Value, "^^", "^", , 1)
Value := StrReplace(Value, "!!", "!", , 1)
Value := StrReplace(Value, "++", "+", , 1)
return StrReplace(Value, "##", "#", , 1)
}
; -------------------------------------- Format --------------------------------------
; http://forum.script-coding.com/viewtopic.php?pid=105023#p105023
Hotkey_HKToStr(HK) {
static LRPrefix := [["<^","LCtrl"],[">^","RCtrl"],["<!","LAlt"],[">!","RAlt"]
,["<+","LShift"],[">+","RShift"],["<#","LWin"],[">#","RWin"]]
, Prefix := [["^","Ctrl"],["!","Alt"],["+","Shift"],["#","Win"]]
, EngSym := {"sc2":"1","sc3":"2","sc4":"3","sc5":"4","sc6":"5","sc7":"6"
,"sc8":"7","sc9":"8","scA":"9","scB":"0","scC":"-","scD":"="
,"sc10":"Q","sc11":"W","sc12":"E","sc13":"R","sc14":"T","sc15":"Y"
,"sc16":"U","sc17":"I","sc18":"O","sc19":"P","sc1A":"[","sc1B":"]"
,"sc1E":"A","sc1F":"S","sc20":"D","sc21":"F","sc22":"G","sc23":"H"
,"sc24":"J","sc25":"K","sc26":"L","sc27":"`;","sc28":"'","sc29":"``"
,"sc2B":"\","sc2C":"Z","sc2D":"X","sc2E":"C","sc2F":"V","sc30":"B"
,"sc31":"N","sc32":"M","sc33":",","sc34":".","sc35":"/"
,"vk31":"1","vk32":"2","vk33":"3","vk34":"4","vk35":"5","vk36":"6"
,"vk37":"7","vk38":"8","vk39":"9","vk30":"0","vkBD":"-","vkBB":"="
,"vk51":"Q","vk57":"W","vk45":"E","vk52":"R","vk54":"T","vk59":"Y"
,"vk55":"U","vk49":"I","vk4F":"O","vk50":"P","vkDB":"[","vkDD":"]"
,"vk41":"A","vk53":"S","vk44":"D","vk46":"F","vk47":"G","vk48":"H"
,"vk4A":"J","vk4B":"K","vk4C":"L","vkBA":"`;","vkDE":"'","vkC0":"``"
,"vkDC":"\","vk5A":"Z","vk58":"X","vk43":"C","vk56":"V","vk42":"B"
,"vk4E":"N","vk4D":"M","vkBC":",","vkBE":".","vkBF":"/"}
RegExMatch(HK, "S)^\s*([~\*\$\^\+!#<>]*)\{?(.*?)}?\s*$", K)
if (K2 = "")
return "" Hotkey_Arr("Empty")
if (InStr("|" K2, "|sc") || InStr("|" K2, "|vk"))
K2 := Hotkey_Arr("OnlyEngSym") && EngSym.HasKey(K2) ? EngSym[K2] : GetKeyName(K2)
if (K1 != "")
for I, V in K1 ~= "[<>]" ? LRPrefix : Prefix
K1 := StrReplace(K1, V[1], "", R), R && (M .= V[2] "+")
return M . (StrLen(K2) = 1 ? Format("{:U}", K2) : K2)
}
Hotkey_HKToSend(HK, Section = "", FilePath = "") {
static LRPrefix := [["<^","LCtrl"],[">^","RCtrl"],["<!","LAlt"],[">!","RAlt"]
,["<+","LShift"],[">+","RShift"],["<#","LWin"],[">#","RWin"]]
, Prefix := [["^","LCtrl"],["!","LAlt"],["+","LShift"],["#","LWin"]]
if (HK = "")
return
if (Section != "")
IniRead, HK, % FilePath = "" ? Hotkey_IniPath() : FilePath, % Section, % HK, % A_Space
RegExMatch(HK, "S)^\s*([~\*\$\^\+!#<>]*)\{?(.*?)}?\s*$", K)
if (K1 != "") {
for I, V in K1 ~= "[<>]" ? LRPrefix : Prefix {
K1 := StrReplace(K1, V[1], "", R)
, R ? (M1 .= "{" V[2] " Down}", M2 .= "{" V[2] " Up}") : 0
}
}
return M1 . "{" K2 "}" . M2
}
#if WinExist("ScreenShot ahk_class AutoHotkeyGUI")
#if
#if IsOverlaySelectionState("armed")
LButton:: BeginOverlaySelectionDrag()
RButton:: CancelOverlaySelection()
Esc:: CancelOverlaySelection()
#if
#if IsOverlaySelectionState("dragging")
*LButton Up:: FinishOverlaySelection()
RButton:: CancelOverlaySelection()
Esc:: CancelOverlaySelection()
#if
#if IsSelectionWindowActive()
^WheelUp:: NudgeSelectionEdge("Left" , -1)
^WheelDown:: NudgeSelectionEdge("Left" , 1)
+WheelUp:: NudgeSelectionEdge("Top" , -1)
+WheelDown:: NudgeSelectionEdge("Top" , 1)
!WheelUp:: NudgeSelectionEdge("Right" , 1)
!WheelDown:: NudgeSelectionEdge("Right" , -1)
#WheelUp:: NudgeSelectionEdge("Bottom", -1)
#WheelDown:: NudgeSelectionEdge("Bottom", 1)
#if
#if WinActive("ScreenShot ahk_class AutoHotkeyGUI")
Esc:: PostMessage, Esc,,,, A
*WheelDown::
*WheelUp:: PostMessage, Wheel, A_ThisHotkey = "*WheelUp" ? 0 : 1,,, A
#if
Сохраните скрипт в кодировке UTF-8 с BOM, (иначе получите кракозябры вместо кириллицы).
Если кто-нибудь захочет задать вопрос по работе скрипта или сообщить о замеченных багах — прошу писать в эту тему.

