OSDN Git Service

* fhandler_console.cc (read): Detect and handle mouse wheel scrolling
authorcorinna <corinna>
Wed, 16 Dec 2009 23:56:09 +0000 (23:56 +0000)
committercorinna <corinna>
Wed, 16 Dec 2009 23:56:09 +0000 (23:56 +0000)
events (for completion of mouse reporting mode 1000) and mouse
movement events (for additional mouse reporting modes 1002 and 1003).
Use mouse_aware() as a guard and only condition for mouse
reporting in order to enforce consistence of read() and select().
Add focus reports (for additional focus reporting mode 1004).
(mouse_aware): Enable detection of additional mouse events for select().
Tune function to precisely match actual reporting criteria.
Move adjustment of mouse position (by window scroll offset)
here to avoid duplicate code.
(char_command): Initialization of enhanced mouse reporting modes.
Initialization of focus reporting mode.
* fhandler.h (use_mouse): Change flag (bool->int) to indicate
additional mouse modes. Add flag to indicate focus reporting.
(mouse_aware): Move enhanced function into fhandler_console.cc.
* select.cc (peek_console): Use modified mouse_aware() for more
general detection of mouse events. Also check for focus reports.

winsup/cygwin/ChangeLog
winsup/cygwin/fhandler.h
winsup/cygwin/fhandler_console.cc
winsup/cygwin/select.cc

index d5fb16b..8fbe012 100644 (file)
@@ -1,3 +1,23 @@
+2009-12-16  Thomas Wolff  <towo@towo.net>
+
+       * fhandler_console.cc (read): Detect and handle mouse wheel scrolling
+       events (for completion of mouse reporting mode 1000) and mouse
+       movement events (for additional mouse reporting modes 1002 and 1003).
+       Use mouse_aware() as a guard and only condition for mouse
+       reporting in order to enforce consistence of read() and select().
+       Add focus reports (for additional focus reporting mode 1004).
+       (mouse_aware): Enable detection of additional mouse events for select().
+       Tune function to precisely match actual reporting criteria.
+       Move adjustment of mouse position (by window scroll offset)
+       here to avoid duplicate code.
+       (char_command): Initialization of enhanced mouse reporting modes.
+       Initialization of focus reporting mode.
+       * fhandler.h (use_mouse): Change flag (bool->int) to indicate
+       additional mouse modes. Add flag to indicate focus reporting.
+       (mouse_aware): Move enhanced function into fhandler_console.cc.
+       * select.cc (peek_console): Use modified mouse_aware() for more
+       general detection of mouse events. Also check for focus reports.
+
 2009-12-16  Corinna Vinschen  <corinna@vinschen.de>
 
        * registry.cc (cygnus_class): Remove.
index 2755092..7da3aa6 100644 (file)
@@ -936,11 +936,15 @@ class dev_console
     } info;
 
   COORD dwLastCursorPosition;
-  DWORD dwLastButtonState;
+  COORD dwMousePosition;       /* scroll-adjusted coord of mouse event */
+  COORD dwLastMousePosition;   /* scroll-adjusted coord of previous mouse event */
+  DWORD dwLastButtonState;     /* (not noting mouse wheel events) */
+  int last_button_code;                /* transformed mouse report button code */
   int nModifiers;
 
   bool insert_mode;
-  bool use_mouse;
+  int use_mouse;
+  bool use_focus;
   bool raw_win32_keyboard_mode;
 
   inline UINT get_console_cp ();
@@ -1012,7 +1016,8 @@ class fhandler_console: public fhandler_termios
 
   int ioctl (unsigned int cmd, void *);
   int init (HANDLE, DWORD, mode_t);
-  bool mouse_aware () {return dev_state->use_mouse;}
+  bool mouse_aware (MOUSE_EVENT_RECORD& mouse_event);
+  bool focus_aware () {return dev_state->use_focus;}
 
   select_record *select_read (select_stuff *);
   select_record *select_write (select_stuff *);
index d2dab95..1e08e2c 100644 (file)
@@ -100,6 +100,10 @@ fhandler_console::get_tty_stuff (int flags = 0)
       dev_state->scroll_region.Bottom = -1;
       dev_state->dwLastCursorPosition.X = -1;
       dev_state->dwLastCursorPosition.Y = -1;
