-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.c
250 lines (209 loc) · 9.48 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
#include <X11/X.h>
#include <stdbool.h>
#include <X11/Xlib.h> /* defines common Xlib functions and structs. */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h> /*need to wait */
#include <math.h>
//IMPORTANT! Keep in mind that in X, x is the left to right coordinate and it starts at the left corner
//And y is the top to bottom coordinate and starts at the top. e.g. 0,0 is the top left corner of your screens
//Modify these variables and recompile the program in order to tune the settings to your liking
//Declare if you want your cursor to moove smoothly or to just warp to the location, 1 for smooth, 0 for warp
//ISSMOOTH makes your cursor travel the distance it should in increments
const bool ISSMOOTH=1;
//This variable will be how many pixels your cursor should cross in a leap
const int SMOOTHINCREMENT = 5;
//This variable will be the time the loop sleeps between increments, in microseconds. usleep is not the most reliable function, so play with this variable, see what works for you
const int SLEEPTIME = 200;
//Declare if you want your cursor to warp ourside of the window. If it does, values for where are treated as abosulte values in pixels.
//You can use - and + to determine whether it's top or bottom, left or right.
//For X - is left, + is right. For Y - is top, + is bottom. 0 is Warp inside, 1 is Warp outside of the window.
const bool WARPOUTSIDE=0;
//If warpOutside!=0, the pointer will be teleported inside of the window and the values for where are treated as relative
//percentage values of the size of the window.
//X goes from left to right, e.g. 0 is the left side, 100 is the right, Y goes from top to bottom, e.g. 0 is the top, 100 is the bottom
const double WARPXPLACE=90;
const double WARPYPLACE=90;
//Always teleport to the desired place, even when already inside of the window.
//1 is always, 0 is check if the window is inside and/or inside of the "tolerance zone"
const bool ALWAYSWARP=0;
//Declare how much the tolerance for distance from the window should be i.e. how far outside of the active window can the cursor be before it gets teleported to the desired place
//Treated as a rectangle outside of the window
const int DISTANCETOLERANCE=50;
//Returns the parent window of "window" (i.e. the ancestor of window
//that is a direct child of the root, or window itself if it is a direct child).
//If window is the root window, returns window.
Window getTopLevelParent(Display *display, Window window)
{
//Variables to hold the current parent, root, pointer to children, etc.
Window parent;
Window root;
Window *children;
unsigned int num_children;
//Until we have to exit because we have found the top level window, search further
while (1)
{
//Query the tree of the current iteration of "window" and check if XQueryTree is "0". If true, there has been an error.
if (0 == XQueryTree(display, window, &root, &parent, &children, &num_children))
{
fprintf(stderr, "XQueryTree error\n");
}
//Test for NULL with if
if (children)
{
XFree(children);
}
//Check if the current iteration is either the root window or its parent is the root window.
//If either is true, then return the window, otherwise iterate further with the parent window as the new window to look into.
if (window == root || parent == root)
{
return window;
}
else
{
window = parent;
}
}
}
//This function will teleport the cursor to your desired location as smooth as possible on a screen baby
void warpSmoothly(int *destinationX, int *destinationY, int *mouseXCoordinate, int *mouseYCoordinate, Display *dsp)
{
//Use doubles, as you need the precision
//Create ints to know in which direction we are sending the cursors and fill them
int leftToRight = -1;
int topToBottom = -1;
//If the destination is to the right and lower respectively, switch the directions from the default ones
if (*destinationX > *mouseXCoordinate ) leftToRight = 1;
if (*destinationY > *mouseYCoordinate ) topToBottom = 1;
//Commit the lengths of the X and Y path, so we do less math
int lengthOfXPath = (*destinationX - *mouseXCoordinate)*leftToRight;
int lengthOfYPath = (*destinationY - *mouseYCoordinate)*topToBottom;
//We also need the length of the path we need to take, in order to move at the right ratios along the X and Y axis
double lengthOfPath = sqrt((pow(lengthOfXPath, 2)+pow(lengthOfYPath, 2)));
//We will always need the ratio of PathX and PathY to the true path
double ratioX = (double) lengthOfXPath/lengthOfPath;
double ratioY = (double) lengthOfYPath/lengthOfPath;
//Commit the X and Y increments to memory so we don't do too much math
double howMuchToMoveX = (((double)SMOOTHINCREMENT)*ratioX);
double howMuchToMoveY = (((double)SMOOTHINCREMENT)*ratioY);
double howMuchToMove = (double)SMOOTHINCREMENT;
//We use these variables to track the length of the way we need to go in the X and Y directions respectively
double trackY = howMuchToMoveY;
double trackX = howMuchToMoveX;
for( double trackPath = howMuchToMove; trackPath < lengthOfPath; trackPath += howMuchToMove)
{
//Increment the spots along the X and Y paths after waiting, and warp the pointer to the newly incremented place
usleep(SLEEPTIME);
trackX += howMuchToMoveX;
trackY += howMuchToMoveY;
XWarpPointer(dsp,None, RootWindow(dsp, 0), 0, 0, 0, 0, (*mouseXCoordinate + trackX*leftToRight), (*mouseYCoordinate + trackY*topToBottom));
XFlush(dsp);
}
//Send it the rest of the way there
XWarpPointer(dsp, None, RootWindow(dsp, 0), 0, 0, 0, 0, *destinationX, *destinationY);
}
//Teleport the cursor to the focused window, given its X,Y position, Height, Width, Mouse Position X and Y, and the Display)
void warpToFocusedWindow(int *focusedX, int *focusedY, int *focusedHeight, int *focusedWidth, int *mouseXCoordinate, int *mouseYCoordinate, Display *dsp)
{
//Declare destination values for the cursor
int destinationX=0;
int destinationY=0;
//Check if you want to warp outside of the window, if not, warp inside with the normal procedure
if(WARPOUTSIDE==1)
{
//This is a nested if to figure out where the cursor should lie, to the left or to the right?
if(WARPXPLACE < 0)
{
//Top or bottom?
if(WARPYPLACE < 0)
{
destinationX=(*focusedX+WARPXPLACE);
destinationY=(*focusedY+WARPYPLACE);
}
else
{
destinationX=(*focusedX+WARPXPLACE);
destinationY=(*focusedY+*focusedHeight+WARPYPLACE);
}
}
else
{
//Top or bottom?
if(WARPYPLACE < 0 )
{
destinationX=(*focusedX+*focusedWidth+WARPXPLACE);
destinationY=(*focusedY+WARPYPLACE);
}
else
{
destinationX=(*focusedX+*focusedWidth+WARPXPLACE);
destinationY=(*focusedY+*focusedHeight+WARPYPLACE);
}
}
}
else
{
//Convert the location input into percentage and use it at the same time
destinationX=*focusedX+((*focusedWidth*WARPXPLACE)/100);
destinationY=*focusedY+((*focusedHeight*WARPYPLACE)/100);
}
//Warp with the coordinates we got, either smoothly or not
if(ISSMOOTH==1)
{
warpSmoothly(&destinationX, &destinationY, mouseXCoordinate, mouseYCoordinate, dsp);
}
else
{
XWarpPointer(dsp, None, RootWindow(dsp, 0), 0, 0, 0, 0, destinationX, destinationY);
}
}
int main()
{
//Initialise the pointer variable returned when opening a display and open the connection to the dsp
Display *dsp = XOpenDisplay( NULL );
if( !dsp ){ return 1; } //if there is no Display, exit
//Initialise structure to hold all of the Event output, namely the mouse coordinates
XEvent event;
//Query current pointer position
XQueryPointer(dsp, RootWindow(dsp, DefaultScreen(dsp)),
&event.xbutton.root, &event.xbutton.window,
&event.xbutton.x_root, &event.xbutton.y_root,
&event.xbutton.x, &event.xbutton.y,
&event.xbutton.state);
//Pump the mouse coordinates into more usable variables
int *mouseXCoordinate=&event.xbutton.x;
int *mouseYCoordinate=&event.xbutton.y;
//Initialise structures for the focused window, and its parent.
//Needed because GTK does some weird thing where the thing that holds the focus is a 1x1 child window of the parent
Window focusedWindow;
Window TopLevelParentofFocused;
int feedback;
//Holds the attributes of the window we actually want to query
XWindowAttributes focusedWindowAttributes;
//Gets the focused window, then sorts through its parents, thank you GTK, and gets the attributes of the parents
XGetInputFocus(dsp, &focusedWindow, &feedback);
TopLevelParentofFocused=getTopLevelParent(dsp, focusedWindow);
XGetWindowAttributes(dsp, TopLevelParentofFocused, &focusedWindowAttributes);
//Port the position and size of the window into more usable variables.
int *focusedX=&focusedWindowAttributes.x;
int *focusedY=&focusedWindowAttributes.y;
int *focusedWidth=&focusedWindowAttributes.width;
int *focusedHeight=&focusedWindowAttributes.height;
//Check if user wants to always teleport, otherwise go through the position checks
if(ALWAYSWARP==1)
{
warpToFocusedWindow(focusedX, focusedY, focusedHeight, focusedWidth, mouseXCoordinate, mouseYCoordinate,dsp);
}
else
{
//Check if the cursor is inside of the acceptable rectangle where it should not be teleported to the new focused screen
if(*mouseXCoordinate < (*focusedX - DISTANCETOLERANCE)
|| *mouseXCoordinate > (*focusedX+*focusedWidth+DISTANCETOLERANCE)
|| *mouseYCoordinate < (*focusedY - DISTANCETOLERANCE)
|| *mouseYCoordinate > (*focusedY + *focusedHeight + DISTANCETOLERANCE) ) {
warpToFocusedWindow(focusedX, focusedY, focusedHeight, focusedWidth, mouseXCoordinate, mouseYCoordinate,dsp);
}
}
//You have to close the connection to the display!!!
XCloseDisplay( dsp );
}