mirror of
https://github.com/gryf/wmaker.git
synced 2026-03-20 18:33:31 +01:00
WPrefs: improve capture_shortcut function
This patch is improving the capture_shortcut function to be able to capture a sequence of multiple key pressed.
This commit is contained in:
committed by
Carlos R. Mafra
parent
ec115fedf7
commit
0aeba6064b
@@ -23,6 +23,8 @@
|
||||
|
||||
#include "WPrefs.h"
|
||||
#include <ctype.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/XKBlib.h>
|
||||
@@ -307,14 +309,53 @@ static int NumLockMask(Display *dpy)
|
||||
return mask;
|
||||
}
|
||||
|
||||
/* Append the modifier prefix and key name to the keybuf */
|
||||
static void build_key_combo(unsigned int xkstate, const char *keyname,
|
||||
unsigned int numlock_mask, char keybuf[64])
|
||||
{
|
||||
if (xkstate & ControlMask)
|
||||
strcat(keybuf, "Control+");
|
||||
if (xkstate & ShiftMask)
|
||||
strcat(keybuf, "Shift+");
|
||||
if ((numlock_mask != Mod1Mask) && (xkstate & Mod1Mask))
|
||||
strcat(keybuf, "Mod1+");
|
||||
if ((numlock_mask != Mod2Mask) && (xkstate & Mod2Mask))
|
||||
strcat(keybuf, "Mod2+");
|
||||
if ((numlock_mask != Mod3Mask) && (xkstate & Mod3Mask))
|
||||
strcat(keybuf, "Mod3+");
|
||||
if ((numlock_mask != Mod4Mask) && (xkstate & Mod4Mask))
|
||||
strcat(keybuf, "Mod4+");
|
||||
if ((numlock_mask != Mod5Mask) && (xkstate & Mod5Mask))
|
||||
strcat(keybuf, "Mod5+");
|
||||
wstrlcat(keybuf, keyname, 64);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interactively capture a key shortcut or keychain,
|
||||
* function waits KeychainTimeoutDelay or 300 ms after
|
||||
* each key press for another key in the chain,
|
||||
* and returns the full key specification string.
|
||||
*/
|
||||
char *capture_shortcut(Display *dpy, Bool *capturing, Bool convert_case)
|
||||
{
|
||||
XEvent ev;
|
||||
KeySym ksym, lksym, uksym;
|
||||
char buffer[64];
|
||||
char *key = NULL;
|
||||
/* Large enough for several chained chords */
|
||||
char buffer[512];
|
||||
char keybuf[64];
|
||||
char *key;
|
||||
unsigned int numlock_mask;
|
||||
Bool have_key = False;
|
||||
Bool chain_mode;
|
||||
int timeout_ms;
|
||||
|
||||
timeout_ms = GetIntegerForKey("KeychainTimeoutDelay");
|
||||
if (timeout_ms <= 0)
|
||||
timeout_ms = 300;
|
||||
|
||||
buffer[0] = '\0';
|
||||
|
||||
/* ---- Phase 1: capture the first key (blocking) ---- */
|
||||
while (*capturing) {
|
||||
XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
|
||||
WMNextEvent(dpy, &ev);
|
||||
@@ -332,41 +373,62 @@ char *capture_shortcut(Display *dpy, Bool *capturing, Bool convert_case)
|
||||
key = XKeysymToString(ksym);
|
||||
}
|
||||
|
||||
*capturing = 0;
|
||||
keybuf[0] = '\0';
|
||||
build_key_combo(ev.xkey.state, key, numlock_mask, keybuf);
|
||||
wstrlcat(buffer, keybuf, sizeof(buffer));
|
||||
have_key = True;
|
||||
break;
|
||||
}
|
||||
}
|
||||
WMHandleEvent(&ev);
|
||||
}
|
||||
|
||||
if (!key)
|
||||
/* ---- Phase 2: collect additional chain keys with timeout ---- */
|
||||
chain_mode = (timeout_ms > 0);
|
||||
while (*capturing && chain_mode) {
|
||||
int xfd = ConnectionNumber(dpy);
|
||||
fd_set rfds;
|
||||
struct timeval tv;
|
||||
|
||||
if (!XPending(dpy)) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(xfd, &rfds);
|
||||
tv.tv_sec = timeout_ms / 1000;
|
||||
tv.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
XFlush(dpy);
|
||||
if (select(xfd + 1, &rfds, NULL, NULL, &tv) == 0)
|
||||
break; /* timeout: the chain is complete */
|
||||
}
|
||||
|
||||
XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
|
||||
WMNextEvent(dpy, &ev);
|
||||
if (ev.type == KeyPress && ev.xkey.keycode != 0) {
|
||||
numlock_mask = NumLockMask(dpy);
|
||||
ksym = W_KeycodeToKeysym(dpy, ev.xkey.keycode,
|
||||
ev.xkey.state & numlock_mask ? 1 : 0);
|
||||
|
||||
if (!IsModifierKey(ksym)) {
|
||||
if (convert_case) {
|
||||
XConvertCase(ksym, &lksym, &uksym);
|
||||
key = XKeysymToString(uksym);
|
||||
} else {
|
||||
key = XKeysymToString(ksym);
|
||||
}
|
||||
|
||||
keybuf[0] = '\0';
|
||||
build_key_combo(ev.xkey.state, key, numlock_mask, keybuf);
|
||||
wstrlcat(buffer, " ", sizeof(buffer));
|
||||
wstrlcat(buffer, keybuf, sizeof(buffer));
|
||||
}
|
||||
} else {
|
||||
WMHandleEvent(&ev);
|
||||
}
|
||||
}
|
||||
|
||||
if (!have_key || !*capturing)
|
||||
return NULL;
|
||||
|
||||
buffer[0] = 0;
|
||||
|
||||
if (ev.xkey.state & ControlMask)
|
||||
strcat(buffer, "Control+");
|
||||
|
||||
if (ev.xkey.state & ShiftMask)
|
||||
strcat(buffer, "Shift+");
|
||||
|
||||
if ((numlock_mask != Mod1Mask) && (ev.xkey.state & Mod1Mask))
|
||||
strcat(buffer, "Mod1+");
|
||||
|
||||
if ((numlock_mask != Mod2Mask) && (ev.xkey.state & Mod2Mask))
|
||||
strcat(buffer, "Mod2+");
|
||||
|
||||
if ((numlock_mask != Mod3Mask) && (ev.xkey.state & Mod3Mask))
|
||||
strcat(buffer, "Mod3+");
|
||||
|
||||
if ((numlock_mask != Mod4Mask) && (ev.xkey.state & Mod4Mask))
|
||||
strcat(buffer, "Mod4+");
|
||||
|
||||
if ((numlock_mask != Mod5Mask) && (ev.xkey.state & Mod5Mask))
|
||||
strcat(buffer, "Mod5+");
|
||||
|
||||
wstrlcat(buffer, key, sizeof(buffer));
|
||||
|
||||
*capturing = 0;
|
||||
return wstrdup(buffer);
|
||||
}
|
||||
|
||||
@@ -444,7 +506,7 @@ static void captureClick(WMWidget * w, void *data)
|
||||
}
|
||||
panel->capturing = 0;
|
||||
WMSetButtonText(w, _("Capture"));
|
||||
WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key."));
|
||||
WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key(s)."));
|
||||
XUngrabKeyboard(dpy, CurrentTime);
|
||||
}
|
||||
|
||||
@@ -456,6 +518,9 @@ static void clearShortcut(WMWidget * w, void *data)
|
||||
/* Parameter not used, but tell the compiler that it is ok */
|
||||
(void) w;
|
||||
|
||||
/* Cancel any ongoing capture so the keychain loop is unblocked */
|
||||
panel->capturing = 0;
|
||||
|
||||
WMSetTextFieldText(panel->shoT, NULL);
|
||||
|
||||
if (row >= 0) {
|
||||
|
||||
Reference in New Issue
Block a user