commit c475067241bf82746853c687c42fd53f5dda74d7
parent 0cc2a3cccb8eeaed517260618e38059404af1237
Author: Miles Alan <m@milesalan.com>
Date: Sat, 7 Mar 2020 10:30:15 -0600
Add multikey patch
Diffstat:
| M | Makefile | | | 2 | +- |
| M | config.def.h | | | 88 | ++++++++++++++++++++++++++++++++++++++++++++----------------------------------- |
| M | dwm.c | | | 106 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
3 files changed, 154 insertions(+), 42 deletions(-)
diff --git a/Makefile b/Makefile
@@ -23,7 +23,7 @@ config.h:
cp config.def.h $@
dwm: ${OBJ}
- ${CC} -o $@ ${OBJ} ${LDFLAGS}
+ ${CC} -lrt -o $@ ${OBJ} ${LDFLAGS}
clean:
rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
diff --git a/config.def.h b/config.def.h
@@ -34,23 +34,23 @@ static const Rule rules[] = {
/* layout(s) */
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
static const int nmaster = 1; /* number of clients in master area */
-static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
+static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */
static const Layout layouts[] = {
/* symbol arrange function */
{ "[]=", tile }, /* first entry is default */
- { "><>", NULL }, /* no layout function means floating behavior */
- { "[M]", monocle },
+ { "|_|", bstack },
+ { "[ ]", monocle },
{ NULL, NULL },
};
/* key definitions */
#define MODKEY Mod1Mask
#define TAGKEYS(KEY,TAG) \
- { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
- { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
- { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
- { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
+ {0, MODKEY, KEY, view, {.ui = 1 << TAG} }, \
+ {0, MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
+ {0, MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
+ {0, MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
@@ -59,44 +59,54 @@ static const Layout layouts[] = {
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *termcmd[] = { "st", NULL };
+static const char *surfcmd[] = { "surf", NULL };
+#include <X11/XF86keysym.h>
static Key keys[] = {
- /* modifier key function argument */
- { MODKEY, XK_p, spawn, {.v = dmenucmd } },
- { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
- { MODKEY, XK_b, togglebar, {0} },
- { MODKEY, XK_j, focusstack, {.i = +1 } },
- { MODKEY, XK_k, focusstack, {.i = -1 } },
- { MODKEY, XK_i, incnmaster, {.i = +1 } },
- { MODKEY, XK_d, incnmaster, {.i = -1 } },
- { MODKEY, XK_h, setmfact, {.f = -0.05} },
- { MODKEY, XK_l, setmfact, {.f = +0.05} },
- { MODKEY, XK_Return, zoom, {0} },
- { MODKEY, XK_Tab, view, {0} },
- { MODKEY|ShiftMask, XK_c, killclient, {0} },
- { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
- { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
- { MODKEY|ControlMask, XK_comma, cyclelayout, {.i = -1 } },
- { MODKEY|ControlMask, XK_period, cyclelayout, {.i = +1 } },
- { MODKEY, XK_space, setlayout, {0} },
- { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
- { MODKEY, XK_0, view, {.ui = ~0 } },
- { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
- { MODKEY, XK_comma, focusmon, {.i = -1 } },
- { MODKEY, XK_period, focusmon, {.i = +1 } },
- { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
- { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
+
+ {1, 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("dmo_appmenu.sh") },
+ {2, 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("dmo_appmenu.sh sys") },
+
+ {1, 0, XF86XK_AudioLowerVolume, cyclelayout , {.i = +1 } },
+ {2, 0, XF86XK_AudioLowerVolume, zoom, {0} },
+ {3, 0, XF86XK_AudioLowerVolume, killclient, {0} },
+
+ {1, 0, XF86XK_PowerOff, spawn, SHCMD("svkbd-layered-toggle") },
+ {2, 0, XF86XK_PowerOff, spawn, { .v = termcmd } },
+ {3, 0, XF86XK_PowerOff, spawn, { .v = surfcmd } }
+
+ /*
+ {0, MODKEY, XK_p, spawn, {.v = dmenucmd } },
+ {0, MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
+ {0, MODKEY, XK_b, togglebar, {0} },
+ {0, MODKEY, XK_j, focusstack, {.i = +1 } },
+ {0, MODKEY, XK_k, focusstack, {.i = -1 } },
+ {0, MODKEY, XK_i, incnmaster, {.i = +1 } },
+ {0, MODKEY, XK_d, incnmaster, {.i = -1 } },
+ {0, MODKEY, XK_h, setmfact, {.f = -0.05} },
+ {0, MODKEY, XK_l, setmfact, {.f = +0.05} },
+ {0, MODKEY, XK_Return, zoom, {0} },
+ {0, MODKEY, XK_Tab, view, {0} },
+ {0, MODKEY|ShiftMask, XK_c, killclient, {0} },
+ {0, MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
+ {0, MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
+ {0, MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
+ {0, MODKEY|ControlMask, XK_comma, cyclelayout, {.i = -1 } },
+ {0, MODKEY|ControlMask, XK_period, cyclelayout, {.i = +1 } },
+ {0, MODKEY, XK_space, setlayout, {0} },
+ {0, MODKEY|ShiftMask, XK_space, togglefloating, {0} },
+ {0, MODKEY, XK_0, view, {.ui = ~0 } },
+ {0, MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
+ {0, MODKEY, XK_comma, focusmon, {.i = -1 } },
+ {0, MODKEY, XK_period, focusmon, {.i = +1 } },
+ {0, MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
+ {0, MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1)
TAGKEYS( XK_3, 2)
TAGKEYS( XK_4, 3)
- TAGKEYS( XK_5, 4)
- TAGKEYS( XK_6, 5)
- TAGKEYS( XK_7, 6)
- TAGKEYS( XK_8, 7)
- TAGKEYS( XK_9, 8)
- { MODKEY|ShiftMask, XK_q, quit, {0} },
+ {0, MODKEY|ShiftMask, XK_q, quit, {0} },
+ */
};
/* button definitions */
diff --git a/dwm.c b/dwm.c
@@ -20,6 +20,7 @@
*
* To understand everything else, start reading main().
*/
+#include <time.h>
#include <errno.h>
#include <locale.h>
#include <signal.h>
@@ -100,6 +101,7 @@ struct Client {
};
typedef struct {
+ unsigned int npresses;
unsigned int mod;
KeySym keysym;
void (*func)(const Arg *);
@@ -177,6 +179,7 @@ static void grabbuttons(Client *c, int focused);
static void grabkeys(void);
static void incnmaster(const Arg *arg);
static void keypress(XEvent *e);
+static void keyrelease(XEvent *e);
static void killclient(const Arg *arg);
static void manage(Window w, XWindowAttributes *wa);
static void mappingnotify(XEvent *e);
@@ -256,12 +259,14 @@ static void (*handler[LASTEvent]) (XEvent *) = {
[Expose] = expose,
[FocusIn] = focusin,
[KeyPress] = keypress,
+ [KeyRelease] = keyrelease,
[MappingNotify] = mappingnotify,
[MapRequest] = maprequest,
[MotionNotify] = motionnotify,
[PropertyNotify] = propertynotify,
[UnmapNotify] = unmapnotify
};
+static Atom timeratom;
static Atom wmatom[WMLast], netatom[NetLast];
static int running = 1;
static Cur *cursor[CurLast];
@@ -271,6 +276,12 @@ static Drw *drw;
static Monitor *mons, *selmon;
static Window root, wmcheckwin;
+#define KEYPRESS_MS_THRESHOLD 200
+#define KEYHOLD_MS_THRESHOLD 700
+static KeySym lastkeysym = NULL;
+static unsigned int lastkeypresses = 0;
+static unsigned int lastkeyreleased = 0;
+
/* configuration, allows nested code to access above variables */
#include "config.h"
@@ -518,6 +529,7 @@ clientmessage(XEvent *e)
XClientMessageEvent *cme = &e->xclient;
Client *c = wintoclient(cme->window);
+ if (cme->message_type == timeratom) { keypresstimerdonesync(cme->data.s[0]); return; }
if (!c)
return;
if (cme->message_type == netatom[NetWMState]) {
@@ -1002,6 +1014,71 @@ isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
}
#endif /* XINERAMA */
+
+void keypresstimerdonesync(int keyindex) {
+ int i;
+ Key * maxkeypresskey = NULL;
+
+ if (
+ keyindex < 0 &&
+ keys[-1 * keyindex].keysym == lastkeysym &&
+ keys[-1 * keyindex].npresses == lastkeypresses
+ ) {
+ // Key hold - find keybinding w/ max npresses and run that fn
+ for (i = 0; i < LENGTH(keys); i++) {
+ if (
+ keys[-1 * keyindex].keysym == keys[i].keysym &&
+ (maxkeypresskey == NULL || keys[i].npresses > maxkeypresskey->npresses)
+ ) {
+ maxkeypresskey = &keys[i];
+ }
+ }
+ lastkeysym = NULL;
+ if (maxkeypresskey && maxkeypresskey->func) maxkeypresskey->func(&(maxkeypresskey->arg));
+ } else if (
+ // Key press
+ keys[keyindex].keysym == lastkeysym &&
+ keys[keyindex].npresses == lastkeypresses
+ ) {
+ if (lastkeyreleased) {
+ lastkeysym = NULL;
+ if (keys[keyindex].func) keys[keyindex].func(&(keys[keyindex].arg));
+ } else {
+ keypresstimerdispatch(KEYHOLD_MS_THRESHOLD - KEYPRESS_MS_THRESHOLD, -1 * keyindex);
+ }
+ }
+}
+
+void keypresstimerdone(union sigval timer_data)
+{
+ XEvent ev;
+ memset(&ev, 0, sizeof ev);
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = root;
+ ev.xclient.message_type = timeratom;
+ ev.xclient.format = 16;
+ ev.xclient.data.s[0] = ((short) timer_data.sival_int);
+ XSendEvent(dpy, root, False, SubstructureRedirectMask, &ev);
+ XSync(dpy, False);
+}
+
+void keypresstimerdispatch(int msduration, int data)
+{
+ struct sigevent timer_signal_event;
+ timer_t timer;
+ struct itimerspec timer_period;
+ timer_signal_event.sigev_notify = SIGEV_THREAD;
+ timer_signal_event.sigev_notify_function = keypresstimerdone;
+ timer_signal_event.sigev_value.sival_int = data;
+ timer_signal_event.sigev_notify_attributes = NULL;
+ timer_create(CLOCK_MONOTONIC, &timer_signal_event, &timer);
+ timer_period.it_value.tv_sec = 0;
+ timer_period.it_value.tv_nsec = msduration * 1000000;
+ timer_period.it_interval.tv_sec = 0;
+ timer_period.it_interval.tv_nsec = 0;
+ timer_settime(timer, 0, &timer_period, NULL);
+}
+
void
keypress(XEvent *e)
{
@@ -1014,8 +1091,31 @@ keypress(XEvent *e)
for (i = 0; i < LENGTH(keys); i++)
if (keysym == keys[i].keysym
&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
- && keys[i].func)
- keys[i].func(&(keys[i].arg));
+ && keys[i].func) {
+ // E.g. normal functionality case - npresses 0
+ if (keys[i].npresses == 0) { keys[i].func(&(keys[i].arg)); continue; }
+
+ if (lastkeysym != keys[i].keysym) {
+ lastkeysym = keys[i].keysym;
+ lastkeypresses = 0;
+ }
+ if (lastkeypresses + 1 == keys[i].npresses) {
+ lastkeypresses++;
+ lastkeyreleased = 0;
+ keypresstimerdispatch(KEYPRESS_MS_THRESHOLD, i);
+ break;
+ }
+ }
+}
+
+void
+keyrelease(XEvent *e)
+{
+ KeySym keysym;
+ XKeyEvent *ev;
+ ev = &e->xkey;
+ keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
+ if (lastkeysym == keysym) { lastkeyreleased = 1; }
}
void
@@ -1569,6 +1669,7 @@ setup(void)
updategeom();
/* init atoms */
utf8string = XInternAtom(dpy, "UTF8_STRING", False);
+ timeratom = XInternAtom(dpy, "TIMER", False);
wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
@@ -2147,6 +2248,7 @@ zoom(const Arg *arg)
int
main(int argc, char *argv[])
{
+ XInitThreads();
if (argc == 2 && !strcmp("-v", argv[1]))
die("dwm-"VERSION);
else if (argc != 1)