655 lines
30 KiB
C++
655 lines
30 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "precomp.h"
|
|
#include <wextestclass.h>
|
|
#include "../../inc/consoletaeftemplates.hpp"
|
|
|
|
#include "../terminal/input/terminalInput.hpp"
|
|
|
|
using namespace WEX::Common;
|
|
using namespace WEX::Logging;
|
|
using namespace WEX::TestExecution;
|
|
|
|
namespace Microsoft
|
|
{
|
|
namespace Console
|
|
{
|
|
namespace VirtualTerminal
|
|
{
|
|
class MouseInputTest;
|
|
};
|
|
};
|
|
};
|
|
using namespace Microsoft::Console::VirtualTerminal;
|
|
|
|
// For magic reasons, this has to live outside the class. Something wonderful about TAEF macros makes it
|
|
// invisible to the linker when inside the class.
|
|
static const wchar_t* s_pwszInputExpected;
|
|
|
|
static wchar_t s_pwszExpectedBuffer[BYTE_MAX]; // big enough for anything
|
|
|
|
static COORD s_rgTestCoords[] = {
|
|
{ 0, 0 },
|
|
{ 0, 1 },
|
|
{ 1, 1 },
|
|
{ 2, 2 },
|
|
{ 94, 94 }, // 94+1+32 = 127
|
|
{ 95, 95 }, // 95+1+32 = 128, this is the ascii boundary
|
|
{ 96, 96 },
|
|
{ 127, 127 },
|
|
{ 128, 128 },
|
|
{ SHORT_MAX - 33, SHORT_MAX - 33 },
|
|
{ SHORT_MAX - 32, SHORT_MAX - 32 },
|
|
};
|
|
|
|
// Note: We're going to be changing the value of the third char (the space) of
|
|
// these strings as we test things with this array, to alter the expected button value.
|
|
// The default value is the button=WM_LBUTTONDOWN case, which is element[3]=' '
|
|
static const wchar_t* s_rgDefaultTestOutput[] = {
|
|
L"\x1b[M !!",
|
|
L"\x1b[M !\"",
|
|
L"\x1b[M \"\"",
|
|
L"\x1b[M ##",
|
|
L"\x1b[M \x7f\x7f",
|
|
L"\x1b[M \x80\x80", // 95 - This and below will always fail for default (non utf8)
|
|
L"\x1b[M \x81\x81",
|
|
L"\x1b[M \x00A0\x00A0", //127
|
|
L"\x1b[M \x00A1\x00A1",
|
|
L"\x1b[M \x7FFF\x7FFF", // FFDE
|
|
L"\x1b[M \x8000\x8000", // This one will always fail for Default and UTF8
|
|
};
|
|
|
|
// Note: We're going to be changing the value of the third char (the space) of
|
|
// these strings as we test things with this array, to alter the expected button value.
|
|
// The default value is the button=WM_LBUTTONDOWN case, which is element[3]='0'
|
|
// We're also going to change the last element, for button-down (M) vs button-up (m)
|
|
static const wchar_t* s_rgSgrTestOutput[] = {
|
|
L"\x1b[<%d;1;1M",
|
|
L"\x1b[<%d;1;2M",
|
|
L"\x1b[<%d;2;2M",
|
|
L"\x1b[<%d;3;3M",
|
|
L"\x1b[<%d;95;95M",
|
|
L"\x1b[<%d;96;96M", // 95 - This and below will always fail for default (non utf8)
|
|
L"\x1b[<%d;97;97M",
|
|
L"\x1b[<%d;128;128M", //127
|
|
L"\x1b[<%d;129;129M",
|
|
L"\x1b[<%d;32735;32735M", // FFDE
|
|
L"\x1b[<%d;32736;32736M",
|
|
};
|
|
|
|
static int s_iTestCoordsLength = ARRAYSIZE(s_rgTestCoords);
|
|
|
|
class MouseInputTest
|
|
{
|
|
public:
|
|
TEST_CLASS(MouseInputTest);
|
|
|
|
static void s_MouseInputTestCallback(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& events)
|
|
{
|
|
Log::Comment(L"MouseInput successfully generated a sequence for the input, and sent it.");
|
|
|
|
size_t cInputExpected = 0;
|
|
VERIFY_SUCCEEDED(StringCchLengthW(s_pwszInputExpected, STRSAFE_MAX_CCH, &cInputExpected));
|
|
|
|
if (VERIFY_ARE_EQUAL(cInputExpected, events.size(), L"Verify expected and actual input array lengths matched."))
|
|
{
|
|
Log::Comment(L"We are expecting always key events and always key down. All other properties should not be written by simulated keys.");
|
|
|
|
for (size_t i = 0; i < events.size(); ++i)
|
|
{
|
|
KeyEvent expectedKeyEvent(TRUE, 1, 0, 0, s_pwszInputExpected[i], 0);
|
|
KeyEvent testKeyEvent = *static_cast<const KeyEvent* const>(events[i].get());
|
|
VERIFY_ARE_EQUAL(expectedKeyEvent, testKeyEvent, NoThrowString().Format(L"Chars='%c','%c'", s_pwszInputExpected[i], testKeyEvent.GetCharData()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void ClearTestBuffer()
|
|
{
|
|
memset(s_pwszExpectedBuffer, 0, ARRAYSIZE(s_pwszExpectedBuffer) * sizeof(wchar_t));
|
|
}
|
|
|
|
// Routine Description:
|
|
// Constructs a string from s_rgDefaultTestOutput with the third char
|
|
// correctly filled in to match uiButton.
|
|
wchar_t* BuildDefaultTestOutput(const wchar_t* pwchTestOutput, unsigned int uiButton, short sModifierKeystate, short sScrollDelta)
|
|
{
|
|
Log::Comment(NoThrowString().Format(L"Input Test Output:\'%s\'", pwchTestOutput));
|
|
// Copy the expected output into the buffer
|
|
size_t cchInputExpected = 0;
|
|
VERIFY_SUCCEEDED(StringCchLengthW(pwchTestOutput, STRSAFE_MAX_CCH, &cchInputExpected));
|
|
VERIFY_ARE_EQUAL(cchInputExpected, 6ul);
|
|
|
|
ClearTestBuffer();
|
|
memcpy(s_pwszExpectedBuffer, pwchTestOutput, cchInputExpected * sizeof(wchar_t));
|
|
|
|
// Change the expected button value
|
|
wchar_t wch = GetDefaultCharFromButton(uiButton, sModifierKeystate, sScrollDelta);
|
|
Log::Comment(NoThrowString().Format(L"Button Char was:\'%d\' for uiButton '%d", (int)wch, uiButton));
|
|
|
|
s_pwszExpectedBuffer[3] = wch;
|
|
Log::Comment(NoThrowString().Format(L"Expected Input:\'%s\'", s_pwszExpectedBuffer));
|
|
return s_pwszExpectedBuffer;
|
|
}
|
|
|
|
// Routine Description:
|
|
// Constructs a string from s_rgSgrTestOutput with the third and last chars
|
|
// correctly filled in to match uiButton.
|
|
wchar_t* BuildSGRTestOutput(const wchar_t* pwchTestOutput, unsigned int uiButton, short sModifierKeystate, short sScrollDelta)
|
|
{
|
|
ClearTestBuffer();
|
|
|
|
// Copy the expected output into the buffer
|
|
swprintf_s(s_pwszExpectedBuffer, BYTE_MAX, pwchTestOutput, GetSgrCharFromButton(uiButton, sModifierKeystate, sScrollDelta));
|
|
|
|
size_t cchInputExpected = 0;
|
|
VERIFY_SUCCEEDED(StringCchLengthW(s_pwszExpectedBuffer, STRSAFE_MAX_CCH, &cchInputExpected));
|
|
|
|
s_pwszExpectedBuffer[cchInputExpected - 1] = IsButtonDown(uiButton) ? L'M' : L'm';
|
|
|
|
Log::Comment(NoThrowString().Format(L"Expected Input:\'%s\'", s_pwszExpectedBuffer));
|
|
return s_pwszExpectedBuffer;
|
|
}
|
|
|
|
wchar_t GetDefaultCharFromButton(unsigned int uiButton, short sModifierKeystate, short sScrollDelta)
|
|
{
|
|
wchar_t wch = L'\x0';
|
|
Log::Comment(NoThrowString().Format(L"uiButton '%d'", uiButton));
|
|
switch (uiButton)
|
|
{
|
|
case WM_LBUTTONDBLCLK:
|
|
case WM_LBUTTONDOWN:
|
|
wch = L' ';
|
|
break;
|
|
case WM_LBUTTONUP:
|
|
case WM_MBUTTONUP:
|
|
case WM_RBUTTONUP:
|
|
wch = L'#';
|
|
break;
|
|
case WM_RBUTTONDOWN:
|
|
case WM_RBUTTONDBLCLK:
|
|
wch = L'\"';
|
|
break;
|
|
case WM_MBUTTONDOWN:
|
|
case WM_MBUTTONDBLCLK:
|
|
wch = L'!';
|
|
break;
|
|
case WM_MOUSEWHEEL:
|
|
case WM_MOUSEHWHEEL:
|
|
Log::Comment(NoThrowString().Format(L"MOUSEWHEEL"));
|
|
wch = L'`' + (sScrollDelta > 0 ? 0 : 1);
|
|
break;
|
|
case WM_MOUSEMOVE:
|
|
default:
|
|
Log::Comment(NoThrowString().Format(L"DEFAULT"));
|
|
wch = L'\x0';
|
|
break;
|
|
}
|
|
// 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;
|
|
}
|
|
|
|
int GetSgrCharFromButton(unsigned int uiButton, short sModifierKeystate, short sScrollDelta)
|
|
{
|
|
int result = 0;
|
|
switch (uiButton)
|
|
{
|
|
case WM_LBUTTONDBLCLK:
|
|
case WM_LBUTTONDOWN:
|
|
case WM_LBUTTONUP:
|
|
result = 0;
|
|
break;
|
|
case WM_MBUTTONUP:
|
|
case WM_MBUTTONDOWN:
|
|
case WM_MBUTTONDBLCLK:
|
|
result = 1;
|
|
break;
|
|
case WM_RBUTTONUP:
|
|
case WM_RBUTTONDOWN:
|
|
case WM_RBUTTONDBLCLK:
|
|
result = 2;
|
|
break;
|
|
case WM_MOUSEMOVE:
|
|
result = 3 + 0x20; // we add 0x20 to hover events, which are all encoded as WM_MOUSEMOVE events
|
|
break;
|
|
case WM_MOUSEWHEEL:
|
|
case WM_MOUSEHWHEEL:
|
|
result = (sScrollDelta > 0 ? 64 : 65);
|
|
break;
|
|
default:
|
|
result = 0;
|
|
break;
|
|
}
|
|
// 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;
|
|
}
|
|
|
|
bool IsButtonDown(unsigned int uiButton)
|
|
{
|
|
bool fIsDown = false;
|
|
switch (uiButton)
|
|
{
|
|
case WM_LBUTTONDBLCLK:
|
|
case WM_LBUTTONDOWN:
|
|
case WM_RBUTTONDOWN:
|
|
case WM_RBUTTONDBLCLK:
|
|
case WM_MBUTTONDOWN:
|
|
case WM_MBUTTONDBLCLK:
|
|
case WM_MOUSEWHEEL:
|
|
case WM_MOUSEHWHEEL:
|
|
fIsDown = true;
|
|
break;
|
|
}
|
|
return fIsDown;
|
|
}
|
|
|
|
/* From winuser.h - Needed to manually specify the test properties
|
|
#define WM_MOUSEFIRST 0x0200
|
|
#define WM_MOUSEMOVE 0x0200
|
|
#define WM_LBUTTONDOWN 0x0201
|
|
#define WM_LBUTTONUP 0x0202
|
|
#define WM_LBUTTONDBLCLK 0x0203
|
|
#define WM_RBUTTONDOWN 0x0204
|
|
#define WM_RBUTTONUP 0x0205
|
|
#define WM_RBUTTONDBLCLK 0x0206
|
|
#define WM_MBUTTONDOWN 0x0207
|
|
#define WM_MBUTTONUP 0x0208
|
|
#define WM_MBUTTONDBLCLK 0x0209
|
|
#if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
|
|
#define WM_MOUSEWHEEL 0x020A
|
|
#endif
|
|
#if (_WIN32_WINNT >= 0x0500)
|
|
#define WM_XBUTTONDOWN 0x020B
|
|
#define WM_XBUTTONUP 0x020C
|
|
#define WM_XBUTTONDBLCLK 0x020D
|
|
#endif
|
|
#if (_WIN32_WINNT >= 0x0600)
|
|
#define WM_MOUSEHWHEEL 0x020E
|
|
*/
|
|
TEST_METHOD(DefaultModeTests)
|
|
{
|
|
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, 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...");
|
|
|
|
std::unique_ptr<TerminalInput> mouseInput = std::make_unique<TerminalInput>(s_MouseInputTestCallback);
|
|
|
|
unsigned int uiModifierKeystate = 0;
|
|
VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"uiModifierKeystate", uiModifierKeystate));
|
|
short sModifierKeystate = (SHORT)uiModifierKeystate;
|
|
short sScrollDelta = 0;
|
|
|
|
unsigned int uiButton;
|
|
VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"uiButton", uiButton));
|
|
|
|
bool fExpectedKeyHandled = false;
|
|
s_pwszInputExpected = L"\x0";
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled, mouseInput->HandleMouse({ 0, 0 }, uiButton, sModifierKeystate, sScrollDelta, {}));
|
|
|
|
mouseInput->SetInputMode(TerminalInput::Mode::DefaultMouseTracking, true);
|
|
|
|
for (int i = 0; i < s_iTestCoordsLength; i++)
|
|
{
|
|
COORD Coord = s_rgTestCoords[i];
|
|
fExpectedKeyHandled = (Coord.X <= 94 && Coord.Y <= 94);
|
|
Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y));
|
|
|
|
s_pwszInputExpected = BuildDefaultTestOutput(s_rgDefaultTestOutput[i], uiButton, sModifierKeystate, sScrollDelta);
|
|
|
|
// validate translation
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled,
|
|
mouseInput->HandleMouse(Coord,
|
|
uiButton,
|
|
sModifierKeystate,
|
|
sScrollDelta,
|
|
{}),
|
|
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
|
}
|
|
|
|
mouseInput->SetInputMode(TerminalInput::Mode::ButtonEventMouseTracking, true);
|
|
for (int i = 0; i < s_iTestCoordsLength; i++)
|
|
{
|
|
COORD Coord = s_rgTestCoords[i];
|
|
fExpectedKeyHandled = (Coord.X <= 94 && Coord.Y <= 94);
|
|
Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y));
|
|
|
|
s_pwszInputExpected = BuildDefaultTestOutput(s_rgDefaultTestOutput[i], uiButton, sModifierKeystate, sScrollDelta);
|
|
|
|
// validate translation
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled,
|
|
mouseInput->HandleMouse(Coord,
|
|
uiButton,
|
|
sModifierKeystate,
|
|
sScrollDelta,
|
|
{}),
|
|
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
|
}
|
|
|
|
mouseInput->SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, true);
|
|
for (int i = 0; i < s_iTestCoordsLength; i++)
|
|
{
|
|
COORD Coord = s_rgTestCoords[i];
|
|
fExpectedKeyHandled = (Coord.X <= 94 && Coord.Y <= 94);
|
|
Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y));
|
|
|
|
s_pwszInputExpected = BuildDefaultTestOutput(s_rgDefaultTestOutput[i], uiButton, sModifierKeystate, sScrollDelta);
|
|
|
|
// validate translation
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled,
|
|
mouseInput->HandleMouse(Coord,
|
|
uiButton,
|
|
sModifierKeystate,
|
|
sScrollDelta,
|
|
{}),
|
|
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
|
}
|
|
}
|
|
TEST_METHOD(Utf8ModeTests)
|
|
{
|
|
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, 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...");
|
|
|
|
std::unique_ptr<TerminalInput> mouseInput = std::make_unique<TerminalInput>(s_MouseInputTestCallback);
|
|
|
|
unsigned int uiModifierKeystate = 0;
|
|
VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"uiModifierKeystate", uiModifierKeystate));
|
|
short sModifierKeystate = (SHORT)uiModifierKeystate;
|
|
short sScrollDelta = 0;
|
|
|
|
unsigned int uiButton;
|
|
VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"uiButton", uiButton));
|
|
|
|
bool fExpectedKeyHandled = false;
|
|
s_pwszInputExpected = L"\x0";
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled, mouseInput->HandleMouse({ 0, 0 }, uiButton, sModifierKeystate, sScrollDelta, {}));
|
|
|
|
mouseInput->SetInputMode(TerminalInput::Mode::Utf8MouseEncoding, true);
|
|
|
|
short MaxCoord = SHORT_MAX - 33;
|
|
|
|
mouseInput->SetInputMode(TerminalInput::Mode::DefaultMouseTracking, true);
|
|
for (int i = 0; i < s_iTestCoordsLength; i++)
|
|
{
|
|
COORD Coord = s_rgTestCoords[i];
|
|
|
|
fExpectedKeyHandled = (Coord.X <= MaxCoord && Coord.Y <= MaxCoord);
|
|
Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y));
|
|
s_pwszInputExpected = BuildDefaultTestOutput(s_rgDefaultTestOutput[i], uiButton, sModifierKeystate, sScrollDelta);
|
|
|
|
// validate translation
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled,
|
|
mouseInput->HandleMouse(Coord,
|
|
uiButton,
|
|
sModifierKeystate,
|
|
sScrollDelta,
|
|
{}),
|
|
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
|
}
|
|
|
|
mouseInput->SetInputMode(TerminalInput::Mode::ButtonEventMouseTracking, true);
|
|
for (int i = 0; i < s_iTestCoordsLength; i++)
|
|
{
|
|
COORD Coord = s_rgTestCoords[i];
|
|
|
|
fExpectedKeyHandled = (Coord.X <= MaxCoord && Coord.Y <= MaxCoord);
|
|
Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y));
|
|
s_pwszInputExpected = BuildDefaultTestOutput(s_rgDefaultTestOutput[i], uiButton, sModifierKeystate, sScrollDelta);
|
|
|
|
// validate translation
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled,
|
|
mouseInput->HandleMouse(Coord,
|
|
uiButton,
|
|
sModifierKeystate,
|
|
sScrollDelta,
|
|
{}),
|
|
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
|
}
|
|
|
|
mouseInput->SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, true);
|
|
for (int i = 0; i < s_iTestCoordsLength; i++)
|
|
{
|
|
COORD Coord = s_rgTestCoords[i];
|
|
|
|
fExpectedKeyHandled = (Coord.X <= MaxCoord && Coord.Y <= MaxCoord);
|
|
Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y));
|
|
s_pwszInputExpected = BuildDefaultTestOutput(s_rgDefaultTestOutput[i], uiButton, sModifierKeystate, sScrollDelta);
|
|
|
|
// validate translation
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled,
|
|
mouseInput->HandleMouse(Coord,
|
|
uiButton,
|
|
sModifierKeystate,
|
|
sScrollDelta,
|
|
{}),
|
|
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
|
}
|
|
}
|
|
|
|
TEST_METHOD(SgrModeTests)
|
|
{
|
|
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}")
|
|
// 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...");
|
|
|
|
std::unique_ptr<TerminalInput> mouseInput = std::make_unique<TerminalInput>(s_MouseInputTestCallback);
|
|
unsigned int uiModifierKeystate = 0;
|
|
VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"uiModifierKeystate", uiModifierKeystate));
|
|
short sModifierKeystate = (SHORT)uiModifierKeystate;
|
|
short sScrollDelta = 0;
|
|
|
|
unsigned int uiButton;
|
|
VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"uiButton", uiButton));
|
|
|
|
bool fExpectedKeyHandled = false;
|
|
s_pwszInputExpected = L"\x0";
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled, mouseInput->HandleMouse({ 0, 0 }, uiButton, sModifierKeystate, sScrollDelta, {}));
|
|
|
|
mouseInput->SetInputMode(TerminalInput::Mode::SgrMouseEncoding, true);
|
|
|
|
// SGR Mode should be able to handle any arbitrary coords.
|
|
// However, mouse moves are only handled in Any Event mode
|
|
fExpectedKeyHandled = uiButton != WM_MOUSEMOVE;
|
|
|
|
mouseInput->SetInputMode(TerminalInput::Mode::DefaultMouseTracking, true);
|
|
for (int i = 0; i < s_iTestCoordsLength; i++)
|
|
{
|
|
COORD Coord = s_rgTestCoords[i];
|
|
|
|
Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y));
|
|
s_pwszInputExpected = BuildSGRTestOutput(s_rgSgrTestOutput[i], uiButton, sModifierKeystate, sScrollDelta);
|
|
|
|
// validate translation
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled,
|
|
mouseInput->HandleMouse(Coord, uiButton, sModifierKeystate, sScrollDelta, {}),
|
|
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
|
}
|
|
|
|
mouseInput->SetInputMode(TerminalInput::Mode::ButtonEventMouseTracking, true);
|
|
for (int i = 0; i < s_iTestCoordsLength; i++)
|
|
{
|
|
COORD Coord = s_rgTestCoords[i];
|
|
|
|
Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y));
|
|
s_pwszInputExpected = BuildSGRTestOutput(s_rgSgrTestOutput[i], uiButton, sModifierKeystate, sScrollDelta);
|
|
|
|
// validate translation
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled,
|
|
mouseInput->HandleMouse(Coord,
|
|
uiButton,
|
|
sModifierKeystate,
|
|
sScrollDelta,
|
|
{}),
|
|
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
|
}
|
|
|
|
fExpectedKeyHandled = true;
|
|
mouseInput->SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, true);
|
|
for (int i = 0; i < s_iTestCoordsLength; i++)
|
|
{
|
|
COORD Coord = s_rgTestCoords[i];
|
|
|
|
Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y));
|
|
s_pwszInputExpected = BuildSGRTestOutput(s_rgSgrTestOutput[i], uiButton, sModifierKeystate, sScrollDelta);
|
|
|
|
// validate translation
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled,
|
|
mouseInput->HandleMouse(Coord,
|
|
uiButton,
|
|
sModifierKeystate,
|
|
sScrollDelta,
|
|
{}),
|
|
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
|
}
|
|
}
|
|
|
|
TEST_METHOD(ScrollWheelTests)
|
|
{
|
|
BEGIN_TEST_METHOD_PROPERTIES()
|
|
TEST_METHOD_PROPERTY(L"Data:sScrollDelta", L"{-120, 120, -10000, 32736}")
|
|
// 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...");
|
|
|
|
std::unique_ptr<TerminalInput> mouseInput = std::make_unique<TerminalInput>(s_MouseInputTestCallback);
|
|
unsigned int uiModifierKeystate = 0;
|
|
VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"uiModifierKeystate", uiModifierKeystate));
|
|
short sModifierKeystate = (SHORT)uiModifierKeystate;
|
|
|
|
unsigned int uiButton = WM_MOUSEWHEEL;
|
|
int iScrollDelta = 0;
|
|
VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"sScrollDelta", iScrollDelta));
|
|
short sScrollDelta = (short)(iScrollDelta);
|
|
|
|
bool fExpectedKeyHandled = false;
|
|
s_pwszInputExpected = L"\x0";
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled, mouseInput->HandleMouse({ 0, 0 }, uiButton, sModifierKeystate, sScrollDelta, {}));
|
|
|
|
// Default Tracking, Default Encoding
|
|
mouseInput->SetInputMode(TerminalInput::Mode::DefaultMouseTracking, true);
|
|
|
|
for (int i = 0; i < s_iTestCoordsLength; i++)
|
|
{
|
|
COORD Coord = s_rgTestCoords[i];
|
|
fExpectedKeyHandled = (Coord.X <= 94 && Coord.Y <= 94);
|
|
|
|
Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y));
|
|
s_pwszInputExpected = BuildDefaultTestOutput(s_rgDefaultTestOutput[i], uiButton, sModifierKeystate, sScrollDelta);
|
|
|
|
// validate translation
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled,
|
|
mouseInput->HandleMouse(Coord,
|
|
uiButton,
|
|
sModifierKeystate,
|
|
sScrollDelta,
|
|
{}),
|
|
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
|
}
|
|
|
|
// Default Tracking, UTF8 Encoding
|
|
mouseInput->SetInputMode(TerminalInput::Mode::Utf8MouseEncoding, true);
|
|
short MaxCoord = SHORT_MAX - 33;
|
|
for (int i = 0; i < s_iTestCoordsLength; i++)
|
|
{
|
|
COORD Coord = s_rgTestCoords[i];
|
|
fExpectedKeyHandled = (Coord.X <= MaxCoord && Coord.Y <= MaxCoord);
|
|
|
|
Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y));
|
|
s_pwszInputExpected = BuildDefaultTestOutput(s_rgDefaultTestOutput[i], uiButton, sModifierKeystate, sScrollDelta);
|
|
|
|
// validate translation
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled,
|
|
mouseInput->HandleMouse(Coord,
|
|
uiButton,
|
|
sModifierKeystate,
|
|
sScrollDelta,
|
|
{}),
|
|
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
|
}
|
|
|
|
// Default Tracking, SGR Encoding
|
|
mouseInput->SetInputMode(TerminalInput::Mode::SgrMouseEncoding, true);
|
|
fExpectedKeyHandled = true; // SGR Mode should be able to handle any arbitrary coords.
|
|
for (int i = 0; i < s_iTestCoordsLength; i++)
|
|
{
|
|
COORD Coord = s_rgTestCoords[i];
|
|
|
|
Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y));
|
|
s_pwszInputExpected = BuildSGRTestOutput(s_rgSgrTestOutput[i], uiButton, sModifierKeystate, sScrollDelta);
|
|
|
|
// validate translation
|
|
VERIFY_ARE_EQUAL(fExpectedKeyHandled,
|
|
mouseInput->HandleMouse(Coord,
|
|
uiButton,
|
|
sModifierKeystate,
|
|
sScrollDelta,
|
|
{}),
|
|
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
|
}
|
|
}
|
|
|
|
TEST_METHOD(AlternateScrollModeTests)
|
|
{
|
|
Log::Comment(L"Starting test...");
|
|
std::unique_ptr<TerminalInput> mouseInput = std::make_unique<TerminalInput>(s_MouseInputTestCallback);
|
|
const short noModifierKeys = 0;
|
|
|
|
Log::Comment(L"Enable alternate scroll mode in the alt screen buffer");
|
|
mouseInput->UseAlternateScreenBuffer();
|
|
mouseInput->SetInputMode(TerminalInput::Mode::AlternateScroll, true);
|
|
|
|
Log::Comment(L"Test mouse wheel scrolling up");
|
|
s_pwszInputExpected = L"\x1B[A";
|
|
VERIFY_IS_TRUE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, WHEEL_DELTA, {}));
|
|
|
|
Log::Comment(L"Test mouse wheel scrolling down");
|
|
s_pwszInputExpected = L"\x1B[B";
|
|
VERIFY_IS_TRUE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, -WHEEL_DELTA, {}));
|
|
|
|
Log::Comment(L"Enable cursor keys mode");
|
|
mouseInput->SetInputMode(TerminalInput::Mode::CursorKey, true);
|
|
|
|
Log::Comment(L"Test mouse wheel scrolling up");
|
|
s_pwszInputExpected = L"\x1BOA";
|
|
VERIFY_IS_TRUE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, WHEEL_DELTA, {}));
|
|
|
|
Log::Comment(L"Test mouse wheel scrolling down");
|
|
s_pwszInputExpected = L"\x1BOB";
|
|
VERIFY_IS_TRUE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, -WHEEL_DELTA, {}));
|
|
|
|
Log::Comment(L"Confirm no effect when scroll mode is disabled");
|
|
mouseInput->UseAlternateScreenBuffer();
|
|
mouseInput->SetInputMode(TerminalInput::Mode::AlternateScroll, false);
|
|
VERIFY_IS_FALSE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, WHEEL_DELTA, {}));
|
|
|
|
Log::Comment(L"Confirm no effect when using the main buffer");
|
|
mouseInput->UseMainScreenBuffer();
|
|
mouseInput->SetInputMode(TerminalInput::Mode::AlternateScroll, true);
|
|
VERIFY_IS_FALSE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, WHEEL_DELTA, {}));
|
|
}
|
|
};
|