Operasi Tetikus Lain-lain
Bagian sebelumnya telah membahas klik mouse dan gerakan mouse. Berikut adalah beberapa operasi lain yang dapat dilakukan dengan mouse.
Menyeret Elemen UI
Jika UI Anda mendukung penyeretan elemen UI, ada satu fungsi lain yang harus Anda panggil di handler pesan mouse-down Anda: DragDetect. Fungsi DragDetect mengembalikan TRUE jika pengguna memulai gerakan mouse yang harus ditafsirkan sebagai menyeret. Kode berikut menunjukkan cara menggunakan fungsi ini.
case WM_LBUTTONDOWN:
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
if (DragDetect(m_hwnd, pt))
{
// Start dragging.
}
}
return 0;
Berikut adalah idenya: Saat program mendukung seret dan letakkan, Anda tidak ingin setiap klik mouse ditafsirkan sebagai seret. Jika tidak, pengguna mungkin secara tidak sengaja menyeret sesuatu ketika dia hanya dimaksudkan untuk mengkliknya (misalnya, untuk memilihnya). Tetapi jika mouse sangat sensitif, mungkin sulit untuk menjaga mouse tetap sempurna sambil mengklik. Oleh karena itu, Windows mendefinisikan ambang seret beberapa piksel. Ketika pengguna menekan tombol mouse, itu tidak dianggap seret kecuali mouse melewati ambang ini. Fungsi DragDetect menguji apakah ambang batas ini tercapai. Jika fungsi mengembalikan TRUE, Anda dapat menginterpretasikan klik mouse sebagai seret. Jika tidak, jangan.
Catatan
Jika DragDetect mengembalikan FALSE, Windows menyembunyikan pesan WM_LBUTTONUP saat pengguna merilis tombol mouse. Oleh karena itu, jangan panggil DragDetect kecuali program Anda saat ini dalam mode yang mendukung penyeretan. (Misalnya, jika elemen UI yang dapat diseret sudah dipilih.) Di akhir modul ini, kita akan melihat contoh kode yang lebih panjang yang menggunakan fungsi DragDetect .
Membatasi Kursor
Terkadang Anda mungkin ingin membatasi kursor ke area klien atau sebagian area klien. Fungsi ClipCursor membatasi pergerakan kursor ke persegi panjang tertentu. Persegi panjang ini diberikan dalam koordinat layar, bukan koordinat klien, jadi titik (0, 0) berarti sudut kiri atas layar. Untuk menerjemahkan koordinat klien ke dalam koordinat layar, panggil fungsi ClientToScreen.
Kode berikut membatasi kursor ke area klien jendela.
// Get the window client area.
RECT rc;
GetClientRect(m_hwnd, &rc);
// Convert the client area to screen coordinates.
POINT pt = { rc.left, rc.top };
POINT pt2 = { rc.right, rc.bottom };
ClientToScreen(m_hwnd, &pt);
ClientToScreen(m_hwnd, &pt2);
SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y);
// Confine the cursor.
ClipCursor(&rc);
ClipCursor mengambil struktur RECT , tetapi ClientToScreen mengambil struktur POINT . Persegi panjang ditentukan oleh titik kiri atas dan kanan bawahnya. Anda dapat membatasi kursor ke area persegi panjang apa pun, termasuk area di luar jendela, tetapi membatasi kursor ke area klien adalah cara umum untuk menggunakan fungsi tersebut. Membatasi kursor ke wilayah sepenuhnya di luar jendela Anda akan menjadi tidak biasa, dan pengguna mungkin akan menganggapnya sebagai bug.
Untuk menghapus pembatasan, panggil ClipCursor dengan nilai NULL.
ClipCursor(NULL);
Peristiwa Pelacakan Mouse: Arahkan kursor dan tinggalkan
Dua pesan mouse lainnya dinonaktifkan secara default, tetapi mungkin berguna untuk beberapa aplikasi:
- WM_MOUSEHOVER: Kursor telah mengarahkan kursor ke area klien untuk jangka waktu tertentu.
- WM_MOUSELEAVE: Kursor telah meninggalkan area klien.
Untuk mengaktifkan pesan ini, panggil fungsi TrackMouseEvent .
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = hwnd;
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&tme);
Struktur TRACKMOUSEEVENT berisi parameter untuk fungsi tersebut. Anggota struktur dwFlags berisi bendera bit yang menentukan pesan pelacakan mana yang Anda minati. Anda dapat memilih untuk mendapatkan WM_MOUSEHOVER dan WM_MOUSELEAVE, seperti yang ditunjukkan di sini, atau hanya salah satu dari keduanya. Anggota dwHoverTime menentukan berapa lama mouse perlu mengarahkan kursor sebelum sistem menghasilkan pesan hover. Nilai ini diberikan dalam milidetik. Konstanta HOVER_DEFAULT berarti menggunakan default sistem.
Setelah Anda mendapatkan salah satu pesan yang Anda minta, fungsi TrackMouseEvent direset. Anda harus memanggilnya lagi untuk mendapatkan pesan pelacakan lain. Namun, Anda harus menunggu hingga pesan pemindahan mouse berikutnya sebelum memanggil TrackMouseEvent lagi. Jika tidak, jendela Anda mungkin dibanjiri dengan pesan pelacakan. Misalnya, jika mouse melayang, sistem akan terus menghasilkan aliran pesan WM_MOUSEHOVER saat mouse diam. Anda sebenarnya tidak ingin pesan WM_MOUSEHOVER lain sampai mouse bergerak ke tempat lain dan mengarahkan kursor lagi.
Berikut adalah kelas pembantu kecil yang dapat Anda gunakan untuk mengelola peristiwa pelacakan mouse.
class MouseTrackEvents
{
bool m_bMouseTracking;
public:
MouseTrackEvents() : m_bMouseTracking(false)
{
}
void OnMouseMove(HWND hwnd)
{
if (!m_bMouseTracking)
{
// Enable mouse tracking.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = hwnd;
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&tme);
m_bMouseTracking = true;
}
}
void Reset(HWND hwnd)
{
m_bMouseTracking = false;
}
};
Contoh berikutnya menunjukkan cara menggunakan kelas ini dalam prosedur jendela Anda.
LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_MOUSEMOVE:
mouseTrack.OnMouseMove(m_hwnd); // Start tracking.
// TODO: Handle the mouse-move message.
return 0;
case WM_MOUSELEAVE:
// TODO: Handle the mouse-leave message.
mouseTrack.Reset(m_hwnd);
return 0;
case WM_MOUSEHOVER:
// TODO: Handle the mouse-hover message.
mouseTrack.Reset(m_hwnd);
return 0;
}
return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}
Peristiwa pelacakan mouse memerlukan pemrosesan tambahan oleh sistem, jadi biarkan dinonaktifkan jika Anda tidak membutuhkannya.
Untuk kelengkapan, berikut adalah fungsi yang mengkueri sistem untuk batas waktu hover default.
UINT GetMouseHoverTime()
{
UINT msec;
if (SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &msec, 0))
{
return msec;
}
else
{
return 0;
}
}
Roda Mouse
Fungsi berikut memeriksa apakah ada roda mouse.
BOOL IsMouseWheelPresent()
{
return (GetSystemMetrics(SM_MOUSEWHEELPRESENT) != 0);
}
Jika pengguna memutar roda mouse, jendela dengan fokus menerima pesan WM_MOUSEWHEEL . Parameter wParam dari pesan ini berisi nilai bilangan bulat yang disebut delta yang mengukur seberapa jauh roda diputar. Delta menggunakan unit arbitrer, di mana 120 unit didefinisikan sebagai rotasi yang diperlukan untuk melakukan satu "tindakan." Tentu saja, definisi tindakan tergantung pada program Anda. Misalnya, jika roda mouse digunakan untuk menggulir teks, setiap 120 unit rotasi akan menggulir satu baris teks.
Tanda delta menunjukkan arah rotasi:
- Positif: Putar maju, jauh dari pengguna.
- Negatif: Putar mundur, ke arah pengguna.
Nilai delta ditempatkan di wParam bersama dengan beberapa bendera tambahan. Gunakan makro GET_WHEEL_DELTA_WPARAM untuk mendapatkan nilai delta.
int delta = GET_WHEEL_DELTA_WPARAM(wParam);
Jika roda mouse memiliki resolusi tinggi, nilai absolut delta mungkin kurang dari 120. Dalam hal ini, jika masuk akal untuk tindakan terjadi dengan kenaikan yang lebih kecil, Anda dapat melakukannya. Misalnya, teks dapat menggulir dengan kenaikan kurang dari satu baris. Jika tidak, akumulasi total delta hingga roda berputar cukup untuk melakukan tindakan. Simpan delta yang tidak digunakan dalam variabel, dan ketika 120 unit terakumulasi (positif atau negatif), lakukan tindakan.
Berikutnya