This patch adds following functionality to lynx:

	a) If one clicks mouse near a link, the "point/focus" is moved to 
		this link (without actual activation);
	b) One can bind keys with ordinals larger than DO_NOTHING;
	c) Primitive context sensitive menu added to the middle button of
	   a mouse (currently ncurses only);

Current micro-problem with "c" is that I do not know how to refresh a screen
before further action, so if the action choosen from the menu would not
redraw the screen, the menu outline is left on the screen.

Enjoy,
Ilya

--- ./src/LYKeymap.c.pp	Sat Dec  5 23:59:32 1998
+++ ./src/LYKeymap.c	Sat Dec  5 21:18:22 1998
@@ -339,7 +339,7 @@ LYK_DO_NOTHING,
    0,                  0,              0,             0,
    0,                  0,              0,             0,
    /* 290...293 */
-   0,                  0,              0,             0,
+   LYK_CHANGE_LINK,    0,              0,             0,
 };
 
 #if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
@@ -583,6 +583,7 @@ PRIVATE struct rmap revmap[] = {
 { "CLEAR_AUTH",		"clear all authorization info for this session" },
 { "SWITCH_DTD",		"switch between two ways of parsing HTML" },
 { "ELGOTO",		"edit the current link's URL or ACTION and go to it" },
+{ "CHANGE_LINK",	"force reset of the current link on the page" },
 #ifdef USE_EXTERNALS
 { "EXTERN",		"run external program with url" },
 #endif
@@ -936,7 +939,7 @@ PUBLIC BOOL LYisNonAlnumKeyname ARGS2(
 {
     if ((ch >= '0' && ch <= '9') ||
         (ch >= 'A' && ch <= 'z') ||
-	ch < 0 || ch > 269)
+	ch < 0 || ch >= TABLESIZE(keymap))
 	return (FALSE);
 
     return(keymap[ch+1] == key_name);
--- ./src/LYMainLoop.c.pp	Sat Dec  5 23:59:20 1998
+++ ./src/LYMainLoop.c	Sat Dec  5 20:31:12 1998
@@ -2501,6 +2501,18 @@ new_cmd:  /*
 	    }
 	    break;
 
+	case LYK_CHANGE_LINK:
+	{
+	    /* Is there a mouse-clicked link waiting? */
+	    int mouse_tmp = get_mouse_link();
+	    /* If yes, use it as the link */
+	    if (mouse_tmp != -1) {
+		highlight(OFF, curdoc.link, prev_target);
+		curdoc.link = mouse_tmp;		 
+	    }
+	    break;
+	}
+
 	case LYK_RIGHT_LINK:
 	    if (curdoc.link<nlinks-1 &&
 			links[curdoc.link].ly == links[curdoc.link+1].ly) {
--- ./src/LYOptions.c.pp	Sat Dec  5 23:59:32 1998
+++ ./src/LYOptions.c	Sun Nov 29 03:12:00 1998
@@ -33,13 +33,6 @@ PRIVATE int boolean_choice PARAMS((
 	int		line,
 	int		column,
 	char ** 	choices));
-PRIVATE int popup_choice PARAMS((
-	int		cur_choice,
-	int		line,
-	int		column,
-	char ** 	choices,
-	int		i_length,
-	int		disabled));
 
 #define MAXCHOICES 10
 
@@ -2178,7 +2171,7 @@ PRIVATE int get_popup_choice_number ARGS
  *  option via a popup window which functions like
  *  that for selection of options in a form. - FM
  */
-PRIVATE int popup_choice ARGS6(
+PUBLIC int popup_choice ARGS6(
 	int,		cur_choice,
 	int,		line,
 	int,		column,
--- ./src/LYOptions.h.pp	Sat Dec  5 23:59:32 1998
+++ ./src/LYOptions.h	Sun Nov 29 03:12:26 1998
@@ -6,6 +6,13 @@
 extern BOOLEAN term_options; /* for LYgetstr() */
 
 extern void edit_bookmarks NOPARAMS;
+extern  int popup_choice PARAMS((
+	int		cur_choice,
+	int		line,
+	int		column,
+	char ** 	choices,
+	int		i_length,
+	int		disabled));
 
 #ifndef NO_OPTION_FORMS
 extern int postoptions PARAMS((document *newdoc));
--- ./src/LYStrings.c.pp	Sun Dec  6 00:06:42 1998
+++ ./src/LYStrings.c	Sat Dec  5 23:52:56 1998
@@ -37,6 +37,7 @@ extern HTCJKlang HTCJK;
 
 /* The number of the link selected w/ the mouse (-1 if none) */
 static int mouse_link = -1;
+static int mouse_is_exact;
 
 static int have_levent;
 
@@ -74,6 +75,20 @@ PUBLIC int peek_mouse_link NOARGS
   return mouse_link;
 }
 
+PRIVATE int XYdist ARGS5(int,x1,int,y1,int,x2,int,y2,int,dx2)
+{
+    int xerr = x2 - x1, yerr = y2 - y1;
+
+    if (xerr < 0)
+	xerr = x1 - x2 - dx2;
+    if (xerr < 0)
+	xerr = 0;
+    if (yerr < 0)
+	yerr = -yerr;
+    return xerr + yerr;
+}
+
+
 /* 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,
@@ -100,6 +115,8 @@ PRIVATE int set_clicked_link ARGS3(int,x
 	else if (x > right) c = '\b';
 	else c = PGUP;
     } else {
+	int mouse_err = 1000000, cur_err;
+
 	/* 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;
@@ -116,26 +133,39 @@ PRIVATE int set_clicked_link ARGS3(int,x
 		len = strlen(links[i].hightext );
 
 	    /* Check the first line of the link */
-	    if ( links[i].hightext != NULL &&
-		links[i].ly == y && (x - lx) < len && (x >= lx)) {
-		int cury, curx;
+	    if ( links[i].hightext != NULL) {
+		cur_err = XYdist(x,y,links[i].lx,links[i].ly,len);
+		if (cur_err == 0) {
+		    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;
+		    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;
+		    } else
+			mouse_link = -1;
+		    mouse_err = 0;
+		    break;
+		} else if (cur_err < mouse_err) {
+		    mouse_err = cur_err;
 		    mouse_link = i;
-
-}		break;		    
+		}
 	    }
 	    /* Check the second line */
-	    if (links[i].hightext2 != NULL &&
-		1+links[i].ly == y &&
-		(x - links[i].hightext2_offset) < (int)strlen(links[i].hightext2) ) {
-		mouse_link = i;
-		break;
+	    if (links[i].hightext2 != NULL) {	    
+		cur_err = XYdist(x,y,links[i].hightext2_offset,links[i].ly+1,
+				 strlen(links[i].hightext2));
+		if (cur_err == 0) {
+		    mouse_link = i;
+		    mouse_err = 0;
+		    break;
+		} else if (cur_err < mouse_err) {
+		    mouse_err = cur_err;
+		    mouse_link = i;
+		}		
 	    }
 	}
 	/*
@@ -143,8 +173,12 @@ PRIVATE int set_clicked_link ARGS3(int,x
 	 * LYK_ACTIVATE We expect to find LYK_ACTIVATE (it's usually mapped to
 	 * the Enter key).
 	 */
-	if (mouse_link >= 0)
-	    c = lookup_keymap(LYK_ACTIVATE);
+	if (mouse_link >= 0) {
+	    if (mouse_err == 0)
+		c = lookup_keymap(LYK_ACTIVATE);
+	    else if (mouse_err < 1000000)
+		c = lookup_keymap(LYK_CHANGE_LINK);
+	}
     }
     return c;
 }
