How to change the right with the left button? - winapi

I'm using the following winapi-code to change the right-button clicks with left-button clicks.
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (wParam == WM_RBUTTONDOWN)
{
return CallNextHookEx(NULL, nCode, WM_LBUTTONDOWN, lParam);
}
else if (wParam == WM_RBUTTONUP)
{
return CallNextHookEx(NULL, nCode, WM_LBUTTONUP, lParam);
}
else if (wParam == WM_RBUTTONDBLCLK)
{
return CallNextHookEx(NULL, nCode, WM_LBUTTONDBLCLK, lParam);
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
The hook works very good, but it seems that this technique is read-only (I read this in some other stackoverflow question). This is what I want to do:
Left click -> Press left button.
Right click -> Press left button.
Any ideas how can I achieve this?
Thanks in advance.

You can use SwapMouseButton function easily to swap mouse buttons.

Related

Windows API Mousehook , Capture rightmousebutton + Ctrl (WM_RBUTTONDOWN + MK_CONTROL) clicked togather

initially i was able to print something when i pressed only right mouse button using
if (wParam == WM_RBUTTONDOWN)but now , i want the same effect, i want to print something when right mouse button + Ctrl key is pressed. how can i acheive that ?
i have tried this
LRESULT CALLBACK MainWindow::mouseProc(int Code, WPARAM wParam, LPARAM lParam)
{
auto& ms = *(const MSLLHOOKSTRUCT*)lParam;
MSLLHOOKSTRUCT* pMouseStruct = (MSLLHOOKSTRUCT*)lParam;
if (pMouseStruct != nullptr)
{
if (wParam == WM_RBUTTONDOWN & MK_CONTROL) // Here, i added MK_CONTROL but it doesn't work
{
qDebug() << "Print something when Right mouse button and Ctrl button is pressed togather";
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);
}
UPDATE
when i want to try the case where only Ctrl is pressed and it should print something, it still doesn't work
LRESULT CALLBACK MainWindow::mouseProc(int Code, WPARAM wParam, LPARAM lParam)
{
auto& ms = *(const MSLLHOOKSTRUCT*)lParam;
MSLLHOOKSTRUCT* pMouseStruct = (MSLLHOOKSTRUCT*)lParam;
if (pMouseStruct != nullptr)
{
if (wParam == MK_CONTROL) // Here, i added only MK_CONTROL but it doesn't work
{
qDebug() << "Print something when Ctrl button is pressed ";
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);
}
what am i missing here ?
First of all, if you want to capture the right button + ctrl, you can check the state of the Ctrl key (whether it is pressed) when WM_RBUTTONDOWN is detected.
LRESULT CALLBACK mouseProc(int Code, WPARAM wParam, LPARAM lParam)
{
auto& ms = *(const MSLLHOOKSTRUCT*)lParam;
MSLLHOOKSTRUCT* pMouseStruct = (MSLLHOOKSTRUCT*)lParam;
if (pMouseStruct != nullptr)
{
if (wParam == WM_RBUTTONDOWN && (GetAsyncKeyState(VK_LCONTROL)&0x8000)) //Left CONTROL key as example
{
std::cout << "ctrl + rbutton";
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);
}
If you want to use a keyboard hook to hook only "Ctrl":
LRESULT CALLBACK keyboardProc(int Code, WPARAM wParam, LPARAM lParam)
{
KBDLLHOOKSTRUCT* pKeyboardStruct = (KBDLLHOOKSTRUCT*)lParam;
if (pKeyboardStruct != nullptr)
{
if (pKeyboardStruct->vkCode == VK_LCONTROL)
{
if(wParam == WM_KEYDOWN)
std::cout << " -ctrl- ";
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);
}
void main(void)
{
HHOOK hmouse = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, hInstance, 0);
HHOOK hkeyboard = SetWindowsHookEx(WH_KEYBOARD_LL, keyboardProc, hInstance, 0);
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hmouse);
UnhookWindowsHookEx(hkeyboard);
return;
};

WM_LBUTTONDOWN & WM_LBUTTONUP not received

I created toplevel window, but for unknown reasons my WNDPROC does not receive WM_LBUTTONDOWN/WM_LBUTTONUP nor WM_MOUSEMOVE messages.
Any suggestions?
Relevant code:
WNDCLASSEX wc = {0};
Wc.cbSize = 48;
Wc.cbWndExtra = 80;
Wc.hCursor = LoadCursorW(g_hInstance, MAKEINTRESOURCEW(1002));
Wc.style = CS_GLOBALCLASS | CS_DBLCLKS;
Wc.lpszClassName = Ici[dItemIndex].sInit;
Wc.lpfnWndProc = Ici[dItemIndex].wInit;
RegisterClassExW(&Wc);
g_hRuler1 = CreateWindowExW(WS_EX_TOOLWINDOW,
RULER_CONTROL,
L"",
WS_POPUP|WS_VISIBLE|0x1,
100 ,100, 40, RECTHEIGHT(g_rScreen),
NULL, NULL, hInst, NULL);
LRESULT WINAPI Ruler_Window(HWND hWindow, UINT uWindow, WPARAM wParam, LPARAM lParam)
{
if (uWindow == WM_GETMINMAXINFO)
{
goto DODEFAULT;
}
if (uWindow == WM_NCCREATE)
{
g_pGRI = RULER_ALLOCATE();
RULER_SET_POINTER(hWindow, (LONG_PTR)g_pGRI);
return 1L;
}
g_pGRI = RULER_GET_POINTER(hWindow);
g_pGRI->hWindow = hWindow;
switch(uWindow)
{
case WM_CREATE:
{
return Ruler_OnCreate(wParam, lParam);
}
case WM_PAINT:
{
return Ruler_OnPaint(wParam, lParam);
}
case WM_MOUSEMOVE:
{
return Ruler_OnMouseMove(wParam, lParam);
}
case WM_DESTROY:
{
return Ruler_OnDestroy(wParam, lParam);
}
case WM_SETCURSOR:
{
return Ruler_OnSetCursor(wParam, lParam);
}
case WM_LBUTTONDOWN:
{
return Ruler_OnLeftButtonDown(wParam, lParam);
}
case WM_LBUTTONUP:
{
return Ruler_OnLeftButtonUp(wParam, lParam);
}
case GM_SETINDICATORS:
{
return Ruler_OnSetIndicators(wParam, lParam);
}
DODEFAULT:
return DefWindowProcW(hWindow, uWindow, wParam, lParam);
}
}
Spy++ messages of window after left button click.
I think that the problem here is that you are most likely not calling DefWindowProc from your custom wndProc method (Ruler_Window).
Your code structure in your wndProc is a little... interesting.
You handle the messages you are interested in in a switch statement (with the exception of WM_NCCREATE, which is fine), but your switch statement doesn't actually have a default: entry... instead you have created a label called DODEFAULT, which you only reference once - when the message is WM_GETMINMAXINFO you goto DODEFAULT. Ignoring the issue of using a goto here, you basically do not handle any messages other than those listed in your code, and more importantly, you don't pass other messages to the default handler.
A very quick, very simple rewrite of your Ruler_Window method:
LRESULT WINAPI Ruler_Window(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_NCCREATE)
{
g_pGRI = RULER_ALLOCATE();
RULER_SET_POINTER(hWindow, (LONG_PTR)g_pGRI);
return DefWindowProcW(hWindow, uMsg, wParam, lParam);
}
// not sure what g_pGRI is, guessing it's a global?
// should this actually be passed into the handlers below?
g_pGRI = RULER_GET_POINTER(hWindow);
g_pGRI->hWindow = hWindow;
switch(uMsg)
{
case WM_CREATE:
return Ruler_OnCreate(wParam, lParam);
case WM_PAINT:
return Ruler_OnPaint(wParam, lParam);
case WM_MOUSEMOVE:
return Ruler_OnMouseMove(wParam, lParam);
case WM_DESTROY:
return Ruler_OnDestroy(wParam, lParam);
case WM_SETCURSOR:
return Ruler_OnSetCursor(wParam, lParam);
case WM_LBUTTONDOWN:
return Ruler_OnLeftButtonDown(wParam, lParam);
case WM_LBUTTONUP:
return Ruler_OnLeftButtonUp(wParam, lParam);
case GM_SETINDICATORS:
return Ruler_OnSetIndicators(wParam, lParam);
default:
break;
}
return DefWindowProcW(hWindow, uMsg, wParam, lParam);
}
Note, I also changed the name of the message parameter to be uMsg, as it makes reading the code much easier, IMHO.
I suspect that the problem is that you are not calling DefWindowProc for WM_NCCREATE and WM_CREATE. This means that the window is never setting up its client areas, so the messages are coming in as WM_NC*.
You should always pass WM_NCCREATE and WM_CREATE on to DefWindowProc.

How to read the data from lParam (the pointers value)

I made a small application that sends text to notepad via SendMessage and EM_REPLACESEL.
Now I’m trying to hook notepad to get the EM_REPLACESEL value (the lParam value and in this case the “GET THIS TEXT” text).
EDIT: See this picture: http://i.stack.imgur.com/8scNL.jpg
The hook works fine, my problem is to listen for the EM_REPLACESEL message and grab the value from the lParam.
This code works fine, when messages are sent to notepad:
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
Beep (2000,100);
return(CallNextHookEx(g_hHook, nCode, wParam, lParam));
}
So now I want to intercept EM_REPLACESEL messages. This do not work:
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == EM_REPLACESEL)
{
Beep (2000,100);
}
return(CallNextHookEx(g_hHook, nCode, wParam, lParam));
}
1) How to listen for the EM_REPLACESEL message?
2) When I have gotten the message how to grab the lParam value and e.g. show it in a MessageBox. Something like this:
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == EM_REPLACESEL)
{
MSG *lpMsg;
lpMsg = (MSG *) lParam;
MessageBox(NULL,(LPCWSTR)lpMsg,NULL,NULL);
}
return(CallNextHookEx(g_hHook, nCode, wParam, lParam));
}
Thanks
EM_REPLACESEL is a sent message, not a posted message, so you need to use a WH_CALLWNDPROC hook instead of a WH_GETMESSAGE hook, eg:
LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION) {
CWPSTRUCT* cwps = (CWPSTRUCT*)lParam;
if (cwps->message == EM_REPLACESEL) {
Beep (2000,100);
// etc..
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
... = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, ...),
Your GetMsgProc() callback is coded wrong. Carefully read the linked MSDN page to see what the arguments of the callback mean. The nCode argument is not the message number, it specifies whether or not you should process the message. You want to use the passed lParam to recover the message that you intercepted. Make it look similar to this instead:
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION) {
MSG* pmsg = (MSG*)lParam;
if (pmsg->message == WM_LBUTTONDOWN) {
Beep (2000,100);
// etc..
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
Do note that you appear to use the WH_GETMESSAGE hook. It only works for messages that are posted to the message queue with PostMessage(). But EM_REPLACESEL is a message that's sent with SendMessage(). That requires a different hook, WH_CALLWNDPROC or WH_CALLWNDPROCRET.
This is how I normally do it.
LRESULT CALLBACK GetMsgProc(MSG nCode, WPARAM wParam, LPARAM lParam)
{
while(GetMessage(&nCode, NULL, 0, 0) > 0)
{
if(nCode.message == EM_REPLACESEL)
{
//Do something
}
else
DispatchMessage(&nCode);
}
return 0;
}

I need to know the x and y coordinates of the button click when a WM_COMMAND is activated

I have a button created with
//Create Compass
HWND hWndCompass = CreateWindowEx(NULL, "BUTTON", "Compass", WS_TABSTOP|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON,
600, 10, 50, 24, hWnd, (HMENU)IDC_COMPASS, GetModuleHandle(NULL), NULL);
I will add the picture in the future but I need to know where on the button they clicked so I can determine if they clicked on N, S, E, W or some other point of the compass.
My call is:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
Do I need to look in the message for that infomration?
In order to retrieve the X and Y coordinates of a mouse click on your button, you should :
In the WndProc() function, catch the WM_MOUSEMOVE event
Once the event is raised, wParam will give you the type of event (Which button has been pressed)
On the desired event, you are able to retrieve the coordinates through lParam
Something like that :
RESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_MOUSEMOVE:
{
if (lParam == MK_LBUTTON)
{
myXCoord = GET_X_LPARAM(lParam);
myYCoord = GET_Y_LPARAM(lParam);
}
}
break;
default:
DefWindowProc(hWnd, message, wParam, lParam);
}
}
For more information about the WM_MOUSEMOVE message, go to : http://msdn.microsoft.com/en-us/library/ms645616%28v=vs.85%29.aspx

WM_MOUSEHOVER in a global hook

I have implemented custom tooltips for a couple of controls in my application (MFC) but I would like to make it general for all the controls.
Right now I am calling TrackMouseEvent in WM_MOUSEMOVE and then catching WM_MOUSEHOVER (both in the overwritten function WindowProc of the control). But this way I have to duplicate code for every control. So my intention was to set a global hook for mouse events and there ask the control for the message to display in the tooltip.
The problem is that I am not able to catch WM_MOUSEHOVER in a global hook. This is the code:
hMouseHook = SetWindowsHookEx( WH_MOUSE,
CallWndMouseProc,
NULL,
AfxGetThread()->m_nThreadID);
hMainHook = SetWindowsHookEx( WH_CALLWNDPROC,
CallWndProc,
NULL,
AfxGetThread()->m_nThreadID);
LRESULT CALLBACK CallWndMouseProc( int nCode,
WPARAM wParam,
LPARAM lParam )
{
if(nCode == HC_ACTION)
{
MOUSEHOOKSTRUCT* pwp = (MOUSEHOOKSTRUCT*)lParam;
TRACE( _T("message: %x hwnd: %x x: %d y: %d\n"),
wParam,
pwp->hwnd,
pwp->pt.x,
pwp->pt.y);
TRACKMOUSEEVENT eventTrack;
eventTrack.cbSize = sizeof(TRACKMOUSEEVENT);
eventTrack.dwFlags = TME_HOVER;
eventTrack.dwHoverTime = HOVER_DEFAULT;
eventTrack.hwndTrack = pwp->hwnd;
_TrackMouseEvent(&eventTrack);
if(wParam == WM_MOUSEHOVER)
{
AfxMessageBox(_T("CallWndMouseProc: WM_MOUSEHOVER"));
}
}
// let the messages through to the next hook
return CallNextHookEx( hMouseHook,
nCode,
wParam,
lParam);
}
LRESULT CALLBACK CallWndProc( int nCode,
WPARAM wParam,
LPARAM lParam )
{
if(nCode == HC_ACTION)
{
CWPSTRUCT *pData = (CWPSTRUCT*)lParam;
if(pData->message == WM_MOUSEHOVER)
{
AfxMessageBox(_T("CallWndProc: WM_MOUSEHOVER"));
}
}
// let the messages through to the next hook
return CallNextHookEx( hMainHook,
nCode,
wParam,
lParam);
}
Both hooks are being call for the rest of messages and I am sure WM_MOUSEHOVER is being sent because it's capture in the WindowProc function. For instance this is the WindowProc function for a custom CListBox:
LRESULT CMyListBox::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_MOUSEHOVER)
{
AfxMessageBox(_T("WindowProc: WM_MOUSEHOVER"));
}
return CListBox::WindowProc(message, wParam, lParam);
}
Ok. So what I am missing? It's just not possible to capture this message in a global hook? Is there other way to make this without having to put the same code in every single control?
Thanks.
Javier
WM_MOUSEHOVER is posted to the thread's message queue, so you won't see it with WH_CALLWNDPROC (that's for sent messages). WH_MOUSE does get posted messages, so I find it a little strange that you aren't seeing it... Perhaps the hook only gets low level mouse input messages? Try a WH_GETMESSAGE hook.

Resources