【问题标题】:SendInput won't send basic Unicode to some windowsSendInput 不会将基本 Unicode 发送到某些窗口
【发布时间】:2018-10-29 10:30:29
【问题描述】:

我在 C# 中对这个项目有一个问题:使用 WinAPI SendInput 函数时

    /// <summary>
    /// Sends Unicode (UTF16) string to foreground window.
    /// </summary>
    /// <param name="inputString">String to be sent to foreground window.</param>
    internal static void Send(string inputString)
    {
        if (inputString == string.Empty)
        { return; }

        char[] chars = inputString.ToCharArray();
        INPUT[] pInputs = new INPUT[chars.Length * 2];

        for (int i = 0; i < chars.Length; i++)
        {
            UInt16 unicode = chars[i];
            pInputs[i * 2] = new INPUT();
            pInputs[i * 2].type = INPUT_KEYBOARD;
            pInputs[i * 2].ki.wVk = 0;
            pInputs[i * 2].ki.wScan = unicode;
            pInputs[i * 2].ki.dwFlags = KEYEVENTF_UNICODE;
            pInputs[i * 2].ki.time = 0;
            pInputs[i * 2].ki.dwExtraInfo = SetMessageExtraInfo(IntPtr.Zero);

            pInputs[i * 2 + 1] = new INPUT();
            pInputs[i * 2 + 1].type = INPUT_KEYBOARD;
            pInputs[i * 2 + 1].ki.wVk = 0;
            pInputs[i * 2 + 1].ki.wScan = unicode;
            pInputs[i * 2 + 1].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
            pInputs[i * 2 + 1].ki.time = 0;
            pInputs[i * 2 + 1].ki.dwExtraInfo = SetMessageExtraInfo(IntPtr.Zero);
        }
        uint nSent = SendInput((uint)chars.Length * 2, pInputs, Marshal.SizeOf(typeof(INPUT)));
        if (nSent == 0)
        {
            Debug.WriteLine("SendInput error " + GetLastError().ToString()); // error 87 : "The parameter is incorrect."
        }
    }

在记事本或 VS 等桌面应用程序中,代码可以正常工作,但在其他应用程序中,它不适用于简单的英文字母和标点符号。 像“íáó”这样带有特殊字符的字符串可以显式/普遍使用,但像“My car”这样的字符串却不行。显然,“我的车”中 chars 的 utf-16 值很低,小于 100; á 和 í 的值分别为 225 和 237。看似表面上的区别。 有人知道使用 SendInput 将常规英文字母作为 Unicode 发送到任意窗口的方法吗?

【问题讨论】:

  • 您在使用哪些应用时遇到问题?
  • Chrome 搜索框、Chrome 多功能框和在 Windows 上安装可执行文件的设置应用程序中的文本框。
  • 为什么不使用 UI 自动化

标签: c# winapi unicode


【解决方案1】:

这不是 MSDN 上的文档,但是在使用 KEYEVENTF_UNICODE 时,如果给定的 Unicode 代码点需要使用 UTF-16 代理,则需要发送 both 不带 KEYEVENTF_KEYUP 的代理,然后用KEYEVENTF_KEYUP发送both代理。您显示的代码根本不考虑 UTF-16 代理,它独立地为每个代理发送向下/向上输入。两个代理需要同时“向下”,然后同时“向上”。

尝试更多类似的方法(基于我在 C++ 中针对同一问题发布的previous answer):

/// <summary>
/// Sends Unicode (UTF16) string to foreground window.
/// </summary>
/// <param name="inputString">String to be sent to foreground window.</param>
internal static void Send(string inputString)
{
    if (string.IsNullOrEmpty(inputString))
    { return; }

    char[] chars = inputString.ToCharArray();
    int len = chars.Length;
    INPUT[] pInputs = new INPUT[len * 2];

    UInt32 ExtraInfo = GetMessageExtraInfo();

    int i = 0, idx = 0;
    while (i < len)
    {
        UInt16 ch = chars[i++];

        if ((ch < 0xD800) || (ch > 0xDFFF))
        {
            pInputs[idx] = new INPUT();
            pInputs[idx].type = INPUT_KEYBOARD;
            pInputs[idx].ki.wVk = 0;
            pInputs[idx].ki.wScan = ch;
            pInputs[idx].ki.dwFlags = KEYEVENTF_UNICODE;
            pInputs[idx].ki.time = 0;
            pInputs[idx].ki.dwExtraInfo = ExtraInfo;
            ++idx;

            pInputs[idx] = new INPUT();
            pInputs[idx].type = INPUT_KEYBOARD;
            pInputs[idx].ki.wVk = 0;
            pInputs[idx].ki.wScan = ch;
            pInputs[idx].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
            pInputs[idx].ki.time = 0;
            pInputs[idx].ki.dwExtraInfo = ExtraInfo;
            ++idx;
        }
        else
        {
            UInt16 ch2 = chars[i++];

            pInputs[idx] = new INPUT();
            pInputs[idx].type = INPUT_KEYBOARD;
            pInputs[idx].ki.wVk = 0;
            pInputs[idx].ki.wScan = ch;
            pInputs[idx].ki.dwFlags = KEYEVENTF_UNICODE;
            pInputs[idx].ki.time = 0;
            pInputs[idx].ki.dwExtraInfo = ExtraInfo;
            ++idx;

            pInputs[idx] = new INPUT();
            pInputs[idx].type = INPUT_KEYBOARD;
            pInputs[idx].ki.wVk = 0;
            pInputs[idx].ki.wScan = ch2;
            pInputs[idx].ki.dwFlags = KEYEVENTF_UNICODE;
            pInputs[idx].ki.time = 0;
            pInputs[idx].ki.dwExtraInfo = ExtraInfo;
            ++idx;

            pInputs[idx] = new INPUT();
            pInputs[idx].type = INPUT_KEYBOARD;
            pInputs[idx].ki.wVk = 0;
            pInputs[idx].ki.wScan = ch;
            pInputs[idx].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
            pInputs[idx].ki.time = 0;
            pInputs[idx].ki.dwExtraInfo = ExtraInfo;
            ++idx;

            pInputs[idx] = new INPUT();
            pInputs[idx].type = INPUT_KEYBOARD;
            pInputs[idx].ki.wVk = 0;
            pInputs[idx].ki.wScan = ch2;
            pInputs[idx].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
            pInputs[idx].ki.time = 0;
            pInputs[idx].ki.dwExtraInfo = ExtraInfo;
            ++idx;
        }
    }

    uint nSent = SendInput((uint)pInputs.Length, pInputs, Marshal.SizeOf(typeof(INPUT)));
    if (nSent == 0)
    {
        Debug.WriteLine("SendInput error " + GetLastError().ToString());
    }
}

【讨论】:

  • 抱歉,Remy,但这段代码对它没有任何作用。我的测试字符串 "M:\Test" 和 "áí" 甚至没有命中代码的 'else' 部分,因为它们都低于 0xD800,因此结果与通过我自己的代码相同。我会保留你的这段代码以供参考,但我仍然不知所措。
  • @JediCommymullah 我不是 C# 开发人员,但我展示的内容在 C++ 中对我来说一直很好用。可能是您遇到问题的应用程序根本无法正确处理键盘输入。不是SendInput 的错。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-11
  • 1970-01-01
相关资源
最近更新 更多