キーボードアクセラレータによるメッセージの削除
たとえば大きなウィンドウにいくつかの子ウィンドウを配置して、その中の1つの子ウィンドウがキーボードアクセラレータでDeleteキーに操作を割り当てていたとします。さらに別の子ウィンドウ(親は同じ)でWM_KEYDOWNなどでDeleteが押されたことを取得しようとすると、できなくなります。これは、メッセージプロシージャでキーボードアクセラレータに渡されるメッセージの処理を行うことによって、メッセージがWM_KEYDOWNをしたいウィンドウに渡されないというだけのようです。
基本的にキーボードアクセラレータによる操作をしたいのはフォーカスの当たっているウィンドウだけでいいと思うので、フォーカスがあたったときと外れたときでキーボードアクセラレータのON/OFFをしてやれば問題は解決できます。
void OnSetFocus( HWND hOldWnd ) { if( m_Accelerator.IsNull() ){ m_Accelerator.LoadAccelerators( IDR_ACCELERATOR ); } CMessageLoop* pLoop = _Module.GetMessageLoop(); pLoop->AddMessageFilter( this ); } void OnKillFocus( HWND hNewWnd ) { CMessageLoop* pLoop = _Module.GetMessageLoop(); pLoop->RemoveMessageFilter( this ); }
ちなみにメッセージループからメッセージを外すときに、すでに外されているかどうかをチェックするときには、pLoop->m_aMsgFilterの中身を見ます。これはATLが提供する配列型で、
CMessageLoop* pLoop = _Module.GetMessageLoop(); if( pLoop->m_aMsgFilter.Find( this ) != -1 ){ pLoop->RemoveMessageFilter( this ); }
というようにFind関数を使うことで配列中に要素が存在するかどうかを確かめることができます。