Mouse lock horizontal / vertical movement - c++

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.

Related

Lags while using windows hooks

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.

SetWindowsHookEx stops receiving WH_MOUSE_LL events when window focus lost

I have an SDL2 program that opens an SDL window. In the main I create a hook for mouse events as
hMSHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, NULL, NULL);
while outside of the main I have the custom mouse event handler
HHOOK hMSHook;
int xPosAbsolute = 0;
int yPosAbsolute = 0;
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
auto &ms = *(const MOUSEHOOKSTRUCT *)lParam;
if (wParam == WM_MOUSEMOVE)
{
xPosAbsolute = ms.pt.x;
yPosAbsolute = ms.pt.y;
}
}
return CallNextHookEx(hMSHook, nCode, wParam, lParam);
}
When the window is in focus, the mouse coordinates xPosAbsolute and yPosAbsolute are properly updated as the mouse moves. However, if another window receives focus, these variables stop being updated.
My question is, how do I make SetWindowsHookEx() continue receiving WH_MOUSE_LL events while my window is not in focus?
EDIT:
Actually, as it turns out, SetWindowsHookEx only stopped receiving event updates when the window focus was lost to another window that was launched as administrator, while the SDL2 window of this program was launched as a regular user. Once the current program is launched as administrator as well, all updates continue to come in (using the above code), even when window focus is lost. So this turned out to be a non-issue.
Focus is not required but keep pumping messages is required.
The following is a mini Win32 window application with low level hook you can refer to. It will receive WM_MOUSEMOVE message in all existing threads running in the same desktop as the calling thread regardless of which window holds the focus.
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
auto& ms = *(const MOUSEHOOKSTRUCT*)lParam;
if (wParam == WM_MOUSEMOVE)
{
OutputDebugString(L"\n WM_MOUSEMOVE \n");
OutputDebugStringA(to_string(counter++).c_str());
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
HHOOK hMSHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, NULL, NULL);
WNDCLASSEXW wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = szWindowClass;
RegisterClassExW(&wcex);
HWND hWnd = CreateWindowW(szWindowClass, L"test", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}

Is there a way I can handle mouse movement and execute a MessageBeep?

Is there a way to identify the mouse movement ?
I want to take some action when the mouse moves,
I did a Google search and found that it can be done with WM_MOUSEMOVE, WM_MOUSEMOVE Is taking handle of the mouse movement
But when I use WM_MOUSEMOVE, nothing happens.
I want the program to detect mouse movement, and then MessageBeep will be called.
Example:
LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CREATE: {
}
break;
case WM_DESTROY: {
PostQuitMessage(0);
}
break;
case WM_MOUSEMOVE: {
MessageBeep(MB_ICONERROR);
}
break;
default:
return DefWindowProc(hwnd, msg, wparam, lparam);
}
return 0;
}
It works but there is a problem, it is a bit stuck, when I don't move the mouse the program do MessageBeep and also when I move then the mouse program sometimes do MessageBeep and sometimes not.
I have also tried with MessageBox but now it just spamming the right corner in the screen with MessageBoxes, Even when I'm not moving the mouse.
From the comments, it seems that you don't want to be limited to detecting whether the mouse moves in the program, and you want to call that beep when the mouse stops moving.
So you can do it by setting the timer and hook.
An application installs the hook procedure by specifying the
WH_MOUSE_LL hook type and a pointer to the hook procedure in a call to
the SetWindowsHookEx function.
If you are unfamiliar with using hooks.Don't worry. There are special documents to explain how to use hooks.
Hooks Overview
SetWindowsHookEx for WH_MOUSE
Don't forget to use GetLastInputInfo which can retrieve the time of the last input event.
Please note: This GetLastInputInfo function takes into consideration ALL input events, not just mouse events.
How to use GetLastInputInfo? Refer #Roger Rowland's answer.
For details, please see my code.
#include <Windows.h>
#include <iostream>
#pragma comment(lib,"Winmm.lib")
using namespace std;
HHOOK mouseHook;
static DWORD t1;
DWORD GetIdleTime()
{
LASTINPUTINFO pInput;
pInput.cbSize = sizeof(LASTINPUTINFO);
if (!GetLastInputInfo(&pInput))
{
// report error, etc.
}
return pInput.dwTime;
}
void CALLBACK f(HWND hwnd, UINT uMsg, UINT timerId, DWORD dwTime)
{
DWORD t2 = GetIdleTime();
if (t2 != t1) //When the mouse is moving, t1 == t2
{
MessageBeep(MB_ICONERROR);
}
cout << "t1: " << t1 << endl; //For test
cout << "t2: " << t2 << endl;
cout << endl;
}
LRESULT __stdcall MouseHookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
Sleep(10); //Used to correct the value of t1
t1 = GetIdleTime();
}
return CallNextHookEx(mouseHook, nCode, wParam, lParam);
}
void SetHook()
{
if (!(mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookCallback, NULL, 0)))
{
cout << "Failed to install mouse hook!" << endl;
}
}
void ReleaseHook()
{
UnhookWindowsHookEx(mouseHook);
}
int main()
{
SetHook(); //Install hook
SetTimer(NULL, 0, 3000, (TIMERPROC)&f); //Check every three seconds
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Debug:
If mouse is moving, t1 == t2.
If mouse stop moving, t1 != t2. MessageBeep will be called.
If you don't need a console, please replace int main() with int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

Hook WH_GETMESSAGE message

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);
}

Control OS mouse clicks

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;
}