-
-
Save pioz/726474 to your computer and use it in GitHub Desktop.
// Written by Pioz. | |
// Compile with: gcc -o autoclick autoclick.c -lX11 | |
#include <stdio.h> // printf, fprintf and fflush | |
#include <string.h> // memset | |
#include <unistd.h> // sleep and usleep | |
#include <X11/Xlib.h> // X11 | |
#include <X11/Xutil.h> // XGetPixel and XDestroyImage | |
// Simulate mouse click | |
void | |
click (Display *display, int button) | |
{ | |
// Create and setting up the event | |
XEvent event; | |
memset (&event, 0, sizeof (event)); | |
event.xbutton.button = button; | |
event.xbutton.same_screen = True; | |
event.xbutton.subwindow = DefaultRootWindow (display); | |
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); | |
} | |
// Press | |
event.type = ButtonPress; | |
if (XSendEvent (display, PointerWindow, True, ButtonPressMask, &event) == 0) | |
fprintf (stderr, "Error to send the event!\n"); | |
XFlush (display); | |
usleep (1); | |
// Release | |
event.type = ButtonRelease; | |
if (XSendEvent (display, PointerWindow, True, ButtonReleaseMask, &event) == 0) | |
fprintf (stderr, "Error to send the event!\n"); | |
XFlush (display); | |
usleep (1); | |
} | |
// Get mouse coordinates | |
void | |
coords (Display *display, int *x, int *y) | |
{ | |
XEvent event; | |
XQueryPointer (display, DefaultRootWindow (display), | |
&event.xbutton.root, &event.xbutton.window, | |
&event.xbutton.x_root, &event.xbutton.y_root, | |
&event.xbutton.x, &event.xbutton.y, | |
&event.xbutton.state); | |
*x = event.xbutton.x; | |
*y = event.xbutton.y; | |
} | |
// Move mouse pointer (relative) | |
void | |
move (Display *display, int x, int y) | |
{ | |
XWarpPointer (display, None, None, 0,0,0,0, x, y); | |
XFlush (display); | |
usleep (1); | |
} | |
// Move mouse pointer (absolute) | |
void | |
move_to (Display *display, int x, int y) | |
{ | |
int cur_x, cur_y; | |
coords (display, &cur_x, &cur_y); | |
XWarpPointer (display, None, None, 0,0,0,0, -cur_x, -cur_y); | |
XWarpPointer (display, None, None, 0,0,0,0, x, y); | |
usleep (1); | |
} | |
// Get pixel color at coordinates x,y | |
void | |
pixel_color (Display *display, int x, int y, XColor *color) | |
{ | |
XImage *image; | |
image = XGetImage (display, DefaultRootWindow (display), x, y, 1, 1, AllPlanes, XYPixmap); | |
color->pixel = XGetPixel (image, 0, 0); | |
XDestroyImage (image); | |
XQueryColor (display, DefaultColormap(display, DefaultScreen (display)), color); | |
} | |
// START HERE | |
int | |
main (int argc, char *argv[]) | |
{ | |
int starting = 3; | |
int x = 0; | |
int y = 0; | |
// Open X display | |
Display *display = XOpenDisplay (NULL); | |
if (display == NULL) | |
{ | |
fprintf (stderr, "Can't open display!\n"); | |
return -1; | |
} | |
// Wait 3 seconds to start | |
printf ("Starting in "); | |
fflush (stdout); | |
while (starting > 0) | |
{ | |
printf ("\b\b\b %d...", starting); | |
fflush (stdout); | |
sleep (1); | |
starting--; | |
} | |
printf ("\n"); | |
// Start | |
while (1) | |
{ | |
click (display, Button1); | |
//move (display, x, y); | |
//coords (dispaly, &x, &y); | |
sleep (1); | |
} | |
// Close X display and exit | |
XCloseDisplay (display); | |
return 0; | |
} |
Hello,
there is a mem leak:
Line 82: replace XFree (image); with: XDestroyImage (image);
click method core dumped
Thank you so much for this code :)
Hey, Pioz.
This is some very useful code.
Do you know by any chane how to use the XEvents for clicking with another pointer device (that was created by e.g xinput create-master mouse
)?
I got this (compile with gcc -lXi -lX11 -lXtst -o test BackgroundMouse.c
):
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
#include <X11/extensions/XTest.h>
int main (int argc, char *argv[])
{
int delta_x = 500, delta_y = 160;
Display *display = XOpenDisplay(0);
Window root = DefaultRootWindow(display);
XIWarpPointer(display, 14, None, root, 0, 0, 0, 0, delta_x, delta_y);
XDevice *device = NULL;
device = XOpenDevice(display, 16);
XTestFakeDeviceButtonEvent(display, device, 1, True, 0, 0, CurrentTime);
XTestFakeDeviceButtonEvent(display, device, 1, False, 0, 0, CurrentTime);
XCloseDisplay(display);
}
but the difference between XTestFakeDeviceButtonEvent and your XEvent code for clicking is that your code can click without giving focus to a window but XTestFakeDeviceButtonEvent gives focus which is not useful for a auto clicker that should run in the background while I use my main virtual pointer for working on different stuff..
Thanks for the code, but does anyone have idea why this clicker wont click in chromium browser? It works in desktop apps.
Hola Agrego otras 2 funciones.
void moveReset() {
int xTmp=0,yTmp=0;
coords(&xTmp, &yTmp);
move(-xTmp, -yTmp);
}
void moveTo(Display *display, int x, int y) {
int xTmp=0,yTmp=0;
coords(&xTmp, &yTmp);
XWarpPointer(display, None, None, 0, 0, 0, 0, -xTmp, -yTmp);
XWarpPointer(display, None, None, 0, 0, 0, 0, x, y);
XFlush(display);
usleep(1);
}