implementing support for gestures with edge and corner detection

Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
master
Maarten van Gompel 4 years ago
parent ee47ac2a5b
commit 827d4c8f2c
  1. 5
      Makefile
  2. 9
      README.md
  3. 22
      config.def.h
  4. 9
      lisgd.1
  5. 198
      lisgd.c

@ -2,6 +2,9 @@ SRC = lisgd.c
OBJ = ${SRC:.c=.o} OBJ = ${SRC:.c=.o}
LDFLAGS = -linput -lm LDFLAGS = -linput -lm
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
all: options lisgd all: options lisgd
options: options:
@ -19,7 +22,7 @@ config.h:
cp config.def.h $@ cp config.def.h $@
lisgd: ${OBJ} lisgd: ${OBJ}
${CC} -g -o $@ ${OBJ} ${LDFLAGS} ${CC} -g -o $@ ${OBJ} -I${X11INC} -lX11 ${LDFLAGS}
install: all install: all
mkdir -p ${DESTDIR}${PREFIX}/bin mkdir -p ${DESTDIR}${PREFIX}/bin

@ -32,12 +32,11 @@ Flags:
- **-d [devicenodepath]**: Defines the dev filesystem device to monitor - **-d [devicenodepath]**: Defines the dev filesystem device to monitor
- Example: `lisgd -d /dev/input/input1` - Example: `lisgd -d /dev/input/input1`
- **-g [nfingers,gesture,command]**: Allows you to bind a gesture wherein - **-g [nfingers,gesture,edge,distance,command]**: Allows you to bind a gesture wherein nfingers is an integer, gesture is
nfingers is an integer, gesture is one of {LR,RL,DU,UD,DLUR,URDL,ULDR,DLUR}, 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
and command is the shell command to be executed. The -g option can be used
multiple times to bind multiple gestures. multiple times to bind multiple gestures.
- Single Gesture Example: `lisgd -g "1,LR,notify-send swiped lr"` - 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"` - 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 - **-m [timeoutms]**: Number of milliseconds gestures must be performed within
to be registered. After the timeoutms value; the gesture won't be registered. to be registered. After the timeoutms value; the gesture won't be registered.
- Example: `lisgd -m 1200` - Example: `lisgd -m 1200`

@ -15,18 +15,20 @@ unsigned int degreesleniency = 15;
unsigned int timeoutms = 800; unsigned int timeoutms = 800;
unsigned int orientation = 0; unsigned int orientation = 0;
unsigned int verbose = 0; unsigned int verbose = 0;
double edgesizex = 50.0;
double edgesizey = 50.0;
char *device = "/dev/input/event1"; char *device = "/dev/input/event1";
Gesture gestures[] = { Gesture gestures[] = {
/* nfingers gesturetype command */ /* nfingers gesturetype command */
{ 1, SwipeLR, "xdotool key --clearmodifiers Alt+Shift+e" }, { 1, SwipeLR, EdgeAny, DistanceAny, "xdotool key --clearmodifiers Alt+Shift+e" },
{ 1, SwipeRL, "xdotool key --clearmodifiers Alt+Shift+r" }, { 1, SwipeRL, EdgeAny, DistanceAny, "xdotool key --clearmodifiers Alt+Shift+r" },
{ 1, SwipeDLUR, "sxmo_vol.sh up" }, { 1, SwipeDLUR, EdgeAny, DistanceAny, "sxmo_vol.sh up" },
{ 1, SwipeURDL, "sxmo_vol.sh down" }, { 1, SwipeURDL, EdgeAny, DistanceAny, "sxmo_vol.sh down" },
{ 1, SwipeDRUL, "sxmo_brightness.sh up" }, { 1, SwipeDRUL, EdgeAny, DistanceAny, "sxmo_brightness.sh up" },
{ 1, SwipeULDR, "sxmo_brightness.sh down" }, { 1, SwipeULDR, EdgeAny, DistanceAny, "sxmo_brightness.sh down" },
{ 2, SwipeLR, "xdotool key --clearmodifiers Alt+e" }, { 2, SwipeLR, EdgeAny, DistanceAny, "xdotool key --clearmodifiers Alt+e" },
{ 2, SwipeRL, "xdotool key --clearmodifiers Alt+r" }, { 2, SwipeRL, EdgeAny, DistanceAny, "xdotool key --clearmodifiers Alt+r" },
{ 2, SwipeDU, "pidof svkbd-sxmo || svkbd-sxmo &" }, { 2, SwipeDU, EdgeAny, DistanceAny, "pidof svkbd-sxmo || svkbd-sxmo &" },
{ 2, SwipeUD, "pkill -9 svkbd-sxmo" }, { 2, SwipeUD, EdgeAny, DistanceAny, "pkill -9 svkbd-sxmo" },
}; };

@ -21,7 +21,8 @@ libinput touch events to run specific commands to execute. For example,
dragging left to right with one finger could execute a particular command 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 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. 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 Unlike other libinput gesture daemons, lisgd uses touch events to
recognize synthetic swipe gestures rather than using the libinput's recognize synthetic swipe gestures rather than using the libinput's
@ -41,9 +42,9 @@ you're using.
Path of the dev filesystem device to monitor (like /dev/input/event1). Path of the dev filesystem device to monitor (like /dev/input/event1).
.TP .TP
.BR \-g ", " \-g\ nfingers,gesture,command\fR .BR \-g ", " \-g\ nfingers,gesture,edge,distance,command\fR
Allow you to bind a gesture wherein nfingers is an integer, gesture is Allows 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. 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. The -g option can be used multiple times to bind multiple gestures.

