2010-06-28 31 views
12

Tôi đang cố gắng nắm bắt đầu vào bàn phím và chuột toàn cầu.Tìm hiểu về móc chuột và bàn phím mức thấp (win32)

LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) { 
    if (nCode >= 0) { 
    if (wParam == WM_RBUTTONDOWN) printf("right mouse down\n"); 
    if (wParam == WM_RBUTTONUP) printf("right mouse up\n"); 
    } 
    return CallNextHookEx(0, nCode, wParam, lParam); 
} 

HHOOK mousehook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, NULL, 0); 
while(true) { 
    MSG msg; 
    if (PeekMessage(&msg,0,0,0,PM_REMOVE)) { 
    printf("msg recvd\n"); 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
    } 
#ifdef TEST 
    Sleep(50); 
#endif 
} 

Vì vậy, tất cả mọi thứ làm việc ở đây, ngoại trừ nếu tôi #define TEST để đưa vào các Sleep, chuột trở nên vô cùng chậm chạp, như thể được dự kiến ​​nếu tôi đột nhiên chỉ cho phép chuột để cập nhật 20 lần một giây. Và không có giấc ngủ, tôi đang chốt CPU ở mức 100%. Nhưng đó là okay cho bây giờ (mà đi xa nếu tôi sử dụng GetMessage). Bây giờ khi tôi hiểu nó, các móc mức thấp hoạt động bằng cách chuyển ngữ cảnh sang tiến trình đã cài đặt nó, và sau đó gửi quá trình một số loại thông điệp để cho phép nó thực hiện cuộc gọi móc. Điều gì làm tôi bối rối một chút, mặc dù, là lý do tại sao chương trình của tôi sẽ không bao giờ in "msg recvd", nhưng nó in "phải chuột xuống/lên" bất cứ khi nào tôi nhấp vào nút chuột phải. Điều này dẫn tôi đến kết luận rằng số MouseHookProc của tôi đang được gọi trong cuộc gọi PeekMessage. Nó chỉ xảy ra là một số loại tin nhắn đặc biệt và PeekMessage trả về 0. Nhưng tôi vẫn cần phải gọi PeekMessage hoặc một số tương đương.

Vì chương trình của tôi cần thực hiện nhiều thứ, tôi rõ ràng không thể cân nhắc vòng lặp truyền tin nhắn của tôi (gọi PeekMessage) bằng cách gọi một chức năng khác, mất 50ms để quay lại. Làm thế nào tôi có thể đa luồng chương trình của tôi để duy trì sự đáp ứng của chuột trong khi đồng thời thực hiện một việc nâng hạng nặng? Trong một chương trình win32 đa luồng, vẫn chỉ có một hàng đợi tin nhắn, đúng không?

Cập nhật: Sau khi đọc lên tài liệu của MS, tôi nghĩ rằng tôi biết điều tôi cần làm là gì. Tôi chỉ nên sinh ra một chuỗi trong ứng dụng của tôi, gọi số SetWindowsHookEx để đăng ký móc chuột, sau đó ngồi quanh vòng lặp tin nhắn riêng của nó và hệ thống sẽ xử lý việc gửi các bản cập nhật chuột cho chủ đề này. Nó sẽ được tự do làm bất cứ điều gì nó muốn trong các MouseHookProc, và phần còn lại của ứng dụng của tôi sẽ chạy độc lập.

+0

Bạn có 'MouseHookProc' bên trong một DLL và' SetWindowsHookEx' và 'PeekMessage' trong một EXE? – Oleg

+0

Tôi muốn tránh phải tiêm một DLL. Nó có vẻ phù hợp hơn cho nhu cầu của tôi cho hệ thống để chuyển sang chương trình của tôi để gọi nó là 'MouseHookProc', do đó tại sao tôi muốn sử dụng móc chuột mức thấp. Theo tôi hiểu nó, một móc chuột thông thường, nếu tôi muốn nó là toàn cục, phải sử dụng phương thức DLL. –

Trả lời

9

Vấn đề là vòng lặp thông điệp của bạn , nó ghi 100% chu kỳ CPU vì bạn sử dụng PeekMessage(). Windows biết cách giữ móc sống ngay cả khi bạn không bình chọn thư, sử dụng GetMessage() để giải quyết vấn đề của bạn. Sử dụng Sleep (1) cũng sẽ giải quyết vấn đề của bạn nhưng không cần thiết ở đây.

Why must SetWindowsHookEx be used with a windows message queue

3

Thay vì thực hiện:

if (PeekMessage(&msg,0,0,0,PM_REMOVE)) { 
    printf("msg recvd\n"); 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
} 
Sleep(50); 

Chuyển này để:

while (PeekMessage(&msg,0,0,0,PM_REMOVE)) { 
    // Add this potentially... 
    if (msg.message == WM_QUIT) 
     break; 
    printf("msg recvd\n"); 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
} 
Sleep(10); 

