From beeae48288c9154beadfa7283a77c754df2feff2 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 16 Dec 2009 14:56:10 +0000 Subject: [PATCH] * 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. --- winsup/cygwin/ChangeLog | 20 +++ winsup/cygwin/fhandler.h | 11 +- winsup/cygwin/fhandler_console.cc | 249 +++++++++++++++++++----------- winsup/cygwin/select.cc | 6 +- 4 files changed, 194 insertions(+), 92 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index d5fb16ba6..8fbe012c8 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,23 @@ +2009-12-16 Thomas Wolff + + * 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 * registry.cc (cygnus_class): Remove. diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 275509227..7da3aa618 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -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 *); diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc index d2dab95c0..1e08e2c60 100644 --- a/winsup/cygwin/fhandler_console.cc +++ b/winsup/cygwin/fhandler_console.cc @@ -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; + { + 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 */ - /* 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; - } + /* 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; + } - /* Did something other than a click occur? */ - if (mouse_event.dwEventFlags) - continue; + /* This code assumes Windows never reports multiple button + events at the same time. */ + int b = 0; + char sz[32]; - /* Retrieve reported mouse position */ - int x = mouse_event.dwMousePosition.X; - int y = mouse_event.dwMousePosition.Y; + 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; - /* 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_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"); + } - /* 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; - } + dev_state->last_button_code = b; - /* Ignore unimportant mouse buttons */ - mouse_event.dwButtonState &= 0x7; + if (mouse_event.dwEventFlags == MOUSE_MOVED) + { + b += 32; + strcpy (sz, "move"); + } + else + { + /* Remember the modified button state */ + dev_state->dwLastButtonState = mouse_event.dwButtonState; + } + } - /* 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"); - } + /* Remember mouse position */ + dev_state->dwLastMousePosition.X = dev_state->dwMousePosition.X; + dev_state->dwLastMousePosition.Y = dev_state->dwMousePosition.Y; - /* Remember the current button state */ - dev_state->dwLastButtonState = mouse_event.dwButtonState; - - /* 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 */ diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index cb58445c9..1cd18e720 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -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; }