滑鼠輸入概觀

滑鼠是應用程式的重要但選擇性使用者輸入裝置。 撰寫良好的應用程式應該包含滑鼠介面,但不應該只依賴滑鼠來取得用戶輸入。 應用程式也應該提供完整的鍵盤支援。

應用程式會以傳送或張貼至其視窗的訊息形式接收滑鼠輸入。

本章節涵蓋下列主題:

滑鼠游標

當用戶移動滑鼠時,系統會在稱為 滑鼠游標的畫面上移動點陣圖。 滑鼠游標包含稱為 作用點的單圖元點,這是系統追蹤並辨識為游標位置的點。 發生滑鼠事件時,包含作用點的視窗通常會接收事件所產生的滑鼠訊息。 視窗不需要使用中,或鍵盤焦點才能接收滑鼠訊息。

系統會維護可控制滑鼠速度的變數,也就是當用戶移動滑鼠時光標移動的距離。 您可以使用 SystemParametersInfo 函式搭配 SPI_GETMOUSESPI_SETMOUSE 旗標來擷取或設定滑鼠速度。 如需滑鼠游標的詳細資訊,請參閱 數據指標

滑鼠捕捉

當發生滑鼠事件時,系統通常會將滑鼠訊息張貼到包含游標作用點的視窗。 應用程式可以使用 SetCapture 函式將滑鼠訊息路由傳送至特定視窗,來變更此行為。 視窗會接收所有滑鼠訊息, 直到應用程式呼叫 ReleaseCapture 函式或指定另一個擷取視窗,或直到使用者按兩下由另一個線程建立的窗口為止。

當滑鼠擷取變更時,系統會將WM_CAPTURECHANGED訊息傳送至遺失滑鼠擷取的視窗。 訊息的 lParam 參數會指定取得滑鼠擷取之視窗的句柄。

只有前景視窗可以擷取滑鼠輸入。 當背景視窗嘗試擷取滑鼠輸入時,它只會接收當游標作用點位於視窗可見部分時發生的滑鼠事件訊息。

如果窗口必須接收所有滑鼠輸入,即使游標在視窗外移動,擷取滑鼠輸入也很有用。 例如,應用程式通常會追蹤滑鼠按鈕向下事件之後的游標位置,並遵循游標直到發生滑鼠按鈕向上事件為止。 如果應用程式尚未擷取滑鼠輸入,且使用者會在視窗外放開滑鼠按鈕,則視窗不會收到按鈕向上訊息。

線程可以使用 GetCapture 函式 來判斷其中一個視窗是否已擷取滑鼠。 如果其中一個線程的視窗擷取滑鼠, GetCapture 會擷取視窗的句柄。

滑鼠 ClickLock

Mouse ClickLock 輔助功能功能可讓使用者在按兩下後鎖定主要滑鼠按鈕。 對應用程式,按鈕仍會顯示為按下。 若要解除鎖定按鈕,應用程式可以傳送任何滑鼠訊息,或使用者可以按下任何滑鼠按鈕。 此功能可讓使用者更簡單地執行複雜的滑鼠組合。 例如,具有特定實體限制的使用者可以更輕鬆地反白顯示文字、拖曳對象或開啟功能表。 如需詳細資訊,請參閱下列旗標和 SystemParametersInfo 中的備註:

  • SPI_GETMOUSECLICKLOCK
  • SPI_SETMOUSECLICKLOCK
  • SPI_GETMOUSECLICKLOCKTIME
  • SPI_SETMOUSECLICKLOCKTIME

滑鼠設定

雖然滑鼠是應用程式的重要輸入設備,但並不是每個用戶都必須有滑鼠。 應用程式可以將SM_MOUSEPRESENT值傳遞GetSystemMetrics 函式,以判斷系統是否包含滑鼠。

Windows 支援最多三個按鈕的滑鼠。 在三鍵滑鼠上,按鈕會指定為左、中間和右按鈕。 與滑鼠按鈕相關的訊息和具名常數會使用字母 L、M 和 R 來識別按鈕。 單一按鈕滑鼠上的按鈕會被視為左按鈕。 雖然 Windows 支援具有多個按鈕的滑鼠,但大部分的應用程式主要使用左按鈕,如果一點也很少使用其他按鈕。

