[英]Send Ctrl+C to previous active window
我正在尝试编写一个位于系统托盘中的小型应用程序。 我已经注册了热键。 触发热键并激活应用程序后,我想将Ctrl + C发送到最后一个活动窗口,以便可以将突出显示的文本放入剪贴板。
这是我到目前为止所得到的:
//http://stackoverflow.com/questions/9468476/switch-to-last-active-application-like-alt-tab
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
static extern IntPtr GetLastActivePopup(IntPtr hWnd);
[DllImport("user32.dll", ExactSpelling = true)]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
const uint GA_PARENT = 1;
const uint GA_ROOT = 2;
const uint GA_ROOTOWNER = 3;
public static IntPtr GetPreviousWindow()
{
IntPtr activeAppWindow = GetForegroundWindow();
if (activeAppWindow == IntPtr.Zero)
return IntPtr.Zero;
IntPtr prevAppWindow = GetLastActivePopup(activeAppWindow);
return IsWindowVisible(prevAppWindow) ? prevAppWindow : IntPtr.Zero;
}
public static void FocusToPreviousWindow()
{
IntPtr prevWindow = GetPreviousWindow();
if (prevWindow != IntPtr.Zero)
SetForegroundWindow(prevWindow);
}
...
private static void OnHotKeyFired()
{
FocusToPreviousWindow();
SendKeys.SendWait("^(c)");
_viewModel.Input = Clipboard.GetText();
new UIWindow(_viewModel).ShowDialog();
}
但是我无法使SendKeys工作。 在大多数应用程序中,没有发生任何事情,这意味着不触发ctrl-c。 在Word女士中,执行SendWait时,在我的文档中插入了一个版权符号(c)。
更新:
我尝试了WM_COPY和SendMessage:
private static void OnHotKeyFired()
{
IntPtr handle = GetPreviousWindow();
SendMessage(handle, WM_COPY, IntPtr.Zero, IntPtr.Zero);
_viewModel.Input = Clipboard.GetText();
...
它可以在Word中工作,但不能在Excel,记事本,Visual Studio中工作
SendKeys.SendWait("^(c)");
那不发送Ctrl + C,括号也被发送。 您可能用的是花括号而不是括号"^{c}"
。 否则,由于Word插入版权符号的原因,它将(c)自动更正为©。 固定:
SendKeys.SendWait("^c");
如果仍然有问题,则可能会遇到问题,然后阅读有关SendKeys的MSDN文章。 建议使用.config文件,以便使用其他方式注入击键。 在Windows的更高版本上,SendInput()比日记钩更好。
我认为您的问题与时间安排有关。
要设置窗口焦点并进行实际复制到剪贴板,您需要等待窗口获得焦点并等待剪贴板更新。
有几种方法可以处理这些难看的win32事情。
对于剪贴板的内容。 我将原始内容与当前内容进行比较。 我将原始内容设置为string.empty,如果其为图像或其他文本数据。 然后,我等待一个检查剪贴板是否有变化的函数。
对于SetForegroundWindow,我目前在异步函数中添加了延迟。 您也可能会找到一个win32 api调用,以等待此窗口正确放置在前台。
我在异步函数中都执行了这两个操作,然后等待它以防止阻塞。
SendKeys应该与SendWait(“ ^ c”)一起使用。 SendWait(“ ^(c)”)并不总是如其他答案中所述。 但是,ctrl + c复制到剪贴板不会立即发生。
Point p;
if (GetCursorPos(out p))
{
IntPtr ptr = WindowFromPoint(p);
if (ptr != IntPtr.Zero)
{
SetForegroundWindow(ptr);
//wait for window to get focus quick and ugly
// probably a cleaner way to wait for windows to send a message
// that it has updated the foreground window
await Task.Delay(300);
//try to copy text in the current window
SendKeys.Send("^c");
await WaitForClipboardToUpdate(originalClipboardText);
}
}
}
private static async Task WaitForClipboardToUpdate(string originalClipboardText)
{
Stopwatch sw = Stopwatch.StartNew();
while (true)
{
if (await DoClipboardCheck(originalClipboardText)) return;
if (sw.ElapsedMilliseconds >= 1500) throw new Exception("TIMED OUT WAITING FOR CLIPBOARD TO UPDATE.");
}
}
private static async Task<bool> DoClipboardCheck(string originalClipboardText)
{
await Task.Delay(10);
if (!Clipboard.ContainsText()) return false;
var currentText = Clipboard.GetText();
Debug.WriteLine("current text: " + currentText + " original text: " + originalClipboardText);
return currentText != originalClipboardText;
}
[DllImport("user32.dll")]
private static extern bool GetCursorPos(out Point pt);
[DllImport("user32.dll", EntryPoint = "WindowFromPoint", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr WindowFromPoint(Point pt);
// Activate an application window.
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImportAttribute("user32.dll", EntryPoint = "GetForegroundWindow")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
另外-快速验证/检查计时是否是您的问题的一种真正快速又肮脏的方法是可以放置Thread.Sleep(1000); 在SetForegroundWindow和SendKeys.SendWait调用之后。
我知道您正在编程,但是万一您发现它是因为找不到更简单的解决方案...您可以尝试使用AutoHotKey ,它是一个小程序,位于您的任务栏中,可以执行各种热键/宏操作东西...您需要为宏编写一个小脚本,如下所示:
#c::Send !{ESC}, ^c
这个简单的脚本意味着:
您可以使用此软件进行各种精美的脚本编写,例如启动程序,regexp,线程,鼠标事件等。
我知道它不能回答您的问题,但这是一个简单的选择。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.