Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
6691a616e3 |
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Alessandro Mauri
|
||||
Copyright (c) 2020 Alessandro Mauri
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -9,8 +9,7 @@
|
||||
|
||||
# Leading or trailing whitespaces are ignored, whitespaces between the marker
|
||||
# And the ':' are also ignored, the general syntax for a hotkey is:
|
||||
# <marker> <keys>: <command>
|
||||
#
|
||||
# marker keys: command
|
||||
# Whitespaces after the ':' count as that counts as the executed command for
|
||||
# the hotkey.
|
||||
# Commads are expanded using wordexp(3) so "|&;<>(){}" as well as unescaped
|
||||
@ -36,12 +35,12 @@
|
||||
# command, to declaring aliases is similar to declaring an hotkey, you must
|
||||
# start the line with '@' to indicate an alias, give it a name (mind that this
|
||||
# is case sensitive), and a command after a ':', just like in hotkeys.
|
||||
# When parsing an hotkey or an alias commad, hkd automatically replaces every
|
||||
# instance of known aliases in it. for an alias to be known must be declared
|
||||
# before it's usage.
|
||||
# To use an alias in an hotkey you have to replace the ':' before the command
|
||||
# with '<' to indicate that the following string is an alias and not a command.
|
||||
# Aliases have to be declared before using them, they can also be concatenated.
|
||||
|
||||
# Examples:
|
||||
# @ term : alacritty
|
||||
# @ volumeup: amixer -q sset Master 3%+
|
||||
# - leftmeta, p : term
|
||||
# - VOLUMEUP : volumeup
|
||||
@ term : alacritty
|
||||
@ volumeup: amixer -q sset Master 3%+
|
||||
# - meta, p < term
|
||||
- XF86AudioRaiseVolume < volumeup
|
||||
|
28
hkd.1
28
hkd.1
@ -36,7 +36,7 @@ override default configuration file location, instead using the specified
|
||||
as the temporary config file
|
||||
|
||||
.SH FILES
|
||||
The configuration files are selected in the following order:
|
||||
The configuration files are searched in the following order:
|
||||
.I $XDG_CONFIG_HOME/hkd/config, $HOME/.config/hkd/config, /etc/hkd/config
|
||||
|
||||
.SH USAGE
|
||||
@ -62,38 +62,31 @@ Normal matching means that the keys need to be pressed in the same order as they
|
||||
are declared, whereas fuzzy matching means that they can be pressed in any order.
|
||||
Aliases are a name-command pair that can be used instead of commands in hotkey
|
||||
definitions.
|
||||
|
||||
|
||||
.SS "Hotkey definition"
|
||||
Leading or trailing whitespaces are ignored, whitespaces between the marker and
|
||||
the ':' are also ignored, whitespaces after the ':' ignored until the first
|
||||
non-whitespace character.
|
||||
The general syntax for an hotkey is:
|
||||
the ':' or '<' are also ignored, whitespaces after the ':' are not ignored.
|
||||
The general syntax for a hotkey is:
|
||||
.EX
|
||||
<'*' or '\-'> <keys>: <command>
|
||||
.EE
|
||||
|
||||
|
||||
if a hotkeys uses an explicit command, if you want to use an alias it becomes:
|
||||
.EX
|
||||
<'*' or '\-'> <keys> < <alias name>
|
||||
.EE
|
||||
note the '<' instead of ':'.
|
||||
.SS "Alias definition"
|
||||
The general syntax for aliases is:
|
||||
.EX
|
||||
@ <name>: <command>
|
||||
.EE
|
||||
beware that alias names are case sensitive.
|
||||
|
||||
.SS "Command field"
|
||||
The command string gets analyzed and every instance of known aliases gets
|
||||
replaced with the appropriate command, this also applies for the command field
|
||||
in alias definitions.
|
||||
|
||||
Upon execution commads are expanded using
|
||||
Commads are expanded using
|
||||
.BR wordexp(3)
|
||||
so "|&;<>(){}" as well as unescaped newlines are forbidden and will result in
|
||||
error, read the manpage for
|
||||
.BR wordexp(3)
|
||||
for more info about the possible word expansion capabilities.
|
||||
|
||||
|
||||
.SS "Keys field"
|
||||
Possible keys are taken directly from linux's input.h header file, those
|
||||
include normal keys, multimedia keys, special keys and button events, for the
|
||||
@ -122,8 +115,7 @@ This is a valid config file example
|
||||
\- LEFALT,leftshift,S: ~/screenshot.sh \-c
|
||||
* LEFTMETA,1, D: $SCRIPTDIR/wonkyscript
|
||||
\- LEFTMETA ,LEFTALT,LEFTSHIFT,S : shutdown now
|
||||
# term gets substituted with xterm
|
||||
\- leftmeta, enter : term
|
||||
\- leftmeta, enter < term
|
||||
.EE
|
||||
|
||||
.SH BUGS
|
||||
|
638
hkd.c
638
hkd.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Alessandro Mauri
|
||||
* Copyright (c) 2020 Alessandro Mauri
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -31,6 +31,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <locale.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/epoll.h>
|
||||
@ -39,12 +40,12 @@
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/mman.h>
|
||||
#include "keys.h"
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
/* Value defines */
|
||||
#define FILE_NAME_MAX_LENGTH 255
|
||||
#define KEY_BUFFER_SIZE 16
|
||||
#define KEY_BUFFER_SIZE 10
|
||||
#define BLOCK_SIZE 512
|
||||
|
||||
/* ANSI colors escape codes */
|
||||
@ -63,8 +64,6 @@
|
||||
#define test_bit(yalv, abs_b) ((((char *)abs_b)[yalv/8] & (1<<yalv%8)) > 0)
|
||||
#define array_size(val) (val ? sizeof(val)/sizeof(val[0]) : 0)
|
||||
#define array_size_const(val) ((int)(sizeof(val)/sizeof(val[0])))
|
||||
#define wrap_err(s) "[%s] " s, __func__
|
||||
#define is_empty(s) (!(s) || !(s)[0])
|
||||
|
||||
#define EVENT_SIZE (sizeof(struct inotify_event))
|
||||
#define EVENT_BUF_LEN (1024*(EVENT_SIZE+16))
|
||||
@ -78,14 +77,12 @@ const char *config_paths[] = {
|
||||
};
|
||||
|
||||
struct key_buffer {
|
||||
unsigned short buf[KEY_BUFFER_SIZE];
|
||||
xkb_keysym_t buf[KEY_BUFFER_SIZE];
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
/* Hotkey list: linked list that holds all valid hoteys parsed from the
|
||||
* config file and the corresponding command
|
||||
* TODO: re-implement hotkey_list as a hash table to make searching O(1)
|
||||
*/
|
||||
* config file and the corresponding command */
|
||||
|
||||
union hotkey_main_data {
|
||||
struct key_buffer kb;
|
||||
@ -99,21 +96,23 @@ struct hotkey_list_e {
|
||||
struct hotkey_list_e *next;
|
||||
};
|
||||
|
||||
struct {
|
||||
struct xkb_context *context;
|
||||
struct xkb_rule_names names;
|
||||
struct xkb_keymap *keymap;
|
||||
struct xkb_state *state;
|
||||
// struct xkb_compose_state *comp_state;
|
||||
} keyboard;
|
||||
|
||||
struct hotkey_list_e *hotkey_list = NULL;
|
||||
/* TODO: add hotkey_range struct as a second check to avoid accessing the list
|
||||
* struct {
|
||||
* unsigned int min;
|
||||
* unsigned int max;
|
||||
* } hotkey_range;
|
||||
*/
|
||||
unsigned long hotkey_size_mask = 0;
|
||||
char *ext_config_file = NULL;
|
||||
/* Global flags */
|
||||
int vflag = 0;
|
||||
int dead = 0; /* Exit flag */
|
||||
/* key buffer operations */
|
||||
int key_buffer_add (struct key_buffer*, unsigned short);
|
||||
int key_buffer_remove (struct key_buffer*, unsigned short);
|
||||
int key_buffer_add (struct key_buffer*, xkb_keysym_t);
|
||||
int key_buffer_remove (struct key_buffer*, xkb_keysym_t);
|
||||
int key_buffer_compare_fuzzy (struct key_buffer *, struct key_buffer *);
|
||||
int key_buffer_compare (struct key_buffer *, struct key_buffer *);
|
||||
void key_buffer_reset (struct key_buffer *);
|
||||
@ -122,7 +121,7 @@ void int_handler (int signum);
|
||||
void exec_command (char *);
|
||||
void parse_config_file (void);
|
||||
void update_descriptors_list (int **, int *);
|
||||
inline void remove_lock (void);
|
||||
void remove_lock (void);
|
||||
void die (const char *, ...);
|
||||
void usage (void);
|
||||
int prepare_epoll (int *, int, int);
|
||||
@ -132,7 +131,6 @@ const char * code_to_name (unsigned int);
|
||||
void hotkey_list_add (struct hotkey_list_e *, union hotkey_main_data *, char *, int);
|
||||
void hotkey_list_destroy (struct hotkey_list_e *);
|
||||
void hotkey_list_remove (struct hotkey_list_e *, struct hotkey_list_e *);
|
||||
void replace (char **, const char *, const char *);
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
@ -148,6 +146,8 @@ int main (int argc, char *argv[])
|
||||
struct sigaction action;
|
||||
struct input_event event;
|
||||
struct key_buffer pb = {{0}, 0}; /* Pressed keys buffer */
|
||||
// struct xkb_compose_table_t *comp_table = NULL;
|
||||
// const char *locale = NULL;
|
||||
|
||||
/* Parse command line arguments */
|
||||
while ((opc = getopt(argc, argv, "vc:dh")) != -1) {
|
||||
@ -158,7 +158,7 @@ int main (int argc, char *argv[])
|
||||
case 'c':
|
||||
ext_config_file = malloc(strlen(optarg) + 1);
|
||||
if (!ext_config_file)
|
||||
die(wrap_err("Bad malloc:"));
|
||||
die("malloc in main():");
|
||||
strcpy(ext_config_file, optarg);
|
||||
break;
|
||||
case 'd':
|
||||
@ -175,13 +175,37 @@ int main (int argc, char *argv[])
|
||||
dead = 0;
|
||||
memset(&action, 0, sizeof(action));
|
||||
action.sa_handler = int_handler;
|
||||
sigaction(SIGINT, &action, NULL);
|
||||
sigaction(SIGUSR1, &action, NULL);
|
||||
sigaction(SIGCHLD, &action, NULL);
|
||||
|
||||
/* Initialize xkbcommon */
|
||||
if (!(keyboard.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS)))
|
||||
die("Error initializing xkbcommon context: ");
|
||||
|
||||
keyboard.names = (struct xkb_rule_names){
|
||||
.rules = NULL,
|
||||
.model = NULL,
|
||||
.layout = "gb",
|
||||
.variant = NULL,
|
||||
.options = NULL,
|
||||
};
|
||||
|
||||
if (sigaction(SIGINT, &action, NULL) == -1)
|
||||
die(wrap_err("Error setting interrupt handler:"));
|
||||
if (sigaction(SIGUSR1, &action, NULL) == -1)
|
||||
die(wrap_err("Error setting interrupt handler:"));
|
||||
if (sigaction(SIGCHLD, &action, NULL) == -1)
|
||||
die(wrap_err("Error setting interrupt handler:"));
|
||||
if (!(keyboard.keymap = xkb_keymap_new_from_names(keyboard.context,
|
||||
&keyboard.names, XKB_KEYMAP_COMPILE_NO_FLAGS)))
|
||||
die("Error compiling keymap: ");
|
||||
|
||||
if (!(keyboard.state = xkb_state_new(keyboard.keymap)))
|
||||
die("Error creating keyboard state: ");
|
||||
/*
|
||||
locale = setlocale(LC_CTYPE, NULL);
|
||||
if (!(comp_table = xkb_compose_table_new_from_locale(keyboard.context,
|
||||
locale, XKB_COMPOSE_COMPILE_NO_FLAGS)))
|
||||
die("Error compiling compose table: ");
|
||||
if (!(keyboard.comp_state = xkb_compose_state_new(comp_table,
|
||||
XKB_COMPOSE_TABLE_NO_FLAGS)))
|
||||
die("Error creating compose state: ");
|
||||
*/
|
||||
|
||||
/* Parse config file */
|
||||
parse_config_file();
|
||||
@ -189,7 +213,7 @@ int main (int argc, char *argv[])
|
||||
/* Check if hkd is already running */
|
||||
lock_file_descriptor = open(LOCK_FILE, O_RDWR | O_CREAT, 0600);
|
||||
if (lock_file_descriptor < 0)
|
||||
die(wrap_err("Can't open lock file:"));
|
||||
die("Can't open lock file:");
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 0;
|
||||
fl.l_type = F_WRLCK;
|
||||
@ -200,12 +224,15 @@ int main (int argc, char *argv[])
|
||||
|
||||
/* If a dump is requested print the hotkey list then exit */
|
||||
if (dump) {
|
||||
char key_name[64];
|
||||
printf("DUMPING HOTKEY LIST\n\n");
|
||||
for (struct hotkey_list_e *tmp = hotkey_list; tmp; tmp = tmp->next) {
|
||||
printf("Hotkey\n");
|
||||
printf("\tKeys: ");
|
||||
for (unsigned int i = 0; i < tmp->data.kb.size; i++)
|
||||
printf("%s ", code_to_name(tmp->data.kb.buf[i]));
|
||||
for (unsigned int i = 0; i < tmp->data.kb.size; i++) {
|
||||
xkb_keysym_get_name(tmp->data.kb.buf[i], key_name, 64);
|
||||
printf("%s ", key_name);
|
||||
}
|
||||
printf("\n\tMatching: %s\n", tmp->fuzzy ? "fuzzy" : "ordered");
|
||||
printf("\tCommand: %s\n\n", tmp->command);
|
||||
}
|
||||
@ -217,9 +244,10 @@ int main (int argc, char *argv[])
|
||||
|
||||
/* Prepare directory update watcher */
|
||||
if (event_watcher < 0)
|
||||
die(wrap_err("Could not call inotify_init:"));
|
||||
die("Could not call inotify_init:");
|
||||
if (inotify_add_watch(event_watcher, EVDEV_ROOT_DIR, IN_CREATE | IN_DELETE) < 0)
|
||||
die(wrap_err("Could not add /dev/input to the watch list:"));
|
||||
die("Could not add /dev/input to the watch list:");
|
||||
|
||||
/* Prepare epoll list */
|
||||
ev_fd = prepare_epoll(fds, fd_num, event_watcher);
|
||||
|
||||
@ -229,8 +257,13 @@ int main (int argc, char *argv[])
|
||||
int t = 0;
|
||||
static unsigned int prev_size;
|
||||
static struct epoll_event ev_type;
|
||||
static xkb_keycode_t keycode;
|
||||
static xkb_keysym_t keysym;
|
||||
// enum xkb_state_component changed;
|
||||
struct hotkey_list_e *tmp;
|
||||
char buf[EVENT_BUF_LEN];
|
||||
static char key_name[64];
|
||||
// enum xkb_compose_status status;
|
||||
|
||||
/* On linux use epoll(2) as it gives better performance */
|
||||
if (epoll_wait(ev_fd, &ev_type, fd_num, -1) < 0 || dead) {
|
||||
@ -245,7 +278,7 @@ int main (int argc, char *argv[])
|
||||
sleep(1); // wait for devices to settle
|
||||
update_descriptors_list(&fds, &fd_num);
|
||||
if (close(ev_fd) < 0)
|
||||
die(wrap_err("Could not close event fd list (ev_fd):"));
|
||||
die("Could not close event filedescriptors list (ev_fd):");
|
||||
ev_fd = prepare_epoll(fds, fd_num, event_watcher);
|
||||
goto mainloop_begin;
|
||||
}
|
||||
@ -256,24 +289,32 @@ int main (int argc, char *argv[])
|
||||
read_b = read(fds[i], &event, sizeof(struct input_event));
|
||||
if (read_b != sizeof(struct input_event)) continue;
|
||||
|
||||
/* Ignore touchpad events */
|
||||
if (
|
||||
event.type == EV_KEY &&
|
||||
event.code != BTN_TOUCH &&
|
||||
event.code != BTN_TOOL_FINGER &&
|
||||
event.code != BTN_TOOL_DOUBLETAP &&
|
||||
event.code != BTN_TOOL_TRIPLETAP
|
||||
) {
|
||||
switch (event.value) {
|
||||
/* Key released */
|
||||
case 0:
|
||||
key_buffer_remove(&pb, event.code);
|
||||
break;
|
||||
/* Key pressed */
|
||||
case 1:
|
||||
key_buffer_add(&pb, event.code);
|
||||
break;
|
||||
}
|
||||
if (event.type != EV_KEY)
|
||||
continue;
|
||||
|
||||
// evdev offset
|
||||
keycode = event.code + 8;
|
||||
if (event.value == 2 && !xkb_keymap_key_repeats(
|
||||
keyboard.keymap, keycode))
|
||||
continue;
|
||||
if (event.value) {
|
||||
keysym = xkb_state_key_get_one_sym(keyboard.state, keycode);
|
||||
// kbd_compose_state_feed(keyboard.comp_state, keysym);
|
||||
}
|
||||
|
||||
/* status = xkb_compose_state_get_status(keyboard.comp_state);
|
||||
if (status == XKB_COMPOSE_CANCELLED || status == XKB_COMPOSE_COMPOSED)
|
||||
xkb_compose_state_reset(kbd->compose_state);
|
||||
*/
|
||||
|
||||
if (event.value) { /* Key pressed */
|
||||
xkb_state_update_key(keyboard.state,
|
||||
keycode, XKB_KEY_UP);
|
||||
key_buffer_add(&pb, keysym);
|
||||
} else {/* Key released */
|
||||
xkb_state_update_key(keyboard.state,
|
||||
keycode, XKB_KEY_DOWN);
|
||||
key_buffer_remove(&pb, keysym);
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,7 +324,8 @@ int main (int argc, char *argv[])
|
||||
if (vflag) {
|
||||
printf("Pressed keys: ");
|
||||
for (unsigned int i = 0; i < pb.size; i++)
|
||||
printf("%s ", code_to_name(pb.buf[i]));
|
||||
xkb_keysym_get_name(pb.buf[i], key_name, 64);
|
||||
printf("%s ", key_name);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
@ -305,17 +347,21 @@ int main (int argc, char *argv[])
|
||||
wait(NULL);
|
||||
if (!dead)
|
||||
fprintf(stderr, red("An error occured: %s\n"), errno ? strerror(errno): "idk");
|
||||
xkb_state_unref(keyboard.state);
|
||||
xkb_keymap_unref(keyboard.keymap);
|
||||
// xkb_compose_state_unref(keyboard.comp_state);
|
||||
xkb_context_unref(keyboard.context);
|
||||
close(ev_fd);
|
||||
close(event_watcher);
|
||||
for (int i = 0; i < fd_num; i++)
|
||||
if (close(fds[i]) == -1)
|
||||
die(wrap_err("Error closing file descriptors:"));
|
||||
die("Error closing file descriptors:");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Adds a keycode to the pressed buffer if it is not already present
|
||||
* Returns non zero if the key was not added. */
|
||||
int key_buffer_add (struct key_buffer *pb, unsigned short key)
|
||||
int key_buffer_add (struct key_buffer *pb, xkb_keysym_t key)
|
||||
{
|
||||
if (!pb) return 1;
|
||||
/* Linear search if the key is already buffered */
|
||||
@ -332,7 +378,7 @@ int key_buffer_add (struct key_buffer *pb, unsigned short key)
|
||||
|
||||
/* Removes a keycode from a pressed buffer if it is present returns
|
||||
* non zero in case of failure (key not present or buffer empty). */
|
||||
int key_buffer_remove (struct key_buffer *pb, unsigned short key)
|
||||
int key_buffer_remove (struct key_buffer *pb, xkb_keysym_t key)
|
||||
{
|
||||
if (!pb) return 1;
|
||||
|
||||
@ -357,7 +403,7 @@ void int_handler (int signum)
|
||||
switch (signum) {
|
||||
case SIGINT:
|
||||
if (dead)
|
||||
die(wrap_err("An error occured, exiting"));
|
||||
die("An error occured, exiting");
|
||||
if (vflag)
|
||||
printf(yellow("Received interrupt signal, exiting gracefully...\n"));
|
||||
dead = 1;
|
||||
@ -387,20 +433,20 @@ void exec_command (char *command)
|
||||
return;
|
||||
default:
|
||||
/* Some other error */
|
||||
fprintf(stderr, wrap_err("Could not parse, %s is not valid\n"), command);
|
||||
fprintf(stderr, "Could not parse, %s is not valid\n", command);
|
||||
return;
|
||||
}
|
||||
|
||||
pid_t cpid;
|
||||
switch (cpid = fork()) {
|
||||
case -1:
|
||||
fprintf(stderr, wrap_err("Could not create child process: %s"), strerror(errno));
|
||||
fprintf(stderr, "Could not create child process: %s", strerror(errno));
|
||||
wordfree(&result);
|
||||
break;
|
||||
case 0:
|
||||
/* This is the child process, execute the command */
|
||||
execvp(result.we_wordv[0], result.we_wordv);
|
||||
die(wrap_err("%s:"), command);
|
||||
die("%s:", command);
|
||||
break;
|
||||
default:
|
||||
while (waitpid(cpid, NULL, WNOHANG) == -1) {}
|
||||
@ -419,7 +465,7 @@ void update_descriptors_list (int **fds, int *fd_num)
|
||||
/* Open the event directory */
|
||||
DIR *ev_dir = opendir(EVDEV_ROOT_DIR);
|
||||
if (!ev_dir)
|
||||
die(wrap_err("Could not open /dev/input:"));
|
||||
die("Could not open /dev/input:");
|
||||
|
||||
(*fd_num) = 0;
|
||||
|
||||
@ -446,7 +492,7 @@ void update_descriptors_list (int **fds, int *fd_num)
|
||||
memset(evtype_b, 0, sizeof(evtype_b));
|
||||
if (ioctl(tmp_fd, EVIOCGBIT(0, EV_MAX), evtype_b) < 0) {
|
||||
if (vflag)
|
||||
printf(red("Could not read capabilities of device %s\n"), ev_path);
|
||||
printf(red("Could not read capabilities of device %s\n"),ev_path);
|
||||
close(tmp_fd);
|
||||
continue;
|
||||
}
|
||||
@ -460,7 +506,7 @@ void update_descriptors_list (int **fds, int *fd_num)
|
||||
|
||||
tmp_p = realloc((*fds), sizeof(int) * ((*fd_num) + 1));
|
||||
if (!tmp_p)
|
||||
die(wrap_err("Realloc file descriptors:"));
|
||||
die("realloc file descriptors:");
|
||||
(*fds) = (int *) tmp_p;
|
||||
|
||||
(*fds)[(*fd_num)] = tmp_fd;
|
||||
@ -471,7 +517,7 @@ void update_descriptors_list (int **fds, int *fd_num)
|
||||
if (vflag)
|
||||
printf(green("Monitoring %d devices\n"), *fd_num);
|
||||
} else {
|
||||
die(wrap_err("Could not open any devices, exiting"));
|
||||
die("Could not open any devices, exiting");
|
||||
}
|
||||
}
|
||||
|
||||
@ -481,12 +527,12 @@ int prepare_epoll (int *fds, int fd_num, int event_watcher)
|
||||
static struct epoll_event epoll_read_ev;
|
||||
epoll_read_ev.events = EPOLLIN;
|
||||
if (ev_fd < 0)
|
||||
die(wrap_err("epoll_create failed:"));
|
||||
die("epoll_create failed in prepare_epoll:");
|
||||
if (epoll_ctl(ev_fd, EPOLL_CTL_ADD, event_watcher, &epoll_read_ev) < 0)
|
||||
die(wrap_err("Could not add file descriptor to the epoll list:"));
|
||||
die("Could not add file descriptor to the epoll list:");
|
||||
for (int i = 0; i < fd_num; i++)
|
||||
if (epoll_ctl(ev_fd, EPOLL_CTL_ADD, fds[i], &epoll_read_ev) < 0)
|
||||
die(wrap_err("Could not add file descriptor to the epoll list:"));
|
||||
die("Could not add file descriptor to the epoll list:");
|
||||
return ev_fd;
|
||||
}
|
||||
|
||||
@ -534,12 +580,12 @@ void hotkey_list_add (struct hotkey_list_e *head, union hotkey_main_data *dt, ch
|
||||
{
|
||||
int size;
|
||||
struct hotkey_list_e *tmp;
|
||||
if (is_empty(cmd) || !(size = strlen(cmd)))
|
||||
if (!(size = strlen(cmd)))
|
||||
return;
|
||||
if (!(tmp = malloc(sizeof(struct hotkey_list_e))))
|
||||
die(wrap_err("Bad malloc:"));
|
||||
die("Memory allocation failed in hotkey_list_add():");
|
||||
if (!(tmp->command = malloc(size + 1)))
|
||||
die(wrap_err("Bad malloc:"));
|
||||
die("Memory allocation failed in hotkey_list_add():");
|
||||
strcpy(tmp->command, cmd);
|
||||
tmp->data = *dt;
|
||||
tmp->fuzzy = f;
|
||||
@ -575,22 +621,22 @@ void hotkey_list_remove (struct hotkey_list_e *head, struct hotkey_list_e *elem)
|
||||
void parse_config_file (void)
|
||||
{
|
||||
wordexp_t result = {0};
|
||||
int config_file;
|
||||
FILE *fd;
|
||||
/* normal, skip line, get matching, get keys, get command, output */
|
||||
enum {NORM, LINE_SKIP, GET_TYPE, GET_KEYS, GET_CMD, LAST} parse_state = NORM;
|
||||
enum {CONT, NEW_BL, LAST_BL, END} block_state = CONT; /* continue, new block, last block, end */
|
||||
enum {HK_NORM = 0, HK_FUZZY = 1, ALIAS = -1} type;
|
||||
int eof = 0;
|
||||
int token_size = 0;
|
||||
int cmd_is_alias = 0;
|
||||
int alloc_tmp = 0, alloc_size = 0;
|
||||
int i_tmp = 0, linenum = 1;
|
||||
char *buffer;
|
||||
char block[BLOCK_SIZE + 1] = {0};
|
||||
char *bb = NULL;
|
||||
char *keys = NULL;
|
||||
char *cmd = NULL;
|
||||
char *cp_tmp = NULL;
|
||||
union hotkey_main_data dt = {0};
|
||||
unsigned short us_tmp = 0;
|
||||
xkb_keysym_t ks_tmp = 0;
|
||||
|
||||
/* Choose config file */
|
||||
if (ext_config_file) {
|
||||
switch (wordexp(ext_config_file, &result, 0)) {
|
||||
case 0:
|
||||
@ -599,15 +645,15 @@ void parse_config_file (void)
|
||||
/* If the error was WRDE_NOSPACE,
|
||||
* then perhaps part of the result was allocated */
|
||||
wordfree (&result);
|
||||
die(wrap_err("Not enough space:"));
|
||||
die("Not enough space:");
|
||||
default:
|
||||
die(wrap_err("Path not valid:"));
|
||||
die("Path not valid:");
|
||||
}
|
||||
|
||||
config_file = open(result.we_wordv[0], O_RDONLY | O_NONBLOCK);
|
||||
fd = fopen(result.we_wordv[0], "r");
|
||||
wordfree(&result);
|
||||
if (config_file < 0)
|
||||
die(wrap_err("Error opening config file:"));
|
||||
if (!fd)
|
||||
die("Error opening config file:");
|
||||
free(ext_config_file);
|
||||
ext_config_file = NULL;
|
||||
} else {
|
||||
@ -619,195 +665,248 @@ void parse_config_file (void)
|
||||
/* If the error was WRDE_NOSPACE,
|
||||
* then perhaps part of the result was allocated */
|
||||
wordfree (&result);
|
||||
die(wrap_err("Not enough space:"));
|
||||
die("Not enough space:");
|
||||
default:
|
||||
die(wrap_err("Path not valid:"));
|
||||
die("Path not valid:");
|
||||
}
|
||||
|
||||
config_file = open(result.we_wordv[0], O_RDONLY | O_NONBLOCK);
|
||||
fd = fopen(result.we_wordv[0], "r");
|
||||
wordfree(&result);
|
||||
if (config_file >= 0)
|
||||
if (fd)
|
||||
break;
|
||||
if (vflag)
|
||||
printf(yellow("config file not found at %s\n"), config_paths[i]);
|
||||
}
|
||||
if (!config_file)
|
||||
die(wrap_err("Could not open any config files, check stderr for more details"));
|
||||
if (!fd)
|
||||
die("Could not open any config files, check the log for more details");
|
||||
}
|
||||
|
||||
/* Using mmap because of simplicity, most config files are smaller than
|
||||
* a page but this method mostly ensures that big files are taken care
|
||||
* of efficiently and reduces the overall complexity of the code.
|
||||
* Furthermore we only need this space when parsing the config file,
|
||||
* afterwards we release it.
|
||||
*/
|
||||
struct stat sb;
|
||||
int file_size;
|
||||
if (fstat(config_file, &sb) == -1)
|
||||
die("fstat");
|
||||
file_size = sb.st_size;
|
||||
// FIXME: page align size
|
||||
buffer = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, config_file, 0);
|
||||
if (buffer == MAP_FAILED)
|
||||
die(wrap_err("mmap failed:"));
|
||||
close(config_file);
|
||||
bb = buffer;
|
||||
|
||||
hotkey_list_destroy(hotkey_list);
|
||||
hotkey_list = NULL;
|
||||
while (!eof) {
|
||||
// FIXME: incorect line counting, especially for multiline commands
|
||||
switch (parse_state) {
|
||||
// First state
|
||||
case NORM:
|
||||
// remove whitespaces
|
||||
while (isblank(*bb))
|
||||
while (block_state != END) {
|
||||
int tmp = 0;
|
||||
memset(block, 0, BLOCK_SIZE + 1);
|
||||
tmp = fread(block, sizeof(char), BLOCK_SIZE, fd);
|
||||
if (!tmp)
|
||||
break;
|
||||
if (tmp < BLOCK_SIZE || feof(fd))
|
||||
block_state = LAST_BL;
|
||||
else
|
||||
block_state = CONT;
|
||||
bb = block;
|
||||
|
||||
while (block_state == CONT || block_state == LAST_BL) {
|
||||
switch (parse_state) {
|
||||
// First state
|
||||
case NORM:
|
||||
// remove whitespaces
|
||||
while (isblank(*bb) && *bb)
|
||||
bb++;
|
||||
// get state
|
||||
switch (*bb) {
|
||||
#if defined(__X86_64__) || defined(__i386__)
|
||||
case EOF:
|
||||
#endif
|
||||
case '\0':
|
||||
// If it is the end of the last block exit
|
||||
block_state = block_state == LAST_BL ? END : NEW_BL;
|
||||
break;
|
||||
case '\n':
|
||||
case '#':
|
||||
parse_state = LINE_SKIP;
|
||||
break;
|
||||
default:
|
||||
parse_state = GET_TYPE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
// Skip line (comment)
|
||||
case LINE_SKIP:
|
||||
while (*bb != '\n' && *bb)
|
||||
bb++;
|
||||
if (*bb) {
|
||||
bb++;
|
||||
linenum++;
|
||||
parse_state = NORM;
|
||||
} else {
|
||||
block_state = NEW_BL;
|
||||
}
|
||||
break;
|
||||
// Get compairson method
|
||||
case GET_TYPE:
|
||||
switch (*bb) {
|
||||
case '-':
|
||||
type = HK_NORM;
|
||||
break;
|
||||
case '*':
|
||||
type = HK_FUZZY;
|
||||
break;
|
||||
case '@':
|
||||
type = ALIAS;
|
||||
break;
|
||||
default:
|
||||
die("Error at line %d: "
|
||||
"hotkey definition must start with '-', '*' or '@'",
|
||||
linenum);
|
||||
break;
|
||||
}
|
||||
bb++;
|
||||
// get state
|
||||
switch (*bb) {
|
||||
case '\0':
|
||||
eof = 1;
|
||||
parse_state = GET_KEYS;
|
||||
break;
|
||||
case '\n':
|
||||
case '#':
|
||||
parse_state = LINE_SKIP;
|
||||
break;
|
||||
default:
|
||||
parse_state = GET_TYPE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
// Skip line (comment)
|
||||
case LINE_SKIP:
|
||||
for (;(bb - buffer) < file_size && *bb != '\n'; bb++);
|
||||
bb++;
|
||||
linenum++;
|
||||
parse_state = NORM;
|
||||
break;
|
||||
// Get compairson method
|
||||
case GET_TYPE:
|
||||
switch (*bb) {
|
||||
case '-':
|
||||
type = HK_NORM;
|
||||
break;
|
||||
case '*':
|
||||
type = HK_FUZZY;
|
||||
break;
|
||||
case '@':
|
||||
type = ALIAS;
|
||||
break;
|
||||
default:
|
||||
die(wrap_err("Error at line %d: "
|
||||
"hotkey definition must start with '-', '*' or '@'"),
|
||||
linenum);
|
||||
break;
|
||||
}
|
||||
bb++;
|
||||
parse_state = GET_KEYS;
|
||||
break;
|
||||
// Get keys
|
||||
case GET_KEYS:
|
||||
for (token_size = 0; token_size < (file_size - (bb - buffer)) && !(bb[token_size] == ':' || bb[token_size] == '\n'); token_size++);
|
||||
if (bb[token_size] == '\n')
|
||||
die(wrap_err("Error at line %d: "
|
||||
"no command specified, missing ':' after keys"),
|
||||
linenum);
|
||||
keys = malloc(token_size + 1);
|
||||
if (!keys)
|
||||
die(wrap_err("Bad malloc parsing keys:"));
|
||||
memcpy(keys, bb, token_size);
|
||||
keys[token_size] = '\0';
|
||||
bb += token_size + 1;
|
||||
parse_state = GET_CMD;
|
||||
break;
|
||||
// Get command
|
||||
case GET_CMD:
|
||||
for (token_size = 0; token_size < (file_size - !(bb - buffer)); token_size++) {
|
||||
if (bb[token_size] == ':')
|
||||
break;
|
||||
if (bb[token_size] == '\n' && bb[token_size - token_size ? 1 : 0] != '\\')
|
||||
break;
|
||||
}
|
||||
cmd = malloc(token_size + 1);
|
||||
if (!cmd)
|
||||
die(wrap_err("Bad malloc parsing command:"));
|
||||
memcpy(cmd, bb, token_size);
|
||||
cmd[token_size] = '\0';
|
||||
bb += token_size;
|
||||
parse_state = LAST;
|
||||
break;
|
||||
case LAST:
|
||||
if (!keys)
|
||||
die(wrap_err("Keys is NULL"));
|
||||
i_tmp = strlen(keys);
|
||||
for (int i = 0; i < i_tmp; i++) {
|
||||
if (isblank(keys[i]))
|
||||
memmove(&keys[i], &keys[i + 1], i_tmp - i);
|
||||
}
|
||||
cp_tmp = strtok(keys, ",");
|
||||
if(!cp_tmp)
|
||||
die(wrap_err("Error at line %d: "
|
||||
"keys not present"), linenum - 1);
|
||||
// Get keys
|
||||
case GET_KEYS:
|
||||
if (!keys) {
|
||||
if (!(keys = malloc(alloc_size = (sizeof(char) * 64))))
|
||||
die("malloc for keys in parse_config_file():");
|
||||
memset(keys, 0, alloc_size);
|
||||
} else if (alloc_tmp >= alloc_size) {
|
||||
if (!(keys = realloc(keys, alloc_size = alloc_size * 2)))
|
||||
die("realloc for keys in parse_config_file():");
|
||||
memset(&keys[alloc_size / 2], 0, alloc_size / 2);
|
||||
}
|
||||
|
||||
if (type != ALIAS) {
|
||||
do {
|
||||
if (!(us_tmp = key_to_code(cp_tmp))) {
|
||||
die(wrap_err("Error at line %d: "
|
||||
"%s is not a valid key"),
|
||||
linenum - 1, cp_tmp);
|
||||
for (alloc_tmp = 0; bb[alloc_tmp] &&
|
||||
bb[alloc_tmp] != ':' &&
|
||||
bb[alloc_tmp] != '<' &&
|
||||
bb[alloc_tmp] != '\n' &&
|
||||
alloc_tmp < alloc_size; alloc_tmp++);
|
||||
|
||||
if (!bb[alloc_tmp] || alloc_tmp == alloc_size) {
|
||||
strncat(keys, bb, alloc_tmp);
|
||||
bb += alloc_tmp;
|
||||
if (block_state == LAST_BL)
|
||||
die("Keys not finished before end of file");
|
||||
else
|
||||
block_state = NEW_BL;
|
||||
break;
|
||||
} else if (bb[alloc_tmp] == ':' || bb[alloc_tmp] == '<') {
|
||||
cmd_is_alias = (bb[alloc_tmp] == '<');
|
||||
strncat(keys, bb, alloc_tmp);
|
||||
bb += alloc_tmp + 1;
|
||||
parse_state = GET_CMD;
|
||||
break;
|
||||
} else {
|
||||
die("Error at line %d: "
|
||||
"no command specified, missing ':' or '<' after keys",
|
||||
linenum);
|
||||
}
|
||||
break;
|
||||
// Get command
|
||||
case GET_CMD:
|
||||
if (!cmd) {
|
||||
if (!(cmd = malloc(alloc_size = (sizeof(char) * 128))))
|
||||
die("malloc for cmd in parse_config_file():");
|
||||
memset(cmd, 0, alloc_size);
|
||||
} else if (alloc_tmp >= alloc_size) {
|
||||
if (!(cmd = realloc(cmd, alloc_size = alloc_size * 2)))
|
||||
die("realloc for cmd in parse_config_file():");
|
||||
memset(&cmd[alloc_size / 2], 0, alloc_size / 2);
|
||||
}
|
||||
|
||||
for (alloc_tmp = 0; bb[alloc_tmp] && bb[alloc_tmp] != '\n' &&
|
||||
alloc_tmp < alloc_size; alloc_tmp++);
|
||||
|
||||
if (!bb[alloc_tmp] || alloc_tmp == alloc_size) {
|
||||
strncat(cmd, bb, alloc_tmp);
|
||||
bb += alloc_tmp;
|
||||
if (block_state == LAST_BL)
|
||||
die("Command not finished before end of file");
|
||||
else
|
||||
block_state = NEW_BL;
|
||||
break;
|
||||
} else {
|
||||
strncat(cmd, bb, alloc_tmp);
|
||||
if (!(bb[alloc_tmp - 1] == '\\'))
|
||||
parse_state = LAST;
|
||||
bb += alloc_tmp + 1;
|
||||
linenum++;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case LAST:
|
||||
if (!keys)
|
||||
die("error");
|
||||
i_tmp = strlen(keys);
|
||||
for (int i = 0; i < i_tmp; i++) {
|
||||
if (isblank(keys[i])) {
|
||||
memmove(&keys[i], &keys[i + 1], --i_tmp);
|
||||
keys[i_tmp] = '\0';
|
||||
}
|
||||
}
|
||||
cp_tmp = strtok(keys, ",");
|
||||
if(!cp_tmp)
|
||||
die("Error at line %d: "
|
||||
"keys not present", linenum - 1);
|
||||
|
||||
if (type != ALIAS) {
|
||||
do {
|
||||
if ((ks_tmp = xkb_keysym_from_name(cp_tmp, XKB_KEYSYM_NO_FLAGS)) == XKB_KEY_NoSymbol) {
|
||||
die("Error at line %d: "
|
||||
"%s is not a valid key",
|
||||
linenum - 1, cp_tmp);
|
||||
}
|
||||
if (key_buffer_add(&dt.kb, ks_tmp))
|
||||
die("Too many keys");
|
||||
} while ((cp_tmp = strtok(NULL, ",")));
|
||||
} else {
|
||||
if (!(dt.name = malloc(strlen(cp_tmp) + 1)))
|
||||
die("malloc in parse_config_file():");
|
||||
strcpy(dt.name, cp_tmp);
|
||||
}
|
||||
|
||||
cp_tmp = cmd;
|
||||
while (isblank(*cp_tmp))
|
||||
cp_tmp++;
|
||||
if (*cp_tmp == '\0')
|
||||
die("Error at line %d: "
|
||||
"command not present", linenum - 1);
|
||||
if (cmd_is_alias) {
|
||||
struct hotkey_list_e *hkl = hotkey_list;
|
||||
// stolen way of removing leading spaces
|
||||
char * end = cp_tmp + strlen(cp_tmp) - 1;
|
||||
while(end > cp_tmp && isspace((unsigned char)*end)) end--;
|
||||
end[1] = '\0';
|
||||
|
||||
while (hkl && !(hkl->fuzzy == ALIAS && strstr(hkl->data.name, cp_tmp)))
|
||||
hkl = hkl->next;
|
||||
if (hkl) {
|
||||
cp_tmp = hkl->command;
|
||||
} else {
|
||||
die("Error at line %d: "
|
||||
"alias %s not found", linenum - 1,
|
||||
cp_tmp);
|
||||
}
|
||||
if (key_buffer_add(&dt.kb, us_tmp))
|
||||
die(wrap_err("Too many keys"));
|
||||
} while ((cp_tmp = strtok(NULL, ",")));
|
||||
} else {
|
||||
if (!(dt.name = malloc(strlen(cp_tmp) + 1)))
|
||||
die(wrap_err("Bad malloc:"));
|
||||
strcpy(dt.name, cp_tmp);
|
||||
}
|
||||
|
||||
hotkey_list_add(hotkey_list, &dt, cp_tmp, type);
|
||||
|
||||
if (type != ALIAS)
|
||||
key_buffer_reset(&dt.kb);
|
||||
free(keys);
|
||||
free(cmd);
|
||||
cp_tmp = keys = cmd = NULL;
|
||||
i_tmp = 0;
|
||||
parse_state = NORM;
|
||||
break;
|
||||
default:
|
||||
die("Unknown state in parse_config_file");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* search the command in the known aliases and replace */
|
||||
struct hotkey_list_e *hkl = hotkey_list;
|
||||
while (hkl && hkl->fuzzy == ALIAS) {
|
||||
replace(&cmd, hkl->data.name, hkl->command);
|
||||
hkl = hkl->next;
|
||||
}
|
||||
|
||||
cp_tmp = cmd;
|
||||
while (isblank(*cp_tmp))
|
||||
cp_tmp++;
|
||||
if (*cp_tmp == '\0')
|
||||
die(wrap_err("Error at line %d: "
|
||||
"command not present"), linenum - 1);
|
||||
|
||||
|
||||
hotkey_list_add(hotkey_list, &dt, cp_tmp, type);
|
||||
|
||||
if (type != ALIAS)
|
||||
key_buffer_reset(&dt.kb);
|
||||
free(keys);
|
||||
free(cmd);
|
||||
cp_tmp = keys = cmd = NULL;
|
||||
i_tmp = 0;
|
||||
parse_state = NORM;
|
||||
break;
|
||||
default:
|
||||
die(wrap_err("Unknown state"));
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
munmap(buffer, file_size);
|
||||
|
||||
for (struct hotkey_list_e *hkl = hotkey_list, *tmp; hkl;) {
|
||||
tmp = hkl;
|
||||
hkl = hkl->next;
|
||||
if (tmp->fuzzy == ALIAS)
|
||||
for (struct hotkey_list_e *hkl = hotkey_list, *tmp; hkl; hkl = hkl->next) {
|
||||
if (hkl->fuzzy == ALIAS) {
|
||||
tmp = hkl;
|
||||
hkl = hkl->next;
|
||||
hotkey_list_remove(hotkey_list, tmp);
|
||||
else
|
||||
hotkey_size_mask |= 1 << (tmp->data.kb.size - 1);
|
||||
} else {
|
||||
hotkey_size_mask |= 1 << (hkl->data.kb.size - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
unsigned short key_to_code (char *key)
|
||||
{
|
||||
for (char *tmp = key; *tmp; tmp++) {
|
||||
@ -820,6 +919,7 @@ unsigned short key_to_code (char *key)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
void remove_lock (void)
|
||||
{
|
||||
@ -846,6 +946,7 @@ void die(const char *fmt, ...)
|
||||
exit(errno ? errno : 1);
|
||||
}
|
||||
|
||||
/*
|
||||
const char * code_to_name (unsigned int code)
|
||||
{
|
||||
for (int i = 0; i < array_size_const(key_conversion_table); i++) {
|
||||
@ -854,6 +955,7 @@ const char * code_to_name (unsigned int code)
|
||||
}
|
||||
return "Key not recognized";
|
||||
}
|
||||
*/
|
||||
|
||||
void usage (void)
|
||||
{
|
||||
@ -864,47 +966,3 @@ void usage (void)
|
||||
"\t-c file uses the specified file as config\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* replaces every instance of m(match) with r(eplace) inside of s */
|
||||
void replace (char **s, const char *m, const char *r)
|
||||
{
|
||||
if (is_empty(s) || is_empty(*s) || is_empty(m) || is_empty(r))
|
||||
return;
|
||||
|
||||
int ms = strlen(m), rs = strlen(r);
|
||||
int count = 0, o = 0;
|
||||
int *offs = NULL, *t2 = NULL;
|
||||
char *t1 = NULL;
|
||||
|
||||
while ((t1 = strstr((*s) + o, m))) {
|
||||
/* check if the match is surrounded by whitespace */
|
||||
if ((t1[ms] == '\0' || isblank(t1[ms]))
|
||||
&& isblank(t1 > *s ? *(t1 - 1) : ' ')) {
|
||||
if (!(t2 = realloc(offs, sizeof(int) * (count + 1))))
|
||||
die(wrap_err("Bad realloc:"));
|
||||
offs = t2;
|
||||
offs[count] = (t1 - *s) + (rs - ms) * count;
|
||||
count++;
|
||||
}
|
||||
o = (t1 - *s) + 1;
|
||||
}
|
||||
|
||||
if (!offs)
|
||||
return;
|
||||
|
||||
int nss = strlen(*s);
|
||||
if ((rs - ms) > 0) {
|
||||
if (!(t1 = realloc(*s, nss + 1 + (rs - ms) * count)))
|
||||
die(wrap_err("Bad realloc:"));
|
||||
*s = t1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
char* x = *s + offs[i];
|
||||
int d = strlen(x) - ms;
|
||||
memmove(x + rs, x + ms, d);
|
||||
memcpy(x, r, rs);
|
||||
}
|
||||
if (offs)
|
||||
free(offs);
|
||||
}
|
||||
|
504
keys.h
504
keys.h
@ -1,504 +0,0 @@
|
||||
#ifndef _H_KEYS
|
||||
#define _H_KEYS
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
struct {
|
||||
const char *const name;
|
||||
const unsigned short value;
|
||||
} key_conversion_table[] =
|
||||
{{"ESC", KEY_ESC},
|
||||
{"1", KEY_1},
|
||||
{"2", KEY_2},
|
||||
{"3", KEY_3},
|
||||
{"4", KEY_4},
|
||||
{"5", KEY_5},
|
||||
{"6", KEY_6},
|
||||
{"7", KEY_7},
|
||||
{"8", KEY_8},
|
||||
{"9", KEY_9},
|
||||
{"0", KEY_0},
|
||||
{"MINUS", KEY_MINUS},
|
||||
{"EQUAL", KEY_EQUAL},
|
||||
{"BACKSPACE", KEY_BACKSPACE},
|
||||
{"TAB", KEY_TAB},
|
||||
{"Q", KEY_Q},
|
||||
{"W", KEY_W},
|
||||
{"E", KEY_E},
|
||||
{"R", KEY_R},
|
||||
{"T", KEY_T},
|
||||
{"Y", KEY_Y},
|
||||
{"U", KEY_U},
|
||||
{"I", KEY_I},
|
||||
{"O", KEY_O},
|
||||
{"P", KEY_P},
|
||||
{"LEFTBRACE", KEY_LEFTBRACE},
|
||||
{"RIGHTBRACE", KEY_RIGHTBRACE},
|
||||
{"ENTER", KEY_ENTER},
|
||||
{"LEFTCTRL", KEY_LEFTCTRL},
|
||||
{"A", KEY_A},
|
||||
{"S", KEY_S},
|
||||
{"D", KEY_D},
|
||||
{"F", KEY_F},
|
||||
{"G", KEY_G},
|
||||
{"H", KEY_H},
|
||||
{"J", KEY_J},
|
||||
{"K", KEY_K},
|
||||
{"L", KEY_L},
|
||||
{"SEMICOLON", KEY_SEMICOLON},
|
||||
{"APOSTROPHE", KEY_APOSTROPHE},
|
||||
{"GRAVE", KEY_GRAVE},
|
||||
{"LEFTSHIFT", KEY_LEFTSHIFT},
|
||||
{"BACKSLASH", KEY_BACKSLASH},
|
||||
{"Z", KEY_Z},
|
||||
{"X", KEY_X},
|
||||
{"C", KEY_C},
|
||||
{"V", KEY_V},
|
||||
{"B", KEY_B},
|
||||
{"N", KEY_N},
|
||||
{"M", KEY_M},
|
||||
{"COMMA", KEY_COMMA},
|
||||
{"DOT", KEY_DOT},
|
||||
{"SLASH", KEY_SLASH},
|
||||
{"RIGHTSHIFT", KEY_RIGHTSHIFT},
|
||||
{"KPASTERISK", KEY_KPASTERISK},
|
||||
{"LEFTALT", KEY_LEFTALT},
|
||||
{"SPACE", KEY_SPACE},
|
||||
{"CAPSLOCK", KEY_CAPSLOCK},
|
||||
{"F1", KEY_F1},
|
||||
{"F2", KEY_F2},
|
||||
{"F3", KEY_F3},
|
||||
{"F4", KEY_F4},
|
||||
{"F5", KEY_F5},
|
||||
{"F6", KEY_F6},
|
||||
{"F7", KEY_F7},
|
||||
{"F8", KEY_F8},
|
||||
{"F9", KEY_F9},
|
||||
{"F10", KEY_F10},
|
||||
{"NUMLOCK", KEY_NUMLOCK},
|
||||
{"SCROLLLOCK", KEY_SCROLLLOCK},
|
||||
{"KP7", KEY_KP7},
|
||||
{"KP8", KEY_KP8},
|
||||
{"KP9", KEY_KP9},
|
||||
{"KPMINUS", KEY_KPMINUS},
|
||||
{"KP4", KEY_KP4},
|
||||
{"KP5", KEY_KP5},
|
||||
{"KP6", KEY_KP6},
|
||||
{"KPPLUS", KEY_KPPLUS},
|
||||
{"KP1", KEY_KP1},
|
||||
{"KP2", KEY_KP2},
|
||||
{"KP3", KEY_KP3},
|
||||
{"KP0", KEY_KP0},
|
||||
{"KPDOT", KEY_KP0},
|
||||
{"ZENKAKUHANKAKU", KEY_ZENKAKUHANKAKU},
|
||||
{"102ND", KEY_102ND},
|
||||
{"F11", KEY_F11},
|
||||
{"F12", KEY_F12},
|
||||
{"RO", KEY_RO},
|
||||
{"KATAKANA", KEY_KATAKANA},
|
||||
{"HIRAGANA", KEY_HIRAGANA},
|
||||
{"HENKAN", KEY_HENKAN},
|
||||
{"KATAKANAHIRAGANA", KEY_KATAKANAHIRAGANA},
|
||||
{"MUHENKAN", KEY_MUHENKAN},
|
||||
{"KPJPCOMMA", KEY_KPJPCOMMA},
|
||||
{"KPENTER", KEY_KPENTER},
|
||||
{"RIGHTCTRL", KEY_RIGHTCTRL},
|
||||
{"KPSLASH", KEY_KPSLASH},
|
||||
{"SYSRQ", KEY_SYSRQ},
|
||||
{"RIGHTALT", KEY_RIGHTALT},
|
||||
{"LINEFEED", KEY_LINEFEED},
|
||||
{"HOME", KEY_HOME},
|
||||
{"UP", KEY_UP},
|
||||
{"PAGEUP", KEY_PAGEUP},
|
||||
{"LEFT", KEY_LEFT},
|
||||
{"RIGHT", KEY_RIGHT},
|
||||
{"END", KEY_END},
|
||||
{"DOWN", KEY_DOWN},
|
||||
{"PAGEDOWN", KEY_PAGEDOWN},
|
||||
{"INSERT", KEY_INSERT},
|
||||
{"DELETE", KEY_DELETE},
|
||||
{"MACRO", KEY_MACRO},
|
||||
{"MUTE", KEY_MUTE},
|
||||
{"VOLUMEDOWN", KEY_VOLUMEDOWN},
|
||||
{"VOLUMEUP", KEY_VOLUMEUP},
|
||||
{"POWER", KEY_POWER},
|
||||
{"KPEQUAL", KEY_KPEQUAL},
|
||||
{"KPPLUSMINUS", KEY_KPPLUSMINUS},
|
||||
{"PAUSE", KEY_PAUSE},
|
||||
{"SCALE", KEY_SCALE},
|
||||
{"KPCOMMA", KEY_KPCOMMA},
|
||||
{"HANGEUL", KEY_HANGEUL},
|
||||
{"HANGUEL", KEY_HANGEUL},
|
||||
{"HANJA", KEY_HANJA},
|
||||
{"YEN", KEY_YEN},
|
||||
{"LEFTMETA", KEY_LEFTMETA},
|
||||
{"RIGHTMETA", KEY_LEFTMETA},
|
||||
{"COMPOSE", KEY_COMPOSE},
|
||||
{"STOP", KEY_STOP},
|
||||
{"AGAIN", KEY_AGAIN},
|
||||
{"PROPS", KEY_PROPS},
|
||||
{"UNDO", KEY_UNDO},
|
||||
{"FRONT", KEY_FRONT},
|
||||
{"COPY", KEY_COPY},
|
||||
{"OPEN", KEY_OPEN},
|
||||
{"PASTE", KEY_PASTE},
|
||||
{"FIND", KEY_FIND},
|
||||
{"CUT", KEY_CUT},
|
||||
{"HELP", KEY_HELP},
|
||||
{"MENU", KEY_MENU},
|
||||
{"CALC", KEY_CALC},
|
||||
{"SETUP", KEY_SETUP},
|
||||
{"SLEEP", KEY_SLEEP},
|
||||
{"WAKEUP", KEY_WAKEUP},
|
||||
{"FILE", KEY_FILE},
|
||||
{"SENDFILE", KEY_SENDFILE},
|
||||
{"DELETEFILE", KEY_DELETEFILE},
|
||||
{"XFER", KEY_XFER},
|
||||
{"PROG1", KEY_PROG1},
|
||||
{"PROG2", KEY_PROG2},
|
||||
{"WWW", KEY_WWW},
|
||||
{"MSDOS", KEY_MSDOS},
|
||||
{"COFFEE", KEY_COFFEE},
|
||||
{"SCREENLOCK", KEY_COFFEE},
|
||||
{"DIRECTION", KEY_DIRECTION},
|
||||
{"CYCLEWINDOWS", KEY_CYCLEWINDOWS},
|
||||
{"MAIL", KEY_MAIL},
|
||||
{"BOOKMARKS", KEY_BOOKMARKS},
|
||||
{"COMPUTER", KEY_COMPUTER},
|
||||
{"BACK", KEY_BACK},
|
||||
{"FORWARD", KEY_FORWARD},
|
||||
{"CLOSECD", KEY_CLOSECD},
|
||||
{"EJECTCD", KEY_EJECTCD},
|
||||
{"EJECTCLOSECD", KEY_EJECTCLOSECD},
|
||||
{"NEXTSONG", KEY_NEXTSONG},
|
||||
{"PLAYPAUSE", KEY_PLAYPAUSE},
|
||||
{"PREVIOUSSONG", KEY_PREVIOUSSONG},
|
||||
{"STOPCD", KEY_STOPCD},
|
||||
{"RECORD", KEY_RECORD},
|
||||
{"REWIND", KEY_REWIND},
|
||||
{"PHONE", KEY_PHONE},
|
||||
{"ISO", KEY_ISO},
|
||||
{"CONFIG", KEY_CONFIG},
|
||||
{"HOMEPAGE", KEY_HOMEPAGE},
|
||||
{"REFRESH", KEY_REFRESH},
|
||||
{"EXIT", KEY_EXIT},
|
||||
{"MOVE", KEY_MOVE},
|
||||
{"EDIT", KEY_EDIT},
|
||||
{"SCROLLUP", KEY_SCROLLUP},
|
||||
{"SCROLLDOWN", KEY_SCROLLDOWN},
|
||||
{"KPLEFTPAREN", KEY_KPLEFTPAREN},
|
||||
{"KPRIGHTPAREN", KEY_KPRIGHTPAREN},
|
||||
{"NEW", KEY_NEW},{"REDO", KEY_REDO},
|
||||
{"F13", KEY_F13},{"F14", KEY_F14},
|
||||
{"F15", KEY_F15},{"F16", KEY_F16},
|
||||
{"F17", KEY_F17},{"F18", KEY_F18},
|
||||
{"F19", KEY_F19},{"F20", KEY_F20},
|
||||
{"F21", KEY_F21},{"F22", KEY_F22},
|
||||
{"F23", KEY_F23},{"F24", KEY_F24},
|
||||
{"PLAYCD", KEY_PLAYCD},
|
||||
{"PAUSECD", KEY_PAUSECD},
|
||||
{"PROG3", KEY_PROG3},
|
||||
{"PROG4", KEY_PROG4},
|
||||
{"DASHBOARD", KEY_DASHBOARD},
|
||||
{"SUSPEND", KEY_SUSPEND},
|
||||
{"CLOSE", KEY_CLOSE},
|
||||
{"PLAY", KEY_PLAY},
|
||||
{"FASTFORWARD", KEY_FASTFORWARD},
|
||||
{"BASSBOOST", KEY_BASSBOOST},
|
||||
{"PRINT", KEY_PRINT},
|
||||
{"HP", KEY_HP},
|
||||
{"CAMERA", KEY_CAMERA},
|
||||
{"SOUND", KEY_SOUND},
|
||||
{"QUESTION", KEY_QUESTION},
|
||||
{"EMAIL", KEY_EMAIL},
|
||||
{"CHAT", KEY_CHAT},
|
||||
{"SEARCH", KEY_SEARCH},
|
||||
{"CONNECT", KEY_CONNECT},
|
||||
{"FINANCE", KEY_FINANCE},
|
||||
{"SPORT", KEY_SPORT},
|
||||
{"SHOP", KEY_SHOP},
|
||||
{"ALTERASE", KEY_ALTERASE},
|
||||
{"CANCEL", KEY_CANCEL},
|
||||
{"BRIGHTNESSDOWN", KEY_BRIGHTNESSDOWN},
|
||||
{"BRIGHTNESSUP", KEY_BRIGHTNESSUP},
|
||||
{"MEDIA", KEY_MEDIA},
|
||||
{"SWITCHVIDEOMODE", KEY_SWITCHVIDEOMODE},
|
||||
{"KBDILLUMTOGGLE", KEY_KBDILLUMTOGGLE},
|
||||
{"KBDILLUMDOWN", KEY_KBDILLUMDOWN},
|
||||
{"KBDILLUMUP", KEY_KBDILLUMUP},
|
||||
{"SEND", KEY_SEND},
|
||||
{"REPLY", KEY_REPLY},
|
||||
{"FORWARDMAIL", KEY_FORWARDMAIL},
|
||||
{"SAVE", KEY_SAVE},
|
||||
{"DOCUMENTS", KEY_DOCUMENTS},
|
||||
{"BATTERY", KEY_BATTERY},
|
||||
{"BLUETOOTH", KEY_BLUETOOTH},
|
||||
{"WLAN", KEY_WLAN},
|
||||
{"UWB", KEY_UWB},
|
||||
{"UNKNOWN", KEY_UNKNOWN},
|
||||
{"VIDEO_NEXT", KEY_VIDEO_NEXT},
|
||||
{"VIDEO_PREV", KEY_VIDEO_PREV},
|
||||
{"BRIGHTNESS_CYCLE", KEY_BRIGHTNESS_CYCLE},
|
||||
{"BRIGHTNESS_ZERO", KEY_BRIGHTNESS_ZERO},
|
||||
{"DISPLAY_OFF", KEY_DISPLAY_OFF},
|
||||
{"WIMAX", KEY_WIMAX},
|
||||
{"RFKILL", KEY_RFKILL},
|
||||
{"BTN_MISC", BTN_MISC},
|
||||
{"BTN_0", BTN_0},
|
||||
{"BTN_1", BTN_1},
|
||||
{"BTN_2", BTN_2},
|
||||
{"BTN_3", BTN_3},
|
||||
{"BTN_4", BTN_4},
|
||||
{"BTN_5", BTN_5},
|
||||
{"BTN_6", BTN_6},
|
||||
{"BTN_7", BTN_7},
|
||||
{"BTN_8", BTN_8},
|
||||
{"BTN_9", BTN_9},
|
||||
{"BTN_MOUSE", BTN_MOUSE},
|
||||
{"BTN_LEFT", BTN_LEFT},
|
||||
{"BTN_RIGHT", BTN_RIGHT},
|
||||
{"BTN_MIDDLE", BTN_MIDDLE},
|
||||
{"BTN_SIDE", BTN_SIDE},
|
||||
{"BTN_EXTRA", BTN_EXTRA},
|
||||
{"BTN_FORWARD", BTN_FORWARD},
|
||||
{"BTN_BACK", BTN_BACK},
|
||||
{"BTN_TASK", BTN_TASK},
|
||||
{"BTN_JOYSTICK", BTN_JOYSTICK},
|
||||
{"BTN_TRIGGER", BTN_TRIGGER},
|
||||
{"BTN_THUMB", BTN_THUMB},
|
||||
{"BTN_THUMB2", BTN_THUMB2},
|
||||
{"BTN_TOP", BTN_TOP},
|
||||
{"BTN_TOP2", BTN_TOP2},
|
||||
{"BTN_PINKIE", BTN_PINKIE},
|
||||
{"BTN_BASE", BTN_BASE},
|
||||
{"BTN_BASE2", BTN_BASE2},
|
||||
{"BTN_BASE3", BTN_BASE3},
|
||||
{"BTN_BASE4", BTN_BASE4},
|
||||
{"BTN_BASE5", BTN_BASE5},
|
||||
{"BTN_BASE6", BTN_BASE6},
|
||||
{"BTN_DEAD", BTN_DEAD},
|
||||
{"BTN_GAMEPAD", BTN_GAMEPAD},
|
||||
{"BTN_A", BTN_A},
|
||||
{"BTN_B", BTN_B},
|
||||
{"BTN_C", BTN_C},
|
||||
{"BTN_X", BTN_X},
|
||||
{"BTN_Y", BTN_Y},
|
||||
{"BTN_Z", BTN_Z},
|
||||
{"BTN_TL", BTN_TL},
|
||||
{"BTN_TR", BTN_TR},
|
||||
{"BTN_TL2", BTN_TL2},
|
||||
{"BTN_TR2", BTN_TR2},
|
||||
{"BTN_SELECT", BTN_SELECT},
|
||||
{"BTN_START", BTN_START},
|
||||
{"BTN_MODE", BTN_MODE},
|
||||
{"BTN_THUMBL", BTN_THUMBL},
|
||||
{"BTN_THUMBR", BTN_THUMBR},
|
||||
{"BTN_DIGI", BTN_DIGI},
|
||||
{"BTN_TOOL_PEN", BTN_TOOL_PEN},
|
||||
{"BTN_TOOL_RUBBER", BTN_TOOL_RUBBER},
|
||||
{"BTN_TOOL_BRUSH", BTN_TOOL_RUBBER},
|
||||
{"BTN_TOOL_PENCIL", BTN_TOOL_PENCIL},
|
||||
{"BTN_TOOL_AIRBRUSH", BTN_TOOL_AIRBRUSH},
|
||||
{"BTN_TOOL_FINGER", BTN_TOOL_FINGER},
|
||||
{"BTN_TOOL_MOUSE", BTN_TOOL_MOUSE},
|
||||
{"BTN_TOOL_LENS", BTN_TOOL_LENS},
|
||||
{"BTN_TOUCH", BTN_TOUCH},
|
||||
{"BTN_STYLUS", BTN_STYLUS},
|
||||
{"BTN_STYLUS2", BTN_STYLUS2},
|
||||
{"BTN_TOOL_DOUBLETAP", BTN_TOOL_DOUBLETAP},
|
||||
{"BTN_TOOL_TRIPLETAP", BTN_TOOL_TRIPLETAP},
|
||||
{"BTN_TOOL_QUADTAP", BTN_TOOL_QUADTAP},
|
||||
{"BTN_WHEEL", BTN_WHEEL},
|
||||
{"BTN_GEAR_DOWN", BTN_GEAR_DOWN},
|
||||
{"BTN_GEAR_UP", BTN_GEAR_UP},
|
||||
{"OK", KEY_OK},
|
||||
{"SELECT", KEY_SELECT},
|
||||
{"GOTO", KEY_GOTO},
|
||||
{"CLEAR", KEY_CLEAR},
|
||||
{"POWER2", KEY_POWER2},
|
||||
{"OPTION", KEY_OPTION},
|
||||
{"INFO", KEY_INFO},
|
||||
{"TIME", KEY_TIME},
|
||||
{"VENDOR", KEY_VENDOR},
|
||||
{"ARCHIVE", KEY_ARCHIVE},
|
||||
{"PROGRAM", KEY_PROGRAM},
|
||||
{"CHANNEL", KEY_CHANNEL},
|
||||
{"FAVORITES", KEY_FAVORITES},
|
||||
{"EPG", KEY_EPG},
|
||||
{"PVR", KEY_PVR},
|
||||
{"MHP", KEY_MHP},
|
||||
{"LANGUAGE", KEY_LANGUAGE},
|
||||
{"TITLE", KEY_TITLE},
|
||||
{"SUBTITLE", KEY_SUBTITLE},
|
||||
{"ANGLE", KEY_ANGLE},
|
||||
{"ZOOM", KEY_ZOOM},
|
||||
{"MODE", KEY_MODE},
|
||||
{"KEYBOARD", KEY_KEYBOARD},
|
||||
{"SCREEN", KEY_SCREEN},
|
||||
{"PC", KEY_PC},
|
||||
{"TV", KEY_TV},
|
||||
{"TV2", KEY_TV2},
|
||||
{"VCR", KEY_VCR},
|
||||
{"VCR2", KEY_VCR2},
|
||||
{"SAT", KEY_SAT},
|
||||
{"SAT2", KEY_SAT2},
|
||||
{"CD", KEY_CD},
|
||||
{"TAPE", KEY_TAPE},
|
||||
{"RADIO", KEY_RADIO},
|
||||
{"TUNER", KEY_TUNER},
|
||||
{"PLAYER", KEY_PLAYER},
|
||||
{"TEXT", KEY_TEXT},
|
||||
{"DVD", KEY_DVD},
|
||||
{"AUX", KEY_AUX},
|
||||
{"MP3", KEY_MP3},
|
||||
{"AUDIO", KEY_AUDIO},
|
||||
{"VIDEO", KEY_VIDEO},
|
||||
{"DIRECTORY", KEY_DIRECTORY},
|
||||
{"LIST", KEY_LIST},
|
||||
{"MEMO", KEY_MEMO},
|
||||
{"CALENDAR", KEY_CALENDAR},
|
||||
{"RED", KEY_RED},
|
||||
{"GREEN", KEY_GREEN},
|
||||
{"YELLOW", KEY_YELLOW},
|
||||
{"BLUE", KEY_BLUE},
|
||||
{"CHANNELUP", KEY_CHANNELUP},
|
||||
{"CHANNELDOWN", KEY_CHANNELDOWN},
|
||||
{"FIRST", KEY_FIRST},{"LAST", KEY_LAST},
|
||||
{"AB", KEY_AB},
|
||||
{"NEXT", KEY_NEXT},
|
||||
{"RESTART", KEY_RESTART},
|
||||
{"SLOW", KEY_SLOW},
|
||||
{"SHUFFLE", KEY_SHUFFLE},
|
||||
{"BREAK", KEY_BREAK},
|
||||
{"PREVIOUS", KEY_PREVIOUS},
|
||||
{"DIGITS", KEY_DIGITS},
|
||||
{"TEEN", KEY_TEEN},
|
||||
{"TWEN", KEY_TWEN},
|
||||
{"VIDEOPHONE", KEY_VIDEOPHONE},
|
||||
{"GAMES", KEY_GAMES},
|
||||
{"ZOOMIN", KEY_ZOOMIN},
|
||||
{"ZOOMOUT", KEY_ZOOMOUT},
|
||||
{"ZOOMRESET", KEY_ZOOMRESET},
|
||||
{"WORDPROCESSOR", KEY_WORDPROCESSOR},
|
||||
{"EDITOR", KEY_EDITOR},
|
||||
{"SPREADSHEET", KEY_SPREADSHEET},
|
||||
{"GRAPHICSEDITOR", KEY_GRAPHICSEDITOR},
|
||||
{"PRESENTATION", KEY_PRESENTATION},
|
||||
{"DATABASE", KEY_DATABASE},
|
||||
{"NEWS", KEY_NEWS},
|
||||
{"VOICEMAIL", KEY_VOICEMAIL},
|
||||
{"ADDRESSBOOK", KEY_ADDRESSBOOK},
|
||||
{"MESSENGER", KEY_MESSENGER},
|
||||
{"DISPLAYTOGGLE", KEY_DISPLAYTOGGLE},
|
||||
{"SPELLCHECK", KEY_SPELLCHECK},
|
||||
{"LOGOFF", KEY_LOGOFF},
|
||||
{"DOLLAR", KEY_DOLLAR},
|
||||
{"EURO", KEY_EURO},
|
||||
{"FRAMEBACK", KEY_FRAMEBACK},
|
||||
{"FRAMEFORWARD", KEY_FRAMEFORWARD},
|
||||
{"CONTEXT_MENU", KEY_CONTEXT_MENU},
|
||||
{"MEDIA_REPEAT", KEY_MEDIA_REPEAT},
|
||||
{"10CHANNELSUP", KEY_10CHANNELSUP},
|
||||
{"10CHANNELSDOWN", KEY_10CHANNELSDOWN},
|
||||
{"DEL_EOL", KEY_DEL_EOL},
|
||||
{"DEL_EOS", KEY_DEL_EOS},
|
||||
{"INS_LINE", KEY_INS_LINE},
|
||||
{"DEL_LINE", KEY_DEL_LINE},
|
||||
{"FN", KEY_FN},
|
||||
{"FN_ESC", KEY_FN_ESC},
|
||||
{"FN_F1", KEY_FN_F1},
|
||||
{"FN_F2", KEY_FN_F2},
|
||||
{"FN_F3", KEY_FN_F3},
|
||||
{"FN_F4", KEY_FN_F4},
|
||||
{"FN_F5", KEY_FN_F5},
|
||||
{"FN_F6", KEY_FN_F6},
|
||||
{"FN_F7", KEY_FN_F7},
|
||||
{"FN_F8", KEY_FN_F8},
|
||||
{"FN_F9", KEY_FN_F9},
|
||||
{"FN_F10", KEY_FN_F10},
|
||||
{"FN_F11", KEY_FN_F11},
|
||||
{"FN_F12", KEY_FN_F12},
|
||||
{"FN_1", KEY_FN_1},
|
||||
{"FN_2", KEY_FN_2},
|
||||
{"FN_D", KEY_FN_D},
|
||||
{"FN_E", KEY_FN_E},
|
||||
{"FN_F", KEY_FN_F},
|
||||
{"FN_S", KEY_FN_S},
|
||||
{"FN_B", KEY_FN_B},
|
||||
{"BRL_DOT1", KEY_BRL_DOT1},
|
||||
{"BRL_DOT2", KEY_BRL_DOT2},
|
||||
{"BRL_DOT3", KEY_BRL_DOT3},
|
||||
{"BRL_DOT4", KEY_BRL_DOT4},
|
||||
{"BRL_DOT5", KEY_BRL_DOT5},
|
||||
{"BRL_DOT6", KEY_BRL_DOT6},
|
||||
{"BRL_DOT7", KEY_BRL_DOT7},
|
||||
{"BRL_DOT8", KEY_BRL_DOT8},
|
||||
{"BRL_DOT9", KEY_BRL_DOT9},
|
||||
{"BRL_DOT10", KEY_BRL_DOT10},
|
||||
{"NUMERIC_0", KEY_NUMERIC_0},
|
||||
{"NUMERIC_1", KEY_NUMERIC_1},
|
||||
{"NUMERIC_2", KEY_NUMERIC_2},
|
||||
{"NUMERIC_3", KEY_NUMERIC_3},
|
||||
{"NUMERIC_4", KEY_NUMERIC_4},
|
||||
{"NUMERIC_5", KEY_NUMERIC_5},
|
||||
{"NUMERIC_6", KEY_NUMERIC_6},
|
||||
{"NUMERIC_7", KEY_NUMERIC_7},
|
||||
{"NUMERIC_8", KEY_NUMERIC_8},
|
||||
{"NUMERIC_9", KEY_NUMERIC_9},
|
||||
{"NUMERIC_STAR", KEY_NUMERIC_STAR},
|
||||
{"NUMERIC_POUND", KEY_NUMERIC_POUND},
|
||||
{"CAMERA_FOCUS", KEY_CAMERA_FOCUS},
|
||||
{"WPS_BUTTON", KEY_WPS_BUTTON},
|
||||
{"TOUCHPAD_TOGGLE", KEY_TOUCHPAD_TOGGLE},
|
||||
{"TOUCHPAD_ON", KEY_TOUCHPAD_ON},
|
||||
{"TOUCHPAD_OFF", KEY_TOUCHPAD_OFF},
|
||||
{"BTN_TRIGGER_HAPPY", BTN_TRIGGER_HAPPY},
|
||||
{"BTN_TRIGGER_HAPPY1", BTN_TRIGGER_HAPPY1},
|
||||
{"BTN_TRIGGER_HAPPY2", BTN_TRIGGER_HAPPY2},
|
||||
{"BTN_TRIGGER_HAPPY3", BTN_TRIGGER_HAPPY3},
|
||||
{"BTN_TRIGGER_HAPPY4", BTN_TRIGGER_HAPPY4},
|
||||
{"BTN_TRIGGER_HAPPY5", BTN_TRIGGER_HAPPY5},
|
||||
{"BTN_TRIGGER_HAPPY6", BTN_TRIGGER_HAPPY6},
|
||||
{"BTN_TRIGGER_HAPPY7", BTN_TRIGGER_HAPPY7},
|
||||
{"BTN_TRIGGER_HAPPY8", BTN_TRIGGER_HAPPY8},
|
||||
{"BTN_TRIGGER_HAPPY9", BTN_TRIGGER_HAPPY9},
|
||||
{"BTN_TRIGGER_HAPPY10", BTN_TRIGGER_HAPPY10},
|
||||
{"BTN_TRIGGER_HAPPY11", BTN_TRIGGER_HAPPY11},
|
||||
{"BTN_TRIGGER_HAPPY12", BTN_TRIGGER_HAPPY12},
|
||||
{"BTN_TRIGGER_HAPPY13", BTN_TRIGGER_HAPPY13},
|
||||
{"BTN_TRIGGER_HAPPY14", BTN_TRIGGER_HAPPY14},
|
||||
{"BTN_TRIGGER_HAPPY15", BTN_TRIGGER_HAPPY15},
|
||||
{"BTN_TRIGGER_HAPPY16", BTN_TRIGGER_HAPPY16},
|
||||
{"BTN_TRIGGER_HAPPY17", BTN_TRIGGER_HAPPY17},
|
||||
{"BTN_TRIGGER_HAPPY18", BTN_TRIGGER_HAPPY18},
|
||||
{"BTN_TRIGGER_HAPPY19", BTN_TRIGGER_HAPPY19},
|
||||
{"BTN_TRIGGER_HAPPY20", BTN_TRIGGER_HAPPY20},
|
||||
{"BTN_TRIGGER_HAPPY21", BTN_TRIGGER_HAPPY21},
|
||||
{"BTN_TRIGGER_HAPPY22", BTN_TRIGGER_HAPPY22},
|
||||
{"BTN_TRIGGER_HAPPY23", BTN_TRIGGER_HAPPY23},
|
||||
{"BTN_TRIGGER_HAPPY24", BTN_TRIGGER_HAPPY24},
|
||||
{"BTN_TRIGGER_HAPPY25", BTN_TRIGGER_HAPPY25},
|
||||
{"BTN_TRIGGER_HAPPY26", BTN_TRIGGER_HAPPY26},
|
||||
{"BTN_TRIGGER_HAPPY27", BTN_TRIGGER_HAPPY27},
|
||||
{"BTN_TRIGGER_HAPPY28", BTN_TRIGGER_HAPPY28},
|
||||
{"BTN_TRIGGER_HAPPY29", BTN_TRIGGER_HAPPY29},
|
||||
{"BTN_TRIGGER_HAPPY30", BTN_TRIGGER_HAPPY30},
|
||||
{"BTN_TRIGGER_HAPPY31", BTN_TRIGGER_HAPPY31},
|
||||
{"BTN_TRIGGER_HAPPY32", BTN_TRIGGER_HAPPY32},
|
||||
{"BTN_TRIGGER_HAPPY33", BTN_TRIGGER_HAPPY33},
|
||||
{"BTN_TRIGGER_HAPPY34", BTN_TRIGGER_HAPPY34},
|
||||
{"BTN_TRIGGER_HAPPY35", BTN_TRIGGER_HAPPY35},
|
||||
{"BTN_TRIGGER_HAPPY36", BTN_TRIGGER_HAPPY36},
|
||||
{"BTN_TRIGGER_HAPPY37", BTN_TRIGGER_HAPPY37},
|
||||
{"BTN_TRIGGER_HAPPY38", BTN_TRIGGER_HAPPY38},
|
||||
{"BTN_TRIGGER_HAPPY39", BTN_TRIGGER_HAPPY39},
|
||||
{"BTN_TRIGGER_HAPPY40", BTN_TRIGGER_HAPPY40},
|
||||
/* Aliases */
|
||||
{"CTRL", KEY_LEFTCTRL},
|
||||
{"META", KEY_LEFTMETA},
|
||||
{"ALT", KEY_LEFTALT},
|
||||
{"SHIFT", KEY_LEFTSHIFT},
|
||||
{"PRINTSCR", KEY_SYSRQ},
|
||||
{"MIC_MUTE", KEY_F20}};
|
||||
|
||||
#endif
|
5
makefile
5
makefile
@ -1,13 +1,14 @@
|
||||
CC ?= gcc
|
||||
CFLAGS = -Wall -Werror -pedantic --std=c99 -O2
|
||||
VERSION = 0.5
|
||||
LDFLAGS = -lxkbcommon
|
||||
VERSION = 0.4
|
||||
PREFIX = /usr/local
|
||||
MANPREFIX = ${PREFIX}/share/man
|
||||
|
||||
hkd: hkd.c
|
||||
|
||||
debug:
|
||||
gcc -Wall -O0 -g hkd.c -o hkd_debug
|
||||
gcc -Wall -O0 -g hkd.c -lxkbcommon -o hkd_debug
|
||||
|
||||
install: hkd
|
||||
mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||
|
@ -5,10 +5,6 @@ parse: parse.c
|
||||
|
||||
parse_v2: parse_v2.c
|
||||
|
||||
replace: replace.c
|
||||
|
||||
replace_v2: replace_v2.c
|
||||
|
||||
ioctl: ioctl.c
|
||||
|
||||
evtest: evtest.c
|
||||
@ -18,4 +14,4 @@ inotify: inotify.c
|
||||
struct_init: struct_init.c
|
||||
|
||||
clean:
|
||||
rm -f *.o parse parse_v2 replace replace_v2 ioctl inotify struct_init
|
||||
rm -f *.o parse parse_v2 ioctl inotify struct_init
|
||||
|
@ -1,43 +0,0 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* recursively replaces every instance of m(match) with r(eplace) inside of s */
|
||||
void replace (char *s, const char *m, const char *r)
|
||||
{
|
||||
static int off = 0;
|
||||
int d = strlen(r) - strlen(m);
|
||||
int ss = strlen(s);
|
||||
char *pos;
|
||||
|
||||
if ((pos = strstr(s + off, m))) {
|
||||
|
||||
char *tmp;
|
||||
int rs = strlen(r);
|
||||
int ms = strlen(m);
|
||||
|
||||
if (d > 0) {
|
||||
if (!(tmp = realloc(s, ss + 2 + d)))
|
||||
exit(-1);
|
||||
s = tmp;
|
||||
}
|
||||
memmove(pos + rs, pos + ms, strlen(pos) - ms + 1);
|
||||
memcpy(pos, r, rs);
|
||||
off += rs;
|
||||
replace(s, m, r);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int main (void) {
|
||||
char *s = strdup(" volup");
|
||||
|
||||
printf("original: %s\n", s);
|
||||
replace(s, "volup", "this short, like a lot--------");
|
||||
printf("replaced: %s\n", s);
|
||||
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
|
||||
char * replace (const char *s, const char *m, const char *r)
|
||||
{
|
||||
char *new_s = strdup(s);
|
||||
int ms = strlen(m), rs = strlen(r);
|
||||
char *pos, *tmp;
|
||||
int off = 0;
|
||||
|
||||
while((pos = strstr(new_s + off, m))) {
|
||||
int ps = strlen(pos), ss = strlen(new_s);
|
||||
|
||||
if (rs > ms) {
|
||||
if (!(tmp = realloc(new_s, ss + 1 + (rs - ms))))
|
||||
exit(-10);
|
||||
new_s = tmp;
|
||||
}
|
||||
|
||||
memmove(pos + rs, pos + ms, ps - ms);
|
||||
memcpy(pos, r, rs);
|
||||
off += rs;
|
||||
}
|
||||
return new_s;
|
||||
}
|
||||
|
||||
char * replace_fast (const char *s, const char *m, const char *r)
|
||||
{
|
||||
char *new_s = strdup(s);
|
||||
int ms = strlen(m), rs = strlen(r);
|
||||
char *t1;
|
||||
|
||||
int count = 0;
|
||||
int *offs = NULL, o = 0, *t2;
|
||||
int nss = strlen(new_s);
|
||||
while ((t1 = strstr(new_s + o, m))) {
|
||||
if (!(t2 = realloc(offs, sizeof(int) * (count + 1))))
|
||||
exit(-10);
|
||||
offs = t2;
|
||||
offs[count] = (t1 - new_s) + (rs - ms) * count;
|
||||
o = (t1 - new_s) + 1;
|
||||
count++;
|
||||
}
|
||||
|
||||
if ((rs - ms) > 0) {
|
||||
if (!(t1 = realloc(new_s, nss + (rs - ms) * count)))
|
||||
exit(-5);
|
||||
new_s = t1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
char* x = new_s + offs[i];
|
||||
int d = strlen(x) - ms;
|
||||
memmove(x + rs, x + ms, d);
|
||||
memcpy(x, r, rs);
|
||||
}
|
||||
|
||||
return new_s;
|
||||
}
|
||||
|
||||
void replace_fast_2 (char **s, const char *m, const char *r)
|
||||
{
|
||||
char **new_s = s;
|
||||
int ms = strlen(m), rs = strlen(r);
|
||||
char *t1;
|
||||
|
||||
int count = 0;
|
||||
int *offs = NULL, o = 0, *t2;
|
||||
int nss = strlen(*new_s);
|
||||
while ((t1 = strstr(*new_s + o, m))) {
|
||||
/* check if the match is surrounded by whitespace */
|
||||
if ((t1[ms] == '\0' || isblank(t1[ms]))
|
||||
&& isblank(t1 > *new_s ? *(t1 - 1) : ' ')) {
|
||||
if (!(t2 = realloc(offs, sizeof(int) * (count + 1))))
|
||||
exit(-1);
|
||||
offs = t2;
|
||||
offs[count] = (t1 - *new_s) + (rs - ms) * count;
|
||||
count++;
|
||||
}
|
||||
o = (t1 - *new_s) + 1;
|
||||
|
||||
}
|
||||
|
||||
if ((rs - ms) > 0) {
|
||||
if (!(t1 = realloc(*new_s, nss + (rs - ms) * count)))
|
||||
exit(-1);
|
||||
*new_s = t1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
char* x = *new_s + offs[i];
|
||||
int d = strlen(x) - ms;
|
||||
memmove(x + rs, x + ms, d);
|
||||
memcpy(x, r, rs);
|
||||
}
|
||||
if (offs)
|
||||
free(offs);
|
||||
}
|
||||
|
||||
|
||||
int main(void){
|
||||
clock_t t1, t2;
|
||||
char *s = " volup";
|
||||
|
||||
|
||||
printf("Before: %s\n", s);
|
||||
if ((t1 = clock()) == (clock_t)-1)
|
||||
exit(-1);
|
||||
char *r = replace(s, "volup", "I am alive, I'm aliveeeeee!");
|
||||
t2 = clock();
|
||||
printf("After replace: %s\n", r);
|
||||
printf("Time took: %f\n\n", (t2-t1)/(CLOCKS_PER_SEC/10e3));
|
||||
free(r);
|
||||
|
||||
|
||||
printf("Before: %s\n", s);
|
||||
if ((t1 = clock()) == (clock_t)-1)
|
||||
exit(-1);
|
||||
char *x = replace_fast(s, "volup", "I am alive, I'm aliveeeeee!");
|
||||
t2 = clock();
|
||||
printf("After replace_fast: %s\n", x);
|
||||
printf("Time took: %f\n\n", (t2-t1)/(CLOCKS_PER_SEC/10e3));
|
||||
free(x);
|
||||
|
||||
printf("Before: %s\n", s);
|
||||
char *s1 = strdup(s);
|
||||
if ((t1 = clock()) == (clock_t)-1)
|
||||
exit(-1);
|
||||
replace_fast_2(&s1, "volup", "I am alive, I'm aliveeeeee!");
|
||||
t2 = clock();
|
||||
printf("After replace_fast: %s\n", s1);
|
||||
printf("Time took: %f\n\n", (t2-t1)/(CLOCKS_PER_SEC/10e3));
|
||||
free(s1);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user