2010-05-25 2 views
2

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

Я пытаюсь отслеживать действия пользователя в компоненте, который я не писал, поэтому я использую оболочку Windows Forms NativeWindow (обертывание компонента), чтобы получить сообщения Windows из метода WndProc().

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

Без модификатора (пропуская краску, таймер и сообщения NCHITTEST):

WM_PARENTNOTIFY 
WM_MOUSEACTIVATE 
WM_MOUSEACTIVATE 
WM_SETCURSOR 
WM_LBUTTONDOWN 
WM_SETCURSOR 
WM_MOUSEMOVE 
WM_SETCURSOR 
WM_LBUTTONUP 

С модификатором (пропуском краску, таймер и сообщения NCHITTEST):

WM_KEYDOWN 
WM_PARENTNOTIFY 
WM_MOUSEACTIVATE 
WM_MOUSEACTIVATE 
WM_SETCURSOR 
WM_LBUTTONDOWN 
WM_SETCURSOR (repeats) 
WM_KEYDOWN (repeats) 
WM_KEYUP 

Если я держу кнопку мыши для долгое время, я обычно могу получить уведомление WM_LBUTTONUP, но должно быть возможно сделать его более отзывчивым.

Редактировать: Я попытался щелкнуть правой кнопкой мыши за пределами представляющую интерес, и перемещая курсор в него, прежде чем отпускать кнопку мыши, а затем я получаю уведомление WM_LBUTTONUP, поэтому он выглядит так, как компонент захватывает мышь при наведении указателя мыши. Есть ли способ получить это уведомление, когда другое окно захватило мышь?

Спасибо.

+0

Нет воспроизведения, конечно. Почему вы используете NativeWindow? Почему в вашем списке WM_MOUSEACTIVATE? Окно должно быть активировано. –

+0

Я использую NativeWindow для захвата сообщений от компонента, который я не писал. Я не знаю, почему есть WM_MOUSEACTIVATE. Насколько я могу судить, окно уже активировано. Похоже, перед сообщением WM_LBUTTONDOWN есть два сообщения WM_MOUSEACTIVATE, если я нажимаю клавишу модификатора. Я не изначально перечислял их в первом списке событий. – Greg

ответ

2

Часто, когда мышь нажимается на (собственное) управление окнами, для управления «перетаскиванием» вводится какой-то модальный цикл отслеживания. В течение продолжительности модального цикла сообщения непосредственно извлекаются из очереди сообщений и обрабатываются - уведомление с помощью мыши является одним из условий завершения для модального цикла и, таким образом, обычно потребляется без отправки.

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


Я могу думать о четырех способах решения этой проблемы.

  • Узнайте, какую операцию перетаскивания поддерживает элемент управления - и отключите его. Надеюсь, если встроенный WindowProc знает, что модальные перетаскивания не допускаются, он не войдет в модальный цикл.
  • Предупреждение о том, что WindowProc узнает об модальном перетаскивании: то есть перехват И НЕ ПРОШИВАТЬ любые сообщения WM_LBUTTONDOWN в следующий Windowproc в цепочке.
  • Установите крючок сообщения с помощью SetWindowsHookEx.

Все эти решения - это API окон. Не знаю, как они переводится в управляемую среду.

+0

+1 для подхода SetWindowsHookEx – hemp

+0

Я смог обойти эту проблему, установив крючок сообщения Windows и установив флаг для моего другого кода для чтения, когда поступило сообщение WM_LBUTTONUP. Благодарю. – Greg

0

В вашем обработчике вам нужно проверить ключ WPARAM, когда вы получаете сообщение WM_LBUTTONUP.

http://msdn.microsoft.com/en-us/library/ms645608%28VS.85%29.aspx

+0

Я не получаю сообщение WM_LBUTTONUP, когда я нажимаю, удерживая клавишу модификатора. – Greg

0