+      dev_state->dwLastMousePosition.X = -1;
+      dev_state->dwLastMousePosition.Y = -1;
+      dev_state->dwLastButtonState = 0;        /* none pressed */
+      dev_state->last_button_code = 3; /* released */
       dev_state->underline_color = FOREGROUND_GREEN | FOREGROUND_BLUE;
       dev_state->dim_color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
       dev_state->meta_mask = LEFT_ALT_PRESSED;
@@ -206,6 +210,45 @@ fhandler_console::send_winch_maybe ()
     }
 }
 
+/* Check whether a mouse event is to be reported as an escape sequence */
+bool
+fhandler_console::mouse_aware (MOUSE_EVENT_RECORD& mouse_event)
+{
+  if (! dev_state->use_mouse)
+    return 0;
+
+  /* Adjust mouse position by window scroll buffer offset
+     and remember adjusted position in state for use by read() */
+  CONSOLE_SCREEN_BUFFER_INFO now;
+  if (GetConsoleScreenBufferInfo (get_output_handle (), &now))
+    {
+      dev_state->dwMousePosition.X = mouse_event.dwMousePosition.X - now.srWindow.Left;
+      dev_state->dwMousePosition.Y = mouse_event.dwMousePosition.Y - now.srWindow.Top;
+    }
+  else
+    {
+      /* Cannot adjust position by window scroll buffer offset */
+      return 0;
+    }
+
+  /* Check whether adjusted mouse position can be reported */
+  if (dev_state->dwMousePosition.X > 0xFF - ' ' - 1
+      || dev_state->dwMousePosition.Y > 0xFF - ' ' - 1)
+    {
+      /* Mouse position out of reporting range */
+      return 0;
+    }
+
+  return ((mouse_event.dwEventFlags == 0 || mouse_event.dwEventFlags == DOUBLE_CLICK)
+         && mouse_event.dwButtonState != dev_state->dwLastButtonState)
+        || mouse_event.dwEventFlags == MOUSE_WHEELED
+        || (mouse_event.dwEventFlags == MOUSE_MOVED
+            && (dev_state->dwMousePosition.X != dev_state->dwLastMousePosition.X
+                || dev_state->dwMousePosition.Y != dev_state->dwLastMousePosition.Y)
+            && ((dev_state->use_mouse >= 2 && mouse_event.dwButtonState)
+                || dev_state->use_mouse >= 3));
+}
+
 void __stdcall
 fhandler_console::read (void *pv, size_t& buflen)
 {
@@ -401,106 +444,125 @@ fhandler_console::read (void *pv, size_t& buflen)
 
        case MOUSE_EVENT:
          send_winch_maybe ();
-         if (dev_state->use_mouse)
-           {
-             MOUSE_EVENT_RECORD& mouse_event = input_rec.Event.MouseEvent;
-
-             /* Treat the double-click event like a regular button press */
-             if (mouse_event.dwEventFlags == DOUBLE_CLICK)
-               {
-                 syscall_printf ("mouse: double-click -> click");
-                 mouse_event.dwEventFlags = 0;
-               }
+         {
+           MOUSE_EVENT_RECORD& mouse_event = input_rec.Event.MouseEvent;
+           /* As a unique guard for mouse report generation, 
+              call mouse_aware() which is common with select(), so the result 
+              of select() and the actual read() will be consistent on the 
+              issue of whether input (i.e. a mouse escape sequence) will 
+              be available or not */
+           if (mouse_aware (mouse_event))
+             {
+               /* Note: Reported mouse position was already retrieved by 
+                  mouse_aware() and adjusted by window scroll buffer offset */
 
-             /* Did something other than a click occur? */
-             if (mouse_event.dwEventFlags)
-               continue;
+               /* Treat the double-click event like a regular button press */
+               if (mouse_event.dwEventFlags == DOUBLE_CLICK)
+                 {
+                   syscall_printf ("mouse: double-click -> click");
+                   mouse_event.dwEventFlags = 0;
+                 }
 
-             /* Retrieve reported mouse position */
-             int x = mouse_event.dwMousePosition.X;
-             int y = mouse_event.dwMousePosition.Y;
+               /* This code assumes Windows never reports multiple button
+                  events at the same time. */
+               int b = 0;
+               char sz[32];
 
-             /* Adjust mouse position by scroll buffer offset */
-             CONSOLE_SCREEN_BUFFER_INFO now;
-             if (GetConsoleScreenBufferInfo (get_output_handle (), &now))
-               {
-                 y -= now.srWindow.Top;
-                 x -= now.srWindow.Left;
-               }
-             else
-               {
-                 syscall_printf ("mouse: cannot adjust position by scroll buffer offset");
-                 continue;
-               }
+               if (mouse_event.dwEventFlags == MOUSE_WHEELED)
+                 {
+                   if (mouse_event.dwButtonState & 0xFF800000)
+                     {
+                       b = 0x41;
+                       strcpy (sz, "wheel down");
+                     }
+                   else
+                     {
+                       b = 0x40;
+                       strcpy (sz, "wheel up");
+                     }
+                 }
+               else
+                 {
+                   /* Ignore unimportant mouse buttons */
+                   mouse_event.dwButtonState &= 0x7;
 
-             /* If the mouse event occurred out of the area we can handle,
-                ignore it. */
-             if ((x + ' ' + 1 > 0xFF) || (y + ' ' + 1 > 0xFF))
-               {
-                 syscall_printf ("mouse: position out of range");
-                 continue;
-               }
+                   if (mouse_event.dwEventFlags == MOUSE_MOVED)
+                     {
+                       b = dev_state->last_button_code;
+                     }
+                   else if (mouse_event.dwButtonState < dev_state->dwLastButtonState)
+                     {
+                       b = 3;
+                       strcpy (sz, "btn up");
+                     }
+                   else if ((mouse_event.dwButtonState & 1) != (dev_state->dwLastButtonState & 1))
+                     {
+                       b = 0;
+                       strcpy (sz, "btn1 down");
+                     }
+                   else if ((mouse_event.dwButtonState & 2) != (dev_state->dwLastButtonState & 2))
+                     {
+                       b = 2;
+                       strcpy (sz, "btn2 down");
+                     }
+                   else if ((mouse_event.dwButtonState & 4) != (dev_state->dwLastButtonState & 4))
+                     {
+                       b = 1;
+                       strcpy (sz, "btn3 down");
+                     }
 
-             /* Ignore unimportant mouse buttons */
-             mouse_event.dwButtonState &= 0x7;
+                   dev_state->last_button_code = b;
 
-             /* This code assumes Windows never reports multiple button
-                events at the same time. */
-             int b = 0;
-             char sz[32];
-             if (mouse_event.dwButtonState == dev_state->dwLastButtonState)
-               {
-                 syscall_printf ("mouse: button state unchanged");
-                 continue;
-               }
-             else if (mouse_event.dwButtonState < dev_state->dwLastButtonState)
-               {
-                 b = 3;
-                 strcpy (sz, "btn up");
-               }
-             else if ((mouse_event.dwButtonState & 1) != (dev_state->dwLastButtonState & 1))
-               {
-                 b = 0;
-                 strcpy (sz, "btn1 down");
-               }
-             else if ((mouse_event.dwButtonState & 2) != (dev_state->dwLastButtonState & 2))
-               {
-                 b = 2;
-                 strcpy (sz, "btn2 down");
-               }
-             else if ((mouse_event.dwButtonState & 4) != (dev_state->dwLastButtonState & 4))
-               {
-                 b = 1;
-                 strcpy (sz, "btn3 down");
-               }
+                   if (mouse_event.dwEventFlags == MOUSE_MOVED)
+                     {
+                       b += 32;
+                       strcpy (sz, "move");
+                     }
+                   else
+                     {
+                       /* Remember the modified button state */
+                       dev_state->dwLastButtonState = mouse_event.dwButtonState;
+                     }
+                 }
 
-             /* Remember the current button state */
-             dev_state->dwLastButtonState = mouse_event.dwButtonState;
+               /* Remember mouse position */
+               dev_state->dwLastMousePosition.X = dev_state->dwMousePosition.X;
+               dev_state->dwLastMousePosition.Y = dev_state->dwMousePosition.Y;
 
-             /* If a button was pressed, remember the modifiers */
-             if (b != 3)
-               {
-                 dev_state->nModifiers = 0;
-                 if (mouse_event.dwControlKeyState & SHIFT_PRESSED)
+               /* Remember the modifiers */
+               dev_state->nModifiers = 0;
+               if (mouse_event.dwControlKeyState & SHIFT_PRESSED)
                    dev_state->nModifiers |= 0x4;
-                 if (mouse_event.dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED))
+               if (mouse_event.dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED))
                    dev_state->nModifiers |= 0x8;
-                 if (mouse_event.dwControlKeyState & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED))
+               if (mouse_event.dwControlKeyState & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED))
                    dev_state->nModifiers |= 0x10;
-               }
 