@ -10,6 +10,7 @@
#include <sys/select.h> #include <sys/select.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <X11/Xlib.h>
/* Defines */ /* Defines */
#define MAXSLOTS 20 #define MAXSLOTS 20
@ -26,11 +27,35 @@ enum {
SwipeURDL, SwipeURDL,
SwipeULDR SwipeULDR
}; };
typedef int Swipe; 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 { typedef struct {
int nfswipe; int nfswipe;
Swipe swipe; Swipe swipe;
Edge edge;
Distance distance;
char *command; char *command;
} Gesture; } Gesture;
@ -41,9 +66,14 @@ typedef struct {
Gesture *gestsarr; Gesture *gestsarr;
int gestsarrlen; int gestsarrlen;
Swipe pendingswipe; Swipe pendingswipe;
Edge pendingedge;
Distance pendingdistance;
double xstart[MAXSLOTS], xend[MAXSLOTS], ystart[MAXSLOTS], yend[MAXSLOTS]; double xstart[MAXSLOTS], xend[MAXSLOTS], ystart[MAXSLOTS], yend[MAXSLOTS];
unsigned nfdown = 0, nfpendingswipe = 0; unsigned nfdown = 0, nfpendingswipe = 0;
struct timespec timedown; struct timespec timedown;
static Display *dpy;
static int screen;
static int screenwidth, screenheight;
void void
die(char * msg) die(char * msg)
@ -91,20 +121,108 @@ gesturecalculateswipe(double x0, double y0, double x1, double y1) {
return -1; 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 void
gestureexecute(Swipe swipe, int nfingers) { gestureexecute(Swipe swipe, int nfingers, Edge edge, Distance distance) {
int i; int i;
for (i = 0; i < gestsarrlen; i++) { for (i = 0; i < gestsarrlen; i++) {
if (verbose) { if (verbose) {
fprintf(stderr, fprintf(stderr,
"[Nfswipe/SwipeId]: Cfg (%d/%d) <=> Evt (%d/%d)\n", "[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, nfingers, swipe 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); if (verbose) fprintf(stderr, "Execute %s\n", gestsarr[i].command);
execcommand(gestsarr[i].command); execcommand(gestsarr[i].command);
break; //execute first match only
} }
} }
} }
@ -141,6 +259,25 @@ swipereorient(Swipe swipe, int orientation) {
return swipe; 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 void
touchdown(struct libinput_event *e) touchdown(struct libinput_event *e)
{ {
@ -197,7 +334,17 @@ touchup(struct libinput_event *e)
Swipe swipe = gesturecalculateswipe( Swipe swipe = gesturecalculateswipe(
xstart[slot], ystart[slot], xend[slot], yend[slot] 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++; if (pendingswipe == swipe) nfpendingswipe++;
resetslot(slot); resetslot(slot);
@ -206,7 +353,7 @@ touchup(struct libinput_event *e)
if ( if (
timeoutms > timeoutms >
((now.tv_sec - timedown.tv_sec) * 1000000 + (now.tv_nsec - timedown.tv_nsec) / 1000) / 1000 ((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; nfpendingswipe = 0;
} }
@ -300,7 +447,7 @@ main(int argc, char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
gestpt = strtok(argv[++i], ","); 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) { switch(j) {
case 0: gestsarr[gestsarrlen - 1].nfswipe = atoi(gestpt); break; case 0: gestsarr[gestsarrlen - 1].nfswipe = atoi(gestpt); break;
case 1: case 1:
@ -313,15 +460,40 @@ main(int argc, char *argv[])
if (!strcmp(gestpt, "ULDR")) gestsarr[gestsarrlen-1].swipe = SwipeULDR; if (!strcmp(gestpt, "ULDR")) gestsarr[gestsarrlen-1].swipe = SwipeULDR;
if (!strcmp(gestpt, "DRUL")) gestsarr[gestsarrlen-1].swipe = SwipeDRUL; if (!strcmp(gestpt, "DRUL")) gestsarr[gestsarrlen-1].swipe = SwipeDRUL;
break; 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 { } 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); 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 // E.g. no gestures passed on CLI - used gestures defined in config.def.h
if (gestsarrlen == 0) { if (gestsarrlen == 0) {
gestsarr = malloc(sizeof(gestures)); gestsarr = malloc(sizeof(gestures));
@ -329,9 +501,11 @@ main(int argc, char *argv[])
memcpy(gestsarr, gestures, sizeof(gestures)); memcpy(gestsarr, gestures, sizeof(gestures));
} }
// Modify gestures swipes based on orientation provided // Modify gestures swipes based on orientation provided
for (i = 0; i < gestsarrlen; i++) for (i = 0; i < gestsarrlen; i++) {
gestsarr[i].swipe = swipereorient(gestsarr[i].swipe, orientation); gestsarr[i].swipe = swipereorient(gestsarr[i].swipe, orientation);
gestsarr[i].edge = edgereorient(gestsarr[i].edge, orientation);
}
run(); run();
return 0; return 0;

Loading…
Cancel
Save