Code:
/* Secondary Button Mouse stimulator
Compile with:
g++ -Wall -Ofast mouse.cpp -o mouse -lX11 -lXtst -lXext
*/
#include <fcntl.h>
#include <iostream>
#include <linux/input.h>
#include <string.h>
#include <unistd.h>
#include <X11/extensions/XTest.h>
#define MOUSEFILE "/dev/input/event0"
int main()
{
Display *dpy = NULL;
XEvent event;
dpy = XOpenDisplay(NULL);
int fd;
struct input_event ie;
Window root, child;
int rootX, rootY, winX, winY;
unsigned int mask;
XQueryPointer(dpy,DefaultRootWindow(dpy),&root,&child,&rootX,&rootY,&winX,&winY,&mask);
if((fd = open(MOUSEFILE, O_RDONLY)) == -1) {
perror("opening device");
exit(EXIT_FAILURE);
}
bool scrolling = false; // Cancel if user is scrolling with wheel
bool hold = false;
auto time_start_sec = ie.time.tv_sec;
auto time_stop_sec = ie.time.tv_sec;
auto time_start_usec = ie.time.tv_usec;
auto time_stop_usec = ie.time.tv_usec;
auto time_stop_usec_adj = ie.time.tv_usec;
auto time_real = ie.time.tv_usec;
float time_elapsed_adj;
float time_to_click = 0.4; // How long to hold the button down?
float time_to_hold = 1.2; // Time pressed for holding click
short startX = 0; // Mouse location (cancel click if moved)
short stopX = 0;
short startY = 0;
short stopY = 0;
short range = 10; // How much can mouse move whilst clicking?
std::cout << "Ready for mouse events..." << std::endl;
while(true){
// Grab mouse events:
read(fd, &ie, sizeof(struct input_event));
if (ie.type == 2) {
if (ie.code == 8 ){
std::cout << "Other button pressed!" << std::endl;
scrolling=true;
}
if (ie.code == 0) { rootX += ie.value;
}else if (ie.code == 1) { rootY += ie.value; }
} else if (ie.type == 1) {
if (ie.code == 272 ) {
if (ie.value == 0) {
// Timer from mouse events is used
time_real = ie.time.tv_sec;
time_stop_sec = time_real - time_start_sec ;
time_stop_usec = ie.time.tv_usec;
if (time_stop_usec < time_start_usec){
time_stop_usec_adj = time_stop_usec + (1000000 - time_start_usec);
if (time_real - time_start_sec > 0 )
time_stop_sec = time_stop_sec - 1;
}else
time_stop_usec_adj = time_stop_usec - time_start_usec;
time_elapsed_adj = float(time_stop_sec) + (float(time_stop_usec_adj) / 1000000);
stopX = rootX;
stopY = rootY;
std::cout << "Released @ X: " << stopX << " Y: " << stopY << " Time held: " << time_elapsed_adj << " seconds." << std::endl;
if (time_elapsed_adj >= time_to_click){
if (stopX <= (startX + range) && stopX >= (startX - range) && stopY <= (startY + range) && stopY >= (startY - range) && scrolling == false)
{
std::cout << "Clicked!" << std::endl;
if(time_elapsed_adj >= time_to_hold)
{
std::cout << "Activating Hold!" << std::endl;
XQueryPointer (dpy, RootWindow (dpy, 0), &event.xbutton.root,
&event.xbutton.window, &event.xbutton.x_root,
&event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y,
&event.xbutton.state);
usleep(1000);
XTestFakeButtonEvent (dpy, 3, True, CurrentTime);
usleep(1000);
XQueryPointer (dpy, RootWindow (dpy, 0), &event.xbutton.root,
&event.xbutton.window, &event.xbutton.x_root,
&event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y,
&event.xbutton.state);
hold = true;
}else{
std::cout << "Activating Click!" << std::endl;
XQueryPointer (dpy, RootWindow (dpy, 0), &event.xbutton.root,
&event.xbutton.window, &event.xbutton.x_root,
&event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y,
&event.xbutton.state);
usleep(1000);
XTestFakeButtonEvent (dpy, 3, True, CurrentTime);
usleep(1000);
XQueryPointer (dpy, RootWindow (dpy, 0), &event.xbutton.root,
&event.xbutton.window, &event.xbutton.x_root,
&event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y,
&event.xbutton.state);
usleep(1000);
XTestFakeButtonEvent (dpy, 3, False, CurrentTime);
usleep(1000);
XQueryPointer (dpy, RootWindow (dpy, 0), &event.xbutton.root,
&event.xbutton.window, &event.xbutton.x_root,
&event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y,
&event.xbutton.state);
}
}
}
}
// Mouse button is 'clicked' (initial press):
if (ie.value == 1) {
scrolling = false;
startX = rootX;
startY = rootY;
time_start_sec = ie.time.tv_sec;
time_start_usec = ie.time.tv_usec;
std::cout << "\nPressed @ X: " << startX << " Y: "<< startY << std::endl;
// Left-clicking cancels the hold:
if (hold){
std::cout << "Cancelling hold!" << std::endl;
XQueryPointer (dpy, RootWindow (dpy, 0), &event.xbutton.root,
&event.xbutton.window, &event.xbutton.x_root,
&event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y,
&event.xbutton.state);
usleep(1000);
XTestFakeButtonEvent (dpy, 3, False, CurrentTime);
usleep(1000);
XQueryPointer (dpy, RootWindow (dpy, 0), &event.xbutton.root,
&event.xbutton.window, &event.xbutton.x_root,
&event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y,
&event.xbutton.state);
}
hold = false;
}
}
}
}
XCloseDisplay (dpy);
return 0;
}
Code on github: