123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2006 Karoly Balogh
- member of the Free Pascal development team
- Mouse unit for Amiga/MorphOS
- 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}
- implementation
- //uses
- // windows,dos,Winevent;
- {$i mouse.inc}
- //var
- // ChangeMouseEvents : TCriticalSection;
- // LastHandlerMouseEvent : TMouseEvent;
- {
- procedure MouseEventHandler(var ir:INPUT_RECORD);
- var
- e : TMouseEvent;
- begin
- EnterCriticalSection(ChangeMouseEvents);
- e.x:=ir.Event.MouseEvent.dwMousePosition.x;
- e.y:=ir.Event.MouseEvent.dwMousePosition.y;
- e.buttons:=0;
- e.action:=0;
- if (ir.Event.MouseEvent.dwButtonState and FROM_LEFT_1ST_BUTTON_PRESSED<>0) then
- e.buttons:=e.buttons or MouseLeftButton;
- if (ir.Event.MouseEvent.dwButtonState and FROM_LEFT_2ND_BUTTON_PRESSED<>0) then
- e.buttons:=e.buttons or MouseMiddleButton;
- if (ir.Event.MouseEvent.dwButtonState and RIGHTMOST_BUTTON_PRESSED<>0) then
- e.buttons:=e.buttons or MouseRightButton;
- if (Lasthandlermouseevent.x<>e.x) or (LasthandlerMouseEvent.y<>e.y) then
- e.Action:=MouseActionMove;
- if (LastHandlerMouseEvent.Buttons<>e.Buttons) then
- begin
- if (LasthandlerMouseEvent.Buttons and e.buttons<>LasthandlerMouseEvent.Buttons) then
- e.Action:=MouseActionUp
- else
- e.Action:=MouseActionDown;
- end;
- //
- // The mouse event compression here was flawed and could lead
- // to "zero" mouse actions if the new (x,y) was the same as the
- // previous one. (bug 2312)
- //
- { can we compress the events? }
- if (PendingMouseEvents>0) and
- (e.buttons=PendingMouseTail^.buttons) and
- (e.action=PendingMouseTail^.action) then
- begin
- PendingMouseTail^.x:=e.x;
- PendingMouseTail^.y:=e.y;
- end
- else
- begin
- if e.action<>0 then
- begin
- LastHandlermouseEvent:=e;
- { what till there is again space in the mouse event queue }
- while PendingMouseEvents>=MouseEventBufSize do
- begin
- LeaveCriticalSection(ChangeMouseEvents);
- sleep(0);
- EnterCriticalSection(ChangeMouseEvents);
- end;
- PutMouseEvent(e);
- end;
- // this should be done in PutMouseEvent, now it is PM
- // inc(PendingMouseEvents);
- end;
- LastMouseEvent:=e;
- LeaveCriticalSection(ChangeMouseEvents);
- end;
- }
- procedure SysInitMouse;
- var
- mode : dword;
- begin
- {
- // enable mouse events
- GetConsoleMode(StdInputHandle,@mode);
- mode:=mode or ENABLE_MOUSE_INPUT;
- SetConsoleMode(StdInputHandle,mode);
- PendingMouseHead:=@PendingMouseEvent;
- PendingMouseTail:=@PendingMouseEvent;
- PendingMouseEvents:=0;
- FillChar(LastMouseEvent,sizeof(TMouseEvent),0);
- InitializeCriticalSection(ChangeMouseEvents);
- SetMouseEventHandler(@MouseEventHandler);
- ShowMouse;
- }
- end;
- procedure SysDoneMouse;
- var
- mode : dword;
- begin
- {
- HideMouse;
- // disable mouse events
- GetConsoleMode(StdInputHandle,@mode);
- mode:=mode and (not ENABLE_MOUSE_INPUT);
- SetConsoleMode(StdInputHandle,mode);
- SetMouseEventHandler(nil);
- DeleteCriticalSection(ChangeMouseEvents);
- }
- end;
- function SysDetectMouse:byte;
- var
- num : dword;
- begin
- // Under Amiga/MorphOS, mouse is always there, and it's unable to easily
- // detect number of buttons. So lets report 3, which is common nowadays. (KB)
- SysDetectMouse:=3;
- end;
- procedure SysGetMouseEvent(var MouseEvent: TMouseEvent);
- var
- b : byte;
- begin
- {
- repeat
- EnterCriticalSection(ChangeMouseEvents);
- b:=PendingMouseEvents;
- LeaveCriticalSection(ChangeMouseEvents);
- if b>0 then
- break
- else
- sleep(50);
- until false;
- EnterCriticalSection(ChangeMouseEvents);
- MouseEvent:=PendingMouseHead^;
- inc(PendingMouseHead);
- if ptrint(PendingMouseHead)=ptrint(@PendingMouseEvent)+sizeof(PendingMouseEvent) then
- PendingMouseHead:=@PendingMouseEvent;
- dec(PendingMouseEvents);
- { LastMouseEvent is already set at the end of the mouse event handler,
- so this code might compare LastMouseEvent with itself leading to
- "empty" events (FK)
- if (LastMouseEvent.x<>MouseEvent.x) or (LastMouseEvent.y<>MouseEvent.y) then
- MouseEvent.Action:=MouseActionMove;
- if (LastMouseEvent.Buttons<>MouseEvent.Buttons) then
- begin
- if (LastMouseEvent.Buttons and MouseEvent.buttons<>LastMouseEvent.Buttons) then
- MouseEvent.Action:=MouseActionUp
- else
- MouseEvent.Action:=MouseActionDown;
- end;
- if MouseEvent.action=0 then
- MousEevent.action:=MouseActionMove; // can sometimes happen due to compression of events.
- LastMouseEvent:=MouseEvent;
- }
- LeaveCriticalSection(ChangeMouseEvents);
- }
- end;
- function SysPollMouseEvent(var MouseEvent: TMouseEvent):boolean;
- begin
- {
- EnterCriticalSection(ChangeMouseEvents);
- if PendingMouseEvents>0 then
- begin
- MouseEvent:=PendingMouseHead^;
- SysPollMouseEvent:=true;
- end
- else
- SysPollMouseEvent:=false;
- LeaveCriticalSection(ChangeMouseEvents);
- }
- end;
- procedure SysPutMouseEvent(const MouseEvent: TMouseEvent);
- begin
- {
- if PendingMouseEvents<MouseEventBufSize then
- begin
- PendingMouseTail^:=MouseEvent;
- inc(PendingMouseTail);
- if ptrint(PendingMouseTail)=ptrint(@PendingMouseEvent)+sizeof(PendingMouseEvent) then
- PendingMouseTail:=@PendingMouseEvent;
- { why isn't this done here ?
- so the win32 version do this by hand:}
- inc(PendingMouseEvents);
- end;
- }
- end;
- function SysGetMouseX:word;
- begin
- {
- EnterCriticalSection(ChangeMouseEvents);
- SysGetMouseX:=LastMouseEvent.x;
- LeaveCriticalSection(ChangeMouseEvents);
- }
- end;
- function SysGetMouseY:word;
- begin
- {
- EnterCriticalSection(ChangeMouseEvents);
- SysGetMouseY:=LastMouseEvent.y;
- LeaveCriticalSection(ChangeMouseEvents);
- }
- end;
- function SysGetMouseButtons:word;
- begin
- {
- EnterCriticalSection(ChangeMouseEvents);
- SysGetMouseButtons:=LastMouseEvent.Buttons;
- LeaveCriticalSection(ChangeMouseEvents);
- }
- end;
- const
- SysMouseDriver : TMouseDriver = (
- UseDefaultQueue : False;
- InitDriver : @SysInitMouse;
- DoneDriver : @SysDoneMouse;
- DetectMouse : @SysDetectMouse;
- ShowMouse : Nil;
- HideMouse : Nil;
- GetMouseX : @SysGetMouseX;
- GetMouseY : @SysGetMouseY;
- GetMouseButtons : @SysGetMouseButtons;
- SetMouseXY : Nil;
- GetMouseEvent : @SysGetMouseEvent;
- PollMouseEvent : @SysPollMouseEvent;
- PutMouseEvent : @SysPutMouseEvent;
- );
- begin
- SetMouseDriver(SysMouseDriver);
- end.
|