【问题标题】:How to send keyboard input to dos application running in window mode in Windows98如何将键盘输入发送到在 Windows 98 中以窗口模式运行的 dos 应用程序
【发布时间】:2020-05-14 17:02:29
【问题描述】:

我的问题是关于非常古老的技术。我的任务是自动化在 Windows 98 中以 Windows 模式运行的旧 DOS 软件(光谱分析)。我制作了两种不同的解决方案,但是它们都不能与 DOS 应用程序一起使用强>:

  1. 第一个解决方案

    • 激活 DOS 应用程序
    • 通过 SendInput 函数发送输入,如下所示:
    void MossbauerLab::Sm2201::SaveManager::AutoSaveManager::sendKeysViaInput(const std::vector<DWORD>& keys, int keyPause)
    {
        std::vector<DWORD>::const_iterator it;
        INPUT keyBoardInput;
        keyBoardInput.type = INPUT_KEYBOARD;
        keyBoardInput.ki.wScan = 0;
        keyBoardInput.ki.time = 0;
        keyBoardInput.ki.dwExtraInfo = 0;

        for(it = keys.begin(); it != keys.end(); it++)
        {
            keyBoardInput.ki.wVk = (*it);
            keyBoardInput.ki.dwFlags = 0;   // key down
            SendInput(1, &keyBoardInput, sizeof(INPUT));
            Sleep(keyPause);
            keyBoardInput.ki.dwFlags = 2;   // key up
            SendInput(1, &keyBoardInput, sizeof(INPUT));
            Sleep(keyPause);
        }
    }
  1. 通过 i8042 键盘控制器生成按键:使用 D2 命令写入键盘缓冲区命令,如下所示 (KEYBOARD_CMD_REG - 0x64, KEYBOARD_DATA_REG - 0x60):
    void MossbauerLab::Sm2201::SaveManager::AutoSaveManager::sendKeysViaKeyboardController(const std::vector<BYTE>& scanCodes, int keyPause)
    {
        std::vector<BYTE>::const_iterator it;
        for(it = scanCodes.begin(); it != scanCodes.end(); it++)
        {
            // wait untill buffer is empty
            int status = 0;
            int result = 0;
            do
            {
                status = _inp(0x64);
                // std::cout <<"Keyboard status: "<< status << std::endl;
                Sleep(10);
            }
            while (status & 1);

            // send scan code for key down
            _outp(KEYBOARD_CMD_REG, 0xD2);
            _outp(KEYBOARD_DATA_REG, (*it));
            result = _inp(KEYBOARD_DATA_REG);
            std::cout <<"Keyboard command result for KEY DOWN: "<< result << std::endl;
            // send scan code for key up
            BYTE keyUpCode = (*it) | 128;
            Sleep(keyPause);
            _outp(KEYBOARD_CMD_REG, 0xD2);
            _outp(KEYBOARD_DATA_REG, keyUpCode);
            result = _inp(KEYBOARD_DATA_REG);
            std::cout <<"Keyboard command result for KEY UP: "<< result << std::endl;
        }
    }

我用标准记事本窗口 (notepad.exe) 测试了这两种解决方案,它们都工作正常,但我无法让它与 DOS 应用程序一起使用.

我生成键盘输入(和整个项目)的代码:https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/saveManager/autoSaveManager.cpp

你能帮我解决这个问题吗?

【问题讨论】:

  • 您尝试执行的操作不起作用,因为 MS-DOS 应用程序运行在与运行 Windows 的主 VM 不同的 VM 中。这两个 VM 有两个不同的虚拟化键盘控制器。缺少编写 VxD(32 位驱动程序)我不确定有没有办法做你想做的事。
  • 也许有办法以某种方式写入 MS-DOS Vx 键盘驱动程序?
  • Ross,感谢您对我以前从未听说过的有关 VxD 的评论,我搜索了有关虚拟键盘驱动程序并找到了有趣的链接:www-user.tu-chemnitz.de/~heha/vxd/vxd.htm#C09S02 可能它可以帮助我找到解决方案
  • 这正是您所需要的。您必须自己编写才能编写自己的 VxD,例如您链接的“VSAMPLED”示例,但它不是键盘驱动程序。相反,它将只使用 Windows 虚拟键盘驱动程序 (VKD) 公开的 API,例如示例代码如何使用 VKD_Force_Keys。

标签: c++ dos keyboard-input windows-98


【解决方案1】:

我在 16 年前遇到过同样的问题,我的(不太优雅但可能更容易实现)的解决方案是将要插入的文本放入剪贴板,获取前景窗口 hWnd,然后使用 SendMessage()以 0xE001 作为数据发送它 WM_SYSCOMMAND。 IIRC 这触发了窗口上下文菜单中的粘贴命令(我使用 Spy++ 找到的)。

我希望有人觉得这很有用。 :)

【讨论】:

    【解决方案2】:

    首先我要感谢所有对这篇文章感兴趣的人,你们都给了我一些有用的信息,我终于做出了我想要的。

    关于它是如何实现的:我已经创建了 VXD 驱动程序(它是我的专有驱动程序,我不能在这里发布它的代码,因为我打算将它用于商业项目)。但此评论的主要目标 - 是的,可以模拟 KEYBOARD INPUT 用于在 Windows 98 中以窗口模式运行的 DOS 应用程序。我可以发布的部分解决方案在 github 上:https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/saveManager/autoSaveManager.cpp

    这里我使用的是 vXd 访问器类:(https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/utils/windows/vxdAccessor.cpp)

    主要思想 - 使用 W32_DEVICEIOCONTROL 驱动程序消息处理程序和 DeviceIoControl 函数与驱动程序交互,并使用 CTL(在我的驱动程序中定义)传递具有 1 个字节对齐的结构代码:我没有使用 CTL_CODE 宏。这个 Github 项目几乎准备好了~95%(目前我只需要手动选择窗口来发送,通过鼠标点击激活它并检查是否有可用的内存)。

    【讨论】:

      【解决方案3】:

      Windows 98 中的 MS-DOS 应用程序在虚拟实模式下运行,而不是在保护模式下,这就是为什么使用保护模式驱动程序或系统调用无法与它们通信的原因。您需要使用 BIOS / DOS 中断来连接键盘,Windows 驱动程序将无法为您做到这一点。

      因此,这样做的唯一方法是使用另一个 DOS 应用程序模拟按键,但我不确定 BIOS 键盘缓冲区是否已虚拟化,但如果没有,那么您应该能够通过启动来将其关闭来自您的应用程序的虚拟实模式进程(必须是一个单独的 exe,但您应该能够在无窗口的情况下运行它)并将按键作为命令行参数传递给 BIOS。

      这是一个非常有趣的问题,希望对您有所帮助并设法解决。

      【讨论】:

        猜你喜欢
        • 2010-10-09
        • 2015-01-15
        • 2012-01-22
        • 2021-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-12
        • 2012-03-03
        相关资源
        最近更新 更多