How to send keyboard input to dos application running in window mode in Windows98

962 views Asked by At

My question is about very antique techologies. I have a task to automate old DOS software (spectrometric) that is running in Windows mode in Windows 98. I made two different solution hovewer both of them doesn't work with DOS application:

  1. First Solution

    • Making DOS Application active
    • Sending input via SendInput function, like this:
    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. Generate key press via i8042 keyboard controllers: write to keyboard buffer command using D2 command, like this (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;
        }
    }

I tested both of these solutions with standard Notepad window (notepad.exe) and both of them works fine, but i can't get it work with DOS application.

My Code where i generate keyboard input (and whole project): https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/saveManager/autoSaveManager.cpp

Could you please help me to solve this solution.

3

There are 3 answers

0
Michael Ushakov On BEST ANSWER

First of all i want to thank all who interesting this post, all of you gave me some useful info and i finally made what i wanted.

About how it was implemented: i've created VXD driver (it is my proprietary driver and i can't post it code here because i am planning to use it for commercial projects). But the main goal of this comment - YES, it is possible to simulate KEYBOARD INPUT for DOS application running in Windows 98 in window mode. Part of my solution that i could post is on github: https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/saveManager/autoSaveManager.cpp

Here i am using vXd accessor class: (https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/utils/windows/vxdAccessor.cpp)

Main idea - interact with driver using W32_DEVICEIOCONTROL driver message handler and DeviceIoControl function and passing struct that have 1 byte align using CTL (define in my driver) CODES: i did not used CTL_CODE macro. This Github project is almost ready ~95% (at present time i just have to manual select window to send by activate it with mouse click and check proper memory free).

0
Sos Sosowski On

MS-DOS applications in Windows 98 run in Virtual Real Mode, not in Protected Mode, that's why it's impossible to communicate with them using protected mode drivers or system calls. You need to use BIOS / DOS interrupts to interface with keyboard, Windows drivers will not be able to do that for you.

Thus, the only way to do this, would be to simulate keypresses using another DOS application, but I am not sure whether the BIOS keyboard buffer is virtualised, but if not, then you should be able to pull it off by launching a Virtual Real Mode process from your application (will have to be a separate exe, but you should be able to get away with running it windowless) and pass over keypresses as commandline arguments to send them to BIOS.

This is a very interesting problem, hope this helps and you manage to solve it.

0
Liron On

I had the same problem 16 years ago, and my (less graceful but maybe easier to implement) solution was to put the text I wanted to insert into the clipboard, get the foreground window hWnd, and then use SendMessage() to send it WM_SYSCOMMAND with 0xE001 as the data. IIRC this triggered the paste command from the window's context menu (which I found by using Spy++).

I hope someone finds this useful. :)