Skip to content

Instantly share code, notes, and snippets.

@bathtime
Created April 13, 2019 13:11
Show Gist options
  • Save bathtime/faa2fc830391e2323107fdf171756509 to your computer and use it in GitHub Desktop.
Save bathtime/faa2fc830391e2323107fdf171756509 to your computer and use it in GitHub Desktop.
/*
Key/Touch/Secondary Button Stimulator
Compile with:
gcc -Wall -O2 mouse.c -o mouse -lX11 -lXtst -lXext
SendKey function courtesy of:
https://bharathisubramanian.wordpress.com/2010/03/14/x11-fake-key-event-generation-using-xtest-ext/
*/
#include<fcntl.h>
#include<unistd.h>
#include<stdio.h>
#include<linux/input.h>
#include<X11/extensions/XTest.h>
#include<stdlib.h>
int fast_abs(int num)
{
if(num < 0)
num *= -1;
return num;
}
void fast_memcpy(char *str, const char *str2, int length)
{
for(;--length > -1; )
str[length] = str2[length];
}
void fast_memcpyS(char *str, const char *str2, int start, int length)
{
for(; --length > -1; )
str[length + start] = str2[length];
}
int fast_memcmp(char *str, const char *str2, int length)
{
length--;
do{
}while(str[length] == str2[length] && --length > -1);
return ++length;
}
/*static void SendKey(Display * disp, KeySym keysym, KeySym modsym)
{
KeyCode keycode = 0, modcode = 0;
keycode = XKeysymToKeycode (disp, keysym);
if (keycode == 0) return;
XTestGrabControl (disp, True);
if (modsym != 0) {
modcode = XKeysymToKeycode(disp, modsym);
XTestFakeKeyEvent (disp, modcode, True, 0);
}
XTestFakeKeyEvent (disp, keycode, True, 0);
XTestFakeKeyEvent (disp, keycode, False, 0);
if (modsym != 0)
XTestFakeKeyEvent (disp, modcode, False, 0);
XSync (disp, False);
XTestGrabControl (disp, False);
}*/
char *get_device()
{
char data[120];
int ret;
FILE * const file = fopen( "/proc/bus/input/devices", "r");
do
ret=fscanf(file, "%*2s %s %*[^\n]\n", data);
while(fast_memcmp(data, "Name=\"FT5406", 12) != 0 && ret != EOF);
fscanf(file, "%*[^\n]\n%*[^\n]\n%*[^\n]\n%*2s %*15s %6s", data);
char *result = (char*)malloc(20);
fast_memcpyS(result, "/dev/input/", 0, 11);
fast_memcpyS(result, data, 11, 6);
return result;
}
void right(Display *dpy, XEvent event)
{
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(5000);
XTestFakeButtonEvent(dpy, 3, True, CurrentTime);
usleep(5000);
XTestFakeButtonEvent(dpy, 3, False, CurrentTime);
usleep(5000);
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);
}
void middle(Display *dpy, XEvent event)
{
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(5000);
XTestFakeButtonEvent (dpy, 2, True, CurrentTime);
usleep(5000);
XTestFakeButtonEvent (dpy, 2, False, CurrentTime);
usleep(5000);
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);
}
int main() {
Display *dpy = XOpenDisplay(NULL);
XEvent event;
//Window rootw = XDefaultRootWindow(dpy);
short 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);
char *eventFile = get_device();
//printf("Using device: %s\n", eventFile);
if((fd = open(eventFile, O_RDONLY)) == -1) {
perror("opening device");
return 1;
}
time_t time_start_sec = ie.time.tv_sec;
time_t time_stop_sec = ie.time.tv_sec;
time_t time_start_usec = ie.time.tv_usec;
time_t time_stop_usec = ie.time.tv_usec;
time_t time_stop_usec_adj = ie.time.tv_usec;
time_t time_real = ie.time.tv_sec;
float time_elapsed_adj;
#define time_to_click .3
#define time_to_hold .9
#define time_max_flick 1
#define xyClickThreshold 10
int Ycaptured = 0;
int Xcaptured = 0;
// X = 0 - 799
// Y = 0 - 479
int Y = 0;
int X = 0;
int lastX = 0;
int lastY = 0;
int moved = 0;
#define bottomMinYEnter 450
#define bottomYRangeThreshold 15
#define bottomXRangeLower 245
#define bottomXRangeUpper 550
#define topMinYEnter 30
#define topYRangeThreshold 15
#define topXRangeLower 300
#define topXRangeUpper 750
#define leftMinXEnter 30
#define leftXRangeThreshold 15
#define leftYRangeLower 80
#define leftYRangeUpper 400
#define rightMinXEnter 785
#define rightXRangeThreshold 30
#define rightYRangeLower 50
#define rightYRangeUpper 430
//printf("Ready for mouse events...\n");
int maskOn = 0;
int masked = 0;
while(1){
// Grab mouse events:
read(fd, &ie, sizeof(struct input_event));
//printf("ie.type: %i ie.code: %i ie.value: %i moved: %i\n", ie.type, ie.code, ie.value, moved);
if (ie.type == 3)
{
if (ie.code == 1)
lastY = ie.value;
else if (ie.code == 0)
lastX = ie.value;
else if (!Ycaptured && ie.code == 54) {
Ycaptured = 1;
Y = ie.value;
}else if (!Xcaptured && ie.code == 53) {
Xcaptured = 1;
X = ie.value;
}
if (maskOn && ((Ycaptured && Y > bottomMinYEnter) || (Ycaptured && Y < topMinYEnter) || (Xcaptured && X < leftMinXEnter) || (Xcaptured && X > rightMinXEnter)) && !masked)
{
if ((Y > bottomMinYEnter || Y < topMinYEnter || X < leftMinXEnter || X > rightMinXEnter) && !masked){
masked = 1;
puts("\nMASKED!!!");
XGrabPointer(dpy, XDefaultRootWindow(dpy), False, PointerMotionMask|ButtonMotionMask|PointerMotionHintMask|ButtonReleaseMask|ButtonPressMask, GrabModeSync, GrabModeAsync, None, None, CurrentTime);
}
}
if (!moved)
{
time_start_sec = ie.time.tv_sec;
time_start_usec = ie.time.tv_usec;
//puts("Entered!");
}
++moved;
}
if (ie.type == 1 && ie.code == 330 && 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 = time_stop_sec + ((float)time_stop_usec_adj / 1000000);
//printf("time: %f\n", time_elapsed_adj);
Ycaptured = 0;
Xcaptured = 0;
if(time_elapsed_adj < time_max_flick)
{
if (Y > bottomMinYEnter && (Y - lastY) > bottomYRangeThreshold && fast_abs(X - lastX) < fast_abs(Y - lastY) && fast_abs(lastX - X) < fast_abs(lastY - Y) && X > bottomXRangeLower && X < bottomXRangeUpper)
{
system("/home/pi/scripts/kbd.sh&");
//SendKey (dpy, 32, 65513); // XK_Spaec, XK_Alt_L
printf("Bottom enter!\n");
}else if (Y < topMinYEnter && (lastY - Y) > topYRangeThreshold && fast_abs(X - lastX) < fast_abs(Y - lastY) && fast_abs(lastX - X) < fast_abs(lastY - Y) && X > topXRangeLower && X < topXRangeUpper )
{
system("xsetroot -name 'fsignal:3'");
//SendKey (dpy, 98, 65513); // XK_b, XK_Alt_L
//printf("Top enter!\n");
}else if (X < leftMinXEnter && (lastX - X) > leftXRangeThreshold && fast_abs(Y - lastY) < fast_abs(X - lastX) && fast_abs(lastY - Y) < fast_abs(lastX - X) && Y > leftYRangeLower && Y < leftYRangeUpper)
{
system("xsetroot -name 'fsignal:4'");
//SendKey (dpy, 107, 65513); // XK_k, XK_Alt_L
//printf("Left enter!\n");
}else if (X > rightMinXEnter && (X - lastX) > rightXRangeThreshold && fast_abs(Y - lastY) < fast_abs(X - lastX) && fast_abs(lastY - Y) < fast_abs(lastX - X) && Y > rightYRangeLower && Y < rightYRangeUpper)
{
system("xsetroot -name 'fsignal:5'");
//SendKey (dpy, 120, 65513); // XK_x, XK_Alt_L
//printf("Right enter!\n");
}
}
printf("Thres x: %i y: %i\n", fast_abs(lastX - X), fast_abs(Y - lastY));
if (time_elapsed_adj > time_to_click && fast_abs(Y - lastY) < xyClickThreshold && fast_abs(lastX - X) < xyClickThreshold)
{
printf("time: %f\n", time_elapsed_adj);
if(time_elapsed_adj > time_to_hold)
{
puts("Middle click down!");
middle(dpy, event);
//clickMiddle(dpy, event);
puts("Middle click up!");
}else{
puts("Right click down!");
right(dpy, event);
//clickRight(dpy, event);
puts("Right click up!");
}
}
if(maskOn && masked)
{
XFlush(dpy);
XSync(dpy, 0);
while(XPending(dpy))
{
puts("Pending event!");
XNextEvent(dpy, &event);
}
/* XQueryPointer(dpy, XDefaultRootWindow(dpy),
&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);
XAllowEvents(dpy, SyncPointer, CurrentTime);
usleep(1000);*/
XQueryPointer(dpy, XDefaultRootWindow(dpy),
&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);
XUngrabPointer(dpy, CurrentTime);
usleep(1000);
XQueryPointer(dpy, XDefaultRootWindow(dpy),
&event.xbutton.root, &event.xbutton.window,
&event.xbutton.x_root, &event.xbutton.y_root,
&event.xbutton.x, &event.xbutton.y,
&event.xbutton.state);
}
//}
puts("reset moved");
masked = 0;
// Reset moved:
moved = 0;
}
}
XCloseDisplay (dpy);
return 0;
}
@kleag
Copy link

kleag commented Dec 2, 2020

Hi, could you please include a license indication in the header comment such that your code can be used, modified and redistributed? If you wish the highest freedom as possible, I would suggest MIT or BSD. I you want to force others to keep your code free, use the GPL or LGPL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment