commit a4c99087ab04515d312bb08bc2d5832a744afd68
parent 4a06e8f4a81a1a9160909f1d6ce22f809a0cade9
Author: Bastien Dejean <nihilhill@gmail.com>
Date: Wed, 28 Aug 2013 22:56:45 +0200
Handle modes via the colon separator
Diffstat:
8 files changed, 68 insertions(+), 38 deletions(-)
diff --git a/doc/sxhkd.1 b/doc/sxhkd.1
@@ -2,12 +2,12 @@
.\" Title: sxhkd
.\" Author: [see the "Author" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 08/05/2013
+.\" Date: 08/28/2013
.\" Manual: Sxhkd Manual
.\" Source: Sxhkd 0.4.2
.\" Language: English
.\"
-.TH "SXHKD" "1" "08/05/2013" "Sxhkd 0\&.4\&.2" "Sxhkd Manual"
+.TH "SXHKD" "1" "08/28/2013" "Sxhkd 0\&.4\&.2" "Sxhkd Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -114,7 +114,7 @@ HOTKEY
COMMAND
HOTKEY := CHORD_1 ; CHORD_2 ; \&... ; CHORD_n
-CHORD_i := [MODIFIER_i][@|!|:]KEYSYM_i
+CHORD_i := [MODIFIER_i][@|!|~]KEYSYM_i
MODIFIER_i := MODIFIER_i1 + MODIFIER_i2 + \&... + MODIFIER_ik
.fi
.if n \{\
@@ -129,11 +129,13 @@ Hotkeys and commands can be spread across multiple lines by ending each partial
.sp
When multiple chords are separated by semicolons, the hotkey is a chord chain: the command will only be executed after receiving each chord of the chain in consecutive order\&.
.sp
+The colon character can be used instead of the semicolon to indicate that the chord chain shall not be aborted when the chain tail is reached\&. In which case, the \fIEscape\fR key can be used to manually abort the chain\&.
+.sp
If \fB@\fR is added at the beginning of the keysym, the command will be run on key release events, otherwise on key press events\&.
.sp
If \fB!\fR is added at the beginning of the keysym, the command will be run on motion notify events and must contain two integer conversion specifications which will be replaced by the \fIx\fR and \fIy\fR coordinates of the pointer relative to the root window referential (the only valid button keysyms for this type of hotkeys are: \fIbutton1\fR, \&..., \fIbutton5\fR)\&.
.sp
-If \fB:\fR is added at the beginning of the keysym, the captured event will be replayed for the other clients\&.
+If \fB~\fR is added at the beginning of the keysym, the captured event will be replayed for the other clients\&.
.sp
Mouse hotkeys can be defined by using one of the following special keysym names: \fIbutton1\fR, \fIbutton2\fR, \fIbutton3\fR, \&..., \fIbutton24\fR\&.
.sp
@@ -177,7 +179,7 @@ super + alt + {0\-9}
super + {alt,ctrl,alt + ctrl} + XF86Eject
sudo systemctl {suspend,reboot,poweroff}
-:button1
+~button1
bspc grab_pointer focus
super + button{1\-3}
diff --git a/doc/sxhkd.1.txt b/doc/sxhkd.1.txt
@@ -58,7 +58,7 @@ HOTKEY
COMMAND
HOTKEY := CHORD_1 ; CHORD_2 ; … ; CHORD_n
-CHORD_i := [MODIFIER_i][@|!|:]KEYSYM_i
+CHORD_i := [MODIFIER_i][@|!|~]KEYSYM_i
MODIFIER_i := MODIFIER_i1 + MODIFIER_i2 + … + MODIFIER_ik
----
@@ -70,11 +70,13 @@ Hotkeys and commands can be spread across multiple lines by ending each partial
When multiple chords are separated by semicolons, the hotkey is a chord chain: the command will only be executed after receiving each chord of the chain in consecutive order.
+The colon character can be used instead of the semicolon to indicate that the chord chain shall not be aborted when the chain tail is reached. In which case, the _Escape_ key can be used to manually abort the chain.
+
If *@* is added at the beginning of the keysym, the command will be run on key release events, otherwise on key press events.
If *!* is added at the beginning of the keysym, the command will be run on motion notify events and must contain two integer conversion specifications which will be replaced by the _x_ and _y_ coordinates of the pointer relative to the root window referential (the only valid button keysyms for this type of hotkeys are: _button1_, …, _button5_).
-If *:* is added at the beginning of the keysym, the captured event will be replayed for the other clients.
+If *~* is added at the beginning of the keysym, the captured event will be replayed for the other clients.
Mouse hotkeys can be defined by using one of the following special keysym names: _button1_, _button2_, _button3_, …, _button24_.
@@ -117,7 +119,7 @@ super + alt + {0-9}
super + {alt,ctrl,alt + ctrl} + XF86Eject
sudo systemctl {suspend,reboot,poweroff}
-:button1
+~button1
bspc grab_pointer focus
super + button{1-3}
diff --git a/parse.c b/parse.c
@@ -2447,10 +2447,10 @@ void process_hotkey(char *hotkey_string, char *command_string)
destroy_chunks(cm_chunks);
}
-char *get_token(char *dst, char *src, char *sep)
+char *get_token(char *dst, char *ign, char *src, char *sep)
{
size_t len = strlen(src);
- unsigned int i = 0, j = 0;
+ unsigned int i = 0, j = 0, k = 0;
bool inhibit = false;
bool found = false;
while (i < len && !found) {
@@ -2465,6 +2465,8 @@ char *get_token(char *dst, char *src, char *sep)
if (j > 0)
found = true;
do {
+ if (ign != NULL)
+ ign[k++] = src[i];
i++;
} while (i < len && strchr(sep, src[i]) != NULL);
i--;
@@ -2474,6 +2476,8 @@ char *get_token(char *dst, char *src, char *sep)
i++;
}
dst[j] = '\0';
+ if (ign != NULL)
+ ign[k] = '\0';
return src + i;
}
@@ -2495,12 +2499,12 @@ void render_next(chunk_t *chunks, char *dest)
}
if (c->advance == NULL) {
incr = true;
- c->advance = get_token(c->item, c->text, SEQ_SEP);
+ c->advance = get_token(c->item, NULL, c->text, SEQ_SEP);
} else if (!incr && c->range_cur > c->range_max) {
if (c->advance[0] == '\0') {
- c->advance = get_token(c->item, c->text, SEQ_SEP);
+ c->advance = get_token(c->item, NULL, c->text, SEQ_SEP);
} else {
- c->advance = get_token(c->item, c->advance, SEQ_SEP);
+ c->advance = get_token(c->item, NULL, c->advance, SEQ_SEP);
incr = true;
}
}
@@ -2601,15 +2605,17 @@ bool parse_chain(char *string, chain_t *chain)
{
char chord[MAXLEN] = {0};
char name[MAXLEN] = {0};
+ char ignored[MAXLEN] = {0};
xcb_keysym_t keysym = XCB_NO_SYMBOL;
xcb_button_t button = XCB_NONE;
uint16_t modfield = 0;
uint8_t event_type = XCB_KEY_PRESS;
bool replay_event = false;
+ bool lock_chain = false;
char *outer_advance;
char *inner_advance;
- for (outer_advance = get_token(chord, string, LNK_SEP); chord[0] != '\0'; outer_advance = get_token(chord, outer_advance, LNK_SEP)) {
- for (inner_advance = get_token(name, chord, SYM_SEP); name[0] != '\0'; inner_advance = get_token(name, inner_advance, SYM_SEP)) {
+ for (outer_advance = get_token(chord, ignored, string, LNK_SEP); chord[0] != '\0'; outer_advance = get_token(chord, ignored, outer_advance, LNK_SEP)) {
+ for (inner_advance = get_token(name, NULL, chord, SYM_SEP); name[0] != '\0'; inner_advance = get_token(name, NULL, inner_advance, SYM_SEP)) {
int offset = 0;
if (name[0] == RELEASE_PREFIX) {
event_type = XCB_KEY_RELEASE;
@@ -2627,9 +2633,11 @@ bool parse_chain(char *string, chain_t *chain)
return false;
}
}
+ if (strstr(ignored, GRP_SEP) != NULL)
+ lock_chain = true;
if (button != XCB_NONE)
event_type = key_to_button(event_type);
- chord_t *c = make_chord(keysym, button, modfield, event_type, replay_event);
+ chord_t *c = make_chord(keysym, button, modfield, event_type, replay_event, lock_chain);
add_chord(chain, c);
if (status_fifo != NULL) {
strncpy(c->repr, chord, sizeof(c->repr));
@@ -2640,6 +2648,7 @@ bool parse_chain(char *string, chain_t *chain)
modfield = 0;
event_type = XCB_KEY_PRESS;
replay_event = false;
+ lock_chain = false;
}
return true;
}
diff --git a/parse.h b/parse.h
@@ -5,11 +5,12 @@
#define RELEASE_PREFIX '@'
#define MOTION_PREFIX '!'
-#define REPLAY_PREFIX ':'
+#define REPLAY_PREFIX '~'
#define START_COMMENT '#'
#define MAGIC_INHIBIT '\\'
#define PARTIAL_LINE '\\'
-#define LNK_SEP ";"
+#define GRP_SEP ":"
+#define LNK_SEP ";" GRP_SEP
#define SYM_SEP "+ "
#define SEQ_BEGIN '{'
#define SEQ_END '}'
@@ -35,7 +36,7 @@ void parse_event(xcb_generic_event_t *, uint8_t, xcb_keysym_t *, xcb_button_t *,
void process_hotkey(char *, char *);
void render_next(chunk_t *, char *);
chunk_t *extract_chunks(char *);
-char *get_token(char *, char *, char *);
+char *get_token(char *, char *, char *, char *);
chunk_t *make_chunk(void);
void destroy_chunks(chunk_t *);
bool parse_chain(char *, chain_t *);
diff --git a/sxhkd.c b/sxhkd.c
@@ -83,6 +83,7 @@ int main(int argc, char *argv[])
setup();
get_standard_keysyms();
get_lock_fields();
+ escape_chord = make_chord(ESCAPE_KEYSYM, XCB_NONE, 0, XCB_KEY_PRESS, false, false);
load_config(config_file);
for (int i = 0; i < num_extra_confs; i++)
load_config(extra_confs[i]);
@@ -93,7 +94,7 @@ int main(int argc, char *argv[])
fd_set descriptors;
- reload = bell = chained = false;
+ reload = bell = chained = locked = false;
running = true;
xcb_flush(dpy);
@@ -149,6 +150,7 @@ int main(int argc, char *argv[])
fclose(status_fifo);
ungrab();
cleanup();
+ destroy_chord(escape_chord);
xcb_key_symbols_free(symbols);
xcb_disconnect(dpy);
return EXIT_SUCCESS;
diff --git a/sxhkd.h b/sxhkd.h
@@ -31,7 +31,8 @@ char progress[MAXLEN];
int timeout;
hotkey_t *hotkeys, *hotkeys_tail;
-bool running, reload, bell, chained;
+bool running, reload, bell, chained, locked;
+chord_t *escape_chord;
uint16_t num_lock;
uint16_t caps_lock;
diff --git a/types.c b/types.c
@@ -26,8 +26,12 @@ hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfiel
}
if (replay_event != NULL && c->state->replay_event)
*replay_event = true;
+ if (!locked && c->state->lock_chain) {
+ locked = true;
+ grab_chord(escape_chord);
+ }
if (c->state == c->tail) {
- if (chained)
+ if (chained && !locked)
abort_chain();
return hk;
} else {
@@ -36,24 +40,22 @@ hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfiel
grab_chord(c->state);
}
} else if (chained) {
- if (c->state->event_type == event_type)
- c->state = c->head;
+ if (!locked && c->state->event_type == event_type)
+ c->state = c->head;
else
num_active++;
}
}
if (!chained) {
- if (num_active > 0) {
+ if (num_active > 0)
chained = true;
- if (timeout > 0)
- alarm(timeout);
- }
- } else if (num_active == 0) {
+ } else if (num_active == 0 || (locked && match_chord(escape_chord, event_type, keysym, button, modfield))) {
abort_chain();
return find_hotkey(keysym, button, modfield, event_type, replay_event);
}
-
+ if (chained && timeout > 0)
+ alarm(timeout);
PRINTF("num active %i\n", num_active);
return NULL;
@@ -66,7 +68,7 @@ bool match_chord(chord_t *chord, uint8_t event_type, xcb_keysym_t keysym, xcb_bu
return false;
}
-chord_t *make_chord(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool replay_event)
+chord_t *make_chord(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool replay_event, bool lock_chain)
{
chord_t *chord;
if (button == XCB_NONE) {
@@ -96,6 +98,7 @@ chord_t *make_chord(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield,
chord->next = chord->more = NULL;
chord->event_type = event_type;
chord->replay_event = replay_event;
+ chord->lock_chain = lock_chain;
if (prev != NULL)
prev->more = chord;
else
@@ -115,6 +118,7 @@ chord_t *make_chord(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield,
chord->modfield = modfield;
chord->event_type = event_type;
chord->replay_event = replay_event;
+ chord->lock_chain = lock_chain;
chord->next = chord->more = NULL;
PRINTF("button chord %u %u\n", button, modfield);
}
@@ -163,6 +167,7 @@ void abort_chain(void)
for (hotkey_t *hk = hotkeys; hk != NULL; hk = hk->next)
hk->chain->state = hk->chain->head;
chained = false;
+ locked = false;
if (timeout > 0)
alarm(0);
ungrab();
@@ -174,13 +179,18 @@ void destroy_chain(chain_t *chain)
chord_t *c = chain->head;
while (c != NULL) {
chord_t *n = c->next;
- chord_t *cc = c->more;
- while (cc != NULL) {
- chord_t *nn = cc->more;
- free(cc);
- cc = nn;
- }
+ destroy_chord(c);
+ c = n;
+ }
+}
+
+void destroy_chord(chord_t *chord)
+{
+ chord_t *c = chord->more;
+ while (c != NULL) {
+ chord_t *n = c->more;
free(c);
c = n;
}
+ free(chord);
}
diff --git a/types.h b/types.h
@@ -7,6 +7,7 @@
#define KEYSYMS_PER_KEYCODE 4
#define MOD_STATE_FIELD 255
+#define ESCAPE_KEYSYM 0xff1b
typedef struct chord_t chord_t;
struct chord_t {
@@ -16,6 +17,7 @@ struct chord_t {
uint16_t modfield;
uint8_t event_type;
bool replay_event;
+ bool lock_chain;
chord_t *next;
chord_t *more;
};
@@ -41,7 +43,7 @@ typedef struct {
xcb_keysym_t Alt_L, Alt_R, Super_L, Super_R, Hyper_L, Hyper_R,
Meta_L, Meta_R, Mode_switch, Num_Lock, Scroll_Lock;
-chord_t *make_chord(xcb_keysym_t, xcb_button_t, uint16_t, uint8_t, bool);
+chord_t *make_chord(xcb_keysym_t, xcb_button_t, uint16_t, uint8_t, bool, bool);
chain_t *make_chain(void);
void add_chord(chain_t *, chord_t *);
bool match_chord(chord_t *, uint8_t, xcb_keysym_t, xcb_button_t, uint16_t);
@@ -50,5 +52,6 @@ hotkey_t *make_hotkey(chain_t *, char *);
void add_hotkey(hotkey_t *);
void abort_chain(void);
void destroy_chain(chain_t *);
+void destroy_chord(chord_t *);
#endif