應用程式也可以支援滑鼠滾輪。 滑鼠滾輪可以按下或旋轉。 按下滑鼠滾輪時,它會做為中間按鈕(第三個)按鈕,將一般中間按鈕訊息傳送至您的應用程式。 旋轉時,方向盤訊息會傳送至您的應用程式。 如需詳細資訊,請參閱 滑鼠滾輪 一節。

應用程式可以支援應用程式命令按鈕。 這些按鈕稱為 X 按鈕,旨在讓您更容易存取因特網瀏覽器、電子郵件和媒體服務。 按下 X 按鈕時,WM_APPCOMMAND訊息會傳送至您的應用程式。 如需詳細資訊,請參閱WM_APPCOMMAND訊息中的描述。

應用程式可以將SM_CMOUSEBUTTONS值傳遞GetSystemMetrics 函式,以判斷滑鼠上的按鈕數目。 若要為左側用戶設定滑鼠,應用程式可以使用 SwapMouseButton 函式來反轉左右滑鼠按鈕的意義。 將SPI_SETMOUSEBUTTONSWAP值傳遞至 SystemParametersInfo 函式,是反轉按鈕意義的另一種方式。 不過請注意,滑鼠是共用資源,因此反轉按鈕的意義會影響所有應用程式。

XBUTTON

Windows 支援具有五個按鈕的滑鼠。 除了左側、中間和右按鈕之外,還有XBUTTON1和XBUTTON2,可在使用瀏覽器時提供向後和向前流覽。

視窗管理員支援透過 WM_XBUTTON* 和 WM_NCXBUTTON* 訊息XBUTTON1和XBUTTON2。 這些訊息中 WPARAMHIWORD 包含旗標,指出按下 X 按鈕。 由於這些滑鼠訊息也適用於常數WM_MOUSEFIRST和WM_MOUSELAST,因此應用程式可以使用 GetMessage 或 PeekMessage 篩選所有滑鼠訊息。

下列支援XBUTTON1和XBUTTON2:

下列 API 已修改為支援這些按鈕:

元件應用程式中的子視窗不太可能直接實作XBUTTON1和XBUTTON2的命令。 因此,當按兩下 X 按鈕時,DefWindowProc 會將WM_APPCOMMAND訊息傳送至視窗。 DefWindowProc 也會將 WM_APPCOMMAND 訊息傳送至其父視窗。 這類似於以滑鼠右鍵按兩下叫用操作功能表的方式:DefWindowProc 會將WM_CONTEXTMENU訊息傳送至功能表,並將它傳送至其父系。 此外,如果 DefWindowProc 收到 最上層視窗的WM_APPCOMMAND 訊息,它會呼叫具有程式碼HSHELL_APPCOMMAND的殼層攔截。

支援鍵盤具有瀏覽器功能、媒體功能、應用程式啟動和電源管理的額外按鍵。 如需詳細資訊,請參閱 流覽和其他函式的鍵盤按鍵。

滑鼠訊息

當用戶移動滑鼠,或按下或放開滑鼠按鈕時,滑鼠會產生輸入事件。 系統會將滑鼠輸入事件轉換成訊息,並將其張貼至適當的線程消息佇列。 當滑鼠訊息的張貼速度比線程快時,系統會捨棄最新的滑鼠訊息以外的所有訊息。

當游標位於視窗的框線內,或視窗擷取滑鼠時,視窗就會收到滑鼠訊息。 滑鼠訊息分成兩個群組:工作區訊息和非客戶端區域訊息。 一般而言,應用程式會處理工作區訊息,並忽略非工作區訊息。

本章節涵蓋下列主題:

工作區滑鼠訊息

當滑鼠事件發生在視窗的工作區內時,視窗會收到工作區滑鼠訊息。 當使用者在工作區內移動游標時,系統會將WM_MOUSEMOVE訊息張貼到視窗。 當使用者按下或放開滑鼠按鈕時,游標位於工作區內時,它會張貼下列其中一則訊息。

