-1

I am trying to get mouse and keyboard input simultaneously using Turbo-C++.

I want to use two functions. The first function would be the main function which may take keyboard inputs or call the delay function from dos.h to temporarily stop the normal functioning of main().

The second function processes mouse input:

void mouse()
 {
    union REGS in,out;
    in.x.ax=1; // Show mouse pointer
    int86(0x33,&in,&out); //interrupt call
    while(1)
     {
       //print the location whenever it changes (not required)
     }
 }
Scott McPeak
  • 8,803
  • 2
  • 40
  • 79
Mohit Shetty
  • 1,551
  • 8
  • 26

2 Answers2

5

Context

If I understand the question correctly, you are writing a program that will run under 16-bit MS-DOS, inside DosBox. That program is expected to respond to both mouse and keyboard input. It might also want to perform some computation while waiting for input.

Polling

The simplest and most straightforward solution is to use polling, meaning you sit in a loop, asking both the keyboard and mouse if they have new input to respond to. In pseudocode:

  while (true) {
    while (keyboard_has_activity()) {
      process_keyboard_input();
    }
    while (mouse_has_activity()) {
      process_mouse_input();
    }
    do_other_computation_for_a_short_time();
  }

How to write keyboard_has_activity? You mentioned kbhit from conio.h in a comment; that should work. There are also lower-level interrupts you could use (although I don't know of any reason not to use kbhit).

Note: process_keyboard_input should only read as many characters as are currently available. If your program involves waiting for the user to press Enter, then you will have to store the typed characters in (say) an array until you actually see the Enter key, and then process all of the input at once.

How to write mouse_has_activity? To my knowledge, you have to use INT 0x33 routines to query the current mouse status and compare that to what it was on the last call.

How to write do_other_computation_for_a_short_time? You'll have to design some sort of time bound into the algorithm. For example, if you are writing a chess engine, it would check the clock after each (say) board evaluation and stop when necessary so you can poll for input. When the algorithm stops, it must remember in a data structure where it was so it can later resume from that point. One common strategy is to maintain a worklist: a list of all the parts of the computation that still need to be done. This is a form of cooperative multitasking.

In any case, you want the time bound to be no more than about 10ms, since otherwise you might miss mouse clicks (user could press and release the button before you notice it).

This solution is simple but not necessarily the most efficient, and potentially unreliable due to the aforementioned problem with missing mouse clicks if the time bound is too long.

Interrupts

The other way to do it is to hook into the low-level keyboard and mouse interrupts. This way, you install code that only runs when an input device is touched, which is more efficient. However, it is also much harder to get right, for a variety of reasons, including that you have little control over what one piece of code is doing when it gets interrupted.

Non-answer: threading

In this environment, it's impractical to try to organize your program as two threads (mouse and keyboard) with two functions running simultaneously. DOS has no threading facilities, and I'm not aware of any way to add them without basically rewriting the OS. Instead, you'll need to do everything from one control thread.

Scott McPeak
  • 8,803
  • 2
  • 40
  • 79
  • 1
    What if there is a mouse activity before the keyboard activity? – Mohit Shetty Sep 07 '19 at 13:33
  • 1
    I want both to run simultaneously..if possible – Mohit Shetty Sep 07 '19 at 13:34
  • 2
    There is no problem if mouse activity happens first because of the outer loop. The computation should only be allowed to run for, say, 10ms, so the program will soon again check both sources of input. Why do you want to run them simultaneously? What problem is that intended to solve? – Scott McPeak Sep 07 '19 at 13:38
  • 1
    Thanks for the answer and support. – Mohit Shetty Sep 07 '19 at 13:44
  • 1
    What if I want the operation to resume from where it had left? – Mohit Shetty Sep 07 '19 at 13:57
  • 1
    do_other_computation_for_a_short_time(); == {i++;delay(700);i++;delay(200);i=100;} – Mohit Shetty Sep 07 '19 at 13:58
  • I edited my post to mention using a worklist in the computation step. If you need more guidance on designing an algorithm that can be stopped and resumed, you may want to ask a new question and provide details about exactly what your algorithm is doing. – Scott McPeak Sep 07 '19 at 14:08
  • Can we do something with interrupts? Maybe get the position/coordinates when the mouse gets clicked and perform a specific set of instructions. – Mohit Shetty Sep 07 '19 at 14:23
  • 1
    Yes, and my answer links to a resource you could use as a starting point. I think you will find that approach far more difficult but it certainly can be made to work. – Scott McPeak Sep 07 '19 at 14:25
1

You say in comments that you are coding for Windows. Microsoft has a ReadConsoleInput() function that reads both keyboard and mouse inputs in a console window. See Reading Input Buffer Events on MSDN.

For example:

#include <windows.h>

int main()
{
    HANDLE hStdIn;
    INPUT_RECORD input[128];
    DWORD dwOldMode, dwNumRead;

    hStdIn = GetStdHandle(STD_INPUT_HANDLE);

    GetConsoleMode(hStdIn, &dwOldMode);
    SetConsoleMode(hStdIn, ENABLE_MOUSE_INPUT);

    while (ReadConsoleInput(hStdIn, input, 128, &dwNumRead))
    {
        for (DWORD i = 0; i < dwNumRead; ++i)
        {
            switch (input[i].EventType)
            {
                case KEY_EVENT:
                    // process input[i].Event.KeyEvent data as needed...
                    break;

                case MOUSE_EVENT:
                    // process input[i].Event.MouseEvent data as needed...
                    break;
            }
        } 
    }

    SetConsoleMode(hStdIn, dwOldMode);
    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    assert(IDE==TURBOC++); // true – Mohit Shetty Sep 07 '19 at 17:08
  • 1
    To implement this solution I'll have to ask another question of about how to include in Turbo C++ – Mohit Shetty Sep 07 '19 at 17:42
  • 2
    @SonofStackoverflow IIRC TurboC++ is only 16bit and MS-DOS ... so you're would be limited to Win3x (and legal problems). I doubt you could run any other windows in DOSBOX even 3.11 is a stretch. to achieve "multi tasking" you can exploit [PIT interrupt service routine](https://stackoverflow.com/a/55807763/2521214) but [interleaving](https://stackoverflow.com/a/48521522/2521214) as in accepted answer was more common and easier to implement... – Spektre Sep 09 '19 at 07:40