[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
lynx-dev Saner mouse in lynx with ncurses
From: |
Ilya Zakharevich |
Subject: |
lynx-dev Saner mouse in lynx with ncurses |
Date: |
Sun, 22 Nov 1998 18:25:51 -0500 (EST) |
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
- lynx-dev Saner mouse in lynx with ncurses,
Ilya Zakharevich <=