dwm-keymodes-20220422.diff (11577B)
1 diff --git a/config.def.h b/config.def.h 2 index a2ac963..3bde49d 100644 3 --- a/config.def.h 4 +++ b/config.def.h 5 @@ -47,10 +47,10 @@ static const Layout layouts[] = { 6 /* key definitions */ 7 #define MODKEY Mod1Mask 8 #define TAGKEYS(KEY,TAG) \ 9 - { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ 10 - { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ 11 - { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ 12 - { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, 13 + { {0,0,0,0}, {KEY,0,0,0}, view, {.ui = 1 << TAG} }, \ 14 + { {ControlMask,0,0,0}, {KEY,0,0,0}, toggleview, {.ui = 1 << TAG} }, \ 15 + { {ShiftMask,0,0,0}, {KEY,0,0,0}, tag, {.ui = 1 << TAG} }, \ 16 + { {ControlMask|ShiftMask,0,0,0}, {KEY,0,0,0}, toggletag, {.ui = 1 << TAG} }, 17 18 /* helper for spawning shell commands in the pre dwm-5.0 fashion */ 19 #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } 20 @@ -62,39 +62,50 @@ static const char *termcmd[] = { "st", NULL }; 21 22 static Key keys[] = { 23 /* modifier key function argument */ 24 - { MODKEY, XK_p, spawn, {.v = dmenucmd } }, 25 - { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, 26 - { MODKEY, XK_b, togglebar, {0} }, 27 - { MODKEY, XK_j, focusstack, {.i = +1 } }, 28 - { MODKEY, XK_k, focusstack, {.i = -1 } }, 29 - { MODKEY, XK_i, incnmaster, {.i = +1 } }, 30 - { MODKEY, XK_d, incnmaster, {.i = -1 } }, 31 - { MODKEY, XK_h, setmfact, {.f = -0.05} }, 32 - { MODKEY, XK_l, setmfact, {.f = +0.05} }, 33 - { MODKEY, XK_Return, zoom, {0} }, 34 - { MODKEY, XK_Tab, view, {0} }, 35 - { MODKEY|ShiftMask, XK_c, killclient, {0} }, 36 - { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, 37 - { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, 38 - { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, 39 - { MODKEY, XK_space, setlayout, {0} }, 40 - { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, 41 - { MODKEY, XK_0, view, {.ui = ~0 } }, 42 - { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, 43 - { MODKEY, XK_comma, focusmon, {.i = -1 } }, 44 - { MODKEY, XK_period, focusmon, {.i = +1 } }, 45 - { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, 46 - { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, 47 - TAGKEYS( XK_1, 0) 48 - TAGKEYS( XK_2, 1) 49 - TAGKEYS( XK_3, 2) 50 - TAGKEYS( XK_4, 3) 51 - TAGKEYS( XK_5, 4) 52 - TAGKEYS( XK_6, 5) 53 - TAGKEYS( XK_7, 6) 54 - TAGKEYS( XK_8, 7) 55 - TAGKEYS( XK_9, 8) 56 - { MODKEY|ShiftMask, XK_q, quit, {0} }, 57 + { MODKEY, XK_Escape, setkeymode, {.ui = ModeCommand} }, 58 +}; 59 + 60 +static Key cmdkeys[] = { 61 + /* modifier keys function argument */ 62 + { 0, XK_Escape, clearcmd, {0} }, 63 + { ControlMask, XK_g, clearcmd, {0} }, 64 + { 0, XK_i, setkeymode, {.ui = ModeInsert} }, 65 +}; 66 +static Command commands[] = { 67 + /* modifier (4 keys) keysyms (4 keys) function argument */ 68 + { {0, 0, 0, 0}, { XK_p, 0, 0, 0}, spawn, {.v = dmenucmd } }, 69 + { {ShiftMask, 0, 0, 0}, { XK_Return, 0, 0, 0}, spawn, {.v = termcmd } }, 70 + { {0, 0, 0, 0}, { XK_b, 0, 0, 0}, togglebar, {0} }, 71 + { {0, 0, 0, 0}, { XK_j, 0, 0, 0}, focusstack, {.i = +1 } }, 72 + { {0, 0, 0, 0}, { XK_k, 0, 0, 0}, focusstack, {.i = -1 } }, 73 + { {0, 0, 0, 0}, { XK_i, 0, 0, 0}, incnmaster, {.i = +1 } }, 74 + { {0, 0, 0, 0}, { XK_d, 0, 0, 0}, incnmaster, {.i = -1 } }, 75 + { {0, 0, 0, 0}, { XK_h, 0, 0, 0}, setmfact, {.f = -0.05} }, 76 + { {0, 0, 0, 0}, { XK_l, 0, 0, 0}, setmfact, {.f = +0.05} }, 77 + { {0, 0, 0, 0}, { XK_Return, 0, 0, 0}, zoom, {0} }, 78 + { {ControlMask, 0, 0, 0}, { XK_i, 0, 0, 0}, view, {0} }, 79 + { {ShiftMask, 0, 0, 0}, { XK_k, 0, 0, 0}, killclient, {0} }, 80 + { {0, 0, 0, 0}, { XK_t, 0, 0, 0}, setlayout, {.v = &layouts[0]} }, 81 + { {0, 0, 0, 0}, { XK_f, 0, 0, 0}, setlayout, {.v = &layouts[1]} }, 82 + { {0, 0, 0, 0}, { XK_m, 0, 0, 0}, setlayout, {.v = &layouts[2]} }, 83 + { {0, 0, 0, 0}, { XK_space, 0, 0, 0}, setlayout, {0} }, 84 + { {ShiftMask, 0, 0, 0}, { XK_space, 0, 0, 0}, togglefloating, {0} }, 85 + { {0, 0, 0, 0}, { XK_0, 0, 0, 0}, view, {.ui = ~0 } }, 86 + { {ShiftMask, 0, 0, 0}, { XK_0, 0, 0, 0}, tag, {.ui = ~0 } }, 87 + { {0, 0, 0, 0}, { XK_comma, 0, 0, 0}, focusmon, {.i = -1 } }, 88 + { {0, 0, 0, 0}, { XK_period, 0, 0, 0}, focusmon, {.i = +1 } }, 89 + { {ShiftMask, 0, 0, 0}, { XK_comma, 0, 0, 0}, tagmon, {.i = -1 } }, 90 + { {ShiftMask, 0, 0, 0}, { XK_period, 0, 0, 0}, tagmon, {.i = +1 } }, 91 + TAGKEYS(XK_1, 0) 92 + TAGKEYS(XK_2, 1) 93 + TAGKEYS(XK_3, 2) 94 + TAGKEYS(XK_4, 3) 95 + TAGKEYS(XK_5, 4) 96 + TAGKEYS(XK_6, 5) 97 + TAGKEYS(XK_7, 6) 98 + TAGKEYS(XK_8, 7) 99 + TAGKEYS(XK_9, 8) 100 + { {ShiftMask, 0, 0, 0}, { XK_q, 0, 0, 0}, quit, {0} }, 101 }; 102 103 /* button definitions */ 104 @@ -113,4 +124,3 @@ static Button buttons[] = { 105 { ClkTagBar, MODKEY, Button1, tag, {0} }, 106 { ClkTagBar, MODKEY, Button3, toggletag, {0} }, 107 }; 108 - 109 diff --git a/dwm.c b/dwm.c 110 index 0fc328a..487484e 100644 111 --- a/dwm.c 112 +++ b/dwm.c 113 @@ -60,6 +60,7 @@ 114 /* enums */ 115 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ 116 enum { SchemeNorm, SchemeSel }; /* color schemes */ 117 +enum { ModeCommand, ModeInsert }; 118 enum { NetSupported, NetWMName, NetWMState, NetWMCheck, 119 NetWMFullscreen, NetActiveWindow, NetWMWindowType, 120 NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ 121 @@ -99,6 +100,13 @@ struct Client { 122 Window win; 123 }; 124 125 +typedef struct { 126 + unsigned int mod[4]; 127 + KeySym keysym[4]; 128 + void (*func)(const Arg *); 129 + const Arg arg; 130 +} Command; 131 + 132 typedef struct { 133 unsigned int mod; 134 KeySym keysym; 135 @@ -152,6 +160,7 @@ static void buttonpress(XEvent *e); 136 static void checkotherwm(void); 137 static void cleanup(void); 138 static void cleanupmon(Monitor *mon); 139 +static void clearcmd(const Arg *arg); 140 static void clientmessage(XEvent *e); 141 static void configure(Client *c); 142 static void configurenotify(XEvent *e); 143 @@ -177,6 +186,7 @@ static void grabbuttons(Client *c, int focused); 144 static void grabkeys(void); 145 static void incnmaster(const Arg *arg); 146 static void keypress(XEvent *e); 147 +static void keypresscmd(XEvent *e); 148 static void killclient(const Arg *arg); 149 static void manage(Window w, XWindowAttributes *wa); 150 static void mappingnotify(XEvent *e); 151 @@ -200,6 +210,8 @@ static void sendmon(Client *c, Monitor *m); 152 static void setclientstate(Client *c, long state); 153 static void setfocus(Client *c); 154 static void setfullscreen(Client *c, int fullscreen); 155 +static void setinsertmode(void); 156 +static void setkeymode(const Arg *arg); 157 static void setlayout(const Arg *arg); 158 static void setmfact(const Arg *arg); 159 static void setup(void); 160 @@ -243,6 +255,8 @@ static int sw, sh; /* X display screen geometry width, height */ 161 static int bh, blw = 0; /* bar geometry */ 162 static int lrpad; /* sum of left and right padding for text */ 163 static int (*xerrorxlib)(Display *, XErrorEvent *); 164 +static unsigned int cmdmod[4]; 165 +static unsigned int keymode = ModeCommand; 166 static unsigned int numlockmask = 0; 167 static void (*handler[LASTEvent]) (XEvent *) = { 168 [ButtonPress] = buttonpress, 169 @@ -266,6 +280,7 @@ static Cur *cursor[CurLast]; 170 static Clr **scheme; 171 static Display *dpy; 172 static Drw *drw; 173 +static KeySym cmdkeysym[4]; 174 static Monitor *mons, *selmon; 175 static Window root, wmcheckwin; 176 177 @@ -513,6 +528,17 @@ cleanupmon(Monitor *mon) 178 free(mon); 179 } 180 181 +void 182 +clearcmd(const Arg *arg) 183 +{ 184 + unsigned int i; 185 + 186 + for (i = 0; i < LENGTH(cmdkeysym); i++) { 187 + cmdkeysym[i] = 0; 188 + cmdmod[i] = 0; 189 + } 190 +} 191 + 192 void 193 clientmessage(XEvent *e) 194 { 195 @@ -955,6 +981,13 @@ grabbuttons(Client *c, int focused) 196 void 197 grabkeys(void) 198 { 199 + if (keymode == ModeCommand) { 200 + XUngrabKey(dpy, AnyKey, AnyModifier, root); 201 + XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime); 202 + return; 203 + } 204 + 205 + XUngrabKeyboard(dpy, CurrentTime); 206 updatenumlockmask(); 207 { 208 unsigned int i, j; 209 @@ -996,6 +1029,11 @@ keypress(XEvent *e) 210 KeySym keysym; 211 XKeyEvent *ev; 212 213 + if (keymode == ModeCommand) { 214 + keypresscmd(e); 215 + return; 216 + } 217 + 218 ev = &e->xkey; 219 keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); 220 for (i = 0; i < LENGTH(keys); i++) 221 @@ -1005,6 +1043,53 @@ keypress(XEvent *e) 222 keys[i].func(&(keys[i].arg)); 223 } 224 225 +void 226 +keypresscmd(XEvent *e) { 227 + unsigned int i, j; 228 + int matches = 0; 229 + KeySym keysym; 230 + XKeyEvent *ev; 231 + 232 + ev = &e->xkey; 233 + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); 234 + if (XK_Shift_L <= keysym && keysym <= XK_Hyper_R) { 235 + return; 236 + } 237 + 238 + for (i = 0; i < LENGTH(cmdkeys); i++) { 239 + if (keysym == cmdkeys[i].keysym 240 + && CLEANMASK(cmdkeys[i].mod) == CLEANMASK(ev->state) 241 + && cmdkeys[i].func) { 242 + cmdkeys[i].func(&(cmdkeys[i].arg)); 243 + return; 244 + } 245 + } 246 + 247 + for (j = 0; j < LENGTH(cmdkeysym); j++) { 248 + if (cmdkeysym[j] == 0) { 249 + cmdkeysym[j] = keysym; 250 + cmdmod[j] = ev->state; 251 + break; 252 + } 253 + } 254 + 255 + for (i = 0; i < LENGTH(commands); i++) { 256 + matches = 0; 257 + for (j = 0; j < LENGTH(cmdkeysym); j++) { 258 + if (cmdkeysym[j] == commands[i].keysym[j] 259 + && CLEANMASK(cmdmod[j]) == CLEANMASK(commands[i].mod[j])) 260 + matches++; 261 + } 262 + if (matches == LENGTH(cmdkeysym)) { 263 + if (commands[i].func) 264 + commands[i].func(&(commands[i].arg)); 265 + clearcmd(NULL); 266 + return; 267 + } 268 + } 269 +} 270 + 271 + 272 void 273 killclient(const Arg *arg) 274 { 275 @@ -1438,6 +1523,24 @@ setclientstate(Client *c, long state) 276 PropModeReplace, (unsigned char *)data, 2); 277 } 278 279 +void 280 +setinsertmode() 281 +{ 282 + keymode = ModeInsert; 283 + clearcmd(NULL); 284 + grabkeys(); 285 +} 286 + 287 +void 288 +setkeymode(const Arg *arg) 289 +{ 290 + if(!arg) 291 + return; 292 + keymode = arg->ui; 293 + clearcmd(NULL); 294 + grabkeys(); 295 +} 296 + 297 int 298 sendevent(Client *c, Atom proto) 299 { 300 @@ -1645,6 +1748,7 @@ sigchld(int unused) 301 void 302 spawn(const Arg *arg) 303 { 304 + setinsertmode(); 305 if (arg->v == dmenucmd) 306 dmenumon[0] = '0' + selmon->num; 307 if (fork() == 0) {