2013-03-13 64 views
0

我有一個主窗口應用程序,它有一堆控件,包括空格鍵,這個控件由一個叫做onSpacebar()的簡單方法處理。在主窗口的頂部,我有一個持續的無模式對話框。 無論對話框是否有焦點,或者主窗口都有焦點,我需要空格鍵的行爲方式完全相同。無模式對話框鍵盤處理(winapi)

此對話框由DialogProc它看起來像這樣的支持:

BOOL CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 
    { 
     switch(uMsg) 
     { 
     case WM_NOTIFY: 
     std::cout<< "WM_NOTIFY" <<std::endl; 
     switch(LOWORD(wParam)) 
     { 
       // which component caused the message? 
     case COMP_TREE: 
       if(((LPNMHDR)lParam)->code == NM_DBLCLK){ 
          onDoubleclk() 
       } 
       //... 
     break; 
     // other components... 

     } 
     break; 
     case WM_CLOSE: 
      // the dialog can only be closed when the whole app is closed 
      //EndDialog(hDlg, IDCANCEL); 
      return TRUE; 
     case WM_DESTROY: 
      PostQuitMessage(0); 
      return TRUE; 
     } 
     return FALSE; 
    } 

從我所收集的,我應該叫我onSpacebar()方法從DialogProc內,我如何相若方式處理雙擊。我可以看到WM_NOTIFY在空格鍵被按下時(WM_NOTIFY短語被打印到cout)時被對話接收,但我似乎無法區分空格鍵通知和對話收到的其他大量通知。

請告訴我如何識別特定的WM_NOTIFY是爲了響應空格鍵按鍵。

+0

你'cout'消息很可能是顯著更深入,如果你嘗試打印* *的東西,除了極消息處理程序部分,你只要把它的名字。也許NMHDR的'code'成員可能會提供一些線索照亮你懷疑的鍵盤通知,特別是如果你真的*顯示*它讓你知道它是什麼。 – WhozCraig 2013-03-13 10:58:25

回答

5

A WM_NOTIFY消息是而不是窗口處理按鍵事件的標準方式。當按下某個鍵時,您的窗口應該收到WM_KEYDOWNWM_KEYUP和可能的WM_CHAR消息。 WM_NOTIFY完全不同的目的:將來自公共控件的消息傳遞給其父窗口。

所以,你在響應接收WM_NOTIFY消息按鍵其實是一個相當不尋常的事情,解釋的,當你知道如何焦點作品(這是關鍵,解決您的終極問題)。

在Windows中,一次只能關注一個窗口,當前關注的窗口是接收到的所有鍵盤輸入的窗口。因此,如果一個對話框具有焦點,它將收到按鍵通知。如果該對話框上的一個具有焦點,則(不是其父母對話框)將接收按鍵通知。並且在對話框上有一個可調焦的子控件,它將始終總是接收焦點,優先於其父對話框,因此它總是會收到按鍵通知。

因此,對於你好奇WM_NOTIFY消息可能的解釋是,common controls您的對話框上的一個具有焦點,它接收空間按鍵下壓事件,並進行處理,傳遞通知到它的父窗口之後(您對話框)以WM_NOTIFY消息的形式。正如你可能想象的那樣,這不是檢測空格鍵被按下的可靠方法。

相反,你需要找出一些方法來捕獲按鍵通知之前他們被髮送到重點控制。爲此,您需要修改應用程序的消息循環,以在調用DispatchMessageIsDialogMessage之前在之前捕獲WM_KEYDOWNWM_KEYUP消息

  • 如果鍵事件對應的空格鍵,你會打電話給你onSpacebar功能,並指示該消息已得到處理,防止它被傳遞並通過另一個窗口處理。
  • 如果鍵事件不對應的空格鍵,那麼你將需要處理的消息,就象你通常,確保它確實得到傳遞,並通過其他窗口處理。

由於這種方法在全球範圍內篩選出空間的按鍵,它解決了在對話框竊取按鍵和其他無模式對話框的子控件的兩個問題。但是,您需要小心,因爲這很容易讓事情搞砸,以至於用戶無法使用鍵盤導航對話框。

更根本的是,我認爲你的想法來處理空格鍵的印刷機是根本性的缺陷。某些通用控件的邏輯基本上要求他們處理空格鍵的按下。例如,考慮一個文本框:如果過濾掉全局級別的所有空格鍵,用戶將永遠無法在文本框中鍵入空格。如果你堅持要處理空格鍵,你需要檢查全局處理程序中的焦點控件,如果它是一個文本框(或者你希望接收空格的其他常用控件),則將其傳遞;否則,你自己處理它。

老實說,我會做的卻是選擇一個比較獨特的組合鍵(如,我不知道,按Ctrl +空間),並設置了爲加速器。據推測,您的全局消息循環已經通過調用TranslateAccelerator函數處理加速鍵,因此可以爲您處理所有骯髒的工作。甚至不需要代碼 - 只需通過編輯項目中的加速器資源文件即可完成所有工作。關於鍵盤加速器的MSDN文檔是here,但您可能會有更輕鬆的時間在Visual C++上諮詢您最喜歡的書籍。

+0

實際上,應用程序在主窗口中使用DirectInput來讀取所有密鑰,包括空格鍵。 TreeView包含不可編輯的項目,所以我寧願只是堅持控制。 這樣說 - 我關心你建議的解決方案(在消息循環中陷印按鍵通知)是否會打破我基於DirectInput的主窗口。 – 2013-03-13 18:39:45

+1

我真的不知道任何有關DirectInput的信息。我從標籤中假定這個問題嚴格限於Win32編程。如果DirectInput的給你一個辦法***主消息循環調度它們進行默認處理之前處理鍵盤事件***,那麼它可能會工作。這就是爲什麼我花時間解釋發生了什麼,而不僅僅是提供可複製和可代碼的代碼。 @sy。 – 2013-03-15 00:22:42

+0

我確定會有一個簡單的方法來掛鉤對話框的默認值 - 通常在Windows中收集我的內容。但我畢竟是個新手。這就是爲什麼我沒有進入主窗口的細節。我沒有想到DirectInput是相關的。 我已經實現了我的空格鍵處理你建議的方式。這一切都像一個魅力。非常感謝你!我有一個後續問題,但:當對話框具有焦點,當主窗口具有焦點,他們不是WM_KEYDOWN,WM_CHAR和WM_KEYUP消息只接收。這對我來說實際上是可取的,但爲什麼呢? – 2013-03-16 10:53:33