Compare commits

..

No commits in common. "master" and "v1.2" have entirely different histories.
master ... v1.2

3 changed files with 48 additions and 85 deletions

View file

@ -12,17 +12,7 @@ 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
$ cd xcape
$ make
@ -30,15 +20,11 @@ Then run:
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>`
@ -56,8 +42,8 @@ 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 "[").
You can also specify keys in decimal (prefix `#`), octal (`#0`), or
hexadecimal (`#0x`). They will be interpreted as keycodes unless no corresponding
You can also specify ModKey in decimal (prefix `#`), octal (`#0`), or
hexadecimal (`#0x`). It will be interpreted as a keycode unless no corresponding
key name is found.
#### Examples
@ -68,11 +54,11 @@ key name is found.
xcape -e 'Shift_L=Escape;Control_L=Control_L|O'
+ In conjunction with xmodmap it is possible to make an ordinary key act
+ 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 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
relased, 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

10
xcape.1
View file

@ -1,4 +1,4 @@
.TH XCAPE 1 2017-07-03 "John Hill" "xcape Manual"
.TH XCAPE 1 2014-02-13 "John Hill" "xcape Manual"
.SH NAME
xcape \- use a modifier key as another key
@ -6,7 +6,6 @@ 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]
@ -18,10 +17,7 @@ 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.
Debug 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
@ -32,7 +28,7 @@ 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 (;).
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).

97
xcape.c
View file

@ -62,11 +62,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;
/************************************************************************
@ -101,24 +101,21 @@ int main (int argc, char **argv)
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,14 +125,13 @@ 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;
@ -192,7 +188,7 @@ int main (int argc, char **argv)
exit (EXIT_FAILURE);
}
if (self->foreground != True)
if (self->debug != True)
daemon (0, 0);
sigemptyset (&self->sigset);
@ -307,7 +303,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,10 +317,13 @@ 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)
{
@ -423,8 +423,8 @@ KeyMap_t *parse_token (Display *dpy, char *token, Bool debug)
KeyMap_t *km = NULL;
KeySym ks;
char *from, *to, *key;
KeyCode code; /* keycode */
long parsed_code; /* parsed keycode value */
KeyCode code; /* keycode (to) */
long fromcode; /* keycode (from) */
to = token;
from = strsep (&to, "=");
@ -436,17 +436,17 @@ KeyMap_t *parse_token (Display *dpy, char *token, Bool debug)
&& strsep (&from, "#") != NULL)
{
errno = 0;
parsed_code = strtoul (from, NULL, 0); /* dec, oct, hex automatically */
fromcode = strtoul (from, NULL, 0); /* dec, oct, hex automatically */
if (errno == 0
&& parsed_code <=255
&& XkbKeycodeToKeysym (dpy, (KeyCode) parsed_code, 0, 0) != NoSymbol)
&& fromcode <=255
&& XkbKeycodeToKeysym (dpy, (KeyCode) fromcode, 0, 0) != NoSymbol)
{
km->UseKeyCode = True;
km->from_kc = (KeyCode) parsed_code;
km->from_kc = (KeyCode) fromcode;
if (debug)
{
KeySym ks_temp = XkbKeycodeToKeysym (dpy, (KeyCode) parsed_code, 0, 0);
fprintf(stderr, "Assigned mapping from \"%s\" ( keysym 0x%x, "
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,
@ -487,47 +487,28 @@ 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);
key,
(unsigned) XStringToKeysym (key),
(unsigned) code);
}
}
}
@ -589,6 +570,6 @@ void delete_keys (Key_t *keys)
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");
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");
}