I created a global mouse hook where I tried to change the x and y cursor position that the hooked application receives without actually moving the cursor. For some reason it did not work. So I tried to change the cursor position to see if it would change anything. But that didn't work either; the input reached the window before the cursor moved. Below is my code.
LRESULT CALLBACK procMouseMsg(int nCode, WPARAM wParam, LPARAM lParam){
//this is the hook procedure
if (wParam == WM_LBUTTONDOWN){
// Tactic #1 -problem: Nothing seems to happen...?
((PMSLLHOOKSTRUCT)lParam)->pt.x = 389; //
((PMSLLHOOKSTRUCT)lParam)->pt.y = 15;
// Tactic #2 -problem: cursor moves after input hits hooked application
SetPhysicalCursorPos(389, 15);
// Tactics were not used at the same time.
}
return CallNextHookEx(hkKey, nCode, wParam, lParam);
}
void __stdcall SetHook()
{
if (hkMouse == NULL){
hkMouse = SetWindowsHookEx(WH_MOUSE_LL, procMouseMsg, hInstHookDll, 0);
}
}
Am I missing something big here? Maybe I should just kill the input in CallNextHookEx and then move the cursor, manually send an input and then move the cursor back? I feel like this should be easier.
BTW I'm not writing a keylogger or anything sketchy. I'm trying to do an operating system overlay. It seems like people assume the worst.
Related
LRESULT CALLBACK LowLevelMouseProc(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
BOOL fpassmove = FALSE;
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_MOUSEMOVE: // how do i catch a dx instead of a cursor points?
PMOUSEHOOKSTRUCT me = (PMOUSEHOOKSTRUCT)lParam;
printf("x:%d\ny:%d\nextrainfo:%04X\n", me->pt.x,me->pt.y, me->dwExtraInfo );
break;
}
}
return(fpassmove ? 1 : CallNextHookEx(NULL, nCode, wParam, lParam));
}
int main()
{
// Install the low-level keyboard & mouse hooks
HHOOK hhkLowLevelMouse = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, 0, 0);
// Keep this app running until we're told to stop
MSG msg;
while (!GetMessage(&msg, NULL, NULL, NULL)) { //this while loop keeps the hook
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hhkLowLevelMouse);
return(0);
}
I am looking at all mouse moment from a global hook, and I'm trying to find the dx and dy of the mouse event, And I was hoping to find it in "dwExtraInfo". However, I have no idea how to make sense of the data inside "dwExtraInfo".
the windows documentation is not helpful in telling me what the data in dwExtraInfo means
dwExtraInfo
Type: ULONG_PTR
Additional information associated with the message.
Could not find any documentation on dwExtraInfo directly, but found something related: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessageextrainfo:
Return value
Type: LPARAM
The return value specifies the extra information. The meaning of the
extra information is device specific.
One example of such device specific extra information is Pen gestures: https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages
Distinguishing Pen Input from Mouse and Touch
When your application receives a mouse message (such as
WM_LBUTTONDOWN), it may call the GetMessageExtraInfo function to
evaluate whether the message originated from a pen or a mouse device.
The value returned from GetMessageExtraInfo needs to be mask-checked
against 0xFFFFFF00, and then compared with 0xFF515700. The following
definitions may make this clearer:
#define MI_WP_SIGNATURE 0xFF515700
#define SIGNATURE_MASK 0xFFFFFF00
#define IsPenEvent(dw) (((dw) & SIGNATURE_MASK) == MI_WP_SIGNATURE
If the comparison is true, then this mouse message was generated by a
Tablet PC pen or touch screen. In all other cases, you can assume that
this message was generated by a mouse device.
The lower 8 bits returned from GetMessageExtraInfo are variable. Of
those bits, 7 (the lower 7, masked by 0x7F) are used to represent the
cursor ID, zero for the mouse or a variable value for the pen ID.
Additionally, in Windows Vista, the eighth bit, masked by 0x80, is
used to differentiate touch input from pen input (0 = pen, 1 = touch).
I have an application which has several windows and I want that some of them (which I will call CMyLockedFrameWndEx, because they derive from CFrameWndEx) stay placed where they were after changing system display area.
The Parent of all windows of my application is NULL.
I've managed to already catch the WM_DISPLAYCHANGE message when I drag the position of the 2nd monitor relatively to the first; and I also had come to catch the WM_DEVICECHANGE when I connect or disconnect the 2nd monitor's HDMI cable. I've intercepted them both at CMyLockedFrameWndEx::WindowProc.
The automatic window repositioning occurs after that. I noticed that bacause I've put breakpoints on CMyLockedFrameWndEx::OnWindowPosChanging and CMyLockedFrameWndEx::OnWindowPosChanged and they stop after the events I catched on WindowProc. This workflow seems to be unrelated to the catching of events I described as my WindowProc method is:
LRESULT CMyLockedFrameWndEx::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_DISPLAYCHANGE)
{
TRACE(_T("DISPLAY CHANGE"));
return 0L;
}
if (message == WM_SYSCOMMAND)
{
TRACE(_T("SYSCOMMAND"));
if (wParam == SC_MOVE)
{
return 0L;
}
}
if (message == WM_WININICHANGE)
{
TRACE(_T("WININICHANGE"));
if (wParam == SPI_SETWORKAREA)
{
return 0L;
}
}
return __super::WindowProc( message, wParam, lParam);
}
and when passing in OnWindowPosChanging or OnWindowPosChanged, the flow doesn't come from the specific cases of WindowProc handled by me. And that is a problem.
I tried to follow the call stack to see what window sent the WM_WINDOWPOSCHANGING or the WM_WINDOWPOSCHANGED message, but I didn't succeed. I have even tried to use Spy++64 to detect who was the the sender of the message, but I didn't succeed. The whole idea of seeing who was the sender was: if it is associated to a system's display change is to detect it beforehand and impeach the auto repositioning to even happen.
As i didn't succeed yet, what can I do to make the window immune to a system's display change?
Thanks.
The good news is: you are, obviously, in control of the placement of your own window.
The bad news - Windows will first move your window to its new position, then send you the WM_DISPLAYCHANGE and WM_SETTINGCHANGE, as seen in this Spy++'s log:
S WM_WINDOWPOSCHANGING lpwp:003CF9AC
S WM_GETMINMAXINFO lpmmi:003CF624
R WM_GETMINMAXINFO lpmmi:003CF624
R WM_WINDOWPOSCHANGING
S WM_WINDOWPOSCHANGED lpwp:003CF9AC
S WM_MOVE xPos:278 yPos:450
R WM_MOVE
R WM_WINDOWPOSCHANGED
S WM_SETTINGCHANGE wFlag:SPI_ICONVERTICALSPACING pszMetrics:0026E018
R WM_SETTINGCHANGE
S WM_DISPLAYCHANGE cBitsPerPixel:32 cxScreen:2560 cyScreen:1440
R WM_DISPLAYCHANGE
S WM_SETTINGCHANGE wFlag:SPI_SETWORKAREA pszMetrics:0026E018
R WM_SETTINGCHANGE
So - you would have to test the position changing to another screen by yourself. Like in this simplified example, where 2560 is my screen's width:
case WM_WINDOWPOSCHANGING:
{
WINDOWPOS* pWP = (WINDOWPOS*)lParam;
if ((pWP->flags & SWP_NOMOVE) == 0) // it's a move
{
if (pWP->x < 2560)
pWP->flags |= SWP_NOMOVE;
}
return 0;
}
The unhappy news are I can not do this on a preventive way, because the system moves the windows to the primary screen even after sending any useful messages.
The good news are I can react to the move by adding a
ON_WM_WINDOWPOSCHANGED()
line on the class's message map and supply it with its respective handler function:
CMyLockedFrameWndEx::OnWindowPosChanged(WINDOWPOS* lpwndpos)
{
__super::OnWindowPosChanged(lpwndpos);
CFrameWndEx* pFrame=(CFrameWndEx*)::AfxGetMainWnd();
VALIDATE_FPTR(pFrame);
CMyDoc* pDoc=(CMyDoc*)pFrame->GetActiveDocument();
VALIDATE_FPTR(pDoc);
POSITION p= pDoc->GetFirstViewPosition();
while(p)
{
CMyLockedView* pLockedView= dynamic_cast<CLockedView*>(pDoc->GetNextView(p));
if(!pLockedView)
continue;
if(pLockedView->GetParentFrame() == this)
{
this->SetWindowPos(NULL, m_Top, m_Left, 0, 0, SWP_NOSIZE);
break;
}
}
}ยด
Note, that it helps me that I was persisting the position where the window was in the m_Top and m_Left variables.
I recently started coding in C++ and I am very new to it. (I code in Javascript, PHP, Java and Obj-C more often)
I'm practicing how to hook a message box and change its position. This is what I have in my .cpp file (after reading this SO post).
#include <iostream>
#pragma comment(lib,"User32.lib")
#include <windows.h>
HHOOK hhookCBTProc = 0;
LRESULT CALLBACK pfnCBTMsgBoxHook(int nCode, WPARAM wParam, LPARAM lParam){
if (nCode == HCBT_CREATEWND)
{
CREATESTRUCT *pcs = ((CBT_CREATEWND *)lParam)->lpcs;
if ((pcs->style & WS_DLGFRAME) || (pcs->style & WS_POPUP))
{
HWND hwnd = (HWND)wParam;
SetWindowPos(hwnd, HWND_TOP,130,122, 0, 0,SWP_NOSIZE);
}
}
return (CallNextHookEx(hhookCBTProc, nCode, wParam, lParam));
}
int main(void)
{
hhookCBTProc = SetWindowsHookEx(WH_CBT,pfnCBTMsgBoxHook,
0, GetCurrentThreadId());
int sResult = MessageBox ( NULL, "Hooked!", "oh my", MB_OK );
UnhookWindowsHookEx(hhookCBTProc);
return 0;
}
For some reason the position of the message box isn't changing. Where did it go wrong?
(I know I can create a customized window or dialog. But I am doing it this way because I want to learn how to hook a message box and where I did wrong.)
Firstly you should check in the debugger that your hook is actually being called, if you haven't already.
Secondly, at the time the HCBT_CREATEWND hook event is triggered, the window has only just been created - the system has yet to size and position it. It will do this with the values in the CREATESTRUCT after the hook returns - overriding your SetWindowPos call.
See the docs from MSDN on the lParam value for this particular hook event:
Specifies a long pointer to a CBT_CREATEWND structure containing
initialization parameters for the window. The parameters include the
coordinates and dimensions of the window. By changing these
parameters, a CBTProc hook procedure can set the initial size and
position of the window.
Therefore, the correct way to use this hook to change a window's position is to modify the values in the CREATESTRUCT directly.
Also note that it's quite possible that the dialog manager sizes and positions the window after creation, so if you find that this still isn't working for you, you may need to try watching for the HCBT_MOVESIZE event instead.
From the docs
At the time of the HCBT_CREATEWND notification, the window has been
created, but its final size and position may not have been determined
and its parent window may not have been established.
Maybe try hooking into CBT_ACTIVATE instead.
I want to get mouse click coordinates X and Y when user press Ctrl and click at same time.
User may click anywhere on the screen or programs. I want my program to catch the event and get coordinates when Ctrl key is down pressed and mouse click occurs at same time. I want to get system coordinates X and Y, not the window coordinates of other programs.
I'm using C++ .
How to do that ?
Windows OS, WIN API code
I'm doing next which is not working:
HHOOK MouseHook;
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam){
PKBDLLHOOKSTRUCT k = (PKBDLLHOOKSTRUCT)(lParam);
POINT p;
if(wParam == WM_RBUTTONDOWN)
{
// right button clicked
GetCursorPos(&p);
//p.x
//p.y
//my program is never getting here, why ?
}
}
MouseHook = SetWindowsHookEx(WH_MOUSE_LL,(HOOKPROC)MouseHookProc,0,0);
if I change the above line to: MouseHook = SetWindowsHookEx(WH_MOUSE,(HOOKPROC)MouseHookProc,GetModuleHandle(NULL),0);
then it will work only for my own program window, but not hooking clicks outside of my program
Have you read this article? link
First of all, if you want to catch system entire mouse + keyboard event, your hooking function must be placed on a dll.
1)If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.
Like below,
if(nCode < 0)
{
CallNextHookEx(hook, nCode, wParam, lParam);
return 0;
}
If CallNextHookEx is not called, there is a chance that other processes that have installed hook may not get the events correctly.
2)And then, check nCode again, whether it is HC_ACTION.
switch (nCode)
{
case HC_ACTION:
...
3)Finally, you can check WPARAM for WM_RBUTTONDOWN, and LPARAM for MSLLHOOKSTRUCT
The way I would approach is I would create a global variable say
int ctrl_pressed = 0
/*
0 -- ctrl nt pressed
1 -- Crtl Pressed
*/
Step 1: Now I would handle both WM_KEYDOWN and WM_KEYUP for ctrl
Step 2: In the callback of WM_KEYDOWN (if lparam is ctrl ) I would set ctrl_pressed to 1.
And in case of WM_KEYUP I would set ctrl_pressed to 0.
Step 3: Now Finally ill handle WM_MOUSECLICKED
and then check if ctrl_pressed(global) is 1 , which if true I can just get the coordinates.
This is just an approach may be not the most efficient solution.
Wait for more experienced WIN32 Developers to give their input on this.
I have a win 32 application written in c++ which sets the low level keyboard hook. now i want to sendInput to any app like word / notepad. how do i do this?
i have already done enough of using findwindow / sendmessage. for all these, i need to know edit controls. finding the edit control is very difficult.
since SendInput works for any windows application, i want to use it. the problem is i get a call to my callback function with the pressed key.
for e.g i pressed A and i want to send U+0BAF unicode character to the active applciation windows. in this case, assume it is notepad.
the problem is i get two characters U+0BAF and A in the notepad.
A is being sent because i am calling CallNextHookEx( NULL, nCode, wParam, lParam);
if i return 1 after sendInput, then nothing is sent to notepad.
any suggestion?
If I understood your problem correctly, you should ignore "injected" key events in your hook procedure, like this:
LRESULT CALLBACK
hook_proc( int code, WPARAM wParam, LPARAM lParam )
{
KBDLLHOOKSTRUCT* kbd = (KBDLLHOOKSTRUCT*)lParam;
// Ignore injected events
if (code < 0 || (kbd->flags & LLKHF_INJECTED)) {
return CallNextHookEx(kbdhook, code, wParam, lParam);
}
...
Update: additionally, you have to eat characters and notify some other routine for a character press through Windows messages.
Example:
...
// Pseudocode
if (kbd->vkCode is character) {
if (WM_KEYDOWN == wParam) {
PostMessage(mainwnd, WM_MY_KEYDOWN, kbd->vkCode, 0);
return 1; // eat the char, ie 'a'
}
}
return CallNextHookEx(kbdhook, code, wParam, lParam);
And, in some other module, you handle WM_MY_KEYDOWN:
ie, #define WM_MY_KEYDOWN (WM_USER + 1)
and call the appropriate routine that will generate new key events.