mouse.pp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. Mouse unit for linux
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit Mouse;
  13. interface
  14. {$i mouseh.inc}
  15. implementation
  16. uses
  17. windows,dos,Winevent;
  18. {$i mouse.inc}
  19. var
  20. ChangeMouseEvents : TCriticalSection;
  21. LastHandlerMouseEvent : TMouseEvent;
  22. procedure MouseEventHandler(var ir:INPUT_RECORD);
  23. var
  24. e : TMouseEvent;
  25. begin
  26. EnterCriticalSection(ChangeMouseEvents);
  27. e.x:=ir.Event.MouseEvent.dwMousePosition.x;
  28. e.y:=ir.Event.MouseEvent.dwMousePosition.y;
  29. e.buttons:=0;
  30. e.action:=0;
  31. if (ir.Event.MouseEvent.dwButtonState and FROM_LEFT_1ST_BUTTON_PRESSED<>0) then
  32. e.buttons:=e.buttons or MouseLeftButton;
  33. if (ir.Event.MouseEvent.dwButtonState and FROM_LEFT_2ND_BUTTON_PRESSED<>0) then
  34. e.buttons:=e.buttons or MouseMiddleButton;
  35. if (ir.Event.MouseEvent.dwButtonState and RIGHTMOST_BUTTON_PRESSED<>0) then
  36. e.buttons:=e.buttons or MouseRightButton;
  37. if (Lasthandlermouseevent.x<>e.x) or (LasthandlerMouseEvent.y<>e.y) then
  38. e.Action:=MouseActionMove;
  39. if (LastHandlerMouseEvent.Buttons<>e.Buttons) then
  40. begin
  41. if (LasthandlerMouseEvent.Buttons and e.buttons<>LasthandlerMouseEvent.Buttons) then
  42. e.Action:=MouseActionUp
  43. else
  44. e.Action:=MouseActionDown;
  45. end;
  46. //
  47. // The mouse event compression here was flawed and could lead
  48. // to "zero" mouse actions if the new (x,y) was the same as the
  49. // previous one. (bug 2312)
  50. //
  51. { can we compress the events? }
  52. if (PendingMouseEvents>0) and
  53. (e.buttons=PendingMouseTail^.buttons) and
  54. (e.action=PendingMouseTail^.action) then
  55. begin
  56. PendingMouseTail^.x:=e.x;
  57. PendingMouseTail^.y:=e.y;
  58. end
  59. else
  60. begin
  61. if e.action<>0 then
  62. begin
  63. LastHandlermouseEvent:=e;
  64. { wait till there is again space in the mouse event queue }
  65. while PendingMouseEvents>=MouseEventBufSize do
  66. begin
  67. LeaveCriticalSection(ChangeMouseEvents);
  68. sleep(0);
  69. EnterCriticalSection(ChangeMouseEvents);
  70. end;
  71. PutMouseEvent(e);
  72. end;
  73. // this should be done in PutMouseEvent, now it is PM
  74. // inc(PendingMouseEvents);
  75. end;
  76. LastMouseEvent:=e;
  77. LeaveCriticalSection(ChangeMouseEvents);
  78. end;
  79. procedure SysInitMouse;
  80. var
  81. mode : dword;
  82. begin
  83. // enable mouse events
  84. GetConsoleMode(StdInputHandle,@mode);
  85. mode:=mode or ENABLE_MOUSE_INPUT;
  86. SetConsoleMode(StdInputHandle,mode);
  87. PendingMouseHead:=@PendingMouseEvent[0];
  88. PendingMouseTail:=@PendingMouseEvent[0];
  89. PendingMouseEvents:=0;
  90. FillChar(LastMouseEvent,sizeof(TMouseEvent),0);
  91. InitializeCriticalSection(ChangeMouseEvents);
  92. SetMouseEventHandler(@MouseEventHandler);
  93. ShowMouse;
  94. end;
  95. procedure SysDoneMouse;
  96. var
  97. mode : dword;
  98. begin
  99. HideMouse;
  100. // disable mouse events
  101. GetConsoleMode(StdInputHandle,@mode);
  102. mode:=mode and (not ENABLE_MOUSE_INPUT);
  103. SetConsoleMode(StdInputHandle,mode);
  104. SetMouseEventHandler(nil);
  105. DeleteCriticalSection(ChangeMouseEvents);
  106. end;
  107. function SysDetectMouse:byte;
  108. var
  109. num : dword;
  110. begin
  111. GetNumberOfConsoleMouseButtons(@num);
  112. SysDetectMouse:=num;
  113. end;
  114. procedure SysGetMouseEvent(var MouseEvent: TMouseEvent);
  115. var
  116. b : byte;
  117. begin
  118. repeat
  119. EnterCriticalSection(ChangeMouseEvents);
  120. b:=PendingMouseEvents;
  121. LeaveCriticalSection(ChangeMouseEvents);
  122. if b>0 then
  123. break
  124. else
  125. sleep(50);
  126. until false;
  127. EnterCriticalSection(ChangeMouseEvents);
  128. MouseEvent:=PendingMouseHead^;
  129. inc(PendingMouseHead);
  130. if ptruint(PendingMouseHead)=ptruint(@PendingMouseEvent)+sizeof(PendingMouseEvent) then
  131. PendingMouseHead:=@PendingMouseEvent[0];
  132. dec(PendingMouseEvents);
  133. { LastMouseEvent is already set at the end of the mouse event handler,
  134. so this code might compare LastMouseEvent with itself leading to
  135. "empty" events (FK)
  136. if (LastMouseEvent.x<>MouseEvent.x) or (LastMouseEvent.y<>MouseEvent.y) then
  137. MouseEvent.Action:=MouseActionMove;
  138. if (LastMouseEvent.Buttons<>MouseEvent.Buttons) then
  139. begin
  140. if (LastMouseEvent.Buttons and MouseEvent.buttons<>LastMouseEvent.Buttons) then
  141. MouseEvent.Action:=MouseActionUp
  142. else
  143. MouseEvent.Action:=MouseActionDown;
  144. end;
  145. if MouseEvent.action=0 then
  146. MousEevent.action:=MouseActionMove; // can sometimes happen due to compression of events.
  147. LastMouseEvent:=MouseEvent;
  148. }
  149. LeaveCriticalSection(ChangeMouseEvents);
  150. end;
  151. function SysPollMouseEvent(var MouseEvent: TMouseEvent):boolean;
  152. begin
  153. EnterCriticalSection(ChangeMouseEvents);
  154. if PendingMouseEvents>0 then
  155. begin
  156. MouseEvent:=PendingMouseHead^;
  157. SysPollMouseEvent:=true;
  158. end
  159. else
  160. SysPollMouseEvent:=false;
  161. LeaveCriticalSection(ChangeMouseEvents);
  162. end;
  163. procedure SysPutMouseEvent(const MouseEvent: TMouseEvent);
  164. begin
  165. EnterCriticalSection(ChangeMouseEvents);
  166. if PendingMouseEvents<MouseEventBufSize then
  167. begin
  168. PendingMouseTail^:=MouseEvent;
  169. inc(PendingMouseTail);
  170. if ptruint(PendingMouseTail)=ptruint(@PendingMouseEvent)+sizeof(PendingMouseEvent) then
  171. PendingMouseTail:=@PendingMouseEvent[0];
  172. { why isn't this done here ?
  173. so the win32 version do this by hand:}
  174. inc(PendingMouseEvents);
  175. end;
  176. LeaveCriticalSection(ChangeMouseEvents);
  177. end;
  178. function SysGetMouseX:word;
  179. begin
  180. EnterCriticalSection(ChangeMouseEvents);
  181. SysGetMouseX:=LastMouseEvent.x;
  182. LeaveCriticalSection(ChangeMouseEvents);
  183. end;
  184. function SysGetMouseY:word;
  185. begin
  186. EnterCriticalSection(ChangeMouseEvents);
  187. SysGetMouseY:=LastMouseEvent.y;
  188. LeaveCriticalSection(ChangeMouseEvents);
  189. end;
  190. function SysGetMouseButtons:word;
  191. begin
  192. EnterCriticalSection(ChangeMouseEvents);
  193. SysGetMouseButtons:=LastMouseEvent.Buttons;
  194. LeaveCriticalSection(ChangeMouseEvents);
  195. end;
  196. Const
  197. SysMouseDriver : TMouseDriver = (
  198. UseDefaultQueue : False;
  199. InitDriver : @SysInitMouse;
  200. DoneDriver : @SysDoneMouse;
  201. DetectMouse : @SysDetectMouse;
  202. ShowMouse : Nil;
  203. HideMouse : Nil;
  204. GetMouseX : @SysGetMouseX;
  205. GetMouseY : @SysGetMouseY;
  206. GetMouseButtons : @SysGetMouseButtons;
  207. SetMouseXY : Nil;
  208. GetMouseEvent : @SysGetMouseEvent;
  209. PollMouseEvent : @SysPollMouseEvent;
  210. PutMouseEvent : @SysPutMouseEvent;
  211. );
  212. Begin
  213. SetMouseDriver(SysMouseDriver);
  214. end.