mirror of
https://github.com/alols/xcape.git
synced 2026-09-10 09:36:15 -04:00
what can I say
This commit is contained in:
parent
067c8c0a2a
commit
6262889876
2
Makefile
2
Makefile
|
|
@ -4,7 +4,7 @@ MANDIR?=/man/man1
|
|||
|
||||
TARGET := xcape
|
||||
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wall -g -O0
|
||||
CFLAGS += `pkg-config --cflags xtst x11`
|
||||
LDFLAGS += `pkg-config --libs xtst x11`
|
||||
LDFLAGS += -pthread
|
||||
|
|
|
|||
857
xcape.c
857
xcape.c
|
|
@ -38,528 +38,517 @@
|
|||
* Internal data types
|
||||
***********************************************************************/
|
||||
typedef struct _Key_t {
|
||||
KeyCode key;
|
||||
struct _Key_t *next;
|
||||
KeyCode key;
|
||||
struct _Key_t* next;
|
||||
} Key_t;
|
||||
|
||||
typedef struct _KeyMap_t {
|
||||
Bool UseKeyCode; /* (for from) instead of KeySym; ignore latter */
|
||||
KeySym from_ks;
|
||||
KeyCode from_kc;
|
||||
Bool UseModifier;
|
||||
Bool UseModifierCode;
|
||||
KeySym modifier;
|
||||
KeyCode modifier_code;
|
||||
Key_t *to_keys;
|
||||
Bool used;
|
||||
Bool pressed;
|
||||
Bool mouse;
|
||||
struct timeval down_at;
|
||||
struct _KeyMap_t *next;
|
||||
Bool UseKeyCode; /* (for from) instead of KeySym; ignore latter */
|
||||
KeySym from_ks;
|
||||
KeyCode from_kc;
|
||||
Bool UseModifier;
|
||||
Bool UseModifierCode;
|
||||
KeySym modifier;
|
||||
KeyCode modifier_code;
|
||||
Key_t* to_keys;
|
||||
Bool used;
|
||||
Bool pressed;
|
||||
Bool mouse;
|
||||
struct timeval down_at;
|
||||
struct _KeyMap_t* next;
|
||||
} KeyMap_t;
|
||||
|
||||
typedef struct _XCape_t {
|
||||
Display *data_conn;
|
||||
Display *ctrl_conn;
|
||||
XRecordContext record_ctx;
|
||||
pthread_t sigwait_thread;
|
||||
sigset_t sigset;
|
||||
Bool debug;
|
||||
KeyMap_t *map;
|
||||
Key_t *generated;
|
||||
struct timeval timeout;
|
||||
Display* data_conn;
|
||||
Display* ctrl_conn;
|
||||
XRecordContext record_ctx;
|
||||
pthread_t sigwait_thread;
|
||||
sigset_t sigset;
|
||||
Bool debug;
|
||||
KeyMap_t* map;
|
||||
Key_t* generated;
|
||||
struct timeval timeout;
|
||||
} XCape_t;
|
||||
|
||||
/************************************************************************
|
||||
* Internal function declarations
|
||||
***********************************************************************/
|
||||
void *sig_handler(void *user_data);
|
||||
void* sig_handler(void* user_data);
|
||||
|
||||
void intercept(XPointer user_data, XRecordInterceptData *data);
|
||||
void intercept(XPointer user_data, XRecordInterceptData* data);
|
||||
|
||||
KeyMap_t *parse_mapping(Display *ctrl_conn, char *mapping, Bool debug);
|
||||
KeyMap_t* parse_mapping(Display* ctrl_conn, char* mapping, Bool debug);
|
||||
|
||||
void delete_mapping(KeyMap_t *map);
|
||||
void delete_mapping(KeyMap_t* map);
|
||||
|
||||
Key_t *key_add_key(Key_t *keys, KeyCode key);
|
||||
Key_t* key_add_key(Key_t* keys, KeyCode key);
|
||||
|
||||
void delete_keys(Key_t *keys);
|
||||
void delete_keys(Key_t* keys);
|
||||
|
||||
void print_usage(const char *program_name);
|
||||
void print_usage(const char* program_name);
|
||||
|
||||
/************************************************************************
|
||||
* Main function
|
||||
***********************************************************************/
|
||||
int main(int argc, char **argv) {
|
||||
XCape_t *self = malloc(sizeof(XCape_t));
|
||||
int main(int argc, char** argv) {
|
||||
XCape_t* self = malloc(sizeof(XCape_t));
|
||||
|
||||
int dummy, ch;
|
||||
int dummy, ch;
|
||||
|
||||
static char default_mapping[] = "Control_L=Escape";
|
||||
char *mapping = default_mapping;
|
||||
static char default_mapping[] = "#37=Escape;#62=Return;#108=Shift_L|Insert;#100=BackSpace";
|
||||
char* mapping = default_mapping;
|
||||
|
||||
XRecordRange *rec_range = XRecordAllocRange();
|
||||
XRecordClientSpec client_spec = XRecordAllClients;
|
||||
XRecordRange* rec_range = XRecordAllocRange();
|
||||
XRecordClientSpec client_spec = XRecordAllClients;
|
||||
|
||||
self->debug = False;
|
||||
self->timeout.tv_sec = 0;
|
||||
self->timeout.tv_usec = 500000;
|
||||
self->generated = NULL;
|
||||
self->debug = False;
|
||||
self->timeout.tv_sec = 0;
|
||||
self->timeout.tv_usec = 500000;
|
||||
self->generated = NULL;
|
||||
|
||||
rec_range->device_events.first = KeyPress;
|
||||
rec_range->device_events.last = ButtonRelease;
|
||||
rec_range->device_events.first = KeyPress;
|
||||
rec_range->device_events.last = ButtonRelease;
|
||||
|
||||
while ((ch = getopt(argc, argv, "de:t:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
self->debug = True;
|
||||
break;
|
||||
case 'e':
|
||||
mapping = optarg;
|
||||
break;
|
||||
case 't': {
|
||||
int ms = atoi(optarg);
|
||||
if (ms > 0) {
|
||||
self->timeout.tv_sec = ms / 1000;
|
||||
self->timeout.tv_usec = (ms % 1000) * 1000;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid argument for '-t': %s.\n", optarg);
|
||||
print_usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
return EXIT_SUCCESS;
|
||||
while ((ch = getopt(argc, argv, "de:t:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
self->debug = True;
|
||||
break;
|
||||
case 'e':
|
||||
mapping = optarg;
|
||||
break;
|
||||
case 't': {
|
||||
int ms = atoi(optarg);
|
||||
if (ms > 0) {
|
||||
self->timeout.tv_sec = ms / 1000;
|
||||
self->timeout.tv_usec = (ms % 1000) * 1000;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid argument for '-t': %s.\n", optarg);
|
||||
print_usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
fprintf(stderr, "Not a command line option: '%s'\n", argv[optind]);
|
||||
print_usage(argv[0]);
|
||||
if (optind < argc) {
|
||||
fprintf(stderr, "Not a command line option: '%s'\n", argv[optind]);
|
||||
print_usage(argv[0]);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (!XInitThreads()) {
|
||||
fprintf(stderr, "Failed to initialize threads.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
self->data_conn = XOpenDisplay(NULL);
|
||||
self->ctrl_conn = XOpenDisplay(NULL);
|
||||
|
||||
if (!self->data_conn || !self->ctrl_conn) {
|
||||
fprintf(stderr, "Unable to connect to X11 display. Is $DISPLAY set?\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!XQueryExtension(self->ctrl_conn, "XTEST", &dummy, &dummy, &dummy)) {
|
||||
fprintf(stderr, "Xtst extension missing\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!XRecordQueryVersion(self->ctrl_conn, &dummy, &dummy)) {
|
||||
fprintf(stderr, "Failed to obtain xrecord version\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!XkbQueryExtension(self->ctrl_conn, &dummy, &dummy, &dummy, &dummy, &dummy)) {
|
||||
fprintf(stderr, "Failed to obtain xkb version\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
self->map = parse_mapping(self->ctrl_conn, mapping, self->debug);
|
||||
|
||||
if (self->map == NULL) {
|
||||
fprintf(stderr, "Failed to parse_mapping\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (self->debug != True)
|
||||
daemon(0, 0);
|
||||
/* self->debug = False; */
|
||||
|
||||
sigemptyset(&self->sigset);
|
||||
sigaddset(&self->sigset, SIGINT);
|
||||
sigaddset(&self->sigset, SIGTERM);
|
||||
pthread_sigmask(SIG_BLOCK, &self->sigset, NULL);
|
||||
|
||||
pthread_create(&self->sigwait_thread, NULL, sig_handler, self);
|
||||
|
||||
self->record_ctx = XRecordCreateContext(self->ctrl_conn, 0, &client_spec, 1, &rec_range, 1);
|
||||
|
||||
if (self->record_ctx == 0) {
|
||||
fprintf(stderr, "Failed to create xrecord context\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
XSync(self->ctrl_conn, False);
|
||||
|
||||
if (!XRecordEnableContext(self->data_conn, self->record_ctx, intercept, (XPointer)self)) {
|
||||
fprintf(stderr, "Failed to enable xrecord context\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pthread_join(self->sigwait_thread, NULL);
|
||||
|
||||
if (!XRecordFreeContext(self->ctrl_conn, self->record_ctx)) {
|
||||
fprintf(stderr, "Failed to free xrecord context\n");
|
||||
}
|
||||
|
||||
if (self->debug)
|
||||
fprintf(stdout, "main exiting\n");
|
||||
|
||||
XFree(rec_range);
|
||||
|
||||
XCloseDisplay(self->ctrl_conn);
|
||||
XCloseDisplay(self->data_conn);
|
||||
|
||||
delete_mapping(self->map);
|
||||
|
||||
free(self);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (!XInitThreads()) {
|
||||
fprintf(stderr, "Failed to initialize threads.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
self->data_conn = XOpenDisplay(NULL);
|
||||
self->ctrl_conn = XOpenDisplay(NULL);
|
||||
|
||||
if (!self->data_conn || !self->ctrl_conn) {
|
||||
fprintf(stderr, "Unable to connect to X11 display. Is $DISPLAY set?\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!XQueryExtension(self->ctrl_conn, "XTEST", &dummy, &dummy, &dummy)) {
|
||||
fprintf(stderr, "Xtst extension missing\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!XRecordQueryVersion(self->ctrl_conn, &dummy, &dummy)) {
|
||||
fprintf(stderr, "Failed to obtain xrecord version\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!XkbQueryExtension(self->ctrl_conn, &dummy, &dummy, &dummy, &dummy,
|
||||
&dummy)) {
|
||||
fprintf(stderr, "Failed to obtain xkb version\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
self->map = parse_mapping(self->ctrl_conn, mapping, self->debug);
|
||||
|
||||
if (self->map == NULL) {
|
||||
fprintf(stderr, "Failed to parse_mapping\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (self->debug != True)
|
||||
daemon(0, 0);
|
||||
self->debug = False;
|
||||
|
||||
sigemptyset(&self->sigset);
|
||||
sigaddset(&self->sigset, SIGINT);
|
||||
sigaddset(&self->sigset, SIGTERM);
|
||||
pthread_sigmask(SIG_BLOCK, &self->sigset, NULL);
|
||||
|
||||
pthread_create(&self->sigwait_thread, NULL, sig_handler, self);
|
||||
|
||||
self->record_ctx =
|
||||
XRecordCreateContext(self->ctrl_conn, 0, &client_spec, 1, &rec_range, 1);
|
||||
|
||||
if (self->record_ctx == 0) {
|
||||
fprintf(stderr, "Failed to create xrecord context\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
XSync(self->ctrl_conn, False);
|
||||
|
||||
if (!XRecordEnableContext(self->data_conn, self->record_ctx, intercept,
|
||||
(XPointer)self)) {
|
||||
fprintf(stderr, "Failed to enable xrecord context\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pthread_join(self->sigwait_thread, NULL);
|
||||
|
||||
if (!XRecordFreeContext(self->ctrl_conn, self->record_ctx)) {
|
||||
fprintf(stderr, "Failed to free xrecord context\n");
|
||||
}
|
||||
|
||||
if (self->debug)
|
||||
fprintf(stdout, "main exiting\n");
|
||||
|
||||
XFree(rec_range);
|
||||
|
||||
XCloseDisplay(self->ctrl_conn);
|
||||
XCloseDisplay(self->data_conn);
|
||||
|
||||
delete_mapping(self->map);
|
||||
|
||||
free(self);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Internal functions
|
||||
***********************************************************************/
|
||||
void *sig_handler(void *user_data) {
|
||||
XCape_t *self = (XCape_t *)user_data;
|
||||
int sig;
|
||||
void* sig_handler(void* user_data) {
|
||||
XCape_t* self = (XCape_t*)user_data;
|
||||
int sig;
|
||||
|
||||
if (self->debug)
|
||||
fprintf(stdout, "sig_handler running...\n");
|
||||
if (self->debug)
|
||||
fprintf(stdout, "sig_handler running...\n");
|
||||
|
||||
sigwait(&self->sigset, &sig);
|
||||
sigwait(&self->sigset, &sig);
|
||||
|
||||
if (self->debug)
|
||||
fprintf(stdout, "Caught signal %d!\n", sig);
|
||||
if (self->debug)
|
||||
fprintf(stdout, "Caught signal %d!\n", sig);
|
||||
|
||||
XLockDisplay(self->ctrl_conn);
|
||||
XLockDisplay(self->ctrl_conn);
|
||||
|
||||
if (!XRecordDisableContext(self->ctrl_conn, self->record_ctx)) {
|
||||
fprintf(stderr, "Failed to disable xrecord context\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!XRecordDisableContext(self->ctrl_conn, self->record_ctx)) {
|
||||
fprintf(stderr, "Failed to disable xrecord context\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
XSync(self->ctrl_conn, False);
|
||||
XSync(self->ctrl_conn, False);
|
||||
|
||||
XUnlockDisplay(self->ctrl_conn);
|
||||
XUnlockDisplay(self->ctrl_conn);
|
||||
|
||||
if (self->debug)
|
||||
fprintf(stdout, "sig_handler exiting...\n");
|
||||
if (self->debug)
|
||||
fprintf(stdout, "sig_handler exiting...\n");
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Key_t *key_add_key(Key_t *keys, KeyCode key) {
|
||||
Key_t *rval = keys;
|
||||
Key_t* key_add_key(Key_t* keys, KeyCode key) {
|
||||
Key_t* rval = keys;
|
||||
|
||||
if (keys == NULL) {
|
||||
keys = malloc(sizeof(Key_t));
|
||||
rval = keys;
|
||||
} else {
|
||||
while (keys->next != NULL)
|
||||
keys = keys->next;
|
||||
keys = (keys->next = malloc(sizeof(Key_t)));
|
||||
}
|
||||
if (keys == NULL) {
|
||||
keys = malloc(sizeof(Key_t));
|
||||
rval = keys;
|
||||
} else {
|
||||
while (keys->next != NULL)
|
||||
keys = keys->next;
|
||||
keys = (keys->next = malloc(sizeof(Key_t)));
|
||||
}
|
||||
|
||||
keys->key = key;
|
||||
keys->next = NULL;
|
||||
keys->key = key;
|
||||
keys->next = NULL;
|
||||
|
||||
return rval;
|
||||
return rval;
|
||||
}
|
||||
|
||||
void handle_key(XCape_t *self, KeyMap_t *key, Bool mouse_pressed,
|
||||
int key_event) {
|
||||
Key_t *k;
|
||||
void handle_key(XCape_t* self, KeyMap_t* key, Bool mouse_pressed, int key_event) {
|
||||
Key_t* k;
|
||||
|
||||
if (key_event == KeyPress) {
|
||||
if (self->debug)
|
||||
fprintf(stdout, "Key pressed!\n");
|
||||
if (key_event == KeyPress) {
|
||||
if (self->debug)
|
||||
fprintf(stdout, "Key pressed!\n");
|
||||
|
||||
|
||||
char buf[32], *keys = buf;
|
||||
XQueryKeymap(self->ctrl_conn, keys);
|
||||
|
||||
// lshift and rshift
|
||||
if ((BIT(keys, 50) || BIT(keys, 62)) && key->from_kc == 100)
|
||||
{
|
||||
XTestFakeKeyEvent(self->ctrl_conn, 22, True, 0);
|
||||
/* XTestFakeKeyEvent(self->ctrl_conn, 22, False, 0); */
|
||||
self->generated = key_add_key(self->generated, 22);
|
||||
XFlush(self->ctrl_conn);
|
||||
key->pressed = True;
|
||||
key->used = True;
|
||||
key->mouse = True;
|
||||
return;
|
||||
}
|
||||
|
||||
key->pressed = True;
|
||||
|
||||
gettimeofday(&key->down_at, NULL);
|
||||
|
||||
if (mouse_pressed) {
|
||||
key->used = True;
|
||||
}
|
||||
} else {
|
||||
if (self->debug)
|
||||
fprintf(stdout, "Key released!\n");
|
||||
if (key->mouse)
|
||||
{
|
||||
XTestFakeKeyEvent(self->ctrl_conn, 22, False, 0);
|
||||
self->generated = key_add_key(self->generated, 22);
|
||||
XFlush(self->ctrl_conn);
|
||||
key->mouse = False;
|
||||
}
|
||||
else if (key->used == False) {
|
||||
struct timeval timev = self->timeout;
|
||||
gettimeofday(&timev, NULL);
|
||||
timersub(&timev, &key->down_at, &timev);
|
||||
|
||||
if (timercmp(&timev, &self->timeout, <)) {
|
||||
char buf[32], *keys = buf;
|
||||
XQueryKeymap(self->ctrl_conn, keys);
|
||||
if (key->UseModifier) {
|
||||
if (!BIT(keys, XKeysymToKeycode(self->ctrl_conn, key->modifier))) {
|
||||
goto skip;
|
||||
}
|
||||
} else if (key->UseModifierCode) {
|
||||
if (!BIT(keys, key->modifier_code)) {
|
||||
goto skip;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 32; i++)
|
||||
if (keys[i])
|
||||
goto skip;
|
||||
}
|
||||
/* if (key->from_kc == 108) system("copyq select 0"); */
|
||||
for (k = key->to_keys; k != NULL; k = k->next) {
|
||||
if (self->debug)
|
||||
fprintf(stdout, "Generating %s!\n",
|
||||
XKeysymToString(
|
||||
XkbKeycodeToKeysym(self->ctrl_conn, k->key, 0, 0)));
|
||||
|
||||
XTestFakeKeyEvent(self->ctrl_conn, k->key, True, 0);
|
||||
self->generated = key_add_key(self->generated, k->key);
|
||||
// lshift and rshift
|
||||
if ((BIT(keys, 50) || BIT(keys, 62)) && key->from_kc == 100) {
|
||||
XTestFakeKeyEvent(self->ctrl_conn, 22, True, 0);
|
||||
/* XTestFakeKeyEvent(self->ctrl_conn, 22, False, 0); */
|
||||
self->generated = key_add_key(self->generated, 22);
|
||||
XFlush(self->ctrl_conn);
|
||||
key->pressed = True;
|
||||
key->used = True;
|
||||
key->mouse = True;
|
||||
return;
|
||||
}
|
||||
for (k = key->to_keys; k != NULL; k = k->next) {
|
||||
XTestFakeKeyEvent(self->ctrl_conn, k->key, False, 0);
|
||||
self->generated = key_add_key(self->generated, k->key);
|
||||
|
||||
key->pressed = True;
|
||||
|
||||
gettimeofday(&key->down_at, NULL);
|
||||
|
||||
/* if (mouse_pressed) { */
|
||||
/* key->used = True; */
|
||||
/* } */
|
||||
} else {
|
||||
if (self->debug)
|
||||
fprintf(stdout, "Key released!\n");
|
||||
if (key->mouse) {
|
||||
XTestFakeKeyEvent(self->ctrl_conn, 22, False, 0);
|
||||
self->generated = key_add_key(self->generated, 22);
|
||||
XFlush(self->ctrl_conn);
|
||||
key->mouse = False;
|
||||
} else if (key->used == False) {
|
||||
struct timeval timev = self->timeout;
|
||||
gettimeofday(&timev, NULL);
|
||||
timersub(&timev, &key->down_at, &timev);
|
||||
|
||||
if (timercmp(&timev, &self->timeout, <)) {
|
||||
char buf[32], *keys = buf;
|
||||
XQueryKeymap(self->ctrl_conn, keys);
|
||||
if (key->UseModifier) {
|
||||
if (!BIT(keys, XKeysymToKeycode(self->ctrl_conn, key->modifier))) {
|
||||
goto skip;
|
||||
}
|
||||
} else if (key->UseModifierCode) {
|
||||
if (!BIT(keys, key->modifier_code)) {
|
||||
goto skip;
|
||||
}
|
||||
}
|
||||
/* else { */
|
||||
/* for (int i = 0; i < 32; i++) */
|
||||
/* if (keys[i]) */
|
||||
/* goto skip; */
|
||||
/* } */
|
||||
/* if (key->from_kc == 108) system("copyq select 0"); */
|
||||
for (k = key->to_keys; k != NULL; k = k->next) {
|
||||
if (self->debug)
|
||||
fprintf(stdout, "Generating %s!\n",
|
||||
XKeysymToString(XkbKeycodeToKeysym(self->ctrl_conn, k->key, 0, 0)));
|
||||
|
||||
XTestFakeKeyEvent(self->ctrl_conn, k->key, True, 0);
|
||||
self->generated = key_add_key(self->generated, k->key);
|
||||
}
|
||||
for (k = key->to_keys; k != NULL; k = k->next) {
|
||||
XTestFakeKeyEvent(self->ctrl_conn, k->key, False, 0);
|
||||
self->generated = key_add_key(self->generated, k->key);
|
||||
}
|
||||
XFlush(self->ctrl_conn);
|
||||
}
|
||||
}
|
||||
XFlush(self->ctrl_conn);
|
||||
}
|
||||
skip:
|
||||
key->used = False;
|
||||
key->pressed = False;
|
||||
}
|
||||
skip:
|
||||
key->used = False;
|
||||
key->pressed = False;
|
||||
}
|
||||
}
|
||||
|
||||
void intercept(XPointer user_data, XRecordInterceptData *data) {
|
||||
XCape_t *self = (XCape_t *)user_data;
|
||||
static Bool mouse_pressed = False;
|
||||
KeyMap_t *km;
|
||||
void intercept(XPointer user_data, XRecordInterceptData* data) {
|
||||
XCape_t* self = (XCape_t*)user_data;
|
||||
static Bool mouse_pressed = False;
|
||||
KeyMap_t* km;
|
||||
|
||||
XLockDisplay(self->ctrl_conn);
|
||||
XLockDisplay(self->ctrl_conn);
|
||||
|
||||
if (data->category == XRecordFromServer) {
|
||||
int key_event = data->data[0];
|
||||
KeyCode key_code = data->data[1];
|
||||
Key_t *g, *g_prev = NULL;
|
||||
if (data->category == XRecordFromServer) {
|
||||
int key_event = data->data[0];
|
||||
KeyCode key_code = data->data[1];
|
||||
Key_t *g, *g_prev = NULL;
|
||||
|
||||
for (g = self->generated; g != NULL; g = g->next) {
|
||||
if (g->key == key_code) {
|
||||
if (self->debug)
|
||||
fprintf(stdout, "Ignoring generated event.\n");
|
||||
if (g_prev != NULL) {
|
||||
g_prev->next = g->next;
|
||||
} else {
|
||||
self->generated = g->next;
|
||||
for (g = self->generated; g != NULL; g = g->next) {
|
||||
if (g->key == key_code) {
|
||||
if (self->debug)
|
||||
fprintf(stdout, "Ignoring generated event.\n");
|
||||
if (g_prev != NULL) {
|
||||
g_prev->next = g->next;
|
||||
} else {
|
||||
self->generated = g->next;
|
||||
}
|
||||
free(g);
|
||||
goto exit;
|
||||
}
|
||||
g_prev = g;
|
||||
}
|
||||
free(g);
|
||||
goto exit;
|
||||
}
|
||||
g_prev = g;
|
||||
}
|
||||
|
||||
if (self->debug)
|
||||
fprintf(stdout, "Intercepted key event %d, key code %d\n", key_event,
|
||||
key_code);
|
||||
if (self->debug)
|
||||
fprintf(stdout, "Intercepted key event %d, key code %d\n", key_event, key_code);
|
||||
|
||||
if (key_event == ButtonPress) {
|
||||
mouse_pressed = True;
|
||||
} else if (key_event == ButtonRelease) {
|
||||
mouse_pressed = False;
|
||||
if (key_event == ButtonPress) {
|
||||
mouse_pressed = True;
|
||||
} else if (key_event == ButtonRelease) {
|
||||
mouse_pressed = False;
|
||||
}
|
||||
for (km = self->map; km != NULL; km = km->next) {
|
||||
if ((km->UseKeyCode == False
|
||||
&& XkbKeycodeToKeysym(self->ctrl_conn, key_code, 0, 0) == km->from_ks)
|
||||
|| (km->UseKeyCode == True && key_code == km->from_kc)) {
|
||||
handle_key(self, km, mouse_pressed, key_event);
|
||||
} else if (km->pressed && (key_event == KeyPress || key_event == ButtonPress)) {
|
||||
km->used = True;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (km = self->map; km != NULL; km = km->next) {
|
||||
if ((km->UseKeyCode == False &&
|
||||
XkbKeycodeToKeysym(self->ctrl_conn, key_code, 0, 0) ==
|
||||
km->from_ks) ||
|
||||
(km->UseKeyCode == True && key_code == km->from_kc)) {
|
||||
handle_key(self, km, mouse_pressed, key_event);
|
||||
} else if (km->pressed &&
|
||||
(key_event == KeyPress || key_event == ButtonPress)) {
|
||||
km->used = True;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
XUnlockDisplay(self->ctrl_conn);
|
||||
XRecordFreeData(data);
|
||||
XUnlockDisplay(self->ctrl_conn);
|
||||
XRecordFreeData(data);
|
||||
}
|
||||
|
||||
KeyMap_t *parse_token(Display *dpy, char *token, Bool debug) {
|
||||
KeyMap_t *km = NULL;
|
||||
KeySym ks;
|
||||
char *modifier, *from, *to, *key;
|
||||
KeyCode code; /* keycode (to) */
|
||||
long fromcode; /* keycode (from) */
|
||||
KeyMap_t* parse_token(Display* dpy, char* token, Bool debug) {
|
||||
KeyMap_t* km = NULL;
|
||||
KeySym ks;
|
||||
char *modifier, *from, *to, *key;
|
||||
KeyCode code; /* keycode (to) */
|
||||
long fromcode; /* keycode (from) */
|
||||
|
||||
to = token;
|
||||
modifier = strsep(&to, ":");
|
||||
if (to == NULL) {
|
||||
to = token;
|
||||
modifier = NULL;
|
||||
}
|
||||
|
||||
from = strsep(&to, "=");
|
||||
if (to != NULL) {
|
||||
km = calloc(1, sizeof(KeyMap_t));
|
||||
|
||||
if (!strncmp(from, "#", 1) && strsep(&from, "#") != NULL) {
|
||||
errno = 0;
|
||||
fromcode = strtoul(from, NULL, 0); /* dec, oct, hex automatically */
|
||||
km->UseKeyCode = True;
|
||||
km->from_kc = (KeyCode)fromcode;
|
||||
if (debug) {
|
||||
KeySym ks_temp = XkbKeycodeToKeysym(dpy, (KeyCode)fromcode, 0, 0);
|
||||
fprintf(stderr, "Assigned mapping from from \"%s\" ( keysym 0x%x, "
|
||||
"key code %d)\n",
|
||||
XKeysymToString(ks_temp), (unsigned)ks_temp,
|
||||
(unsigned)km->from_kc);
|
||||
}
|
||||
} else {
|
||||
if ((ks = XStringToKeysym(from)) == NoSymbol) {
|
||||
fprintf(stderr, "Invalid key: %s\n", token);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
km->UseKeyCode = False;
|
||||
km->from_ks = ks;
|
||||
km->to_keys = NULL;
|
||||
|
||||
if (debug) {
|
||||
fprintf(stderr, "Assigned mapping from \"%s\" ( keysym 0x%x, "
|
||||
"key code %d)\n",
|
||||
XKeysymToString(km->from_ks), (unsigned)km->from_ks,
|
||||
(unsigned)XKeysymToKeycode(dpy, km->from_ks));
|
||||
}
|
||||
modifier = strsep(&to, ":");
|
||||
if (to == NULL) {
|
||||
to = token;
|
||||
modifier = NULL;
|
||||
}
|
||||
|
||||
if (modifier != NULL) {
|
||||
if (!strncmp(modifier, "#", 1) && strsep(&modifier, "#") != NULL) {
|
||||
km->UseModifierCode = True;
|
||||
km->modifier_code =
|
||||
strtoul(modifier, NULL, 0); /* dec, oct, hex automatically */
|
||||
} else {
|
||||
if ((ks = XStringToKeysym(modifier)) == NoSymbol) {
|
||||
fprintf(stderr, "Invalid key: %s\n", token);
|
||||
return NULL;
|
||||
}
|
||||
km->UseModifier = True;
|
||||
km->modifier = ks;
|
||||
if (debug) {
|
||||
fprintf(stderr,
|
||||
"Assigned mapping with modifier \"%s\" ( keysym 0x%x, "
|
||||
"key code %d)\n",
|
||||
XKeysymToString(km->modifier), (unsigned)km->modifier,
|
||||
(unsigned)XKeysymToKeycode(dpy, km->modifier));
|
||||
}
|
||||
}
|
||||
from = strsep(&to, "=");
|
||||
if (to != NULL) {
|
||||
km = calloc(1, sizeof(KeyMap_t));
|
||||
|
||||
} else {
|
||||
km->UseModifier = False;
|
||||
}
|
||||
if (!strncmp(from, "#", 1) && strsep(&from, "#") != NULL) {
|
||||
errno = 0;
|
||||
fromcode = strtoul(from, NULL, 0); /* dec, oct, hex automatically */
|
||||
km->UseKeyCode = True;
|
||||
km->from_kc = (KeyCode)fromcode;
|
||||
if (debug) {
|
||||
KeySym ks_temp = XkbKeycodeToKeysym(dpy, (KeyCode)fromcode, 0, 0);
|
||||
fprintf(stderr,
|
||||
"Assigned mapping from from \"%s\" ( keysym 0x%x, "
|
||||
"key code %d)\n",
|
||||
XKeysymToString(ks_temp), (unsigned)ks_temp, (unsigned)km->from_kc);
|
||||
}
|
||||
} else {
|
||||
if ((ks = XStringToKeysym(from)) == NoSymbol) {
|
||||
fprintf(stderr, "Invalid key: %s\n", token);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
km->UseKeyCode = False;
|
||||
km->from_ks = ks;
|
||||
km->to_keys = NULL;
|
||||
|
||||
if (debug) {
|
||||
fprintf(stderr,
|
||||
"Assigned mapping from \"%s\" ( keysym 0x%x, "
|
||||
"key code %d)\n",
|
||||
XKeysymToString(km->from_ks), (unsigned)km->from_ks,
|
||||
(unsigned)XKeysymToKeycode(dpy, km->from_ks));
|
||||
}
|
||||
}
|
||||
|
||||
if (modifier != NULL) {
|
||||
if (!strncmp(modifier, "#", 1) && strsep(&modifier, "#") != NULL) {
|
||||
km->UseModifierCode = True;
|
||||
km->modifier_code = strtoul(modifier, NULL, 0); /* dec, oct, hex automatically */
|
||||
} else {
|
||||
if ((ks = XStringToKeysym(modifier)) == NoSymbol) {
|
||||
fprintf(stderr, "Invalid key: %s\n", token);
|
||||
return NULL;
|
||||
}
|
||||
km->UseModifier = True;
|
||||
km->modifier = ks;
|
||||
if (debug) {
|
||||
fprintf(stderr,
|
||||
"Assigned mapping with modifier \"%s\" ( keysym 0x%x, "
|
||||
"key code %d)\n",
|
||||
XKeysymToString(km->modifier), (unsigned)km->modifier,
|
||||
(unsigned)XKeysymToKeycode(dpy, km->modifier));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
km->UseModifier = False;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
key = strsep(&to, "|");
|
||||
if (key == NULL)
|
||||
break;
|
||||
|
||||
if ((ks = XStringToKeysym(key)) == NoSymbol) {
|
||||
fprintf(stderr, "Invalid key: %s\n", key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
code = XKeysymToKeycode(dpy, ks);
|
||||
if (code == 0) {
|
||||
fprintf(stderr,
|
||||
"WARNING: No keycode found for keysym "
|
||||
"%s (0x%x) in mapping %s. Ignoring this "
|
||||
"mapping.\n",
|
||||
key, (unsigned int)ks, token);
|
||||
return NULL;
|
||||
}
|
||||
km->to_keys = key_add_key(km->to_keys, code);
|
||||
|
||||
if (debug) {
|
||||
fprintf(stderr, "to \"%s\" (keysym 0x%x, key code %d)\n", key,
|
||||
(unsigned)XStringToKeysym(key), (unsigned)code);
|
||||
}
|
||||
}
|
||||
} else
|
||||
fprintf(stderr, "WARNING: Mapping without = has no effect: '%s'\n", token);
|
||||
|
||||
return km;
|
||||
}
|
||||
|
||||
KeyMap_t* parse_mapping(Display* ctrl_conn, char* mapping, Bool debug) {
|
||||
char* token;
|
||||
KeyMap_t *rval, *km, *nkm;
|
||||
|
||||
rval = km = NULL;
|
||||
|
||||
for (;;) {
|
||||
key = strsep(&to, "|");
|
||||
if (key == NULL)
|
||||
break;
|
||||
token = strsep(&mapping, ";");
|
||||
if (token == NULL)
|
||||
break;
|
||||
|
||||
if ((ks = XStringToKeysym(key)) == NoSymbol) {
|
||||
fprintf(stderr, "Invalid key: %s\n", key);
|
||||
return NULL;
|
||||
}
|
||||
nkm = parse_token(ctrl_conn, token, debug);
|
||||
|
||||
code = XKeysymToKeycode(dpy, ks);
|
||||
if (code == 0) {
|
||||
fprintf(stderr, "WARNING: No keycode found for keysym "
|
||||
"%s (0x%x) in mapping %s. Ignoring this "
|
||||
"mapping.\n",
|
||||
key, (unsigned int)ks, token);
|
||||
return NULL;
|
||||
}
|
||||
km->to_keys = key_add_key(km->to_keys, code);
|
||||
|
||||
if (debug) {
|
||||
fprintf(stderr, "to \"%s\" (keysym 0x%x, key code %d)\n", key,
|
||||
(unsigned)XStringToKeysym(key), (unsigned)code);
|
||||
}
|
||||
if (nkm != NULL) {
|
||||
if (km == NULL)
|
||||
rval = km = nkm;
|
||||
else {
|
||||
km->next = nkm;
|
||||
km = nkm;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
fprintf(stderr, "WARNING: Mapping without = has no effect: '%s'\n", token);
|
||||
|
||||
return km;
|
||||
return rval;
|
||||
}
|
||||
|
||||
KeyMap_t *parse_mapping(Display *ctrl_conn, char *mapping, Bool debug) {
|
||||
char *token;
|
||||
KeyMap_t *rval, *km, *nkm;
|
||||
|
||||
rval = km = NULL;
|
||||
|
||||
for (;;) {
|
||||
token = strsep(&mapping, ";");
|
||||
if (token == NULL)
|
||||
break;
|
||||
|
||||
nkm = parse_token(ctrl_conn, token, debug);
|
||||
|
||||
if (nkm != NULL) {
|
||||
if (km == NULL)
|
||||
rval = km = nkm;
|
||||
else {
|
||||
km->next = nkm;
|
||||
km = nkm;
|
||||
}
|
||||
void delete_mapping(KeyMap_t* map) {
|
||||
while (map != NULL) {
|
||||
KeyMap_t* next = map->next;
|
||||
delete_keys(map->to_keys);
|
||||
free(map);
|
||||
map = next;
|
||||
}
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
void delete_mapping(KeyMap_t *map) {
|
||||
while (map != NULL) {
|
||||
KeyMap_t *next = map->next;
|
||||
delete_keys(map->to_keys);
|
||||
free(map);
|
||||
map = next;
|
||||
}
|
||||
void delete_keys(Key_t* keys) {
|
||||
while (keys != NULL) {
|
||||
Key_t* next = keys->next;
|
||||
free(keys);
|
||||
keys = next;
|
||||
}
|
||||
}
|
||||
|
||||
void delete_keys(Key_t *keys) {
|
||||
while (keys != NULL) {
|
||||
Key_t *next = keys->next;
|
||||
free(keys);
|
||||
keys = next;
|
||||
}
|
||||
}
|
||||
|
||||
void print_usage(const char *program_name) {
|
||||
fprintf(stdout, "Usage: %s [-d] [-t timeout_ms] [-e <mapping>]\n",
|
||||
program_name);
|
||||
fprintf(stdout, "Runs as a daemon unless -d flag is set\n");
|
||||
void print_usage(const char* program_name) {
|
||||
fprintf(stdout, "Usage: %s [-d] [-t timeout_ms] [-e <mapping>]\n", program_name);
|
||||
fprintf(stdout, "Runs as a daemon unless -d flag is set\n");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue