[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Mouse Click vs Keyboard synchronization



(A summary first for the SLUG people.)
Beginning with 7.0, we have been quite bothered by the apparent lack of
synchronization between mouse clicks and keyboard input especially in the
editor.  We found that we often had situations where, in the editor, we
would click the mouse to move somewhere and follow it by typing a character
(eg, a RUBOUT) that we expected to go where we were moving to.  Unfortunately,
the actions would reverse.  The character would get inserted (or otherwise
acted upon) at the old position and then the cursor would move to the new
location.  This would be quite distressing if you didn't realize what happened
and much later found something to be different than you expected.

Our perception was that the problem was somehow related to dynamic windows.
The problem *apparently* hadn't existed before them and seemed not to occur
in non-dynamic windows in Gen. 7.  We felt that this was a bug and that
Symbolics would surely fix it for 7.1.

7.1 is out but the problem still exists.  It doesn't occur as often
because the working set of 7.1 is smaller and so less paging occurs.  I
presume some part of the paging code ran WITHOUT-INTERRUPTS (which is
what triggers the problem).  However, if you try to edit while another
process is running WITHOUT-INTERRUPTS (maybe for paging), the same
effect occurs.

The frustration level of our users finally hit a boiling point and so we
decided to track this down.  I'm sending this note to explain what happens,
why it doesn't occur in non-dynamic windows, and to propose some possible
cures.

I would like to point out that apparently the problem cannot be solved in
general, given the current hardware and firmware.  If, for whatever reason
(two events too close together or they occur during a WITHOUT-INTERRUPTS),
a mouse-click and a keyboard event occur closely enough that neither the
mouse process nor the keyboard process has been initiated anew between the
two, then it is unclear that the machine can determine which happened first.
Those two processes are at the same priority and so either one might fire
first.

In such a case, in non-dynamic windows, the mouse-click always is considered
to have occurred first.  In dynamic windows, the mouse-click always is
considered to have occurred last.

There are two key points in the code.  The first is in TV:KEY-STATE.
This function is typically called 5 times during the processing of a
mouse click by the mouse process.  It is called to determine whether
there is a modifier to the mouse click (eg, SHIFT-MOUSE-LEFT rather than
clicking twice).  The very first thing that function does is to shove
onto the TV:KBD-IO-BUFFER (which is shared by mouse clicks and keyboard
input) any keyboard characters that have been noticed by the hardware.
These calls to TV:KEY-STATE occur before the mouse click is put into
an IO buffer.

The other key point is in (FLAVOR:METHOD :MOUSE-CLICK
TV:DYNAMIC-MOUSE-MIXIN).  For almost all cases of mouse clicks in a
dynamic window, this routine will shove the mouse click (after all the
calls to KEY-STATE mentioned above) onto TV:KBD-IO-BUFFER.  So, any
keyboard input that occurred at effectively the same time as the mouse
click will be entered earlier in that buffer and so will be handled
before the mouse click.

For non-dynamic windows, (FLAVOR:METHOD :MOUSE-CLICK TV:ESSENTIAL-MOUSE)
sends :FORCE-KBD-INPUT to the window.  This puts the mouse click into the
IO-BUFFER instance variable of the window.  This buffer is read before the
TV:KBD-IO-BUFFER and so mouse-clicks always have priority over keyboard input.
(See Release 6 documentation, Volume 7, page 154 for a comment.)

In summary, both methods have to handle simultaneous mouse clicks and
keyboard input.  Unfortunately they handle them in exactly opposite
fashion.  It is our strong feeling that the dynamic-window method
results in much confusion and frustration.  While similar difficulties
can occur in the non-dynamic style when clicking follows typing too
closely, we do not ever recall those difficulties ever presenting a
problem.  Usually people move the mouse after typing and before
clicking.  That delay is enough.  They often type shortly after
clicking.

Given that we think the old style interaction is best, we have come up
with several different possible patches.  We presume that there was some
reason (that we don't know of) that the dynamic windows shove things
onto the TV:KBD-IO-BUFFER rather than the IO-BUFFER.  For that reason we
don't simply change the (FLAVOR:METHOD :MOUSE-CLICK
TV:DYNAMIC-MOUSE-MIXIN) to just use :FORCE-KBD-INPUT.

I should stress that we have not used these patches much, if at all.
They are suggested as possible patches.

If we are wrong and there is no reason that the dynamic windows
:MOUSE-CLICK is using TV:KBD-IO-BUFFER instead of IO-BUFFER, then making
that change would be the best solution.

One possible patch is to define the :MOUSE-CLICK flavor for
ZWEI:ZWEI-WINDOW to be a duplicate of that method on
TV:DYNAMIC-MOUSE-MIXIN except that it call :FORCE-KBD-INPUT.  This
should only change the editor windows (and ZMAIL, etc) and thereby
minimize any loss of features for general dynamic windows.  I think this may
have some problems with the DW:MARGIN-MIXIN method for :MOUSE-CLICK.

Another possible patch is to fix the :MOUSE-CLICK method so that it
shoves the mouse click onto TV:KBD-IO-BUFFER in front of any characters
(and after any other mouse clicks that may be on it already).  This is
what I am currently using.

(A patch to prevent calling KBD-PROCESS-MAIN-LOOP-INTERNAL in TV:KEY-STATE 
when in the mouse process doesn't work right because the key state might
not be updated if you moved the mouse continuously during which you
pressed the shift key and then a mouse button.  It would have required
setting the mouse process's priority higher than the keyboard process's
so the mouse clicks always got handled first.)


I should point out that if you press the shift key, then the mouse
button, then let up the mouse button, and let up the shift key (all
while running without interrupts), then you will lose the fact that the
mouse click was shifted.  (If you happen to be holding down, say,
CONTROL when the WITHOUT-INTERRUPTS finishes, it will think you pressed
CONTROL-CLICK.)  Until the low-level IO system is changed, we are stuck
with this.