lynx-dev
[Top][All Lists]
Advanced

[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

reply via email to

[Prev in Thread] Current Thread [Next in Thread]