WM_MOUSEWHEEL, похоже, не всегда генерируется, что дает?

#c #windows #winapi #mouseevent #mouse-hook

Вопрос:

Во-первых, чего я хотел добиться: перехватывать (с помощью низкоуровневого крючка мыши) WM_MOUSEHWHEEL сообщения, чтобы возвращаться и перенаправляться в историю проводника файлов Windows или, по крайней мере, в родительское окно, если доступ к истории был невозможен.

С этого все и началось, не то чтобы я понятия не имел, возможно это или нет, особенно с тачпадом, но таково было мое намерение. Поэтому я начал смотреть на более обычную WM_MOUSEWHEEL (вертикальную прокрутку), только чтобы узнать, что эти сообщения генерируются не так часто!

В соответствии с документами MSDN на WM_MOUSEWHEEL :

Отправляется в окно фокусировки при вращении колесика мыши. Функция DefWindowProc распространяет сообщение на родительское окно окна. Внутренней пересылки сообщения быть не должно, так как DefWindowProc распространяет его по родительской цепочке до тех пор, пока не найдет окно, которое его обработает.

Хорошо, выглядит хорошо, поэтому при вращении колесика мыши это сообщение отправляется в окно, на котором находится фокус. Давайте посмотрим, так ли это с помощью Spy из пакета утилит Visual Studio, сделали его запись и загрузили на YouTube, встраивание, похоже, не разрешено в этом обмене стеками: https://youtu.be/YJvjw_BPJf0

Подводя итог, однако, WM_MOUSEWHEEL следует отметить, что для всех протестированных программ не создается никаких данных. Проводник был первым, на который я попытался взглянуть, сосредоточив внимание на различных подокнах окна и убедившись, что оно прокручивается.

Я мог видеть, как раздел полосы прокрутки получает некоторые связанные сообщения, но это все, нигде никаких признаков этого сообщения (тем не менее, VM_VSCROLL оно было отправлено в одно из окон полосы прокрутки).

Следующим был Notepad3, nada, он SysListView32 ничего не видит, и родительское окно получает некоторые уведомления, сообщения об активации и тому подобное, но ничего, связанного с прокруткой.

Все SysListView32 получили некоторые LVS_SCROLL сообщения, но они не подействовали на них (его цикл сообщений, вероятно, вместо этого ищет проклятые WM_MOUSEWHEEL буквы s).

Наконец, браузер, вообще ничего, «вид» вообще ничего не регистрировал, в то время как родительское окно захватило мышь по виду событий.

NOTE: For those of you who see the video, note that while Spy was on top it didn’t have focus during all tests, it was merely pinned so I could see the messages.


I almost gave up, starting from the default example Win32 application they give you in Visual Studio I added a hook procedure and if that message was received it’d print a message box, just in case it was the shell the one getting the messages somehow.

There was my surprise when I ran the code directly in VS that I see message boxes when I scroll through the code. WTF?!

Fire Spy again (also 64-bit because it was the 2022 Preview I was running) and let’s see, there they are!

https://youtu.be/ekrWKP7HiTE

Подокно редактора кода получает эти сообщения всякий раз, когда я прокручиваю трекпад по вертикали двумя пальцами. Итак, что же происходит?

Я имею в виду, что я даже попытался запустить этот образец кода с повышенным уровнем целостности и посмотреть, появятся ли при этом эти сообщения, но безрезультатно.

Код настолько прост, насколько это возможно, большая его часть была автоматически сгенерирована как образец приложения Win32, но крючок и процедура следующие:

 // The callback procedure:
LRESULT CALLBACK mouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
  if (nCode == 0) {
    if (wParam == WM_MOUSEWHEEL)
      MessageBox(NULL, L"We got it!", L"Yay!", MB_OK);
  }
  return CallNextHookEx(NULL, nCode, wParam, lParam);
}

...

// Setting the mouse hook (at the application's entry point):
HHOOK mouseHook = SetWindowsHookEx(WH_MOUSE_LL, mouseHookProc, hInstance, 0);
if (!mouseHook) {
  LPWSTR errorMessage = NULL;
  if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, (LPWSTR)amp;errorMessage, 0, NULL) == 0) {
    MessageBox(NULL, L"Couldn't format the error message...", L"Error", MB_OK | MB_ICONERROR);
  }
  MessageBox(NULL, errorMessage, L"Damn", MB_OK | MB_ICONERROR);
  LocalFree(errorMessage);
  return FALSE;
}
 

Хотя я пометил его как C, он действительно применим к любому языку, который работает в Windows и может получать доступ к событиям мыши низкого уровня, независимо от того, управляется он или нет.

пс. Кстати, хотя намерение, о котором я упоминал в начале, было мотивацией, с которой все началось, я считаю, что это невозможно сделать. Если сообщения с вертикальной прокруткой не всегда генерируются даже в прокручиваемых элементах управления, я не вижу, чтобы сообщения с горизонтальной прокруткой создавались, когда прокручивать нечего. Скорее всего, это должно быть реализовано в самом проводнике файлов.

Комментарии:

1. У вас есть настоящая мышь, с которой вы могли бы протестировать? Я не совсем уверен, как это работает, но я думаю, что трекпад может изначально генерировать сообщения жестов; и, вероятно, они преобразуются в WM_MOUSEWHEEL с помощью DefWndProc.

2. @JonathanPotter ты попал в точку! Вчера у меня не было доступа к нему, но сегодня я попытался подключить его по кабелю, и действительно, появляются сообщения (даже если элемент управления внизу не прокручивается). Ваш комментарий снова привел меня к документам, на этот раз в поисках жестов, и я нашел другую страницу ( docs.microsoft.com/en-us/windows/win32/wintouch/… ), где они объясняют, что вы говорили раньше об обработчике жестов по умолчанию.

3. Однако, что касается устаревшей поддержки, в нем говорится, что панорамирование (прокрутка) заставляет обработчик жестов по умолчанию генерировать сообщения WM_VSCROLL или WM_HSCROLL, и я видел это только в 1 случае: в проводнике файлов и только в том случае, если представление достаточно длинное, чтобы полоса прокрутки была видна. Так что, как это иногда бывает, это кажется непоследовательным… вздыхать

4. В нем говорится, что обработчик жестов по умолчанию генерирует WM_VSCROLL и WM_HSCROLL сообщения, поэтому, если приложение само обрабатывает сообщения WM_GESTURE (а не пересылает их DefWindowProc ), этого не произойдет.

5. Но это WM_GESTURE сообщение также не отправляется и не публикуется в приложениях (или я не вижу его с помощью Spy ). Я посмотрел, что я зарегистрировал в этих видео, и оно не появилось ни в одной из проблемных программ. Это не одно из сообщений, которые я мог бы поймать с помощью мыши, хотя, и я действительно не хочу подключаться к памяти приложений и тому подобному, так что конец строки. Мне интересно, что происходит, хотя для создания этих сообщений должны быть какие-то другие условия, не задокументированные.