diff --git a/src/interactivity/win32/windowio.cpp b/src/interactivity/win32/windowio.cpp index d331607d459..0734af874f2 100644 --- a/src/interactivity/win32/windowio.cpp +++ b/src/interactivity/win32/windowio.cpp @@ -651,8 +651,12 @@ BOOL HandleMouseEvent(const SCREEN_INFORMATION& ScreenInfo, sDelta = GET_WHEEL_DELTA_WPARAM(wParam); } - if (HandleTerminalMouseEvent(MousePosition, Message, GET_KEYSTATE_WPARAM(wParam), sDelta)) + if (HandleTerminalMouseEvent(MousePosition, Message, LOWORD(GetControlKeyState(0)), sDelta)) { + // Use GetControlKeyState here to get the control state in console event mode. + // This will ensure that we get ALT and SHIFT, the former of which is not available + // through MK_ constants. We only care about the bottom 16 bits. + // GH#6401: Capturing the mouse ensures that we get drag/release events // even if the user moves outside the window. // HandleTerminalMouseEvent returns false if the terminal's not in VT mode, diff --git a/src/terminal/adapter/ut_adapter/MouseInputTest.cpp b/src/terminal/adapter/ut_adapter/MouseInputTest.cpp index 881f19543a9..b16288f2b04 100644 --- a/src/terminal/adapter/ut_adapter/MouseInputTest.cpp +++ b/src/terminal/adapter/ut_adapter/MouseInputTest.cpp @@ -186,8 +186,10 @@ class MouseInputTest wch = L'\x0'; break; } - // MK_SHIFT is ignored by the translator - wch += (sModifierKeystate & MK_CONTROL) ? 0x08 : 0x00; + // Use Any here with the multi-flag constants -- they capture left/right key state + WI_UpdateFlag(wch, 0x04, WI_IsAnyFlagSet(sModifierKeystate, SHIFT_PRESSED)); + WI_UpdateFlag(wch, 0x08, WI_IsAnyFlagSet(sModifierKeystate, ALT_PRESSED)); + WI_UpdateFlag(wch, 0x10, WI_IsAnyFlagSet(sModifierKeystate, CTRL_PRESSED)); return wch; } @@ -222,8 +224,10 @@ class MouseInputTest result = 0; break; } - // MK_SHIFT and MK_ALT is ignored by the translator - result += (sModifierKeystate & MK_CONTROL) ? 0x08 : 0x00; + // Use Any here with the multi-flag constants -- they capture left/right key state + WI_UpdateFlag(result, 0x04, WI_IsAnyFlagSet(sModifierKeystate, SHIFT_PRESSED)); + WI_UpdateFlag(result, 0x08, WI_IsAnyFlagSet(sModifierKeystate, ALT_PRESSED)); + WI_UpdateFlag(result, 0x10, WI_IsAnyFlagSet(sModifierKeystate, CTRL_PRESSED)); return result; } @@ -274,8 +278,8 @@ class MouseInputTest BEGIN_TEST_METHOD_PROPERTIES() // TEST_METHOD_PROPERTY(L"Data:uiButton", L"{WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_RBUTTONDOWN, WM_RBUTTONUP}") TEST_METHOD_PROPERTY(L"Data:uiButton", L"{0x0201, 0x0202, 0x0207, 0x0208, 0x0204, 0x0205}") - // None, MK_SHIFT, MK_CONTROL - TEST_METHOD_PROPERTY(L"Data:uiModifierKeystate", L"{0x0000, 0x0004, 0x0008}") + // None, SHIFT, LEFT_CONTROL, RIGHT_ALT, RIGHT_ALT | LEFT_CONTROL + TEST_METHOD_PROPERTY(L"Data:uiModifierKeystate", L"{0x0000, 0x0010, 0x0008, 0x0001, 0x0009}") END_TEST_METHOD_PROPERTIES() Log::Comment(L"Starting test..."); @@ -357,7 +361,8 @@ class MouseInputTest BEGIN_TEST_METHOD_PROPERTIES() // TEST_METHOD_PROPERTY(L"Data:uiButton", L"{WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_RBUTTONDOWN, WM_RBUTTONUP}") TEST_METHOD_PROPERTY(L"Data:uiButton", L"{0x0201, 0x0202, 0x0207, 0x0208, 0x0204, 0x0205}") - TEST_METHOD_PROPERTY(L"Data:uiModifierKeystate", L"{0x0000, 0x0004, 0x0008}") + // None, SHIFT, LEFT_CONTROL, RIGHT_ALT, RIGHT_ALT | LEFT_CONTROL + TEST_METHOD_PROPERTY(L"Data:uiModifierKeystate", L"{0x0000, 0x0010, 0x0008, 0x0001, 0x0009}") END_TEST_METHOD_PROPERTIES() Log::Comment(L"Starting test..."); @@ -443,7 +448,8 @@ class MouseInputTest BEGIN_TEST_METHOD_PROPERTIES() // TEST_METHOD_PROPERTY(L"Data:uiButton", L"{WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_MOUSEMOVE}") TEST_METHOD_PROPERTY(L"Data:uiButton", L"{0x0201, 0x0202, 0x0207, 0x0208, 0x0204, 0x0205, 0x0200}") - TEST_METHOD_PROPERTY(L"Data:uiModifierKeystate", L"{0x0000, 0x0004, 0x0008}") + // None, SHIFT, LEFT_CONTROL, RIGHT_ALT, RIGHT_ALT | LEFT_CONTROL + TEST_METHOD_PROPERTY(L"Data:uiModifierKeystate", L"{0x0000, 0x0010, 0x0008, 0x0001, 0x0009}") END_TEST_METHOD_PROPERTIES() Log::Comment(L"Starting test..."); @@ -523,7 +529,8 @@ class MouseInputTest { BEGIN_TEST_METHOD_PROPERTIES() TEST_METHOD_PROPERTY(L"Data:sScrollDelta", L"{-120, 120, -10000, 32736}") - TEST_METHOD_PROPERTY(L"Data:uiModifierKeystate", L"{0x0000, 0x0004, 0x0008}") + // None, SHIFT, LEFT_CONTROL, RIGHT_ALT, RIGHT_ALT | LEFT_CONTROL + TEST_METHOD_PROPERTY(L"Data:uiModifierKeystate", L"{0x0000, 0x0010, 0x0008, 0x0001, 0x0009}") END_TEST_METHOD_PROPERTIES() Log::Comment(L"Starting test..."); diff --git a/src/terminal/input/mouseInput.cpp b/src/terminal/input/mouseInput.cpp index 6aecb68b7a7..5d9f7a7d6a5 100644 --- a/src/terminal/input/mouseInput.cpp +++ b/src/terminal/input/mouseInput.cpp @@ -133,8 +133,8 @@ constexpr unsigned int TerminalInput::s_GetPressedButton(const MouseButtonState // 11 - released (none) // Next three bits indicate modifier keys: // 0x04 - shift (This never makes it through, as our emulator is skipped when shift is pressed.) -// 0x08 - ctrl -// 0x10 - meta +// 0x08 - meta +// 0x10 - ctrl // 32 (x20) is added for "hover" events: // "For example, motion into cell x,y with button 1 down is reported as `CSI M @ CxCy`. // ( @ = 32 + 0 (button 1) + 32 (motion indicator) ). @@ -146,7 +146,7 @@ constexpr unsigned int TerminalInput::s_GetPressedButton(const MouseButtonState // Parameters: // - button - the message to decode. // - isHover - whether or not this is a hover event -// - modifierKeyState - alt/ctrl/shift key hold state +// - modifierKeyState - the modifier keys _in console format_ // - delta - scroll wheel delta // Return value: // - the int representing the equivalent X button encoding. @@ -188,12 +188,10 @@ static constexpr int _windowsButtonToXEncoding(const unsigned int button, xvalue += 0x20; } - // Shift will never pass through to us, because shift is used by the host to skip VT mouse and use the default handler. - // TODO: MSFT:8804719 Add an option to disable/remap shift as a bypass for VT mousemode handling - // xvalue += (modifierKeyState & MK_SHIFT) ? 0x04 : 0x00; - xvalue += (modifierKeyState & MK_CONTROL) ? 0x08 : 0x00; - // Unfortunately, we don't get meta/alt as a part of mouse events. Only Ctrl and Shift. - // xvalue += (modifierKeyState & MK_META) ? 0x10 : 0x00; + // Use Any here with the multi-flag constants -- they capture left/right key state + WI_UpdateFlag(xvalue, 0x04, WI_IsAnyFlagSet(modifierKeyState, SHIFT_PRESSED)); + WI_UpdateFlag(xvalue, 0x08, WI_IsAnyFlagSet(modifierKeyState, ALT_PRESSED)); + WI_UpdateFlag(xvalue, 0x10, WI_IsAnyFlagSet(modifierKeyState, CTRL_PRESSED)); return xvalue; } @@ -206,6 +204,7 @@ static constexpr int _windowsButtonToXEncoding(const unsigned int button, // See MSFT:19461988 and https://github.com/Microsoft/console/issues/296 // Parameters: // - button - the message to decode. +// - modifierKeyState - the modifier keys _in console format_ // Return value: // - the int representing the equivalent X button encoding. static constexpr int _windowsButtonToSGREncoding(const unsigned int button, @@ -247,12 +246,10 @@ static constexpr int _windowsButtonToSGREncoding(const unsigned int button, xvalue += 0x20; } - // Shift will never pass through to us, because shift is used by the host to skip VT mouse and use the default handler. - // TODO: MSFT:8804719 Add an option to disable/remap shift as a bypass for VT mousemode handling - // xvalue += (modifierKeyState & MK_SHIFT) ? 0x04 : 0x00; - xvalue += (modifierKeyState & MK_CONTROL) ? 0x08 : 0x00; - // Unfortunately, we don't get meta/alt as a part of mouse events. Only Ctrl and Shift. - // xvalue += (modifierKeyState & MK_META) ? 0x10 : 0x00; + // Use Any here with the multi-flag constants -- they capture left/right key state + WI_UpdateFlag(xvalue, 0x04, WI_IsAnyFlagSet(modifierKeyState, SHIFT_PRESSED)); + WI_UpdateFlag(xvalue, 0x08, WI_IsAnyFlagSet(modifierKeyState, ALT_PRESSED)); + WI_UpdateFlag(xvalue, 0x10, WI_IsAnyFlagSet(modifierKeyState, CTRL_PRESSED)); return xvalue; }