-             b |= dev_state->nModifiers;
+               /* Indicate the modifiers */
+               b |= dev_state->nModifiers;
 
-             /* We can now create the code. */
-             sprintf (tmp, "\033[M%c%c%c", b + ' ', x + ' ' + 1, y + ' ' + 1);
-             syscall_printf ("mouse: %s at (%d,%d)", sz, x, y);
+               /* We can now create the code. */
+               sprintf (tmp, "\033[M%c%c%c", b + ' ', dev_state->dwMousePosition.X + ' ' + 1, dev_state->dwMousePosition.Y + ' ' + 1);
+               syscall_printf ("mouse: %s at (%d,%d)", sz, dev_state->dwMousePosition.X, dev_state->dwMousePosition.Y);
 
-             toadd = tmp;
-             nread = 6;
-           }
+               toadd = tmp;
+               nread = 6;
+             }
+         }
          break;
 
        case FOCUS_EVENT:
+         if (dev_state->use_focus) {
+           if (input_rec.Event.FocusEvent.bSetFocus)
+             sprintf (tmp, "\033[I");
+           else
+             sprintf (tmp, "\033[O");
+
+           toadd = tmp;
+           nread = 3;
+         }
+         break;
+
        case WINDOW_BUFFER_SIZE_EVENT:
          send_winch_maybe ();
          /* fall through */
