ペイン内でのアクセラレータキー入力

解決


ひる  2011-06-10 20:50:44  No: 72711  IP: 192.*.*.*

現在、テストプログラムで以下のような問題を抱えています。

・VC2008でSDI標準のプロジェクトを作成し、リソースエディタ上で
  ID_APP_ABOUTのアクセラレータにVK_UPを割り当て、ビルドして実行。

・上キーを押すとバージョン情報ダイアログが表示される。

・ところがこの状態だと、クラスビューのツリー上で上キーを押しても、
  ツリー内の移動ではなくバージョン情報ダイアログが表示されてしまう。

・そこで、CMainFrame::PreTranslateMessageを追加し、以下のようにした。

BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
  if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) {
    if (m_wndClassView.IsDialogMessage(pMsg)) {
      return TRUE;
    }
  }

  return CFrameWndEx::PreTranslateMessage(pMsg);
}

・ツリー上では上キーでもツリー内の移動をしてくれるようになった。

・しかし、他のアクセラレータキー(Ctrl+OやCtrl+Pなど)も
  ツリー上では無視されてしまう。

Ctrl+OやCtrl+Pなど、ダイアログ自身が処理していないはずのメッセージも、
IsDialogMessageで処理されてしまうものなのでしょうか?

編集 削除
gak  2011-06-13 18:13:44  No: 72712  IP: 192.*.*.*

> Ctrl+OやCtrl+Pなど、ダイアログ自身が処理していないはずのメッセージも、
> IsDialogMessageで処理されてしまうものなのでしょうか?
http://msdn.microsoft.com/en-us/library/ms645498.aspx
「IsDialogMessage sends WM_GETDLGCODE messages to the dialog box procedure to determine which keys should be processed.」
http://msdn.microsoft.com/en-us/library/ms645425.aspx
「By default, the system handles all keyboard input to the control.」

とある。

> ・ところがこの状態だと、クラスビューのツリー上で上キーを押しても、
>   ツリー内の移動ではなくバージョン情報ダイアログが表示されてしまう。
MFC使ってるなら GetDefaultAccelerator() をオーバーライドしてやれば良い。
CDocument 単位で切り替えたいなら CDocument::GetDefaultAccelerator() で対応する HACCEL 返せば良いし、
そうで無いなら↓な感じで切り替えてやっても良い。

HACCEL m_wndClassView::GetAccelerator() {
    return ::LoadAccelerators(, m_wndClassView専用のアクセラレータ);
}

HACCEL CMainFrame::GetDefaultAccelerator() {
    HWND wnd = ::GetFocus();
    if (wnd == m_wndClassView || ::IsChild(m_wndClassView, wnd)) {
        return m_wndClassView.GetAccelerator();
    }
    return CFrameWndEx::GetDefaultAccelerator();
}

編集 削除
ひる  2011-06-13 20:16:31  No: 72713  IP: 192.*.*.*

> MFC使ってるなら GetDefaultAccelerator() をオーバーライドしてやれば良い。

ありがとうございます。
CFrameWndにこんな隠れ仮想関数があったのですね。

実際にはコントロールを持つペインは複数あるので、
CMainFrameのメンバとしてペイン用のアクセラレータ(上下キーのみ削除)を用意し、

HACCEL CMainFrame::GetDefaultAccelerator()
{
  if (ペイン1.IsChild(GetFocus()) || ペイン2.IsChild(GetFocus())) {
    return m_hAccelPane; // ペイン用のアクセラレータ
  }

  return CFrameWndEx::GetDefaultAccelerator();
}

とすることで、上下キー以外のアクセラレータを残したまま
ペイン内のキーボード移動を有効にすることができました。
ありがとうございました。

編集 削除