提交 3a3f05c6 编写于 作者: D Dustin Campbell

Make SendKeys faster by collecting inputs and blasting all at once

上级 3bce1ce5
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Roslyn.VisualStudio.Test.Utilities.Interop;
namespace Roslyn.VisualStudio.Test.Utilities.Input
......@@ -14,98 +15,98 @@ public SendKeys(VisualStudioInstance visualStudioInstance)
_visualStudioInstance = visualStudioInstance;
}
public void Send(KeyPress keyPress)
public void Send(object[] keys)
{
Send(keyPress.VirtualKey, keyPress.ShiftState);
}
public void Send(VirtualKey virtualKey, ShiftState shiftState = 0)
{
var foregroundWindow = IntPtr.Zero;
var inputBlocked = false;
var inputs = new List<User32.INPUT>(keys.Length);
try
foreach (var key in keys)
{
inputBlocked = IntegrationHelper.BlockInput();
foregroundWindow = IntegrationHelper.GetForegroundWindow();
_visualStudioInstance.ActivateMainWindow();
if ((shiftState & ShiftState.Shift) != 0)
if (key is string)
{
SendKey(VirtualKey.Shift, User32.KEYEVENTF_NONE);
var text = ((string)key)
.Replace("\r\n", "\r")
.Replace("\n", "\r");
foreach (var ch in text)
{
AddInputs(inputs, ch);
}
}
if ((shiftState & ShiftState.Ctrl) != 0)
else if (key is char)
{
SendKey(VirtualKey.Control, User32.KEYEVENTF_NONE);
AddInputs(inputs, (char)key);
}
if ((shiftState & ShiftState.Alt) != 0)
else if (key is VirtualKey)
{
SendKey(VirtualKey.Alt, User32.KEYEVENTF_NONE);
AddInputs(inputs, (VirtualKey)key);
}
SendKeyPressAndRelease(virtualKey);
if ((shiftState & ShiftState.Shift) != 0)
else if (key is KeyPress)
{
SendKey(VirtualKey.Shift, User32.KEYEVENTF_KEYUP);
AddInputs(inputs, (KeyPress)key);
}
if ((shiftState & ShiftState.Ctrl) != 0)
else if (key == null)
{
SendKey(VirtualKey.Control, User32.KEYEVENTF_KEYUP);
throw new ArgumentNullException(nameof(keys));
}
if ((shiftState & ShiftState.Alt) != 0)
else
{
SendKey(VirtualKey.Alt, User32.KEYEVENTF_KEYUP);
throw new ArgumentException($"Unexpected type encountered: {key.GetType()}", nameof(keys));
}
}
finally
{
if (foregroundWindow != IntPtr.Zero)
{
IntegrationHelper.SetForegroundWindow(foregroundWindow);
}
if (inputBlocked)
{
IntegrationHelper.UnblockInput();
}
}
SendInputs(inputs.ToArray());
}
public void Send(char character)
private static void AddInputs(List<User32.INPUT> inputs, char ch)
{
var result = User32.VkKeyScan(character);
var result = User32.VkKeyScan(ch);
if (result == -1)
{
SendUnicodeCharacter(character);
// This is a unicode character that must be handled differently.
AddUnicodeInputs(inputs, ch);
return;
}
var virtualKeyCode = (VirtualKey)(result & 0xff);
var virtualKey = (VirtualKey)(result & 0xff);
var shiftState = (ShiftState)(((ushort)result >> 8) & 0xff);
Send(virtualKeyCode, shiftState);
AddInputs(inputs, virtualKey, shiftState);
}
private static bool IsExtendedKey(VirtualKey virtualKey)
private static void AddUnicodeInputs(List<User32.INPUT> inputs, char ch)
{
return (virtualKey >= VirtualKey.PageUp && virtualKey <= VirtualKey.Down)
|| virtualKey == VirtualKey.Insert
|| virtualKey == VirtualKey.Delete;
}
var keyDownInput = new User32.INPUT
{
Type = User32.INPUT_KEYBOARD,
ki = new User32.KEYBDINPUT
{
wVk = 0,
wScan = ch,
dwFlags = User32.KEYEVENTF_UNICODE,
time = 0,
dwExtraInfo = IntPtr.Zero
}
};
private void SendKeyPressAndRelease(VirtualKey virtualKey)
{
SendKey(virtualKey, User32.KEYEVENTF_NONE);
SendKey(virtualKey, User32.KEYEVENTF_KEYUP);
var keyUpInput = new User32.INPUT
{
Type = User32.INPUT_KEYBOARD,
ki = new User32.KEYBDINPUT
{
wVk = 0,
wScan = ch,
dwFlags = User32.KEYEVENTF_UNICODE | User32.KEYEVENTF_KEYUP,
time = 0,
dwExtraInfo = IntPtr.Zero
}
};
inputs.Add(keyDownInput);
inputs.Add(keyUpInput);
}
private void SendKey(VirtualKey virtualKey, uint dwFlags)
private static void AddInputs(List<User32.INPUT> inputs, VirtualKey virtualKey, uint dwFlags)
{
var input = new User32.INPUT
{
......@@ -125,38 +126,83 @@ private void SendKey(VirtualKey virtualKey, uint dwFlags)
input.ki.dwFlags |= User32.KEYEVENTF_EXTENDEDKEY;
}
IntegrationHelper.SendInput(new[] { input });
inputs.Add(input);
}
private void SendUnicodeCharacter(char character)
private static bool IsExtendedKey(VirtualKey virtualKey)
{
var keyDownInput = new User32.INPUT
return (virtualKey >= VirtualKey.PageUp && virtualKey <= VirtualKey.Down)
|| virtualKey == VirtualKey.Insert
|| virtualKey == VirtualKey.Delete;
}
private static void AddInputs(List<User32.INPUT> inputs, KeyPress keyPress)
{
AddInputs(inputs, keyPress.VirtualKey, keyPress.ShiftState);
}
private static void AddInputs(List<User32.INPUT> inputs, VirtualKey virtualKey, ShiftState shiftState = 0)
{
if ((shiftState & ShiftState.Shift) != 0)
{
Type = User32.INPUT_KEYBOARD,
ki = new User32.KEYBDINPUT
{
wVk = 0,
wScan = character,
dwFlags = User32.KEYEVENTF_UNICODE,
time = 0,
dwExtraInfo = IntPtr.Zero
}
};
AddInputs(inputs, VirtualKey.Shift, User32.KEYEVENTF_NONE);
}
var keyUpInput = new User32.INPUT
if ((shiftState & ShiftState.Ctrl) != 0)
{
Type = User32.INPUT_KEYBOARD,
ki = new User32.KEYBDINPUT
AddInputs(inputs, VirtualKey.Control, User32.KEYEVENTF_NONE);
}
if ((shiftState & ShiftState.Alt) != 0)
{
AddInputs(inputs, VirtualKey.Alt, User32.KEYEVENTF_NONE);
}
AddInputs(inputs, virtualKey, User32.KEYEVENTF_NONE);
AddInputs(inputs, virtualKey, User32.KEYEVENTF_KEYUP);
if ((shiftState & ShiftState.Shift) != 0)
{
AddInputs(inputs, VirtualKey.Shift, User32.KEYEVENTF_KEYUP);
}
if ((shiftState & ShiftState.Ctrl) != 0)
{
AddInputs(inputs, VirtualKey.Control, User32.KEYEVENTF_KEYUP);
}
if ((shiftState & ShiftState.Alt) != 0)
{
AddInputs(inputs, VirtualKey.Alt, User32.KEYEVENTF_KEYUP);
}
}
private void SendInputs(User32.INPUT[] inputs)
{
var foregroundWindow = IntPtr.Zero;
var inputBlocked = false;
try
{
inputBlocked = IntegrationHelper.BlockInput();
foregroundWindow = IntegrationHelper.GetForegroundWindow();
_visualStudioInstance.ActivateMainWindow();
IntegrationHelper.SendInput(inputs);
}
finally
{
if (foregroundWindow != IntPtr.Zero)
{
wVk = 0,
wScan = character,
dwFlags = User32.KEYEVENTF_UNICODE | User32.KEYEVENTF_KEYUP,
time = 0,
dwExtraInfo = IntPtr.Zero
IntegrationHelper.SetForegroundWindow(foregroundWindow);
}
};
IntegrationHelper.SendInput(new[] { keyDownInput, keyUpInput });
if (inputBlocked)
{
IntegrationHelper.UnblockInput();
}
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Roslyn.VisualStudio.Test.Utilities.Common;
using Roslyn.VisualStudio.Test.Utilities.InProcess;
using Roslyn.VisualStudio.Test.Utilities.Input;
namespace Roslyn.VisualStudio.Test.Utilities.OutOfProcess
{
......@@ -72,42 +70,7 @@ public Signature GetCurrentSignature()
public void SendKeys(params object[] keys)
{
Activate();
foreach (var key in keys)
{
if (key is string)
{
var text = ((string)key)
.Replace("\r\n", "\r")
.Replace("\n", "\r");
foreach (var ch in text)
{
VisualStudioInstance.SendKeys.Send(ch);
}
}
else if (key is char)
{
VisualStudioInstance.SendKeys.Send((char)key);
}
else if (key is VirtualKey)
{
VisualStudioInstance.SendKeys.Send((VirtualKey)key);
}
else if (key is KeyPress)
{
VisualStudioInstance.SendKeys.Send((KeyPress)key);
}
else if (key == null)
{
throw new ArgumentNullException(nameof(keys));
}
else
{
throw new ArgumentException($"Unexpected type encountered: {key.GetType()}", nameof(keys));
}
}
VisualStudioInstance.SendKeys.Send(keys);
VisualStudioInstance.WaitForApplicationIdle();
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册