djb@wjh12.harvard.edu (David J. Birnbaum) (04/14/90)
Adding Mouse Support to a Screen Saving Utility - Report ======================================================== I recently posted an inquiry about how to modify a screen blanking utility so that it would respond to mouse activity. Despite a few false starts, I was able to do this successfully, thanks primarily to several useful suggestions by Bill Marsh. A few people sent me email asking for a report and most of them seemed headed in the same wrong direction I was, so I thought it might be useful to post the report. Some of this may be quite elementary to more experienced programmers, but most of it was news to me and may be of interest to other readers. The program I was modifying, save.asm, was a utility pro- vided by Hercules for use with Hercules Graphics Card Plus. Be- cause this card has certain registers not present in other cards (including the standard Hercules Graphics Card), a ready-made mouse-aware screen blanker, even if I had been able to find one, would not have been able to restore the screen properly. Her- cules was not interested in adding mouse support to the program themselves, but they graciously sent me the source code and wished me luck. Save.asm works by hooking the timer and keyboard inter- rupts, as follows: At every timer tick, it decrements a counter and checks the counter value. If the value is zero, it checks the screen mode, blanks the screen as required by the current mode, and sets a screen_off flag. At every int 9, the counter is reset to its starting value. The program then checks the screen_off flag and, if the screen is off, it checks the mode and restores the screen as ap- propriate. My initial approach (later abandoned completely) was to hook int 33h and duplicate what goes on in the int 9 handler: I could check for mouse motion and, if the mouse moved, reset the counter and do what was necessary with the screen. I modified the loader portion of the program to swap the interrupt vector and to call int 33h function 0 to initialize the mouse. My processing of int 33h would have to differ from the keyboard handler as follows. The latter interrupt always means there has been keyboard activity, while int 33h can be issued by an application that is polling the mouse even if there is no mouse activity. Since I wanted the screen-blanking counter reset only when there had been some actual mouse activity, and not every time a program polled the mouse, I would have to check for a change in the state of the mouse within my routine. My first thought had been that I could use one of the int 33h functions that allows the user to install event handlers (functions 0ch, 14h, or 18h). It turns out that none of these is actually appropriate for a tsr that must run under other applica- tions because an application that uses the mouse would begin by issuing a call to function 0 to reinitialize the mouse and this function wipes out all user-installed event handlers. Instead I would have to use specific int 33h calls to check for mouse motion. From within my interrupt handler I could not issue an int 33h call directly without falling into a loop, but I could use pushf followed by a call to the old int 33h vec- tor to simulate an int instruction and check the mouse position while avoiding the loop. I initially tried using mouse function 0bh 'read mouse motion counters' to check for mouse motion. The screen save now worked correctly with some graphics and text mode programs, but there were problems with several others. When Shez v5.4 was running on top of my routine, the mouse began to move *very* slowly. It turns out the function 0bh works by reading an internal counter (the 'mickey count'), com- paring it to the last reading, *and resetting the counter*. When my routine was running as a tsr under an application that also used function 0bh (such as Shez), my routine would keep resetting the internal counter before the application could read it. The solution was to abandon function 0bh and to set up variables to hold the mouse cursor horizontal and vertical positions, use function 3 to get the current cursor coordinates, compare them to the old readings in the variables, replace the old readings with them, and then take whatever action was necessary. The screen saver now responded correctly to the mouse in a few more applications (both graphics and text mode), but it ig- nored certain text mode applications, both those that use a mouse (such as Quarterdeck's Manifest) and those that don't (such Xy- Quest's XyWrite). It also didn't function at the command line. In all these cases, touching the keyboard restored the screen, but moving the mouse didn't. As a diagnostic, I added a call to int 33h function 1 in the loader; this caused the mouse cursor to appear on the screen and move in response to my moving the mouse. I assumed that this movement meant that the mouse was properly initialized (which it was) and that moving the mouse was generating int 33h calls that could be read by my routine (which it wasn't). The catch here is that moving the mouse generates a hard- ware interrupt, which varies depending on the type of mouse and its configuration. The mouse driver reads the relevant interrupt without issuing int 33h calls; although I was moving the mouse and the cursor was moving on the screen in response, no int 33h calls were being issued and, as a result, my routine was not being called. The applications that worked with my routine were the ones that generated int 33h calls regularly, while those that didn't poll the mouse by repeated issuing int 33h calls kept my mouse watching routine from being read. The solution was to move the mouse routine out of a sepa- rate int 33h handler and into the new timer routine. This enabled me to unhook int 33h (and to use a real int 33h call in the timer routine, instead of the one I faked with pushf and a call earlier). The timer routine now gets the mouse position, compares it to the old mouse position, and stores the new read- ings. If the mouse has moved, it resets the counter to its starting value and, if necessary, restores the screen. Control then flows into the timer routine that was present in Hercules's version of the program, which checks the countdown and blanks the screen if necessary. I hope this report will be of some use to readers who wish to add mouse support to other screen blanking programs. --David ================================================================= David J. Birnbaum djb@wjh12.harvard.edu [Internet] djb@harvunxw.bitnet [Bitnet]