AutoKey思想的應用(一)
進行某e化專案的過程中,用戶使用的一個設備是由第三方提供的,但為了實現自動操作第三方提供的軟件程序,想了几個方案:
1. 使用屏幕錄制,然后重放來實現自動操作,雖然在技朮上實現沒有問題,但效果不佳,主要是需要在最終用戶使用前要錄制,而且一旦軟件程序被移動位置,整個就失效了,所以不可靠(not stateble)
2. 第二種方案,用VC Spy++來找到窗口,然后模擬消息事件發送到指定的控件中。用Notepad.exe可以成功,但到了正式環境卻不行,原因是第三方開發的軟件程序使用的不是標准windows控件,而是自己組合的,消息也是自定議的(_USERMSG+),所以要用Spy++仔細查找方可。這種方法比較笨拙不說,而且不易作成一個通過的模塊
3. 模擬Keyboard消息,向當前活動窗口發送快捷鍵。這個方法比較正規,所以下面展示重要代碼
public class AutoKey
{
public void SendKeyWithAlt(string keys)
{
//Press Alt Key
structInput.ki.wVk = (ushort)VK.MENU;
intReturn = SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
for (int i = 0; i < c_array.Length; i++)
{
structInput.ki.wVk = (ushort)c_array[i];
structInput.ki.wScan = (ushort)MapVirtualKey(c_array[i], 0);
structInput.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_UNICODE;
intReturn = SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
Thread.Sleep(50);
}
//Keyup Alt
structInput.ki.dwFlags = KEYEVENTF_KEYUP;
structInput.ki.wVk = (ushort)VK.MENU;
intReturn = SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
}
public void SendKeys(string keys)
{
char[] c_array;
for (int i = 0; i < c_array.Length; i++)
{
structInput.ki.wVk = (ushort)c_array[i];
structInput.ki.wScan = (ushort)MapVirtualKey(c_array[i], 0);
structInput.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_UNICODE ;
intReturn = SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
Thread.Sleep(50);
}
}
}
}
調用代碼如下:
private void button1_Click(object sender, EventArgs e)
{
AutoKey abc = new AutoKey();
abc.ActiveWindow("notepad");
abc.SendKeyWithAlt("F");
Thread.Sleep(50);
abc.SendKeys("A");
IntPtr p1 = AutoKey.FindWindow("Notepad", "Untitled - Notepad");
if (p1 == IntPtr.Zero)
{
return;
}
IntPtr p2 = AutoKey.FindWindow("#32770", "Save As");
IntPtr p3 = AutoKey.GetParent(p2);
int i = 10;
while (p3 != p1 && i++ < 100)
{
Thread.Sleep(10);
p3 = AutoKey.GetParent(p2);
}
abc.SendKeys("MMM");
Thread.Sleep(50);
abc.SendKeyWithAlt("S");
}