TMouse 封裝系統滑鼠狀態,全域單例 Mouse(定義於 Controls.hpp)提供游標位置、捕獲視窗、拖曳行為參數、滾輪訊息常數、硬體存在性檢測等輕量級介面。本文系統講解核心屬性、拖曳閾值機制、滾輪訊息處理、多顯示器座標轉換與常見陷阱。
TObject
└── TMouse // 非元件,全域單例 Mouse
| 屬性 | 類型 | 說明 |
|---|---|---|
CursorPos | TPoint | 螢幕絕對座標(虛擬桌面座標系) |
Capture | HWND | 當前捕獲滑鼠訊息的視窗句柄(0 表示無) |
DragImmediate | Boolean | true:按下即啟動拖曳;false:需移動 DragThreshold 像素 |
DragThreshold | Integer | 啟動拖曳所需移動像素(預設 5),DragImmediate=false 時生效 |
MousePresent | Boolean | 系統是否有滑鼠裝置 |
WheelPresent | Boolean | 滑鼠是否有滾輪 |
WheelScrollLines | Integer | 每滾輪刻度捲動行數(控制面板設定,通常 3) |
RegWheelMessage | UINT | 系統滾輪訊息常數(RegisterWindowMessage("MSWHEEL_ROLLMSG")) |
constructor Create; // 內部調用
// 初始值
DragImmediate = true;
DragThreshold = 5;
WheelScrollLines = 系統設定值;
RegWheelMessage = RegisterWindowMessage(MSH_MOUSEWHEEL);
VCL 拖曳啟動邏輯(TControl::MouseDown → BeginDrag):
if (Mouse->DragImmediate) {
BeginDrag(true); // 立即進入拖曳模式
} else {
// 進入「潛在拖曳」狀態,等待 MouseMove 累積位移
// 當 |DeltaX| + |DeltaY| >= DragThreshold 時自動 BeginDrag(true)
}
OnMouseDown 臨時修改 Mouse->DragThreshold,離開時恢復。// 訊息常數(全域唯一)
const UINT WM_MOUSEWHEEL = 0x020A; // 標準垂直滾輪
const UINT WM_MOUSEHWHEEL = 0x020E; // 水平滾輪 (Win Vista+)
// 在控件訊息處理器中
MESSAGE void __fastcall WMMouseWheel(TMessage& Msg) {
if (Msg.Msg == Mouse->RegWheelMessage) { // 兼容舊版註冊訊息
int zDelta = (short)HIWORD(Msg.WParam); // ±120 為一檔
int lines = zDelta * Mouse->WheelScrollLines / 120;
// 處理捲動...
}
}
// 高精度滾輪 (Win10 1809+)
// 使用 WM_MOUSEWHEEL + GET_WHEEL_DELTA_WPARAM 宏
// 支援高解析度滾輪(zDelta 非 120 倍數)
// 螢幕絕對座標 → 客戶區座標
TPoint clientPt = Control->ScreenToClient(Mouse->CursorPos);
// 多監視器虛擬桌面座標系說明
// 主監視器左上角為 (0,0)
// 次監視器在左側 → 負 X 座標
// 次監視器在上方 → 負 Y 座標
// 使用 GetMonitorInfo / MonitorFromPoint 判斷所在監視器
Control->Capture = true → SetCapture(Handle) → Mouse->Capture = Handle。ReleaseCapture() → Mouse->Capture = 0。| 現象 | 原因 | 對策 |
|---|---|---|
| 拖曳不啟動 | DragMode=dmManual 但未呼叫 BeginDrag | 在 OnMouseDown 呼叫 BeginDrag(false) 或設 DragMode=dmAutomatic |
| 滾輪不觸發 | 控件未處理 RegWheelMessage 或 WM_MOUSEWHEEL | 重寫 WndProc 或使用 OnMouseWheel 事件 (VCL 內部已分發) |
| CursorPos 為負值 | 游標在主監視器左/上側的次監視器 | 正常現象,轉換客戶區座標用 ScreenToClient |
| WheelScrollLines 讀取為 0 | 系統設定「一次捲動一頁」 | 視為「大量捲動」,自行定義行數如 20 |
| MousePresent=false 但有觸控板 | API 僅檢測傳統滑鼠 | 觸控板通常模擬滑鼠,實際可用 |
WM_MOUSEWHEEL 非 120 倍數 zDelta,建議累積餘量平滑捲動。TMouse 無觸控支援,需用 WM_TOUCH / WM_GESTURE 或 TTouchManager (VCL 10.3+)。ShowCursor(false) + SetCursor(LoadCursor(...)),或 Screen->Cursors 註冊動畫光標。TMouse 雖輕量,卻是滑鼠交互行為的「中央配置中心」。理解 DragImmediate/Threshold 的雙模式、RegWheelMessage 的版本演進、虛擬桌面座標系,即能精準控制從傳統滑鼠到高精度滾輪、多監視器環境下的交互體驗。