dwm-keymodes-20220422.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       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) {