From a1937a73b7f51bf931a6316c669f8b51a89d796e Mon Sep 17 00:00:00 2001 From: Darrin Chandler Date: Tue, 10 Mar 2009 01:32:06 +0000 Subject: [PATCH] Add key binding capabilities to the configuration file. Some minor refactoring. "Sure, go ahead" mcbride, "ok get it in" marco --- scrotwm.1 | 295 ++++++++++++++++++++++++++++------------- scrotwm.c | 416 ++++++++++++++++++++++++++++++++++++++++++++++++---------- scrotwm.conf | 56 ++++++++ 3 files changed, 607 insertions(+), 160 deletions(-) diff --git a/scrotwm.1 b/scrotwm.1 index 1838614..67124d1 100644 --- a/scrotwm.1 +++ b/scrotwm.1 @@ -56,94 +56,10 @@ Mouse button 3 .Pp .Nm is very simple in its use. -Most of the actions are initiated via keybindings. -The current keybindings are described below: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm M-S- Ns Aq Cm Return -Spawn a new terminal -.It Cm M-p -Menu -.It Cm M-S-q -Quit -.It Cm M-q -Restart -.Nm -.It Cm M- Ns Aq Cm Space -Cycle layout -.It Cm M-S- Ns Aq Cm Space -Reset layout -.It Cm M-h -Shrink master area -.It Cm M-l -Grow master area -.It Cm M-, -Add windows to master area -.It Cm M-. -Remove windows from master area -.It Cm M-S-, -Add columns/rows to stacking area -.It Cm M-S-. -Remove columns/rows from stacking area -.It Cm M- Ns Aq Cm Return -Move current window to master area -.It Xo -.Cm M-j , -.Cm M- Ns Aq Cm TAB -.Xc -Focus next window in workspace -.It Xo -.Cm M-k , -.Cm M-S- Ns Aq Cm TAB -.Xc -Focus previous window in workspace -.It Cm M-m -Focus on main window in workspace -.It Cm M-S-j -Swap with next window in workspace -.It Cm M-S-k -Swap with previous window in workspace -.It Cm M-b -Toggle status bar in all workspaces -.It Cm M-x -Delete current window in workspace -.It Cm M-S-x -Destroy current window in workspace -.It Cm M- Ns Aq Ar n -Switch to workspace -.Ar n -.It Cm M-S- Ns Aq Ar n -Move current window to workspace -.Ar n -.It Cm M- Ns Aq Cm Right -Switch to next workspace with a window in it -.It Cm M- Ns Aq Cm Left -Switch to previous workspace with a window in it -.It Cm M-S- Ns Aq Cm Right -Move pointer to next region -.It Cm M-S- Ns Aq Cm Left -Move pointer to previous region -.It Cm M-s -Take screenshot of entire screen (if enabled) -.It Cm M-S-s -Take screenshot of selected window (if enabled) -.It Cm M-S-v -Toggle version in status bar -.It Cm M-t -Toggle focused window between tiled and floating -.It Cm M-S Aq Cm Delete -Lock screen -.It Cm M-S-i -Reinitialize physical screens -.It Cm M1 -Focus window -.It Cm M-M1 -Move window -.It Cm M-M3 -Resize window -.It Cm M-S-M3 -Resize window while maintaining it centered -.El +Most of the actions are initiated via key or mouse bindings. +See the +.Sx BINDINGS +section below for defaults and customizations. .Sh CONFIGURATION FILES .Nm first tries to open the user specific file, @@ -224,6 +140,12 @@ binary without the setgid bit set. .It Cm modkey Change mod key. Mod1 is generally the ALT key and Mod4 is the windows key on a PC. +.It Cm bind Ns Bq Ar x +Bind key combo to action +.Ar x . +See the +.Sx BINDINGS +section below. .El .Pp Colors need to be specified per the @@ -231,6 +153,198 @@ Colors need to be specified per the specification and fonts need to be specified per the .Xr XQueryFont 3 specification. +.Sh BINDINGS +.Nm +provides many functions (or actions) accessed via key or mouse bindings. +.Pp +The current mouse bindings are described below: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm M1 +Focus window +.It Cm M-M1 +Move window +.It Cm M-M3 +Resize window +.It Cm M-S-M3 +Resize window while maintaining it centered +.El +.Pp +The default key bindings are described below: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm M-S- Ns Aq Cm Return +spawn_term +.It Cm M-p +spawn_menu +.It Cm M-S-q +quit +.It Cm M-q +restart +.Nm +.It Cm M- Ns Aq Cm Space +cycle_layout +.It Cm M-S- Ns Aq Cm Space +reset_layout +.It Cm M-h +master_shrink +.It Cm M-l +master_grow +.It Cm M-, +master_add +.It Cm M-. +master_del +.It Cm M-S-, +stack_inc +.It Cm M-S-. +stack_del +.It Cm M- Ns Aq Cm Return +swap_main +.It Xo +.Cm M-j , +.Cm M- Ns Aq Cm TAB +.Xc +focus_next +.It Xo +.Cm M-k , +.Cm M-S- Ns Aq Cm TAB +.Xc +focus_prev +.It Cm M-m +focus_main +.It Cm M-S-j +swap_next +.It Cm M-S-k +swap_prev +.It Cm M-b +bar_toggle +.It Cm M-x +wind_del +.It Cm M-S-x +wind_kill +.It Cm M- Ns Aq Ar n +.Ns ws_ Ns Ar n +.It Cm M-S- Ns Aq Ar n +.Ns mvws_ Ns Ar n +.It Cm M- Ns Aq Cm Right +ws_next +.It Cm M- Ns Aq Cm Left +ws_prev +.It Cm M-S- Ns Aq Cm Right +screen_next +.It Cm M-S- Ns Aq Cm Left +screen_prev +.It Cm M-s +screenshot_all +.It Cm M-S-s +screenshot_wind +.It Cm M-S-v +version +.It Cm M-t +float_toggle +.It Cm M-S Aq Cm Delete +spawn_lock +.It Cm M-S-i +spawn_initscr +.El +.Pp +The action names and descriptions are listed below: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm spawn_term +Spawn a new terminal +.It Cm spawn_menu +Menu +.It Cm quit +Quit +.Nm +.It Cm restart +Restart +.Nm +.It Cm cycle_layout +Cycle layout +.It Cm reset_layout +Reset layout +.It Cm master_shrink +Shrink master area +.It Cm master_grow +Grow master area +.It Cm master_add +Add windows to master area +.It Cm master_del +Remove windows from master area +.It Cm stack_inc +Add columns/rows to stacking area +.It Cm stack_del +Remove columns/rows from stacking area +.It Cm swap_main +Move current window to master area +.It Cm focus_next +Focus next window in workspace +.It Cm focus_prev +Focus previous window in workspace +.It Cm focus_main +Focus on main window in workspace +.It Cm swap_next +Swap with next window in workspace +.It Cm swap_prev +Swap with previous window in workspace +.It Cm bar_toggle +Toggle status bar in all workspaces +.It Cm wind_del +Delete current window in workspace +.It Cm wind_kill +Destroy current window in workspace +.It Cm ws_ Ns Ar n +Switch to workspace +.Ar n , +where +.Ar n +is 1 through 10 +.It Cm mvws_ Ns Ar n +Move current window to workspace +.Ar n , +where +.Ar n +is 1 through 10 +.It Cm ws_next +Switch to next workspace with a window in it +.It Cm ws_prev +Switch to previous workspace with a window in it +.It Cm screen_next +Move pointer to next region +.It Cm screen_prev +Move pointer to previous region +.It Cm screenshot_all +Take screenshot of entire screen (if enabled) +.It Cm screenshot_wind +Take screenshot of selected window (if enabled) +.It Cm version +Toggle version in status bar +.It Cm float_toggle +Toggle focused window between tiled and floating +.It Cm spawn_lock +Lock screen +.It Cm spawn_initscr +Reinitialize physical screens +.El +.Pp +Custom bindings in the configuration file are specified as follows: +.Pp +.Dl bind[] = +.Pp +.Aq action +is one of the actions listed above (or empty) and +.Aq keys +is in the form of zero or more modifier keys +(MOD, Mod1, Shift, etc.) and one or more normal keys +(b, space, etc.), separated by "+". For example: +.Bd -literal -offset indent +bind[reset] = Mod4+q # bind Windows-key + q to reset +bind[] = Mod1+q # unbind Alt + q +.Ed +.Pp +Multiple key combinations may be bound to the same action. .Sh FILES .Bl -tag -width "/etc/scrotwm.confXXX" -compact .It Pa ~/.scrotwm.conf @@ -248,9 +362,10 @@ was inspired by xmonad & dwm. .Pp .Nm was written by -.An Marco Peereboom Aq marco@peereboom.us +.An Marco Peereboom Aq marco@peereboom.us , +.An Ryan Thomas McBride Aq mcbride@countersiege.com and -.An Ryan Thomas McBride Aq mcbride@countersiege.com . +.An Darrin Chandler Aq dwchandler@stilyagin.com . .Sh BUGS Currently the menu, invoked with .Cm M-p , diff --git a/scrotwm.c b/scrotwm.c index 12b4265..c86a6cc 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2009 Marco Peereboom * Copyright (c) 2009 Ryan McBride + * Copyright (c) 2009 Darrin Chandler * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -105,6 +106,7 @@ static const char *cvstag = "$scrotwm$"; #define SWM_D_MOUSE 0x0040 #define SWM_D_PROP 0x0080 #define SWM_D_CLASS 0x0100 +#define SWM_D_KEY 0x0200 u_int32_t swm_debug = 0 | SWM_D_MISC @@ -116,6 +118,7 @@ u_int32_t swm_debug = 0 | SWM_D_MOUSE | SWM_D_PROP | SWM_D_CLASS + | SWM_D_KEY ; #else #define DPRINTF(x...) @@ -128,6 +131,8 @@ u_int32_t swm_debug = 0 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define SWM_PROPLEN (16) +#define SWM_FUNCNAME_LEN (32) +#define SWM_KEYS_LEN (255) #define X(r) (r)->g.x #define Y(r) (r)->g.y #define WIDTH(r) (r)->g.w @@ -241,6 +246,62 @@ struct ws_win { }; TAILQ_HEAD(ws_win_list, ws_win); +/* user/key callable function IDs */ +enum keyfuncid { + kf_cycle_layout, + kf_stack_reset, + kf_master_shrink, + kf_master_grow, + kf_master_add, + kf_master_del, + kf_stack_inc, + kf_stack_dec, + kf_swap_main, + kf_focus_next, + kf_focus_prev, + kf_swap_next, + kf_swap_prev, + kf_spawn_term, + kf_spawn_menu, + kf_quit, + kf_restart, + kf_focus_main, + kf_ws_1, + kf_ws_2, + kf_ws_3, + kf_ws_4, + kf_ws_5, + kf_ws_6, + kf_ws_7, + kf_ws_8, + kf_ws_9, + kf_ws_10, + kf_ws_next, + kf_ws_prev, + kf_screen_next, + kf_screen_prev, + kf_mvws_1, + kf_mvws_2, + kf_mvws_3, + kf_mvws_4, + kf_mvws_5, + kf_mvws_6, + kf_mvws_7, + kf_mvws_8, + kf_mvws_9, + kf_mvws_10, + kf_bar_toggle, + kf_wind_kill, + kf_wind_del, + kf_screenshot_all, + kf_screenshot_wind, + kf_float_toggle, + kf_version, + kf_spawn_lock, + kf_spawn_initscr, + kf_invalid +}; + /* layout handlers */ void stack(void); void vertical_config(struct workspace *, int); @@ -252,6 +313,10 @@ void max_stack(struct workspace *, struct swm_geometry *); void grabbuttons(struct ws_win *, int); void new_region(struct swm_screen *, int, int, int, int); void update_modkey(unsigned int); +/* user functions / key binding */ +int bindmatch(const char *var, const char *name, unsigned int currmod, char *keystr, + enum keyfuncid *kfid, unsigned int *mod, KeySym *ks); +void setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid); struct layout { void (*l_stack)(struct workspace *, struct swm_geometry *); @@ -506,7 +571,9 @@ conf_load(char *filename) char *line, *cp, *var, *val; size_t len, lineno = 0; int i, sc; - unsigned int modkey; + unsigned int modkey = MODKEY, modmask; + KeySym ks; + enum keyfuncid kfid; DNPRINTF(SWM_D_MISC, "conf_load: filename %s\n", filename); @@ -550,6 +617,9 @@ conf_load(char *filename) asprintf(&bar_argv[0], "%s", val); else if (!strncmp(var, "bar_delay", strlen("bar_delay"))) bar_delay = atoi(val); + else if (!bindmatch(var, "bind", modkey, val, + &kfid, &modmask, &ks)) + setkeybinding(modmask, ks, kfid); else goto bad; break; @@ -1893,69 +1963,6 @@ floating_toggle(struct swm_region *r, union arg *args) focus_win(win); } -/* key definitions */ -struct key { - unsigned int mod; - KeySym keysym; - void (*func)(struct swm_region *r, union arg *); - union arg args; -} keys[] = { - /* modifier key function argument */ - { MODKEY, XK_space, cycle_layout, {0} }, - { MODKEY | ShiftMask, XK_space, stack_config, {.id = SWM_ARG_ID_STACKRESET} }, - { MODKEY, XK_h, stack_config, {.id = SWM_ARG_ID_MASTERSHRINK} }, - { MODKEY, XK_l, stack_config, {.id = SWM_ARG_ID_MASTERGROW} }, - { MODKEY, XK_comma, stack_config, {.id = SWM_ARG_ID_MASTERADD} }, - { MODKEY, XK_period, stack_config, {.id = SWM_ARG_ID_MASTERDEL} }, - { MODKEY | ShiftMask, XK_comma, stack_config, {.id = SWM_ARG_ID_STACKINC} }, - { MODKEY | ShiftMask, XK_period, stack_config, {.id = SWM_ARG_ID_STACKDEC} }, - { MODKEY, XK_Return, swapwin, {.id = SWM_ARG_ID_SWAPMAIN} }, - { MODKEY, XK_j, focus, {.id = SWM_ARG_ID_FOCUSNEXT} }, - { MODKEY, XK_k, focus, {.id = SWM_ARG_ID_FOCUSPREV} }, - { MODKEY | ShiftMask, XK_j, swapwin, {.id = SWM_ARG_ID_SWAPNEXT} }, - { MODKEY | ShiftMask, XK_k, swapwin, {.id = SWM_ARG_ID_SWAPPREV} }, - { MODKEY | ShiftMask, XK_Return, spawnterm, {.argv = spawn_term} }, - { MODKEY, XK_p, spawnmenu, {.argv = spawn_menu} }, - { MODKEY | ShiftMask, XK_q, quit, {0} }, - { MODKEY, XK_q, restart, {0} }, - { MODKEY, XK_m, focus, {.id = SWM_ARG_ID_FOCUSMAIN} }, - { MODKEY, XK_1, switchws, {.id = 0} }, - { MODKEY, XK_2, switchws, {.id = 1} }, - { MODKEY, XK_3, switchws, {.id = 2} }, - { MODKEY, XK_4, switchws, {.id = 3} }, - { MODKEY, XK_5, switchws, {.id = 4} }, - { MODKEY, XK_6, switchws, {.id = 5} }, - { MODKEY, XK_7, switchws, {.id = 6} }, - { MODKEY, XK_8, switchws, {.id = 7} }, - { MODKEY, XK_9, switchws, {.id = 8} }, - { MODKEY, XK_0, switchws, {.id = 9} }, - { MODKEY, XK_Right, cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP} }, - { MODKEY, XK_Left, cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN} }, - { MODKEY | ShiftMask, XK_Right, cyclescr, {.id = SWM_ARG_ID_CYCLESC_UP} }, - { MODKEY | ShiftMask, XK_Left, cyclescr, {.id = SWM_ARG_ID_CYCLESC_DOWN} }, - { MODKEY | ShiftMask, XK_1, send_to_ws, {.id = 0} }, - { MODKEY | ShiftMask, XK_2, send_to_ws, {.id = 1} }, - { MODKEY | ShiftMask, XK_3, send_to_ws, {.id = 2} }, - { MODKEY | ShiftMask, XK_4, send_to_ws, {.id = 3} }, - { MODKEY | ShiftMask, XK_5, send_to_ws, {.id = 4} }, - { MODKEY | ShiftMask, XK_6, send_to_ws, {.id = 5} }, - { MODKEY | ShiftMask, XK_7, send_to_ws, {.id = 6} }, - { MODKEY | ShiftMask, XK_8, send_to_ws, {.id = 7} }, - { MODKEY | ShiftMask, XK_9, send_to_ws, {.id = 8} }, - { MODKEY | ShiftMask, XK_0, send_to_ws, {.id = 9} }, - { MODKEY, XK_b, bar_toggle, {0} }, - { MODKEY, XK_Tab, focus, {.id = SWM_ARG_ID_FOCUSNEXT} }, - { MODKEY | ShiftMask, XK_Tab, focus, {.id = SWM_ARG_ID_FOCUSPREV} }, - { MODKEY | ShiftMask, XK_x, wkill, {.id = SWM_ARG_ID_KILLWINDOW} }, - { MODKEY, XK_x, wkill, {.id = SWM_ARG_ID_DELETEWINDOW} }, - { MODKEY, XK_s, screenshot, {.id = SWM_ARG_ID_SS_ALL} }, - { MODKEY | ShiftMask, XK_s, screenshot, {.id = SWM_ARG_ID_SS_WINDOW} }, - { MODKEY, XK_t, floating_toggle,{0} }, - { MODKEY | ShiftMask, XK_v, version, {0} }, - { MODKEY | ShiftMask, XK_Delete, spawn, {.argv = spawn_lock} }, - { MODKEY | ShiftMask, XK_i, spawn, {.argv = spawn_initscr} }, -}; - void resize_window(struct ws_win *win, int center) { @@ -2111,6 +2118,73 @@ move(struct ws_win *win, union arg *args) while (XCheckMaskEvent(display, EnterWindowMask, &ev)); } +/* key definitions */ +struct keyfunc { + char name[SWM_FUNCNAME_LEN]; + void (*func)(struct swm_region *r, union arg *); + union arg args; +} keyfuncs[kf_invalid] = { + /* name function argument */ + { "cycle_layout", cycle_layout, {0} }, + { "stack_reset", stack_config, {.id = SWM_ARG_ID_STACKRESET} }, + { "master_shrink", stack_config, {.id = SWM_ARG_ID_MASTERSHRINK} }, + { "master_grow", stack_config, {.id = SWM_ARG_ID_MASTERGROW} }, + { "master_add", stack_config, {.id = SWM_ARG_ID_MASTERADD} }, + { "master_del", stack_config, {.id = SWM_ARG_ID_MASTERDEL} }, + { "stack_inc", stack_config, {.id = SWM_ARG_ID_STACKINC} }, + { "stack_dec", stack_config, {.id = SWM_ARG_ID_STACKDEC} }, + { "swap_main", swapwin, {.id = SWM_ARG_ID_SWAPMAIN} }, + { "focus_next", focus, {.id = SWM_ARG_ID_FOCUSNEXT} }, + { "focus_prev", focus, {.id = SWM_ARG_ID_FOCUSPREV} }, + { "swap_next", swapwin, {.id = SWM_ARG_ID_SWAPNEXT} }, + { "swap_prev", swapwin, {.id = SWM_ARG_ID_SWAPPREV} }, + { "spawn_term", spawnterm, {.argv = spawn_term} }, + { "spawn_menu", spawnmenu, {.argv = spawn_menu} }, + { "quit", quit, {0} }, + { "restart", restart, {0} }, + { "focus_main", focus, {.id = SWM_ARG_ID_FOCUSMAIN} }, + { "ws_1", switchws, {.id = 0} }, + { "ws_2", switchws, {.id = 1} }, + { "ws_3", switchws, {.id = 2} }, + { "ws_4", switchws, {.id = 3} }, + { "ws_5", switchws, {.id = 4} }, + { "ws_6", switchws, {.id = 5} }, + { "ws_7", switchws, {.id = 6} }, + { "ws_8", switchws, {.id = 7} }, + { "ws_9", switchws, {.id = 8} }, + { "ws_10", switchws, {.id = 9} }, + { "ws_next", cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP} }, + { "ws_prev", cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN} }, + { "screen_next", cyclescr, {.id = SWM_ARG_ID_CYCLESC_UP} }, + { "screen_prev", cyclescr, {.id = SWM_ARG_ID_CYCLESC_DOWN} }, + { "mvws_1", send_to_ws, {.id = 0} }, + { "mvws_2", send_to_ws, {.id = 1} }, + { "mvws_3", send_to_ws, {.id = 2} }, + { "mvws_4", send_to_ws, {.id = 3} }, + { "mvws_5", send_to_ws, {.id = 4} }, + { "mvws_6", send_to_ws, {.id = 5} }, + { "mvws_7", send_to_ws, {.id = 6} }, + { "mvws_8", send_to_ws, {.id = 7} }, + { "mvws_9", send_to_ws, {.id = 8} }, + { "mvws_10", send_to_ws, {.id = 9} }, + { "bar_toggle", bar_toggle, {0} }, + { "wind_kill", wkill, {.id = SWM_ARG_ID_KILLWINDOW} }, + { "wind_del", wkill, {.id = SWM_ARG_ID_DELETEWINDOW} }, + { "screenshot_all", screenshot, {.id = SWM_ARG_ID_SS_ALL} }, + { "screenshot_wind", screenshot, {.id = SWM_ARG_ID_SS_WINDOW} }, + { "float_toggle", floating_toggle,{0} }, + { "version", version, {0} }, + { "spawn_lock", spawn, {.argv = spawn_lock} }, + { "spawn_initscr", spawn, {.argv = spawn_initscr} }, +}; +struct key { + unsigned int mod; + KeySym keysym; + enum keyfuncid funcid; +}; +int keys_size = 0, keys_length = 0; +struct key *keys = NULL; + /* mouse */ enum { client_click, root_click }; struct button { @@ -2131,7 +2205,7 @@ update_modkey(unsigned int mod) { int i; - for (i = 0; i < LENGTH(keys); i++) + for (i = 0; i < keys_length; i++) if (keys[i].mod & ShiftMask) keys[i].mod = mod | ShiftMask; else @@ -2144,6 +2218,205 @@ update_modkey(unsigned int mod) buttons[i].mask = mod; } +#define SWM_MODNAME_SIZE 32 +#define SWM_KEY_WS "\n+ \t" +int +parsekeys(char *keystr, unsigned int currmod, unsigned int *mod, KeySym *ks) +{ + char *cp, *name; + KeySym uks; + if (mod == NULL || ks == NULL) + return (0); + cp = keystr; + *mod = 0; + while ((name = strsep(&cp, SWM_KEY_WS)) != NULL) { + if (cp) + cp += (long)strspn(cp, SWM_KEY_WS); + if (strncasecmp(name, "MOD", SWM_MODNAME_SIZE) == 0) + *mod |= currmod; + else if (!strncasecmp(name, "Mod1", SWM_MODNAME_SIZE)) + *mod |= Mod1Mask; + else if (!strncasecmp(name, "Mod2", SWM_MODNAME_SIZE)) + *mod += Mod2Mask; + else if (!strncmp(name, "Mod3", SWM_MODNAME_SIZE)) + *mod |= Mod3Mask; + else if (!strncmp(name, "Mod4", SWM_MODNAME_SIZE)) + *mod |= Mod4Mask; + else if (strncasecmp(name, "SHIFT", SWM_MODNAME_SIZE) == 0) + *mod |= ShiftMask; + else { + *ks = XStringToKeysym(name); + XConvertCase(*ks, ks, &uks); + if (ks == NoSymbol) { + DNPRINTF(SWM_D_KEY, + "parsekeys: invalid key %s\n", + name); + return (0); + } + } + } + return (1); +} +int +bindmatch(const char *var, const char *name, unsigned int currmod, char *keystr, + enum keyfuncid *kfid, unsigned int *mod, KeySym *ks) +{ + char *p; + int i; + char funcname[SWM_FUNCNAME_LEN]; + i = strncmp(var, name, 255); + if (kfid == NULL || mod == NULL || ks == NULL) + return (i); + *kfid = kf_invalid; + *mod = 0; + *ks = NoSymbol; + bzero(funcname, LENGTH(funcname)); + if (i <= 0) + return (i); + p = (char *)var + strlen(name); + if (*p++ != '[') + return (i); + i = 0; + while (isgraph(*p) && *p != ']' && i < LENGTH(funcname)) + funcname[i++] = *p++; + if (i >= LENGTH(funcname) || *p != ']') + return (1); + if (i == 0) + return (!parsekeys(keystr, currmod, mod, ks)); + for (*kfid = 0; *kfid < kf_invalid; (*kfid)++) { + if (strncasecmp(funcname, keyfuncs[*kfid].name, + SWM_FUNCNAME_LEN) == 0) { + return (!parsekeys(keystr, currmod, mod, ks)); + } + + } + return (1); +} +void +setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid) +{ + int i, j; + /* find existing */ + for (i = 0; i < keys_length; i++) { + if (keys[i].mod == mod && keys[i].keysym == ks) { + if (kfid == kf_invalid) { + /* found: delete */ + DNPRINTF(SWM_D_KEY, + "setkeybinding: delete #%d %s\n", + i, keyfuncs[keys[i].funcid].name); + j = keys_length - 1; + if (i < j) + keys[i] = keys[j]; + keys_length--; + return; + } else { + /* found: replace */ + DNPRINTF(SWM_D_KEY, + "setkeybinding: replace #%d %s\n", + i, keyfuncs[keys[i].funcid].name); + keys[i].mod = mod; + keys[i].keysym = ks; + keys[i].funcid = kfid; + return; + } + } + } + if (kfid == kf_invalid) { + fprintf(stderr, + "error: setkeybinding: cannot find mod/key combination"); + return; + } + /* not found: add */ + if (keys_size == 0 || keys == NULL) { + keys_size = 4; + DNPRINTF(SWM_D_KEY, "setkeybinding: init list %d\n", keys_size); + keys = malloc((size_t)keys_size * sizeof(struct key)); + if (!keys) { + fprintf(stderr, "malloc failed\n"); + perror(" failed"); + quit(NULL, NULL); + } + } else if (keys_length == keys_size) { + keys_size *= 2; + DNPRINTF(SWM_D_KEY, "setkeybinding: grow list %d\n", keys_size); + keys = realloc(keys, (size_t)keys_size * sizeof(struct key)); + if (!keys) { + fprintf(stderr, "realloc failed\n"); + perror(" failed"); + quit(NULL, NULL); + } + } + if (keys_length < keys_size) { + DNPRINTF(SWM_D_KEY, "setkeybinding: add %d\n", keys_length); + j = keys_length++; + keys[j].mod = mod; + keys[j].keysym = ks; + keys[j].funcid = kfid; + } else { + fprintf(stderr, "keys array problem?\n"); + if (!keys) { + fprintf(stderr, "keys array problem\n"); + quit(NULL, NULL); + } + } +} +void +setup_keys(void) +{ + setkeybinding(MODKEY, XK_space, kf_cycle_layout); + setkeybinding(MODKEY|ShiftMask, XK_space, kf_stack_reset); + setkeybinding(MODKEY, XK_h, kf_master_shrink); + setkeybinding(MODKEY, XK_l, kf_master_grow); + setkeybinding(MODKEY, XK_comma, kf_master_add); + setkeybinding(MODKEY, XK_period, kf_master_del); + setkeybinding(MODKEY|ShiftMask, XK_comma, kf_stack_inc); + setkeybinding(MODKEY|ShiftMask, XK_period, kf_stack_dec); + setkeybinding(MODKEY, XK_Return, kf_swap_main); + setkeybinding(MODKEY, XK_j, kf_focus_next); + setkeybinding(MODKEY, XK_k, kf_focus_prev); + setkeybinding(MODKEY|ShiftMask, XK_j, kf_swap_next); + setkeybinding(MODKEY|ShiftMask, XK_k, kf_swap_next); + setkeybinding(MODKEY|ShiftMask, XK_Return, kf_spawn_term); + setkeybinding(MODKEY, XK_p, kf_spawn_menu); + setkeybinding(MODKEY|ShiftMask, XK_q, kf_quit); + setkeybinding(MODKEY, XK_q, kf_restart); + setkeybinding(MODKEY, XK_m, kf_focus_main); + setkeybinding(MODKEY, XK_1, kf_ws_1); + setkeybinding(MODKEY, XK_2, kf_ws_2); + setkeybinding(MODKEY, XK_3, kf_ws_3); + setkeybinding(MODKEY, XK_4, kf_ws_4); + setkeybinding(MODKEY, XK_5, kf_ws_5); + setkeybinding(MODKEY, XK_6, kf_ws_6); + setkeybinding(MODKEY, XK_7, kf_ws_7); + setkeybinding(MODKEY, XK_8, kf_ws_8); + setkeybinding(MODKEY, XK_9, kf_ws_9); + setkeybinding(MODKEY, XK_0, kf_ws_10); + setkeybinding(MODKEY, XK_Right, kf_ws_next); + setkeybinding(MODKEY, XK_Left, kf_ws_prev); + setkeybinding(MODKEY|ShiftMask, XK_Right, kf_screen_next); + setkeybinding(MODKEY|ShiftMask, XK_Left, kf_screen_prev); + setkeybinding(MODKEY|ShiftMask, XK_1, kf_mvws_1); + setkeybinding(MODKEY|ShiftMask, XK_2, kf_mvws_2); + setkeybinding(MODKEY|ShiftMask, XK_3, kf_mvws_3); + setkeybinding(MODKEY|ShiftMask, XK_4, kf_mvws_4); + setkeybinding(MODKEY|ShiftMask, XK_5, kf_mvws_5); + setkeybinding(MODKEY|ShiftMask, XK_6, kf_mvws_6); + setkeybinding(MODKEY|ShiftMask, XK_7, kf_mvws_7); + setkeybinding(MODKEY|ShiftMask, XK_8, kf_mvws_8); + setkeybinding(MODKEY|ShiftMask, XK_9, kf_mvws_9); + setkeybinding(MODKEY|ShiftMask, XK_0, kf_mvws_10); + setkeybinding(MODKEY, XK_b, kf_bar_toggle); + setkeybinding(MODKEY, XK_Tab, kf_focus_next); + setkeybinding(MODKEY|ShiftMask, XK_Tab, kf_focus_prev); + setkeybinding(MODKEY|ShiftMask, XK_x, kf_wind_kill); + setkeybinding(MODKEY, XK_x, kf_wind_del); + setkeybinding(MODKEY, XK_s, kf_screenshot_all); + setkeybinding(MODKEY|ShiftMask, XK_s, kf_screenshot_wind); + setkeybinding(MODKEY, XK_t, kf_float_toggle); + setkeybinding(MODKEY|ShiftMask, XK_v, kf_version); + setkeybinding(MODKEY|ShiftMask, XK_Delete, kf_spawn_lock); + setkeybinding(MODKEY|ShiftMask, XK_i, kf_spawn_initscr); +} void updatenumlockmask(void) { @@ -2177,7 +2450,7 @@ grabkeys(void) if (TAILQ_EMPTY(&screens[k].rl)) continue; XUngrabKey(display, AnyKey, AnyModifier, screens[k].root); - for (i = 0; i < LENGTH(keys); i++) { + for (i = 0; i < keys_length; i++) { if ((code = XKeysymToKeycode(display, keys[i].keysym))) for (j = 0; j < LENGTH(modifiers); j++) XGrabKey(display, code, @@ -2227,12 +2500,14 @@ keypress(XEvent *e) DNPRINTF(SWM_D_EVENT, "keypress: window: %lu\n", ev->window); keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0); - for (i = 0; i < LENGTH(keys); i++) + for (i = 0; i < keys_length; i++) if (keysym == keys[i].keysym && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) - && keys[i].func) - keys[i].func(root_to_region(ev->root), - &(keys[i].args)); + && keyfuncs[keys[i].funcid].func) + keyfuncs[keys[i].funcid].func( + root_to_region(ev->root), + &(keyfuncs[keys[i].funcid].args) + ); } void @@ -3041,6 +3316,7 @@ main(int argc, char *argv[]) errx(1, "invalid user %d", getuid()); setup_screens(); + setup_keys(); snprintf(conf, sizeof conf, "%s/.%s", pwd->pw_dir, SWM_CONF_FILE); if (stat(conf, &sb) != -1) { diff --git a/scrotwm.conf b/scrotwm.conf index 765dfd1..50e4f82 100644 --- a/scrotwm.conf +++ b/scrotwm.conf @@ -31,3 +31,59 @@ dialog_ratio = 0.6 # mod key, (windows key is Mod4) # modkey = Mod1 + +# key bindings +# unbind with: bind[] = +#bind[cycle_layout] = MOD+space +#bind[stack_reset] = MOD+Shift+space +#bind[master_shrink] = MOD+h +#bind[master_grow] = MOD+l +#bind[master_add] = MOD+comma +#bind[master_del] = MOD+period +#bind[stack_inc] = MOD+Shift+comma +#bind[stack_dec] = MOD+Shift+period +#bind[swap_main] = MOD+Return +#bind[focus_next] = MOD+j +#bind[focus_prev] = MOD+k +#bind[swap_next] = MOD+Shift+j +#bind[swap_prev] = MOD+Shift+k +#bind[spawn_term] = MOD+Shift+Return +#bind[spawn_menu] = MOD+p +#bind[quit] = MOD+Shift+q +#bind[restart] = MOD+q +#bind[focus_main] = MOD+m +#bind[ws_1] = MOD+1 +#bind[ws_2] = MOD+2 +#bind[ws_3] = MOD+3 +#bind[ws_4] = MOD+4 +#bind[ws_5] = MOD+5 +#bind[ws_6] = MOD+6 +#bind[ws_7] = MOD+7 +#bind[ws_8] = MOD+8 +#bind[ws_9] = MOD+9 +#bind[ws_10] = MOD+0 +#bind[ws_next] = MOD+Right +#bind[ws_prev] = MOD+Left +#bind[screen_next] = MOD+Shift+Right +#bind[screen_prev] = MOD+Shift+Left +#bind[mvws_1] = MOD+Shift+1 +#bind[mvws_2] = MOD+Shift+2 +#bind[mvws_3] = MOD+Shift+3 +#bind[mvws_4] = MOD+Shift+4 +#bind[mvws_5] = MOD+Shift+5 +#bind[mvws_6] = MOD+Shift+6 +#bind[mvws_7] = MOD+Shift+7 +#bind[mvws_8] = MOD+Shift+8 +#bind[mvws_9] = MOD+Shift+9 +#bind[mvws_10] = MOD+Shift+0 +#bind[bar_toggle] = MOD+b +#bind[focus_next] = MOD+Tab +#bind[focus_prev] = MOD+Shift+Tab +#bind[wind_kill] = MOD+Shift+x +#bind[wind_del] = MOD+x +#bind[screenshot_all] = MOD+s +#bind[screenshot_wind] = MOD+Shift+s +#bind[float_toggle] = MOD+t +#bind[version] = MOD+Shift+v +#bind[spawn_lock] = MOD+Shift+Delete +#bind[spawn_initscr] = MOD+Shift+i -- 1.7.10.4