[alt.msdos.programmer] Adding Mouse Support to a Screen Saver - Report

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]