When I put the hook on the mouse, I periodically lose sensitivity, it increases by ~0.3 seconds (approximately twice). How can I fix this?
My handler code:
LRESULT CALLBACK mouseProc(int Code, WPARAM wParam, LPARAM lParam){
MOUSEHOOKSTRUCT* pMouseStruct = (MOUSEHOOKSTRUCT*)lParam;
if (pMouseStruct != nullptr) {
switch (wParam) {
case WM_LBUTTONDOWN:
std::cout << "WM_LBUTTONDOWN";
break;
case WM_LBUTTONUP:
std::cout << "WM_LBUTTONUP";
break;
case WM_RBUTTONDOWN:
std::cout << "WM_RBUTTONDOWN";
break;
case WM_RBUTTONUP:
std::cout << "WM_RBUTTONUP";
break;
default:
break;
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);}
I put the hook this way:
HHOOK hook = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, NULL, 0);
MSG message;
while (GetMessage(&message, NULL, 0, 0) > 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
UnhookWindowsHookEx(hook);
You lose sensitivity in this code, because std::cout is very slow. You need a very quick response for this hooking or you obviously lose sensitivity.
If you really need to log in your hook, use something like spdlog and log everything asynchronously.
In addition, as Richard mentioned in comments, you need something like this at start of your hook:
if (nCode < 0) // do not process message
return CallNextHookEx(hhook, nCode, wParam, lParam);
Related
How do I get my mousehook to callback from a seperate thread, to avoid it from interfering with my mainthread, and causing mouselag?
HHOOK Mousehook;
int trial=0; //paintflag for testing
LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case WM_LBUTTONDOWN:
trial = 1; //set paintflag
InvalidateRect(hWnd, NULL, TRUE);
break;
case WM_RBUTTONDOWN:
PostQuitMessage(0);
break;
default:
break;
}
return CallNextHookEx(Mousehook, nCode, wParam, lParam);
}
this is the function I have, and it is called with
Mousehook = SetWindowsHookEx(WH_MOUSE_LL, HookCallback, NULL, 0);
But I have no idea how to make all that into a seperate thread and single call.
Anyone know a good way? Any help would be much appreciated, is it even possible like this?
I found out how to do it. Atleast for now, this is how I made a designated thread for my mousehook, so that it can run in the background:
declaring my hook and the callback routine
HHOOK Mousehook;
LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case WM_LBUTTONDOWN: //incase lmb down
//
break;
case WM_RBUTTONDOWN: //incase of rmb down
//
break;
default:
break;
}
return CallNextHookEx(Mousehook, nCode, wParam, lParam);
}
This is old news however, so whats the trick? First off add threading
#include <thread>
using std::thread //for convenience
then we make the function that the thread runs:
void mhook()
{
MSG msg;
Mousehook = SetWindowsHookEx(WH_MOUSE_LL, HookCallback, NULL, 0);
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
this will keep the thread waiting for msg'es. Now all we need to do is create the thread like so:
thread listen(mhook);
this will make a thread that hooks and listens for mouseactions, without disturbing your main thread.
I have wrote a window hook to retrieve the mouse events
_handle = SetWindowsHookEx(WH_MOUSE,
(HOOKPROC)KeyEvent,
nullptr,
GetCurrentThreadId());
static LRESULT WINAPI KeyEvent(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode >= 0)
{
MOUSEHOOKSTRUCT* mStruct = ( MOUSEHOOKSTRUCT*)lParam;
MSLLHOOKSTRUCT* mWheelDStruct = (MSLLHOOKSTRUCT*)lParam;
CMouseHookCom::_this->ReportEventW(mStruct->hwnd, wParam, mWheelDStruct);
}
return(CallNextHookEx(NULL, nCode, wParam, lParam));
}
case WM_MOUSEWHEEL:
OutputDebugString(L"CMouseHookCom-WM_MOUSEWHEEL");
strm = (MSLLHOOKSTRUCT*)extraData;
zDelta = (short)(HIWORD(((MSLLHOOKSTRUCT*)extraData)->mouseData));
_stprintf(buffer, L"CMouseHookCom - WM_MOUSEWHEEL delta %d %i", zDelta, short((strm->mouseData >> 16) & 0xffff));
OutputDebugString(buffer);
if (zDelta > 0)
{
OutputDebugString(L"CMouseHookCom-WM_MOUSEWHEEL UP");
Invoke_onScrollOut(componentId);
}
else
{
OutputDebugString(L"CMouseHookCom-WM_MOUSEWHEEL DOWN");
Invoke_onScrollIn(componentId);
}
break;
default:
_stprintf(buffer, L"CMouseHookCom - UnHandleled event %d", event);
OutputDebugString(buffer);
break;
}
no matter how I try I always get positive results of the wheel. Also I always get different value. What is the correct way to retrieve the data?
You should use Raw Input instead of a mouse hook. That is less overhead on the OS to monitor the mouse, and it gives you information that a hook would not.
my program knows 2 states: A annd B, where A is the default state.
When you press ALT-# it should change it's state to B and when you release the combination it should go back to A.
This should work with a LowLevel Keyboard hook but it seems I am stuck somewhere.
#define VK_POUND 0xBF // 191 - the # key
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
KBDLLHOOKSTRUCT* kbdStruct = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
switch (wParam) {
case WM_KEYDOWN: {
std::cout << kbdStruct->vkCode << "\n";
if (kbdStruct->vkCode == VK_POUND && kbdStruct->flags & LLKHF_ALTDOWN) {
MessageBox(NULL, "WE GOT IT", "", MB_OK);
}
} break;
case WM_KEYUP: {
} break;
}
}
return CallNextHookEx(g_HotKeyHook, nCode, wParam, lParam);
}
What confuses me: When I press the combination ALT and # there is no output in the console.
I've created a custom message type for use in resizing my Window, called WM_NEED_RESIZE. I've defined it in my .h file, and initialized in my .cpp file. I have also registered my WindowProc function to accept messages. Here is the code for these items:
const uint32 WindowsGLWindow::WM_NEED_RESIZE = WM_USER + 100;
LONG WINAPI WindowsGLWindow::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static PAINTSTRUCT ps;// do I need this?
static sint32 newWidth = 0;
static sint32 newHeight = 0;
bool res = false;
switch (uMsg) {
case WM_PAINT:
//display();
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;
case WM_SIZE:
//glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
res = PostMessage(hWnd, WindowsGLWindow::WM_NEED_RESIZE, wParam, lParam);
std::cout << "WM_SIZE: " << res << std::endl;
return 0;
case WindowsGLWindow::WM_NEED_RESIZE:
std::cout << "WindowsGLWindow::WM_NEED_RESIZE" << std::endl;
break;
case WM_CHAR:
switch (wParam) {
case 27: /* ESC key */
PostQuitMessage(0);
break;
}
return 0;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
In another function I am running through PeekMessage(..) to collect all messages. Here is the snippet of the message pump:
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) == TRUE) // maybe use GetInputState(?) as well?
{
if (msg.message == WM_QUIT)
retVal = -1;
if (msg.message == WindowsGLWindow::WM_NEED_RESIZE) {
uint32 newWidth = LOWORD(msg.lParam);
uint32 newHeight = HIWORD(msg.lParam);
std::cout << "PeekMessage: WindowsGLWindow::WM_NEED_RESIZE" << std::endl;
// call resize only if our window-size changed
if ((newWidth != width_) || (newHeight != height_)) {
resize(newWidth, newHeight);
}
PostMessage(msg.hwnd, WM_PAINT, 0, 0);
}
switch (msg.message) {
case WM_MOUSEMOVE:
// Retrieve mouse screen position
//int x = (short) LOWORD(lParam);
//int y = (short) HIWORD(lParam);
// Check to see if the left button is held down:
//bool leftButtonDown = wParam & MK_LBUTTON;
// Check if right button down:
//bool rightButtonDown = wParam & MK_RBUTTON;
break;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_KEYUP:
case WM_KEYDOWN:
/*
switch (msg.wParam) {
case 'W':
// w key pressed
break;
case VK_RIGHT:
// Right arrow pressed
break;
default:
break;
}
*/
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
My problem is that the WM_NEED_RESIZE message is only found once in the message queue when the window first opens, after which it is never found in the message queue by my PeekMessage(..). I'm really not sure why this is happening. It is, however, being received by the WindowProc(..) method (which doesn't really help me). I would appreciate any help you guys could provide.
Thanks
Jarrett
Dont use std::cout expecting to see that output in your debugger, insted use OutputDebugString(); .
You need to pass your class pointer to the last parameter of your call to CreateWindowEx, then retrieve that pointer from the LPCREATESTRUCT passed to you in the LPARAM of WM_CREATE, your class pointer will be in the lpCreateParmas feild of the struct. Set your clas pointer to the GWLP_USERDATA of your window, and on any other message calls , call GetWindowsLong , retrieve your class pointer, then pass the message, wparam, and lparam all off to your internal class message handler.
http://msdn.microsoft.com/en-us/library/ff381400%28v=VS.85%29.aspx
The message pump loop that you are showing will exit as soon as the queue is empty. I can't tell from what you've posted if it ever gets entered again.
If this is your main message pump, you should use GetMessage() instead, as it will wait until something is available before returning. Take a look at this MSDN article for more info.
I am doing a voice chat application which uses a push-to-talk key. I have done a hook so it will register push-to-talk outside application too.
HHOOK hHook = SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)pushtotalk,0,0);
LRESULT CALLBACK pushtotalk(int key, WPARAM wParam,LPARAM lParam) {
if (key < 0) {
return (CallNextHookEx(hook,key,wParam,lParam));
}
else if (connected) {
KBDLLHOOKSTRUCT* kbdll = (KBDLLHOOKSTRUCT*)lParam;
if (kbdll ->vkCode == 75 && wParam == WM_KEYDOWN) {
MessageBox(mainhWnd,"KEYSTART","KEYSTART",0);
}
else if (kbdll ->vkCode == 75 && wParam == WM_KEYUP) {
MessageBox(mainhWnd,"KEYSTOP","KEYSTOP",0);
}
}
return (CallNextHookEx(hook,key,wParam,lParam));
}
Problems;
1) Sometimes, (for example the first execution of the proc in the application), the proc causes a 5 sec system freeze before continuing. Why?
2) The hook only works on process that were started before my application started, if I start a text program after starting my application, the hooks wont register. Is there a fix for this?
3) If I hold down the key for ~3 seconds, alot of MessageBoxes shows obviously, but after that, the proc will never register another key being pushed down, so I guess I somehow gets disconnected from the hook chain?
Cheers
EDIT: Here's the main message loop for the application
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch(message) {
case WM_COMMAND:
switch (LOWORD(wParam)) {
case ID_MENU_EXIT:
SendMessage(hWnd,WM_CLOSE,0,0);
break;
case ID_MENU_PREFERENCES:
voiceManager->send((void*) "1");
break;
case ID_BUTTON_CONNECT:
onConnect(hWnd);
break;
case ID_BUTTON_DISCONNECT:
onDisconnect(hWnd);
break;
case ID_BUTTON_SEND:
onSendText(hWnd);
break;
default:
break;
}
break;
case SOCKET_TCP:
switch (lParam) {
case FD_READ:
{
// Disable repeated FD_READ call while we process message
WSAAsyncSelect(wParam,hWnd,SOCKET_TCP, FD_WRITE | FD_ACCEPT | FD_CLOSE);
// first four bytes is packet size
// second four bytes are used to identify type of msg
char* psize = (char*)malloc(5);
char* ptype = (char*)malloc(5);
psize[4] = '\0';
ptype[4] = '\0';
recv(wParam,psize,4,0);
recv(wParam,ptype,4,0);
// allocate memory for the buffer
int size_to_recv = atoi(psize);
char* textbuff = (char*)malloc(size_to_recv);
// receive
int i = size_to_recv;
while (i > 0) {
int read = recv(wParam,textbuff,i,0);
i = i - read;
}
// handle msg depending on type
switch(identifyMsg(ptype)) {
case 1:
// handle 'text' msg
onReadText(hWnd,textbuff);
break;
case 2:
// handle 'name' msg
onReadName(hWnd,textbuff);
break;
case 3:
// handle 'list' msg
onReadList(hWnd,textbuff);
break;
case 4:
// handle 'remv' msg
onReadRemv(hWnd,textbuff,size_to_recv);
break;
case 5:
// handle 'ipad' msg -- add ip
voiceManager->addParticipant(inet_addr(textbuff));
break;
case 6:
// handle 'iprm' msg -- remove ip
voiceManager->removeParticipant(inet_addr(textbuff));
break;
default:
break;
}
// re-enable FD_READ
WSAAsyncSelect(wParam,hWnd,SOCKET_TCP, FD_WRITE | FD_ACCEPT | FD_READ | FD_CLOSE);
// free resources
free(psize);
free(ptype);
free(textbuff);
break;
}
case FD_WRITE:
break;
case FD_CONNECT:
break;
case FD_CLOSE:
onDisconnect(hWnd);
break;
default:
break;
}
break;
case WM_PAINT:
paintText(hWnd);
break;
case WM_DESTROY:
shutdownConnection(hWnd);
// reset window procs
SetWindowLong(GetDlgItem(hWnd,ID_EDIT_SEND), GWL_WNDPROC,(LONG) OriginalEditProc);
SetWindowLong(GetDlgItem(hWnd,ID_EDIT_IP), GWL_WNDPROC,(LONG) OriginalEditProc);
PostQuitMessage(0);
return 0;
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
default:
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT CALLBACK sendEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == WM_CHAR) {
if (wParam == VK_RETURN) {
onSendText(GetParent(hWnd));
return 0;
}
}
if (message == WM_KEYUP || message == WM_KEYDOWN) {
if (wParam == VK_RETURN) {
return 0;
}
}
return CallWindowProc(OriginalEditProc, hWnd, message, wParam,lParam);
}
Where sendEditProc is a sub/superclass designed to intercept 'enter' keys when inside an edit control 'send'
Does this help?
Here's the message loop; it's the standard so nothing fancy that could go wrong afaik :)
while (GetMessage(&msg, NULL,0,0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
You're calling CallNextHookEx one too many times. If key < 0 return CallNextHookEx, otherwise return 0.
The problem you're seeing has to do with keyboard repeats and the MessageBox or MessageBeep methods being very, very expensive calls. Try this test:
HHOOK hHook;
BOOL bTalkEnabled = FALSE;
LRESULT CALLBACK pushtotalk(int key, WPARAM wParam, LPARAM lParam)
{
if (key < 0)
return CallNextHookEx(hHook, key, wParam, lParam);
KBDLLHOOKSTRUCT* kbdll = (KBDLLHOOKSTRUCT*)lParam;
if (kbdll->vkCode == VK_F11)
{
BOOL bStarted = FALSE;
BOOL bStopped = FALSE;
if (wParam == WM_KEYDOWN)
{
if (!bTalkEnabled)
{
bStarted = TRUE;
bTalkEnabled = TRUE;
}
}
else if (wParam == WM_KEYUP)
{
if (bTalkEnabled)
{
bStopped = TRUE;
bTalkEnabled = FALSE;
}
}
if (bStarted)
OutputDebugString(L"Pushed\r\n");
if (bStopped)
OutputDebugString(L"Released\r\n");
}
return 0;
}
You can monitor the debug strings by running the app under the debugger (check the Output window), or you can get DebugView and watch that.
Notice that I do not check for connected as you did. You don't want to perform that check in the hook, do that outside the hook and only use the hook to determain if the key is pressed or not pressed.