20

How can I simulate a mouse event causing the pointer to move 500 pixels to the left, then click using C++. How would I do something like this?

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Josh Polk
  • 255
  • 1
  • 3
  • 9

6 Answers6

46

Here's some modified Win32 code I had lying around:

#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 123
#define Y 123
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 800


void MouseSetup(INPUT *buffer)
{
    buffer->type = INPUT_MOUSE;
    buffer->mi.dx = (0 * (0xFFFF / SCREEN_WIDTH));
    buffer->mi.dy = (0 * (0xFFFF / SCREEN_HEIGHT));
    buffer->mi.mouseData = 0;
    buffer->mi.dwFlags = MOUSEEVENTF_ABSOLUTE;
    buffer->mi.time = 0;
    buffer->mi.dwExtraInfo = 0;
}


void MouseMoveAbsolute(INPUT *buffer, int x, int y)
{
    buffer->mi.dx = (x * (0xFFFF / SCREEN_WIDTH));
    buffer->mi.dy = (y * (0xFFFF / SCREEN_HEIGHT));
    buffer->mi.dwFlags = (MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE);

    SendInput(1, buffer, sizeof(INPUT));
}


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

    Sleep(10);

    buffer->mi.dwFlags = (MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP);
    SendInput(1, buffer, sizeof(INPUT));
}


int main(int argc, char *argv[])
{
    INPUT buffer[1];

    MouseSetup(&buffer);

    MouseMoveAbsolute(&buffer, X, Y);
    MouseClick(&buffer);

    return 0;
}

You'll need to call MouseSetup() to each INPUT buffer before you use it.

Resources

