From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=0.7 required=5.0 tests=BAYES_00,INVALID_DATE, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 Path: utzoo!mnetor!uunet!lll-winken!lll-lcc!lll-tis!ames!pasteur!ucbvax!EGLIN-VAX.ARPA!mooremj From: mooremj@EGLIN-VAX.ARPA ("MARTIN J. MOORE") Newsgroups: comp.lang.ada Subject: Handling asynchronous keyboard input Message-ID: <8804111501.AA10741@ajpo.sei.cmu.edu> Date: 11 Apr 88 14:47:00 GMT Sender: usenet@ucbvax.BERKELEY.EDU Reply-To: "MARTIN J. MOORE" Organization: The Internet List-Id: > Date: 8 Apr 88 16:51:29 GMT > From: decvax!mandrill!asheem@ucbvax.Berkeley.EDU (Asheem Chandna) > Subject: Handling Interactive Input from the Keyboard Buffer > > I have a large simulation program with many tasks in it. During every time > loop, I want to do a check to see if the user has typed anything from the > keyboard. If he (or she) has, then I want to pull up the user menu. If he > hasn't, then I just want the program to continue WITHOUT waiting for user > input. Since, I'd like to do this every time loop, I'm also looking for a low > overhead way to do it (for e.g., I'd rather not have a delay based time-out on > every loop). So, basically, I'm looking for an elegant way to have the user > interrupt a program run. About a year ago, I had the same problem: how to allow asynchronous keyboard input without blocking the whole program. My solution (using VAX Ada) was as follows: The heart of the solution is a package called ASYNC_KB_INPUT. When elaborated, this package starts a task to read the keyboard. This task consists of a loop which calls DEC's TASK_QIOW procedure. TASK_QIOW is a useful substitute for VAX/VMS's $QIOW system service in a task environment. A vanilla $QIOW is generally unacceptable because it puts the process into hibernation, blocking the entire program. TASK_QIOW, however, is implemented using AST's, so it blocks only the calling task. The keyboard task calls TASK_QIOW with a character count of 1, so the task waits until a character is typed, while the rest of the program goes about its business. (By the way, there is also an entry in the keyboard task to perform a clean termination of the task.) When the keyboard task reads a character (i.e., after the TASK_QIOW call completes) the character is placed in a circular queue which is hidden inside the ASYNC_KB_INPUT package. The package exports two functions: function INPUT_AVAILABLE return BOOLEAN; function GET_CHARACTER return CHARACTER; INPUT_AVAILABLE simply tells whether there are any new characters in the queue. GET_CHARACTER removes the oldest character from the queue and returns it (or returns ASCII.NUL if the queue is empty.) These two functions are called from an executive task to periodically check for keyboard input. The executive task uses the receive characters to drive a finite state machine which parses the input and takes the appropriate actions. There are some things to be careful of when using this solution. First, when using this method of keyboard input, you cannot use the standard GET; the keyboard task must be shut down in order to use GET. (We got around this by implementing the keyboard task as a task type, so we could shut down the task and start another one at a later time.) Second, only one keyboard task must be active at a time, or REAL trouble will result. Third, you have to be sure to handle the queue-full case correctly, i.e., don't put characters in the queue when it is full. Also, be sure to make the queue big enough so that filling the queue is very unlikely, or characters may be lost. This solution served me well. The non-portable portion is limited to the TASK_QIOW call, which is not visible to the outside world; other implementations could substitute the appropriate code for their systems. Martin Moore mooremj@eglin-vax.arpa ------