Обработка колесика мыши над иконкой в трее
"По следам наших публикаций", как любили писать в советской прессе. В предыдущей статье я обещал рассказать, каким образом можно реализовать обработку вращения колесика мыши над иконкой в системном трее. Поскольку система не отправляет иконкам в трее сообщение WM_MOUSEWHEEL, обрабатывать его мы будем при помощи хуков и описанных в предыдущей статье методов определения, что курсор находится над нужной иконкой. Начнем с локального хука. Установка и снятие хука выполняется самым обычным способом, например:Code (Assembler) : Убрать нумерацию
- proc DialogProc hwnddlg,msg,wparam,lparam
- push ebx esi edi
- cmp [msg],WM_INITDIALOG
- je .wminitdialog
- cmp [msg],WM_CLOSE
- je .wmclose
- ...
- ...
- xor eax,eax
- jmp .finish
- .wminitdialog:
- ...
- ...
- ; Показать иконку в трее
- invoke Shell_NotifyIcon, NIM_ADD,node
- ; Установить обработчик мыши
- invoke GetCurrentThreadId
- invoke SetWindowsHookEx,WH_MOUSE,MousewheelProc,NULL,eax
- mov [hhkm],eax
- mov eax,[hwnddlg]
- mov [hwmain],eax
- jmp .processed
- ...
- ...
- .wmclose:
- ; Снять обработчик мыши
- invoke UnhookWindowsHookEx,[hhkm]
- ; Удалить иконку из трея
- invoke Shell_NotifyIcon,NIM_DELETE,node
- ; Закрыть окно
- invoke EndDialog,[hwnddlg],0
- .processed:
- mov eax,1
- .finish:
- pop edi esi ebx
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ; Структура для обработчика хука
- struct MOUSEHOOKSTRUCTEX
- pt POINT
- hwnd dd ?
- wHitTestCode dd ?
- dwExtraInfo dd ?
- mouseData dd ?
- ends
- ;-------------------------------------------------------------
- ; Обработка mousewheel
- ;-------------------------------------------------------------
- proc MousewheelProc nCode:dword,wParam:dword,lParam:dword
- pusha
- cmp [nCode],0
- jl .loc_ret
- ; Это сообщение от колеса мыши?
- cmp [wParam],WM_MOUSEWHEEL
- jne .loc_ret
- ; Заполнить структуру для идентификации иконки
- mov [notify.cbSize],sizeof.NOTIFYICONIDENTIFIER
- mov eax,[hwmain]
- mov [notify.hWnd],eax
- mov [notify.uID],ICON_ID
- ; Получить координаты иконки в трее
- invoke Shell_NotifyIconGetRect,notify,rc
- ; Указатель на MOUSEHOOKSTRUCT
- mov ebx,[lParam]
- ; Курсор находится внутри прямоугольника иконки?
- invoke PtInRect,rc,[ebx+MOUSEHOOKSTRUCTEX.pt.x],\
- [ebx+MOUSEHOOKSTRUCTEX.pt.y]
- or eax,eax
- ; Нет, ничего не делать
- jz .loc_ret
- ; Проверить направление поворота колесика
- mov eax,[ebx+MOUSEHOOKSTRUCTEX.mouseData]
- or eax,eax
- js .loc_down
- .loc_up:
- ; Вращение вверх
- ...
- ...
- jmp .loc_ret
- .loc_down:
- ; Вращение вниз
- ...
- ...
- .loc_ret:
- popa
- invoke CallNextHookEx,[hhkm],[nCode],[wParam],[lParam]
- ret
- endp
Для более правильной реализации обработки колесика мыши воспользуемся глобальным хуком на низкоуровневые события мыши, то есть WH_MOUSE_LL. Небольшие отличия будут только в установке обработчика и в структуре, приходящей в обработчик хука.
Code (Assembler) : Убрать нумерацию
- proc DialogProc hwnddlg,msg,wparam,lparam
- push ebx esi edi
- cmp [msg],WM_INITDIALOG
- je .wminitdialog
- cmp [msg],WM_CLOSE
- je .wmclose
- ...
- ...
- xor eax,eax
- jmp .finish
- .wminitdialog:
- ...
- ...
- ; Показать иконку в трее
- invoke Shell_NotifyIcon, NIM_ADD,node
- ; Установить обработчик низкоуровневых событий мыши
- invoke SetWindowsHookEx,WH_MOUSE_LL,MousewheelProc,NULL,NULL
- mov [hhkm],eax
- mov eax,[hwnddlg]
- mov [hwmain],eax
- jmp .processed
- ...
- ...
- .wmclose:
- ; Снять обработчик мыши
- invoke UnhookWindowsHookEx,[hhkm]
- ; Удалить иконку из трея
- invoke Shell_NotifyIcon,NIM_DELETE,node
- ; Закрыть окно
- invoke EndDialog,[hwnddlg],0
- .processed:
- mov eax,1
- .finish:
- pop edi esi ebx
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ; Структура для обработчика хука
- struct MSLLHOOKSTRUCT
- pt POINT
- mouseData dd ?
- flags dd ?
- time dd ?
- dwExtraInfo dd ?
- ends
- ;-------------------------------------------------------------
- ; Обработка mousewheel
- ;-------------------------------------------------------------
- proc MousewheelProc nCode:dword,wParam:dword,lParam:dword
- pusha
- cmp [nCode],0
- jl .loc_ret
- ; Это сообщение от колеса мыши?
- cmp [wParam],WM_MOUSEWHEEL
- jne .loc_ret
- ; Заполнить структуру для идентификации иконки
- mov [notify.cbSize],sizeof.NOTIFYICONIDENTIFIER
- mov eax,[hwmain]
- mov [notify.hWnd],eax
- mov [notify.uID],ICON_ID
- ; Получить координаты иконки в трее
- invoke Shell_NotifyIconGetRect,notify,rc
- ; Указатель на MSLLHOOKSTRUCT
- mov ebx,[lParam]
- ; Курсор находится внутри прямоугольника иконки?
- invoke PtInRect,rc,[ebx+MSLLHOOKSTRUCT.pt.x],[ebx+MSLLHOOKSTRUCT.pt.y]
- or eax,eax
- ; Нет, ничего не делать
- jz .loc_ret
- ; Проверить направление поворота колесика
- mov eax,[ebx+MSLLHOOKSTRUCT.mouseData]
- or eax,eax
- js .loc_down
- .loc_up:
- ; Вращение вверх
- ...
- ...
- jmp .loc_ret
- .loc_down:
- ; Вращение вниз
- ...
- ...
- .loc_ret:
- popa
- invoke CallNextHookEx,[hhkm],[nCode],[wParam],[lParam]
- ret
- endp
Есть еще один вариант, как можно установить глобальный хук - вынести его в DLL. Информацию о вращении колесика обработчик будет отправлять главному окну приложения через пользовательские сообщения. Обработка колесика, соответственно, переносится из хука в основное приложение.
Code (Assembler) : Убрать нумерацию
- ; Пользовательское сообщение для главного окна
- WM_OUR_MOUSE = WM_USER + 702
- ;-------------------------------------------------------------
- ; Инициализация DLL
- ;-------------------------------------------------------------
- proc DllEntryPoint hinstDLL:dword,fdwReason:dword,lpvReserved:dword
- mov eax,[hinstDLL]
- mov [dll_base],eax
- mov eax,TRUE
- ret
- endp
- ;-------------------------------------------------------------
- ; Установка хука mousewheel
- ;-------------------------------------------------------------
- proc InitMousewheelHook parent_hwnd:DWORD
- pusha
- cmp [hhkm],0
- jne @f
- invoke SetWindowsHookEx,WH_MOUSE,MousewheelProc,[dll_base],NULL
- mov [hhkm],eax
- mov eax,[parent_hwnd]
- mov [hhwnd],eax
- @@:
- popa
- ret
- endp
- ;-------------------------------------------------------------
- ; Снятие хука mousewheel
- ;-------------------------------------------------------------
- proc KillMousewheelHook
- pusha
- cmp [hhkm],0
- je @f
- invoke UnhookWindowsHookEx,[hhkm]
- mov [hhkm],NULL
- @@:
- popa
- ret
- endp
- ;-------------------------------------------------------------
- ; Обработка mousewheel
- ;-------------------------------------------------------------
- proc MousewheelProc nCode:dword,wParam:dword,lParam:dword
- pusha
- cmp [nCode],0
- jl .loc_ret
- ; Это сообщение от колеса мыши?
- cmp [wParam],WM_MOUSEWHEEL
- jne .loc_ret
- ; Получить направление вращения колесика
- mov eax,[lParam]
- mov eax,[eax+20]
- ; Отправить сообщение главному окну программы
- invoke PostMessage,[hhwnd],WM_OUR_MOUSE,1,eax
- .loc_ret:
- popa
- invoke CallNextHookEx,[hhkm],[nCode],[wParam],[lParam]
- ret
- endp
Code (Assembler) : Убрать нумерацию
- proc DialogProc hwnddlg,msg,wparam,lparam
- push ebx esi edi
- cmp [msg],WM_INITDIALOG
- je .wminitdialog
- cmp [msg],WM_CLOSE
- je .wmclose
- ; Это пользовательское сообщение от DLL?
- cmp [msg],WM_OUR_MOUSE
- je .get_coord
- ...
- ...
- xor eax,eax
- jmp .finish
- .wminitdialog:
- ...
- ...
- ; Показать иконку в трее
- invoke Shell_NotifyIcon, NIM_ADD,node
- ; Установить глобальный обработчик мыши
- invoke InitMousewheelHook,[hwnddlg]
- jmp .processed
- ...
- ...
- .get_coord:
- ; Заполнить структуру для идентификации иконки
- mov [notify.cbSize],sizeof.NOTIFYICONIDENTIFIER
- mov eax,[hwnddlg]
- mov [notify.hWnd],eax
- mov [notify.uID],ICON_ID
- ; Получить координаты иконки в трее
- invoke Shell_NotifyIconGetRect,notify,rc
- ; Получить позицию курсора
- invoke GetCursorPos,pt
- ; Курсор находится внутри прямоугольника иконки?
- invoke PtInRect,rc,[pt.x],[pt.y]
- or eax,eax
- ; Нет, ничего не делать
- jz .processed
- ; Проверить направление поворота колесика
- mov eax,[lparam]
- or eax,eax
- js @f
- .loc_up:
- ; Вращение вверх
- ...
- ...
- jmp .processed
- .loc_down:
- ; Вращение вниз
- ...
- ...
- jmp .processed
- .wmclose:
- ; Снять глобальный обработчик мыши
- invoke KillMousewheelHook
- ; Удалить иконку из трея
- invoke Shell_NotifyIcon,NIM_DELETE,node
- ; Закрыть окно
- invoke EndDialog,[hwnddlg],0
- .processed:
- mov eax,1
- .finish:
- pop edi esi ebx
- ret
- endp
В приложении примеры программ с исходными текстами, которые обрабатывают вращение колесика мыши над иконкой в трее при помощи локального и глобального хуков.
Просмотров: 889 | Комментариев: 8
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Гость
(10.01.2023 в 21:26):
В реестре есть настройка SetWindowsHookEx ключом LowLevelHooksTimeout, возможно будет полезен.
ManHunter
(12.11.2021 в 18:18):
Немного причесал код для наглядности. Архив обновлен.
SMaSm-94
(12.11.2021 в 17:21):
ManHunter, упс. Ошибся - бывает. Извиняюсь)
ManHunter
(12.11.2021 в 17:12):
SMaSm-94, нет, там же приходит не просто сообщение с lparam, а целая структура, в которой координаты события обозначены через POINT:
https://docs.microsoft.com/ru-...sehookstruct
https://docs.microsoft.com/ru-...llhookstruct
У DRON все написано правильно.
https://docs.microsoft.com/ru-...sehookstruct
https://docs.microsoft.com/ru-...llhookstruct
У DRON все написано правильно.
SMaSm-94
(12.11.2021 в 17:08):
@DRON, тогда уж вот так вот (не проверял код на работоспособность):
... ; код обработки сообщения WM_MOUSEWHEEL
mov eax,[lParam]
movzx ecx,ax ; LOWORD - координата курсора по оси X (относительно левого верхнего угла экрана)
shr eax,16 ; HIWORD - координата курсора по оси Y (относительно левого верхнего угла экрана)
invoke PtInRect,rc,ecx,eax
...
... ; код обработки сообщения WM_MOUSEWHEEL
mov eax,[lParam]
movzx ecx,ax ; LOWORD - координата курсора по оси X (относительно левого верхнего угла экрана)
shr eax,16 ; HIWORD - координата курсора по оси Y (относительно левого верхнего угла экрана)
invoke PtInRect,rc,ecx,eax
...
DRON
(12.11.2021 в 16:46):
Просто я когда-то уже решал аналогичную задачу при написании плагина к фубару: https://foobar2000.ru/forum/vi...c.php?t=2177
Ни на что не влияет, но во всех хуках координаты приходят в параметрах, поэтому можно вместо GetCursorPos делать что-то вроде:
mov eax,[lParam]
invoke PtInRect,rc,[eax],[eax+4]
Ни на что не влияет, но во всех хуках координаты приходят в параметрах, поэтому можно вместо GetCursorPos делать что-то вроде:
mov eax,[lParam]
invoke PtInRect,rc,[eax],[eax+4]
ManHunter
(12.11.2021 в 15:55):
Добавил пример с WH_MOUSE_LL. Архив обновлен.
DRON, чувствую, пора бежать за пивом, поляну накрывать :)
DRON, чувствую, пора бежать за пивом, поляну накрывать :)
DRON
(12.11.2021 в 15:37):
Не надо никаких DLL-ок: WM_MOUSEHWHEEL прекрасно ловится из WH_MOUSE_LL хука.
Вообще, для данной конкретной задачи определять координаты иконки (это я про первую статью) не требуется: можно ловить обычный WM_MOUSEMOVE в обработчике иконки, сравнивать его с координатами из хука и если они не совпадают, то значит курсор вышел за пределы иконки.
Вообще, для данной конкретной задачи определять координаты иконки (это я про первую статью) не требуется: можно ловить обычный WM_MOUSEMOVE в обработчике иконки, сравнивать его с координатами из хука и если они не совпадают, то значит курсор вышел за пределы иконки.
Добавить комментарий
Заполните форму для добавления комментария