MSDN - SendInput()
MSDN - INPUT
MSDN - MOUSEINPUT

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
  • 1
    Better use `x * 0xFFFF / SCREEN_WIDTH + 1` for pixel-perfect coordinate normalization. (For all values of SCREEN_WIDTH < (0xFFFF / 2) and x <= SCREEN_WIDTH). Your formula can be tens of pixels off for common screen resolutions. – Kay Sarraute Sep 17 '13 at 14:17
  • This is required - otherwise you will have worsening cursor positioning accuracy from left-to-right and top-to-bottom. – Ani Dec 05 '13 at 23:15
  • `MouseSetup()` to each `INPUT` means each **variable** of type `INPUT`... I was confused - at the first sight I thought you have to call it before every mouseinput (which made no sense...). – jave.web Nov 21 '14 at 16:44
  • how to retrieve SCREEN_WIDTH and SCREEN_HEIGHT to make MouseMoveAbsolute() display size (resolution) independent? – Michał Ziobro Dec 07 '16 at 20:23
  • 1
    " (x * (0xFFFF / SCREEN_WIDTH));" result in very huge values.Is it supposed to be like that? – Michael IV Sep 15 '17 at 16:37
  • `x * 65536 / SCREEN_WIDTH + 1` works better in my case, which is also used in [AutoHotKey](https://github.com/Lexikos/AutoHotkey_L/blob/58842fb2956fe082bc11476316d4590b0e2ee8a8/source/keyboard_mouse.cpp#L2545). – J3soon Mar 06 '18 at 13:15
26

Here is a solution using Xlib for those who use Linux :

#include <X11/Xlib.h>
#include<stdio.h>
#include<unistd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

void mouseClick(int button)
{
    Display *display = XOpenDisplay(NULL);

    XEvent event;

    if(display == NULL)
    {
        fprintf(stderr, "Errore nell'apertura del Display !!!\n");
        exit(EXIT_FAILURE);
    }

    memset(&event, 0x00, sizeof(event));

    event.type = ButtonPress;
    event.xbutton.button = button;
    event.xbutton.same_screen = True;

    XQueryPointer(display, RootWindow(display, DefaultScreen(display)), &event.xbutton.root, &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);

    event.xbutton.subwindow = event.xbutton.window;

    while(event.xbutton.subwindow)
    {
        event.xbutton.window = event.xbutton.subwindow;

        XQueryPointer(display, event.xbutton.window, &event.xbutton.root, &event.xbutton.subwindow, &event.xbutton.x_root, &event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
    }

    if(XSendEvent(display, PointerWindow, True, 0xfff, &event) == 0) fprintf(stderr, "Error\n");

    XFlush(display);

    usleep(100000);

    event.type = ButtonRelease;
    event.xbutton.state = 0x100;

    if(XSendEvent(display, PointerWindow, True, 0xfff, &event) == 0) fprintf(stderr, "Error\n");

    XFlush(display);

    XCloseDisplay(display);
}


int main(int argc, char * argv[]) {

    int x , y;
    x = atoi(argv[1]);
    y = atoi(argv[2]);
    Display *display = XOpenDisplay(0);

    Window root = DefaultRootWindow(display);
    XWarpPointer(display, None, root, 0, 0, 0, 0, x, y);
    mouseClick(Button1);
    XFlush(display);
    XCloseDisplay(display);
    return 0;
}

Just Build it and then to simulate a click at x ,y do:

$ ./a.out x y

i.e.

$g++ -lX11 sgmousesim2.cpp

$./a.out 123 13
axiom
  • 8,765
  • 3
  • 36
  • 38
  • 2
    That's quite correct for X11, but the question did get clarified to ask for a Windows solution. – Flexo Jan 09 '12 at 17:09
  • 8
    Just noticed it :) . maybe it will help those who come looking for a Linux specific solution. – axiom Jan 09 '12 at 17:13
3

Use SendInput to generate the input you want to simulate. From MSDN documentation:

Synthesizes keystrokes, mouse motions, and button clicks.

tenfour
  • 36,141
  • 15
  • 83
  • 142
1

I have never did this using C++. Nevertheless, there is a Java class called Robot which is able to produce mouse events. I used this back on Java version 1.4 but it does still work. I tried the example from this Simulate a physical mouse move in Mac OS X. It runs smoothly with Oracle Java 1.6.0_26 on MacOSX Lion. The good about Java is that it is platform independent.

import java.awt.AWTException;
import java.awt.Robot;

public final class MovingMouseDemo
{
   public static void main(String[] args) throws AWTException
   {
     Robot robot = new Robot();
     robot.setAutoDelay(5);
     robot.setAutoWaitForIdle(true);

     //put mouse in the top left of the screen
     robot.mouseMove(0, 0);
     //wait so that you can see the result
     robot.delay(1000);
     //put the mouse 200 pixels away from the top
     //10 pixels away from the left 
     robot.mouseMove(200, 10);
     robot.delay(1000);
     robot.mouseMove(40, 130);
  }
}

You can still use JNI to bind it with C++.

I hope it helps

Community
  • 1
  • 1
Chubs
  • 131
  • 1
  • 9
0

C++ alone can't do this. It has no concept of a "mouse", let alone a "click".

You need some sort of library which talks to your windowing system. For example, QT. Then it's a matter of searching through the API and making the right C++ calls.

nsanders
  • 12,250
  • 2
  • 40
  • 47
0

Use the mouse_event function.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
George Gaál
  • 1,216
  • 10
  • 21
  • 2
    If you read the documentation, it says "***Note** This function has been superseded. Use SendInput instead.*" – Mateen Ulhaq Sep 21 '11 at 23:36
  • 1
    It works anyway in Win2k and WinXP. I've checked this. I don't know about support in W7, but I assume that `mouse_event` will work too because there are many legacy code using it.Also syntax of this function is more obvious than syntax of `SendInput`. – George Gaál Sep 22 '11 at 00:39
  • Whether something works or not is not important. A lot of things work fine. once, or when your testing, or on 1 machine. Whats important is that you were told by the vendor not to use it, and you ignore them. You will not PASS certification on that vendors platform. And if you dont need certification, you will most likely just piss off customers by selling them broken crap. Its deprecated for a reason. DO NOT USE IT. Could be there is a 1 in 10000 chance that you kill someone. You dont know. so dont use it. – Dan May 01 '19 at 22:39