On Mon, Oct 17, 2011 at 5:06 PM, Connor Lane Smith <c...@lubutu.com> wrote:
> I'm not a st developer, but I've had a look at this. Arrow keys do
> need to be handled in a special way, but the arrow keys don't work
> with any modifier keys.
>
> Currently st handles an arrow key by printing, eg, "\033[D". With
> shift it is "\033[1;2D", with alt "\033[1;3D", and so on. So it needs
> to detect bucky bits and react accordingly.

Unfortunately, it's not that simple.
Modifiers in terminals are handled differently in each terminal.
Sometime they are added as a parameter, sometime it's a key on its
own.
Start cat with no argument and try pressing any combination of
modifier with any arrow key in xterm and urxvt.
note: ^[ is \033 aka ESC

It seems that ncurses (which is maintained by xterm folks mind you)
doesn't even try to handle this clusterfuck [1].

On Mon, Oct 17, 2011 at 5:20 PM, Stephen Paul Weber
<singpol...@singpolyma.net> wrote:
> Excellent!  I shoved this in st.c for now:
> <snip>
> And it works! :D

It works in irssi? This is weird.
I've attached a patch to handle modifiers like xterm. Of course
modified arrow keys still don't work in emacs... Ugh. This is really
depressing.
Can anyone please try it with his favourite modifed-arrow-key-using
software with TERM=st and TERM=xterm?

Reminder:
$ hg clone http://hg.suckless.org/st
$ patch -p1 < xterm-arrow-keys.diff
$ make
$ ./st
(in st window) TERM=xterm yourapp
or, for TERM=st-xxx
(in st window) yourapp

1: http://invisible-island.net/ncurses/ncurses.faq.html#modified_keys
diff -r 704261718508 st.c
--- a/st.c      Thu Oct 06 21:32:34 2011 +0200
+++ b/st.c      Tue Oct 18 12:02:40 2011 +0200
@@ -208,6 +208,7 @@
 static void ttyread(void);
 static void ttyresize(int, int);
 static void ttywrite(const char *, size_t);
+static void ttyprintf(const char *, ...);
 
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
@@ -733,10 +734,27 @@
 
 void
 ttywrite(const char *s, size_t n) {
-       if(write(cmdfd, s, n) == -1)
+       if(write(cmdfd, s, n) < 0)
                die("write error on tty: %s\n", SERRNO);
 }
 
+/* tty helper: slow, use it for non-frequent small stuff */
+void
+ttyprintf(const char *f, ...) {
+       char buf[1024];
+       va_list ap;
+       int n = 0;
+
+       va_start(ap, f);
+       n = vsnprintf(buf, sizeof(buf), f, ap);
+       va_end(ap);
+
+       if(n < 0 || n >= sizeof(buf))
+               die("ttyprintf: vnsprintf failed (%d/%d)", n, sizeof(buf));
+
+       ttywrite(buf, strlen(buf));
+}
+
 void
 ttyresize(int x, int y) {
        struct winsize w;
@@ -1890,8 +1908,10 @@
        int len;
        int meta;
        int shift;
+       int ctrl;
        Status status;
 
+       ctrl = e->state & ControlMask;
        meta = e->state & Mod1Mask;
        shift = e->state & ShiftMask;
        len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status);
@@ -1905,11 +1925,21 @@
                case XK_Up:
                case XK_Down:
                case XK_Left:
-               case XK_Right:
-                       /* XXX: shift up/down doesn't work */
-                       sprintf(buf, "\033%c%c", IS_SET(MODE_APPKEYPAD) ? 'O' : 
'[', (shift ? "dacb":"DACB")[ksym - XK_Left]);
-                       ttywrite(buf, 3);
+               case XK_Right: {
+                       char cursor = (shift ? "dacb" : "DACB")[ksym - XK_Left];
+                       char mode = IS_SET(MODE_APPKEYPAD) ? 'O' : '[';
+                       int n = 1;
+
+                       if(shift) n += 1;
+                       if(meta)  n += 2;
+                       if(ctrl)  n += 4;
+
+                       if(n > 1)
+                               ttyprintf("\033%c1;%d%c", mode, n, cursor);
+                       else
+                               ttyprintf("\033%c%c", mode, cursor);
                        break;
+               }                       
                case XK_Insert:
                        if(shift)
                                selpaste();

Reply via email to