訊息 意義
WM_LBUTTONDBLCLK 滑鼠左鍵已按兩下。
WM_LBUTTONDOWN 按下滑鼠左鍵。
WM_LBUTTONUP 放開滑鼠左鍵。
WM_MBUTTONDBLCLK 按兩下滑鼠中間按鈕。
WM_MBUTTONDOWN 按下中間滑鼠按鈕。
WM_MBUTTONUP 放開滑鼠中間按鈕。
WM_RBUTTONDBLCLK 滑鼠右鍵已按兩下。
WM_RBUTTONDOWN 按下滑鼠右鍵。
WM_RBUTTONUP 滑鼠右鍵已放開。
WM_XBUTTONDBLCLK 按兩下 X 滑鼠按鈕。
WM_XBUTTONDOWN 按下 X 滑鼠按鈕。
WM_XBUTTONUP 已放開 X 滑鼠按鈕。

 

此外,應用程式可以呼叫 TrackMouseEvent 函式,讓系統傳送另外兩則訊息。 當游標停留在用戶端區域一段時間時,它會張貼 WM_MOUSEHOVER 訊息。 當游標離開工作區時,它會張貼 WM_MOUSELEAVE 訊息。

訊息參數

工作區滑鼠訊息的 lParam 參數會指出游標作用點的位置。 低序字表示作用點的 X 座標,而高階字則表示 Y 座標。 座標是在用戶端座標中指定。 在用戶端座標系統中,會指定螢幕上的所有點,相對於工作區左上角的座標(0,0)。

wParam 參數包含旗標,指出滑鼠事件時其他滑鼠按鈕和 CTRL 和 SHIFT 鍵的狀態。 當滑鼠訊息處理取決於另一個滑鼠按鈕或 CTRL 或 SHIFT 鍵的狀態時,您可以檢查這些旗標。 wParam 參數可以是下列值的組合。

Description
MK_CONTROL CTRL 鍵已關閉。
MK_LBUTTON 滑鼠左鍵已關閉。
MK_MBUTTON 滑鼠中間按鈕已關閉。
MK_RBUTTON 滑鼠右鍵已關閉。
MK_SHIFT SHIFT 鍵已關閉。
MK_XBUTTON1 第一個 X 按鈕已關閉。
MK_XBUTTON2 第二個 X 按鈕已關閉。

 

按兩下訊息

當用戶連續兩次按兩下滑鼠按鈕時,系統會產生雙擊訊息。 當使用者按鍵時,系統會建立以游標作用點為中心的矩形。 它也會標示按兩下發生的時間。 當使用者第二次按兩下相同的按鈕時,系統會判斷作用點是否仍在矩形內,並計算自第一次按兩下之後經過的時間。 如果作用點仍在矩形內,且經過的時間未超過按兩下逾時值,系統會產生雙擊訊息。

應用程式可以使用 GetDoubleClickTime 和 SetDoubleClickTime 函式,分別取得和設定按兩下逾時值。 或者,應用程式可以使用 SPI_SETDOUBLECLICKTIME 旗標搭配 SystemParametersInfo 函式來設定按兩下逾時值。 它也可以設定系統用來偵測按兩下的矩形大小,方法是將SPI_SETDOUBLECLKWIDTH和SPI_SETDOUBLECLKHEIGHT旗標傳遞SystemParametersInfo。 不過請注意,設定按兩下逾時值和矩形會影響所有應用程式。

應用程式定義的窗口預設不會接收按兩下訊息。 由於產生雙擊訊息所涉及的系統額外負荷,這些訊息只會針對屬於具有 CS_DBLCLKS 類別樣式之類別的窗口產生。 註冊視窗類別時,您的應用程式必須設定此樣式。 如需詳細資訊,請參閱 窗口類別

