среда, 26 ноября 2008 г.

Почему я получаю ложные сообщения WM_MOUSEMOVE?

Это перевод Why do I get spurious WM_MOUSEMOVE messages?

Чтобы правильно это понять, полезно знать, откуда вообще берутся сообщения WM_MOUSEMOVE.

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

Когда этот поток вызовет функцию получения сообщения, такую как GetMessage, и при этом флаг "если это кого-то сейчас заботит, то мышь сейчас двигали" был установлен, то Windows проверяет положение мыши и делает работу, которая обычно рассматривается как часть движения мыши: определяет окно, которое должно получить сообщение, меняет курсор и определяет тип сообщения, которое нужно сгенерировать (чаще всего это WM_MOUSEMOVE или, возможно, WM_NCMOUSEMOVE).

Если вы понимаете этот сценарий, то вы уже можете видеть ответ на вопрос: "почему моя программа не принимает все сообщения мыши, если мышь двигать очень быстро?".

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

Вы также можете видеть ответ на вопрос: "как быстро Windows может доставлять сообщения о движениях мыши?".

Ответ: "настолько быстро, насколько вы этого хотите". Если вы часто вызываете GetMessage - вы часто получаете сообщения от мыши; если вы вызываете GetMessage редко - то вы редко получаете и сообщения от мыши.

Окей, вернёмся к нашим баранам: "почему я получаю ложные сообщения WM_MOUSEMOVE?".

Заметим, что доставка сообщения включает в себя множество работы, которая обычно считается частью движения мыши. Часто Windows нужно выполнить эту "сопроводительную часть" работы, хотя мышь реально ещё не двигали. Самый очевидный пример: когда окно показывается, скрывается или перемещается. Когда такое случается, курсор мыши может оказаться под другим окном, чем он был до движения окна (или, в случае движения окна, - курсор может оказаться над другой частью того же окна). Windows нужно определить курсор мыши (например, старому окну нужна была стандартная стрелочка, а новому подавай указывающую руку), поэтому Windows искусственно устанавливает флаг "если это кого-то сейчас заботит, то мышь сейчас двигали". Это приводит к выполнению всей "сопроводительной" работы, побочным эффектом которой является генерация ложного сообщения WM_MOUSEMOVE.

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

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

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

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