I want to move the mouse cursor with a c++ script. I am using Visual C++ 2010 Express in a Windows 7 inside Parallels and I created a console application.
I know SetCursorPos method but it is just not working (it does nothing).
I managed to simulate clicks with SendInput but it does not actually move the mouse.
This is my code:
#include <Windows.h>
#include <Tlhelp32.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <time.h>
void mouseLeftClick(const int x, const int y);
// window
HWND hWindow;
int main()
{
// find window
hWindow = FindWindow(NULL, "Calculadora");
if (NULL == hWindow) {
OutputDebugStringA("Couldn't find application.");
}else{
if (!SetForegroundWindow(hWindow)) {
OutputDebugStringA("Couldn't set application to foreground.");
}else{
// click on 1
mouseLeftClick(20 265));
Sleep(500);
// click on 2
mouseLeftClick(60, 265);
Sleep(500);
}
}
return 0;
}
void mouseLeftClick(const int x, const int y)
{
// get the window position
RECT rect;
GetWindowRect(hWindow, &rect);
// calculate scale factor
const double XSCALEFACTOR = 65535 / (GetSystemMetrics(SM_CXSCREEN) - 1);
const double YSCALEFACTOR = 65535 / (GetSystemMetrics(SM_CYSCREEN) - 1);
// get current position
POINT cursorPos;
GetCursorPos(&cursorPos);
double cx = cursorPos.x * XSCALEFACTOR;
double cy = cursorPos.y * YSCALEFACTOR;
// calculate target position relative to application
double nx = (x + rect.left) * XSCALEFACTOR;
double ny = (y + rect.top) * YSCALEFACTOR;
INPUT Input={0};
Input.type = INPUT_MOUSE;
Input.mi.dx = (LONG)nx;
Input.mi.dy = (LONG)ny;
// set move cursor directly and left click
Input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP;
SendInput(1,&Input,sizeof(INPUT));
}
This happens in Parallels because of SmartMouse is On or on Auto.
In order for a program in Parallels VM to control the mouse with SetCursorPos you need to hide cursor first. You can do that with ShowCursor(0); before you do any mouse movement e.g. SetCursorPos.
Now you will be able to control the mouse while SmartMouse is set to Auto or Off.
I found the problem. It turns out Parallels has a feature called Smart Mouse that allows you move freely between OSX and Windows. Once I deactivated it, mouse moved as expected.
Related
I have a simple program that has a main window and a small window on the bottom like (without the lines, thats just so you can see the two windows:
+------------------+
| |
| |
| |
+------------------+
| |
+------------------+
I want the bottom area to be a place where you can type in, and here is my source code:
#include <termios.h>
#include <bits/stdc++.h>
#include <ncurses.h>
int main()
{
int scrx;
int scry;
initscr();
cbreak();
noecho();
clear();
raw();
getmaxyx(stdscr, scrx, scry);
WINDOW* input = newwin(1, scrx, scry, 0);
std::string cmdbuf;
while(true)
{
int newx;
int newy;
getmaxyx(stdscr, newx, newy);
if(newx != scrx || newy != scry)
{
// do stuff;
}
char c = wgetch(input);
cmdbuf.push_back(c);
werase(input);
mvwprintw(input, 0, 0, cmdbuf.c_str());
refresh();
wrefresh(input);
}
}
However, it doesn't seem to print anything, just move my cursor (which gets suck halfway across the screen). How can I make it so that text actually gets printed and that my cursor actually moves across the full screen?
Tidied it up for you a bit. Press 'q' to quit. You get the idea.
#include <termios.h>
#include <bits/stdc++.h>
#include <ncurses.h>
int main()
{
int scrx, scry;
initscr();
getmaxyx(stdscr, scry, scrx);
WINDOW *w = newwin(1, scrx, scry - 1, 0);
std::string cmdbuf {};
char c = '\0';
while (c != 'q')
{
int newx, newy;
getmaxyx(stdscr, newx, newy);
if(newx != scrx || newy != scry)
{
// do stuff;
}
c = wgetch(w);
cmdbuf += c;
mvwprintw(w, 0, 0, "%s", cmdbuf.c_str());
wrefresh(w);
}
delwin(w);
endwin();
}
The refresh is overwriting the mvwprintw because they're different windows. For the given example, there's no reason to refresh stdscr because nothing (except for the initscr call) has updated that window. Moving refresh out of the loop would help (but the "do stuff" can obviously interfere with that).
The newx/newy logic is too fragmentary to comment on (I'd use getbegyx ...).
The declaration of newwin is:
WINDOW *newwin(
int nlines, int ncols,
int begin_y, int begin_x);
You are calling:
newwin(1,scry,scrx,0)
Which sets the size of you window to 1 tall and scry wide, and puts it at coordinates (0,srcx). What you want is:
newwin(1,scry,scrx-1,0)
Where 1 is the height of the window.
Also, cbreak overrides raw, so there is no point to calling both.
I want to get the (accurate) on-screen X and Y coordinates of a window (the client area). My problem is that I have to define a horizontal shift which has to be added onto the X coordinate to get the correct result:
#include <windows.h>
inline int get_title_bar_thickness(const HWND window_handle)
{
RECT window_rectangle, client_rectangle;
GetWindowRect(window_handle, &window_rectangle);
GetClientRect(window_handle, &client_rectangle);
const int height = window_rectangle.bottom - window_rectangle.top -
(client_rectangle.bottom - client_rectangle.top);
const int width = window_rectangle.right - window_rectangle.left -
(client_rectangle.right - client_rectangle.left);
return height - width / 2;
}
#define HORIZONTAL_SHIFT 8
/**
* Gets the window position of the window handle
* excluding the title bar and populates the x and y coordinates
*/
inline void get_window_position(const HWND window_handle, int* x, int* y)
{
RECT rectangle;
const auto window_rectangle = GetWindowRect(window_handle, &rectangle);
const auto title_bar_thickness = get_title_bar_thickness(window_handle);
if (window_rectangle)
{
*x = rectangle.left + HORIZONTAL_SHIFT;
*y = rectangle.top + title_bar_thickness;
}
}
The issue can be observed by moving the window programmatically:
const auto window_handle = FindWindow(nullptr, "Command Prompt");
SetWindowPos(window_handle, nullptr, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
I would expect this SetWindowPos() call to perfectly place the window into the upper left corner of my screen but there is some space left between the window and the screen border (exactly 8 pixels). Is there a way to assure that this horizontal offset is automatically considered? This might be related to laptops so how to make this behave as expected?
As commented by Castorix, the horizontal shift can be retrieved.
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
inline int get_horizontal_shift(const HWND window_handle)
{
RECT window_rectangle, frame_rectangle;
GetWindowRect(window_handle, &window_rectangle);
DwmGetWindowAttribute(window_handle,
DWMWA_EXTENDED_FRAME_BOUNDS, &frame_rectangle, sizeof(RECT));
return frame_rectangle.left - window_rectangle.left;
}
The code is based on this post. The return value is 7 on my machine.
I need to automate some mouse actions.
I need to do
mousemove1, lbuttondown1, wait1, mousemove1, lbuttonup1, wait1,
mousemove2, lbuttondown2, wait2, mousemove2, lbuttonup2, wait2,
...
The actions have to work regarding screen coordinates. The window which have to accept an event is the top window at this point.
There is a file with data.
For example
500 450 1000 500 300 2000
600 450 1000 600 300 5000
What did I try to do
#include <fstream>
#include <vector>
#include <windows.h>
struct A
{
POINT point1;
unsigned sleep1;
POINT point2;
unsigned sleep2;
A() { point1.x = point1.y = sleep1 = point2.x = point2.y = sleep2 = 0; }
};
void f(const A &a)
{
mouse_event(MOUSEEVENTF_LEFTDOWN, a.point1.x, a.point1.y, 0, 0);
mouse_event(MOUSEEVENTF_MOVE, a.point1.x, a.point1.y, 0, 0);
Sleep(a.sleep1);
mouse_event(MOUSEEVENTF_LEFTUP, a.point2.x, a.point2.y, 0, 0);
mouse_event(MOUSEEVENTF_MOVE, a.point2.x, a.point2.y, 0, 0);
Sleep(a.sleep2);
}
int main()
{
std::vector<A> as;
std::ifstream fin("params.txt");
if (fin) {
A a;
while (fin.good()) {
fin >> a.point1.x;
fin >> a.point1.y;
fin >> a.sleep1;
fin >> a.point2.x;
fin >> a.point2.y;
fin >> a.sleep2;
if (fin.eof()) {
break;
}
as.push_back(a);
}
}
for (;;) {
for (const A &a : as) {
f(a);
}
}
}
Something is happening but I can not understand what is and where is a mistake.
A problem with your code is that you are using mouse_event with screen coordinates rather than normalized absolute coordinates. Normalized absolute coordinates always range between (0,0) in the top-left corner to (65535,65535) in the bottom-right corner, no matter what the desktop size happens to be.
The MouseTo function in the example below accepts screen coordinates as inputs, then uses the dekstop window's size to convert to normalized absolute coordinates. This example uses SendInput, which supersedes mouse_event, but they both use the same coordinates. I'm not sure if mouse_event can take the MOUSEEVENTF_VIRTUALDESK flag, but this is for supporting multi-monitor desktops.
If you wish build this example, start with a new Win32 Console application.
#include <Windows.h>
#include <cmath>
void MouseTo(int x, int y) {
RECT desktop_rect;
GetClientRect(GetDesktopWindow(), &desktop_rect);
INPUT input = {0};
input.type = INPUT_MOUSE;
input.mi.dwFlags =
MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK | MOUSEEVENTF_MOVE;
input.mi.dx = x * 65536 / desktop_rect.right;
input.mi.dy = y * 65536 / desktop_rect.bottom;
SendInput(1, &input, sizeof(input));
}
void MouseLButton(bool tf_down_up) {
INPUT input = {0};
input.type = INPUT_MOUSE;
input.mi.dwFlags = tf_down_up ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
SendInput(1, &input, sizeof(input));
}
void MouseLButtonDown() { MouseLButton(true); }
void MouseLButtonUp() { MouseLButton(false); }
void AnimatedDrag(const POINT& from, const POINT& to) {
static const double iteration_dist = 20;
static const DWORD iteration_delay_ms = 1;
const double dx = to.x - from.x;
const double dy = to.y - from.y;
const double dist = sqrt(dx*dx + dy*dy);
const int count = static_cast<int>(dist / iteration_dist);
MouseTo(from.x, from.y);
MouseLButtonDown();
for(int i=1; i<count; ++i) {
const int x = from.x + static_cast<int>(dx * i / count);
const int y = from.y + static_cast<int>(dy * i / count);
MouseTo(x, y);
Sleep(iteration_delay_ms);
}
MouseTo(to.x, to.y);
MouseLButtonUp();
}
int main() {
// minimize console window
ShowWindow(GetConsoleWindow(), SW_SHOWMINNOACTIVE);
Sleep(500);
// Drag whatever is at the window coordinates in "from" to "to"
const POINT from = {300, 100};
const POINT to = {900, 600};
AnimatedDrag(from, to);
}
Christopher's answer should suffice, but might be a little intimidating to anyone not well-versed with C++, and just trying to hack together a click-utility. This should be easy enough to hack away at for most newbies.
Pardon the use of macros; I'm using them to make the intent of the code a little more English-friendly.
It should right-click on your primary display (unless you changed the X coordinate line as-commented) then shift a few pixels over and left-click to close the Right-click menu prompt, if one was created. You can see what else is available on MSDN for your own custom requirements.
I kept click / unclick / move as seperate actions, so things like drag & drop should be fairly intuitive to perform when starting with all the right ingredients.
#include <Windows.h>
// Uses absolute coords where the primary display starts at 0,0
// That works well with enumerated monitors structures and their reported coords.
#define QUEUE_MV_MOUSE ip.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
#define QUEUE_RC_START_MOUSE ip.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
#define QUEUE_RC_END_MOUSE ip.mi.dwFlags = MOUSEEVENTF_RIGHTUP;
#define QUEUE_LC_START_MOUSE ip.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
#define QUEUE_LC_END_MOUSE ip.mi.dwFlags = MOUSEEVENTF_LEFTUP;
#define SEND_IT SendInput(1, &ip, sizeof(ip));
#define VIRTUAL_X_MODIFIER (65536 / GetSystemMetrics(SM_CXSCREEN));
#define VIRTUAL_Y_MODIFIER (65536 / GetSystemMetrics(SM_CYSCREEN));
int main()
{
INPUT ip;
ip.type = INPUT_MOUSE;
ip.mi.mouseData = 0;
// Change 500 to -500 for a left-hand extended display.
ip.mi.dx = 500 * VIRTUAL_X_MODIFIER;
ip.mi.dy = 1000 * VIRTUAL_Y_MODIFIER;
// Un-comment this Sleep timer if you're debugging in an IDE and need a quick pause.
// Sleep(500);
QUEUE_MV_MOUSE;
SEND_IT;
// Various users advise brief Sleep pauses between queued mouse and keyboard events.
// 500 milliseconds is probably overkill for your automation requirements.
Sleep(500);
QUEUE_RC_START_MOUSE;
SEND_IT;
Sleep(500);
QUEUE_RC_END_MOUSE;
SEND_IT;
Sleep(500);
ip.mi.dx -= 10 * VIRTUAL_X_MODIFIER;
ip.mi.dx -= 10 * VIRTUAL_Y_MODIFIER;
QUEUE_MV_MOUSE;
SEND_IT;
Sleep(500);
QUEUE_LC_START_MOUSE;
SEND_IT;
Sleep(500);
QUEUE_LC_END_MOUSE;
SEND_IT;
return 0;
}
I want to test a flash application running on browser. I need to drag pieces around in the application. I want to do this by simulating mouse movements using windows api.
Here is my navie solution to simulate a mouse drag:
void MoveMouse(LPINPUT input, int x, int y) {
input->type = INPUT_MOUSE;
input->mi.dx = x*(65536/GetSystemMetrics(SM_CXSCREEN));
input->mi.dy = y*(65536/GetSystemMetrics(SM_CYSCREEN));
input->mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
}
void LeftDownMouse(LPINPUT input, int x, int y) {
input->type = INPUT_MOUSE;
input->mi.dx = x*(65536/GetSystemMetrics(SM_CXSCREEN));
input->mi.dy = y*(65536/GetSystemMetrics(SM_CYSCREEN));
input->mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
}
void LeftUpMouse(LPINPUT input, int x, int y) {
input->type = INPUT_MOUSE;
input->mi.dx = x*(65536/GetSystemMetrics(SM_CXSCREEN));
input->mi.dy = y*(65536/GetSystemMetrics(SM_CYSCREEN));
input->mi.dwFlags = MOUSEEVENTF_LEFTUP;
}
void DragMouse(LPINPUT inputs, int startX, int startY, int dropX, int dropY) {
MoveMouse(&inputs[0], startX, startY);
LeftDownMouse(&inputs[1], startX, startY);
LeftUpMouse(&inputs[2], startX, startY);
LeftDownMouse(&inputs[3], startX, startY);
MoveMouse(&inputs[4], dropX, dropY);
LeftUpMouse(&inputs[5], dropX, dropY);
}
int _tmain(int argc, _TCHAR* argv[])
{
INPUT inputs [6] = {};
// Assume there is a maximized window, mouse drags the window from 40, 10 to 100,100 coordinates.
DragMouse(inputs, 40, 10, 100, 100);
SendInput(6, inputs, sizeof(INPUT));
Sleep(1000);
return 0;
}
This code mostly doesn't work, sometimes works, it has undefined behaviour. What could be the problem? How can i solve this?
I had a similar problem with drag and drop, although my results were consistent in that the mouse was moving but not the item being dragged.
Your MoveMouse function is missing the MOUSEEVENTF_LEFTDOWN flag. Try input->mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTDOWN;
Without the flag setting you are just asking the mouse to move without the left mouse button being down.
Edit
I just checked my implementation and I don't set coordinates when pressing or releasing the mouse buttons. Only when moving.
As for variance in results, you may stop these by zeroing out the INPUT before setting fields.
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?
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
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
Use SendInput to generate the input you want to simulate. From MSDN documentation:
Synthesizes keystrokes, mouse motions, and button clicks.
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
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.
Use the mouse_event function.