按兩下訊息一律是四個訊息系列中的第三個訊息。 前兩則訊息是按兩下時所產生的按鈕按鈕和向上按鈕訊息。 第二次按兩下會產生雙擊訊息,後面接著另一個按鈕訊息。 例如,按兩下滑鼠左鍵會產生下列訊息順序:

  1. WM_LBUTTONDOWN
  2. WM_LBUTTONUP
  3. WM_LBUTTONDBLCLK
  4. WM_LBUTTONUP

因為視窗在收到按兩下訊息之前一律會收到按鈕關閉訊息,所以應用程式通常會使用按兩下訊息來擴充在按鈕關閉訊息期間開始的工作。 例如,當使用者在 Microsoft 小畫家 的調色盤中按兩下色彩時,[繪製] 會在調色盤旁邊顯示選取的色彩。 當使用者按兩下色彩時,[繪製] 會顯示色彩,並開啟 [ 編輯色彩 ] 對話框。

非客戶端區域滑鼠訊息

當滑鼠事件發生在工作區以外的任何部分時,視窗會收到非客戶端區域滑鼠訊息。 視窗的非工作區包含其框線、功能表欄、標題列、滾動條、視窗功能表、最小化按鈕和最大化按鈕。

系統會產生非用戶端區域訊息,主要供其使用。 例如,當游標作用點移至視窗框線時,系統會使用非客戶端區域訊息,將游標變更為雙頭箭號。 窗口必須將非工作區滑鼠訊息傳遞至 DefWindowProc 函式,才能利用內建的滑鼠介面。

每個工作區滑鼠訊息都有對應的非工作區滑鼠訊息。 這些訊息的名稱類似,不同之處在於非用戶端區域訊息的具名常數包含字母 NC。 例如,在非用戶端區域中移動游標會產生WM_NCMOUSEMOVE訊息,並在游標位於非工作區時按下滑鼠左鍵會產生WM_NCLBUTTONDOWN訊息。

非工作區滑鼠訊息的 lParam 參數是結構,其中包含游標作用點的 x 座標和 Y 座標。 不同於工作區滑鼠訊息的座標,座標是在螢幕座標中指定,而不是用戶端座標。 在螢幕座標系統中,螢幕上的所有點都與畫面左上角的座標 (0,0) 相對。

wParam 參數包含點擊測試值,這個值表示滑鼠事件發生在非客戶端區域中的位置。 下一節說明點擊測試值的目的。

WM_NCHITTEST訊息

每當發生滑鼠事件時,系統會將WM_NCHITTEST訊息傳送至包含游標作用點的視窗或擷取滑鼠的視窗。 系統會使用此訊息來判斷傳送工作區或非工作區滑鼠訊息。 必須接收滑鼠移動和滑鼠按鈕訊息的應用程式必須將WM_NCHITTEST訊息傳遞DefWindowProc 函式。

WM_NCHITTEST訊息的 lParam 參數包含游標作用點的螢幕座標。 DefWindowProc 函式會檢查座標,並傳回點擊測試值,指出熱點的位置。 點擊測試值可以是下列其中一個值。

熱點位置
HTBORDER 在沒有重設大小框線的視窗框線中。
HTBOTTOM 在視窗的下水平框線中。
HTBOTTOMLEFT 在視窗框線的左下角。
HTBOTTOMRIGHT 在視窗框線的右下角。
TCAPTION 在標題列中。
TCLIENT 在工作區中。
TCLOSE 在 [關閉] 按鈕中。
HTERROR 在螢幕背景或視窗之間的分隔線上(與 HTNOWHERE 相同,不同之處在於 DefWindowProc 函式會產生系統嗶聲來指出錯誤)。
HTGROWBOX 在大小方塊中(與 HTSIZE 相同)。
HTHELP 在 [ 說明] 按鈕中。
HTHSCROLL 在水平滾動條中。
HTLEFT 在視窗的左框線中。
HTMENU 在功能表中。
HTMAXBUTTON 在 [最大化] 按鈕中。
HTMINBUTTON 在 [最小化] 按鈕中。
HTNOWHERE 在畫面背景或視窗之間的分隔線上。
HTREDUCE 在 [最小化] 按鈕中。
HTRIGHT 在視窗的右框線中。
HTSIZE 在大小方塊中(與 HTGROWBOX 相同)。
HTSYSMENU 在 [ 系統] 選單或子視窗中的 [ 關閉 ] 按鈕中。
HTTOP 在視窗的上水平框線中。
HTTOPLEFT 在視窗框線的左上角。
HTTOPRIGHT 在視窗框線的右上角。
HTTRANSPARENT 在目前由相同線程中另一個視窗所涵蓋的視窗中。
HTVSCROLL 在垂直滾動條中。
HTZOOM 在 [最大化] 按鈕中。

 

