mirror of
https://github.com/alols/xcape.git
synced 2026-09-10 13:06:14 -04:00
Compare commits
No commits in common. "master" and "v1.0" have entirely different histories.
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
xcape
|
||||
10
Makefile
10
Makefile
|
|
@ -1,6 +1,5 @@
|
|||
INSTALL=install
|
||||
PREFIX=/usr
|
||||
MANDIR?=/local/man/man1
|
||||
|
||||
TARGET := xcape
|
||||
|
||||
|
|
@ -9,18 +8,13 @@ CFLAGS += `pkg-config --cflags xtst x11`
|
|||
LDFLAGS += `pkg-config --libs xtst x11`
|
||||
LDFLAGS += -pthread
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): xcape.c
|
||||
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
|
||||
|
||||
install:
|
||||
$(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)/bin
|
||||
$(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)$(MANDIR)
|
||||
$(INSTALL) -m 0755 $(TARGET) $(DESTDIR)$(PREFIX)/bin/$(TARGET)
|
||||
$(INSTALL) -m 0644 xcape.1 $(DESTDIR)$(PREFIX)$(MANDIR)/xcape.1
|
||||
$(INSTALL) -Dm 755 $(TARGET) $(DESTDIR)$(PREFIX)/bin/$(TARGET)
|
||||
|
||||
clean:
|
||||
rm $(TARGET)
|
||||
|
||||
.PHONY: all clean install
|
||||
.PHONY: clean
|
||||
|
|
|
|||
82
README.md
82
README.md
|
|
@ -12,89 +12,39 @@ editor ;)
|
|||
Minimal building instructions
|
||||
-----------------------------
|
||||
|
||||
First install the development dependencies. On Debian-based systems
|
||||
(including Ubuntu and Linux Mint), run:
|
||||
|
||||
$ sudo apt-get install git gcc make pkg-config libx11-dev libxtst-dev libxi-dev
|
||||
|
||||
On Fedora-based systems, run:
|
||||
|
||||
$ sudo dnf install git gcc make pkgconfig libX11-devel libXtst-devel libXi-devel
|
||||
|
||||
Then run:
|
||||
|
||||
$ git clone https://github.com/alols/xcape.git
|
||||
$ sudo apt-get install git gcc make libx11-dev libxtst-dev
|
||||
$ mkdir xcape
|
||||
$ cd xcape
|
||||
$ git clone https://github.com/alols/xcape.git .
|
||||
$ make
|
||||
$ sudo make install
|
||||
|
||||
Usage
|
||||
-----
|
||||
$ xcape [-d] [-f] [-t <timeout ms>] [-e <map-expression>]
|
||||
$ xcape [-d] [-t <timeout ms>] [-e <map-expression>]
|
||||
|
||||
### `-d`
|
||||
|
||||
Debug mode. Does not fork into the background. Prints debug information.
|
||||
|
||||
### `-f`
|
||||
|
||||
Foreground mode. Does not fork into the background.
|
||||
Debug mode. Does not fork into the background.
|
||||
|
||||
### `-t <timeout ms>`
|
||||
|
||||
If you hold a key longer than this timeout, xcape will not generate a key
|
||||
event. Default is 500 ms.
|
||||
event. Default is 50 ms.
|
||||
|
||||
### `-e <map-expression>`
|
||||
|
||||
The expression has the grammar `'ModKey=Key[|OtherKey][;NextExpression]'`
|
||||
|
||||
The list of key names is found in the header file `X11/keysymdef.h` (remove
|
||||
the `XK_` prefix). Note that due to limitations of X11 shifted keys *must*
|
||||
be specified as a shift key followed by the key to be pressed rather than
|
||||
the actual name of the character. For example to generate "{" the
|
||||
expression `'ModKey=Shift_L|bracketleft'` could be used (assuming that you
|
||||
have a key with "{" above "[").
|
||||
The list of key names is found in the header file `X11/keysymdef.h`
|
||||
(remove the `XK_` prefix).
|
||||
|
||||
You can also specify keys in decimal (prefix `#`), octal (`#0`), or
|
||||
hexadecimal (`#0x`). They will be interpreted as keycodes unless no corresponding
|
||||
key name is found.
|
||||
#### Example
|
||||
|
||||
#### Examples
|
||||
|
||||
+ This will make Left Shift generate Escape when pressed and released on
|
||||
its own, and Left Control generate Ctrl-O combination when pressed and
|
||||
released on its own.
|
||||
|
||||
xcape -e 'Shift_L=Escape;Control_L=Control_L|O'
|
||||
|
||||
+ In conjunction with xmodmap it is possible to make an ordinary key act
|
||||
as an extra modifier. First map the key to the modifier with xmodmap
|
||||
and then the modifier back to the key with xcape. However, this has
|
||||
several limitations: the key will not work as ordinary until it is
|
||||
released, and in particular, *it may act as a modifier unintentionally if
|
||||
you type too fast.* This is not a bug in xcape, but an unavoidable
|
||||
consequence of using these two tools together in this way.
|
||||
As an example, we can make the space bar work as an additional ctrl
|
||||
key when held (similar to
|
||||
[Space2ctrl](https://github.com/r0adrunner/Space2Ctrl)) with the
|
||||
following sequence of commands.
|
||||
|
||||
# Map an unused modifier's keysym to the spacebar's keycode and make it a
|
||||
# control modifier. It needs to be an existing key so that emacs won't
|
||||
# spazz out when you press it. Hyper_L is a good candidate.
|
||||
spare_modifier="Hyper_L"
|
||||
xmodmap -e "keycode 65 = $spare_modifier"
|
||||
xmodmap -e "remove mod4 = $spare_modifier" # hyper_l is mod4 by default
|
||||
xmodmap -e "add Control = $spare_modifier"
|
||||
|
||||
# Map space to an unused keycode (to keep it around for xcape to
|
||||
# use).
|
||||
xmodmap -e "keycode any = space"
|
||||
|
||||
# Finally use xcape to cause the space bar to generate a space when tapped.
|
||||
xcape -e "$spare_modifier=space"
|
||||
xcape -e 'Shift_L=Escape;Control_L=Control_L|O'
|
||||
|
||||
This will make Left Shift generate Escape when pressed and released on
|
||||
it's own, and Left Control generate Ctrl-O combination when pressed and
|
||||
released on it's own.
|
||||
|
||||
Note regarding xmodmap
|
||||
----------------------
|
||||
|
|
@ -102,11 +52,11 @@ Note regarding xmodmap
|
|||
If you are in the habit of remapping keycodes to keysyms (eg, using xmodmap),
|
||||
there are two issues you may encounter.
|
||||
|
||||
1. You will need to restart xcape after every time you modify the mapping from
|
||||
1) You will need to restart xcape after every time you modify the mapping from
|
||||
keycodes to keysyms (eg, with xmodmap), or xcape will still use the old
|
||||
mapping.
|
||||
|
||||
2. The key you wish to send must have a defined keycode. So for example, with
|
||||
|
||||
2) The key you wish to send must have a defined keycode. So for example, with
|
||||
the default mapping `Control_L=Escape`, you still need an escape key defined
|
||||
in your xmodmap mapping. (I get around this by using 255, which my keyboard
|
||||
cannot send).
|
||||
|
|
|
|||
96
xcape.1
96
xcape.1
|
|
@ -1,96 +0,0 @@
|
|||
.TH XCAPE 1 2017-07-03 "John Hill" "xcape Manual"
|
||||
|
||||
.SH NAME
|
||||
xcape \- use a modifier key as another key
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B xcape
|
||||
[\fB-d\fR]
|
||||
[\fB-f\fR]
|
||||
[\fB-t\fR \fItimeout\fR]
|
||||
[\fB-e\fR \fImap-expression\fR]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBxcape\fR allows a modifier key to be used as another key when it is pressed
|
||||
and released on its own. The default behaviour is to generate the \fIEscape\fR
|
||||
key in place of \fIControl_L\fR (Left Control).
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-d
|
||||
Debug mode. Will run as a foreground process and print debug information.
|
||||
.TP
|
||||
.BR \-f
|
||||
Foreground mode. Will run as a foreground process.
|
||||
.TP
|
||||
.BR \-t " " \fItimeout\fR
|
||||
Give a \fItimeout\fR in milliseconds. If you hold a key longer than
|
||||
\fItimeout\fR a key event will not be generated.
|
||||
.TP
|
||||
.BR \-e " " \fImap-expression\fR
|
||||
Use \fImap-expression\fR as the expression(s).
|
||||
|
||||
.SH EXPRESSION SYNTAX
|
||||
Expression syntax is \'\fBModKey\fR=\fBKey\fR[|\fBOtherKey\fR]\'. Multiple
|
||||
expressions can be passed, delimited by semi-colons (;).
|
||||
.PP
|
||||
A list of keysyms can be found in the header file <\fIX11/keysymdef.h\fR>
|
||||
(without the \fIXK_\fR prefix).
|
||||
.PP
|
||||
Note that shifted keys must be specified as a shift key followed by the key to
|
||||
be pressed rather than the actual name of the character. For example to
|
||||
generate "\fI{\fR" the expression
|
||||
\'\fIModKey\fR=\fIShift_L\fR|\fIbracketleft\fR\' could be used
|
||||
(assuming that you have a key with \'{\' above \'[\').
|
||||
.PP
|
||||
You can also specify \fBModKey\fR in decimal (prefix \fI#\fR), octal
|
||||
(\fI#0\fR), or hexadecimal (\fI#0x\fR). It will be interpreted as a keycode
|
||||
unless no corresponding key name is
|
||||
found.
|
||||
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
Make Left Shift generate Escape when pressed and released on it's own, and Left
|
||||
Control generate Ctrl\-O combination when pressed and released on it's own:
|
||||
.RS
|
||||
\fBxcape\fR \fB-e\fR '\fIShift_L\fR=\fIEscape\fR;\fIControl_L\fR=\fIControl_L\fR|\fIO\fR'
|
||||
.RE
|
||||
.PP
|
||||
In conjugation with xmodmap it is possible to make an ordinary key act as an
|
||||
extra modifier. First map the key to the modifier with xmodmap and then the
|
||||
modifier back to the key with \fBxcape\fR. As an example, we can make the space
|
||||
bar work as an additional ctrl key when held with the following sequence of
|
||||
commands:
|
||||
.PP
|
||||
First, map an unused modifier's keysym to the spacebar's keycode and make it a
|
||||
control modifier. It needs to be an existing key so that emacs won't spazz out
|
||||
when you press it. Hyper_L is a good candidate.
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
\fBspare_modifier\fR="\fIHyper_L\fR"
|
||||
\fBxmodmap\fR \fB-e\fR "\fBkeycode\fR \fI65\fR = \fI$spare_modifier\fR"
|
||||
\fBxmodmap\fR \fB-e\fR "\fBremove\fR \fImod4\fR = \fI$spare_modifier\fR"
|
||||
# hyper_l is mod4 by default
|
||||
\fBxmodmap\fR \fB-e\fR "\fBadd\fR \fIControl\fR = \fI$spare_modifier\fR"
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
Next, map space to an unused keycode (to keep it around for \fBxcape\fR to use).
|
||||
.PP
|
||||
.RS
|
||||
\fBxmodmap\fR \fR-e\fR "\fBkeycode\fR \fIany\fR = \fIspace\fR"
|
||||
.RE
|
||||
.PP
|
||||
Finally use \fBxcape\fR to cause the space bar to generate a space when tapped.
|
||||
.PP
|
||||
.RS
|
||||
\fBxcape\fR \fB-e\fR "\fI$spare_modifier\fR=\fIspace\fR"
|
||||
.RE
|
||||
|
||||
.SH SEE ALSO
|
||||
\fBxmodmap\fR(1), \fBxev\fR(1)
|
||||
|
||||
.SH AUTHOR
|
||||
\fBxcape\fR was written by Albin Olsson
|
||||
(albin dot olsson at gmail dot com)
|
||||
265
xcape.c
265
xcape.c
|
|
@ -1,7 +1,7 @@
|
|||
/************************************************************************
|
||||
* xcape.c
|
||||
*
|
||||
* Copyright 2015 Albin Olsson
|
||||
* Copyright 2012 Albin Olsson
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -25,7 +25,6 @@
|
|||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/extensions/record.h>
|
||||
|
|
@ -44,9 +43,7 @@ typedef struct _Key_t
|
|||
|
||||
typedef struct _KeyMap_t
|
||||
{
|
||||
Bool UseKeyCode; /* (for from) instead of KeySym; ignore latter */
|
||||
KeySym from_ks;
|
||||
KeyCode from_kc;
|
||||
KeySym from;
|
||||
Key_t *to_keys;
|
||||
Bool used;
|
||||
Bool pressed;
|
||||
|
|
@ -62,11 +59,11 @@ typedef struct _XCape_t
|
|||
XRecordContext record_ctx;
|
||||
pthread_t sigwait_thread;
|
||||
sigset_t sigset;
|
||||
Bool foreground;
|
||||
Bool debug;
|
||||
KeyMap_t *map;
|
||||
Key_t *generated;
|
||||
struct timeval timeout;
|
||||
Bool timeout_valid;
|
||||
} XCape_t;
|
||||
|
||||
/************************************************************************
|
||||
|
|
@ -76,49 +73,31 @@ void *sig_handler (void *user_data);
|
|||
|
||||
void intercept (XPointer user_data, XRecordInterceptData *data);
|
||||
|
||||
KeyMap_t *parse_mapping (Display *ctrl_conn, char *mapping, Bool debug);
|
||||
|
||||
void delete_mapping (KeyMap_t *map);
|
||||
KeyMap_t *parse_mapping (Display *ctrl_conn, char *mapping);
|
||||
|
||||
Key_t *key_add_key (Key_t *keys, KeyCode key);
|
||||
|
||||
void delete_keys (Key_t *keys);
|
||||
|
||||
void print_usage (const char *program_name);
|
||||
|
||||
/************************************************************************
|
||||
* Main function
|
||||
***********************************************************************/
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
XCape_t *self = malloc (sizeof (XCape_t));
|
||||
|
||||
int dummy, ch;
|
||||
|
||||
static char default_mapping[] = "Control_L=Escape";
|
||||
char *mapping = default_mapping;
|
||||
|
||||
XRecordRange *rec_range = XRecordAllocRange();
|
||||
XRecordClientSpec client_spec = XRecordAllClients;
|
||||
|
||||
self->foreground = False;
|
||||
self->debug = False;
|
||||
self->timeout.tv_sec = 0;
|
||||
self->timeout.tv_usec = 500000;
|
||||
self->timeout_valid = True;
|
||||
self->generated = NULL;
|
||||
|
||||
rec_range->device_events.first = KeyPress;
|
||||
rec_range->device_events.last = ButtonRelease;
|
||||
|
||||
while ((ch = getopt (argc, argv, "dfe:t:")) != -1)
|
||||
while ((ch = getopt (argc, argv, "de:t:")) != -1)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 'd':
|
||||
self->debug = True;
|
||||
/* imply -f (no break) */
|
||||
case 'f':
|
||||
self->foreground = True;
|
||||
break;
|
||||
case 'e':
|
||||
mapping = optarg;
|
||||
|
|
@ -128,44 +107,27 @@ int main (int argc, char **argv)
|
|||
int ms = atoi (optarg);
|
||||
if (ms > 0)
|
||||
{
|
||||
self->timeout_valid = True;
|
||||
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;
|
||||
self->timeout_valid = False;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
print_usage (argv[0]);
|
||||
fprintf (stdout, "Usage: %s [-d] [-t timeout_ms] [-e <mapping>]\n", argv[0]);
|
||||
fprintf (stdout,
|
||||
"Runs as a daemon unless -d flag is set\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
|
|
@ -177,22 +139,19 @@ int main (int argc, char **argv)
|
|||
fprintf (stderr, "Failed to obtain xrecord version\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (!XkbQueryExtension (self->ctrl_conn, &dummy, &dummy,
|
||||
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);
|
||||
self->map = parse_mapping (self->ctrl_conn, mapping);
|
||||
|
||||
if (self->map == NULL)
|
||||
{
|
||||
fprintf (stderr, "Failed to parse_mapping\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (self->foreground != True)
|
||||
if (self->debug != True)
|
||||
daemon (0, 0);
|
||||
|
||||
sigemptyset (&self->sigset);
|
||||
|
|
@ -203,6 +162,11 @@ int main (int argc, char **argv)
|
|||
pthread_create (&self->sigwait_thread,
|
||||
NULL, sig_handler, self);
|
||||
|
||||
XRecordRange *rec_range = XRecordAllocRange();
|
||||
rec_range->device_events.first = KeyPress;
|
||||
rec_range->device_events.last = ButtonRelease;
|
||||
XRecordClientSpec client_spec = XRecordAllClients;
|
||||
|
||||
self->record_ctx = XRecordCreateContext (self->ctrl_conn,
|
||||
0, &client_spec, 1, &rec_range, 1);
|
||||
|
||||
|
|
@ -221,23 +185,15 @@ int main (int argc, char **argv)
|
|||
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);
|
||||
if (self->debug) fprintf (stdout, "main exiting\n");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -257,8 +213,6 @@ void *sig_handler (void *user_data)
|
|||
|
||||
if (self->debug) fprintf (stdout, "Caught signal %d!\n", sig);
|
||||
|
||||
XLockDisplay (self->ctrl_conn);
|
||||
|
||||
if (!XRecordDisableContext (self->ctrl_conn,
|
||||
self->record_ctx))
|
||||
{
|
||||
|
|
@ -268,8 +222,6 @@ void *sig_handler (void *user_data)
|
|||
|
||||
XSync (self->ctrl_conn, False);
|
||||
|
||||
XUnlockDisplay (self->ctrl_conn);
|
||||
|
||||
if (self->debug) fprintf (stdout, "sig_handler exiting...\n");
|
||||
|
||||
return NULL;
|
||||
|
|
@ -307,7 +259,8 @@ void handle_key (XCape_t *self, KeyMap_t *key,
|
|||
|
||||
key->pressed = True;
|
||||
|
||||
gettimeofday (&key->down_at, NULL);
|
||||
if (self->timeout_valid)
|
||||
gettimeofday (&key->down_at, NULL);
|
||||
|
||||
if (mouse_pressed)
|
||||
{
|
||||
|
|
@ -320,16 +273,19 @@ void handle_key (XCape_t *self, KeyMap_t *key,
|
|||
if (key->used == False)
|
||||
{
|
||||
struct timeval timev = self->timeout;
|
||||
gettimeofday (&timev, NULL);
|
||||
timersub (&timev, &key->down_at, &timev);
|
||||
if (self->timeout_valid)
|
||||
{
|
||||
gettimeofday (&timev, NULL);
|
||||
timersub (&timev, &key->down_at, &timev);
|
||||
}
|
||||
|
||||
if (timercmp (&timev, &self->timeout, <))
|
||||
if (!self->timeout_valid || timercmp (&timev, &self->timeout, <))
|
||||
{
|
||||
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)));
|
||||
XKeysymToString (XKeycodeToKeysym (self->ctrl_conn,
|
||||
k->key, 0)));
|
||||
|
||||
XTestFakeKeyEvent (self->ctrl_conn,
|
||||
k->key, True, 0);
|
||||
|
|
@ -355,8 +311,6 @@ void intercept (XPointer user_data, XRecordInterceptData *data)
|
|||
static Bool mouse_pressed = False;
|
||||
KeyMap_t *km;
|
||||
|
||||
XLockDisplay (self->ctrl_conn);
|
||||
|
||||
if (data->category == XRecordFromServer)
|
||||
{
|
||||
int key_event = data->data[0];
|
||||
|
|
@ -395,36 +349,33 @@ void intercept (XPointer user_data, XRecordInterceptData *data)
|
|||
{
|
||||
mouse_pressed = False;
|
||||
}
|
||||
for (km = self->map; km != NULL; km = km->next)
|
||||
else
|
||||
{
|
||||
if ((km->UseKeyCode == False
|
||||
&& XkbKeycodeToKeysym (self->ctrl_conn, key_code, 0, 0)
|
||||
== km->from_ks)
|
||||
|| (km->UseKeyCode == True
|
||||
&& key_code == km->from_kc))
|
||||
for (km = self->map; km != NULL; km = km->next)
|
||||
{
|
||||
handle_key (self, km, mouse_pressed, key_event);
|
||||
}
|
||||
else if (km->pressed
|
||||
&& (key_event == KeyPress || key_event == ButtonPress))
|
||||
{
|
||||
km->used = True;
|
||||
if (XkbKeycodeToKeysym (self->ctrl_conn, key_code, 0, 0)
|
||||
== km->from)
|
||||
{
|
||||
handle_key (self, km, mouse_pressed, key_event);
|
||||
}
|
||||
else if (km->pressed && key_event == KeyPress)
|
||||
{
|
||||
km->used = True;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
XUnlockDisplay (self->ctrl_conn);
|
||||
XRecordFreeData (data);
|
||||
}
|
||||
|
||||
KeyMap_t *parse_token (Display *dpy, char *token, Bool debug)
|
||||
KeyMap_t *parse_token (Display *dpy, char *token)
|
||||
{
|
||||
KeyMap_t *km = NULL;
|
||||
KeySym ks;
|
||||
char *from, *to, *key;
|
||||
KeyCode code; /* keycode */
|
||||
long parsed_code; /* parsed keycode value */
|
||||
KeyCode code;
|
||||
|
||||
to = token;
|
||||
from = strsep (&to, "=");
|
||||
|
|
@ -432,54 +383,14 @@ KeyMap_t *parse_token (Display *dpy, char *token, Bool debug)
|
|||
{
|
||||
km = calloc (1, sizeof (KeyMap_t));
|
||||
|
||||
if (!strncmp (from, "#", 1)
|
||||
&& strsep (&from, "#") != NULL)
|
||||
if ((ks = XStringToKeysym (from)) == NoSymbol)
|
||||
{
|
||||
errno = 0;
|
||||
parsed_code = strtoul (from, NULL, 0); /* dec, oct, hex automatically */
|
||||
if (errno == 0
|
||||
&& parsed_code <=255
|
||||
&& XkbKeycodeToKeysym (dpy, (KeyCode) parsed_code, 0, 0) != NoSymbol)
|
||||
{
|
||||
km->UseKeyCode = True;
|
||||
km->from_kc = (KeyCode) parsed_code;
|
||||
if (debug)
|
||||
{
|
||||
KeySym ks_temp = XkbKeycodeToKeysym (dpy, (KeyCode) parsed_code, 0, 0);
|
||||
fprintf(stderr, "Assigned mapping from \"%s\" ( keysym 0x%x, "
|
||||
"key code %d)\n",
|
||||
XKeysymToString(ks_temp),
|
||||
(unsigned) ks_temp,
|
||||
(unsigned) km->from_kc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Invalid keycode: %s\n", from);
|
||||
return NULL;
|
||||
}
|
||||
fprintf (stderr, "Invalid key: %s\n", token);
|
||||
return NULL;
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
km->from = ks;
|
||||
km->to_keys = NULL;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
|
|
@ -487,58 +398,31 @@ KeyMap_t *parse_token (Display *dpy, char *token, Bool debug)
|
|||
if (key == NULL)
|
||||
break;
|
||||
|
||||
if (!strncmp (key, "#", 1)
|
||||
&& strsep (&key, "#") != NULL)
|
||||
if ((ks = XStringToKeysym (key)) == NoSymbol)
|
||||
{
|
||||
errno = 0;
|
||||
parsed_code = strtoul (key, NULL, 0); /* dec, oct, hex automatically */
|
||||
if (!(errno == 0
|
||||
&& parsed_code <=255
|
||||
&& XkbKeycodeToKeysym (dpy, (KeyCode) parsed_code, 0, 0) != NoSymbol))
|
||||
{
|
||||
fprintf (stderr, "Invalid keycode: %s\n", key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
code = (KeyCode) parsed_code;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
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)
|
||||
{
|
||||
KeySym ks_temp = XkbKeycodeToKeysym (dpy, code, 0, 0);
|
||||
fprintf(stderr, "to \"%s\" (keysym 0x%x, key code %d)\n",
|
||||
XKeysymToString(ks_temp),
|
||||
(unsigned) ks_temp,
|
||||
(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)
|
||||
KeyMap_t *parse_mapping (Display *ctrl_conn, char *mapping)
|
||||
{
|
||||
char *token;
|
||||
KeyMap_t *rval, *km, *nkm;
|
||||
|
|
@ -551,7 +435,7 @@ KeyMap_t *parse_mapping (Display *ctrl_conn, char *mapping, Bool debug)
|
|||
if (token == NULL)
|
||||
break;
|
||||
|
||||
nkm = parse_token (ctrl_conn, token, debug);
|
||||
nkm = parse_token (ctrl_conn, token);
|
||||
|
||||
if (nkm != NULL)
|
||||
{
|
||||
|
|
@ -567,28 +451,3 @@ KeyMap_t *parse_mapping (Display *ctrl_conn, char *mapping, Bool debug)
|
|||
|
||||
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 print_usage (const char *program_name)
|
||||
{
|
||||
fprintf (stdout, "Usage: %s [-d] [-f] [-t timeout_ms] [-e <mapping>]\n", program_name);
|
||||
fprintf (stdout, "Runs as a daemon unless -d or -f flag is set\n");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue