fpc/rtl/unix/mouse.pp
tom_at_work 923c70932e * removed surplus semicolon
git-svn-id: trunk@6252 -
2007-01-28 19:21:14 +00:00

502 lines
11 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 linux
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
{$ifdef NOMOUSE}
{$DEFINE NOGPM}
{$ENDIF}
{$i mouseh.inc}
implementation
uses
BaseUnix,Video
{$ifndef NOGPM}
,gpm,linuxvcs
{$endif ndef NOGPM}
;
{$i mouse.inc}
{$ifndef NOMOUSE}
const
WaitMouseMove : boolean = false;
PrintMouseCur : boolean = false;
mousecurofs : longint = -1;
var
mousecurcell : TVideoCell;
SysLastMouseEvent : TMouseEvent;
const
gpm_fs : longint = -1;
{$ifndef NOGPM}
procedure GPMEvent2MouseEvent(const e:Tgpm_event;var mouseevent:tmouseevent);
var
PrevButtons : byte;
begin
PrevButtons:=SysLastMouseEvent.Buttons;
if e.x>0 then
mouseevent.x:=e.x-1
else
MouseEvent.x:=0;
if e.y>0 then
MouseEvent.y:=e.y-1
else
MouseEvent.y:=0;
MouseEvent.buttons:=0;
if e.buttons and Gpm_b_left<>0 then
inc(MouseEvent.buttons,1);
if e.buttons and Gpm_b_right<>0 then
inc(MouseEvent.buttons,2);
if e.buttons and Gpm_b_middle<>0 then
inc(MouseEvent.buttons,4);
case (e.EventType and $f) of
GPM_MOVE,
GPM_DRAG :
begin
MouseEvent.Action:=MouseActionMove;
WaitMouseMove:=false;
end;
GPM_DOWN :
begin
MouseEvent.Action:=MouseActionDown;
WaitMouseMove:=false;
end;
GPM_UP :
begin
{ gpm apparently sends the button that is left up
while mouse unit expects the button state after
the button was released PM }
if MouseEvent.Buttons<>0 then
begin
MouseEvent.Buttons:=MouseEvent.Buttons xor PrevButtons;
MouseEvent.Action:=MouseActionUp;
end
{ this does probably never happen...
but its just a security PM }
else
MouseEvent.Action:=MouseActionMove;
WaitMouseMove:=false;
end;
else
MouseEvent.Action:=MouseActionMove;
end;
end;
{$ENDIF}
procedure PlaceMouseCur(ofs:longint);
var
upd : boolean;
begin
if (VideoBuf=nil) or (MouseCurOfs=Ofs) then
exit;
upd:=false;
if (MouseCurOfs<>-1) and (VideoBuf^[MouseCurOfs]=MouseCurCell) then
begin
VideoBuf^[MouseCurOfs]:=MouseCurCell xor $7f00;
upd:=true;
end;
MouseCurOfs:=ofs;
if (MouseCurOfs<>-1) then
begin
MouseCurCell:=VideoBuf^[MouseCurOfs] xor $7f00;
VideoBuf^[MouseCurOfs]:=MouseCurCell;
upd:=true;
end;
if upd then
Updatescreen(false);
end;
{Note: libgpm will initialize an xterm mouse if TERM=xterm.
However, this check sucks, because xterm is not the only terminal
with mouse. To make it worse, it assumes gpm should be used on
anything not xterm, while in reality only the Linux console has gpm.
Some distributions use a patched libgpm to work around this, but
to avoid this mess, we detect the xterm mouse ourselves (we need to
be able to do this anyway for the NOGPM case), and don't do any libgpm
call at all if an xterm mouse is detected. Of course, we use the
Pascal libgpm translation, doing it here allows us to keep the Pascal
one compatible with the external C one.
}
function detect_xterm_mouse:word;
const mouse_terminals:array[0..6] of string[7]=('cons','eterm','gnome',
'konsole','rxvt','screen',
'xterm');
xterm=6;
mouse_1003_capable=[xterm]; {xterm only for now}
var term,colorterm:string;
i,t:shortint;
begin
detect_xterm_mouse:=0;
t:=-1;
term:=fpgetenv('TERM');
for i:=low(mouse_terminals) to high(mouse_terminals) do
if copy(term,1,length(mouse_terminals[i]))=mouse_terminals[i] then
begin
t:=i;
break;
end;
if t=xterm then
begin
{Rxvt sets TERM=xterm and COLORTERM=rxvt. Gnome does something similar.}
term:=fpgetenv('COLORTERM');
for i:=low(mouse_terminals) to high(mouse_terminals) do
if copy(term,1,length(mouse_terminals[i]))=mouse_terminals[i] then
begin
t:=i;
break;
end;
end;
if t>0 then
begin
detect_xterm_mouse:=1000;
{Can the terminal report all mouse events?}
if t in mouse_1003_capable then
detect_xterm_mouse:=1003;
end;
end;
procedure SysInitMouse;
{$ifndef NOGPM}
var connect:TGPMConnect;
e:Tgpm_event;
{$endif ndef NOGPM}
begin
{ if gpm_fs<>-1 then
runerror(240);}
{Test wether to use X-terminals.}
case detect_xterm_mouse of
1000:
begin
{Use the xterm mouse, report button events only.}
gpm_fs:=-1000;
{write(#27'[?1001s');} { save old hilit tracking }
write(#27'[?1000h'); { enable mouse tracking }
end;
1003:
begin
{Use the xterm mouse, report all mouse events.}
gpm_fs:=-1003;
write(#27'[?1003h'); { enable mouse tracking }
end;
end;
{$ifndef NOGPM}
{Use the gpm mouse?}
if (gpm_fs=-1) and (vcs_device<>-1) then
begin
{ open gpm }
connect.EventMask:=GPM_MOVE or GPM_DRAG or GPM_DOWN or GPM_UP;
connect.DefaultMask:=0;
connect.MinMod:=0;
connect.MaxMod:=0;
gpm_fs:=gpm_open(connect,0);
{ initialize SysLastMouseEvent }
if gpm_fs<>-1 then
begin
Gpm_GetSnapshot(e);
GPMEvent2MouseEvent(e,SysLastMouseEvent);
end;
end;
{$endif NOGPM}
end;
procedure SysDoneMouse;
begin
case gpm_fs of
-1:
HideMouse;
-1000:
begin
{xterm mouse}
write(#27'[?1000l'); { disable mouse tracking }
{write(#27'[?1001r');} { Restore old hilit tracking }
end;
-1003:
write(#27'[?1003l'); { disable mouse tracking }
{$ifndef NOGPM}
else
gpm_close;
{$endif}
end;
gpm_fs:=-1;
end;
function SysDetectMouse:byte;
{$ifndef NOGPM}
var
connect : TGPMConnect;
fds : tFDSet;
e : Tgpm_event;
{$endif ndef NOGPM}
begin
if detect_xterm_mouse<>0 then
SysDetectMouse:=2
{$ifndef NOGPM}
else
begin
if gpm_fs=-1 then
begin
connect.EventMask:=GPM_MOVE or GPM_DRAG or GPM_DOWN or GPM_UP;
connect.DefaultMask:=0;
connect.MinMod:=0;
connect.MaxMod:=0;
gpm_fs:=gpm_open(connect,0);
end;
if gpm_fs>=0 then
begin
fpFD_ZERO(fds);
fpFD_SET(gpm_fs,fds);
while fpSelect(gpm_fs+1,@fds,nil,nil,1)>0 do
begin
fillchar(e,sizeof(e),#0);
Gpm_GetEvent(e);
end;
end;
if gpm_fs<>-1 then
SysDetectMouse:=Gpm_GetSnapshot(nil)
else
SysDetectMouse:=0;
end
{$endif NOGPM};
end;
procedure SysGetMouseEvent(var MouseEvent: TMouseEvent);
{$ifndef NOGPM}
var
e : Tgpm_event;
{$endif ndef NOGPM}
begin
fillchar(MouseEvent,SizeOf(TMouseEvent),#0);
if gpm_fs<0 then
exit;
{$ifndef NOGPM}
Gpm_GetEvent(e);
GPMEvent2MouseEvent(e,MouseEvent);
SysLastMouseEvent:=MouseEvent;
{ update mouse cursor }
if PrintMouseCur then
PlaceMouseCur(MouseEvent.y*ScreenWidth+MouseEvent.x);
{$endif ndef NOGPM}
end;
function SysPollMouseEvent(var MouseEvent: TMouseEvent):boolean;
{$ifndef NOGPM}
var
e : Tgpm_event;
fds : tFDSet;
{$endif ndef NOGPM}
begin
fillchar(MouseEvent,SizeOf(TMouseEvent),#0);
{$ifndef NOGPM}
if gpm_fs<0 then
exit(false);
if gpm_fs>0 then
begin
fpFD_ZERO(fds);
fpFD_SET(gpm_fs,fds);
end;
if (fpSelect(gpm_fs+1,@fds,nil,nil,1)>0) then
begin
FillChar(e,SizeOf(e),#0);
{ Gpm_snapshot does not work here PM }
Gpm_GetEvent(e);
GPMEvent2MouseEvent(e,MouseEvent);
SysLastMouseEvent:=MouseEvent;
if (MouseEvent.Action<>0) then
begin
{ As we now use Gpm_GetEvent, we need to put in
in the MouseEvent queue PM }
PutMouseEvent(MouseEvent);
SysPollMouseEvent:=true;
{ update mouse cursor is also required here
as next call will read MouseEvent from queue }
if PrintMouseCur then
PlaceMouseCur(MouseEvent.y*ScreenWidth+MouseEvent.x);
end
else
SysPollMouseEvent:=false;
end
else
{$endif NOGPM}
SysPollMouseEvent:=false;
end;
function SysGetMouseX:word;
{$ifndef NOGPM}
var
me : TMouseEvent;
{$endif ndef NOGPM}
begin
if gpm_fs<0 then
exit(0);
{$ifndef NOGPM}
if PollMouseEvent(ME) then
begin
{ Remove mouse event, we are only interrested in
the X,Y so all other events can be thrown away }
GetMouseEvent(ME);
SysGetMouseX:=ME.X
end
else
begin
SysGetMouseX:=SysLastMouseEvent.x;
end;
{$endif ndef NOGPM}
end;
function SysGetMouseY:word;
{$ifndef NOGPM}
var
me : TMouseEvent;
{$endif ndef NOGPM}
begin
if gpm_fs<0 then
exit(0);
{$ifndef NOGPM}
if PollMouseEvent(ME) then
begin
{ Remove mouse event, we are only interrested in
the X,Y so all other events can be thrown away }
GetMouseEvent(ME);
SysGetMouseY:=ME.Y
end
else
begin
SysGetMouseY:=SysLastMouseEvent.y;
end;
{$endif ndef NOGPM}
end;
procedure SysShowMouse;
var
x,y : word;
begin
PrintMouseCur:=true;
{ Wait with showing the cursor until the mouse has moved. Else the
cursor updates will be to quickly }
if WaitMouseMove then
exit;
if (MouseCurOfs>=0) or (gpm_fs=-1) then
PlaceMouseCur(MouseCurOfs)
else
begin
x:=SysGetMouseX;
y:=SysGetMouseY;
if (x<=ScreenWidth) and (y<=ScreenHeight) then
PlaceMouseCur(Y*ScreenWidth+X)
else
PlaceMouseCur(MouseCurOfs);
end;
end;
procedure SysHideMouse;
begin
if (MouseCurOfs>=0) then
PlaceMouseCur(-1);
WaitMouseMove:=true;
PrintMouseCur:=false;
end;
function SysGetMouseButtons:word;
{$ifndef NOGPM}
var
me : TMouseEvent;
{$endif ndef NOGPM}
begin
if gpm_fs<0 then
exit(0);
{$ifndef NOGPM}
if PollMouseEvent(ME) then
begin
{ Remove mouse event, we are only interrested in
the buttons so all other events can be thrown away }
GetMouseEvent(ME);
SysGetMouseButtons:=ME.Buttons;
end
else
begin
SysGetMouseButtons:=SysLastMouseEvent.buttons;
end;
{$endif ndef NOGPM}
end;
Const
SysMouseDriver : TMouseDriver = (
UseDefaultQueue : true;
InitDriver : @SysInitMouse;
DoneDriver : @SysDoneMouse;
DetectMouse : @SysDetectMouse;
ShowMouse : @SysShowMouse;
HideMouse : @SysHideMouse;
GetMouseX : @SysGetMouseX;
GetMouseY : @SysGetMouseY;
GetMouseButtons : @SysGetMouseButtons;
SetMouseXY : Nil;
GetMouseEvent : @SysGetMouseEvent;
PollMouseEvent : @SysPollMouseEvent;
PutMouseEvent : Nil;
);
{$else ifndef NOMOUSE}
Const
SysMouseDriver : TMouseDriver = (
UseDefaultQueue : true;
InitDriver : Nil;
DoneDriver : Nil;
DetectMouse : Nil;
ShowMouse : Nil;
HideMouse : Nil;
GetMouseX : Nil;
GetMouseY : Nil;
GetMouseButtons : Nil;
SetMouseXY : Nil;
GetMouseEvent : Nil;
PollMouseEvent : Nil;
PutMouseEvent : Nil;
);
{$endif}
Begin
SetMouseDriver(SysMouseDriver);
end.