如果游標位於視窗的工作區中, DefWindowProc 會將 HTCLIENT 點擊測試值傳回至窗口程式。 當視窗程式將此程式代碼傳回系統時,系統會將游標作用點的螢幕座標轉換為用戶端座標,然後張貼適當的工作區滑鼠訊息。

當游標作用點位於視窗的非工作區時,DefWindowProc 函式會傳回另一個點擊測試值。 當視窗程式傳回下列其中一個點擊測試值時,系統會張貼非工作區滑鼠訊息、將點擊測試值放在訊息的 wParam 參數和 lParam 參數中的數據指標座標中。

Mouse Sonar

當使用者按下並放開 CTRL 鍵時,滑鼠 Sonar 輔助功能功能會簡短地顯示指標周圍的數個同心圓圈。 這項功能可協助使用者在雜亂或解析度設定為高、品質不佳的監視器上,或針對視力受損的使用者,找出滑鼠指標。 如需詳細資訊,請參閱 SystemParametersInfo 中的下列旗標:

SPI_GETMOUSESONAR

SPI_SETMOUSESONAR

滑鼠消失

當使用者輸入時,滑鼠消失輔助功能功能會隱藏指標。 當用戶移動滑鼠時,滑鼠指標會重新出現。 此功能會讓指標無法遮蔽正在輸入的文字,例如,在電子郵件或其他檔中。 如需詳細資訊,請參閱 SystemParametersInfo 中的下列旗標:

SPI_GETMOUSEVANISH

SPI_SETMOUSEVANISH

滑鼠滾輪

滑鼠滾輪結合了滾輪和滑鼠按鈕的功能。 方向盤具有離散、平均間距的聲道。 當您旋轉方向盤時,會在遇到每個凹口時,將滾輪訊息傳送至您的應用程式。 滾輪按鈕也可以作為一般的 Windows 中間 (第三個) 按鈕運作。 按下滑鼠滾輪並放開會傳送標準WM_MBUTTONUPWM_MBUTTONDOWN訊息。 按兩下第三個按鈕會傳送標準 WM_MBUTTONDBLCLK 訊息。

滑鼠滾輪可透過 WM_MOUSEWHEEL 訊息支援。

旋轉滑鼠會將 WM_MOUSEWHEEL 訊息傳送至焦點視窗。 DefWindowProc 函式會將訊息傳播至視窗的父系。 訊息不應有內部轉送,因為 DefWindowProc 會將它傳播到父鏈結,直到找到處理訊息的窗口為止。

判斷滾動條數目

應用程式應該使用 SystemParametersInfo 函式來擷取每一個卷動作業的文件捲動行數(滾輪記號)。 若要擷取行數,應用程式會進行下列呼叫:

SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, pulScrollLines, 0)

變數 「pulScrollLines」 指向不帶正負號的整數值,這個值會在滑鼠滾輪沒有修飾詞鍵時接收建議的滾動行數:

  • 如果這個數位是 0,就不應該發生捲動。
  • 如果這個數位是 WHEEL_PAGESCROLL,滾輪卷應該解譯為在滾動條頁面向下或向上頁面區域中按兩下一次。
  • 如果要卷動的行數大於可檢視的行數,卷動作業也應該解譯為向下頁或向上頁作業。

