There is another way, but this way I'm going to present, involve the use of pure X11, although seeing your question's tags, an answer that uses X11 is acceptable too.
That said, let me start by introducing the function where all happens, one thing, I'm going to be a bit verbose, in case of some other people that don't understand how use this function.
void
mouse_click(Display *display, int x, int y, int click_type, struct timeval *t);
- display structure previously returned by
XOpenDisplay()
that contains all the information about the X server.
- x the x coordinate of the pointer relative to the root of the screen.
- y the y coordinate of the pointer relative to the root of the screen.
- click_type the type of the click. For this answer, either
MOUSE_RIGHT_CLICK
or MOUSE_LEFT_CLICK
- t
timeval
structure, specified the time interval the click should remain pressed.
Implementation
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#define portable_usleep(t) select(0, NULL, NULL,NULL, t)
enum { MOUSE_RIGHT_CLICK, MOUSE_LEFT_CLICK };
void
mouse_click(Display *display, int x, int y, int click_type, struct timeval *t)
{
Window root;
XEvent event;
root = DefaultRootWindow(display);
XWarpPointer(display, None, root, 0, 0, 0, 0, x, y);
memset(&event, 0, sizeof(event));
event.xbutton.type = ButtonPress;
event.xbutton.button = click_type;
event.xbutton.same_screen = True;
XQueryPointer(display, root, &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, "XSendEvent()\n");
XFlush(display);
portable_usleep(t); /* keeps the click pressed */
event.type = ButtonRelease;
event.xbutton.state = 0x100;
if(XSendEvent(display, PointerWindow, True, 0xfff, &event)==0)
fprintf(stderr, "XSendEvent()\n");
XFlush(display);
}
Well, this function it's pretty straight forward, for example, left click at position 500,645 button pressed for half a second, this is how:
int
main(void)
{
int x;
int y;
Display *display;
struct timeval t;
display = XOpenDisplay(NULL);
if(!display) {
fprintf(stderr, "Can't open display!\n");
exit(EXIT_FAILURE);
}
x = 500;
y = 645;
t.tv_sec = 0;
t.tv_usec = 500000; /* 0.5 secs */
mouse_click(display, x, y, MOUSE_LEFT_CLICK, &t);
XCloseDisplay(display);
return 0;
}
Compile
$ gcc -o click click.c -lX11