mead@uxh.cso.uiuc.edu (Alan David Mead) (11/03/90)
Here are some routines from Turbo Technix (May/June 1988). If they
have been posted previously, I missed them. They simplify programming
the mouse. You should get a copy of the article (p52-64?) or a
discussion of the results of the mouse functions. Only Microsoft and
(really) 100% compatibles are (garrunteed to be) supported except that
there are 2 extra Logitech functions.
After MOUSE, there is my modified version of the event handler demo
that was included in the article. The program is set up for a color
monitor (of any type)--change the offset parameter in the MemW array
in the procedure handler to $B000 for a monochrome. The code draws
a screen and then continuously displays the coordinates of the cursor,
clicking every time the cursor moves. Hitting the right button exits
the demo.
I have been having several problems, here are two:
1) the mouse cursor is specified by character AND attribute, so
when you move it from the blue background onto the cyan it doesn't
look so hot--to compensate, I thought I'd just
a) read the color attribute with mem,
b) clear the low bits, and
c) redefine the cursor with the new attribute.
But on my IBM PS2 55SX, the blue background returns a 7? Also, I fear
that I'm over-burdening the event handler (which should be quick,
right?). Does anyone know of a better way?
2) Perhaps related to the above (although I don't think so), the
cursor sometimes forgets to erase itself as it moves. This results
in green or black (or whatever) blocks messing up the display. Is this
a timing problem? It is most acute when the cursor is being moved
moderately quickly.
Any help would be greatly appreciated. One user recommended a book
by Microsoft (title similar to _Programming a Mouse_)--has anyone used
the book? Is it any good? Thanks in advance.
-alan mead : mead@uxh.cso.uiuc
==========[ begin ]===============
unit mouse;
Interface
(*{$U \tp}*)
uses dos;
const
MDD = $33;
type
ResetRec = record
exists : boolean; { true if mouse installed }
nButtons : integer; { number buttons on mouse }
end;
LocRec = record
buttonStatus, { initialized by functions 3 5 & 6 }
opCount, { bits 0-2 on if L,R,M button is down }
column,
row : integer;
end;
moveRec = record { initialized by function 11 }
hCount, { net horizontal movement }
vCount : integer; { net vertical movement }
end;
var
reg : registers;
{ Microsoft mouse functions }
procedure mReset( var Mouse:ResetRec ); { function 0 }
procedure mShow; { function 1 }
procedure mHide; { function 2 }
procedure mPos( var Mouse:LocRec ); { function 3 }
procedure mMoveTo( col,row:integer ); { function 4 }
procedure mPressed( button:integer; var mouse:LocRec ); { function 5 }
procedure mReleased( button:integer; var mouse:LocRec ); { function 6 }
procedure mColRange( min,max:integer ); { function 7 }
procedure mRowRange( min,max:integer ); { function 8 }
procedure mGraphCursor( hHot,vHot:integer; { function 9 }
MaskSeg,MaskOfs:word );
procedure mTextCursor( cType,p1,p2:word ); { function 10 }
procedure mMotion( var moved:moveRec ); { function 11 }
procedure mInstTask( mask,TaskSeg,TaskOfs:word ); { function 12 }
procedure mLpenOn; { function 13 }
procedure mLpenOff; { function 14 }
procedure mRatio( horiz,vert:integer ); { function 15 }
implementation
function Lower( n1,n2:integer ):integer; { local to unit }
begin
if n1 < n2 then
lower := n1
else
lower := n2;
end;
function Upper( n1,n2:integer ):integer;
begin
if n1 > n2 then
Upper := n1
else
Upper := n2;
end;
procedure mReset;
begin
reg.AX := 0;
intr( MDD,reg );
{ mouse.exists := ( reg.AX = 0 ); }
if reg.AX <> 0 then
mouse.exists := TRUE
else
mouse.exists := FALSE;
mouse.nButtons := reg.BX;
end;
procedure mShow;
begin
reg.AX := 1;
intr( MDD,reg );
end; { mShow }
procedure mHide;
begin
reg.AX := 2;
intr( MDD,reg );
end; { mHide }
procedure mPos;
begin
reg.AX := 3;
intr( MDD,reg );
mouse.ButtonStatus := reg.BX;
mouse.Column := reg.CX;
mouse.Row := reg.DX;
end; { mPos }
procedure mMoveTo;
begin
reg.AX := 4;
reg.CX := col;
reg.DX := row;
intr( MDD,reg );
end; { mMoveTo }
procedure mPressed;
begin
reg.AX := 5;
reg.BX := button;
intr( MDD,reg );
mouse.ButtonStatus := reg.AX;
mouse.OpCount := reg.BX;
mouse.column := reg.CX;
mouse.row := reg.DX;
end; { mPressed }
procedure mReleased;
begin
reg.AX := 6;
reg.BX := button;
intr( MDD,reg );
mouse.ButtonStatus := reg.AX;
mouse.OpCount := reg.BX;
mouse.column := reg.CX;
mouse.row := reg.DX;
end; {mReleased }
procedure mColRange;
begin
reg.AX := 7;
reg.CX := lower( min,max );
reg.DX := upper( min,max );
intr( MDD,reg );
end; { mColRange }
procedure mRowRange;
begin
reg.AX := 8;
reg.CX := lower( min,max );
reg.DX := upper( min,max );
intr( MDD,reg );
end; { mRowRange }
procedure mGraphCursor;
begin
reg.AX := 9;
reg.BX := hHot;
reg.CX := vHot;
reg.DX := maskOfs;
reg.ES := maskSeg;
intr( MDD,reg );
end; { mGraphCursor }
procedure mTextCursor;
{ NOTES: Type 0 is the software cursor. When unspecified, p1 and p2 are
the screen and cursor masks.
Type 1 is the hardware cursor. When specified, p1 and p2 are the start
and stop scan lines, ie the cursor shape. }
begin
reg.AX := 10;
reg.BX := ctype;
reg.CX := p1;
reg.DX := p2;
intr( MDD,reg );
end; { mTextCursor }
procedure mMotion; { Net movement since last call }
begin { Expressed in mickeys (1/100") }
reg.AX := 11;
intr( MDD,reg );
moved.hCount := reg.CX;
moved.vCount := reg.DX;
end; { mMotion }
procedure mInstTask; { Install user-defined task }
begin
reg.AX := 12;
reg.CX := mask;
reg.DX := taskOfs;
reg.ES := taskSeg;
intr( MDD,reg );
end; { mInstTask }
procedure mLpenOn; { Begin emulation of light pen }
begin
reg.AX := 14;
intr( MDD,reg );
end; { mLpenOn }
procedure mLpenOff; { Stop emulating light pen }
begin
reg.AX := 15;
intr( MDD,reg );
end; { mLpenOff }
procedure mRatio; { set mickey to pixel ratio }
{ NOTES:
Ratios are R/8.
Default is 16 for vertical, 8 for horizontal }
begin
reg.AX := 15;
reg.CX := horiz;
reg.DX := vert;
intr( MDD,reg );
end; { mRatio }
end.
==============[ cut here ]================
program mousevnt;
uses dos,crt,mouse;
type
mEvent = record
event ,
btnStatus,
horiz,
vert : word;
end;
var
mous : mEvent;
t : LocRec;
m : resetRec;
x,y : byte;
procedure handler( Flags,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP : word );
{
For speed, I've used inc() to add and SHR | SHL to divide | multiply
by powers of two.
}
interrupt;
var attribute:word; AtOffset:word;
begin
mous.event := AX;
mous.btnStatus := BX;
mous.horiz := CX;
mous.vert := DX;
AtOffset := (( 5*mous.vert ) SHL 5 )+( mous.horiz * 2 ) ;
attribute := MemW[ $B800:AtOffset ];
attribute := ( attribute SHR 8 );
attribute := ( attribute SHL 8 );
mTextCursor( 0,0,$0040+ attribute );
mous.horiz := mous.horiz SHR 3; { divide by 8. Mouse goes by (graphic) }
mous.vert := mous.vert SHR 3; { pixels instead of rows & columns }
inc( mous.horiz ); { So that the upper left is 1,1--not 0,0 }
inc( mous.vert );
inline( { exit processing and far return from the driver }
$8B/$E5/
$5D/
$07/
$1F/
$5F/
$5E/
$5A/
$59/
$5B/
$58/
$CB );
end;
begin
window( 1,1,80,1 );
textcolor( white );
textBackground( Cyan );
ClrScr;
GotoXY( 2,1 );
write( 'MOUSE EVENT-HANDLING DEMO' );
window( 1,25,80,25 );
ClrScr;
GotoXY( 17,1 );
write( 'Press right button to quit' );
window( 1,2,80,24 );
TextColor( White );
TextBackground( Blue );
ClrScr;
window( 1,1,80,25 );
textbackground( cyan );
{ set up rodent }
mReset( m );
if m.exists then
begin
mInstTask( 25,seg( handler ),ofs( Handler ));
mous.event := 0;
mous.horiz := 0;
mous.vert := 0;
mShow;
mTextCursor( 0,0,$1f40); { white on blue at-symbol }
x := 0; y := 0;
{ Loop to perform demo }
repeat
mPressed( 4,t );
if ( mous.horiz <> x ) OR ( mous.vert <> y ) then
begin
x := mous.horiz;
y := mous.vert;
mHide;
Gotoxy( 50,1 );
writeln( 'X= ',mous.horiz:5,', Y= ',mous.vert:5 );
sound( 2000 );
delay( 5 );
nosound;
mShow;
end;
until t.ButtonStatus = 2 ;
GotoXY( 50,1 );
writeln( 'Good bye ! ' );
{ Clean up and quit }
mHide;
mReset( m );
end;
{ ClrScr; }
end.
======================[ end ]========================
--
Alan Mead : mead@uxh.cso.uiuc.edu