fpc/rtl/os2/mouse.pp

413 lines
10 KiB
ObjectPascal

{
This file is part of the Free Pascal run time library.
Copyright (c) 1999-2000 by Florian Klaempfl
member of the Free Pascal development team
Mouse unit for OS/2
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
unit Mouse;
interface
{$i mouseh.inc}
const
MouseIsVisible: boolean = false;
implementation
uses
Video,
MouCalls, DosCalls;
{$i mouse.inc}
var
PendingMouseEventOrder: array [0..MouseEventBufSize-1] of cardinal;
MouseEventOrderHead, MouseEventOrderTail: cardinal;
const
NoMouse = $FFFF;
DefaultMouse = 0;
Handle: word = DefaultMouse;
HideCounter: cardinal = 0;
OldEventMask: longint = -1;
procedure SysInitMouse;
var
Loc: TPtrLoc;
SetPrev: boolean;
SysEvent: TMouEventInfo;
QI: TMouQueInfo;
W: word;
begin
SetPrev := MouGetPtrPos (Loc, DefaultMouse) = 0;
if MouGetEventMask (W, DefaultMouse) = 0 then OldEventMask := W;
MouseEventOrderTail := 0;
MouseEventOrderHead := 0;
HideCounter := 0;
if MouOpen (nil, Handle) = Error_Mouse_No_Device then Handle := NoMouse else
begin
W := Mou_NoWait;
repeat
MouGetNumQueEl (QI, Handle);
if QI.cEvents <> 0 then MouReadEventQue (SysEvent, W, Handle);
until QI.cEvents = 0;
W := $FFFF;
MouSetEventMask (W, Handle);
if SetPrev then MouSetPtrPos (Loc, Handle);
(*
It would be possible to issue a MouRegister call here to hook our own mouse
handler, but such handler would have to be in a DLL and it is questionable,
whether there would be so many advantages in doing so.
*)
MouDrawPtr (Handle);
MouseIsVisible := true;
end;
end;
procedure SysDoneMouse;
var
W: word;
begin
if (Handle <> NoMouse) and (Handle <> DefaultMouse) then
begin
(*
If our own mouse handler would be installed in InitMouse, MouDeregister would
have appeared here.
*)
HideCounter := 0;
HideMouse;
MouClose (Handle);
end;
if OldEventMask <> -1 then
begin
W := OldEventMask;
MouSetEventMask (W, 0);
end;
end;
function SysDetectMouse:byte;
var
Buttons: word;
TempHandle: word;
begin
MouOpen (nil, TempHandle);
if MouGetNumButtons (Buttons, TempHandle) = 0 then
SysDetectMouse := Buttons
else
SysDetectMouse := 0;
MouClose (TempHandle);
end;
procedure SysShowMouse;
begin
if Handle <> NoMouse then
begin
if HideCounter <> 0 then
begin
Dec (HideCounter);
if HideCounter = 0 then MouDrawPtr (Handle);
MouseIsVisible := true;
end;
end;
end;
procedure SysHideMouse;
var
PtrRect: TNoPtrRect;
begin
if Handle <> NoMouse then
begin
Inc (HideCounter);
case HideCounter of
0: Dec (HideCounter); (* HideCounter overflowed - stay at the maximum *)
1: begin
PtrRect.Row := 0;
PtrRect.Col := 0;
PtrRect.cRow := Pred (ScreenHeight);
PtrRect.cCol := Pred (ScreenWidth);
MouRemovePtr (PtrRect, Handle);
MouseIsVisible := false;
end;
end;
end;
end;
function SysGetMouseX: word;
var
Event: TMouseEvent;
begin
if Handle = NoMouse then
SysGetMouseX := 0
else
begin
PollMouseEvent (Event);
SysGetMouseX := Event.X;
end;
end;
function SysGetMouseY: word;
var
Event: TMouseEvent;
begin
if Handle = NoMouse then
SysGetMouseY := 0
else
begin
PollMouseEvent (Event);
SysGetMouseY := Event.Y;
end;
end;
procedure SysGetMouseXY (var X: word; var Y: word);
var
Loc: TPtrLoc;
begin
if Handle = NoMouse then
begin
X := 0;
Y := 0;
end else if MouGetPtrPos (Loc, Handle) <> 0 then
begin
X := $FFFF;
Y := $FFFF;
end else
begin
X := Loc.Col;
Y := Loc.Row;
end;
end;
procedure SysSetMouseXY (X, Y: word);
var
Loc: TPtrLoc;
begin
if Handle <> NoMouse then
begin
Loc.Row := Y;
Loc.Col := X;
MouSetPtrPos (Loc, Handle);
end;
end;
procedure TranslateEvents (const SysEvent: TMouEventInfo;
var Event: TMouseEvent);
begin
Event.Buttons := 0;
Event.Action := 0;
if SysEvent.fs and (Mouse_Motion_With_BN1_Down or Mouse_BN1_Down) <> 0 then
Event.Buttons := Event.Buttons or MouseLeftButton;
if SysEvent.fs and (Mouse_Motion_With_BN2_Down or Mouse_BN2_Down) <> 0 then
Event.Buttons := Event.Buttons or MouseRightButton;
if SysEvent.fs and (Mouse_Motion_With_BN3_Down or Mouse_BN3_Down) <> 0 then
Event.Buttons := Event.Buttons or MouseMiddleButton;
Event.X := SysEvent.Col;
Event.Y := SysEvent.Row;
if Event.Buttons <> LastMouseEvent.Buttons then
if (Event.Buttons and MouseLeftButton = 0) and
(LastMouseEvent.Buttons and MouseLeftButton = MouseLeftButton)
then Event.Action := MouseActionUp else
if (Event.Buttons and MouseRightButton = 0) and
(LastMouseEvent.Buttons and MouseRightButton = MouseRightButton)
then Event.Action := MouseActionUp else
if (Event.Buttons and MouseMiddleButton = 0) and
(LastMouseEvent.Buttons and MouseMiddleButton = MouseMiddleButton)
then Event.Action := MouseActionUp
else Event.Action := MouseActionDown
else if (Event.X <> LastMouseEvent.X) or (Event.Y <> LastMouseEvent.Y)
then Event.Action := MouseActionMove;
LastMouseEvent := Event;
end;
procedure NullOrder;
var
I: cardinal;
begin
if PendingMouseEvents > 0 then
begin
I := MouseEventOrderHead;
repeat
PendingMouseEventOrder [I] := 0;
if I = Pred (MouseEventBufSize) then I := 0 else Inc (I);
until (I <> MouseEventOrderTail);
end;
end;
procedure LowerOrder;
var
I: cardinal;
begin
if PendingMouseEvents > 0 then
begin
I := MouseEventOrderHead;
repeat
if PendingMouseEventOrder [I] <> 0 then
begin
Dec (PendingMouseEventOrder [I]);
if I = Pred (MouseEventBufSize) then I := 0 else Inc (I);
end;
until (I <> MouseEventOrderTail) or (PendingMouseEventOrder [I] = 0);
end;
end;
function SysPollMouseEvent (var MouseEvent: TMouseEvent) :boolean;
var
SysEvent: TMouEventInfo;
P, Q: PMouseEvent;
Event: TMouseEvent;
WF: word;
QI: TMouQueInfo;
begin
if (PendingMouseEvents = 0) or
(PendingMouseEventOrder [MouseEventOrderHead] <> 0) and
(PendingMouseEvents < MouseEventBufSize) then
begin
MouGetNumQueEl (QI, Handle);
if QI.cEvents = 0 then NullOrder else
begin
LowerOrder;
WF := Mou_NoWait;
if (MouReadEventQue (SysEvent, WF, Handle) = 0) then
begin
if PendingMouseHead = @PendingMouseEvent[0] then
P := @PendingMouseEvent [MouseEventBufSize - 1] else
begin
P := PendingMouseHead;
Dec (P);
end;
TranslateEvents (SysEvent, P^);
if P^.Action <> 0 then
begin
if PendingMouseEvents < MouseEventBufSize then
begin
Q := P;
WF := Mou_NoWait;
while (P^.Action = MouseActionMove) and
(PendingMouseEventOrder [MouseEventOrderHead] <> 0) and
(MouReadEventQue (SysEvent, WF, Handle) = 0) and
((SysEvent.fs <> 0) or (LastMouseEvent.Buttons <> 0)) do
begin
LowerOrder;
TranslateEvents (SysEvent, Event);
if Event.Action <> MouseActionMove then
begin
if Q = @PendingMouseEvent[0] then
Q := @PendingMouseEvent [MouseEventBufSize - 1] else Dec (Q);
if MouseEventOrderHead = 0 then
MouseEventOrderHead := MouseEventBufSize - 1 else
Dec (MouseEventOrderHead);
PendingMouseEventOrder [MouseEventOrderHead] := 0;
Q^ := P^;
Inc (PendingMouseEvents);
if MouseEventOrderHead = 0 then
MouseEventOrderHead := MouseEventBufSize - 1 else
Dec (MouseEventOrderHead);
PendingMouseEventOrder [MouseEventOrderHead] := 0;
end else WF := Mou_NoWait;
P^ := Event;
end;
P := Q;
end;
Inc (PendingMouseEvents);
if MouseEventOrderHead = 0 then
MouseEventOrderHead := MouseEventBufSize - 1 else
Dec (MouseEventOrderHead);
PendingMouseEventOrder [MouseEventOrderHead] := 0;
PendingMouseHead := P;
end;
end else NullOrder;
end;
end;
if PendingMouseEvents <> 0 then
begin
MouseEvent := PendingMouseHead^;
LastMouseEvent := MouseEvent;
SysPollMouseEvent := true;
end else
begin
SysPollMouseEvent := false;
MouseEvent := LastMouseEvent;
MouseEvent.Action := 0;
end;
end;
function SysGetMouseButtons: word;
var
Event: TMouseEvent;
begin
PollMouseEvent (Event);
SysGetMouseButtons := Event.Buttons;
end;
procedure SysGetMouseEvent (var MouseEvent: TMouseEvent);
begin
if (PendingMouseEvents = 0) or
(PendingMouseEventOrder [MouseEventOrderHead] <> 0) then
repeat
DosSleep (1);
PollMouseEvent (MouseEvent);
until (PendingMouseEvents <> 0) and
(PendingMouseEventOrder [MouseEventOrderHead] = 0) else
begin
MouseEvent := PendingMouseHead^;
LastMouseEvent := MouseEvent;
end;
Inc (PendingMouseHead);
if PendingMouseHead = @PendingMouseEvent[0]+MouseEventBufsize then
PendingMouseHead := @PendingMouseEvent[0];
Inc (MouseEventOrderHead);
if MouseEventOrderHead = MouseEventBufSize then MouseEventOrderHead := 0;
Dec (PendingMouseEvents);
end;
procedure SysPutMouseEvent (const MouseEvent: TMouseEvent);
var
QI: TMouQueInfo;
begin
if PendingMouseEvents < MouseEventBufSize then
begin
PendingMouseTail^ := MouseEvent;
Inc (PendingMouseTail);
if PendingMouseTail=@PendingMouseEvent[0]+MouseEventBufSize then
PendingMouseTail := @PendingMouseEvent[0];
MouGetNumQueEl (QI, Handle);
PendingMouseEventOrder [MouseEventOrderTail] := QI.cEvents;
Inc (MouseEventOrderTail);
if MouseEventOrderTail = MouseEventBufSize then MouseEventOrderTail := 0;
Inc (PendingMouseEvents);
end;
end;
Const
SysMouseDriver : TMouseDriver = (
UseDefaultQueue : False;
InitDriver : @SysInitMouse;
DoneDriver : @SysDoneMouse;
DetectMouse : @SysDetectMouse;
ShowMouse : @SysShowMouse;
HideMouse : @SysHideMouse;
GetMouseX : @SysGetMouseX;
GetMouseY : @SysGetMouseY;
GetMouseButtons : @SysGetMouseButtons;
SetMouseXY : @SysSetMouseXY;
GetMouseEvent : @SysGetMouseEvent;
PollMouseEvent : @SysPollMouseEvent;
PutMouseEvent : @SysPutMouseEvent;
);
Begin
SetMouseDriver(SysMouseDriver);
end.