@@ -828,6 +862,91 @@ PUBLIC int lynx_initialize_keymaps NOARG
 
 #endif				       /* USE_KEYMAPS */
 
+PRIVATE int LYmouse_menu ARGS3(int, x, int, y, int, atlink)
+{
+    char *choices[] = {
+	"Quit",
+	"Home page",
+	"Previous document",
+	"Beginning of document",
+	"Page up",
+	"Half page up",
+	"Two lines up",
+	"History",
+	"Help",
+	"Do nothing (refresh)",
+	"Load again",
+	"Edit URL and load",
+	"Show info",
+	"Search",
+	"Print",
+	"Two lines down",
+	"Half page down",
+	"Page down",
+	"End of document",
+	"Bookmarks",
+/* 	"Cookie jar", */
+	"Search index",
+	"Set Options",
+	NULL
+    };
+    char *choices_link[] = {
+	"Help",
+	"Do nothing",
+	"Activate this link",
+	"Show info",
+	"Download",
+	NULL
+    };
+    int actions[] = {
+	LYK_ABORT,
+	LYK_MAIN_MENU,
+	LYK_PREV_DOC,
+	LYK_HOME,
+	LYK_PREV_PAGE,
+	LYK_UP_HALF,
+	LYK_UP_TWO,
+	LYK_HISTORY,
+	LYK_HELP,
+	LYK_REFRESH,
+	LYK_RELOAD,
+	LYK_ECGOTO,
+	LYK_INFO,
+	LYK_WHEREIS,
+	LYK_PRINT,
+	LYK_DOWN_TWO,
+	LYK_DOWN_HALF,
+	LYK_NEXT_PAGE,
+	LYK_END,
+	LYK_VIEW_BOOKMARK,
+/* 	LYK_COOKIE_JAR, */
+	LYK_INDEX_SEARCH,
+	LYK_OPTIONS
+    };
+    int actions_link[] = {
+	LYK_HELP,
+	LYK_REFRESH,
+	LYK_ACTIVATE,
+	LYK_INFO,
+	LYK_DOWNLOAD
+    };
+    int c;
+    
+    if (LYlines < 24) {
+        HTAlert(OPTION_SCREEN_NEEDS_24);
+        return;
+    }
+    /* Somehow the mouse is over the number instead of being over the
+       name, so we decrease x. */
+    c = popup_choice((atlink ? 2 : 9) - 1, y, (x >= 5 ? x-5 : 0), 
+		     (atlink ? choices_link : choices), 
+		     (atlink 
+		      ? (sizeof(actions_link)/sizeof(int)) 
+		      : (sizeof(actions)/sizeof(int))), FALSE);
+    
+    return atlink ? (actions_link[c]) : (actions[c]);
+}
+
 #if defined(USE_KEYMAPS) && defined(USE_SLANG)
 
 /* We cannot guarantee the type for 'GetChar', and should not use a cast. */
