2
0

mouse.pp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2006 Karoly Balogh
  4. member of the Free Pascal development team
  5. Mouse unit for Amiga/MorphOS
  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. {
  23. procedure MouseEventHandler(var ir:INPUT_RECORD);
  24. var
  25. e : TMouseEvent;
  26. begin
  27. EnterCriticalSection(ChangeMouseEvents);
  28. e.x:=ir.Event.MouseEvent.dwMousePosition.x;
  29. e.y:=ir.Event.MouseEvent.dwMousePosition.y;
  30. e.buttons:=0;
  31. e.action:=0;
  32. if (ir.Event.MouseEvent.dwButtonState and FROM_LEFT_1ST_BUTTON_PRESSED<>0) then
  33. e.buttons:=e.buttons or MouseLeftButton;
  34. if (ir.Event.MouseEvent.dwButtonState and FROM_LEFT_2ND_BUTTON_PRESSED<>0) then
  35. e.buttons:=e.buttons or MouseMiddleButton;
  36. if (ir.Event.MouseEvent.dwButtonState and RIGHTMOST_BUTTON_PRESSED<>0) then
  37. e.buttons:=e.buttons or MouseRightButton;
  38. if (Lasthandlermouseevent.x<>e.x) or (LasthandlerMouseEvent.y<>e.y) then
  39. e.Action:=MouseActionMove;
  40. if (LastHandlerMouseEvent.Buttons<>e.Buttons) then
  41. begin
  42. if (LasthandlerMouseEvent.Buttons and e.buttons<>LasthandlerMouseEvent.Buttons) then
  43. e.Action:=MouseActionUp
  44. else
  45. e.Action:=MouseActionDown;
  46. end;
  47. //
  48. // The mouse event compression here was flawed and could lead
  49. // to "zero" mouse actions if the new (x,y) was the same as the
  50. // previous one. (bug 2312)
  51. //
  52. { can we compress the events? }
  53. if (PendingMouseEvents>0) and
  54. (e.buttons=PendingMouseTail^.buttons) and
  55. (e.action=PendingMouseTail^.action) then
  56. begin
  57. PendingMouseTail^.x:=e.x;
  58. PendingMouseTail^.y:=e.y;
  59. end
  60. else
  61. begin
  62. if e.action<>0 then
  63. begin
  64. LastHandlermouseEvent:=e;
  65. { what till there is again space in the mouse event queue }
  66. while PendingMouseEvents>=MouseEventBufSize do
  67. begin
  68. LeaveCriticalSection(ChangeMouseEvents);
  69. sleep(0);
  70. EnterCriticalSection(ChangeMouseEvents);
  71. end;
  72. PutMouseEvent(e);
  73. end;
  74. // this should be done in PutMouseEvent, now it is PM
  75. // inc(PendingMouseEvents);
  76. end;
  77. LastMouseEvent:=e;
  78. LeaveCriticalSection(ChangeMouseEvents);
  79. end;
  80. }
  81. procedure SysInitMouse;
  82. var
  83. mode : dword;
  84. begin
  85. {
  86. // enable mouse events
  87. GetConsoleMode(StdInputHandle,@mode);
  88. mode:=mode or ENABLE_MOUSE_INPUT;
  89. SetConsoleMode(StdInputHandle,mode);
  90. PendingMouseHead:=@PendingMouseEvent;
  91. PendingMouseTail:=@PendingMouseEvent;
  92. PendingMouseEvents:=0;
  93. FillChar(LastMouseEvent,sizeof(TMouseEvent),0);
  94. InitializeCriticalSection(ChangeMouseEvents);
  95. SetMouseEventHandler(@MouseEventHandler);
  96. ShowMouse;
  97. }
  98. end;
  99. procedure SysDoneMouse;
  100. var
  101. mode : dword;
  102. begin
  103. {
  104. HideMouse;
  105. // disable mouse events
  106. GetConsoleMode(StdInputHandle,@mode);
  107. mode:=mode and (not ENABLE_MOUSE_INPUT);
  108. SetConsoleMode(StdInputHandle,mode);
  109. SetMouseEventHandler(nil);
  110. DeleteCriticalSection(ChangeMouseEvents);
  111. }
  112. end;
  113. function SysDetectMouse:byte;
  114. var
  115. num : dword;
  116. begin
  117. // Under Amiga/MorphOS, mouse is always there, and it's unable to easily
  118. // detect number of buttons. So lets report 3, which is common nowadays. (KB)
  119. SysDetectMouse:=3;
  120. end;
  121. procedure SysGetMouseEvent(var MouseEvent: TMouseEvent);
  122. var
  123. b : byte;
  124. begin
  125. {
  126. repeat
  127. EnterCriticalSection(ChangeMouseEvents);
  128. b:=PendingMouseEvents;
  129. LeaveCriticalSection(ChangeMouseEvents);
  130. if b>0 then
  131. break
  132. else
  133. sleep(50);
  134. until false;
  135. EnterCriticalSection(ChangeMouseEvents);
  136. MouseEvent:=PendingMouseHead^;
  137. inc(PendingMouseHead);
  138. if ptrint(PendingMouseHead)=ptrint(@PendingMouseEvent)+sizeof(PendingMouseEvent) then
  139. PendingMouseHead:=@PendingMouseEvent;
  140. dec(PendingMouseEvents);
  141. { LastMouseEvent is already set at the end of the mouse event handler,
  142. so this code might compare LastMouseEvent with itself leading to
  143. "empty" events (FK)
  144. if (LastMouseEvent.x<>MouseEvent.x) or (LastMouseEvent.y<>MouseEvent.y) then
  145. MouseEvent.Action:=MouseActionMove;
  146. if (LastMouseEvent.Buttons<>MouseEvent.Buttons) then
  147. begin
  148. if (LastMouseEvent.Buttons and MouseEvent.buttons<>LastMouseEvent.Buttons) then
  149. MouseEvent.Action:=MouseActionUp
  150. else
  151. MouseEvent.Action:=MouseActionDown;
  152. end;
  153. if MouseEvent.action=0 then
  154. MousEevent.action:=MouseActionMove; // can sometimes happen due to compression of events.
  155. LastMouseEvent:=MouseEvent;
  156. }
  157. LeaveCriticalSection(ChangeMouseEvents);
  158. }
  159. end;
  160. function SysPollMouseEvent(var MouseEvent: TMouseEvent):boolean;
  161. begin
  162. {
  163. EnterCriticalSection(ChangeMouseEvents);
  164. if PendingMouseEvents>0 then
  165. begin
  166. MouseEvent:=PendingMouseHead^;
  167. SysPollMouseEvent:=true;
  168. end
  169. else
  170. SysPollMouseEvent:=false;
  171. LeaveCriticalSection(ChangeMouseEvents);
  172. }
  173. end;
  174. procedure SysPutMouseEvent(const MouseEvent: TMouseEvent);
  175. begin
  176. {
  177. if PendingMouseEvents<MouseEventBufSize then
  178. begin
  179. PendingMouseTail^:=MouseEvent;
  180. inc(PendingMouseTail);
  181. if ptrint(PendingMouseTail)=ptrint(@PendingMouseEvent)+sizeof(PendingMouseEvent) then
  182. PendingMouseTail:=@PendingMouseEvent;
  183. { why isn't this done here ?
  184. so the win32 version do this by hand:}
  185. inc(PendingMouseEvents);
  186. end;
  187. }
  188. end;
  189. function SysGetMouseX:word;
  190. begin
  191. {
  192. EnterCriticalSection(ChangeMouseEvents);
  193. SysGetMouseX:=LastMouseEvent.x;
  194. LeaveCriticalSection(ChangeMouseEvents);
  195. }
  196. end;
  197. function SysGetMouseY:word;
  198. begin
  199. {
  200. EnterCriticalSection(ChangeMouseEvents);
  201. SysGetMouseY:=LastMouseEvent.y;
  202. LeaveCriticalSection(ChangeMouseEvents);
  203. }
  204. end;
  205. function SysGetMouseButtons:word;
  206. begin
  207. {
  208. EnterCriticalSection(ChangeMouseEvents);
  209. SysGetMouseButtons:=LastMouseEvent.Buttons;
  210. LeaveCriticalSection(ChangeMouseEvents);
  211. }
  212. end;
  213. const
  214. SysMouseDriver : TMouseDriver = (
  215. UseDefaultQueue : False;
  216. InitDriver : @SysInitMouse;
  217. DoneDriver : @SysDoneMouse;
  218. DetectMouse : @SysDetectMouse;
  219. ShowMouse : Nil;
  220. HideMouse : Nil;
  221. GetMouseX : @SysGetMouseX;
  222. GetMouseY : @SysGetMouseY;
  223. GetMouseButtons : @SysGetMouseButtons;
  224. SetMouseXY : Nil;
  225. GetMouseEvent : @SysGetMouseEvent;
  226. PollMouseEvent : @SysPollMouseEvent;
  227. PutMouseEvent : @SysPutMouseEvent;
  228. );
  229. begin
  230. SetMouseDriver(SysMouseDriver);
  231. end.