【问题标题】:C Windows API keyboardC Windows API 键盘
【发布时间】:2022-01-22 23:18:56
【问题描述】:

我编写了一个程序,可以向计算机键入字符串。一切正常,但我遇到了两个问题: 1. 当我输入大写字母时,它不写大写字母。 2. 当我写两个相同的字母并排在一起时,其中一个没有写出来。我阅读了很多 Windows API 文档,但找不到任何东西。有人可以帮我解决问题吗?

#include <stdio.h>
#include <windows.h>

void keyboard(char *str)
{
    int x = strlen(str);

    INPUT inputStruct[x];
    ZeroMemory(inputStruct, sizeof(inputStruct));

    for (int i = 0; i < x; i++)
    {
        inputStruct[i].type = INPUT_KEYBOARD;
        inputStruct[i].ki.wVk = VkKeyScanA(str[i]);
    }

    SendInput(x, inputStruct, sizeof(INPUT));
}

int main()
{
    keyboard("hoe is het");
}

【问题讨论】:

  • 这段代码还能编译吗?你有一个非常量大小的数组!
  • 我在函数的第一行计算数组的大小?
  • 是的,但是在普通程序中,您不能使用 strlen 来设置堆栈分配数组的大小。你可能会很幸运,编译器会在编译时计算它。将strlen 更改为lstrlenA 看看会发生什么。
  • 它还能用吗?
  • C99 可能允许这样做或作为 GCC 扩展,但我认为这无关紧要,因为在使用虚拟键时,您无法仅根据字符串知道正确的大小。

标签: c windows api keyboard


【解决方案1】:
  • VkKeyScan 返回 16 位信息,前 8 位是有关需要按下哪些修饰键的信息,在您的情况下最有可能是“shift”。
  • 每个角色至少需要 2 个 INPUT 事件,每个事件的最后一个都设置了KEYEVENTF_KEYUP 以释放按键。
  • 您可以使用KEYEVENTF_UNICODE 标志模拟文本输入,这样您就不必处理键盘切换状态。

仅使用 Unicode 标志很容易。手动设置键盘状态容易出错,这是半心半意的尝试:

void SendTextInputASCII(LPCTSTR str)
{
    SIZE_T i;
    INPUT ki[2];
    ZeroMemory(&ki, sizeof(ki));
    for (i = 0; str[i]; ++i)
    {
        ki[0].type = INPUT_KEYBOARD;
        ki[0].ki.dwFlags = KEYEVENTF_UNICODE;
        ki[0].ki.wScan = str[i]; // TODO: To properly support non-ASCII you need to fill this with the correct Unicode codepoint.
        ki[1] = ki[0];
        ki[1].ki.dwFlags |= KEYEVENTF_KEYUP;
        SendInput(2, ki, sizeof(INPUT));
    }
}

void SendCharacterInput(TCHAR ch)
{
    UINT info = VkKeyScan(ch), wantshift, hadshift;
    INPUT ki[2];
    ZeroMemory(&ki, sizeof(ki));
    hadshift = GetAsyncKeyState(VK_SHIFT) < 0;
    wantshift = HIBYTE(info) & 1;
    if (wantshift != hadshift)
    {
        ki[0].type = INPUT_KEYBOARD;
        ki[0].ki.dwFlags = hadshift ? KEYEVENTF_KEYUP : 0;
        ki[0].ki.wVk = VK_LSHIFT;
        SendInput(1, ki, sizeof(INPUT));
    }
    // TODO: Should also handle Control and Alt keys!
    ki[0].type = INPUT_KEYBOARD;
    ki[0].ki.dwFlags = 0;
    ki[0].ki.wVk = LOBYTE(info);
    ki[1] = ki[0];
    ki[1].ki.dwFlags |= KEYEVENTF_KEYUP;
    SendInput(2, ki, sizeof(INPUT));
    if (wantshift != hadshift)
    {
        ki[0].type = INPUT_KEYBOARD;
        ki[0].ki.dwFlags = wantshift ? KEYEVENTF_KEYUP : 0;
        ki[0].ki.wVk = VK_LSHIFT;
        SendInput(1, ki, sizeof(INPUT));
    }
}

void SendCharactersInput(LPCTSTR str)
{
    SIZE_T i;
    for (i = 0; str[i]; ++i)
        SendCharacterInput(str[i]);
}

void Example()
{
    LPCTSTR text = TEXT("Hello World\n");
    WinExec("Notepad.exe", SW_SHOW);
    Sleep(2000);

    SendTextInputASCII(text);
    SendCharactersInput(text);
}

【讨论】:

  • 我仍然无法正常工作。我检查了:docs.microsoft.com/en-us/windows/win32/api/winuser/…,但我没有读到任何可以按 shift 按钮的地方
  • 我把我的代码编辑成了这个
  • 我必须在 if 语句中做一些事情来写一个大写字母
  • 如果您坚持使用 VkKeyScan,那么您必须检查其返回值的高位,并在需要时检查 SendInput 的 Shift/Control/Alt。只使用 KEYEVENTF_UNICODE 更容易
  • 如何检查位?
猜你喜欢
  • 1970-01-01
  • 2010-11-15
  • 2015-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多