@@ -1282,9 +1344,24 @@ fhandler_console::char_command (char c)
            }
          break;
 
-       case 1000: /* Mouse support */
-         dev_state->use_mouse = (c == 'h') ? true : false;
-         syscall_printf ("mouse support %sabled", dev_state->use_mouse ? "en" : "dis");
+       case 1000: /* Mouse tracking */
+         dev_state->use_mouse = (c == 'h') ? 1 : 0;
+         syscall_printf ("mouse support set to mode %d", dev_state->use_mouse);
+         break;
+
+       case 1002: /* Mouse button event tracking */
+         dev_state->use_mouse = (c == 'h') ? 2 : 0;
+         syscall_printf ("mouse support set to mode %d", dev_state->use_mouse);
+         break;
+
+       case 1003: /* Mouse any event tracking */
+         dev_state->use_mouse = (c == 'h') ? 3 : 0;
+         syscall_printf ("mouse support set to mode %d", dev_state->use_mouse);
+         break;
+
+       case 1004: /* Focus in/out event reporting */
+         dev_state->use_focus = (c == 'h') ? true : false;
+         syscall_printf ("focus reporting set to %d", dev_state->use_focus);
          break;
 
        case 2000: /* Raw keyboard mode */
index cb58445..1cd18e7 100644 (file)
@@ -823,9 +823,9 @@ peek_console (select_record *me, bool)
        else
          {
            if (irec.EventType == MOUSE_EVENT
-               && fh->mouse_aware ()
-               && (irec.Event.MouseEvent.dwEventFlags == 0
-                   || irec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK))
+               && fh->mouse_aware (irec.Event.MouseEvent))
+               return me->read_ready = true;
+           if (irec.EventType == FOCUS_EVENT && fh->focus_aware ())
                return me->read_ready = true;
          }