M Makefile => Makefile +4 -1
@@ 2,6 2,9 @@ SRC = lisgd.c
OBJ = ${SRC:.c=.o}
LDFLAGS = -linput -lm
+X11INC = /usr/X11R6/include
+X11LIB = /usr/X11R6/lib
+
all: options lisgd
options:
@@ 19,7 22,7 @@ config.h:
cp config.def.h $@
lisgd: ${OBJ}
- ${CC} -g -o $@ ${OBJ} ${LDFLAGS}
+ ${CC} -g -o $@ ${OBJ} -I${X11INC} -lX11 ${LDFLAGS}
install: all
mkdir -p ${DESTDIR}${PREFIX}/bin
M README.md => README.md +12 -13
@@ 4,7 4,7 @@ Lisgd (libinput **synthetic** gesture daemon) lets you bind gestures based on
libinput touch events to run specific commands to execute. For example,
dragging left to right with one finger could execute a particular command
like launching a terminal. Directional L-R, R-L, U-D, and D-U gestures and
-diagnol LD-RU, RD-LU, UR-DL, UL-DR gestures are supported with 1 through
+diagnol LD-RU, RD-LU, UR-DL, UL-DR gestures are supported with 1 through
n fingers.
Unlike other libinput gesture daemons, lisgd uses touch events to
@@ 32,25 32,24 @@ Flags:
- **-d [devicenodepath]**: Defines the dev filesystem device to monitor
- Example: `lisgd -d /dev/input/input1`
-- **-g [nfingers,gesture,command]**: Allows you to bind a gesture wherein
- nfingers is an integer, gesture is one of {LR,RL,DU,UD,DLUR,URDL,ULDR,DLUR},
- and command is the shell command to be executed. The -g option can be used
+- **-g [nfingers,gesture,edge,distance,command]**: Allows you to bind a gesture wherein nfingers is an integer, gesture is
+one of {LR,RL,DU,UD,DLUR,URDL,ULDR,DLUR}, edge is one of * (any), N (none), L (left), R (right), T (top), B (bottom), TL (top left), TR (top right), BL (bottom left), BR (bottom right) and distance is one of * (any), S (short), M (medium), L (large). command is the shell command to be executed. The -g option can be used
multiple times to bind multiple gestures.
- - Single Gesture Example: `lisgd -g "1,LR,notify-send swiped lr"`
- - Multiple Gestures Example: `lisgd -g "1,LR,notify-send swiped lr" -g "1,RL,noitfy-send swiped rl"`
-- **-m [timeoutms]**: Number of milliseconds gestures must be performed within
+ - Single Gesture Example: `lisgd -g "1,LR,*,*,notify-send swiped lr"`
+ - Multiple Gestures Example: `lisgd -g "1,LR,*,*,notify-send swiped lr" -g "1,RL,R,*,noitfy-send swiped rl from right edge"`
+- **-m [timeoutms]**: Number of milliseconds gestures must be performed within
to be registered. After the timeoutms value; the gesture won't be registered.
- Example: `lisgd -m 1200`
-- **-o [orientation]**: Number of 90-degree rotations to translate gestures by.
- Can be set to 0-3. For example using 1; a L-R gesture would become a U-D
+- **-o [orientation]**: Number of 90-degree rotations to translate gestures by.
+ Can be set to 0-3. For example using 1; a L-R gesture would become a U-D
gesture. Meant to be used for screen-rotation.
- Example `lisgd -o 1`
-- **-r [degrees]**: Number of degrees offset each 45-degree interval may still
- be recognized within. Maximum value is 45. Default value is 15. E.g. U-D
- is a 180 degree gesture but with 15 degrees of leniency will be recognized
+- **-r [degrees]**: Number of degrees offset each 45-degree interval may still
+ be recognized within. Maximum value is 45. Default value is 15. E.g. U-D
+ is a 180 degree gesture but with 15 degrees of leniency will be recognized
between 165-195 degrees.
- Example: `lisgd -r 20`
-- **-t [threshold_units]**: Threshold in libinput units (pixels) after which a
+- **-t [threshold_units]**: Threshold in libinput units (pixels) after which a
gesture registers. Defaults to 300.
- Example: `lisgd -t 400`
- **-v**: Verbose mode, useful for debugging
M config.def.h => config.def.h +14 -12
@@ 1,5 1,5 @@
-/*
- distancethreshold: Minimum cutoff for a gestures to take effect
+/*
+ distancethreshold: Minimum cutoff for a gestures to take effect
degreesleniency: Offset degrees within which gesture is recognized (max=45)
timeoutms: Maximum duration for a gesture to take place in miliseconds
orientation: Number of 90 degree turns to shift gestures by
@@ 15,18 15,20 @@ unsigned int degreesleniency = 15;
unsigned int timeoutms = 800;
unsigned int orientation = 0;
unsigned int verbose = 0;
+double edgesizex = 50.0;
+double edgesizey = 50.0;
char *device = "/dev/input/event1";
Gesture gestures[] = {
/* nfingers gesturetype command */
- { 1, SwipeLR, "xdotool key --clearmodifiers Alt+Shift+e" },
- { 1, SwipeRL, "xdotool key --clearmodifiers Alt+Shift+r" },
- { 1, SwipeDLUR, "sxmo_vol.sh up" },
- { 1, SwipeURDL, "sxmo_vol.sh down" },
- { 1, SwipeDRUL, "sxmo_brightness.sh up" },
- { 1, SwipeULDR, "sxmo_brightness.sh down" },
- { 2, SwipeLR, "xdotool key --clearmodifiers Alt+e" },
- { 2, SwipeRL, "xdotool key --clearmodifiers Alt+r" },
- { 2, SwipeDU, "pidof svkbd-sxmo || svkbd-sxmo &" },
- { 2, SwipeUD, "pkill -9 svkbd-sxmo" },
+ { 1, SwipeLR, EdgeAny, DistanceAny, "xdotool key --clearmodifiers Alt+Shift+e" },
+ { 1, SwipeRL, EdgeAny, DistanceAny, "xdotool key --clearmodifiers Alt+Shift+r" },
+ { 1, SwipeDLUR, EdgeAny, DistanceAny, "sxmo_vol.sh up" },
+ { 1, SwipeURDL, EdgeAny, DistanceAny, "sxmo_vol.sh down" },
+ { 1, SwipeDRUL, EdgeAny, DistanceAny, "sxmo_brightness.sh up" },
+ { 1, SwipeULDR, EdgeAny, DistanceAny, "sxmo_brightness.sh down" },
+ { 2, SwipeLR, EdgeAny, DistanceAny, "xdotool key --clearmodifiers Alt+e" },
+ { 2, SwipeRL, EdgeAny, DistanceAny, "xdotool key --clearmodifiers Alt+r" },
+ { 2, SwipeDU, EdgeAny, DistanceAny, "pidof svkbd-sxmo || svkbd-sxmo &" },
+ { 2, SwipeUD, EdgeAny, DistanceAny, "pkill -9 svkbd-sxmo" },
};
M lisgd.1 => lisgd.1 +9 -8
@@ 20,8 20,9 @@ lisgd \- libinput synthetic gesture daemon
libinput touch events to run specific commands to execute. For example,
dragging left to right with one finger could execute a particular command
like launching a terminal. Directional L-R, R-L, U-D, and D-U gestures and
-diagnol LD-RU, RD-LU, UR-DL, UL-DR gestures are supported with 1 through
-n fingers.
+diagnol LD-RU, RD-LU, UR-DL, UL-DR gestures are supported with 1 through
+n fingers and can be bound to the screen's edges and/or made sensitive to
+the distance of the gesture.
Unlike other libinput gesture daemons, lisgd uses touch events to
recognize synthetic swipe gestures rather than using the libinput's
@@ 29,9 30,9 @@ gesture events. The advantage of this is that the synthetic gestures
you define via lisgd can be used on touchscreens, which normal libinput
gestures don't support.
-This program was built for use on the Pinephone however it could be used in
-general for any device that supports touch events, like laptop touchscreens
-or similar. You may want to adjust the threshold depending on the device
+This program was built for use on the Pinephone however it could be used in
+general for any device that supports touch events, like laptop touchscreens
+or similar. You may want to adjust the threshold depending on the device
you're using.
@@ 41,9 42,9 @@ you're using.
Path of the dev filesystem device to monitor (like /dev/input/event1).
.TP
-.BR \-g ", " \-g\ nfingers,gesture,command\fR
-Allow you to bind a gesture wherein nfingers is an integer, gesture is
-one of {LR,RL,DU,UD,DLUR,URDL,ULDR,DLUR}, and the shell command to be executed.
+.BR \-g ", " \-g\ nfingers,gesture,edge,distance,command\fR
+Allows you to bind a gesture wherein nfingers is an integer, gesture is
+one of {LR,RL,DU,UD,DLUR,URDL,ULDR,DLUR}, edge is one of * (any), N (none), L (left), R (right), T (top), B (bottom), TL (top left), TR (top right), BL (bottom left), BR (bottom right) and distance is one of * (any), S (short), M (medium), L (large). command is the shell command to be executed.
The -g option can be used multiple times to bind multiple gestures.
M lisgd.c => lisgd.c +194 -20
@@ 10,6 10,7 @@
#include <sys/select.h>
#include <time.h>
#include <unistd.h>
+#include <X11/Xlib.h>
/* Defines */
#define MAXSLOTS 20
@@ 26,11 27,35 @@ enum {
SwipeURDL,
SwipeULDR
};
-
typedef int Swipe;
+
+enum {
+ EdgeAny,
+ EdgeNone,
+ EdgeLeft,
+ EdgeRight,
+ EdgeTop,
+ EdgeBottom,
+ CornerTopLeft,
+ CornerTopRight,
+ CornerBottomLeft,
+ CornerBottomRight,
+};
+typedef int Edge;
+
+enum {
+ DistanceAny,
+ DistanceShort,
+ DistanceMedium,
+ DistanceLong,
+};
+typedef int Distance;
+
typedef struct {
int nfswipe;
Swipe swipe;
+ Edge edge;
+ Distance distance;
char *command;
} Gesture;
@@ 41,9 66,14 @@ typedef struct {
Gesture *gestsarr;
int gestsarrlen;
Swipe pendingswipe;
+Edge pendingedge;
+Distance pendingdistance;
double xstart[MAXSLOTS], xend[MAXSLOTS], ystart[MAXSLOTS], yend[MAXSLOTS];
unsigned nfdown = 0, nfpendingswipe = 0;
struct timespec timedown;
+static Display *dpy;
+static int screen;
+static int screenwidth, screenheight;
void
die(char * msg)
@@ 91,31 121,119 @@ gesturecalculateswipe(double x0, double y0, double x1, double y1) {
return -1;
}
+Distance
+gesturecalculatedistance(double x0, double y0, double x1, double y1, Swipe swipe) {
+ double dist = sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2));
+ double diag = sqrt(pow(screenwidth,2) + pow(screenheight,2));
+ switch (swipe) {
+ case SwipeDU:
+ case SwipeUD:
+ if (dist >= screenheight * 0.66) {
+ return DistanceLong;
+ } else if (dist >= screenheight * 0.33) {
+ return DistanceMedium;
+ } else {
+ return DistanceShort;
+ }
+ break;
+ case SwipeLR:
+ case SwipeRL:
+ if (dist >= screenwidth * 0.66) {
+ return DistanceLong;
+ } else if (dist >= screenwidth * 0.33) {
+ return DistanceMedium;
+ } else {
+ return DistanceShort;
+ }
+ break;
+ case SwipeULDR:
+ case SwipeDRUL:
+ case SwipeDLUR:
+ case SwipeURDL:
+ if (dist >= diag * 0.66) {
+ return DistanceLong;
+ } else if (dist >= diag * 0.33) {
+ return DistanceMedium;
+ } else {
+ return DistanceShort;
+ }
+ break;
+ }
+
+ return 0; //shouldn't happen
+}
+
+Edge
+gesturecalculateedge(double x0, double y0, double x1, double y1) {
+ Edge horizontal = EdgeNone;
+ Edge vertical = EdgeNone;
+ if (x0 <= edgesizex) {
+ horizontal = EdgeLeft;
+ } else if (x0 >= screenwidth - edgesizex) {
+ horizontal = EdgeRight;
+ } else if (x1 <= edgesizex) {
+ horizontal = EdgeLeft;
+ } else if (x1 >= screenwidth - edgesizex) {
+ horizontal = EdgeRight;
+ }
+ if (y0 <= edgesizey) {
+ vertical = EdgeTop;
+ } else if (y0 >= screenheight - edgesizey) {
+ vertical = EdgeBottom;
+ } else if (y1 <= edgesizey) {
+ vertical = EdgeTop;
+ } else if (y1 >= screenheight - edgesizey) {
+ vertical = EdgeBottom;
+ }
+ if (horizontal == EdgeLeft && vertical == EdgeTop) {
+ return CornerTopLeft;
+ } else if (horizontal == EdgeRight && vertical == EdgeTop) {
+ return CornerTopRight;
+ } else if (horizontal == EdgeLeft && vertical == EdgeBottom) {
+ return CornerBottomLeft;
+ } else if (horizontal == EdgeRight && vertical == EdgeBottom) {
+ return CornerBottomRight;
+ } else if (horizontal != EdgeNone) {
+ return horizontal;
+ } else {
+ return vertical;
+ }
+}
+
void
-gestureexecute(Swipe swipe, int nfingers) {
+gestureexecute(Swipe swipe, int nfingers, Edge edge, Distance distance) {
int i;
for (i = 0; i < gestsarrlen; i++) {
if (verbose) {
- fprintf(stderr,
- "[Nfswipe/SwipeId]: Cfg (%d/%d) <=> Evt (%d/%d)\n",
- gestsarr[i].nfswipe, gestsarr[i].swipe, nfingers, swipe
+ fprintf(stderr,
+ "[swipe]: Cfg(f=%d/s=%d/e=%d/d=%d) <=> Evt(f=%d/s=%d/e=%d/d=%d)\n",
+ gestsarr[i].nfswipe, gestsarr[i].swipe, gestsarr[i].edge, gestsarr[i].distance, nfingers, swipe, edge, distance
);
}
- if (gestsarr[i].nfswipe == nfingers && gestsarr[i].swipe == swipe) {
+ if (gestsarr[i].nfswipe == nfingers && gestsarr[i].swipe == swipe
+ && gestsarr[i].distance <= distance
+ && (gestsarr[i].edge == EdgeAny || gestsarr[i].edge == edge ||
+ ((edge == CornerTopLeft || edge == CornerTopRight) && gestsarr[i].edge == EdgeTop) ||
+ ((edge == CornerBottomLeft || edge == CornerBottomRight) && gestsarr[i].edge == EdgeBottom) ||
+ ((edge == CornerTopLeft || edge == CornerBottomLeft) && gestsarr[i].edge == EdgeLeft) ||
+ ((edge == CornerTopRight || edge == CornerBottomRight) && gestsarr[i].edge == EdgeRight)
+ )
+ ) {
if (verbose) fprintf(stderr, "Execute %s\n", gestsarr[i].command);
execcommand(gestsarr[i].command);
+ break; //execute first match only
}
}
}
-static int
+static int
libinputopenrestricted(const char *path, int flags, void *user_data)
{
int fd = open(path, flags);
return fd < 0 ? -errno : fd;
}
-
+
static void
libinputcloserestricted(int fd, void *user_data)
{
@@ 141,6 259,25 @@ swipereorient(Swipe swipe, int orientation) {
return swipe;
}
+Edge
+edgereorient(Edge edge, int orientation) {
+ while (orientation > 0) {
+ switch(edge) {
+ // 90deg per turn
+ case EdgeLeft: edge = EdgeTop; break;
+ case EdgeRight: edge = EdgeBottom; break;
+ case EdgeTop: edge = EdgeRight; break;
+ case EdgeBottom: edge = EdgeLeft; break;
+ case CornerTopLeft: edge = CornerTopRight; break;
+ case CornerTopRight: edge = CornerBottomRight; break;
+ case CornerBottomLeft: edge = CornerTopLeft; break;
+ case CornerBottomRight: edge = CornerBottomLeft; break;
+ }
+ orientation--;
+ }
+ return edge;
+}
+
void
touchdown(struct libinput_event *e)
{
@@ 197,17 334,27 @@ touchup(struct libinput_event *e)
Swipe swipe = gesturecalculateswipe(
xstart[slot], ystart[slot], xend[slot], yend[slot]
);
- if (nfpendingswipe == 0) pendingswipe = swipe;
+ Edge edge = gesturecalculateedge(
+ xstart[slot], ystart[slot], xend[slot], yend[slot]
+ );
+ Distance distance = gesturecalculatedistance(
+ xstart[slot], ystart[slot], xend[slot], yend[slot], swipe
+ );
+ if (nfpendingswipe == 0) {
+ pendingswipe = swipe;
+ pendingedge = edge;
+ pendingdistance = distance;
+ }
if (pendingswipe == swipe) nfpendingswipe++;
resetslot(slot);
// All fingers up - check if within milisecond limit, exec, & reset
if (nfdown == 0) {
if (
- timeoutms >
+ timeoutms >
((now.tv_sec - timedown.tv_sec) * 1000000 + (now.tv_nsec - timedown.tv_nsec) / 1000) / 1000
- ) gestureexecute(swipe, nfpendingswipe);
-
+ ) gestureexecute(swipe, nfpendingswipe, edge, distance);
+
nfpendingswipe = 0;
}
}
@@ 238,7 385,7 @@ run()
die("Couldn't set mode to capture events");
}
- // E.g. initially invalidate every slot
+ // E.g. initially invalidate every slot
for (i = 0; i < MAXSLOTS; i++) {
xend[i] = NOMOTION;
yend[i] = NOMOTION;
@@ 266,7 413,7 @@ run()
}
libinput_unref(li);
}
-
+
int
main(int argc, char *argv[])
{
@@ 300,10 447,10 @@ main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
gestpt = strtok(argv[++i], ",");
- for (j = 0; gestpt != NULL && j < 3; gestpt = strtok(NULL, ","), j++) {
+ for (j = 0; gestpt != NULL && j < 5; gestpt = strtok(NULL, ","), j++) {
switch(j) {
case 0: gestsarr[gestsarrlen - 1].nfswipe = atoi(gestpt); break;
- case 1:
+ case 1:
if (!strcmp(gestpt, "LR")) gestsarr[gestsarrlen-1].swipe = SwipeLR;
if (!strcmp(gestpt, "RL")) gestsarr[gestsarrlen-1].swipe = SwipeRL;
if (!strcmp(gestpt, "DU")) gestsarr[gestsarrlen-1].swipe = SwipeDU;
@@ 313,15 460,40 @@ main(int argc, char *argv[])
if (!strcmp(gestpt, "ULDR")) gestsarr[gestsarrlen-1].swipe = SwipeULDR;
if (!strcmp(gestpt, "DRUL")) gestsarr[gestsarrlen-1].swipe = SwipeDRUL;
break;
- case 2: gestsarr[gestsarrlen - 1].command = gestpt; break;
+ case 2:
+ if (!strcmp(gestpt, "L")) gestsarr[gestsarrlen-1].edge = EdgeLeft;
+ if (!strcmp(gestpt, "R")) gestsarr[gestsarrlen-1].edge = EdgeRight;
+ if (!strcmp(gestpt, "T")) gestsarr[gestsarrlen-1].edge = EdgeTop;
+ if (!strcmp(gestpt, "B")) gestsarr[gestsarrlen-1].edge = EdgeBottom;
+ if (!strcmp(gestpt, "TL")) gestsarr[gestsarrlen-1].edge = CornerTopLeft;
+ if (!strcmp(gestpt, "TR")) gestsarr[gestsarrlen-1].edge = CornerTopRight;
+ if (!strcmp(gestpt, "BL")) gestsarr[gestsarrlen-1].edge = CornerBottomLeft;
+ if (!strcmp(gestpt, "BR")) gestsarr[gestsarrlen-1].edge = CornerBottomRight;
+ if (!strcmp(gestpt, "N")) gestsarr[gestsarrlen-1].edge = EdgeNone;
+ if (!strcmp(gestpt, "*")) gestsarr[gestsarrlen-1].edge = EdgeAny;
+ break;
+ case 3:
+ if (!strcmp(gestpt, "L")) gestsarr[gestsarrlen-1].distance = DistanceLong;
+ if (!strcmp(gestpt, "M")) gestsarr[gestsarrlen-1].distance = DistanceMedium;
+ if (!strcmp(gestpt, "S")) gestsarr[gestsarrlen-1].distance = DistanceShort;
+ if (!strcmp(gestpt, "*")) gestsarr[gestsarrlen-1].distance = DistanceAny;
+ break;
+ case 4: gestsarr[gestsarrlen - 1].command = gestpt; break;
}
}
} else {
- fprintf(stderr, "lisgd [-v] [-d /dev/input/0] [-o 0] [-t 200] [-r 20] [-m 400] [-g '1,LR,notify-send swiped left to right']\n");
+ fprintf(stderr, "lisgd [-v] [-d /dev/input/0] [-o 0] [-t 200] [-r 20] [-m 400] [-g '1,LR,L,notify-send swiped left to right from left edge']\n");
exit(1);
}
}
+ //get display size
+ if (!(dpy = XOpenDisplay(0)))
+ die("cannot open display");
+ screen = DefaultScreen(dpy);
+ screenwidth = DisplayWidth(dpy, screen);
+ screenheight = DisplayHeight(dpy, screen);
+
// E.g. no gestures passed on CLI - used gestures defined in config.def.h
if (gestsarrlen == 0) {
gestsarr = malloc(sizeof(gestures));
@@ 329,9 501,11 @@ main(int argc, char *argv[])
memcpy(gestsarr, gestures, sizeof(gestures));
}
- // Modify gestures swipes based on orientation provided
- for (i = 0; i < gestsarrlen; i++)
+ // Modify gestures swipes based on orientation provided
+ for (i = 0; i < gestsarrlen; i++) {
gestsarr[i].swipe = swipereorient(gestsarr[i].swipe, orientation);
+ gestsarr[i].edge = edgereorient(gestsarr[i].edge, orientation);
+ }
run();
return 0;