如何在 Windows98 中以 window 模式将键盘输入发送到 dos 应用程序 运行
How to send keyboard input to dos application running in window mode in Windows98
我的问题是关于非常古老的技术。我的任务是在 Windows 98 中以 Windows 模式自动化旧 DOS 软件(光谱)。我做了两个不同的解决方案,但它们都不起作用 使用 DOS 应用程序:
第一个解决方案
- 激活 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);
}
}
- 通过 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;
}
}
我用标准记事本测试了这两种解决方案 window (notepad.exe),它们都工作正常,但我无法让它与 DOS 应用程序一起工作。
我生成键盘输入的代码(和整个项目):https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/saveManager/autoSaveManager.cpp
你能帮我解决这个问题吗?
MS-DOS 应用程序在 Windows 98 运行 中处于虚拟实模式,而不是处于保护模式,这就是为什么无法使用保护模式驱动程序或系统调用与它们通信的原因。您需要使用 BIOS / DOS 中断来连接键盘,Windows 驱动程序将无法为您完成。
因此,唯一的方法是使用另一个 DOS 应用程序模拟按键,但我不确定 BIOS 键盘缓冲区是否已虚拟化,但如果没有,那么您应该可以将其关闭通过从您的应用程序启动一个虚拟实模式进程(必须是一个单独的 exe,但您应该能够摆脱 运行 无窗口)并将按键作为命令行参数传递给 BIOS。
这是一个非常有趣的问题,希望对您有所帮助,并设法解决它。
首先我要感谢所有对此感兴趣的人post,你们所有人都给了我一些有用的信息,我终于做出了我想要的。
关于它是如何实现的:我已经创建了 VXD 驱动程序(这是我的专有驱动程序,我不能 post 它在这里编码,因为我打算将它用于商业项目)。但此评论的主要目标 - YES,可以在 Windows 98 中以 window 模式模拟 DOS 应用程序 运行 的键盘输入 。我可以 post 的部分解决方案在 github 上:https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/saveManager/autoSaveManager.cpp
这里我使用的是 vXd 访问器 class: (https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/utils/windows/vxdAccessor.cpp)
主要思想 - 使用 W32_DEVICEIOCONTROL 驱动程序消息处理程序和 DeviceIoControl 函数与驱动程序交互,并使用 CTL 传递具有 1 字节对齐的结构(在我的驱动程序中定义)代码:我没有使用 CTL_CODE宏。这个 Github 项目几乎已准备就绪 ~95%(目前我只需要手动 select window 通过单击鼠标激活它并检查是否有可用内存来发送)。
我在 16 年前遇到过同样的问题,我的(不太优雅但可能更容易实现)解决方案是将我想插入的文本放入剪贴板,获取前景 window hWnd,然后然后使用 SendMessage() 以 0xE001 作为数据发送它 WM_SYSCOMMAND。 IIRC 这从 window 的上下文菜单(我使用 Spy++ 找到)触发了粘贴命令。
我希望有人觉得这有用。 :)
我的问题是关于非常古老的技术。我的任务是在 Windows 98 中以 Windows 模式自动化旧 DOS 软件(光谱)。我做了两个不同的解决方案,但它们都不起作用 使用 DOS 应用程序:
第一个解决方案
- 激活 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);
}
}
- 通过 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;
}
}
我用标准记事本测试了这两种解决方案 window (notepad.exe),它们都工作正常,但我无法让它与 DOS 应用程序一起工作。
我生成键盘输入的代码(和整个项目):https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/saveManager/autoSaveManager.cpp
你能帮我解决这个问题吗?
MS-DOS 应用程序在 Windows 98 运行 中处于虚拟实模式,而不是处于保护模式,这就是为什么无法使用保护模式驱动程序或系统调用与它们通信的原因。您需要使用 BIOS / DOS 中断来连接键盘,Windows 驱动程序将无法为您完成。
因此,唯一的方法是使用另一个 DOS 应用程序模拟按键,但我不确定 BIOS 键盘缓冲区是否已虚拟化,但如果没有,那么您应该可以将其关闭通过从您的应用程序启动一个虚拟实模式进程(必须是一个单独的 exe,但您应该能够摆脱 运行 无窗口)并将按键作为命令行参数传递给 BIOS。
这是一个非常有趣的问题,希望对您有所帮助,并设法解决它。
首先我要感谢所有对此感兴趣的人post,你们所有人都给了我一些有用的信息,我终于做出了我想要的。
关于它是如何实现的:我已经创建了 VXD 驱动程序(这是我的专有驱动程序,我不能 post 它在这里编码,因为我打算将它用于商业项目)。但此评论的主要目标 - YES,可以在 Windows 98 中以 window 模式模拟 DOS 应用程序 运行 的键盘输入 。我可以 post 的部分解决方案在 github 上:https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/saveManager/autoSaveManager.cpp
这里我使用的是 vXd 访问器 class: (https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/utils/windows/vxdAccessor.cpp)
主要思想 - 使用 W32_DEVICEIOCONTROL 驱动程序消息处理程序和 DeviceIoControl 函数与驱动程序交互,并使用 CTL 传递具有 1 字节对齐的结构(在我的驱动程序中定义)代码:我没有使用 CTL_CODE宏。这个 Github 项目几乎已准备就绪 ~95%(目前我只需要手动 select window 通过单击鼠标激活它并检查是否有可用内存来发送)。
我在 16 年前遇到过同样的问题,我的(不太优雅但可能更容易实现)解决方案是将我想插入的文本放入剪贴板,获取前景 window hWnd,然后然后使用 SendMessage() 以 0xE001 作为数据发送它 WM_SYSCOMMAND。 IIRC 这从 window 的上下文菜单(我使用 Spy++ 找到)触发了粘贴命令。
我希望有人觉得这有用。 :)