此部分我们通过System.Windows.Forms.SendKeys类中的Send方法来模拟通过键盘输入数据到相应的控件中。
使用 SendKeys 将键击和组合键击发送到活动应用程序。此类无法实例化。若要发送一个键击给某个类并立即继续程序流,请使用 Send。若要等待键击启动的任何进程,请使用 SendWait。
每个键都由一个或多个字符表示。若要指定单个键盘字符,请使用该字符本身。例如,若要表示字母 A,请将字符串“A”传递给方法。若要表示多个字符,请将各个附加字符追加到它之前的字符的后面。若要表示字母 A、B 和 C,请将参数指定为“ABC”。
加号 (+)、插入符号 (^)、百分号 (%)、波浪号 (~) 以及圆括号 ( ) 对 SendKeys 具有特殊含义。若要指定这些字符中的某个字符,请将其放在大括号 ({}) 内。例如,若要指定加号,请使用“{+}”。若要指定大括号字符,请使用“{{}”和“{}}”。中括号 ([ ]) 对 SendKeys 没有特殊含义,但必须将它们放在大括号内。在其他应用程序中,中括号具有特殊含义,此含义可能会在发生动态数据交换 (DDE) 时起重要作用。
SendKeys有两个重要的方法:
1. Send方法:向活动应用程序发送击键。
2. SendWait方法:向活动应用程序发送给定的键,然后等待消息被处理。
有关SendKeys的参考: 英文站点:http://msdn.microsoft.com/en-us/library/8c6yea83(VS.85).aspx 中文站点:http://msdn.microsoft.com/zh-cn/library/system.windows.forms.sendkeys_methods(VS.80).aspx |
下面我们通过一个实例来演示通过SendKeys类来模拟键盘操作进行数据输入和快捷菜单的打开:
using System;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Windows.Automation;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Forms;
namespace UIATest
{
class Program
{
static void Main(string[] args)
{
Process process = Process.Start(@"E:\WorkBook\ATP\WpfApp\bin\Debug\WpfApp.exe");
int processId = process.Id;
AutomationElement element = FindElementById(processId, "textBox1");
SendKeys sendkeys = new SendKeys();
sendkeys.Sendkeys(element, "Sending keys to input data");
Console.WriteLine(sendkeys.ToString());
sendkeys.Sendkeys(element, sendkeys.ContextMenu);
Console.WriteLine(sendkeys.ToString());
Console.WriteLine("Test finised.");
}
/// <summary>
/// Get the automation elemention of current form.
/// </summary>
/// <param name="processId">Process Id</param>
/// <returns>Target element</returns>
public static AutomationElement FindWindowByProcessId(int processId)
{
AutomationElement targetWindow = null;
int count = 0;
try
{
Process p = Process.GetProcessById(processId);
targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);
return targetWindow;
}
catch (Exception ex)
{
count++;
StringBuilder sb = new StringBuilder();
string message = sb.AppendLine(string.Format("Target window is not existing.try #{0}", count)).ToString();
if (count > 5)
{
throw new InvalidProgramException(message, ex);
}
else
{
return FindWindowByProcessId(processId);
}
}
}
/// <summary>
/// Get the automation element by automation Id.
/// </summary>
/// <param name="windowName">Window name</param>
/// <param name="automationId">Control automation Id</param>
/// <returns>Automatin element searched by automation Id</returns>
public static AutomationElement FindElementById(int processId, string automationId)
{
AutomationElement aeForm = FindWindowByProcessId(processId);
AutomationElement tarFindElement = aeForm.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.AutomationIdProperty, automationId));
return tarFindElement;
}
}
} |
我们自定义一个SendKeys类来对已有的SendKeys类进行优化,代码如下:
using System;
using System.Windows.Automation;
using System.Threading;
using System.Text;
using System.Windows.Forms;
namespace UIATest
{
public class SendKeys
{
StringBuilder builder = new StringBuilder();
public string Alt = "%";
public string ContextMenu = "+{F10}";
public string Ctrl = "^";
public string Shift = "+";
public string Enter = "{Enter}";
public string Delete = "{Del}";
public string Save = "^S";
public string SaveAll = "^+S";
public string Copy = "^C";
public string Cut = "^X";
public string Paste = "^V";
public string Undo = "^Z";
public string Redo = "^Y";
public string Print = "^P";
public string Help = "{F1}";
public string New = "^N";
public string[] Keys{ get; set; }
public void Sendkeys(AutomationElement element, string[] keys)
{
this.Keys = keys;
try
{
element.SetFocus();
}
catch (Exception exception)
{
throw new Exception("Cannot set focus to this element.", exception);
}
string myKeys = "";
foreach (string str2 in this.Keys)
{
myKeys = myKeys + str2;
}
Thread.Sleep(200);
if ((this.ContainsUnescapedKey(myKeys, '^') || this.ContainsUnescapedKey(myKeys, '%')) || this.ContainsUnescapedKey(myKeys, '+'))
{
myKeys = myKeys.ToLower();
}
System.Windows.Forms.SendKeys.SendWait(myKeys);
Thread.Sleep(0x3e8);
}
public void Sendkeys(AutomationElement element, string myKeys)
{
this.Keys = new string[1];
this.Keys[0] = myKeys;
try
{
element.SetFocus();
}
catch (Exception exception)
{
throw new Exception("Cannot set focus to this element.", exception);
}
Thread.Sleep(200);
if ((this.ContainsUnescapedKey(myKeys, '^') || this.ContainsUnescapedKey(myKeys, '%')) || this.ContainsUnescapedKey(myKeys, '+'))
{
myKeys = myKeys.ToLower();
}
System.Windows.Forms.SendKeys.SendWait(myKeys);
Thread.Sleep(0x3e8);
}
private bool ContainsUnescapedKey(string keys, char key)
{
for (int i = 0; i < keys.Length; i++)
{
if (keys[i] == key)
{
if ((i == 0) || (i == (keys.Length - 1)))
{
return true;
}
if ((keys[i - 1] != '{') || (keys[i + 1] != '}'))
{
return true;
}
}
}
return false;
}
private string KeysToString(string[] keys)
{
if (keys != null)
{
for (int i = 0; i < keys.Length; i++)
{
string str = keys[i];
if (str == null)
{
builder.Append(keys[i]);
}
int length = keys.Length - 1;
switch (str)
{
case "^":
builder.Append("Ctrl");
IsEquals(i, length, builder);
break;
case "+{F10}":
builder.Append("Open Context Menu");
IsEquals(i, length, builder);
break;
case "%":
builder.Append("Alt");
IsEquals(i, length, builder);
break;
case "+":
builder.Append("Shift");
IsEquals(i, length, builder);
break;
case "^S":
builder.Append("Save");
IsEquals(i, length, builder);
break;
case "^X":
builder.Append("Cut");
IsEquals(i, length, builder);
break;
case "^C":
builder.Append("Copy");
IsEquals(i, length, builder);
break;
case "^V":
builder.Append("Paste");
IsEquals(i, length, builder);
break;
case "^+S":
builder.Append("Save All");
IsEquals(i, length, builder);
break;
case "^P":
builder.Append("Print");
IsEquals(i, length, builder);
break;
case "^Z":
builder.Append("Undo");
IsEquals(i, length, builder);
break;
case "^Y":
builder.Append("Redo");
IsEquals(i, length, builder);
break;
case "^N":
builder.Append("New");
IsEquals(i, length, builder);
break;
default:
builder.Append(keys[i]);
IsEquals(i, length, builder);
break;
}
}
}
return builder.ToString();
}
void IsEquals(int i, int length, StringBuilder builder)
{
if(i<length)
builder.Append("+");
}
#region Public Method
public override string ToString()
{
return string.Format("Sendkeys to input data or operator with keys = '{0}'",
this.KeysToString(Keys));
}
#endregion
}
}
|
如下代码为对应的WPF窗体XAML代码:
<Window x:Class="WpfApp.SendKeysInputData"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SendKeysInputData" Height="250" Width="367">
<Grid>
<TextBox Margin="28,80,41,101" Name="textBox1">
<TextBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Open" />
<MenuItem Header="Save" />
<MenuItem Header="New" />
<MenuItem Header="Save As" />
<MenuItem Header="Load" />
<MenuItem Header="ReLoad" />
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
</Grid>
</Window>
|
本小节首先简单介绍了如何在.NET通过调用Win32 API来模拟键盘的操作,进而通过实例演示了模拟鼠标与模拟键盘在基于UI Automation的自动化测试中应用。