3

I'm trying to create a little app that will detect when the mouse cursor moves to the edge of the screen and will move it to the opposite edge, to create a continuous desktop effect, if that makes sense.

Below is some code from someone else (the mouse hook part) I adapted by added the SetCursorPos to move the mouse to a fixed position for now. When I run it, SetCursorPos returns true, which I assume means the call succeeded, but the mouse does not move. I read somewhere something about security constraints in later Windows version preventing stuff like this, which would make sense, but the source was unclear to how true this is. Does anyone know why this would not work?

Thanks, code below:

#define _WIN32_WINNT 0x0400
#pragma comment( lib, "user32.lib" )

#include <windows.h>
#include <stdio.h>

HHOOK hMouseHook;

__declspec(dllexport) LRESULT CALLBACK KeyboardEvent (int nCode, WPARAM wParam, LPARAM lParam)
{
    MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lParam;
    if (pMouseStruct != NULL)
    {
        if (pMouseStruct->pt.x < -1900)
        {
            BOOL r = SetCursorPos(
                500,
                500
            );

            printf("Trigger %d.  Response %d", pMouseStruct->pt.x, r);
        }
    }

    return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}

void MessageLoop()
{
    MSG message;
    while (GetMessage(&message,NULL,0,0)) {
        TranslateMessage( &message );
        DispatchMessage( &message );
    }
}

DWORD WINAPI MyMouseLogger(LPVOID lpParm)
{
    HINSTANCE hInstance = GetModuleHandle(NULL);
    if (!hInstance) hInstance = LoadLibrary((LPCSTR) lpParm); 
    if (!hInstance) return 1;

    hMouseHook = SetWindowsHookEx (  
        WH_MOUSE_LL,
        (HOOKPROC) KeyboardEvent,  
        hInstance,                 
        NULL                       
        );
    MessageLoop();
    UnhookWindowsHookEx(hMouseHook);
    return 0;
}

int main(int argc, char** argv)
{
    HANDLE hThread;
    DWORD dwThread;

    hThread = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)
        MyMouseLogger, (LPVOID) argv[0], NULL, &dwThread);
    if (hThread)
        return WaitForSingleObject(hThread,INFINITE);
    else return 1;
}
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Steve Whitfield
  • 1,981
  • 3
  • 21
  • 30
  • Are you getting any output from your printfs? – drescherjm Jan 21 '13 at 13:31
  • Also you may want to try something bigger than -1900 just to test. – drescherjm Jan 21 '13 at 13:34
  • @drescherjm It's -1900 because that was 20 or so pixels to the left of my left hand monitor. My printf spits out the following "Trigger -1917. Response 1", etc. I take the "Response 1" to mean the call did not fail, yet the mouse does not move. Could it be anything to do with the separate thread? If I stick a SetCursorPos call right at the start of the program (before hooking), the call succeeds. – Steve Whitfield Jan 21 '13 at 13:54
  • Your KeyboardEvent function is not 100% correct. When nCode < 0, you need to return CallNextHookEx immediately. Maybe this is not the reason of SetCursorPos failure, but hook function must work according to documentation. – Alex F Jan 21 '13 at 14:33
  • Many things begin to work when they are executed asynchronously. I would try to post user-defined message from KeyboardEvent to the main application thread, and execute SetCursorPos there. – Alex F Jan 21 '13 at 14:34
  • Seen this code before. My flabber is still gasted why you'd call a mouse hook callback function "KeyboardEvent". Casting to MOUSEHOOKSTRUCT is just plain wrong, a low-level mouse hook callback gets a MSLLHOOKSTRUCT* – Hans Passant Jan 21 '13 at 14:38
  • I'm aware the function name is wrong and probably screwed, but this isn't anything like production code (just a little play around) and it worked when I first ran it so decided not to correct it. Thanks, Alex, I'll try your suggestion. – Steve Whitfield Jan 21 '13 at 15:03
  • Read again Hans Passant's comment about incorrect casting. – Alex F Jan 21 '13 at 15:25

2 Answers2

4

This appears to be a problem with calling SetCursorPos inside your hook proceedure. I guess this is explicitly prohibted in Vista/Windows 7, but I couldn't find any documentation to confirm that. I modified your code slightly to post a thread message when it wants to move the cursor, and do the actual SetCursorPos inside your message proceedure. It works fine once this is done.

In your hook procedure:

if (pMouseStruct->pt.x < -1900)
    {
        PostThreadMessage( GetCurrentThreadId(), WM_USER, 0, 0 );
        printf("Trigger %d.  Response %d", pMouseStruct->pt.x, r);
    }

In your message loop:

while (GetMessage(&message,NULL,0,0)) {
    if( message.hwnd == NULL ) {
        if( message.message == WM_USER ) {
            SetWindowPos( 500, 500 );
        }
     } else {
         TranslateMessage( &message );
         DispatchMessage( &message );
     }
}

(Note this is just a demonstration, not an actual fix.)

That being said, there are numerous, serious problems with your code. I don't think it's appropriate to go into all of them here, but I recommend you post it on https://codereview.stackexchange.com/.

Community
  • 1
  • 1
Peter Ruderman
  • 12,241
  • 1
  • 36
  • 58
  • Thanks Peter, tried this and it worked. I'm aware the code is awful, it was meant as a bad prototype for something I would like to maybe make later, but couldn't figure out what SetCursorPos would not work. Thanks again, Steve. PS Didn't know about codereview, could definitely be useful! – Steve Whitfield Jan 21 '13 at 17:18
0

Looks like you need to translate coordinates. as per docs you need to call ClientToScreen or ScreenToClient to translate the point. I don't know which Window is the reference. You need to pass that window handle as point (as out parameter) as parameter. and then use the altered point with SetCursorPos

check example

If you want the Screen You need to do GetDC(NULL) and pass the returned handle to ClientToScreen

Neel Basu
  • 12,638
  • 12
  • 82
  • 146
  • Sorry I'm not sure I understand. Which docs are you refering to? Why do I need a window? I just wanted this to be a simple app that monitors the global mouse position. The event method is correctly receiving the mouse position in screen coordinates. SetCursorPos requires screen coordinates. Why do I need to translate? – Steve Whitfield Jan 21 '13 at 14:27