I try to track mouse with code like this:
#include <Windows.h>
#include <iostream>
HHOOK hMouseHook;
LRESULT CALLBACK mouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MOUSEHOOKSTRUCT* pMouseStruct = (MOUSEHOOKSTRUCT*)lParam;
if (pMouseStruct != NULL)
printf("X: %d Y: %d\n", pMouseStruct->pt.x, pMouseStruct->pt.y);
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}
int main() {
hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, 0, 0);
MSG message;
while (GetMessage(&message, NULL, 0, 0)) {
TranslateMessage(&message);
DispatchMessage(&message);
}
UnhookWindowsHookEx(hMouseHook);
return 0;
}
And this works mostly good except one case. When I click on app console window mouse become very laggy. CPU usage is ok, and I can hit "enter" to "unfreeze" mouse. I can't figure out what I messed up.
Related
running this code leads to the title question:
if you resize the window you will not see any flicker (repaint sended by the system)
if you move mouse inside the window, severe flicker will occurr (repaint sended by me)
how to reproduce the system-driven WM_PAINT?
#include <windows.h>
#include <wingdi.h>
LRESULT CALLBACK proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
case WM_ERASEBKGND: return true;break;
case WM_MOUSEMOVE: InvalidateRect(hwnd, 0, 0); break;
case WM_PAINT:
{
InvalidateRect(hwnd,0,0);
HBRUSH b= CreateSolidBrush(0x000000ff);
HBRUSH c= CreateSolidBrush(0x0000ff00);
HBRUSH d= CreateSolidBrush(0x00ff0000);
RECT r;
GetClientRect(hwnd,&r);
PAINTSTRUCT ps;
HDC hdc=BeginPaint(hwnd,&ps);
FillRect(hdc,&r, b);
Sleep(10);
FillRect(hdc,&r, c);
` Sleep(10);
FillRect(hdc,&r,d);
EndPaint(hwnd,&ps);
DeleteObject(b);
DeleteObject(c);
DeleteObject(d);
}
break;
default:
return DefWindowProc(hwnd, msg, wparam, lparam);
}
return 0;
}
int main()
{
HWND hwnd=CreateWindow(WC_DIALOG,0,WS_OVERLAPPEDWINDOW|WS_VISIBLE,0,0,500,500,0,0,0,0);
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)proc);
MSG msg;
while (true)
{
if (GetMessage(&msg, 0, 0, 0) != WM_CLOSE)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 1;
}
You should not invalidate the window if the mouse only moves over it because that will lead to a WM_PAINT message ultimately. That causes the flicker (in combination with the sleep).
I'm trying to hook WH_GETMESSAGE from my class to determine the moment when specific window is resizing. However, looks like the hook isn't set.
Class from where I try to hook:
class WindowDisplayHelper : // public ...
{
public:
// some other public methods here
void SetMsgHook();
protected:
LRESULT CALLBACK GetMsgProcHook(int code, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK MsgPoc(int code, WPARAM wParam, LPARAM lParam);
private:
// some other private members there
HWND m_windowHandle;
bool m_isWindowResizing = false;
static HHOOK m_msgHook;
static WindowsDisplayHelperMasterWindow* m_pThis;
};
.cpp file:
WindowDisplayHelper* WindowDisplayHelper ::m_pThis = nullptr;
HHOOK WindowDisplayHelper ::m_msgHook = NULL;
void WindowDisplayHelper ::SetMsgHook()
{
m_pThis = this;
m_msgHook = SetWindowsHookEx(WH_GETMESSAGE, MsgPoc, NULL, 0);
}
LRESULT CALLBACK WindowDisplayHelper::MsgPoc(int code, WPARAM wParam, LPARAM lParam)
{
if (m_pThis != nullptr)
{
return m_pThis->GetMsgProcHook(code, wParam, lParam);
}
return CallNextHookEx(0, code, wParam, lParam);
}
LRESULT CALLBACK WindowDisplayHelper::GetMsgProcHook(int code, WPARAM wParam, LPARAM lParam)
{
DUMPER_INFO("Hooked");
if (code < 0)
{
return CallNextHookEx(0, code, wParam, lParam);
}
MSG* lpmsg = (MSG*)lParam;
DUMPER_INFO("Hooked for HWND: %p. Current window %p", lpmsg->hwnd, m_windowHandle);
if (lpmsg->hwnd != m_windowHandle)
{
return CallNextHookEx(0, code, wParam, lParam);
}
if (lpmsg->message == WM_ENTERSIZEMOVE && !m_isWindowResizing)
{
DUMPER_INFO("Start window resizing");
m_isWindowResizing = true;
}
else if (lpmsg->message == WM_EXITSIZEMOVE && m_isWindowResizing)
{
DUMPER_INFO("Stop window resizing");
m_isWindowResizing = false;
}
return CallNextHookEx(0, code, wParam, lParam);
}
Here is how I create WindowDisplayHelper object:
bool DisplayManager::CreateWindowDisplay(TDisplayId displayId, void * windowHandle)
{
auto helper = boost::make_shared<WindowDisplayHelper>(windowHandle);
helper->SetMsgHook();
AddDisplayHelper(displayId, helper);
return true;
}
Though I call SetMsgHook() after the object is created, looks like hook isn't set, because I don't see any debug outputs in my log file and m_isWindowResizing variable always == false. So the question is why my hook doesn't work?
Thanks.
m_msgHook = SetWindowsHookEx(WH_GETMESSAGE, MsgPoc, NULL, 0);
This line produce a ERROR_HOOK_NEEDS_HMOD (1428) system error. It means that Cannot set nonlocal hook without a module handle. If you set dwThreadId parameter to zero, the hook procedure is associated with all existing threads running in the same desktop as the calling thread. It is a nonload hook you need specified a valid hmod parameter. You need put the hook code in a DLL as #Remy Lebeau pointed out.
Or set a valid dwThreadId parameter using GetCurrentThreadId() as #rudolfninja pointed out.
I test based on a Windows Desktop Application Template with the following code. It works. You can have a try.
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
// ...
HHOOK m_msgHook = SetWindowsHookEx(WH_GETMESSAGE, MsgPoc, NULL, GetCurrentThreadId());
DWORD errCode = GetLastError();
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
LRESULT CALLBACK MsgPoc(int code, WPARAM wParam, LPARAM lParam)
{
OutputDebugString(L"Hooked");
if (code < 0)
{
return CallNextHookEx(0, code, wParam, lParam);
}
MSG* lpmsg = (MSG*)lParam;
//OutputDebugString("Hooked for HWND: %p. Current window %p", lpmsg->hwnd, m_windowHandle);
if (lpmsg->hwnd != m_windowHandle)
{
return CallNextHookEx(0, code, wParam, lParam);
}
if (lpmsg->message == WM_ENTERSIZEMOVE && !m_isWindowResizing)
{
OutputDebugString(L"Start window resizing");
m_isWindowResizing = true;
}
else if (lpmsg->message == WM_EXITSIZEMOVE && m_isWindowResizing)
{
OutputDebugString(L"Stop window resizing");
m_isWindowResizing = false;
}
return CallNextHookEx(0, code, wParam, lParam);
}
Windows 10 (1607) - ElementFromPoint call duration near 2 ms.
After Windows 10 Creators Update (1703) - ElementFromPoint call duration near 500ms.
#include <Windows.h>
#include <UIAutomationClient.h>
IUIAutomation* g_automation = nullptr;
LRESULT CALLBACK LowLevelMouseProc(INT nCode, WPARAM wParam, LPARAM lParam)
{
POINT pt = ((PMSLLHOOKSTRUCT)lParam)->pt;
IUIAutomationElement *element = nullptr;
g_automation->ElementFromPoint(pt, &element);
return CallNextHookEx(0, nCode, wParam, lParam);
}
void main()
{
CoInitializeEx(NULL, COINIT_SPEED_OVER_MEMORY);
CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER,
__uuidof(IUIAutomation), (void**)& g_automation);
SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)LowLevelMouseProc,
GetModuleHandle(nullptr), 0);
MSG message;
GetMessage(&message, (HWND)NULL, 0, 0);
}
Point is mouse click coordinates.
Too long ElementFromPoint - this is issue.
Looks like some changed in COM/UIAutomation processing?
Is exist some workaround get UI element from point?
I can't seem to find what I am looking for which is a way to alter the OS's mouse clicks. To specify this would be on Windows.
The goal is to limit the number of mouse clicks a user can register within a period of time.
I think the function that you are looking for is SetWindowsHookEx. Here is a quick example.
#include <windows.h>
const DWORD desireddelay = 10;
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
static DWORD previoustimestamp = 0;
if ((nCode == 0) && (wParam == WM_RBUTTONDOWN))
{
if ((((MSLLHOOKSTRUCT*)lParam)->time - previoustimestamp) < desireddelay)
{
return 1; //Non-Zero Swallows the keystroke. 0 Allows it. Always CallNextHookEx if you are not swallowing it.
}
else
{
previoustimestamp = ((MSLLHOOKSTRUCT*)lParam)->time;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main()
{
HHOOK hook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, GetModuleHandle(NULL), NULL);
MSG msg;
bool done = false;
while (GetMessage(&msg, NULL, NULL, NULL)) {}
UnhookWindowsHookEx(hook);
return 0;
}
I want the mouse cursor to lock on a specified point on X or Y axis respectively. I managed to accomplish this with low level mouse proc and keyboard proc (need the keyboard proc as input for what movement the user desires the mouse to follow - vertical or horizontal). However, my problem is that -while in locked movement, say horizontal with F7- when I hit a mouse button or use the mouse wheel, the locked movement is released for some weird reason I am unable to understand and I obviously don't want it to be released unless the user says so (ie by hitting F6). Here is the code you can check it and see the problem I am talking about :
#define _WIN32_WINNT 0x0501
#include <iostream>
#include <windows.h>
using namespace std;
bool block = false;
POINT p;
HHOOK hHook,hHook2;
unsigned int status = 0;
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
KBDLLHOOKSTRUCT key;
memcpy(&key,(void*)lParam,sizeof(KBDLLHOOKSTRUCT));
if( wParam == WM_KEYDOWN)
{
if(key.vkCode == VK_F7)
{
//Horizontal only
if (GetCursorPos(&p)) status = 1;
}
else if(key.vkCode == VK_F8)
{
//Vertical only
if (GetCursorPos(&p)) status = 2;
}
else if(key.vkCode == VK_F6)
{
//Normal
status = 0;
}
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MSLLHOOKSTRUCT key;
memcpy(&key,(void*)lParam,sizeof(MSLLHOOKSTRUCT));
if(wParam == WM_MOUSEMOVE)
{
if(status == 1)
{
SetCursorPos(key.pt.x,p.y);
}
else if(status == 2)
{
SetCursorPos(p.x,key.pt.y);
}
else
{
return CallNextHookEx(hHook2, nCode, wParam, lParam);
}
}
else
{
return CallNextHookEx(hHook2, nCode, wParam, lParam);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
cout<<"F7 to allow Horizontal moving ONLY"<<endl;
cout<<"F8 to allow Vertical moving ONLY"<<endl;
cout<<"F6 to move freely"<<endl;
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, 0);
hHook2 = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, hInstance, 0);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
You probably have a low-level hook in your application which takes longer than i believe 200ms or you have a breakpoint set in debugger; this will cause Windows to unregister your window hook.