Hi, I've updated Anatoly's patch from 2005 that adds mouse tracking using slang/ncurses to mutt. With "set mouse" (unset by default) mutt will react to button1/2/3/wheel with configurable bindings. I like it :)
I've tested it with Debian's ncurses which unfortunately doesn't support the mouse wheel (yet), but I think it should work. slang is untested. Testers welcome. It would be nice if the patch could be considered for mutt 2.0. (More comments below.) # HG changeset patch # User Christoph Berg <[EMAIL PROTECTED]> # Date 1179420372 -7200 # Node ID c3665ea5ba2ac090527ce98fd672252e65c012b7 # Parent 33af2883d52b99ece0a935818a91293b502603aa Add mouse ncurses/slang mouse tracking capability, set mouse=yes to enable. Based on a patch by Anatoly Vorobey. diff -r 33af2883d52b -r c3665ea5ba2a OPS --- a/OPS Tue May 15 21:05:53 2007 +0200 +++ b/OPS Thu May 17 18:46:12 2007 +0200 @@ -129,6 +129,7 @@ OP_MAIN_UNDELETE_PATTERN "undelete messa OP_MAIN_UNDELETE_PATTERN "undelete messages matching a pattern" OP_MAIN_UNTAG_PATTERN "untag messages matching a pattern" OP_MIDDLE_PAGE "move to the middle of the page" +OP_MOUSE_SELECT "select entry with a mouse button" OP_NEXT_ENTRY "move to the next entry" OP_NEXT_LINE "scroll down one line" OP_NEXT_PAGE "move to the next page" diff -r 33af2883d52b -r c3665ea5ba2a curs_lib.c --- a/curs_lib.c Tue May 15 21:05:53 2007 +0200 +++ b/curs_lib.c Thu May 17 18:46:12 2007 +0200 @@ -80,6 +80,9 @@ event_t mutt_getch (void) { int ch; event_t err = {-1, OP_NULL }, ret; +#ifndef USE_SLANG_CURSES + MEVENT m_event; +#endif if (!option(OPTUNBUFFEREDINPUT) && UngetCount) return (KeyEvent[--UngetCount]); @@ -100,7 +103,74 @@ event_t mutt_getch (void) if(ch == ERR) return err; - + +#ifdef USE_SLANG_CURSES /* mouse tracking */ + if (ch == KEY_SLANG_MOUSE) { + /* get button number and coordinates */ + /* coordinates are further -1'd synchronize them with the values + ncurses returns: starting from 0,0 */ + ch = getch(); + if (ch == ERR) + return err; + LastButton = ch - 32; + ch = getch(); + if (ch == ERR) + return err; + LastX = ch - 32 - 1; + ch = getch(); + if (ch == ERR) + return err; + LastY = ch - 32 - 1; + + dprint (5, (debugfile, "SLang mouse message: Button: %d X: %d Y: %d\n", LastButton, LastX, LastY)); + + /* which event is it? */ + ch = -1; + + /* ignore shift-alt-control modifiers for now */ + + if (LastButton & 64) { /* wheel mouse? */ + if ((LastButton & 3) == 0) + ch = KEY_MUTT_BUTTON4; + else if ((LastButton & 3) == 1) + ch = KEY_MUTT_BUTTON5; + } else { + if ((LastButton & 3) == 0) + ch = KEY_MUTT_BUTTON1; + else if ((LastButton & 3) == 1) + ch = KEY_MUTT_BUTTON2; + else if ((LastButton & 3) == 2) + ch = KEY_MUTT_BUTTON3; + } + + dprint(5, (debugfile, "SLang mouse: emitting key 0x%x\n", ch)); + + } +#else + if (ch == KEY_MOUSE) { + if (getmouse(&m_event) == OK) { + LastX = m_event.x; + LastY = m_event.y; + LastButton = m_event.bstate; + if (m_event.bstate & BUTTON1_CLICKED) + ch = KEY_MUTT_BUTTON1; + else if (m_event.bstate & BUTTON2_CLICKED) + ch = KEY_MUTT_BUTTON2; + else if (m_event.bstate & BUTTON3_CLICKED) + ch = KEY_MUTT_BUTTON3; + else if (m_event.bstate & BUTTON4_CLICKED) + ch = KEY_MUTT_BUTTON4; +# if NCURSES_MOUSE_VERSION > 1 + else if (m_event.bstate & BUTTON5_CLICKED) + ch = KEY_MUTT_BUTTON5; +# endif + else ch = -1; + dprint (5, (debugfile, "NCurses mouse message: bstate: 0x%x X: %d Y: %d\n", LastButton, LastX, LastY)); + dprint(5, (debugfile, "NCurses mouse: emitting key 0x%x\n", ch)); + } + } +#endif /* mouse tracking */ + if ((ch & 0x80) && option (OPTMETAKEY)) { /* send ALT-x as ESC-x */ @@ -417,6 +487,10 @@ void mutt_endwin (const char *msg) attrset (A_NORMAL); mutt_refresh (); +#ifdef USE_SLANG_CURSES + SLtt_set_mouse_mode(0, 0); + /* ncurses: endwin() resets xterm mouse tracking for us */ +#endif endwin (); } diff -r 33af2883d52b -r c3665ea5ba2a curs_main.c --- a/curs_main.c Tue May 15 21:05:53 2007 +0200 +++ b/curs_main.c Thu May 17 18:46:12 2007 +0200 @@ -744,6 +744,12 @@ int mutt_index_menu (void) menu_current_bottom (menu); break; + case OP_MOUSE_SELECT: + /* jump to a line if we're not on it already; otherwise + display that message */ + menu_mouse_click (menu, OP_DISPLAY_MESSAGE); + break; + case OP_JUMP: CHECK_MSGCOUNT; diff -r 33af2883d52b -r c3665ea5ba2a functions.h --- a/functions.h Tue May 15 21:05:53 2007 +0200 +++ b/functions.h Thu May 17 18:46:12 2007 +0200 @@ -79,6 +79,7 @@ struct binding_t OpGeneric[] = { /* map: { "current-middle", OP_CURRENT_MIDDLE, NULL }, { "current-bottom", OP_CURRENT_BOTTOM, NULL }, { "what-key", OP_WHAT_KEY, NULL }, + { "mouse-select", OP_MOUSE_SELECT, "<Button1>" }, { NULL, 0, NULL } }; @@ -158,7 +159,7 @@ struct binding_t OpMain[] = { /* map: in { "next-unread", OP_MAIN_NEXT_UNREAD, NULL }, { "previous-unread", OP_MAIN_PREV_UNREAD, NULL }, { "parent-message", OP_MAIN_PARENT_MESSAGE, "P" }, - + { "mouse-select", OP_MOUSE_SELECT, "<Button1>" }, { "extract-keys", OP_EXTRACT_KEYS, "\013" }, { "forget-passphrase", OP_FORGET_PASSPHRASE, "\006" }, diff -r 33af2883d52b -r c3665ea5ba2a init.h --- a/init.h Tue May 15 21:05:53 2007 +0200 +++ b/init.h Thu May 17 18:46:12 2007 +0200 @@ -1279,7 +1279,14 @@ struct option_t MuttVars[] = { */ #endif - + { "mouse", DT_BOOL, R_NONE, OPTMOUSE, 0 }, + /* + ** .pp + ** Controls whether or not Mutt will react to mouse clicks in your terminal. + ** .pp + ** \fBNote:\fP you need to set this option in .muttrc; it won't have any + ** effect when used interactively. + */ { "move", DT_QUAD, R_NONE, OPT_MOVE, M_ASKNO }, /* ** .pp diff -r 33af2883d52b -r c3665ea5ba2a keymap.c --- a/keymap.c Tue May 15 21:05:53 2007 +0200 +++ b/keymap.c Thu May 17 18:46:12 2007 +0200 @@ -86,11 +86,24 @@ static struct mapping_t KeyNames[] = { #ifdef KEY_NEXT { "<Next>", KEY_NEXT }, #endif + + { "<Button1>", KEY_MUTT_BUTTON1 }, + { "<Button2>", KEY_MUTT_BUTTON2 }, + { "<Button3>", KEY_MUTT_BUTTON3 }, + { "<WheelUp>", KEY_MUTT_BUTTON4 }, + { "<WheelDown>", KEY_MUTT_BUTTON5 }, + { "<Button4>", KEY_MUTT_BUTTON4 }, + { "<Button5>", KEY_MUTT_BUTTON5 }, + { NULL, 0 } }; /* contains the last key the user pressed */ int LastKey; + +/* coordinates of last mouse event, and button number */ +int LastX, LastY; +int LastButton; struct keymap_t *Keymaps[MENU_MAX]; @@ -661,6 +674,17 @@ void km_init (void) /* edit-to (default "t") hides generic tag-entry in Compose menu This will bind tag-entry to "T" in the Compose menu */ km_bindkey ("T", MENU_COMPOSE, OP_TAG); + + /* mouse tracking bindings */ + km_bindkey ("<Button3>", MENU_GENERIC, OP_EXIT); + km_bindkey ("<Button3>", MENU_PAGER, OP_EXIT); + km_bindkey ("<Button3>", MENU_MAIN, OP_QUIT); +#if defined(USE_SLANG_CURSES) || NCURSES_MOUSE_VERSION > 1 + km_bindkey ("<WheelUp>", MENU_PAGER, OP_PREV_LINE); + km_bindkey ("<WheelDown>", MENU_PAGER, OP_NEXT_LINE); + km_bindkey ("<WheelUp>", MENU_GENERIC, OP_PREV_ENTRY); + km_bindkey ("<WheelDown>", MENU_GENERIC, OP_NEXT_ENTRY); +#endif } void km_error_key (int menu) diff -r 33af2883d52b -r c3665ea5ba2a keymap.h --- a/keymap.h Tue May 15 21:05:53 2007 +0200 +++ b/keymap.h Thu May 17 18:46:12 2007 +0200 @@ -87,6 +87,10 @@ extern struct keymap_t *Keymaps[]; /* dokey() records the last real key pressed */ extern int LastKey; +/* coordinates of last mouse event, and button number */ +extern int LastX, LastY; +extern int LastButton; + extern struct mapping_t Menus[]; struct binding_t diff -r 33af2883d52b -r c3665ea5ba2a main.c --- a/main.c Tue May 15 21:05:53 2007 +0200 +++ b/main.c Thu May 17 18:46:12 2007 +0200 @@ -714,6 +714,35 @@ int main (int argc, char **argv) mutt_init (flags & M_NOSYSRC, commands); mutt_free_list (&commands); + if (!option (OPTNOCURSES) && option (OPTMOUSE)) + { +#ifdef USE_SLANG_CURSES + /* TODO: also add a runtime option for this. maybe also for the + second argument, to force */ + SLtt_set_mouse_mode (1, 0); + + /* HACK: add ESC[M to SLang's keypad keymap, so that it "finds" + it and doesn't clear the input buffer. If we don't do this, + SLkeypad.c tries to match ESC[M and when it cannot, returns it + but before that flushes the remaining input, so we lose + parameters that follow ESC[M. + + Sigh. SLang should support its own mouse tracking together with + its own keypad better. */ + + SLkp_define_keysym ("\033[M", KEY_SLANG_MOUSE); +#else + mousemask (BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED | BUTTON4_CLICKED +# if NCURSES_MOUSE_VERSION > 1 + | BUTTON5_CLICKED +# endif + , 0); + /* make ncurses give us a click for every press and ignore doubleclicks + and such. -1 here seems like it should be working but didn't. */ + mouseinterval (0); +#endif + } + /* Initialize crypto backends. */ crypt_init (); diff -r 33af2883d52b -r c3665ea5ba2a menu.c --- a/menu.c Tue May 15 21:05:53 2007 +0200 +++ b/menu.c Thu May 17 18:46:12 2007 +0200 @@ -662,6 +662,21 @@ void menu_prev_entry (MUTTMENU *menu) } else mutt_error _("You are on the first entry."); +} + +void menu_mouse_click (MUTTMENU *menu, int op) +{ + int click = LastY + menu->top - menu->offset; + if (click < 0) + click = 0; + if (click >= menu->max) + click = menu->max -1; + if (click == menu->current) { + mutt_ungetch(0, op); + } else { + menu->current = click; + menu->redraw = REDRAW_MOTION; + } } static int default_color (int i) @@ -1005,6 +1020,12 @@ int mutt_menuLoop (MUTTMENU *menu) mutt_error _("Jumping is not implemented for dialogs."); else menu_jump (menu); + break; + + case OP_MOUSE_SELECT: + /* jump to a line if we're not on it already; otherwise + select entry */ + menu_mouse_click (menu, OP_GENERIC_SELECT_ENTRY); break; case OP_ENTER_COMMAND: diff -r 33af2883d52b -r c3665ea5ba2a mutt.h --- a/mutt.h Tue May 15 21:05:53 2007 +0200 +++ b/mutt.h Thu May 17 18:46:12 2007 +0200 @@ -407,6 +407,7 @@ enum OPTMETOO, OPTMHPURGE, OPTMIMEFORWDECODE, + OPTMOUSE, /* curses/slang mouse tracking */ OPTNARROWTREE, OPTPAGERSTOP, OPTPIPEDECODE, diff -r 33af2883d52b -r c3665ea5ba2a mutt_curses.h --- a/mutt_curses.h Tue May 15 21:05:53 2007 +0200 +++ b/mutt_curses.h Thu May 17 18:46:12 2007 +0200 @@ -185,6 +185,21 @@ void ci_start_color (void); #define MAYBE_REDRAW(x) if (option (OPTNEEDREDRAW)) { unset_option (OPTNEEDREDRAW); x = REDRAW_FULL; } /* ---------------------------------------------------------------------------- + * Support for mouse tracking + */ + +/* Neither SLang nor ncurses use keysyms above 0x1000, use these + for our private keys */ +#ifdef USE_SLANG_CURSES +# define KEY_SLANG_MOUSE 0x1001 /* a pseudo-key for SLang */ +#endif +#define KEY_MUTT_BUTTON1 0x1011 +#define KEY_MUTT_BUTTON2 0x1012 +#define KEY_MUTT_BUTTON3 0x1013 +#define KEY_MUTT_BUTTON4 0x1014 +#define KEY_MUTT_BUTTON5 0x1015 + +/* ---------------------------------------------------------------------------- * These are here to avoid compiler warnings with -Wall under SunOS 4.1.x */ diff -r 33af2883d52b -r c3665ea5ba2a mutt_menu.h --- a/mutt_menu.h Tue May 15 21:05:53 2007 +0200 +++ b/mutt_menu.h Thu May 17 18:46:12 2007 +0200 @@ -102,6 +102,7 @@ void menu_current_middle (MUTTMENU *); void menu_current_middle (MUTTMENU *); void menu_current_bottom (MUTTMENU *); void menu_check_recenter (MUTTMENU *); +void menu_mouse_click (MUTTMENU *, int); void menu_status_line (char *, size_t, MUTTMENU *, const char *); MUTTMENU *mutt_new_menu (void); Comments on the original message: Re: Anatoly Vorobey 2005-04-03 <[EMAIL PROTECTED]> > Attached is a patch to enable [some degree of] mouse tracking support, > for mutt compiled against either ncurses or SLang. > > The patch is against CVS HEAD; criticism, praise, bug reports, requests for > patches against other versions, feature requests, questions, and so on are > welcome. > > I'd especially like to hear if this has any chance of making it into mutt. > (I'm aware of past discussions of this issue, and the fact that many > users/developers see no reason to add such a feature. Still, I had an itch > to scratch, so I wrote it). > > Notes: > > - To use, apply the patch, configure mutt as usual, with either ncurses or > SLang, and then add either "#define HAVE_NCURSES_MOUSE 1" or > "#define HAVE_SLANG_MOUSE 1" to your config.h, and then make, or re-make, > mutt. > > Or, if you don't want to change config.h, use a hack such as > $ export AM_CFLAGS="-DHAVE_SLANG_MOUSE=1" > $ make > That'll make mutt's Makefile pick up the needed flag. > > I haven't yet added the recognition of the right option to configure, > because, in order to do that, I have to learn autoconf first. Been avoiding > that for some years. Mouse support is now a config option. I didn't add a configure flag as I don't think having it built-in but disabled by default hurts. > - With SLang, you must have a version recent enough to include > SLtt_set_mouse_mode() . Based on slang's changes.txt, this appears to be > 0.99.21, but I've only tested with 1.4.9 so far. I haven't tested this stuff > on platforms other than Linux (so far). Untested. > - Currently the events that are recognised are: button clicks and wheel > movements for wheel mice. Wheel movements are only recognized with SLang > because ncurses doesn't support wheel movement recognition. Wheel mouse should work with a ncurses compiled with --ext-mouse (requires ABI/SONAME bump for libncurses). > - The following bindings are hardcoded into keymap.c (but can of course be > changed in .muttrc): In message index menu, wheel movement scrolls the menu; > clicking a line moves the selection to that message, if it's not selected, or > displays the message if it's alrady selected (as if you pressed Enter on it). > This means also that double-clicking a line selects and displays the > message. In pager mode, wheel movement scrolls the view. Ideas for other > bindinds/new operations to add which would rely on them will be appreciated. Left button will jump to/select a line in all menus. Right button is bound to "exit" in menus/pager and "quit" in the index. > - Your terminal program may or may not support the needed functionality for > mouse tracking support to work. Currently, the SLang version only works with > terminals that support "xterm mouse tracking" in the "old X10 compatibility > mode", because this is what SLang's SLtt_set_mouse_mode() does. The ncurses > version works with whatever ncurses was compiled to recognize, which will > at least be "xterm mouse tracking" in the "normal tracking mode" (better than > the one SLang uses), and also possibly GPM (Linux) and sysmouse (BSD). I only > tested ncurses with xterm-style tracking so far. The terminal programs I > tested this on are: > * gnome-terminal, a recent version - ncurses and SLang work, wheel movement > works with SLang. > * xterm, some recent version - ncurses and SLang work, wheel movement > doesn't work. > * PuTTY - only works with ncurses, because PuTTY doesn't support the > "old X10 compatibility mode". Tested here with xterm. > Plans: > > - introduce a runtime option to use/not use mouse tracking, therefore > enabling mutt not to use it even if it's compiled in (suggestions for > option name/behavior?) > - integrate recognition of HAVE_SLANG_MOUSE/HAVE_NCURSES_MOUSE into > configure; set mouse. > - configurable speed of wheel scrolling in pager/menu? Should be done by macros (bind index WheelUp next-page or macro ... <down><down><down> etc.) > - look into bypassing SLang's SLtt_set_mouse_mode() and using normal > mouse tracking with SLang; then it'd be possible to track and bind > button releases and buttons+modifiers (shift, control, meta -- whenever the > terminal program doesn't use them for its own actions). > > This might be a good thing to do, especially because it's possible that > the only combination I have right now in which wheel movement works (SLang > + > gnome-terminal) does so because gnome-terminal sends too much information > in violation, strictly speaking, of the X10 compatibility mode; the spec is > a bit unclear on this. I'd like to see reports of other terminal programs. xterm uses Shift+Mouse for selection handling as with disabled mouse tracking; probably not possible/desirable to work around. > - look into bypassing ncurses' handling of mouse tracking and parsing xterm > mouse tracking ourselves; this would be bad because ncurses won't use > GPM/sysmouse if they're available, but this would be good because mutt will > be able to recognize wheel movement with ncurses. While gpm support could be a nice feature, I don't think it is needed. > - suggestions? > > I'm going to do some/all of the above based on whether I need these > features, whether there's enough interest in the patch and > requests/suggestions from other users, and whether it has any chance of > making it into mutt. > > Best regards, > Anatoly Christoph