This patch fixes all the mouse problems I see with lynx as far as
ncurses are used.  The only thing really missing is a (possibly 
context-sensitive) menu of possible actions assigned to button-2 of the 
mouse.  Well, one could also enjoy a menu of possible print/download 
methods on Shift-clicking a link!  ;-)

(These changes should be propagated into other branches (PDCURSES etc),
but I cannot do it myself.  It should be pretty straightforward.)

Q. Why have almost-duplicate code for popup_choice() and popup_option()?

Improvements:

	a) Mouse navigation inside text entry fields;

	b) Mouse navigation to a text entry field (including an empty one)

	c) Mouse navigation to a specific position of a text field
		(since I do not know which fields are text fields,
		 I implemented "b" and "c" for F_TEXTAREA_TYPE and 
		 F_TEXT_TYPE only, search for these symbols in the patch);

	d) Mouse navigation in menus:
	   To scroll, one can click on top/bottom border 
		(single=byline, double=bypage, triple=beg/end),
		or above/below menu (single=bypage, double=beg/end))
		mouse-3 ==> quit;

	e)  Double-click-1 on the first and last row are interpreted as
		goto- start/end/main-window (depending on the 
		location of the click).
	
Changes:
	a) Ask ncurses for all mouse events, but increase mouseinterval()
	   to simulate current behaviour (which is effectively an infinite
	   mouseinterval() + masking of repeated clicks);

	b) Earlier clicking to the left of a link would activate the link.  
	   I see no use for this, so consider this a bug.

Enjoy,
Ilya

--- ./src/LYCurses.c~	Tue Nov 10 14:47:38 1998
+++ ./src/LYCurses.c	Sun Nov 22 03:22:24 1998
@@ -882,10 +882,22 @@ PUBLIC void lynx_enable_mouse ARGS1(int,
     }
 #else
     /* Inform ncurses that we're interested in knowing when mouse
-     * button 1 is clicked */
-    if (state)
-	mousemask(BUTTON1_CLICKED | BUTTON3_CLICKED, NULL);
-    else
+     * button 1 is clicked.  We cannot just specify 
+     * BUTTON1_CLICKED | BUTTON3_CLICKED, since ncurses will try hard
+     * to translate other events to single-clicks.
+     * Compensate for small value of maxclick in ncurses.  */
+    if (state) {
+	static was = 0;
+
+	if (!was) {
+	    int old = mouseinterval(-1);
+
+	    was++;
+	    if (old < 200)		/* Default 166 */
+		mouseinterval(300);
+	}
+	mousemask(ALL_MOUSE_EVENTS, NULL);
+    } else
 	mousemask(0, NULL);
 #endif /* __BORLANDC__ and __PDCURSES__ */
 #endif /* NCURSES_MOUSE_VERSION */
--- ./src/LYEditmap.c~	Thu Aug  6 07:28:22 1998
+++ ./src/LYEditmap.c	Sun Nov 22 01:09:22 1998
@@ -99,7 +99,7 @@ LYE_CHAR,       LYE_CHAR,       LYE_CHAR
 LYE_CHAR,       LYE_CHAR,       LYE_CHAR,       LYE_CHAR,
 LYE_CHAR,       LYE_CHAR,       LYE_CHAR,       LYE_CHAR,
 
-/* 100..10E function key definitions in LYStrings.h */
+/* 100..10F function key definitions in LYStrings.h */
 LYE_NOP,        LYE_NOP,        LYE_FORW,       LYE_BACK,
 /* UPARROW      DNARROW         RTARROW         LTARROW     */
 
@@ -110,7 +110,7 @@ LYE_NOP,        LYE_TAB,        LYE_BOL,
 /* F1           Do key          Find key        Select key  */
 
 LYE_NOP,        LYE_DELP,       LYE_NOP,        LYE_NOP,
-/* Insert key   Remove key      DO_NOTHING      ...         */
+/* Insert key   Remove key      MOUSE_KEY       DO_NOTHING         */
 };
 
 /*
--- ./src/LYForms.c~	Sun Sep 13 09:35:54 1998
+++ ./src/LYForms.c	Sun Nov 22 17:40:04 1998
@@ -263,7 +263,7 @@ PRIVATE int form_getstr ARGS1(
     int max_length;
     int startcol, startline;
     BOOL HaveMaxlength = FALSE;
-    int action;
+    int action, repeat, non_first = 0;
 
 #ifdef VMS
     extern BOOLEAN HadVMSInterrupt;	/* Flag from cleanup_sig() AST */