Если компонент captures mouse messages, сообщение WM_LBUTTONUP может обойти вашу обертку и перейти непосредственно к компоненту.

+0

Это выглядит так. Есть ли способ обойти это и до сих пор получать событие для мыши? – Greg

0

Модификатор и клавиши навигации зарезервированы для внутреннего использования ОС по умолчанию. Обработчик клавиатуры по умолчанию интерпретирует их и генерирует соответствующие сообщения на их основе по мере необходимости. Если элемент управления хочет действовать на них напрямую, ему необходимо обработать сообщение WM_GETDLGCODE, необязательно с результатом, который включает в себя соответствующие флаги DLGC_WANT..., такие как DLGC_WANTALLKEYS и DLGC_WANTARROWS, поэтому ключи доставляются в очередь сообщений как обычные сообщения (например , DLGC_WANTALLKEYS будет генерировать сообщения WM_KEYDOWN/UP).

0

Используйте Application.AddMessageFilter, чтобы добавить обработчик в нативный насос сообщений. Что-то вроде этого:

[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
private class ZoomGestureHandler : IMessageFilter 
{ 
    private const UInt32 WM_MOUSEWHEEL = 0x20A; 
    private const UInt32 MK_CONTROL = 0x08; 

    private readonly ImageListView _target; 

    public ZoomGestureHandler(ImageListView target) 
    { 
     _target = target; 
    } 

    public bool PreFilterMessage(ref Message m) 
    { 
     if (m.Msg != WM_MOUSEWHEEL) 
     { 
      // Not a mouse wheel message 
      return false; 
     } 

     int wheelDelta = HiWord(m.WParam.ToInt32()); 
     int keyState = LoWord(m.WParam.ToInt32()); 

     // Mouse wheel scrolled while the Control key was down 
     if ((wheelDelta != 0) && (MK_CONTROL == keyState)) 
     { 
      // Hit test the mouse location 
      int xPos = LoWord(m.LParam.ToInt32()); 
      int yPos = HiWord(m.LParam.ToInt32()); 

      Point controlLocation = _target.Parent.PointToScreen(_target.Location); 
      if ((xPos >= controlLocation.X) && (xPos < (controlLocation.X + _target.Width)) 
       && (yPos >= controlLocation.Y) && (yPos < (controlLocation.Y + _target.Height))) 
      { 
       // Determine whether to zoom in or out 
       if (wheelDelta > 0) 
       { 
        _target.ViewModel.TryZoomIn(); 
       } 
       if (wheelDelta < 0) 
       { 
        _target.ViewModel.TryZoomOut(); 
       } 
      } 
     } 
     return false; 
    } 

    private static int HiWord(int number) 
    { 
     if ((number & 0x80000000) == 0x80000000) 
      return (number >> 16); 
     return (number >> 16) & 0xffff; 
    } 

    private static int LoWord(int number) 
    { 
     return number & 0xffff; 
    } 
} 

Этот пример не является специфичным для конкретной цели, но вы можете изменить его в соответствии с. Это только что я написал недавно.

+0

Я попытался добавить фильтр сообщений, но он не вызван. Мой код работает в вспомогательном объекте браузера Internet Explorer. Может ли это вмешаться в работу IMessageFilter? Я нашел примечание [1], что фильтры сообщений не работают с элементами управления COM. [1] http://www.codeproject.com/KB/cs/imessagefilterarticle.aspx?msg=640160#xx640160xx – Greg

+0

Управление COM может работать в отдельном помещении с собственным насосом сообщений. Я никогда не работал с объектами вспомогательных браузеров, но определенно кажется, что вы сильно нападаете на присущее этой модели ограничение. В потоке комментариев к кодовому проекту, на который вы ссылались, есть предложения по использованию Windows Hook для выполнения этого. Это поражает меня, скорее всего, будет успешным для вашего сценария. – hemp

+0

Спасибо, я попробую. – Greg

 Смежные вопросы

  • Нет связанных вопросов^_^