này sẽ cho phép ứng dụng của bạn để tiếp tục xử lý tất cả các thông điệp trong hàng đợi cho đến khi nó là rỗng (như không có giấc ngủ), rồi từ bỏ một số thời gian CPU khi ứng dụng "không hoạt động".

3

MouseHookProc nên cư trú tại dll, nếu không bạn không thể nắm bắt được "toàn cầu" đầu vào (http://msdn.microsoft.com/en-us/library/ms997537.aspx)

Về vòng lặp - bạn có thể sửa đổi nó như thế này:

while(true) { 
    MSG msg; 
    while (PeekMessage(&msg,0,0,0,PM_REMOVE)) { 
    printf("msg recvd\n"); 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
    } 
#ifdef TEST 
    DoStuff(); 
    Sleep(50); 
#endif 
} 
+4

Một móc chuột cấp thấp không * không * yêu cầu một DLL, nó không phải là một móc toàn cầu như WH_MOUSE. –

6

tôi aksed bạn cho dù bạn đặt nơi MouseHookProc trong DLL, vì cố gắng đặt nó bên trong một EXE đó là một lỗi điển hình. Tôi đã làm nó nhiều năm trước.

Trước hết, làm thế nào bạn có thể đọc trong http://msdn.microsoft.com/en-us/library/ms644990.aspx:

SetWindowsHookEx có thể được sử dụng để tiêm một DLL vào một quá trình. Không thể tiêm một tệp 322 DLL vào quy trình 64 bit và một DLL 64 bit không thể được tiêm vào quy trình 32 bit. Nếu một ứng dụng yêu cầu sử dụng móc trong các quá trình khác, nó là cần thiết mà một ứng dụng 32-bit gọi SetWindowsHookEx để tiêm một 32-bit DLL vào các quá trình 32-bit, và một 64-bit gọi ứng dụng SetWindowsHookEx để tiêm một bitDLL vào các quy trình 64 bit. 322 bitvà 64-bit DLL phải có các tên khác nhau.

Vì vậy, bạn phải đặt trong một DLL. Để được chính xác nếu bạn muốn hỗ trợ cả hai nền tảng 32-bit và 64-bit, bạn phải thực hiện hai dlls: một 32-bit và 64-bit DLL. Nhưng tại sao? Và cách hoạt động của SetWindowsHookEx?

Nếu bạn thực hiện trong một EXE mã như sau

HINSTANCE hinstDLL = LoadLibrary(TEXT("c:\\myapp\\syshook.dll")); 
HOOKPROC hkprcMouse = (HOOKPROC)GetProcAddress(hinstDLL, "MouseHookProc"); 
HHOOK hhookMouse = SetWindowsHookEx( 
        WH_MOUSE_LL, 
        hkprcMouse, 
        hinstDLL, 
        0); 

bạn cung cấp cho user32.dll yêu cầu phải tiêm bạn syshook.dll trong tất cả các quá trình khác trên trạm cửa sổ tương tự (dll sẽ không được đưa vào các dịch vụ và quy trình của những người dùng khác được đăng nhập thông qua chuyển đổi người dùng nhanh). Sau đó, user32.dll gọi LoadLibrary đến syshook.dll trong các quy trình khác nhau. Sau đó, nếu hàm MouseHookProc sẽ được gọi, sẽ được gọi trong ngữ cảnh của quá trình xử lý thông báo chuột. Nếu quy trình không phải là ứng dụng bảng điều khiển, mã như

printf("right mouse down\n"); 

không thể hoạt động.

Vì vậy, tôi hy vọng bây giờ bạn sẽ hủy bỏ lý do tại sao bạn phải đặt MouseHookProc trong một DLL.

+2

Tôi nghĩ rằng có thể có một số nhầm lẫn ở đây. Hiện tại, tôi đã tìm ra được mọi thứ tôi cần từ chủ đề này: http://stackoverflow.com/questions/2060345/in-what-thread-does-a-low-level-mouse-and-keyboard- hook-callback-run Cảm ơn bạn đã dành thời gian trợ giúp! –

+2

Đó là thông tin rất thú vị! Nó rất thú vị rằng 'WH_MOUSE_LL' là một ngoại lệ của quy tắc tiêm DLL đại tá. Cảm ơn! Tôi khuyên bạn nên sử dụng "Gửi nhận xét về chủ đề này cho Microsoft" trên http://msdn.microsoft.com/en-us/library/ms644990.aspx để đề xuất Microsoft thay đổi một tài liệu nhỏ về 'SetWindowsHookEx' corespond thành thông tin từ http://msdn.microsoft.com/en-us/library/ms644986.aspx. – Oleg

+0

vì vậy bạn đang nói với WH_MOUSE_LL nó hoạt động mà không có trong một DLL, nhưng đối với các loại tin nhắn khác nó phải nằm trong một dll? – rogerdpack

Các vấn đề liên quan