-3

I'm trying to implement LBUTTONDOWN->MOUSEMOVE->WM_LBUTTONUP using winapi in outfocus. But the "MouseButtons" information doesn't come.

enter image description here

I want to simulate the same mouse click and move using winapi.

I created a winform application to make sure winapi works. This form Event monitors mouse and keyboard input.

Using

SendMessage LBUTTONDOWN-> MOUSEMOVE-> WM_LBUTTONUP

message has been sent.

But my code doesn't give the button information during MOUSEMOVE.

[System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, IntPtr lParam);

Here is my code.

int x = 0;
int y = 0;
IntPtr lparam = IntPtr.Zero;

x = 160;
y = 500;
lparam = new IntPtr(x | (y << 16));
SendMessage(hwnd_child, WM_LBUTTONDOWN, (int)0x0, lparam);

Thread.Sleep(3000);

//이벤트
for (int i = 0; i < 100; ++i)
{
    //일반
    x = 160;
    y = 500 - i;
    lparam = new IntPtr(x | (y << 16));
    SendMessage(hwnd_child, WM_MOUSEMOVE, 0, lparam);
    //Thread.Sleep(10);
}

x = 160;
y = 500 - 100;
lparam = new IntPtr(x | (y << 16));
SendMessage(hwnd_child, WM_LBUTTONUP, (int)0x0, lparam);

Existing result (See Previous image)

I want the below result enter image description here

2019-09-02 Added

I modified the code in the way of the answer.

I checked the log through spy++.

Modified code

//SendMessage -> PostMessage
PostMessage(hwnd_child, WM_MOUSEMOVE, MK_LBUTTON, lparam);

Result of modified code

Desired result.

Log obtained by dragging the mouse directly.

Log obtained by dragging the mouse directly.

test program code

private void FrmMain_MouseMove(object sender, MouseEventArgs e)
{
    if (this.m_bMouseMoveEnabled == true)
    {
        this.SendLog("MouseMove"
        , string.Format("Btn:{0}, X:{1}, Y:{2}"
                        , e.Button
                        , e.X
                        , e.Y));
    }
}


2022-05-04 Update

I have created several test programs.
And I found the cause.

The 'MOUSEMOVE' information of 'winapi' appears to be that of a physical mouse.

I have "MouseButtons" when I hold down the physics mouse.

  • Did you look at the docs for those messages (example: https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttondown)? You encode the mouse button information into the wParam – Flydog57 Aug 29 '19 at 02:30
  • 1
    For simulate mouse click movement ,avoid using SendMessage, you should use `sendInput` to synthesize mouse keystrokes. – Strive Sun Aug 29 '19 at 02:44
  • Thank you for answer. SendMessage (hwnd_child, WM_MOUSEMOVE, MK_LBUTTON, lparam); I tried it but it still doesn't work. 'SendInput' cannot be used because it should work in a window that has no focus. – Dang-gun Roleeyas Aug 31 '19 at 00:38

1 Answers1

1

As @Flydog57 said, you can change the wParam parameter of SendMessage to MK_LBUTTON.

This allows you to press the left button while the mouse is moving. I tested it and found it works.

Like this:

 SendMessage(hwnd_child, WM_MOUSEMOVE, MK_LBUTTON, lparam);

You can refer WM_MOUSEMOVE for more details.

Or you can use SendInput, which I recommend more.

This is the smallest code example shown with SendInput.

The SendInput function inserts the events in the INPUT structures serially into the keyboard or mouse input stream. These events are not interspersed with other keyboard or mouse input events inserted either by the user (with the keyboard or mouse) or by calls to keybd_event, mouse_event, or other calls to SendInput.

Although it's written in C++, it gives you a good idea.

#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0500

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <string.h>
#include <windows.h>


#define X 160
#define Y 500
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 800


void MouseClickDOWN(INPUT *buffer)
{
    buffer->mi.dwFlags = (MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN);
    SendInput(1, buffer, sizeof(INPUT));

}



int main(int argc, char *argv[])
{
    int i = 0;
    INPUT input;
    INPUT buffer[101];

    memset(&input,0,sizeof(INPUT));
    memset(buffer,0, sizeof(INPUT)*101);

    input.mi.dwFlags = (MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN);
    SendInput(1, &input, sizeof(INPUT));

    Sleep(3000);

    for (i; i < 100; ++i)
    {
        buffer[i].mi.dx = (X* (0xFFFF / SCREEN_WIDTH));
        buffer[i].mi.dy = ((Y - i) * (0xFFFF / SCREEN_HEIGHT));
        buffer[i].mi.dwFlags = (MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE);
    }

    buffer[i].mi.dwFlags = (MOUSEEVENTF_LEFTUP);

    SendInput(101, buffer, sizeof(INPUT));

    return 0;
}

You can view the details of the simulate mouse from the MOUSEINPUT structure.

I've found some other considerations for using SendInput in C#, please refer this.

Why do I recommend SendInput instead of SendMessage?

I think the charm of SendInput lies in its ability to synthesize keystrokes and reduce overhead.

Thank you in particular for @Remy Lebeau's help.

Updated:

Call SendMessage

SendMessage

Call PostMessage

PostMessage

I tested SendMessage and PostMessage separately, both of which could be tested by pressing the left mouse button while moving.

The difference between SendMessage and PostMessage is:

PostMessage (in "pure windows programming", aka win32 API) is asynchronous, i.e., to quote the docs:

Places (posts) a message in the message queue associated with the thread that created the specified window and returns without waiting for the thread to process the message.

To post a message in the message queue associated with a thread, use the PostThreadMessage function.

SendMessage is synchronous, that is, again quoting:

Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.

To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread's message queue and return immediately, use the PostMessage or PostThreadMessage function.

Strive Sun
  • 5,988
  • 1
  • 9
  • 26
  • It is almost always a bug to call `SendInput()` with `cInputs=1` when sending multiple events. It should be called once with all of the events in an array at one time. Otherwise you risk user events intermixing with simulated events, which is exactly the kind of thing `SendInput()` is designed to prevent. – Remy Lebeau Aug 29 '19 at 06:51
  • @RemyLebeau Wow, thank you for your reminder. I've corrected it. – Strive Sun Aug 29 '19 at 07:29
  • 1
    your edit is no better than your original code, in fact it is worse. You are still making 102 individual calls to `SendInput()` with `cInputs=1` each time, but now you are wasting more memory doing it. The use of a sleep prevents 1 call with `cInputs=102`, but you can at least make 1 call with `cInputs=1` and 1 call with `cInputs=101` since there are no simulated delays between the mouse moves and the mouse up. MUCH less overhead and risk making 2 function calls rather than 102 function calls – Remy Lebeau Aug 29 '19 at 08:19
  • @RemyLebeau I thought carefully about what you said and reviewed my code. Now I put the correct code on it. Anyway, thank you for your help. – Strive Sun Aug 29 '19 at 09:47
  • Thank you for answer. 'SendInput' cannot be used because it should work in a window that has no focus. – Dang-gun Roleeyas Aug 31 '19 at 00:40
  • @Dang-gunRoleeyas Yes, for windows without focus, we can only use `SendMessage`. For `SendMessage` and `PostMessage`, I tested them separately. They all work. Please see the update of my answer. – Strive Sun Sep 02 '19 at 06:05