簡體   English   中英

發送Ctrl + C到上一個活動窗口

[英]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

這個簡單的腳本意味着:

  • #c::(定義Windows + c熱鍵)
  • 發送(發送一些擊鍵)
  • !{ESC}(Alt + Esc切換到最后一個程序)
  • ^ c(Control + c)

您可以使用此軟件進行各種精美的腳本編寫,例如啟動程序,regexp,線程,鼠標事件等。

我知道它不能回答您的問題,但這是一個簡單的選擇。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM