Compare commits

...

3 Commits

Author SHA1 Message Date
05a18e8874 implemented exec_command with wordexp(3)
this allows for a less error-prone parsing method
(as wordexp(3) is in libc) and enables for shell-like
word expansion, refer to the man page for more info
about wordexp(3)
2020-07-05 17:00:50 +02:00
d39281f9a6 minor fix
hotkeys don't get triggerd twice when after the right
keys are pressed one or more other keys are pressed
afterwards
2020-07-05 12:02:32 +02:00
ed7202e5c8 added key_buffer_compare_random/ordered
In the future one can specify that the hotkey triggers
only when the keys are pressed in the right order, or
in any order, this will be configured per-hotkey in the
config file
2020-07-05 11:58:21 +02:00

103
hkd.c
View File

@ -14,6 +14,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include <sys/inotify.h> #include <sys/inotify.h>
#include <wordexp.h>
#define FILE_NAME_MAX_LENGTH 255 #define FILE_NAME_MAX_LENGTH 255
#define KEY_BUFFER_SIZE 16 #define KEY_BUFFER_SIZE 16
@ -30,7 +31,7 @@
#define green(str) (ANSI_COLOR_GREEN str ANSI_COLOR_RESET) #define green(str) (ANSI_COLOR_GREEN str ANSI_COLOR_RESET)
#define red(str) (ANSI_COLOR_RED str ANSI_COLOR_RESET) #define red(str) (ANSI_COLOR_RED str ANSI_COLOR_RESET)
#define test_bit(yalv, abs_b) ((((char *)abs_b)[yalv/8] & (1<<yalv%8)) > 0) #define test_bit(yalv, abs_b) ((((char *)abs_b)[yalv/8] & (1<<yalv%8)) > 0)
#define die(str) {perror(red(str)); exit(errno);} #define die(str) {fputs(ANSI_COLOR_RED, stderr); perror(str); fputs(ANSI_COLOR_RESET, stderr); exit(errno);}
#define array_size(val) (val ? sizeof(val)/sizeof(val[0]) : 0) #define array_size(val) (val ? sizeof(val)/sizeof(val[0]) : 0)
#define EVENT_SIZE (sizeof(struct inotify_event)) #define EVENT_SIZE (sizeof(struct inotify_event))
@ -187,12 +188,12 @@ const char evdev_root_dir[] = "/dev/input/";
int key_buffer_add (struct key_buffer*, unsigned short); int key_buffer_add (struct key_buffer*, unsigned short);
int key_buffer_remove (struct key_buffer*, unsigned short); int key_buffer_remove (struct key_buffer*, unsigned short);
int key_buffer_compare (struct key_buffer *haystack, struct key_buffer *needle); int key_buffer_compare_random (struct key_buffer *, struct key_buffer *);
int key_buffer_compare_ordered (struct key_buffer *, struct key_buffer *);
void int_handler (int signum); void int_handler (int signum);
void exec_command (char *); void exec_command (char *);
void update_descriptors_list (int **, int *); void update_descriptors_list (int **, int *);
int prepare_epoll (int *, int, int); int prepare_epoll (int *, int, int);
void str_to_argv (char ***, const char *);
// TODO: use getopts() to parse command line options // TODO: use getopts() to parse command line options
int main (void) int main (void)
@ -260,11 +261,11 @@ int main (void)
) { ) {
switch (event.value) { switch (event.value) {
/* Key released */ /* Key released */
case (0): case 0:
key_buffer_remove(&pb, event.code); key_buffer_remove(&pb, event.code);
break; break;
/* Key pressed */ /* Key pressed */
case (1): case 1:
key_buffer_add(&pb, event.code); key_buffer_add(&pb, event.code);
break; break;
} }
@ -273,14 +274,14 @@ int main (void)
struct key_buffer comb1 = {{KEY_LEFTALT, KEY_S}, 2}; struct key_buffer comb1 = {{KEY_LEFTALT, KEY_S}, 2};
if (pb.size != prev_size) { if (pb.size > prev_size) {
printf("Pressed keys: "); printf("Pressed keys: ");
for (unsigned int i = 0; i < pb.size; i++) for (unsigned int i = 0; i < pb.size; i++)
printf("%d ", pb.buf[i]); printf("%d ", pb.buf[i]);
putchar('\n'); putchar('\n');
if (key_buffer_compare(&pb, &comb1)) if (key_buffer_compare_ordered(&pb, &comb1))
exec_command("ufetch"); exec_command("ls -l [a-z]*");
} }
} }
@ -336,31 +337,42 @@ void int_handler (int signum)
dead = 1; dead = 1;
} }
void exec_command (char *path) /* Executes a command from a string */
void exec_command (char *command)
{ {
char **argv = NULL; static wordexp_t result;
str_to_argv(&argv, path);
switch (fork()) { /* Expand the string for the program to run */
switch (wordexp (command, &result, 0)) {
case 0:
break;
case WRDE_NOSPACE:
/* If the error was WRDE_NOSPACE,
* then perhaps part of the result was allocated */
wordfree (&result);
return;
default:
/* Some other error */
fprintf(stderr, "Could not parse, %s is not valid", command);
return;
}
pid_t cpid;
switch (cpid = fork()) {
case -1: case -1:
die("Could not fork"); fprintf(stderr, "Could not create child process: %s", strerror(errno));
wordfree(&result);
break; break;
case 0: case 0:
/* we are the child */ /* This is the child process, execute the command */
if (!argv) { execvp(result.we_wordv[0], result.we_wordv);
printf(red("No command to execute\n")); die("Could not run command");
exit(1); break;
} default:
if(execvp(path, argv) < 0) { while (waitpid(cpid, NULL, WNOHANG) == -1) {}
/* execv only returns if an error occured, so we exit wordfree(&result);
* otherwise we duplicate the process */
fprintf(stderr, red("Could not run %s\n"), path);
exit(-1);
}
/* we shouldn't be here */
break; break;
} }
// TODO: communication between parent and child about process status/errors/etc
} }
void update_descriptors_list (int **fds, int *fd_num) void update_descriptors_list (int **fds, int *fd_num)
@ -443,7 +455,8 @@ int prepare_epoll (int *fds, int fd_num, int event_watcher)
return ev_fd; return ev_fd;
} }
int key_buffer_compare (struct key_buffer *haystack, struct key_buffer *needle) /* Checks if two key buffers contain the same keys in no specified order */
int key_buffer_compare_random (struct key_buffer *haystack, struct key_buffer *needle)
{ {
if (haystack->size != needle->size) if (haystack->size != needle->size)
return 0; return 0;
@ -458,34 +471,14 @@ int key_buffer_compare (struct key_buffer *haystack, struct key_buffer *needle)
return 1; return 1;
} }
void str_to_argv (char ***argv, const char *path) /* Checks if two key buffers are the same (same order) */
int key_buffer_compare_ordered (struct key_buffer *haystack, struct key_buffer *needle)
{ {
char * str = NULL; if (haystack->size != needle->size)
if (!(str = malloc(sizeof(path)))) return 0;
die("malloc in str_to_argv()"); for (int i = 0; i < needle->size; i++) {
strcpy(str, path); if (needle->buf[i] != haystack->buf[i])
return 0;
char *token = NULL;
token = strtok(str, " ");
if (!token) {
if (!(*argv = realloc(*argv, sizeof(char *))))
die("realloc in str_to_argv()");
*argv[0] = malloc(sizeof(str));
strcpy(*argv[0], str);
goto end_return;
} else {
if (!(*argv = realloc(*argv, sizeof(char *))))
die("realloc in str_to_argv()");
*argv[0] = malloc(sizeof(token));
strcpy(*argv[0], token);
} }
for (int i = 1; (token = strtok(NULL, " ")); i++) { return 1;
if (!(*argv = realloc(*argv, sizeof(char *) * (i + 1))))
die("realloc in str_to_argv()");
*argv[i] = malloc(sizeof(token));
strcpy(*argv[i], token);
}
end_return:
free(str);
return;
} }