@@ -1197,6 +1316,23 @@ re_read:
 			c = LYReverseKeymap(LYK_MAIN_MENU);
 		} else if (event.bstate & BUTTON3_CLICKED) {
 		    c = LYReverseKeymap (LYK_PREV_DOC);
+		} else if (event.bstate & BUTTON2_CLICKED) {
+		    int atlink;
+
+		    c = set_clicked_link(event.x, event.y, code);
+		    atlink = c == LYReverseKeymap (LYK_ACTIVATE);
+		    if (!atlink)
+			mouse_link = -1; /* Forget about approx stuff. */
+
+		    c = LYmouse_menu(event.x, event.y, atlink);
+		    if (c == LYK_ACTIVATE && mouse_link == -1) {
+			HTAlert("No link chosen");
+			c = LYK_DO_NOTHING;
+			c = LYK_REFRESH; /* refresh() below does not work... */
+		    }
+		    c = LYReverseKeymap(c);
+		    lynx_force_repaint();
+		    refresh();
 		}
 		if (code == FOR_INPUT && mouse_link == -1) {
 		    ungetmouse(&event);	/* Caller will process this. */
@@ -1295,7 +1431,7 @@ re_read:
 #if (defined(__DJGPP__) || defined(_WINDOWS))
     if (c > 659)
 #else
-    if (c > DO_NOTHING)
+    if (c >= 0x293)
 #endif /* __DJGPP__ || _WINDOWS */
     {
 	/*
