* 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.
This commit is contained in:
Corinna Vinschen 2009-12-16 14:56:10 +00:00
parent 7077c48e54
commit beeae48288
4 changed files with 194 additions and 92 deletions

View 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> 2009-12-16 Corinna Vinschen <corinna@vinschen.de>
* registry.cc (cygnus_class): Remove. * registry.cc (cygnus_class): Remove.

View File

@ -936,11 +936,15 @@ class dev_console
} info; } info;
COORD dwLastCursorPosition; 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; int nModifiers;
bool insert_mode; bool insert_mode;
bool use_mouse; int use_mouse;
bool use_focus;
bool raw_win32_keyboard_mode; bool raw_win32_keyboard_mode;
inline UINT get_console_cp (); inline UINT get_console_cp ();
@ -1012,7 +1016,8 @@ class fhandler_console: public fhandler_termios
int ioctl (unsigned int cmd, void *); int ioctl (unsigned int cmd, void *);
int init (HANDLE, DWORD, mode_t); 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_read (select_stuff *);
select_record *select_write (select_stuff *); select_record *select_write (select_stuff *);

View File

@ -100,6 +100,10 @@ fhandler_console::get_tty_stuff (int flags = 0)
dev_state->scroll_region.Bottom = -1; dev_state->scroll_region.Bottom = -1;
dev_state->dwLastCursorPosition.X = -1; dev_state->dwLastCursorPosition.X = -1;
dev_state->dwLastCursorPosition.Y = -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->underline_color = FOREGROUND_GREEN | FOREGROUND_BLUE;
dev_state->dim_color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; dev_state->dim_color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
dev_state->meta_mask = LEFT_ALT_PRESSED; 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 void __stdcall
fhandler_console::read (void *pv, size_t& buflen) fhandler_console::read (void *pv, size_t& buflen)
{ {
@ -401,9 +444,17 @@ fhandler_console::read (void *pv, size_t& buflen)
case MOUSE_EVENT: case MOUSE_EVENT:
send_winch_maybe (); 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 */ /* Treat the double-click event like a regular button press */
if (mouse_event.dwEventFlags == DOUBLE_CLICK) if (mouse_event.dwEventFlags == DOUBLE_CLICK)
@ -412,46 +463,32 @@ fhandler_console::read (void *pv, size_t& buflen)
mouse_event.dwEventFlags = 0; mouse_event.dwEventFlags = 0;
} }
/* Did something other than a click occur? */
if (mouse_event.dwEventFlags)
continue;
/* Retrieve reported mouse position */
int x = mouse_event.dwMousePosition.X;
int y = mouse_event.dwMousePosition.Y;
/* 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 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;
}
/* Ignore unimportant mouse buttons */
mouse_event.dwButtonState &= 0x7;
/* This code assumes Windows never reports multiple button /* This code assumes Windows never reports multiple button
events at the same time. */ events at the same time. */
int b = 0; int b = 0;
char sz[32]; char sz[32];
if (mouse_event.dwButtonState == dev_state->dwLastButtonState)
if (mouse_event.dwEventFlags == MOUSE_WHEELED)
{ {
syscall_printf ("mouse: button state unchanged"); if (mouse_event.dwButtonState & 0xFF800000)
continue; {
b = 0x41;
strcpy (sz, "wheel down");
}
else
{
b = 0x40;
strcpy (sz, "wheel up");
}
}
else
{
/* Ignore unimportant mouse buttons */
mouse_event.dwButtonState &= 0x7;
if (mouse_event.dwEventFlags == MOUSE_MOVED)
{
b = dev_state->last_button_code;
} }
else if (mouse_event.dwButtonState < dev_state->dwLastButtonState) else if (mouse_event.dwButtonState < dev_state->dwLastButtonState)
{ {
@ -474,12 +511,25 @@ fhandler_console::read (void *pv, size_t& buflen)
strcpy (sz, "btn3 down"); strcpy (sz, "btn3 down");
} }
/* Remember the current button state */ dev_state->last_button_code = b;
dev_state->dwLastButtonState = mouse_event.dwButtonState;
/* If a button was pressed, remember the modifiers */ if (mouse_event.dwEventFlags == MOUSE_MOVED)
if (b != 3)
{ {
b += 32;
strcpy (sz, "move");
}
else
{
/* Remember the modified 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;
/* Remember the modifiers */
dev_state->nModifiers = 0; dev_state->nModifiers = 0;
if (mouse_event.dwControlKeyState & SHIFT_PRESSED) if (mouse_event.dwControlKeyState & SHIFT_PRESSED)
dev_state->nModifiers |= 0x4; dev_state->nModifiers |= 0x4;
@ -487,20 +537,32 @@ fhandler_console::read (void *pv, size_t& buflen)
dev_state->nModifiers |= 0x8; 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; dev_state->nModifiers |= 0x10;
}
/* Indicate the modifiers */
b |= dev_state->nModifiers; b |= dev_state->nModifiers;
/* We can now create the code. */ /* We can now create the code. */
sprintf (tmp, "\033[M%c%c%c", b + ' ', x + ' ' + 1, y + ' ' + 1); 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, x, y); syscall_printf ("mouse: %s at (%d,%d)", sz, dev_state->dwMousePosition.X, dev_state->dwMousePosition.Y);
toadd = tmp; toadd = tmp;
nread = 6; nread = 6;
} }
}
break; break;
case FOCUS_EVENT: 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: case WINDOW_BUFFER_SIZE_EVENT:
send_winch_maybe (); send_winch_maybe ();
/* fall through */ /* fall through */
@ -1282,9 +1344,24 @@ fhandler_console::char_command (char c)
} }
break; break;
case 1000: /* Mouse support */ case 1000: /* Mouse tracking */
dev_state->use_mouse = (c == 'h') ? true : false; dev_state->use_mouse = (c == 'h') ? 1 : 0;
syscall_printf ("mouse support %sabled", dev_state->use_mouse ? "en" : "dis"); 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; break;
case 2000: /* Raw keyboard mode */ case 2000: /* Raw keyboard mode */

View File

@ -823,9 +823,9 @@ peek_console (select_record *me, bool)
else else
{ {
if (irec.EventType == MOUSE_EVENT if (irec.EventType == MOUSE_EVENT
&& fh->mouse_aware () && fh->mouse_aware (irec.Event.MouseEvent))
&& (irec.Event.MouseEvent.dwEventFlags == 0 return me->read_ready = true;
|| irec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)) if (irec.EventType == FOCUS_EVENT && fh->focus_aware ())
return me->read_ready = true; return me->read_ready = true;
} }