changeset 6:0968b3739b8d

apply keymodes patch
author paulo@thepaulopc
date Sun, 12 Jun 2011 14:32:54 -0700
parents e060ab82b136
children 162accc5d36d
files client.c config.h draw.c dwm.h event.c main.c util.c
diffstat 7 files changed, 240 insertions(+), 74 deletions(-) [+]
line diff
     1.1 --- a/client.c	Wed Jan 27 23:28:29 2010 -0800
     1.2 +++ b/client.c	Sun Jun 12 14:32:54 2011 -0700
     1.3 @@ -426,6 +426,11 @@
     1.4  	lt->arrange();
     1.5  }
     1.6  
     1.7 +void
     1.8 +zoom_insert(Arg *arg) {
     1.9 +	func_insert(zoom, arg);
    1.10 +}
    1.11 +
    1.12  Client *
    1.13  prevtiled(Client *c) {
    1.14  	for(; c && (c->isversatile || !isvisible(c)); c = c->prev);
     2.1 --- a/config.h	Wed Jan 27 23:28:29 2010 -0800
     2.2 +++ b/config.h	Sun Jun 12 14:32:54 2011 -0700
     2.3 @@ -46,79 +46,15 @@
     2.4  #define MASTER			650		/* per thousand */
     2.5  #define NMASTER			1		/* clients in master area */
     2.6  
     2.7 +#define COMMANDMODE             1
     2.8 +#define INSERTMODE              2
     2.9 +
    2.10  /* key definitions */
    2.11  #define MODKEY			Mod4Mask
    2.12  #define KEYS \
    2.13  static Key key[] = { \
    2.14  	/* modifier			key		function	argument */ \
    2.15 -	{ MODKEY|ShiftMask,		XK_Return,	spawn,		{ .cmd = "/home/paulo/bin/myterm.sh" } }, \
    2.16 -	{ MODKEY,			XK_backslash,	spawn,		{ .cmd = "/home/paulo/bin/myterm.sh -e /home/paulo/bin/viclip.sh" } }, \
    2.17 -	{ MODKEY,			XK_n,		pushdown,	{ 0 } }, \
    2.18 -	{ MODKEY,			XK_p,		pushup,	{ 0 } }, \
    2.19 -	{ MODKEY,			XK_Tab,		focusnext,	{ 0 } }, \
    2.20 -	{ MODKEY|ShiftMask,		XK_Tab,		focusprev,	{ 0 } }, \
    2.21 -	{ MODKEY,			XK_Return,	zoom,		{ 0 } }, \
    2.22 -	{ MODKEY,			XK_g,		resizemaster,	{ .i = 15 } }, \
    2.23 -	{ MODKEY,			XK_s,		resizemaster,	{ .i = -15 } }, \
    2.24 -	{ MODKEY,			XK_i,		incnmaster,	{ .i = 1 } }, \
    2.25 -	{ MODKEY,			XK_d,		incnmaster,	{ .i = -1 } }, \
    2.26 -	{ MODKEY|ShiftMask,		XK_grave,		tag,		{ .i = -1 } }, \
    2.27 -	{ MODKEY|ShiftMask,		XK_1,		tag,		{ .i = 0 } }, \
    2.28 -	{ MODKEY|ShiftMask,		XK_2,		tag,		{ .i = 1 } }, \
    2.29 -	{ MODKEY|ShiftMask,		XK_3,		tag,		{ .i = 2 } }, \
    2.30 -	{ MODKEY|ShiftMask,		XK_4,		tag,		{ .i = 3 } }, \
    2.31 -	{ MODKEY|ShiftMask,		XK_5,		tag,		{ .i = 4 } }, \
    2.32 -	{ MODKEY|ShiftMask,		XK_6,		tag,		{ .i = 5 } }, \
    2.33 -	{ MODKEY|ShiftMask,		XK_7,		tag,		{ .i = 6 } }, \
    2.34 -	{ MODKEY|ShiftMask,		XK_8,		tag,		{ .i = 7 } }, \
    2.35 -	{ MODKEY|ShiftMask,		XK_9,		tag,		{ .i = 8 } }, \
    2.36 -	{ MODKEY|ShiftMask,		XK_0,		tag,		{ .i = 9 } }, \
    2.37 -	{ MODKEY|ControlMask|ShiftMask,	XK_1,		toggletag,	{ .i = 0 } }, \
    2.38 -	{ MODKEY|ControlMask|ShiftMask,	XK_2,		toggletag,	{ .i = 1 } }, \
    2.39 -	{ MODKEY|ControlMask|ShiftMask,	XK_3,		toggletag,	{ .i = 2 } }, \
    2.40 -	{ MODKEY|ControlMask|ShiftMask,	XK_4,		toggletag,	{ .i = 3 } }, \
    2.41 -	{ MODKEY|ControlMask|ShiftMask,	XK_5,		toggletag,	{ .i = 4 } }, \
    2.42 -	{ MODKEY|ControlMask|ShiftMask,	XK_6,		toggletag,	{ .i = 5 } }, \
    2.43 -	{ MODKEY|ControlMask|ShiftMask,	XK_7,		toggletag,	{ .i = 6 } }, \
    2.44 -	{ MODKEY|ControlMask|ShiftMask,	XK_8,		toggletag,	{ .i = 7 } }, \
    2.45 -	{ MODKEY|ControlMask|ShiftMask,	XK_9,		toggletag,	{ .i = 8 } }, \
    2.46 -	{ MODKEY|ControlMask|ShiftMask,	XK_0,		toggletag,	{ .i = 9 } }, \
    2.47 -	{ MODKEY|ShiftMask,		XK_c,		killclient,	{ 0 } }, \
    2.48 -	{ MODKEY,			XK_space,	setlayout,	{ .i = -1 } }, \
    2.49 -	{ MODKEY|ShiftMask,			XK_space,	setlayout,	{ .i = -2 } }, \
    2.50 -	{ MODKEY,			XK_F1,	setlayout,	{ .i = 0 } }, \
    2.51 -	{ MODKEY,			XK_F2,	setlayout,	{ .i = 1 } }, \
    2.52 -	{ MODKEY,			XK_F3,	setlayout,	{ .i = 2 } }, \
    2.53 -	{ MODKEY,			XK_F4,	setlayout,	{ .i = 3 } }, \
    2.54 -	{ MODKEY,			XK_F5,	setlayout,	{ .i = 4 } }, \
    2.55 -	{ MODKEY,			XK_F6,	setlayout,	{ .i = 5 } }, \
    2.56 -	{ MODKEY,			XK_F7,	setlayout,	{ .i = 6 } }, \
    2.57 -	{ MODKEY|ControlMask,		XK_space,	toggleversatile,{ 0 } }, \
    2.58 -	{ MODKEY,			XK_grave,		view,		{ .i = -1 } }, \
    2.59 -	{ MODKEY,			XK_1,		view,		{ .i = 0 } }, \
    2.60 -	{ MODKEY,			XK_2,		view,		{ .i = 1 } }, \
    2.61 -	{ MODKEY,			XK_3,		view,		{ .i = 2 } }, \
    2.62 -	{ MODKEY,			XK_4,		view,		{ .i = 3 } }, \
    2.63 -	{ MODKEY,			XK_5,		view,		{ .i = 4 } }, \
    2.64 -	{ MODKEY,			XK_6,		view,		{ .i = 5 } }, \
    2.65 -	{ MODKEY,			XK_7,		view,		{ .i = 6 } }, \
    2.66 -	{ MODKEY,			XK_8,		view,		{ .i = 7 } }, \
    2.67 -	{ MODKEY,			XK_9,		view,		{ .i = 8 } }, \
    2.68 -	{ MODKEY,			XK_0,		view,		{ .i = 9 } }, \
    2.69 -	{ MODKEY,			XK_minus,		next_view,		{ .i = -1 } }, \
    2.70 -	{ MODKEY,			XK_equal,		next_view,		{ .i = 1 } }, \
    2.71 -	{ MODKEY,			XK_BackSpace,		last_view,		{ 0 } }, \
    2.72 -	{ MODKEY|ControlMask,		XK_1,		toggleview,	{ .i = 0 } }, \
    2.73 -	{ MODKEY|ControlMask,		XK_2,		toggleview,	{ .i = 1 } }, \
    2.74 -	{ MODKEY|ControlMask,		XK_3,		toggleview,	{ .i = 2 } }, \
    2.75 -	{ MODKEY|ControlMask,		XK_4,		toggleview,	{ .i = 3 } }, \
    2.76 -	{ MODKEY|ControlMask,		XK_5,		toggleview,	{ .i = 4 } }, \
    2.77 -	{ MODKEY|ControlMask,		XK_6,		toggleview,	{ .i = 5 } }, \
    2.78 -	{ MODKEY|ControlMask,		XK_7,		toggleview,	{ .i = 6 } }, \
    2.79 -	{ MODKEY|ControlMask,		XK_8,		toggleview,	{ .i = 7 } }, \
    2.80 -	{ MODKEY|ControlMask,		XK_9,		toggleview,	{ .i = 8 } }, \
    2.81 -	{ MODKEY|ControlMask,		XK_0,		toggleview,	{ .i = 9 } }, \
    2.82 -	{ MODKEY|ShiftMask,		XK_q,		quit,		{ 0 } }, \
    2.83 +	{ MODKEY,			XK_Escape,	setkeymode,	{ .i = COMMANDMODE } }, \
    2.84  	{ MODKEY,		XK_h,		moveresize,		"-25x 0y 0w 0h" }, \
    2.85  	{ MODKEY,		XK_l,		moveresize,		"25x 0y 0w 0h" }, \
    2.86  	{ MODKEY,		XK_j,		moveresize,		"0x 25y 0w 0h" }, \
    2.87 @@ -134,3 +70,87 @@
    2.88  };
    2.89  
    2.90  #define MAX_TASKS		13		/* max number of apps in taskbar */
    2.91 +
    2.92 +#define CMDKEYS \
    2.93 +static Key cmdkeys[] = { \
    2.94 +	/* modifier		keys		function		argument */ \
    2.95 +	{ 0,		XK_Escape,		clearcmd,		{ 0 } }, \
    2.96 +	{ ControlMask,		XK_c,		clearcmd,		{ 0 } }, \
    2.97 +	{ MODKEY|ShiftMask,		XK_x,		killclient,	{ 0 } }, \
    2.98 +	{ MODKEY|ShiftMask,		XK_q,		quit,		{ 0 } }, \
    2.99 +	{ 0,		XK_i,		setkeymode,		{ .i = INSERTMODE } }, \
   2.100 +	{ 0,		XK_o,		spawn,		{ .cmd = "/home/paulo/bin/myterm.sh" } }, \
   2.101 +	{ ShiftMask,		XK_o,		spawn_insert,		{ .cmd = "/home/paulo/bin/myterm.sh" } }, \
   2.102 +	{ 0,			XK_backslash,	spawn,		{ .cmd = "/home/paulo/bin/myterm.sh -e /home/paulo/bin/viclip.sh" } }, \
   2.103 +	{ ShiftMask,			XK_backslash,	spawn_insert,		{ .cmd = "/home/paulo/bin/myterm.sh -e /home/paulo/bin/viclip.sh" } }, \
   2.104 +	{ 0,			XK_n,		pushdown,	{ 0 } }, \
   2.105 +	{ ShiftMask,		XK_n,		pushup,	{ 0 } }, \
   2.106 +	{ 0,			XK_j,		focusnext,	{ 0 } }, \
   2.107 +	{ 0,			XK_k,		focusprev,	{ 0 } }, \
   2.108 +	{ 0,			XK_Return,	zoom,		{ 0 } }, \
   2.109 +	{ ShiftMask,			XK_Return,	zoom_insert,		{ 0 } }, \
   2.110 +	{ 0,			XK_m,		resizemaster,	{ .i = 15 } }, \
   2.111 +	{ ShiftMask,		XK_m,		resizemaster,	{ .i = -15 } }, \
   2.112 +	{ 0,			XK_d,		incnmaster,	{ .i = 1 } }, \
   2.113 +	{ ShiftMask,		XK_d,		incnmaster,	{ .i = -1 } }, \
   2.114 +	{ 0,			XK_v,		next_view,		{ .i = 1 } }, \
   2.115 +	{ ShiftMask,			XK_v,		next_view,		{ .i = -1 } }, \
   2.116 +	{ 0,			XK_BackSpace,		last_view,		{ 0 } }, \
   2.117 +	{ 0,			XK_l,		setlayout,		{ .i = -1 } }, \
   2.118 +	{ ShiftMask,			XK_l,		setlayout,		{ .i = -2 } }, \
   2.119 +};
   2.120 +
   2.121 +#define COMMANDS \
   2.122 +static Command commands[] = { \
   2.123 +	/* modifier (4 keys)		keysyms (4 keys)		function		argument */ \
   2.124 +	{ {0, 0, 0, 0},		{XK_grave, XK_v, 0, 0},		view,		{ .i = -1 } }, \
   2.125 +	{ {0, 0, 0, 0},		{XK_1, XK_v, 0, 0},		view,		{ .i = 0 } }, \
   2.126 +	{ {0, 0, 0, 0},		{XK_2, XK_v, 0, 0},		view,		{ .i = 1 } }, \
   2.127 +	{ {0, 0, 0, 0},		{XK_3, XK_v, 0, 0},		view,		{ .i = 2 } }, \
   2.128 +	{ {0, 0, 0, 0},		{XK_4, XK_v, 0, 0},		view,		{ .i = 3 } }, \
   2.129 +	{ {0, 0, 0, 0},		{XK_5, XK_v, 0, 0},		view,		{ .i = 4 } }, \
   2.130 +	{ {0, 0, 0, 0},		{XK_6, XK_v, 0, 0},		view,		{ .i = 5 } }, \
   2.131 +	{ {0, 0, 0, 0},		{XK_7, XK_v, 0, 0},		view,		{ .i = 6 } }, \
   2.132 +	{ {0, 0, 0, 0},		{XK_8, XK_v, 0, 0},		view,		{ .i = 7 } }, \
   2.133 +	{ {0, 0, 0, 0},		{XK_9, XK_v, 0, 0},		view,		{ .i = 8 } }, \
   2.134 +	{ {0, 0, 0, 0},		{XK_0, XK_v, 0, 0},		view,		{ .i = 9 } }, \
   2.135 +	{ {0, ShiftMask, 0, 0},		{XK_grave, XK_v, 0, 0},		toggleversatile,		{ 0 } }, \
   2.136 +	{ {0, ShiftMask, 0, 0},		{XK_1, XK_v, 0, 0},		toggleview,		{ .i = 0 } }, \
   2.137 +	{ {0, ShiftMask, 0, 0},		{XK_2, XK_v, 0, 0},		toggleview,		{ .i = 1 } }, \
   2.138 +	{ {0, ShiftMask, 0, 0},		{XK_3, XK_v, 0, 0},		toggleview,		{ .i = 2 } }, \
   2.139 +	{ {0, ShiftMask, 0, 0},		{XK_4, XK_v, 0, 0},		toggleview,		{ .i = 3 } }, \
   2.140 +	{ {0, ShiftMask, 0, 0},		{XK_5, XK_v, 0, 0},		toggleview,		{ .i = 4 } }, \
   2.141 +	{ {0, ShiftMask, 0, 0},		{XK_6, XK_v, 0, 0},		toggleview,		{ .i = 5 } }, \
   2.142 +	{ {0, ShiftMask, 0, 0},		{XK_7, XK_v, 0, 0},		toggleview,		{ .i = 6 } }, \
   2.143 +	{ {0, ShiftMask, 0, 0},		{XK_8, XK_v, 0, 0},		toggleview,		{ .i = 7 } }, \
   2.144 +	{ {0, ShiftMask, 0, 0},		{XK_9, XK_v, 0, 0},		toggleview,		{ .i = 8 } }, \
   2.145 +	{ {0, ShiftMask, 0, 0},		{XK_0, XK_v, 0, 0},		toggleview,		{ .i = 9 } }, \
   2.146 +	{ {0, 0, 0, 0},		{XK_1, XK_l, 0, 0},		setlayout,		{ .i = 0 } }, \
   2.147 +	{ {0, 0, 0, 0},		{XK_2, XK_l, 0, 0},		setlayout,		{ .i = 1 } }, \
   2.148 +	{ {0, 0, 0, 0},		{XK_3, XK_l, 0, 0},		setlayout,		{ .i = 2 } }, \
   2.149 +	{ {0, 0, 0, 0},		{XK_4, XK_l, 0, 0},		setlayout,		{ .i = 3 } }, \
   2.150 +	{ {0, 0, 0, 0},		{XK_5, XK_l, 0, 0},		setlayout,		{ .i = 4 } }, \
   2.151 +	{ {0, 0, 0, 0},		{XK_6, XK_l, 0, 0},		setlayout,		{ .i = 5 } }, \
   2.152 +	{ {0, 0, 0, 0},		{XK_7, XK_l, 0, 0},		setlayout,		{ .i = 6 } }, \
   2.153 +	{ {0, 0, 0, 0},		{XK_grave, XK_t, 0, 0},		tag,		{ .i = -1 } }, \
   2.154 +	{ {0, 0, 0, 0},		{XK_1, XK_t, 0, 0},		tag,		{ .i = 0 } }, \
   2.155 +	{ {0, 0, 0, 0},		{XK_2, XK_t, 0, 0},		tag,		{ .i = 1 } }, \
   2.156 +	{ {0, 0, 0, 0},		{XK_3, XK_t, 0, 0},		tag,		{ .i = 2 } }, \
   2.157 +	{ {0, 0, 0, 0},		{XK_4, XK_t, 0, 0},		tag,		{ .i = 3 } }, \
   2.158 +	{ {0, 0, 0, 0},		{XK_5, XK_t, 0, 0},		tag,		{ .i = 4 } }, \
   2.159 +	{ {0, 0, 0, 0},		{XK_6, XK_t, 0, 0},		tag,		{ .i = 5 } }, \
   2.160 +	{ {0, 0, 0, 0},		{XK_7, XK_t, 0, 0},		tag,		{ .i = 6 } }, \
   2.161 +	{ {0, 0, 0, 0},		{XK_8, XK_t, 0, 0},		tag,		{ .i = 7 } }, \
   2.162 +	{ {0, 0, 0, 0},		{XK_9, XK_t, 0, 0},		tag,		{ .i = 8 } }, \
   2.163 +	{ {0, 0, 0, 0},		{XK_0, XK_t, 0, 0},		tag,		{ .i = 9 } }, \
   2.164 +	{ {0, ShiftMask, 0, 0},		{XK_1, XK_t, 0, 0},		toggletag,		{ .i = 0 } }, \
   2.165 +	{ {0, ShiftMask, 0, 0},		{XK_2, XK_t, 0, 0},		toggletag,		{ .i = 1 } }, \
   2.166 +	{ {0, ShiftMask, 0, 0},		{XK_3, XK_t, 0, 0},		toggletag,		{ .i = 2 } }, \
   2.167 +	{ {0, ShiftMask, 0, 0},		{XK_4, XK_t, 0, 0},		toggletag,		{ .i = 3 } }, \
   2.168 +	{ {0, ShiftMask, 0, 0},		{XK_5, XK_t, 0, 0},		toggletag,		{ .i = 4 } }, \
   2.169 +	{ {0, ShiftMask, 0, 0},		{XK_6, XK_t, 0, 0},		toggletag,		{ .i = 5 } }, \
   2.170 +	{ {0, ShiftMask, 0, 0},		{XK_7, XK_t, 0, 0},		toggletag,		{ .i = 6 } }, \
   2.171 +	{ {0, ShiftMask, 0, 0},		{XK_8, XK_t, 0, 0},		toggletag,		{ .i = 7 } }, \
   2.172 +	{ {0, ShiftMask, 0, 0},		{XK_9, XK_t, 0, 0},		toggletag,		{ .i = 8 } }, \
   2.173 +	{ {0, ShiftMask, 0, 0},		{XK_0, XK_t, 0, 0},		toggletag,		{ .i = 9 } }, \
   2.174 +};
     3.1 --- a/draw.c	Wed Jan 27 23:28:29 2010 -0800
     3.2 +++ b/draw.c	Sun Jun 12 14:32:54 2011 -0700
     3.3 @@ -71,13 +71,21 @@
     3.4  	dc.w = blw;
     3.5  	drawtext(lt->symbol, dc.norm);
     3.6  	x = dc.x + dc.w;
     3.7 -	dc.w = textw(stext);
     3.8 +
     3.9 +	char *_stext = stext;
    3.10 +	if (getkeymode() == COMMANDMODE) {
    3.11 +		strcpy(cmtext, "-- CMD -- ");
    3.12 +		strncat(cmtext, stext, sizeof cmtext - 1 - strlen(cmtext));
    3.13 +		_stext = cmtext;
    3.14 +	}
    3.15 +	dc.w = textw(_stext);
    3.16  	dc.x = sw - dc.w;
    3.17  	if(dc.x < x) {
    3.18  		dc.x = x;
    3.19  		dc.w = sw - x;
    3.20  	}
    3.21 -	drawtext(stext, dc.norm);
    3.22 +	drawtext(_stext, dc.norm);
    3.23 +
    3.24  	if((dc.w = dc.x - x) > bh) {
    3.25  		dc.x = x;
    3.26  		drawtext(sel ? sel->name : NULL, sel ? dc.sel : dc.norm);
     4.1 --- a/dwm.h	Wed Jan 27 23:28:29 2010 -0800
     4.2 +++ b/dwm.h	Sun Jun 12 14:32:54 2011 -0700
     4.3 @@ -33,6 +33,8 @@
     4.4  #include "config.h"
     4.5  #include <X11/Xlib.h>
     4.6  
     4.7 +#define LENGTH(X)		(sizeof X / sizeof X[0])
     4.8 +
     4.9  /* mask shorthands, used in event.c and client.c */
    4.10  #define BUTTONMASK		(ButtonPressMask | ButtonReleaseMask)
    4.11  
    4.12 @@ -87,6 +89,7 @@
    4.13  
    4.14  extern const char *tags[];			/* all tags */
    4.15  extern char stext[256];				/* status text */
    4.16 +extern char cmtext[256];				/* command mode text */
    4.17  extern int screen, sx, sy, sw, sh;		/* screen geometry */
    4.18  extern int wax, way, wah, waw;			/* windowarea geometry */
    4.19  extern unsigned int bh, blw;			/* bar height, bar layout label width */
    4.20 @@ -114,6 +117,7 @@
    4.21  extern void updatetitle(Client *c);		/* update the name of c */
    4.22  extern void unmanage(Client *c);		/* destroy c */
    4.23  extern void zoom(Arg *arg);			/* zooms the focused client to master area, arg is ignored */
    4.24 +extern void zoom_insert(Arg *arg);			/* zoom, then go into insert mode */
    4.25  extern void pushup(Arg *arg);
    4.26  extern void pushdown(Arg *arg);
    4.27  extern void moveresize(Arg *arg);
    4.28 @@ -126,6 +130,10 @@
    4.29  
    4.30  /* event.c */
    4.31  extern void grabkeys(void);			/* grab all keys defined in config.h */
    4.32 +extern void clearcmd(Arg *arg);
    4.33 +extern void setkeymode(Arg *arg);
    4.34 +extern unsigned int getkeymode(void);
    4.35 +extern void func_insert(void (*argfunc)(Arg *), Arg *arg);
    4.36  
    4.37  /* layout.c */
    4.38  extern void focusnext(Arg *arg);		/* focuses next visible client, arg is ignored  */
    4.39 @@ -158,4 +166,4 @@
    4.40  extern void *emallocz(unsigned int size);	/* allocates zero-initialized memory, exits on error */
    4.41  extern void eprint(const char *errstr, ...);	/* prints errstr and exits with 1 */
    4.42  extern void spawn(Arg *arg);			/* forks a new subprocess with arg's cmd */
    4.43 -
    4.44 +extern void spawn_insert(Arg *arg);			/* spawn, then go into insert mode */
     5.1 --- a/event.c	Wed Jan 27 23:28:29 2010 -0800
     5.2 +++ b/event.c	Sun Jun 12 14:32:54 2011 -0700
     5.3 @@ -2,12 +2,15 @@
     5.4   * See LICENSE file for license details.
     5.5   */
     5.6  #include "dwm.h"
     5.7 -#include <stdlib.h>
     5.8  #include <X11/keysym.h>
     5.9  #include <X11/Xatom.h>
    5.10  
    5.11  /* static */
    5.12  
    5.13 +static unsigned int cmdmod[4];
    5.14 +static unsigned int keymode = COMMANDMODE;
    5.15 +static KeySym cmdkeysym[4];
    5.16 +
    5.17  typedef struct {
    5.18  	unsigned long mod;
    5.19  	KeySym keysym;
    5.20 @@ -287,7 +290,7 @@
    5.21  }
    5.22  
    5.23  static void
    5.24 -keypress(XEvent *e) {
    5.25 +defkeypress(XEvent *e) {
    5.26  	static unsigned int len = sizeof key / sizeof key[0];
    5.27  	unsigned int i;
    5.28  	KeySym keysym;
    5.29 @@ -372,6 +375,75 @@
    5.30  		unmanage(c);
    5.31  }
    5.32  
    5.33 +typedef struct {
    5.34 +	unsigned int mod[4];
    5.35 +	KeySym keysym[4];
    5.36 +	void (*func)(Arg *arg);
    5.37 +	Arg arg;
    5.38 +} Command;
    5.39 +
    5.40 +CMDKEYS
    5.41 +COMMANDS
    5.42 +
    5.43 +void
    5.44 +keypress(XEvent *e) {
    5.45 +	unsigned int i, j;
    5.46 +	Arg a = {0};
    5.47 +	Bool ismatch = False, maybematch = False;
    5.48 +	KeySym keysym;
    5.49 +	XKeyEvent *ev;
    5.50 +
    5.51 +	if(keymode == INSERTMODE)
    5.52 +		defkeypress(e);
    5.53 +	else if(keymode == COMMANDMODE) {
    5.54 +		ev = &e->xkey;
    5.55 +		keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
    5.56 +		if(keysym < XK_Shift_L || keysym > XK_Hyper_R) {
    5.57 +			for(j = 0; j < LENGTH(cmdkeysym); j++)
    5.58 +				if(cmdkeysym[j] == 0) {
    5.59 +					cmdkeysym[j] = keysym;
    5.60 +					cmdmod[j] = ev->state;
    5.61 +					break;
    5.62 +				}
    5.63 +			for(i = 0; i < LENGTH(commands); i++) {
    5.64 +				for(j = 0; j < LENGTH(cmdkeysym); j++) {
    5.65 +					if(cmdkeysym[j] == commands[i].keysym[j] 
    5.66 +					&& CLEANMASK(cmdmod[j]) == CLEANMASK(commands[i].mod[j]))
    5.67 +						ismatch = True;
    5.68 +					else if(cmdkeysym[j] == 0 
    5.69 +					&& cmdmod[j] == 0) {
    5.70 +						ismatch = False;
    5.71 +						maybematch = True;
    5.72 +						break;
    5.73 +					} else {
    5.74 +						ismatch = False;
    5.75 +						break;
    5.76 +					}
    5.77 +				}
    5.78 +				if(ismatch) {
    5.79 +					if(commands[i].func)
    5.80 +						commands[i].func(&(commands[i].arg));
    5.81 +					clearcmd(&a);
    5.82 +					break;
    5.83 +				}
    5.84 +
    5.85 +			}
    5.86 +			if(!maybematch)
    5.87 +				clearcmd(&a);
    5.88 +			if(!ismatch) {
    5.89 +				for(i = 0; i < LENGTH(cmdkeys); i++)
    5.90 +					if(keysym == cmdkeys[i].keysym
    5.91 +					&& CLEANMASK(cmdkeys[i].mod) == CLEANMASK(ev->state)
    5.92 +					&& cmdkeys[i].func) {
    5.93 +						cmdkeys[i].func(&(cmdkeys[i].arg));
    5.94 +						ismatch = True;
    5.95 +						break;
    5.96 +					}
    5.97 +			}
    5.98 +		}
    5.99 +	}
   5.100 +}
   5.101 +
   5.102  /* extern */
   5.103  
   5.104  void (*handler[LASTEvent]) (XEvent *) = {
   5.105 @@ -389,7 +461,7 @@
   5.106  };
   5.107  
   5.108  void
   5.109 -grabkeys(void) {
   5.110 +grabdefkeys(void) {
   5.111  	static unsigned int len = sizeof key / sizeof key[0];
   5.112  	unsigned int i;
   5.113  	KeyCode code;
   5.114 @@ -407,3 +479,50 @@
   5.115  				GrabModeAsync, GrabModeAsync);
   5.116  	}
   5.117  }
   5.118 +
   5.119 +void
   5.120 +clearcmd(Arg *arg) {
   5.121 +	unsigned int i;
   5.122 +
   5.123 +	for(i = 0; i < LENGTH(cmdkeysym); i++) {
   5.124 +		cmdkeysym[i] = 0;
   5.125 +		cmdmod[i] = 0;
   5.126 +	}
   5.127 +}
   5.128 +
   5.129 +void
   5.130 +grabkeys(void) {
   5.131 +	if(keymode == INSERTMODE) {
   5.132 +		XUngrabKeyboard(dpy, CurrentTime);
   5.133 +		grabdefkeys();
   5.134 +	} else if(keymode == COMMANDMODE) {
   5.135 +		XUngrabKey(dpy, AnyKey, AnyModifier, root);
   5.136 +		//XGrabKey(dpy, AnyKey, AnyModifier, root,
   5.137 +		//	 True, GrabModeAsync, GrabModeAsync);
   5.138 +		XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
   5.139 +	}
   5.140 +}
   5.141 +
   5.142 +void
   5.143 +setkeymode(Arg *arg) {
   5.144 +	Arg a = {0};
   5.145 +
   5.146 +	if(!arg)
   5.147 +		return;
   5.148 +	keymode = arg->i;
   5.149 +	clearcmd(&a);
   5.150 +	grabkeys();
   5.151 +	drawstatus();
   5.152 +}
   5.153 +
   5.154 +unsigned int
   5.155 +getkeymode(void) {
   5.156 +	return keymode;
   5.157 +}
   5.158 +
   5.159 +void
   5.160 +func_insert(void (*argfunc)(Arg *), Arg *arg) {
   5.161 +	Arg a = { .i = INSERTMODE };
   5.162 +	argfunc(arg);
   5.163 +	setkeymode(&a);
   5.164 +}
     6.1 --- a/main.c	Wed Jan 27 23:28:29 2010 -0800
     6.2 +++ b/main.c	Sun Jun 12 14:32:54 2011 -0700
     6.3 @@ -18,6 +18,7 @@
     6.4  /* extern */
     6.5  
     6.6  char stext[256];
     6.7 +char cmtext[256];
     6.8  int screen, sx, sy, sw, sh, wax, way, waw, wah;
     6.9  unsigned int bh, ntags, numlockmask;
    6.10  Atom wmatom[WMLast], netatom[NetLast];
     7.1 --- a/util.c	Wed Jan 27 23:28:29 2010 -0800
     7.2 +++ b/util.c	Sun Jun 12 14:32:54 2011 -0700
     7.3 @@ -52,3 +52,8 @@
     7.4  	}
     7.5  	wait(0);
     7.6  }
     7.7 +
     7.8 +void
     7.9 +spawn_insert(Arg *arg) {
    7.10 +	func_insert(spawn, arg);
    7.11 +}