SendKeys.Send() 没有像我预期的那样发送或做出反应

SendKeys.Send() does not send or react as I expect

我在 C# 应用程序中使用 Sendkeys.Send 时遇到问题,我真的不明白为什么。使用它时,它不会将我期望的内容发送到活动应用程序。我将它与全局热键管理器一起使用,https://github.com/thomaslevesque/NHotkey

我已经创建了这个简单的 PoC,至少就我而言,它能够重现我的问题。只需启动 写字板 并按下热键 ALT + O:

using System.Windows.Forms;
using System.Diagnostics;
using NHotkey.WindowsForms;

namespace WindowsFormsApp5
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            // Convert string to keys
            string hotkey = "Alt + O";
            KeysConverter cvt;
            Keys key;
            cvt = new KeysConverter();
            key = (Keys)cvt.ConvertFrom(hotkey);

            // Setup the hotkey
            HotkeyManager.Current.AddOrReplace("MyID", key, HotkeyAction);

            // Copy some text to the clipboard that I want to paste to the active application
            Clipboard.SetText("My String");
        }

        private void HotkeyAction(object sender, NHotkey.HotkeyEventArgs e)
        {
            Debug.WriteLine("Pressed the hotkey");
            SendKeys.Send("^v");
//            SendKeys.Send("Test string");
            e.Handled = true;
        }

    }    
}

当我在 写字板 中执行此操作时,它不会粘贴剪贴板(^v 等于 CTRL + V),而是尝试“选择性粘贴”:

即使我做了最简单的事情,然后只是在 SendKeys.Send 中输入了一些文本,那么它似乎会弄乱 写字板 中的菜单? SendKeys.SendWait没有什么不同。

我已经尝试解决这个问题很长一段时间了,但我只是不明白为什么会这样。基本上,我需要将剪贴板粘贴到热键上,尽管它不需要使用这种确切的方法,所以如果有人知道另一种方法,那么我会很感激一些提示。


我的实施方案

基于已接受的答案,我确实稍微更改了我的实现,因为我无法仅使用计时器来实现它。我可能遗漏了一些东西(?),但这是有效的。

在基本情况下,一旦检测到热键,我就会将焦点转移到我的应用程序,以避免与活动应用程序中的修改键(ALT 等)发生冲突。然后我创建一个不可见的表单,当我检测到 KeyUp 事件时,我会检查修改键,如果 none 被按下,我会启用一个计时器并立即将焦点切换回原始应用程序。 50 毫秒后,剪贴板将粘贴到活动应用程序。

像这样:

// Somewhere else in code but nice to know
// IntPtr activeApp = GetForegroundWindow(); // get HWnd for active application
// SetForegroundWindow(this.Handle); // switch to my application

private System.Timers.Timer timerPasteOnHotkey = new System.Timers.Timer();

// Main
public PasteOnHotkey()
{
    InitializeComponent();

    // Define the timer
    timerPasteOnHotkey.Elapsed += new ElapsedEventHandler(OnTimedEvent);
    timerPasteOnHotkey.Interval = 50;
    timerPasteOnHotkey.Enabled = false;

    // Make the form invisble
    this.Size = new System.Drawing.Size(0, 0);
    this.Opacity = 0.0;
}

private void PasteOnHotkey_KeyUp(object sender, KeyEventArgs e)
{
    // Check if modifier keys are pressed
    bool isShift = e.Shift;
    bool isAlt = e.Alt;
    bool isControl = e.Control;

    // Proceed if no modifier keys are pressed down
    if (!isShift && !isAlt && !isControl)
    {
        Hide();

        // Start the timer and change focus to the active application
        timerPasteOnHotkey.Enabled = true;
        SetForegroundWindow(activeApp);
    }
}

private void OnTimedEvent(object source, ElapsedEventArgs e)
{
    timerPasteOnHotkey.Enabled = false;
    SendKeys.SendWait("^v"); // send "CTRL + v" (paste from clipboard)
}

当您使用 SendKeys.Send 响应按键时,您发送的按键可能会与您当时持有的物理按键结合使用。在这种情况下,您按住 Alt,因此写字板假定您按下的是 Alt-Ctrl-V 而不是 Ctrl-V。 Alt 也会打开菜单,因此发送其他键可能与那里的热键有关。

添加延迟将消除此问题,并且通常在发送按键时会与其他按键无关,因此不会有问题。