Перечитываю братьев Фроловых "Библиотека системного программиста", книга 11 "Операционная система Microsoft Windows 3.1 для программиста", глава 6 "Мышь" Полный список сообщений, поступающих от мышиСообщениеhexОписаниеWM_MOUSEACTIVATE21Нажата клавиша мыши над неактивным окномWM_NCHITTEST84Перемещение мыши в любом месте экранаWM_NCMOUSEMOVEA0Перемещение курсора мыши во внешней области окнаWM_NCLBUTTONDOWNA1Нажата левая клавиша мыши во внешней области окнаWM_NCLBUTTONUPA2Отпущена левая клавиша мыши во внешней области окнаWM_NCLBUTTONDBLCLKA3Двойной щелчок левой клавишей мыши во внешней (non-client) области окнаWM_NCRBUTTONDOWNA4Нажата правая клавиша мыши во внешней области окнаWM_NCRBUTTONUPA5Отпущена правая клавиша мыши во внешней области окнаWM_NCRBUTTONDBLCLKA6Двойной щелчок правой клавишей мыши во внешней области окнаWM_NCMBUTTONDOWNA7Нажата средняя клавиша мыши во внешней области окнаWM_NCMBUTTONUPA8Отпущена средняя клавиша мыши во внешней области окнаWM_NCMBUTTONDBLCLKA9Двойной щелчок средней клавишей мыши во внешней области окнаWM_NCXBUTTONDOWNABWM_NCXBUTTONUPACWM_NCXBUTTONDBLCLKADWM_MOUSEMOVE WM_MOUSEFIRST200Перемещение курсора мыши во внутренней области окнаWM_LBUTTONDOWN201Нажата левая клавиша мыши во внутренней области окнаWM_LBUTTONUP202Отпущена левая клавиша мыши во внутренней области окнаWM_LBUTTONDBLCLK203Двойной щелчок левой клавишей мыши во внутренней (client) области окнаWM_RBUTTONDOWN204Нажата правая клавиша мыши во внутренней области окнаWM_RBUTTONUP205Отпущена правая клавиша мыши во внутренней области окнаWM_RBUTTONDBLCLK206Двойной щелчок правой клавишей мыши во внутренней области окнаWM_MBUTTONDOWN207Нажата средняя клавиша мыши во внутренней области окнаWM_MBUTTOMUP208Отпущена средняя клавиша мыши во внутренней области окнаWM_MBUTTONDBLCLK WM_MOUSELAST209Двойной щелчок средней клавишей мыши во внутренней области окнаWM_MOUSEWHEEL20AWM_XBUTTONDOWN20BWM_XBUTTONUP20CWM_XBUTTONDBLCLK20DWM_NCMOUSEHOVER2A0WM_MOUSEHOVER2A1WM_NCMOUSELEAVE2A2WM_MOUSELEAVE2A3Из приведенных 22 сообщений ― 21 сообщение образуется из сообщения WM_NCHITTEST. Это сообщение генерируется драйвером мыши при любых перемещениях мыши. Сообщение WM_NCHITTEST не использует параметр wParam. (Выделенное красным это цитата Фроловых, далее пытаюсь проверить так ли это экспериментальным путем). В младшем слове параметра lParam передается X координата курсора мыши, в старшем ― Y координата. Координаты вычисляются относительно верхнего левого угла экрана. Объединяем клиентские и неклиентские сообщения binСообщениеClient Area=2 /non-client=0Client Area=0 /non-client=0xA0010/00000000/10100000MOUSEMOVE0010/00000000/10100001LBUTTONDOWN0010/00000000/10100010LBUTTONUP0010/00000000/10100011LBUTTONDBLCLK0010/00000000/10100100RBUTTONDOWN0010/00000000/10100101RBUTTONUP0010/00000000/10100110RBUTTONDBLCLK0010/00000000/10100111MBUTTONDOWN0010/00000000/10101000MBUTTOMUP0010/00000000/10101001MBUTTONDBLCLK0010/00000000/00001010MOUSEWHEEL0010/00000000/10101011XBUTTONDOWN0010/00000000/10101100XBUTTONUP0010/00000000/10101101XBUTTONDBLCLK0010/000010100000/ 0001MOUSEHOVER0010/000010100010/ 0011MOUSELEAVEСообщение WM_NCHITTEST передается функции DefWindowProc. Функция DefWindowProc определяет положение курсора мыши относительно расположенных на экране объектов и возвращает одно из значений (раздел dec ― Фроловы, раздел hex ― то что подтверждает эксперимент) ЗначениеdechexРасположение курсора мышиHTERROR-2Над поверхностью экрана или на линии, разделяющей различные окна. Дополнительно функция DefWindowProc выдает звуковой сигналHTTRANSPARENT-1В окне, которое перекрыто другим окномHTNOWHERE0Над поверхностью экрана или на линии, разделяющей различные окнаHTCLIENT11Во внутренней области окна (client area)HTCAPTION2На заголовке окна (title-bar)HTSYSMENU3В области системного менюHTGROWBOX, HTSIZE4В области изменения размера окна (size box)HTMENU5В области менюHTHSCROLL6На горизонтальной полосе просмотраHTVSCROLL7На вертикальной полосе просмотраHTMINBUTTON, HTREDUCE8На кнопке минимизацииHTMAXBUTTON, HTZOOM9На кнопке максимизацииHTLEFT, HTSIZEFIRST10AЗа левой вертикальной линией рамки окнаHTRIGHT11BЗа правой вертикальной линией рамки окнаHTTOP12CЗа верхней горизонтальной линией рамки окнаHTTOPLEFT13В верхнем левом углу рамки окнаHTTOPRIGHT14В правом верхнем углу рамки окнаHTBOTTOM15FЗа нижней горизонтальной линией рамки окнаHTBOTTOMLEFT1610За левым нижним углом рамкиHTBOTTOMRIGHT, HTSIZELAST1711За правым нижним углом рамкиHTBORDER18На рамке окна, которое создано без толстой рамки, предназначенной для изменения размера окнаHTOBJECT19HTCLOSE20На кнопке ×HTHELP21На кнопке HelpКак генерируется WM_MOUSEMOVE понятно. DefWindowProc возвращает HTCLIENT, в lParam координаты курсора. Вопрос в том, КАК генерируются L/M/X/RBUTTONDOWN/UP/DBLCLK? По каким признакам DefWindowProc определяет ЧТО в клиентской области щелкали клавишами мыши? Ведь WM_NCHITTEST не использует wParam. При приходе WM_NCHITTEST wParam=0. А ведь при других сообщениях в параметре wParam содержится значение, с помощью которого можно определить, какие клавиши на мыши и клавиатуре были нажаты в тот момент, когда произошло событие, связанное с сообщением. Параметр wParam состоит из отдельных битовых флагов. ЗначениеhexbinОписаниеX2X1MCtrlShiftRightLeftMK_LBUTTON10000001Нажата левая клавиша мышиMK_RBUTTON20000010Нажата правая клавиша мышиMK_SHIFT40000100На клавиатуре нажат ShiftMK_CONTROL80001000На клавиатуре нажат CtrlMK_MBUTTON100010000Нажата средняя клавиша мышиMK_XBUTTON1200100000Нажата клавиша XBUTTON1MK_XBUTTON2401000000Нажата клавиша XBUTTON2
А разве WM_LBUTTONDOWN/WM_RBUTTONDOWN/ WM_RBUTTONDOWN происходят из WM_NCHITTEST? Для происхождения этих сообщений есть соответствующие non client сообщения. WM_NCLBUTTONDOWN/WM_NCRBUTTONDOWN/ WM_NCRBUTTONDOWN Т.е. WM_NCHITTEST только подсказывает куда перенаправить сообщение. А само сообщение уже идет следом и превращается либо в WM_LBUTTONDOWN либо остается WM_NCLBUTTONDOWN.
MaKsIm, я цитирую Фроловых А Фроловы вытащили/перевели эту фразу из недр документации о Windows. Часть сообщений я могу сымитировать используя WM_NCHITTEST и реакцию DefWindowProc. Часть не понимаю как, к ним относятся реакции на L/R/M/XBUTTONDOWN/UP/DBLCLK Хотелось бы узнать о предположениях форумчан...
Вот хотелось бы видеть эти недра доки Windows. Тут разве что информация дополняется из глобальных системных переменных из сегмента fs после получения информации от WM_NCHITTEST. Иначе информации привязанной к непосредственному состоянию системы в конкретный момент времени взяться неоткуда. Я же полагаю, что сообщение L/R/M/XBUTTONDOWN/UP/DBLCLK уже есть, но по родительскому handle (desktop), которое порождает WM_NCHITTEST для окна текущего приложения и после превращается в одно из событий.
MaKsIm, очень возможно, что вы правы. Я написал крохотную программу. Сообщение WM_NCHITTEST появляется при движении мыши и предваряет появление WM_MOUSEMOVE. Щелчки к появлению WM_NCHITTEST перед сообщениями L/R/M/XBUTTONDOWN/UP/DBLCLK не приводят.
Ну пока все сходится. Сначала, при движении мыши, DWM опрашивает окна на предмет попадания в их области. После же при событии клика просто использует последнее полученное значение из WM_NCHITTEST для перенаправления события клика. --- Сообщение объединено, 26 окт 2025 --- Вообще совершить одновременно передвижение курсора мыши и клик для человека попросту невозможно. Но, предположу, что ответ кешируется вместе с координатами из MOUSEMOVE и попросту подавляется повторное сообщение NCHITTEST. Для мыши это подавляет лишний опрос окна, а вот для тачскрина приходится слать NCHITTEST перед каждым событием.
MaKsIm > информация дополняется из глобальных системных переменных из сегмента fs Это врядле. Там только механизм пакетной обработки есть, ничего туда кернел не пишет(лишь несколько переменных к гую не относящихся). Это проверено визорами(гуи апп на каждой итерации секвенации(на каждой инструкции и выборке в память, после сисколов втч) сравнивает дамп сегмента). Там можно найти двойной линк на известные таблицы apfndispatch. Но это вроде в другом билде можно смотреть, оптимизация - любой шадов сервисный вызов рисует текст, окна и тп. Что бы ядро лишний раз не дергать.
Ahimov, если братья Фроловы правы и Из приведенных 22 сообщений ― 21 сообщение образуется из сообщения WM_NCHITTEST, то как выдернуть сообщения типа WM_NCLBUTTON/WM_LBUTTON из WM_NCHITTEST и DefWindowProc? Хотя бы намекните как?
Такой четкий вопрос, респект, Текли сурки не только эти. Где это на гх с мобилы искать я не знаю. Поднимите тему по утекшим когда то исходам, думаю вам помогут. Физически два харда заныканы за 200км, даже если я туда поеду, меня с этим возьмут будет беда. В какой сборке были lsass msgina etc я не знаю, но это было давно очень и паблик. Я это пишу с телефона что бы вы понимали. --- Сообщение объединено, 1 ноя 2025 --- Откуда эти сообщения берутся можно глянуть и юзер отладчиком, не нужен ядерный. Окна э́то юзер, зачем знать как это реализовано в кернел, если вы не ищите уязвимости, те анализ работы этого механизма. --- Сообщение объединено, 1 ноя 2025 --- Пролистал сурки, есть только case WM_NCHITTEST. Загрузку константы я не нашел, мб это: Код (Text): if (HTCLIENT == (int)SendMessage(_hwnd, WM_NCHITTEST, 0, lParam)) { - это уже не системная обработка, те это не ядро/тень/user/gui а сторонние либы или апп.
Чарльз Петцольд «Программирование для Windows 95» в двух томах. Том I. Глава 6. Мышь Сообщение теста попаданияЕсли вы вели подсчет, то знаете, что мы рассмотрели 20 из 21 сообщения мыши. Последним сообщением является WM_NCHITTEST, означающее "тест попадания в нерабочую область" (nonclient hit-test). Это сообщение предшествует всем остальным сообщениям мыши рабочей и нерабочей области. Параметр lParam содержит значения х и у экранных координат положения мыши. Параметр wParam не используется. В приложениях для Windows это сообщение обычно передается в DefWindowProc. В этом случае Windows использует сообщение WM_NCHITTEST для выработки всех остальных сообщений мыши на основе положения мыши. Для сообщений мыши нерабочей области возвращаемое значение функции DefWindowProc при обработке сообщения WM_NCHITTEST передается как параметр wParam в сообщении мыши. Это значение может быть любым из множества значений wParam, которое бывает у этого параметра для сообщений мыши нерабочей области, плюс следующие: HTCLIENTРабочая областьHTNOWHEREНет ни на одном из оконHTTRANSPARENTОкно перекрыто другим окномHTERRORЗаставляет DefWindowProc генерировать гудокЕсли функция DefWindowProc после обработки сообщения WM_NCHITTEST возвращает значение HTCLIENT, то Windows преобразует экранные координаты в координаты рабочей области вырабатывает сообщение мыши рабочей области. Если вы вспомните, как мы запретили все системные функции клавиатуры при обработке сообщения WM_SYSKEYDOWN, то вы, наверное, удивитесь, если сможете сделать что-нибудь подобное, используя сообщения мыши. Действительно, если вы вставите строки: Код (C): case WM_NCHITTEST: return(LRESULT) HTNOWHERE; в вашу оконную процедуру, то вы полностью запретите все сообщения мыши рабочей и нерабочей области вашего окна. Кнопки мыши просто не будут работать до тех пор, пока мышь будет находится где-либо внутри вашего окна, включая значок системного меню, кнопки минимизации, максимизации и закрытия окна. Сообщения порождают сообщенияWindows использует сообщение WM_NCHITTEST для выработки всех остальных сообщений мыши. Идея сообщений, порождающих другие сообщения, характерна для Windows. Давайте рассмотрим пример. Если вы дважды щелкните мышью на значке системного меню Windows-программы, то программа завершится. Двойной щелчок генерирует серию сообщений WM_NCHITTEST. Поскольку мышь установлена над значком системного меню, то возвращаемым значением функции DefWindowProc является HTSYSMENU, и Windows ставит в очередь сообщение WM_NCLBUTTONDBLCLK с параметром wParam, равным HTSYSMENU. Оконная процедура обычно передает это сообщение DefWindowProc. Когда функция DefWindowProc получает сообщение WM_NCLBUTTONDBLCLK с параметром wParam, равным HTSYSMENU, то она ставит в очередь сообщение WM_SYSCOMMAND с параметром wParam, равным SC_CLOSE. (Это сообщение WM_SYSCOMMAND также генерируется, когда пользователь выбирает в системном меню пункт Close.) Оконная процедура вновь передает это сообщение в DefWindowProc. DefWindowProc обрабатывает сообщение, отправляя оконной процедуре синхронное сообщение WM_CLOSE.
Пример. Оконная процедура: Код (Text): WM_LBUTTONDOWN: GetWindowRect() if !PtInRect() SendMessage( WM_NCLBUTTONDOWN) xxxButtonEvent(RIT) rit это поток сырого ввода. Вот как возникают мышиные сообщения: Код (C): switch (ButtonNumber) { case MOUSE_BUTTON_RIGHT: if (fBreak) { message = WM_RBUTTONUP; } else { if (ISTS() && fDblClk) message = WM_RBUTTONDBLCLK; else message = WM_RBUTTONDOWN; } break; Из SendInput() или непосредственно от RawInputThread. Так что wm_ncX noclient msg приложение шлет само себе.