Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Implement xterm mouse modes #461

Closed
wants to merge 4 commits into from

9 participants

@niieani

No description provided.

@keithw
Owner

This looks very clean; thank you for doing this.

  • What are the consequences of sending one of these escape sequences to an outer terminal that doesn't support it? Can you please make sure these sequences aren't a problem on xterm/rxvt/Terminal.app/gnome-terminal/PuTTY/iTerm/iTerm2? (Obligatory note that it would be nice if these were represented in a terminfo capability! Otherwise how are applications supposed to know what they can send and can't send.)

  • Does no application actually use 1001, 1003, 1004, or 1005? How did you decide which ones to implement?

  • This implements a semantics where 1000 and 1002 modify the same flag (SET_BTN_EVENT_MOUSE) and then 1006 modifies an orthogonal flag (SET_SGR_EXT_MODE_MOUSE). Is that really what xterm does? My assumption would have been that these are all just exclusive settings, so if you turn on 1002 and then turn on 1006 and then turn off 1006, you end up with no mouse reporting at all. But I haven't tried it.

Thanks again -- this looks very mergable once we get these issues ironed out.

@niieani

Thanks.
I've implemented passing of the DEC mode for xterm mouse and xterm extended. I tested it in PuTTY and gnome-terminal. According to the sources I reference, terminals which don't support this mode just ignore it.
I actually got to it by analyzing the source-code of PuTTY, which by the way might be quite useful for adding support for other DEC modes in the future (file terminal.c). That's how I decided on which ones to implement. We could later add rxvt mouse mode 1015.
Apparently 1005 is an ugly setting, and PuTTY doesn't implement it either, please see my references below.
1003 is really only useful for debugging, as it reports every mouse move printing it to the console.
The implementation of VT100 mouse mode 1000 isn't correct, because I fallback to 1002 for both of them, but it shouldn't be a problem. If it is, I can correct it, we just need to add one more mode for it.
As for your third question, you are correct in that if we turn off just 1002, we end up with no mouse reporting, but the SGR flag is still set - so if we re-enable just 1002, without 1006 the flag SGR will still be on. That's why I'm turning them both off.

The demo here is good for testing the modes:
http://www.leonerd.org.uk/code/libtermkey/

Compile and use: ./demo -m -p 1002 (or 1006)

It works well (remember to have the same version compiled both on the server and client), but there's something really, really weird happening when using the following combination:

  • mosh client compiled under a cygwin shell
  • connect via mosh to a linux server,
  • and then run tmux

Under these conditions, inside tmux mouse events work, but (!) they spill some random characters sometimes, especially when dragging the mouse really quickly. This doesn't happen when connecting from a linux client to a linux server.
GNU Screen doesn't have this problem.
I was debugging it for 10 hours now, but can't seem to find the problem.
It's the same when using the old mouse trick.

Some history and info:
http://leonerds-code.blogspot.co.uk/2012/04/wide-mouse-support-in-libvterm.html

And other references / reading that's useful:

Useful DEC mode parts from PuTTY terminal.c:

/*
 * Toggle terminal mode `mode' to state `state'. (`query' indicates
 * whether the mode is a DEC private one or a normal one.)
 */
static void toggle_mode(Terminal *term, int mode, int query, int state)
{
    if (query)
    switch (mode) {
      case 1:              /* DECCKM: application cursor keys */
        term->app_cursor_keys = state;
        break;
      case 2:              /* DECANM: VT52 mode */
        term->vt52_mode = !state;
        if (term->vt52_mode) {
        term->blink_is_real = FALSE;
        term->vt52_bold = FALSE;
        } else {
        term->blink_is_real = term->blinktext;
        }
        term_schedule_tblink(term);
        break;
      case 3:              /* DECCOLM: 80/132 columns */
        deselect(term);
        if (!term->no_remote_resize)
        request_resize(term->frontend, state ? 132 : 80, term->rows);
        term->reset_132 = state;
        term->alt_t = term->marg_t = 0;
        term->alt_b = term->marg_b = term->rows - 1;
        move(term, 0, 0, 0);
        erase_lots(term, FALSE, TRUE, TRUE);
        break;
      case 5:              /* DECSCNM: reverse video */
        /*
         * Toggle reverse video. If we receive an OFF within the
         * visual bell timeout period after an ON, we trigger an
         * effective visual bell, so that ESC[?5hESC[?5l will
         * always be an actually _visible_ visual bell.
         */
        if (term->rvideo && !state) {
        /* This is an OFF, so set up a vbell */
        term_schedule_vbell(term, TRUE, term->rvbell_startpoint);
        } else if (!term->rvideo && state) {
        /* This is an ON, so we notice the time and save it. */
        term->rvbell_startpoint = GETTICKCOUNT();
        }
        term->rvideo = state;
        seen_disp_event(term);
        break;
      case 6:              /* DECOM: DEC origin mode */
        term->dec_om = state;
        break;
      case 7:              /* DECAWM: auto wrap */
        term->wrap = state;
        break;
      case 8:              /* DECARM: auto key repeat */
        term->repeat_off = !state;
        break;
      case 10:             /* DECEDM: set local edit mode */
        term->term_editing = state;
        if (term->ldisc)           /* cause ldisc to notice changes */
        ldisc_send(term->ldisc, NULL, 0, 0);
        break;
      case 25:             /* DECTCEM: enable/disable cursor */
        compatibility2(OTHER, VT220);
        term->cursor_on = state;
        seen_disp_event(term);
        break;
      case 47:             /* alternate screen */
        compatibility(OTHER);
        deselect(term);
        swap_screen(term, term->no_alt_screen ? 0 : state, FALSE, FALSE);
        term->disptop = 0;
        break;
      case 1000:               /* xterm mouse 1 (normal) */
        term->xterm_mouse = state ? 1 : 0;
        set_raw_mouse_mode(term->frontend, state);
        break;
      case 1002:               /* xterm mouse 2 (inc. button drags) */
        term->xterm_mouse = state ? 2 : 0;
        set_raw_mouse_mode(term->frontend, state);
        break;
      case 1006:               /* xterm extended mouse */
        term->xterm_extended_mouse = state ? 1 : 0;
        break;
      case 1015:               /* urxvt extended mouse */
        term->urxvt_extended_mouse = state ? 1 : 0;
        break;
      case 1047:                   /* alternate screen */
        compatibility(OTHER);
        deselect(term);
        swap_screen(term, term->no_alt_screen ? 0 : state, TRUE, TRUE);
        term->disptop = 0;
        break;
      case 1048:                   /* save/restore cursor */
        if (!term->no_alt_screen)
                save_cursor(term, state);
        if (!state) seen_disp_event(term);
        break;
      case 1049:                   /* cursor & alternate screen */
        if (state && !term->no_alt_screen)
        save_cursor(term, state);
        if (!state) seen_disp_event(term);
        compatibility(OTHER);
        deselect(term);
        swap_screen(term, term->no_alt_screen ? 0 : state, TRUE, FALSE);
        if (!state && !term->no_alt_screen)
        save_cursor(term, state);
        term->disptop = 0;
        break;
      case 2004:               /* xterm bracketed paste */
        term->bracketed_paste = state ? TRUE : FALSE;
        break;
    } else
    switch (mode) {
      case 4:              /* IRM: set insert mode */
        compatibility(VT102);
        term->insert = state;
        break;
      case 12:             /* SRM: set echo mode */
        term->term_echoing = !state;
        if (term->ldisc)           /* cause ldisc to notice changes */
        ldisc_send(term->ldisc, NULL, 0, 0);
        break;
      case 20:             /* LNM: Return sends ... */
        term->cr_lf_return = state;
        break;
      case 34:             /* WYULCURM: Make cursor BIG */
        compatibility2(OTHER, VT220);
        term->big_cursor = !state;
    }
}
@niieani

I've added the missing 1000 mode.

@niieani

Ah, as for that tmux problem - upgrading to tmux 1.8 seemed to help.
But it still seems weird to me - what could possibly be different in mosh under windows vs mosh under linux, or better yet - the same thing under ssh and under mosh behaving differently?
Totally weird, but I'm happy it works now.

@niieani

Here's a ppa with the package for ubuntu:
ppa:nixin/mosh

@drnc drnc referenced this pull request
Open

Implement alternate screen #420

@comex

Note that with these patches, mosh will attempt to predict mouse clicks as text in --predict=experimental mode. (I prefer this mode because I don't like the lag when initially starting to type.)

@niieani

@comex that's a problem with the predict mode though, not with the patch itself.

@pierz

I haven't looked closely at the patches but there's also some useful discussion here regarding coding wide mouse support in midnight commander:
http://www.midnight-commander.org/ticket/2662

@HunterWare

This patch works nicely for me and several of us are running it on our work boxes now.

@keithw keithw closed this pull request from a commit
@niieani niieani Implement vt100 mouse mode (1000)
(closes #461)
492cfa3
@keithw keithw closed this in 492cfa3
@Neal

This is supposed to improve mouse support, but it actually breaks for me. While on stable, I used to run perl -E ' print "\e[?1005h\e[?1002h" ' before running mosh to enable mouse as suggested in some other issue. And since stable does not have ipv6 support, I tried compiling latest stable, which did fix my ipv6 issue, but my mouse stopped working (with or without running the perl command). I just now reverted all four of these commits and mouse works now. I am using iTerm 2.

@niieani

@Neal Most probably the terminal app you're using is sending out wrong or strange xterm mouse-start or mouse-off events. Could you specify what that application is that you're trying to use the mouse with?

@Neal

As I said, iTerm 2.

@niieani

@Neal No, that's the terminal emulator itself, but what I'm asking is: what are you using inside iTerm 2 that uses the mouse? Midnight Commander, emacs, nano, htop, etc.?

@Neal

Oh, sorry. I tried weechat, less and tail - which don't work. But I also just tried htop and it works.

@niieani

If htop mouse works, then perhaps you just don't have mouse support enabled in the apps? When you were used to force the mouse the messages worked, but perhaps the apps themselves just don't activate the mouse, and that's why it doesn't work?
For example, mouse in weechat is disabled by default, see here: http://dev.weechat.org/post/2011/07/26/Mouse-support-and-free-movement-of-cursor

Does mouse work when using SSH, but not Mosh?

@Neal

I do have mouse enabled in weechat and it works when using SSH (and also when I run that perl command). Mouse also doesn't work in tmux, and I was running weechat in tmux, so I thought that could be the issue, but running weechat without tmux also doesn't work.

@niieani

@Neal That's pretty strange then. Have you tried another terminal app?

@Neal

This is strange, indeed. Running tmux or not does not seem to affect what app I'm running. I also just noticed that when I try to scroll up on a prompt, it invokes an up arrow key event, not page up - is this intended?

@pinepara

Can't wait before this get released!

@blueyed

@niieani @Neal
I had the same problem, but had forgotten to also build/install Git master on the server.

@FiXato

While this patch does enable most of the mouse support, there's still something going wrong with the coordinates being sent.

This is especially noticeable with WeeChat on a wide screen, as mouse events after a certain x-position, will reset x to 0.

To reproduce:
I have WeeChat (www.weechat.org) running remotely under tmux (though I'm fairly certain the same happens without using the terminal multiplexer; but I'll verify that soon verified: using tmux or not makes no difference). Mouse support within WeeChat is enabled with /mouse enable, as well as mouse debugging with /debug mouse.

If I connect 'directly' using SSH, and click somewhere on the right side of the screen, it will report in the core buffer of WeeChat:

Mouse: button1-event-down, (263,70) -> (263,70)
Mouse: button1, (263,70) -> (263,70)

When I connect via mosh, and click around the same point, I get this instead:

Mouse: button1-event-down, (7,70) -> (7,70)
Mouse: button1, (7,70) -> (7,70)

As you can see, the x-coords have 'wrapped around'. The highest x value I can get under mosh, is about 222.

I did not have this issue before updating to git; on stable + using the perl workaround the coordinates would get reported correctly.

@FiXato

Perhaps an easier way to test, is the mousetest.pl script from https://code.google.com/p/iterm2/issues/detail?id=432

Running that in extended mode (perl mousetest.pl extended), with the latest git mosh-client (built using brew install mosh --HEAD), will report negative values (usually -32), nothing, occasionally ridiculously high values (such as 40928), and far enough to the right it will rollover to 0 and count 'normally' from there, for the columns after col=95.

A mosh stable build (built using brew install mosh) using the perl workaround will report properly (eg: [col=266 row=74]).

@niieani

@FiXato Did you upgrade both your client AND the server? They're running the same version of mosh?

@niieani

Actually, the best way to test this is using libtermkey:
It includes a demo to test all of the mouse modes supported by xterm:
http://www.leonerd.org.uk/code/libtermkey/

Compile and use: ./demo -m -p 1002 (or 1006) to text for the 1002 or 1006 modes.
You can try others, like 1005 too, I don't know which one is used by WeeChat.
Perhaps we can identify the problem that way.

Cheers

@FiXato

Yes, all tests have been done against the latest mosh-server version.
I'll try that libtermkey demo later this weekend. :)

(On a side-note, is it possible to get a git revision number included in the version number reply?)

@FiXato

Right, finally found some time/motivation to look into this again. :)
Looks like part of the issue I was having, had to do with an outdated version of tmux (though according to my previous post I was at that time also experiencing issues outside of tmux).

Anyway, latest mosh-client+server + tmux + weechat works without coords wrapping again, so I'm satisfied! :D Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 8, 2013
  1. @niieani

    Implement xterm mouse mode

    niieani authored
Commits on Sep 9, 2013
  1. @niieani
  2. @niieani

    xterm extended fix

    niieani authored
  3. @niieani
This page is out of date. Refresh to see the latest.
View
18 src/terminal/terminaldisplay.cc
@@ -292,6 +292,24 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
frame.append( f.ds.bracketed_paste ? "\033[?2004h" : "\033[?2004l" );
}
+ /* has xterm VT100 mouse mode changed? */
+ if ( (!initialized)
+ || (f.ds.vt100_mouse != frame.last_frame.ds.vt100_mouse) ) {
+ frame.append( f.ds.vt100_mouse ? "\033[?1000h" : "\033[?1000l" );
+ }
+
+ /* has xterm mouse mode changed? */
+ if ( (!initialized)
+ || (f.ds.xterm_mouse != frame.last_frame.ds.xterm_mouse) ) {
+ frame.append( f.ds.xterm_mouse ? "\033[?1002h" : "\033[?1002l" );
+ }
+
+ /* has xterm mouse mode changed? */
+ if ( (!initialized)
+ || (f.ds.xterm_extended_mouse != frame.last_frame.ds.xterm_extended_mouse) ) {
+ frame.append( f.ds.xterm_extended_mouse ? "\033[?1006h\033[?1002h" : "\033[?1006l\033[?1002l" );
+ }
+
return frame.str;
}
View
3  src/terminal/terminalframebuffer.cc
@@ -62,7 +62,8 @@ DrawState::DrawState( int s_width, int s_height )
renditions( 0 ), save(),
next_print_will_wrap( false ), origin_mode( false ), auto_wrap_mode( true ),
insert_mode( false ), cursor_visible( true ), reverse_video( false ),
- bracketed_paste( false ), application_mode_cursor_keys( false )
+ bracketed_paste( false ), vt100_mouse( false ), xterm_mouse( false ),
+ xterm_extended_mouse( false ), application_mode_cursor_keys( false )
{
reinitialize_tabs( 0 );
}
View
6 src/terminal/terminalframebuffer.h
@@ -190,6 +190,9 @@ namespace Terminal {
bool cursor_visible;
bool reverse_video;
bool bracketed_paste;
+ bool vt100_mouse;
+ bool xterm_mouse;
+ bool xterm_extended_mouse;
bool application_mode_cursor_keys;
@@ -239,7 +242,8 @@ namespace Terminal {
return ( width == x.width ) && ( height == x.height ) && ( cursor_col == x.cursor_col )
&& ( cursor_row == x.cursor_row ) && ( cursor_visible == x.cursor_visible ) &&
( reverse_video == x.reverse_video ) && ( renditions == x.renditions ) &&
- ( bracketed_paste == x.bracketed_paste );
+ ( bracketed_paste == x.bracketed_paste ) && ( vt100_mouse == x.vt100_mouse ) &&
+ ( xterm_mouse == x.xterm_mouse ) && ( xterm_extended_mouse == x.xterm_extended_mouse );
}
};
View
6 src/terminal/terminalfunctions.cc
@@ -268,6 +268,12 @@ static bool *get_DEC_mode( int param, Framebuffer *fb ) {
return &(fb->ds.auto_wrap_mode);
case 25:
return &(fb->ds.cursor_visible);
+ case 1000: /* xterm mouse 1 (normal) */
+ return &(fb->ds.vt100_mouse);
+ case 1002: /* xterm mouse 2 (inc. button drags) */
+ return &(fb->ds.xterm_mouse);
+ case 1006: /* xterm extended mouse */
+ return &(fb->ds.xterm_extended_mouse);
case 2004: /* bracketed paste */
return &(fb->ds.bracketed_paste);
}
Something went wrong with that request. Please try again.