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; }