@@ -337,14 +337,38 @@ PRIVATE int form_getstr ARGS1(
      */
     for (;;) {
 again:
-	ch = LYgetch();
+	repeat = -1;
+	get_mouse_link();		/* Reset mouse_link. */
+	/* Try to set position basing on the last mouse event */
+	if (!non_first++)
+	    peek_mouse_levent();
+
+	ch = LYgetch_for(FOR_INPUT);
 #ifdef VMS
 	if (HadVMSInterrupt) {
 	    HadVMSInterrupt = FALSE;
 	    ch = 7;
 	}
 #endif /* VMS */
-
+#  ifdef NCURSES_MOUSE_VERSION
+	if (ch == MOUSE_KEY) {		/* Need to process ourselves */
+	    MEVENT	event;
+	    int curx, cury;
+
+	    getmouse(&event);
+	    LYGetYX(cury, curx);
+	    if (event.y == cury) {
+		repeat = event.x - curx;
+		if (repeat < 0) {
+		    ch = LTARROW;
+		    repeat = - repeat;
+		} else
+		    ch = RTARROW;
+	    }
+	}
+#  endif	/* defined NCURSES_MOUSE_VERSION */ 
+	if (peek_mouse_link() != -1)
+	    break;
 	/*
 	 *  Filter out global navigation keys that should not be passed
 	 *  to line editor, and LYK_REFRESH.
@@ -393,7 +417,7 @@ again:
 	     *  else you can get trapped in a form without submit button!
 	     */
 	    case LTARROW:
-		if (MyEdit.pos == 0) {
+		if (MyEdit.pos == 0 && repeat == -1) {
 		    int c = 'Y';    /* Go back immediately if no changes */
 		    if (strcmp(MyEdit.buffer, value)) {
 			_statusline(PREV_DOC_QUERY);
@@ -416,7 +440,10 @@ again:
 		/*
 		 *  Make sure the statusline uses editmode help.
 		 */
-		LYLineEdit(&MyEdit, ch, TRUE);
+		if (repeat < 0)
+		    repeat = 1;
+		while (repeat--)
+		    LYLineEdit(&MyEdit, ch, TRUE);
 		if (MyEdit.strlen >= max_length) {
 		    HaveMaxlength = TRUE;
 		} else if (HaveMaxlength &&
@@ -824,9 +851,84 @@ redraw:
 	wrefresh(form_window);
 #endif /* USE_SLANG  */
 
-	c = LYgetch();
+	c = LYgetch_for(FOR_CHOICE);
 	if (c == 3 || c == 7)	/* Control-C or Control-G */
 	    cmd = LYK_QUIT;
+#  ifdef NCURSES_MOUSE_VERSION
+	else if (c == MOUSE_KEY) {
+	    MEVENT	event;
+
+	    getmouse(&event);
+	    if ((event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED
+				 | BUTTON1_TRIPLE_CLICKED))
+		&& (event.x >= form_window->_begx)
+		&& (event.x <= (form_window->_begx + form_window->_maxx))) {
+		int delta = event.y
+		    - form_window->_begy - form_window->_yoffset
+		    - ((i + 1) - window_offset);
+		int menu_pos = event.y
+		    - form_window->_begy - form_window->_yoffset;
+	      
+		if (menu_pos == form_window->_maxy) {
+		    /* At the decorative border: scroll forward */
+		    if (event.bstate & BUTTON1_TRIPLE_CLICKED)
+			cmd = LYK_END;
+		    else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
+			cmd = LYK_NEXT_PAGE;
+		    else
+			cmd = LYK_NEXT_LINK;
+		} else if (menu_pos > form_window->_maxy) {
+		    if (event.bstate & (BUTTON1_DOUBLE_CLICKED
+					| BUTTON1_TRIPLE_CLICKED))
+			cmd = LYK_END;
+		    else
+			cmd = LYK_NEXT_PAGE;
+		} else if (menu_pos == 0) {
+		    /* At the decorative border: scroll back */
+		    if (event.bstate & BUTTON1_TRIPLE_CLICKED)
+			cmd = LYK_HOME;
+		    else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
+			cmd = LYK_PREV_PAGE;
+		    else
+			cmd = LYK_PREV_LINK;
+		} else if (menu_pos < 0) {
+		    if (event.bstate & (BUTTON1_DOUBLE_CLICKED
+					| BUTTON1_TRIPLE_CLICKED))
+			cmd = LYK_HOME;
+		    else
+			cmd = LYK_PREV_PAGE;
+#    ifdef KNOW_HOW_TO_TOGGLE
+		} else if (event.bstate & (BUTTON_CTRL)) {
+		    cur_selection += delta;
+		    cmd = LYX_TOGGLE;
+#    endif
+		} else if (event.bstate & (BUTTON_ALT | BUTTON_SHIFT
+					   | BUTTON_CTRL)) {
+		    /* Probably some unrelated activity, such as
+		     * selecting some text.  Select, but do nothing else. */
+		    cur_selection += delta;
+		    goto redraw;
+		} else {
+		    /* No scrolling or overflow checks necessary. */
+		    cur_selection += delta;
+#    if 0		/* Immediate action looks reasonable since we
+			 * have no help available for individual options.
+			 * Moreover, one can position active element
+			 * with shift-click-1.  (;-)  */
+		    if (!(event.bstate & (BUTTON1_DOUBLE_CLICKED
+					  | BUTTON1_TRIPLE_CLICKED)))
+			goto redraw;
+#    endif
+		    cmd = LYK_ACTIVATE;
+		    break;
+		}
+	    } else if (event.bstate & (BUTTON3_CLICKED | BUTTON3_DOUBLE_CLICKED
+				       | BUTTON3_TRIPLE_CLICKED))
+		cmd = LYK_QUIT;
+	    else
+		cmd = LYK_DO_NOTHING;
+	}
+#  endif
 	else
 	    cmd = keymap[c+1];
 #ifdef VMS
--- ./src/LYOptions.c~	Mon Nov 16 17:59:26 1998
+++ ./src/LYOptions.c	Sun Nov 22 17:58:04 1998
@@ -2486,10 +2486,86 @@ redraw:
 #endif /* USE_SLANG  */
 
 	term_options = FALSE;
-	c = LYgetch();
+	c = LYgetch_for(FOR_CHOICE);
 	if (term_options || c == 3 || c == 7) {
 	    cmd = LYK_QUIT;
-	} else {
+	} 
+#  ifdef NCURSES_MOUSE_VERSION
+	else if (c == MOUSE_KEY) {
+	    MEVENT	event;
+
+	    getmouse(&event);
+	    if ((event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED
+				 | BUTTON1_TRIPLE_CLICKED))
+		&& (event.x >= form_window->_begx)
+		&& (event.x <= (form_window->_begx + form_window->_maxx))) {
+		int delta = event.y
+		    - form_window->_begy - form_window->_yoffset
+		    - ((i + 1) - window_offset);
+		int menu_pos = event.y
+		    - form_window->_begy - form_window->_yoffset;
+	      
+		if (menu_pos == form_window->_maxy) {
+		    /* At the decorative border: scroll forward */
+		    if (event.bstate & BUTTON1_TRIPLE_CLICKED)
+			cmd = LYK_END;
+		    else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
+			cmd = LYK_NEXT_PAGE;
+		    else
+			cmd = LYK_NEXT_LINK;
+		} else if (menu_pos > form_window->_maxy) {
+		    if (event.bstate & (BUTTON1_DOUBLE_CLICKED
+					| BUTTON1_TRIPLE_CLICKED))
+			cmd = LYK_END;
+		    else
+			cmd = LYK_NEXT_PAGE;
+		} else if (menu_pos == 0) {
+		    /* At the decorative border: scroll back */
+		    if (event.bstate & BUTTON1_TRIPLE_CLICKED)
+			cmd = LYK_HOME;
+		    else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
+			cmd = LYK_PREV_PAGE;
+		    else
+			cmd = LYK_PREV_LINK;
+		} else if (menu_pos < 0) {
+		    if (event.bstate & (BUTTON1_DOUBLE_CLICKED
+					| BUTTON1_TRIPLE_CLICKED))
+			cmd = LYK_HOME;
+		    else
+			cmd = LYK_PREV_PAGE;
+#    ifdef KNOW_HOW_TO_TOGGLE
+		} else if (event.bstate & (BUTTON_CTRL)) {
+		    cur_selection += delta;
+		    cmd = LYX_TOGGLE;
+#    endif
+		} else if (event.bstate & (BUTTON_ALT | BUTTON_SHIFT
+					   | BUTTON_CTRL)) {
+		    /* Probably some unrelated activity, such as
+		     * selecting some text.  Select, but do nothing else. */
+		    cur_choice += delta;
+		    goto redraw;
+		} else {
+		    /* No scrolling or overflow checks necessary. */
+		    cur_choice += delta;
+#    if 0		/* Immediate action looks reasonable since we
+			 * have no help available for individual options.
+			 * Moreover, one can position active element
+			 * with shift-click-1.  (;-)  */
+		    if (!(event.bstate & (BUTTON1_DOUBLE_CLICKED
+					  | BUTTON1_TRIPLE_CLICKED)))
+			goto redraw;
+#    endif
+		    cmd = LYK_ACTIVATE;
+		    break;
+		}
+	    } else if (event.bstate & (BUTTON3_CLICKED | BUTTON3_DOUBLE_CLICKED
+				       | BUTTON3_TRIPLE_CLICKED))
+		cmd = LYK_QUIT;
+	    else
+		cmd = LYK_DO_NOTHING;
+	}
+#  endif
+	else {
 	    cmd = keymap[c+1];
 	}
 #ifdef VMS
--- ./src/LYStrings.c~	Mon Nov 16 17:59:26 1998
+++ ./src/LYStrings.c	Sun Nov 22 17:44:12 1998
@@ -38,15 +38,42 @@ extern HTCJKlang HTCJK;
 /* The number of the link selected w/ the mouse (-1 if none) */
 static int mouse_link = -1;
 
+static int have_levent;
+
+#ifdef NCURSES_MOUSE_VERSION
+static MEVENT levent;
+/* Return the value of mouse_link */
+PUBLIC int peek_mouse_levent NOARGS
+{
+  if (!have_levent)
+      return 0;
+  ungetmouse(&levent);
+  return 1;
+}
+#else
+PUBLIC int peek_mouse_levent NOARGS
+{
+  return 0;
+}
+#endif
+
 /* Return the value of mouse_link, erasing it */
 PUBLIC int get_mouse_link NOARGS
 {
   int t;
   t=mouse_link;
   mouse_link = -1;
+  if (t < 0)
+      t = -1;				/* Backward compatibility. */
   return t;
 }
 
+/* Return the value of mouse_link */
+PUBLIC int peek_mouse_link NOARGS
+{
+  return mouse_link;
+}
+
 /* Given X and Y coordinates of a mouse event, set mouse_link to the
 ** index of the corresponding hyperlink, or set mouse_link to -1 if no
 ** link matches the event.  Returns -1 if no link matched the click,
@@ -54,7 +81,7 @@ PUBLIC int get_mouse_link NOARGS
 ** link.
 **/
 
-PRIVATE int set_clicked_link ARGS2(int,x,int,y)
+PRIVATE int set_clicked_link ARGS3(int,x,int,y,int,code)
 {
     int left = 6;
     int right = LYcols-6;
@@ -63,22 +90,45 @@ PRIVATE int set_clicked_link ARGS2(int,x
     int c = -1;
 
     if (y == (LYlines-1)) {
+	mouse_link = -2;
 	if (x < left) c = LTARROW;
 	else if (x > right) c = '\b';
 	else c = PGDOWN;
     } else if (y == 0) {
+	mouse_link = -2;
 	if (x < left) c = LTARROW;
 	else if (x > right) c = '\b';
 	else c = PGUP;
     } else {
 	/* Loop over the links and see if we can get a match */
 	for (i = 0; i < nlinks; i++) {
+	    int len, lx = links[i].lx, is_text = 0;
+
+	    if (links[i].type == WWW_FORM_LINK_TYPE
+		/* XXXX What else? */
+		&& (links[i].form->type == F_TEXTAREA_TYPE
+		    || links[i].form->type == F_TEXT_TYPE))
+		is_text = 1;
+
+	    if (is_text)
+		len = links[i].form->size;
+	    else
+		len = strlen(links[i].hightext );
+
 	    /* Check the first line of the link */
 	    if ( links[i].hightext != NULL &&
-		links[i].ly == y &&
-		(x - links[i].lx) < (int)strlen(links[i].hightext ) ) {
-		mouse_link = i;
-		break;
+		links[i].ly == y && (x - lx) < len && (x >= lx)) {
+		int cury, curx;
+		
+		if (code != FOR_INPUT
+		    /* Do not pick up the current input field */
+		    || !(LYGetYX(cury,curx), 
+			 (cury == y && (curx >= lx) && ((curx - lx) <= len)))) {
+		    if (is_text)
+			have_levent = 1;
+		    mouse_link = i;
+
+}		break;		    
 	    }
 	    /* Check the second line */
 	    if (links[i].hightext2 != NULL &&
@@ -323,7 +373,7 @@ PRIVATE int sl_read_mouse_event NOARGS
    if (-1 != sl_parse_mouse_event (&mouse_x, &mouse_y, &button))
      {
 	if (button == 0)  /* left */
-	  return set_clicked_link (mouse_x, mouse_y);
+	  return set_clicked_link (mouse_x, mouse_y, FOR_PANEL);
 
 	if (button == 2)   /* right */
 	  {
@@ -808,6 +858,12 @@ PUBLIC int LYgetch NOARGS
    return keysym;
 }
 
+PUBLIC int LYgetch_for ARGS1(
+	int, 	code)
+{
+    return LYgetch();
+}
+
 #else /* !USE_KEYMAPS */
 
 /*
@@ -817,8 +873,16 @@ PUBLIC int LYgetch NOARGS
 
 PUBLIC int LYgetch NOARGS
 {
+    return LYgetch_for(FOR_PANEL);
+}
+
+PUBLIC int LYgetch_for ARGS1(
+	int, 	code)
+{
     int a, b, c, d = -1;
 
+    have_levent = 0;
+
 #if defined(IGNORE_CTRL_C) || defined(USE_GETCHAR) || !defined(NCURSES)
 re_read:
 #endif /* IGNORE_CTRL_C || USE_GETCHAR */
@@ -1110,7 +1174,9 @@ re_read:
 #endif /* KEY_DC */
 #ifdef NCURSES_MOUSE_VERSION
 	case KEY_MOUSE:
-	    {
+	    if (code == FOR_CHOICE) {
+		c = MOUSE_KEY;		/* Will be processed by the caller */
+	    } else {
 #ifndef DOSPATH
 		MEVENT event;
 		int err;
@@ -1118,17 +1184,31 @@ re_read:
 		c = -1;
 		mouse_link = -1;
 		err = getmouse(&event);
+		levent = event;		/* Allow setting pos in entry fields */
 		if (event.bstate & BUTTON1_CLICKED) {
-		    c = set_clicked_link(event.x, event.y);
+		    c = set_clicked_link(event.x, event.y, code);
+		} else if (event.bstate & BUTTON1_DOUBLE_CLICKED) {
+		    c = set_clicked_link(event.x, event.y, code);
+		    if (c == PGDOWN)
+			c = END_KEY;
+		    else if (c == PGUP)
+			c = HOME;
+		    else if (c == LTARROW)
+			c = LYReverseKeymap(LYK_MAIN_MENU);
 		} else if (event.bstate & BUTTON3_CLICKED) {
 		    c = LYReverseKeymap (LYK_PREV_DOC);
 		}
+		if (code == FOR_INPUT && mouse_link == -1) {
+		    ungetmouse(&event);	/* Caller will process this. */
+		    getch();		/* ungetmouse puts KEY_MOUSE back */
+		    c = MOUSE_KEY;
+		}
 #else /* pdcurses version */
 		c = -1;
 		mouse_link = -1;
 		request_mouse_pos();
 		if (BUTTON_STATUS(1) & BUTTON_CLICKED) {
-		    c = set_clicked_link(MOUSE_X_POS, MOUSE_Y_POS);
+		    c = set_clicked_link(MOUSE_X_POS, MOUSE_Y_POS, FOR_PANEL);
 		} else if (BUTTON_STATUS(3) & BUTTON_CLICKED) {
 		    c = LYReverseKeymap (LYK_PREV_DOC);
 		}
--- ./src/LYStrings.h~	Mon Nov 16 17:59:26 1998
+++ ./src/LYStrings.h	Sun Nov 22 18:03:04 1998
@@ -9,12 +9,17 @@ extern int UPPER8  PARAMS((
 	int		ch2));
 
 extern int get_mouse_link NOPARAMS;
+extern int peek_mouse_link NOPARAMS;
+extern int peek_mouse_levent NOPARAMS;
+
 extern char * LYstrncpy PARAMS((
 	char *		dst,
 	CONST char *	src,
 	int		n));
 extern void ena_csi PARAMS((BOOLEAN flag));
 extern int LYgetch NOPARAMS;
+extern int LYgetch_for PARAMS((
+	int		code));
 extern int LYgetstr PARAMS((
 	char *		inputline,
 	int		hidden,
@@ -84,7 +89,12 @@ extern char * SNACat PARAMS((
 #define SELECT_KEY	267	/* 0x10B */
 #define INSERT_KEY	268	/* 0x10C */
 #define REMOVE_KEY	269	/* 0x10D */
-#define DO_NOTHING	270	/* 0x10E */
+#define MOUSE_KEY	270	/* 0x10E */
+#define DO_NOTHING	271	/* 0x10F */
+
+#  define FOR_PANEL	0
+#  define FOR_CHOICE	1
+#  define FOR_INPUT	2
 
 #define VISIBLE  0
 #define HIDDEN   1
