wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

commit 6b1d84a866744fcd8e6ebbb73406b0011eb53ed7
parent fac8780e4b1632e8ede500a97d26b033caa12c80
Author: Kris Maglione <jg@suckless.org>
Date:   Wed, 13 May 2009 23:30:20 -0400

Allow rebinding of keys in wimenu.

Diffstat:
.hgignore | 10++++++----
cmd/Makefile | 2+-
cmd/menu/Makefile | 8++++++++
cmd/menu/caret.c | 5+++--
cmd/menu/dat.h | 24++++++++++++++++++++++++
cmd/menu/fns.h | 5+++++
cmd/menu/keys.c | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/menu/keys.txt | 49+++++++++++++++++++++++++++++++++++++++++++++++++
cmd/menu/main.c | 71++++++++++++++++++++++++++++-------------------------------------------
cmd/menu/menu.c | 187++++++++++++++++++++++---------------------------------------------------------
cmd/util.c | 18++++++++++++++++++
cmd/wmii9menu.c | 38++------------------------------------
include/util.h | 3++-
13 files changed, 341 insertions(+), 222 deletions(-)

diff --git a/.hgignore b/.hgignore @@ -1,6 +1,8 @@ syntax: regexp -(^|/)\.((.*\.)?swp|depend|hgignore)$ +(^|/)\.((.*\.)?sw.|depend|hgignore)$ (^|/)(tags|mkfile)$ -\.([oOa]|o_pic|so)$ -^config\.local\.mk$ - +\.([oOa]|o_pic|so|orig|bak)$ +^cmd/(stfo|osd|wiwarp)(/|$) +syntax: glob +config.local.mk +cmd/menu/bindings.c diff --git a/cmd/Makefile b/cmd/Makefile @@ -35,7 +35,7 @@ wmiir.O: $(OWMIIR) wmii/x11.o wmii/map.o: dall true -O9MENU=wmii9menu.o wmii/x11.o wmii/map.o $(OFILES) $(LIBIXP) +O9MENU=wmii9menu.o clientutil.o wmii/x11.o wmii/map.o $(OFILES) $(LIBIXP) wmii9menu.O: $(O9MENU) $(LINK) $@ $(O9MENU) $(LIBX11) -lXext -lbio diff --git a/cmd/menu/Makefile b/cmd/menu/Makefile @@ -4,6 +4,11 @@ include $(ROOT)/mk/wmii.mk main.c: $(ROOT)/mk/wmii.mk +bindings.c: keys.txt Makefile + ( echo "char binding_spec[] = "; \ + sed 's/.*/ "&\\n"/' keys.txt; \ + echo " ;" ) >bindings.c + TARG = wimenu HFILES= dat.h fns.h @@ -17,11 +22,14 @@ OBJ = main \ history \ event \ menu \ + keys \ + bindings \ ../wmii/geom \ ../wmii/map \ ../wmii/printevent \ ../wmii/x11 \ ../wmii/xext \ + ../clientutil \ ../util include $(ROOT)/mk/one.mk diff --git a/cmd/menu/caret.c b/cmd/menu/caret.c @@ -79,8 +79,7 @@ caret_find(int dir, int type) { return end; } } - die("not reached"); - return nil; /* shut up ken */ + return input.pos; } void @@ -114,6 +113,8 @@ void caret_insert(char *s, bool clear) { int pos, end, len, size; + if(s == nil) + return; if(clear) { input.pos = input.string; input.end = input.string; diff --git a/cmd/menu/dat.h b/cmd/menu/dat.h @@ -26,6 +26,26 @@ enum { CARET_LAST, }; +enum { + LACCEPT, + LBACKWARD, + LCHAR, + LCOMPLETE, + LFIRST, + LFORWARD, + LHISTORY, + LKILL, + LLAST, + LLINE, + LLITERAL, + LNEXT, + LNEXTPAGE, + LPREV, + LPREVPAGE, + LREJECT, + LWORD, +}; + typedef struct Item Item; struct Item { @@ -46,6 +66,10 @@ EXTERN struct { int size; } input; +extern char binding_spec[]; + +EXTERN int numlock; + EXTERN long xtime; EXTERN Image* ibuf; EXTERN Font* font; diff --git a/cmd/menu/fns.h b/cmd/menu/fns.h @@ -18,6 +18,11 @@ void menu_show(void); void xtime_kludge(void); void update_filter(void); +/* keys.c */ +void parse_keys(char*); +char** find_key(char*, long); +int getsym(char*); + /* geom.c */ Align get_sticky(Rectangle src, Rectangle dst); Cursor quad_cursor(Align); diff --git a/cmd/menu/keys.c b/cmd/menu/keys.c @@ -0,0 +1,143 @@ +#include "dat.h" +#include <ctype.h> +#include <strings.h> +#include <unistd.h> +#include "fns.h" + +typedef struct Key Key; +typedef struct KMask KMask; + +struct Key { + Key* next; + long mask; + char* key; + char** action; +}; + +static Key* bindings; + +static struct KMask { + int mask; + const char* name; +} masks[] = { + {ControlMask, "Control"}, + {Mod1Mask, "Mod1"}, + {Mod2Mask, "Mod2"}, + {Mod3Mask, "Mod3"}, + {Mod4Mask, "Mod4"}, + {ShiftMask, "Shift"}, + {0,} +}; + +/* + * To do: Find my red black tree implementation. + */ +void +parse_keys(char *spec) { + static char *lines[1024]; + static char *words[16]; + static char *keys[16]; + Key *k; + KMask *m; + char *p, *line; + long mask; + int i, j, nlines, nwords, nkeys; + + nlines = tokenize(lines, nelem(lines), spec, '\n'); + for(i=0; i < nlines; i++) { + line = lines[i]; + p = strchr(line, '#'); + if(p) + *p = '\0'; + nwords = stokenize(words, nelem(words) - 1, line, " \t"); + words[nwords] = nil; + if(!words[0]) + continue; + mask = 0; + nkeys = tokenize(keys, nelem(keys), words[0], '-'); + for(j=0; j < nkeys; j++) { + for(m=masks; m->mask; m++) + if(!strcasecmp(m->name, keys[j])) { + mask |= m->mask; + goto next; + } + break; + next: continue; + } + if(j == nkeys - 1) { + k = emallocz(sizeof *k); + k->key = keys[j]; + k->mask = mask; + k->action = strlistdup(words + 1); + k->next = bindings; + bindings = k; + } + } +} + +char** +find_key(char *key, long mask) { + Key *k; + + /* Horrible hack. */ + if(!strcmp(key, "ISO_Left_Tab")) + key = "Tab"; + + mask &= ~(numlock | LockMask); + for(k=bindings; k; k=k->next) + if(!strcasecmp(k->key, key) && k->mask == mask) + return k->action; + return nil; +} + + /* sed 's/"([^"]+)"/L\1/g' | tr 'a-z' 'A-Z' */ + /* awk '{$1=""; print}' keys.txt | perl -e '$_=lc join "", <>; print join "\n", m/(\w+)/g;' | sort -u | sed 's:.*: "&",:' */ +char *symtab[] = { + "accept", + "backward", + "char", + "complete", + "first", + "forward", + "history", + "kill", + "last", + "line", + "literal", + "next", + "nextpage", + "prev", + "prevpage", + "reject", + "word", +}; + +static int +_bsearch(char *s, char **tab, int ntab) { + int i, n, m, cmp; + + if(s == nil) + return -1; + + n = ntab; + i = 0; + while(n) { + m = n/2; + cmp = strcasecmp(s, tab[i+m]); + if(cmp == 0) + return i+m; + if(cmp < 0 || m == 0) + n = m; + else { + i += m; + n = n-m; + } + } + return -1; +} + +int +getsym(char *s) { + return _bsearch(s, symtab, nelem(symtab)); +} + diff --git a/cmd/menu/keys.txt b/cmd/menu/keys.txt @@ -0,0 +1,49 @@ +Control-j Accept +Control-m Accept +Return Accept +Control-Shift-j Accept literal +Control-Shift-m Accept literal +Shift-Return Accept literal + +Escape Reject +Control-[ Reject + +Left Backward char +Control-b Backward char +Right Forward char +Control-f Forward char + +Mod1-b Backward word +Mod1-f Forward word + +Control-a Backward line +Control-e Forward line + +Control-p History backward +Up History backward +Control-n History forward +Down History forward + +BackSpace Kill char +Control-h Kill char +Control-Backspace Kill word +Control-w Kill word +Control-u Kill line + +Tab Complete next +Control-i Complete next +Mod1-l Complete next + +Shift-Tab Complete prev +Control-Shift-i Complete prev +Mod1-h Complete prev + +Prior Complete prevpage +Mod1-k Complete prevpage +Next Complete nextpage +Mod1-j Complete nextpage +Home Complete first +Mod1-g Complete first +End Complete last +Mod1-Shift-g Complete last + diff --git a/cmd/menu/main.c b/cmd/menu/main.c @@ -10,15 +10,13 @@ #include <strings.h> #include <unistd.h> #include <bio.h> +#include <clientutil.h> #include "fns.h" #define link _link static const char version[] = "wimenu-"VERSION", ©2009 Kris Maglione\n"; -static IxpClient* client; -static IxpCFid* ctlfid; static Biobuf* inbuf; -static char ctl[1024]; -static char* ectl; +static bool alwaysprint; static void usage(void) { @@ -51,27 +49,6 @@ void dprint(long mask, char *fmt, ...) { va_end(ap); } -static char* -readctl(char *key) { - char *s, *p; - int nkey, n; - - nkey = strlen(key); - p = ctl - 1; - do { - p++; - if(!strncmp(p, key, nkey)) { - p += nkey; - s = strchr(p, '\n'); - n = (s ? s : ectl) - p; - s = freelater(emalloc(n + 1)); - s[n] = '\0'; - return strncpy(s, p, n); - } - } while((p = strchr(p, '\n'))); - return ""; -} - static void splice(Item *i) { i->next->prev = i->prev; @@ -149,6 +126,11 @@ update_filter(void) { * has been truncated. */ matchfirst = matchstart = matchidx = filter_list(items, input.string); + if(alwaysprint) { + write(1, input.string, input.pos - input.string); + write(1, "", 1); + write(1, input.pos, input.end - input.pos + 1); + } } /* @@ -182,7 +164,7 @@ preselect(IxpServer *s) { check_x_event(nil); } -#define SCREEN_WITH_POINTER -1 +enum { PointerScreen = -1 }; void init_screens(int screen_hint) { @@ -191,11 +173,10 @@ init_screens(int screen_hint) { int i, n; rects = xinerama_screens(&n); - if (screen_hint >= 0 && screen_hint < n) { - /* we were given a valid screen index, use that */ + if (screen_hint >= 0 && screen_hint < n) + /* We were given a valid screen index, use that. */ i = screen_hint; - - } else { + else { /* Pick the screen with the pointer, for now. Later, * try for the screen with the focused window first. */ @@ -215,6 +196,7 @@ main(int argc, char *argv[]) { Item *item; char *address; char *histfile; + char *keyfile; int i; long ndump; int screen; @@ -223,9 +205,8 @@ main(int argc, char *argv[]) { fmtinstall('r', errfmt); address = getenv("WMII_ADDRESS"); histfile = nil; - prompt = nil; - promptw = 0; - screen = SCREEN_WITH_POINTER; + keyfile = nil; + screen = PointerScreen; find = strstr; compare = strncmp; @@ -236,9 +217,15 @@ main(int argc, char *argv[]) { case 'a': address = EARGF(usage()); break; + case 'c': + alwaysprint = true; + break; case 'h': histfile = EARGF(usage()); break; + case 'k': + keyfile = EARGF(usage()); + break; case 'n': ndump = strtol(EARGF(usage()), nil, 10); break; @@ -267,16 +254,7 @@ main(int argc, char *argv[]) { if(!isatty(0)) menu_init(); - if(address && *address) - client = ixp_mount(address); - else - client = ixp_nsmount("wmii"); - if(client == nil) - fatal("can't mount: %r\n"); - - ctlfid = ixp_open(client, "ctl", OREAD); - i = ixp_read(ctlfid, ctl, 1023); - ectl = ctl + i; + client_init(address); srv.preselect = preselect; ixp_listen(&srv, ConnectionNumber(display), nil, check_x_event, end); @@ -293,6 +271,13 @@ main(int argc, char *argv[]) { caret_insert("", true); update_filter(); + parse_keys(binding_spec); + if(keyfile) { + i = open(keyfile, O_RDONLY); + if(read(i, buffer, sizeof(buffer)) > 0) + parse_keys(buffer); + } + Bterm(inbuf); histidx = &hist; link(&hist, &hist); diff --git a/cmd/menu/menu.c b/cmd/menu/menu.c @@ -7,7 +7,6 @@ static Handlers handlers; static int ltwidth; -static int numlock; static void menu_draw(void); @@ -232,12 +231,15 @@ menu_show(void) { static void kdown_event(Window *w, XKeyEvent *e) { + char **action, **p; + char *key; char buf[32]; int num; KeySym ksym; buf[0] = 0; num = XLookupString(e, buf, sizeof buf, &ksym, 0); + key = XKeysymToString(ksym); if(IsKeypadKey(ksym)) if(ksym == XK_KP_Enter) ksym = XK_Return; @@ -251,145 +253,60 @@ kdown_event(Window *w, XKeyEvent *e) { || IsPFKey(ksym)) return; - if(e->state & ControlMask) { - switch (ksym) { - default: - return; - case XK_bracketleft: /* Esc */ - menu_cmd(REJECT, 0); - return; - case XK_j: - case XK_J: - case XK_m: - case XK_M: - menu_cmd(ACCEPT, e->state&ShiftMask); - return; - case XK_a: - case XK_A: - menu_cmd(BACKWARD, LINE); - return; - case XK_e: - case XK_E: - menu_cmd(FORWARD, LINE); - return; - case XK_b: - case XK_B: - menu_cmd(BACKWARD, CHAR); - return; - case XK_f: - case XK_F: - menu_cmd(FORWARD, CHAR); - return; - case XK_n: - case XK_N: - menu_cmd(HIST, FORWARD); - return; - case XK_p: - case XK_P: - menu_cmd(HIST, BACKWARD); - return; - case XK_h: - case XK_H: - menu_cmd(KILL, CHAR); - return; - case XK_BackSpace: - case XK_w: - case XK_W: - menu_cmd(KILL, WORD); - return; - case XK_u: - case XK_U: - menu_cmd(KILL, LINE); - return; - case XK_i: /* Tab */ - case XK_I: - if(e->state & ShiftMask) - menu_cmd(CMPL_PREV, 0); - else - menu_cmd(CMPL_NEXT, 0); - return; - } - } - /* Alt-<Key> - Vim */ - if((e->state & ~(numlock | LockMask)) & Mod1Mask) { - switch(ksym) { - default: - return; - case XK_h: - menu_cmd(CMPL_PREV, 0); - return; - case XK_l: - menu_cmd(CMPL_NEXT, 0); - return; - case XK_k: - menu_cmd(CMPL_PREV_PAGE, 0); - return; - case XK_j: - menu_cmd(CMPL_NEXT_PAGE, 0); - return; - case XK_g: - menu_cmd(CMPL_FIRST, 0); - return; - case XK_G: - menu_cmd(CMPL_LAST, 0); - return; - case XK_b: - case XK_B: - menu_cmd(BACKWARD, WORD); - return; - case XK_f: - case XK_F: - menu_cmd(FORWARD, WORD); - return; - } - } - switch(ksym) { - default: + action = find_key(key, e->state); + if(action == nil || action[0] == nil) { if(num && !iscntrl(buf[0])) { caret_insert(buf, false); update_filter(); menu_draw(); } - break; - case XK_Tab: - if(e->state & ShiftMask) - menu_cmd(CMPL_PREV, 0); - else - menu_cmd(CMPL_NEXT, 0); - return; - case XK_Return: - menu_cmd(ACCEPT, e->state & ShiftMask); - return; - case XK_Escape: - menu_cmd(REJECT, 0); - return; - case XK_BackSpace: - menu_cmd(KILL, CHAR); - return; - case XK_Left: - menu_cmd(BACKWARD, CHAR); - return; - case XK_Right: - menu_cmd(FORWARD, CHAR); - return; - case XK_Up: - menu_cmd(HIST, BACKWARD); - return; - case XK_Down: - menu_cmd(HIST, FORWARD); - return; - case XK_Home: - menu_cmd(CMPL_FIRST, 0); - return; - case XK_End: - menu_cmd(CMPL_LAST, 0); - return; - case XK_Prior: - menu_cmd(CMPL_PREV_PAGE, 0); - return; - case XK_Next: - menu_cmd(CMPL_NEXT_PAGE, 0); - return; + } + else { + long mask = 0; +# define have(val) !!(mask & (1 << val)) + for(p=action+1; *p; p++) + mask |= 1 << getsym(*p); + int amount = ( + have(LCHAR) ? CHAR : + have(LWORD) ? WORD : + have(LLINE) ? LINE : + -1); + switch(getsym(action[0])) { + case LACCEPT: + menu_cmd(ACCEPT, have(LLITERAL)); + break; + case LBACKWARD: + menu_cmd(BACKWARD, amount); + break; + case LCOMPLETE: + amount = CMPL_NEXT; + if(have(LNEXT)) + amount = CMPL_NEXT; + else if(have(LPREV)) + amount = CMPL_PREV; + else if(have(LNEXTPAGE)) + amount = CMPL_NEXT_PAGE; + else if(have(LPREVPAGE)) + amount = CMPL_PREV_PAGE; + else if(have(LFIRST)) + amount = CMPL_FIRST; + else if(have(LLAST)) + amount = CMPL_LAST; + menu_cmd(amount, 0); + break; + case LFORWARD: + menu_cmd(FORWARD, amount); + break; + case LHISTORY: + menu_cmd(HIST, have(LBACKWARD) ? BACKWARD : FORWARD); + break; + case LKILL: + menu_cmd(KILL, amount); + break; + case LREJECT: + menu_cmd(REJECT, 0); + break; + } } } diff --git a/cmd/util.c b/cmd/util.c @@ -177,6 +177,24 @@ tokenize(char *res[], uint reslen, char *str, char delim) { return i; } +uint +stokenize(char *res[], uint reslen, char *str, char *delim) { + char *s; + uint i; + + i = 0; + s = str; + while(i < reslen && *s) { + while(strchr(delim, *s)) + *(s++) = '\0'; + if(*s) + res[i++] = s; + while(*s && !strchr(delim, *s)) + s++; + } + return i; +} + int max(int a, int b) { if(a > b) diff --git a/cmd/wmii9menu.c b/cmd/wmii9menu.c @@ -44,6 +44,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <clientutil.h> #include <util.h> #include <x11.h> @@ -55,37 +56,11 @@ static CTuple cnorm; static CTuple csel; static Font* font; -static IxpClient* client; -static IxpCFid* ctlfid; -static char ctl[1024]; -static char* ectl; - static int wborder; char buffer[8092]; char* _buffer; -static char* -readctl(char *key) { - char *s, *p; - int nkey, n; - - nkey = strlen(key); - p = ctl - 1; - do { - p++; - if(!strncmp(p, key, nkey)) { - p += nkey; - s = strchr(p, '\n'); - n = (s ? s : ectl) - p; - s = freelater(emalloc(n + 1)); - s[n] = '\0'; - return strncpy(s, p, n); - } - } while((p = strchr(p, '\n'))); - return ""; -} - /* for XSetWMProperties to use */ int g_argc; char **g_argv; @@ -154,16 +129,7 @@ main(int argc, char **argv) cur = i; } - if(address && *address) - client = ixp_mount(address); - else - client = ixp_nsmount("wmii"); - if(client == nil) - fatal("can't mount: %r\n"); - - ctlfid = ixp_open(client, "ctl", OREAD); - i = ixp_read(ctlfid, ctl, 1023); - ectl = ctl + i; + client_init(address); wborder = strtol(readctl("border "), nil, 10); loadcolor(&cnorm, readctl("normcolors ")); diff --git a/include/util.h b/include/util.h @@ -46,7 +46,8 @@ int min(int, int); uint strlcat(char*, const char*, uint); char* strcasestr(const char*, const char*); char* sxprint(const char*, ...); -uint tokenize(char **, uint, char*, char); +uint tokenize(char**, uint, char*, char); +uint stokenize(char**, uint, char*, char*); int utflcpy(char*, const char*, int); char* vsxprint(const char*, va_list);