2872f147f8
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Every single time a PR is run, there are a bunch of warnings about whitespace in the .cs files, so I ran the code format on those files, without changing their contents, so it won't be flagged anymore. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [X] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [X] Tests added/passed <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Ran the code-format utility on the .cs files
239 lines
8.2 KiB
C#
239 lines
8.2 KiB
C#
//----------------------------------------------------------------------------------------------------------------------
|
|
// <copyright file="ViewportArea.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
// <summary>Wrapper and helper for instantiating and interacting with the main text region (viewport area) of the console.</summary>
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
namespace Conhost.UIA.Tests.Elements
|
|
{
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
|
|
using OpenQA.Selenium.Appium;
|
|
|
|
using WEX.Logging.Interop;
|
|
using WEX.TestExecution;
|
|
|
|
using Conhost.UIA.Tests.Common;
|
|
using Conhost.UIA.Tests.Common.NativeMethods;
|
|
using OpenQA.Selenium;
|
|
|
|
public class ViewportArea : IDisposable
|
|
{
|
|
private CmdApp app;
|
|
private Point clientTopLeft;
|
|
private Size sizeFont;
|
|
|
|
private ViewportStates state;
|
|
|
|
public enum ViewportStates
|
|
{
|
|
Normal,
|
|
Mark, // keyboard selection
|
|
Select, // mouse selection
|
|
Scroll
|
|
}
|
|
|
|
public ViewportArea(CmdApp app)
|
|
{
|
|
this.app = app;
|
|
|
|
this.state = ViewportStates.Normal;
|
|
|
|
this.InitializeFont();
|
|
this.InitializeWindow();
|
|
}
|
|
|
|
~ViewportArea()
|
|
{
|
|
this.Dispose(false);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
this.Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
// Don't need to dispose of anything now, but this helps maintain the pattern used by other controls.
|
|
}
|
|
|
|
private void InitializeFont()
|
|
{
|
|
AutoHelpers.LogInvariant("Initializing font data for viewport area...");
|
|
this.sizeFont = new Size();
|
|
|
|
IntPtr hCon = app.GetStdOutHandle();
|
|
Verify.IsNotNull(hCon, "Check that we obtained the console output handle.");
|
|
|
|
WinCon.CONSOLE_FONT_INFO cfi = new WinCon.CONSOLE_FONT_INFO();
|
|
NativeMethods.Win32BoolHelper(WinCon.GetCurrentConsoleFont(hCon, false, out cfi), "Attempt to get current console font.");
|
|
|
|
this.sizeFont.Width = cfi.dwFontSize.X;
|
|
this.sizeFont.Height = cfi.dwFontSize.Y;
|
|
AutoHelpers.LogInvariant("Font size is X:{0} Y:{1}", this.sizeFont.Width, this.sizeFont.Height);
|
|
}
|
|
|
|
private void InitializeWindow()
|
|
{
|
|
AutoHelpers.LogInvariant("Initializing window data for viewport area...");
|
|
|
|
IntPtr hWnd = app.GetWindowHandle();
|
|
|
|
User32.RECT lpRect;
|
|
User32.GetClientRect(hWnd, out lpRect);
|
|
|
|
int style = User32.GetWindowLong(hWnd, User32.GWL_STYLE);
|
|
int exStyle = User32.GetWindowLong(hWnd, User32.GWL_EXSTYLE);
|
|
|
|
Verify.IsTrue(User32.AdjustWindowRectEx(ref lpRect, style, false, exStyle));
|
|
|
|
this.clientTopLeft = new Point();
|
|
this.clientTopLeft.X = Math.Abs(lpRect.left);
|
|
this.clientTopLeft.Y = Math.Abs(lpRect.top);
|
|
AutoHelpers.LogInvariant("Top left corner of client area is at X:{0} Y:{1}", this.clientTopLeft.X, this.clientTopLeft.Y);
|
|
}
|
|
|
|
public void ExitModes()
|
|
{
|
|
app.UIRoot.SendKeys(Keys.Escape);
|
|
this.state = ViewportStates.Normal;
|
|
}
|
|
|
|
public void EnterMode(ViewportStates state)
|
|
{
|
|
if (state == ViewportStates.Normal)
|
|
{
|
|
ExitModes();
|
|
return;
|
|
}
|
|
|
|
var titleBar = app.UIRoot.FindElementByAccessibilityId("TitleBar");
|
|
app.Session.Mouse.ContextClick(titleBar.Coordinates);
|
|
|
|
Globals.WaitForTimeout();
|
|
var contextMenu = app.Session.FindElementByClassName(Globals.PopupMenuClassId);
|
|
|
|
var editButton = contextMenu.FindElementByName("Edit");
|
|
|
|
editButton.Click();
|
|
Globals.WaitForTimeout();
|
|
|
|
Globals.WaitForTimeout();
|
|
|
|
AppiumWebElement subMenuButton;
|
|
switch (state)
|
|
{
|
|
case ViewportStates.Mark:
|
|
subMenuButton = app.Session.FindElementByName("Mark");
|
|
break;
|
|
default:
|
|
throw new NotImplementedException(AutoHelpers.FormatInvariant("Set Mode doesn't yet support type of '{0}'", state.ToString()));
|
|
}
|
|
|
|
subMenuButton.Click();
|
|
Globals.WaitForTimeout();
|
|
|
|
this.state = state;
|
|
}
|
|
|
|
|
|
// Accepts Point in characters. Will convert to pixels and move to the right location relative to this viewport.
|
|
public void MouseMove(Point pt)
|
|
{
|
|
Log.Comment($"Character position {pt.X}, {pt.Y}");
|
|
|
|
Point modPoint = pt;
|
|
ConvertCharacterOffsetToPixelPosition(ref modPoint);
|
|
|
|
Log.Comment($"Pixel position {modPoint.X}, {modPoint.Y}");
|
|
|
|
app.Session.Mouse.MouseMove(app.UIRoot.Coordinates, modPoint.X, modPoint.Y);
|
|
}
|
|
|
|
public void MouseDown()
|
|
{
|
|
app.Session.Mouse.MouseDown(null);
|
|
}
|
|
|
|
public void MouseUp()
|
|
{
|
|
app.Session.Mouse.MouseUp(null);
|
|
}
|
|
|
|
private void ConvertCharacterOffsetToPixelPosition(ref Point pt)
|
|
{
|
|
// Scale by pixel count per character
|
|
pt.X *= this.sizeFont.Width;
|
|
pt.Y *= this.sizeFont.Height;
|
|
|
|
// Move it to center of character
|
|
pt.X += this.sizeFont.Width / 2;
|
|
pt.Y += this.sizeFont.Height / 2;
|
|
|
|
// Adjust to the top left corner of the client rectangle.
|
|
pt.X += this.clientTopLeft.X;
|
|
pt.Y += this.clientTopLeft.Y;
|
|
}
|
|
|
|
public WinCon.CHAR_INFO GetCharInfoAt(IntPtr handle, Point pt)
|
|
{
|
|
Size size = new Size(1, 1);
|
|
Rectangle rect = new Rectangle(pt, size);
|
|
|
|
WinCon.CHAR_INFO[,] data = GetCharInfoInRectangle(handle, rect);
|
|
|
|
return data[0, 0];
|
|
}
|
|
|
|
public WinCon.CHAR_INFO[,] GetCharInfoInRectangle(IntPtr handle, Rectangle rect)
|
|
{
|
|
WinCon.SMALL_RECT readRectangle = new WinCon.SMALL_RECT();
|
|
readRectangle.Top = (short)rect.Top;
|
|
readRectangle.Bottom = (short)(rect.Bottom - 1);
|
|
readRectangle.Left = (short)rect.Left;
|
|
readRectangle.Right = (short)(rect.Right - 1);
|
|
|
|
WinCon.COORD dataBufferSize = new WinCon.COORD();
|
|
dataBufferSize.X = (short)rect.Width;
|
|
dataBufferSize.Y = (short)rect.Height;
|
|
|
|
WinCon.COORD dataBufferPos = new WinCon.COORD();
|
|
dataBufferPos.X = 0;
|
|
dataBufferPos.Y = 0;
|
|
|
|
WinCon.CHAR_INFO[,] data = new WinCon.CHAR_INFO[dataBufferSize.Y, dataBufferSize.X];
|
|
|
|
NativeMethods.Win32BoolHelper(WinCon.ReadConsoleOutput(handle, data, dataBufferSize, dataBufferPos, ref readRectangle), string.Format("Attempting to read rectangle (L: {0}, T: {1}, R: {2}, B: {3}) from output buffer.", readRectangle.Left, readRectangle.Top, readRectangle.Right, readRectangle.Bottom));
|
|
|
|
return data;
|
|
}
|
|
|
|
public IEnumerable<string> GetLinesInRectangle(IntPtr handle, Rectangle rect)
|
|
{
|
|
WinCon.CHAR_INFO[,] data = GetCharInfoInRectangle(handle, rect);
|
|
List<string> lines = new List<string>();
|
|
|
|
for (int row = 0; row < data.GetLength(0); row++)
|
|
{
|
|
StringBuilder builder = new StringBuilder();
|
|
|
|
for (int col = 0; col < data.GetLength(1); col++)
|
|
{
|
|
char z = data[row, col].UnicodeChar;
|
|
builder.Append(z);
|
|
}
|
|
|
|
lines.Add(builder.ToString());
|
|
}
|
|
|
|
return lines;
|
|
}
|
|
}
|
|
} |