commit bab7d06386deefc481785911e5a9eb240dce9a51
Author: Tonton Couillon <[email protected]>
Date:   Tue Jun 19 14:56:11 2018 +0200

    This patch allows you to select and copy text to primary buffer with
    keyboard shortcuts like the perl extension keyboard-select for urxvt.

diff --git 
a/st.suckless.org/patches/keyboard_select/git-st-keyboard_select-20180619-937e367.diff
 
b/st.suckless.org/patches/keyboard_select/git-st-keyboard_select-20180619-937e367.diff
new file mode 100644
index 00000000..55f77095
--- /dev/null
+++ 
b/st.suckless.org/patches/keyboard_select/git-st-keyboard_select-20180619-937e367.diff
@@ -0,0 +1,319 @@
+diff --git a/a/config.def.h b/b/config.def.h
+index 82b1b09..cdfbdc9 100644
+--- a/a/config.def.h
++++ b/b/config.def.h
+@@ -178,6 +178,7 @@ static Shortcut shortcuts[] = {
+       { TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
+       { TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
+       { TERMMOD,              XK_I,           iso14755,       {.i =  0} },
++      { TERMMOD,              XK_Escape,      keyboard_select,{ 0 } },
+ };
+ 
+ /*
+diff --git a/a/st.c b/b/st.c
+index 76bb3ea..8a0d448 100644
+--- a/a/st.c
++++ b/b/st.c
+@@ -16,6 +16,8 @@
+ #include <termios.h>
+ #include <unistd.h>
+ #include <wchar.h>
++#include <X11/keysym.h>
++#include <X11/X.h>
+ 
+ #include "st.h"
+ #include "win.h"
+@@ -2504,6 +2506,9 @@ tresize(int col, int row)
+       int *bp;
+       TCursor c;
+ 
++      if ( row < term.row  || col < term.col )
++        toggle_winmode(trt_kbdselect(XK_Escape, NULL, 0));
++
+       if (col < 1 || row < 1) {
+               fprintf(stderr,
+                       "tresize: error resizing to %dx%d
", col, row);
+@@ -2625,3 +2630,220 @@ redraw(void)
+       tfulldirt();
+       draw();
+ }
++
++void set_notifmode(int type, KeySym ksym) {
++    static char *lib[] = { " MOVE ", " SEL  "};
++    static Glyph *g, *deb, *fin;
++    static int col, bot;
++
++    if ( ksym == -1 ) {
++        free(g);
++        col = term.col, bot = term.bot;
++        g = xmalloc(col * sizeof(Glyph));
++        memcpy(g, term.line[bot], col * sizeof(Glyph));
++    
++    }
++    else if ( ksym == -2 )
++        memcpy(term.line[bot], g, col * sizeof(Glyph));
++
++    if ( type < 2 ) {
++        char *z = lib[type];
++        for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb 
< fin; z++, deb++)
++            deb->mode = ATTR_REVERSE,
++            deb->u = *z,
++            deb->fg = defaultfg, deb->bg = defaultbg;
++    }
++    else if ( type < 5 )
++        memcpy(term.line[bot], g, col * sizeof(Glyph));
++    else {
++        for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; 
deb++)
++            deb->mode = ATTR_REVERSE,
++            deb->u = ' ',
++            deb->fg = defaultfg, deb->bg = defaultbg;
++        term.line[bot][0].u = ksym;
++    }
++
++    term.dirty[bot] = 1;
++    drawregion(0, bot, col, bot + 1);
++}
++
++void select_or_drawcursor(int selectsearch_mode, int type) {
++    int done = 0;
++
++    if ( selectsearch_mode & 1 ) {
++        selextend(term.c.x, term.c.y, type, done);
++        xsetsel(getsel());
++    }
++    else
++        xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x],
++                    term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
++}
++
++void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int 
type, TCursor *cu) {
++    Rune *r;
++    int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr;
++
++    for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) {
++        for (r = target; r - target < ptarget; r++) {
++            if ( *r == term.line[(i + r - target) / term.col][(i + r - 
target) % term.col].u ) {
++                if ( r - target == ptarget - 1 )     break;
++            } else {
++                r = NULL;
++                break;
++            }
++        }
++        if ( r != NULL )    break;
++    }
++        
++    if ( i != bound ) {
++        term.c.y = i / term.col, term.c.x = i % term.col;
++        select_or_drawcursor(selectsearch_mode, type);
++    }
++}
++
++int trt_kbdselect(KeySym ksym, char *buf, int len) {
++    static TCursor cu;
++    static Rune target[64];
++    static int type = 1, ptarget, in_use;
++    static int sens, quant;
++    static char selectsearch_mode;
++    int i, bound, *xy;
++    
++    
++    if ( selectsearch_mode & 2 ) {
++              if ( ksym == XK_Return ) {
++                      selectsearch_mode ^= 2;
++                      set_notifmode(selectsearch_mode, -2);
++            if ( ksym == XK_Escape )    ptarget = 0;
++                      return 0;
++              }
++        else if ( ksym == XK_BackSpace ) {
++            if ( !ptarget )     return 0;
++            term.line[term.bot][ptarget--].u = ' ';
++              }
++        else if ( len < 1 ) {
++                      return 0;
++              }
++        else if ( ptarget == term.col  || ksym == XK_Escape ) {
++            return 0;
++        }
++              else {
++            utf8decode(buf, &target[ptarget++], len);
++            term.line[term.bot][ptarget].u = target[ptarget - 1];
++              }
++
++        if ( ksym != XK_BackSpace )
++            search(selectsearch_mode, &target[0], ptarget, sens, type, &cu);
++
++        term.dirty[term.bot] = 1; 
++        drawregion(0, term.bot, term.col, term.bot + 1);
++        return 0;
++    }
++
++    switch ( ksym ) {
++    case -1 :
++        in_use = 1;
++        cu.x = term.c.x, cu.y = term.c.y;
++        set_notifmode(0, ksym);
++        return MODE_KBDSELECT;
++    case XK_s :
++        if ( selectsearch_mode & 1 )
++            selclear();
++        else
++            selstart(term.c.x, term.c.y, 0);
++        set_notifmode(selectsearch_mode ^= 1, ksym);
++        break;
++    case XK_t :
++        selextend(term.c.x, term.c.y, type ^= 3, i = 0);  /* 2 fois */
++        selextend(term.c.x, term.c.y, type, i = 0);
++        break;
++    case XK_slash :
++    case XK_KP_Divide :
++    case XK_question :
++        ksym &= XK_question;                /* Divide to slash */
++        sens = (ksym == XK_slash) ? -1 : 1;
++        ptarget = 0;
++        set_notifmode(15, ksym);
++        selectsearch_mode ^= 2;
++        break;
++    case XK_Escape :
++        if ( !in_use )  break;
++        selclear();
++    case XK_Return :
++        set_notifmode(4, ksym);
++        term.c.x = cu.x, term.c.y = cu.y;
++        select_or_drawcursor(selectsearch_mode = 0, type);
++        in_use = quant = 0;
++        return MODE_KBDSELECT;
++    case XK_n :
++    case XK_N :
++        if ( ptarget )
++            search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? 
-1 : 1, type, &cu);
++        break;
++    case XK_BackSpace :
++        term.c.x = 0;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    case XK_dollar :
++        term.c.x = term.col - 1;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    case XK_Home :
++        term.c.x = 0, term.c.y = 0;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    case XK_End :
++        term.c.x = cu.x, term.c.y = cu.y;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    case XK_Page_Up :
++    case XK_Page_Down :
++        term.c.y = (ksym == XK_Prior ) ? 0 : cu.y;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    case XK_exclam :
++        term.c.x = term.col >> 1;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    case XK_asterisk :
++    case XK_KP_Multiply :
++        term.c.x = term.col >> 1;
++    case XK_underscore :
++        term.c.y = cu.y >> 1;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    default :
++        if ( ksym >= XK_0 && ksym <= XK_9 ) {               /* 0-9 keyboard */
++            quant = (quant * 10) + (ksym ^ XK_0);
++            return 0;
++        }
++        else if ( ksym >= XK_KP_0 && ksym <= XK_KP_9 ) {    /* 0-9 numpad */
++            quant = (quant * 10) + (ksym ^ XK_KP_0);
++            return 0;
++        }
++        else if ( ksym == XK_k || ksym == XK_h )
++            i = ksym & 1;
++        else if ( ksym == XK_l || ksym == XK_j )
++            i = ((ksym & 6) | 4) >> 1;
++        else if ( (XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 
3 )
++            break;
++
++        xy = (i & 1) ? &term.c.y : &term.c.x;
++        sens = (i & 2) ? 1 : -1;
++        bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot;
++
++        if ( quant == 0 )
++            quant++;
++
++        if ( *xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound 
> 0)) )
++            break;
++
++        *xy += quant * sens;
++        if ( *xy < 0 || ( bound > 0 && *xy > bound) )
++            *xy = bound;
++
++        select_or_drawcursor(selectsearch_mode, type);
++    }
++    quant = 0;
++    return 0;
++}
+diff --git a/a/st.h b/b/st.h
+index dac64d8..d6693bf 100644
+--- a/a/st.h
++++ b/b/st.h
+@@ -110,6 +110,7 @@ size_t utf8encode(Rune, char *);
+ void *xmalloc(size_t);
+ void *xrealloc(void *, size_t);
+ char *xstrdup(char *);
++int trt_kbdselect(KeySym, char *, int);
+ 
+ /* config.h globals */
+ extern char *utmp;
+diff --git a/a/win.h b/b/win.h
+index 31f327d..75a2756 100644
+--- a/a/win.h
++++ b/b/win.h
+@@ -21,6 +21,7 @@ enum win_mode {
+       MODE_NUMLOCK     = 1 << 17,
+       MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
+                         |MODE_MOUSEMANY,
++      MODE_KBDSELECT   = 1 << 18,
+ };
+ 
+ void xbell(void);
+@@ -36,3 +37,5 @@ void xsetmode(int, unsigned int);
+ void xsetpointermotion(int);
+ void xsetsel(char *);
+ int xstartdraw(void);
++void toggle_winmode(int);
++void keyboard_select(const Arg *);
+diff --git a/a/x.c b/b/x.c
+index c0bd890..39e2984 100644
+--- a/a/x.c
++++ b/b/x.c
+@@ -1695,6 +1695,13 @@ kpress(XEvent *ev)
+               return;
+ 
+       len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
++    if ( IS_SET(MODE_KBDSELECT) ) {
++              if ( match(XK_NO_MOD, e->state) ||
++            (XK_Shift_L | XK_Shift_R) & e->state )
++            win.mode ^= trt_kbdselect(ksym, buf, len);
++              return;
++    }
++
+       /* 1. shortcuts */
+       for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
+               if (ksym == bp->keysym && match(bp->mod, e->state)) {
+@@ -1879,6 +1886,14 @@ usage(void)
+           " [stty_args ...]
", argv0, argv0);
+ }
+ 
++void toggle_winmode(int flag) {
++        win.mode ^= flag;
++}
++
++void keyboard_select(const Arg *dummy) {
++    win.mode ^= trt_kbdselect(-1, NULL, 0);
++}
++
+ int
+ main(int argc, char *argv[])
+ {
diff --git a/st.suckless.org/patches/keyboard_select/index.md 
b/st.suckless.org/patches/keyboard_select/index.md
new file mode 100644
index 00000000..be9c209e
--- /dev/null
+++ b/st.suckless.org/patches/keyboard_select/index.md
@@ -0,0 +1,65 @@
+keyboard_select
+===============
+
+Description
+-----------
+
+This patch allows you to select and copy text to primary buffer with keyboard
+shortcuts like the perl extension &ldquo;keyboard-select&rdquo; for urxvt.
+
+Instructions
+------------
+The patch changes the &ldquo;config.def.h&rdquo;. Delete your
+&ldquo;config.h&rdquo; or add the shortcut below if you use a custom one.
+
+    Shortcut shortcuts[] = {
+        ...
+        { TERMMOD, XK_Escape, keyboard_select, { 0 } },
+    };
+
+
+Notes
+-----
+
+When you run "keyboard_select", you have 3 modes available :
+
+* move mode :   to set the start of the selection;
+* select mode : to activate and set the end of the selection;
+* input mode :  to enter the search criteria.
+
+<br>
+
+Shortcuts for move and select modes :
+
+     h, j, k, l:    move cursor left/down/up/right (also with arrow keys)
+     !, _, *:       move cursor to the middle of the line/column/screen
+     Backspace, $:  move cursor to the beginning/end of the line
+     PgUp, PgDown : move cursor to the beginning/end of the column
+     Home, End:     move cursor to the top/bottom left corner of the screen
+     /, ?:          activate input mode and search up/down
+     n, N:          repeat last search, up/down
+     s:             toggle move/selection mode
+     t:             toggle regular/rectangular selection type
+     Return:        quit keyboard_select, keeping the highlight of the 
selection
+     Escape:        quit keyboard_select
+
+With h,j,k,l (also with arrow keys), you can use a quantifier. Enter a number 
before hitting the appropriate key.
+
+<br>
+
+Shortcuts for input mode :
+
+     Return:       Return to the previous mode
+
+
+
+Download
+--------
+
+ * 
[git-st-keyboard_select-20180619-937e367.diff](git-st-keyboard_select-20180619-937e367.diff)
   
+ * [st-keyboard_select-0.8.1.diff](st-keyboard_select-0.8.1.diff)
+
+
+Authors
+-------
+ * Tonton Couillon - &lt;la dot luge at free dot fr>
diff --git 
a/st.suckless.org/patches/keyboard_select/st-keyboard_select-0.8.1.diff 
b/st.suckless.org/patches/keyboard_select/st-keyboard_select-0.8.1.diff
new file mode 100644
index 00000000..cc2b9017
--- /dev/null
+++ b/st.suckless.org/patches/keyboard_select/st-keyboard_select-0.8.1.diff
@@ -0,0 +1,319 @@
+diff --git a/a/config.def.h b/b/config.def.h
+index 82b1b09..cdfbdc9 100644
+--- a/a/config.def.h
++++ b/b/config.def.h
+@@ -178,6 +178,7 @@ static Shortcut shortcuts[] = {
+       { TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
+       { TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
+       { TERMMOD,              XK_I,           iso14755,       {.i =  0} },
++      { TERMMOD,              XK_Escape,      keyboard_select,{ 0 } },
+ };
+ 
+ /*
+diff --git a/a/st.c b/b/st.c
+index 46c954b..1c07288 100644
+--- a/a/st.c
++++ b/b/st.c
+@@ -16,6 +16,8 @@
+ #include <termios.h>
+ #include <unistd.h>
+ #include <wchar.h>
++#include <X11/keysym.h>
++#include <X11/X.h>
+ 
+ #include "st.h"
+ #include "win.h"
+@@ -2495,6 +2497,9 @@ tresize(int col, int row)
+       int *bp;
+       TCursor c;
+ 
++      if ( row < term.row  || col < term.col )
++        toggle_winmode(trt_kbdselect(XK_Escape, NULL, 0));
++
+       if (col < 1 || row < 1) {
+               fprintf(stderr,
+                       "tresize: error resizing to %dx%d
", col, row);
+@@ -2616,3 +2621,220 @@ redraw(void)
+       tfulldirt();
+       draw();
+ }
++
++void set_notifmode(int type, KeySym ksym) {
++    static char *lib[] = { " MOVE ", " SEL  "};
++    static Glyph *g, *deb, *fin;
++    static int col, bot;
++
++    if ( ksym == -1 ) {
++        free(g);
++        col = term.col, bot = term.bot;
++        g = xmalloc(col * sizeof(Glyph));
++        memcpy(g, term.line[bot], col * sizeof(Glyph));
++    
++    }
++    else if ( ksym == -2 )
++        memcpy(term.line[bot], g, col * sizeof(Glyph));
++
++    if ( type < 2 ) {
++        char *z = lib[type];
++        for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb 
< fin; z++, deb++)
++            deb->mode = ATTR_REVERSE,
++            deb->u = *z,
++            deb->fg = defaultfg, deb->bg = defaultbg;
++    }
++    else if ( type < 5 )
++        memcpy(term.line[bot], g, col * sizeof(Glyph));
++    else {
++        for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; 
deb++)
++            deb->mode = ATTR_REVERSE,
++            deb->u = ' ',
++            deb->fg = defaultfg, deb->bg = defaultbg;
++        term.line[bot][0].u = ksym;
++    }
++
++    term.dirty[bot] = 1;
++    drawregion(0, bot, col, bot + 1);
++}
++
++void select_or_drawcursor(int selectsearch_mode, int type) {
++    int done = 0;
++
++    if ( selectsearch_mode & 1 ) {
++        selextend(term.c.x, term.c.y, type, done);
++        xsetsel(getsel());
++    }
++    else
++        xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x],
++                    term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
++}
++
++void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int 
type, TCursor *cu) {
++    Rune *r;
++    int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr;
++
++    for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) {
++        for (r = target; r - target < ptarget; r++) {
++            if ( *r == term.line[(i + r - target) / term.col][(i + r - 
target) % term.col].u ) {
++                if ( r - target == ptarget - 1 )     break;
++            } else {
++                r = NULL;
++                break;
++            }
++        }
++        if ( r != NULL )    break;
++    }
++        
++    if ( i != bound ) {
++        term.c.y = i / term.col, term.c.x = i % term.col;
++        select_or_drawcursor(selectsearch_mode, type);
++    }
++}
++
++int trt_kbdselect(KeySym ksym, char *buf, int len) {
++    static TCursor cu;
++    static Rune target[64];
++    static int type = 1, ptarget, in_use;
++    static int sens, quant;
++    static char selectsearch_mode;
++    int i, bound, *xy;
++    
++    
++    if ( selectsearch_mode & 2 ) {
++              if ( ksym == XK_Return ) {
++                      selectsearch_mode ^= 2;
++                      set_notifmode(selectsearch_mode, -2);
++            if ( ksym == XK_Escape )    ptarget = 0;
++                      return 0;
++              }
++        else if ( ksym == XK_BackSpace ) {
++            if ( !ptarget )     return 0;
++            term.line[term.bot][ptarget--].u = ' ';
++              }
++        else if ( len < 1 ) {
++                      return 0;
++              }
++        else if ( ptarget == term.col  || ksym == XK_Escape ) {
++            return 0;
++        }
++              else {
++            utf8decode(buf, &target[ptarget++], len);
++            term.line[term.bot][ptarget].u = target[ptarget - 1];
++              }
++
++        if ( ksym != XK_BackSpace )
++            search(selectsearch_mode, &target[0], ptarget, sens, type, &cu);
++
++        term.dirty[term.bot] = 1; 
++        drawregion(0, term.bot, term.col, term.bot + 1);
++        return 0;
++    }
++
++    switch ( ksym ) {
++    case -1 :
++        in_use = 1;
++        cu.x = term.c.x, cu.y = term.c.y;
++        set_notifmode(0, ksym);
++        return MODE_KBDSELECT;
++    case XK_s :
++        if ( selectsearch_mode & 1 )
++            selclear();
++        else
++            selstart(term.c.x, term.c.y, 0);
++        set_notifmode(selectsearch_mode ^= 1, ksym);
++        break;
++    case XK_t :
++        selextend(term.c.x, term.c.y, type ^= 3, i = 0);  /* 2 fois */
++        selextend(term.c.x, term.c.y, type, i = 0);
++        break;
++    case XK_slash :
++    case XK_KP_Divide :
++    case XK_question :
++        ksym &= XK_question;                /* Divide to slash */
++        sens = (ksym == XK_slash) ? -1 : 1;
++        ptarget = 0;
++        set_notifmode(15, ksym);
++        selectsearch_mode ^= 2;
++        break;
++    case XK_Escape :
++        if ( !in_use )  break;
++        selclear();
++    case XK_Return :
++        set_notifmode(4, ksym);
++        term.c.x = cu.x, term.c.y = cu.y;
++        select_or_drawcursor(selectsearch_mode = 0, type);
++        in_use = quant = 0;
++        return MODE_KBDSELECT;
++    case XK_n :
++    case XK_N :
++        if ( ptarget )
++            search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? 
-1 : 1, type, &cu);
++        break;
++    case XK_BackSpace :
++        term.c.x = 0;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    case XK_dollar :
++        term.c.x = term.col - 1;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    case XK_Home :
++        term.c.x = 0, term.c.y = 0;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    case XK_End :
++        term.c.x = cu.x, term.c.y = cu.y;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    case XK_Page_Up :
++    case XK_Page_Down :
++        term.c.y = (ksym == XK_Prior ) ? 0 : cu.y;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    case XK_exclam :
++        term.c.x = term.col >> 1;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    case XK_asterisk :
++    case XK_KP_Multiply :
++        term.c.x = term.col >> 1;
++    case XK_underscore :
++        term.c.y = cu.y >> 1;
++        select_or_drawcursor(selectsearch_mode, type);
++        break;
++    default :
++        if ( ksym >= XK_0 && ksym <= XK_9 ) {               /* 0-9 keyboard */
++            quant = (quant * 10) + (ksym ^ XK_0);
++            return 0;
++        }
++        else if ( ksym >= XK_KP_0 && ksym <= XK_KP_9 ) {    /* 0-9 numpad */
++            quant = (quant * 10) + (ksym ^ XK_KP_0);
++            return 0;
++        }
++        else if ( ksym == XK_k || ksym == XK_h )
++            i = ksym & 1;
++        else if ( ksym == XK_l || ksym == XK_j )
++            i = ((ksym & 6) | 4) >> 1;
++        else if ( (XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 
3 )
++            break;
++
++        xy = (i & 1) ? &term.c.y : &term.c.x;
++        sens = (i & 2) ? 1 : -1;
++        bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot;
++
++        if ( quant == 0 )
++            quant++;
++
++        if ( *xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound 
> 0)) )
++            break;
++
++        *xy += quant * sens;
++        if ( *xy < 0 || ( bound > 0 && *xy > bound) )
++            *xy = bound;
++
++        select_or_drawcursor(selectsearch_mode, type);
++    }
++    quant = 0;
++    return 0;
++}
+diff --git a/a/st.h b/b/st.h
+index dac64d8..d6693bf 100644
+--- a/a/st.h
++++ b/b/st.h
+@@ -110,6 +110,7 @@ size_t utf8encode(Rune, char *);
+ void *xmalloc(size_t);
+ void *xrealloc(void *, size_t);
+ char *xstrdup(char *);
++int trt_kbdselect(KeySym, char *, int);
+ 
+ /* config.h globals */
+ extern char *utmp;
+diff --git a/a/win.h b/b/win.h
+index 31f327d..75a2756 100644
+--- a/a/win.h
++++ b/b/win.h
+@@ -21,6 +21,7 @@ enum win_mode {
+       MODE_NUMLOCK     = 1 << 17,
+       MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
+                         |MODE_MOUSEMANY,
++      MODE_KBDSELECT   = 1 << 18,
+ };
+ 
+ void xbell(void);
+@@ -36,3 +37,5 @@ void xsetmode(int, unsigned int);
+ void xsetpointermotion(int);
+ void xsetsel(char *);
+ int xstartdraw(void);
++void toggle_winmode(int);
++void keyboard_select(const Arg *);
+diff --git a/a/x.c b/b/x.c
+index c343ba2..14279de 100644
+--- a/a/x.c
++++ b/b/x.c
+@@ -1696,6 +1696,13 @@ kpress(XEvent *ev)
+               return;
+ 
+       len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
++    if ( IS_SET(MODE_KBDSELECT) ) {
++              if ( match(XK_NO_MOD, e->state) ||
++            (XK_Shift_L | XK_Shift_R) & e->state )
++            win.mode ^= trt_kbdselect(ksym, buf, len);
++              return;
++    }
++
+       /* 1. shortcuts */
+       for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
+               if (ksym == bp->keysym && match(bp->mod, e->state)) {
+@@ -1880,6 +1887,14 @@ usage(void)
+           " [stty_args ...]
", argv0, argv0);
+ }
+ 
++void toggle_winmode(int flag) {
++        win.mode ^= flag;
++}
++
++void keyboard_select(const Arg *dummy) {
++    win.mode ^= trt_kbdselect(-1, NULL, 0);
++}
++
+ int
+ main(int argc, char *argv[])
+ {


Reply via email to