滾動條數目的預設值為 3。 如果使用者使用 控制台 中的滑鼠屬性工作表變更滾動條數目,則操作系統會將WM_SETTINGCHANGE訊息廣播至指定SPI_SETWHEELSCROLLLINES的所有最上層視窗。 當應用程式收到 WM_SETTINGCHANGE 訊息時,接著可以藉由呼叫 來取得新的滾動行數目:

SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, pulScrollLines, 0)

捲動的控件

下表列出具有捲動功能的控件(包括用戶設定的滾動線)。

控制 捲動
編輯控制件 垂直和水準。
清單框控制件 垂直和水準。
組合方塊 當未卸除時,每個捲動都會擷取下一個或上一個專案。 當下拉式清單時,每個捲動都會將訊息向前捲動至清單框,而清單框會據此卷動。
CMD (命令列) 垂直。
樹狀目錄檢視 垂直和水準。
清單檢視 垂直和水準。
向上/向下捲動 一次一個專案。
追蹤列捲動 一次一個專案。
Microsoft Rich Edit 1.0 垂直。 請注意,Exchange 用戶端有自己的清單檢視版本,以及沒有轉輪支援的樹視圖控件。
Microsoft Rich Edit 2.0 垂直。

 

使用滾輪偵測滑鼠

若要判斷具有滾輪的滑鼠是否已連接,請使用 SM_MOUSEWHEELPRESENT呼叫 GetSystemMetrics。 TRUE傳回值表示滑鼠已連接。

下列範例來自多行編輯控制元件的視窗程式:

BOOL ScrollLines(
     PWNDDATA pwndData,   //scrolls the window indicated
     int cLinesToScroll); //number of times

short gcWheelDelta; //wheel delta from roll
PWNDDATA pWndData; //pointer to structure containing info about the window
UINT gucWheelScrollLines=0;//number of lines to scroll on a wheel rotation

gucWheelScrollLines = SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 
                             0, 
                             pulScrollLines, 
                             0);

case WM_MOUSEWHEEL:
    /*
     * Do not handle zoom and datazoom.
     */
    if (wParam & (MK_SHIFT | MK_CONTROL)) {
        goto PassToDefaultWindowProc;
    }

    gcWheelDelta -= (short) HIWORD(wParam);
    if (abs(gcWheelDelta) >= WHEEL_DELTA && gucWheelScrollLines > 0) 
    {
        int cLineScroll;

        /*
         * Limit a roll of one (1) WHEEL_DELTA to
         * scroll one (1) page.
         */
        cLineScroll = (int) min(
                (UINT) pWndData->ichLinesOnScreen - 1,
                gucWheelScrollLines);

        if (cLineScroll == 0) {
            cLineScroll++;
        }

        cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
        assert(cLineScroll != 0);

        gcWheelDelta = gcWheelDelta % WHEEL_DELTA;
        return ScrollLines(pWndData, cLineScroll);
    }

    break;

視窗啟動

當使用者按兩下非使用中最上層視窗或非使用中最上層視窗的子視窗時,系統會將WM_MOUSEACTIVATE訊息(以及其他)傳送至最上層或子視窗。 系統會在 將WM_NCHITTEST 訊息張貼至窗口之後,但在張貼按鈕關閉訊息之前傳送此訊息。 當WM_MOUSEACTIVATE傳遞至 DefWindowProc 函式時,系統會啟動最上層視窗,然後將按鈕向下訊息張貼至最上層或子視窗。

藉由處理 WM_MOUSEACTIVATE,視窗可以控制最上層視窗是否因為按鼠而變成使用中視窗,以及按兩下的視窗是否會收到後續的按鈕關閉訊息。 在處理 WM_MOUSEACTIVATE之後,它會傳回下列其中一個值。

意義
MA_ACTIVATE 啟動視窗,而不會捨棄滑鼠訊息。
MA_NOACTIVATE 不會啟動視窗,也不會捨棄滑鼠訊息。
MA_ACTIVATEANDEAT 啟動視窗並捨棄滑鼠訊息。
MA_NOACTIVATEANDEAT 不會啟動視窗,但會捨棄滑鼠訊息。

另請參閱

利用高畫質滑鼠移動