mouse.pp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Florian Klaempfl
  5. member of the Free Pascal development team
  6. Mouse unit for linux
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit Mouse;
  14. interface
  15. const
  16. MouseEventBufSize = 16;
  17. {$i mouseh.inc}
  18. implementation
  19. uses
  20. Video,
  21. MouCalls, DosCalls;
  22. var
  23. PendingMouseEventOrder: array [0..MouseEventBufSize-1] of cardinal;
  24. MouseEventOrderHead, MouseEventOrderTail: cardinal;
  25. const
  26. NoMouse = $FFFF;
  27. DefaultMouse = 0;
  28. Handle: word = DefaultMouse;
  29. HideCounter: cardinal = 0;
  30. OldEventMask: longint = -1;
  31. procedure InitMouse;
  32. var
  33. Loc: TPtrLoc;
  34. SetPrev: boolean;
  35. SysEvent: TMouEventInfo;
  36. QI: TMouQueInfo;
  37. W: word;
  38. begin
  39. SetPrev := MouGetPtrPos (Loc, DefaultMouse) = 0;
  40. if MouGetEventMask (W, DefaultMouse) = 0 then OldEventMask := W;
  41. PendingMouseHead := @PendingMouseEvent;
  42. PendingMouseTail := @PendingMouseEvent;
  43. PendingMouseEvents := 0;
  44. FillChar (LastMouseEvent, SizeOf (TMouseEvent), 0);
  45. MouseEventOrderTail := 0;
  46. MouseEventOrderHead := 0;
  47. HideCounter := 0;
  48. if MouOpen (nil, Handle) = Error_Mouse_No_Device then Handle := NoMouse else
  49. begin
  50. W := Mou_NoWait;
  51. repeat
  52. MouGetNumQueEl (QI, Handle);
  53. if QI.cEvents <> 0 then MouReadEventQue (SysEvent, W, Handle);
  54. until QI.cEvents = 0;
  55. W := $FFFF;
  56. MouSetEventMask (W, Handle);
  57. if SetPrev then MouSetPtrPos (Loc, Handle);
  58. (*
  59. It would be possible to issue a MouRegister call here to hook our own mouse
  60. handler, but such handler would have to be in a DLL and it is questionable,
  61. whether there would be so many advantages in doing so.
  62. *)
  63. MouDrawPtr (Handle);
  64. end;
  65. end;
  66. procedure DoneMouse;
  67. var
  68. W: word;
  69. begin
  70. if (Handle <> NoMouse) and (Handle <> DefaultMouse) then
  71. begin
  72. (*
  73. If our own mouse handler would be installed in InitMouse, MouDeregister would
  74. have appeared here.
  75. *)
  76. HideCounter := 0;
  77. HideMouse;
  78. MouClose (Handle);
  79. end;
  80. if OldEventMask <> -1 then
  81. begin
  82. W := OldEventMask;
  83. MouSetEventMask (W, 0);
  84. end;
  85. end;
  86. function DetectMouse:byte;
  87. var
  88. Buttons: word;
  89. RC: longint;
  90. TempHandle: word;
  91. begin
  92. MouOpen (nil, TempHandle);
  93. if MouGetNumButtons (Buttons, TempHandle) = 0 then DetectMouse := Buttons
  94. else DetectMouse := 0;
  95. MouClose (TempHandle);
  96. end;
  97. procedure ShowMouse;
  98. begin
  99. if Handle <> NoMouse then
  100. begin
  101. if HideCounter <> 0 then
  102. begin
  103. Dec (HideCounter);
  104. if HideCounter = 0 then MouDrawPtr (Handle);
  105. end;
  106. end;
  107. end;
  108. procedure HideMouse;
  109. var
  110. PtrRect: TNoPtrRect;
  111. begin
  112. if Handle <> NoMouse then
  113. begin
  114. Inc (HideCounter);
  115. case HideCounter of
  116. 0: Dec (HideCounter); (* HideCounter overflowed - stay at the maximum *)
  117. 1: begin
  118. PtrRect.Row := 0;
  119. PtrRect.Col := 0;
  120. PtrRect.cRow := Pred (ScreenHeight);
  121. PtrRect.cCol := Pred (ScreenWidth);
  122. MouRemovePtr (PtrRect, Handle);
  123. end;
  124. end;
  125. end;
  126. end;
  127. function GetMouseX: word;
  128. var
  129. Event: TMouseEvent;
  130. begin
  131. if Handle = NoMouse then GetMouseX := 0 else
  132. begin
  133. PollMouseEvent (Event);
  134. GetMouseX := Event.X;
  135. end;
  136. end;
  137. function GetMouseY: word;
  138. var
  139. Event: TMouseEvent;
  140. begin
  141. if Handle = NoMouse then GetMouseY := 0 else
  142. begin
  143. PollMouseEvent (Event);
  144. GetMouseY := Event.Y;
  145. end;
  146. end;
  147. procedure GetMouseXY (var X: word; var Y: word);
  148. var
  149. Loc: TPtrLoc;
  150. begin
  151. if Handle = NoMouse then
  152. begin
  153. X := 0;
  154. Y := 0;
  155. end else if MouGetPtrPos (Loc, Handle) <> 0 then
  156. begin
  157. X := $FFFF;
  158. Y := $FFFF;
  159. end else
  160. begin
  161. X := Loc.Col;
  162. Y := Loc.Row;
  163. end;
  164. end;
  165. procedure SetMouseXY (X, Y: word);
  166. var
  167. Loc: TPtrLoc;
  168. begin
  169. if Handle <> NoMouse then
  170. begin
  171. Loc.Row := Y;
  172. Loc.Col := X;
  173. MouSetPtrPos (Loc, Handle);
  174. end;
  175. end;
  176. procedure TranslateEvents (const SysEvent: TMouEventInfo;
  177. var Event: TMouseEvent);
  178. begin
  179. Event.Buttons := 0;
  180. Event.Action := 0;
  181. if SysEvent.fs and (Mouse_Motion_With_BN1_Down or Mouse_BN1_Down) <> 0 then
  182. Event.Buttons := Event.Buttons or MouseLeftButton;
  183. if SysEvent.fs and (Mouse_Motion_With_BN2_Down or Mouse_BN2_Down) <> 0 then
  184. Event.Buttons := Event.Buttons or MouseRightButton;
  185. if SysEvent.fs and (Mouse_Motion_With_BN3_Down or Mouse_BN3_Down) <> 0 then
  186. Event.Buttons := Event.Buttons or MouseMiddleButton;
  187. Event.X := SysEvent.Col;
  188. Event.Y := SysEvent.Row;
  189. if Event.Buttons <> LastMouseEvent.Buttons then
  190. if (Event.Buttons and MouseLeftButton = 0) and
  191. (LastMouseEvent.Buttons and MouseLeftButton = MouseLeftButton)
  192. then Event.Action := MouseActionUp else
  193. if (Event.Buttons and MouseRightButton = 0) and
  194. (LastMouseEvent.Buttons and MouseRightButton = MouseRightButton)
  195. then Event.Action := MouseActionUp else
  196. if (Event.Buttons and MouseMiddleButton = 0) and
  197. (LastMouseEvent.Buttons and MouseMiddleButton = MouseMiddleButton)
  198. then Event.Action := MouseActionUp
  199. else Event.Action := MouseActionDown
  200. else if (Event.X <> LastMouseEvent.X) or (Event.Y <> LastMouseEvent.Y)
  201. then Event.Action := MouseActionMove;
  202. LastMouseEvent := Event;
  203. end;
  204. procedure NullOrder;
  205. var
  206. I: cardinal;
  207. begin
  208. if PendingMouseEvents > 0 then
  209. begin
  210. I := MouseEventOrderHead;
  211. repeat
  212. PendingMouseEventOrder [I] := 0;
  213. if I = Pred (MouseEventBufSize) then I := 0 else Inc (I);
  214. until (I <> MouseEventOrderTail);
  215. end;
  216. end;
  217. procedure LowerOrder;
  218. var
  219. I: cardinal;
  220. begin
  221. if PendingMouseEvents > 0 then
  222. begin
  223. I := MouseEventOrderHead;
  224. repeat
  225. if PendingMouseEventOrder [I] <> 0 then
  226. begin
  227. Dec (PendingMouseEventOrder [I]);
  228. if I = Pred (MouseEventBufSize) then I := 0 else Inc (I);
  229. end;
  230. until (I <> MouseEventOrderTail) or (PendingMouseEventOrder [I] = 0);
  231. end;
  232. end;
  233. function PollMouseEvent (var MouseEvent: TMouseEvent) :boolean;
  234. var
  235. SysEvent: TMouEventInfo;
  236. P, Q: PMouseEvent;
  237. Event: TMouseEvent;
  238. WF: word;
  239. QI: TMouQueInfo;
  240. begin
  241. if (PendingMouseEvents = 0) or
  242. (PendingMouseEventOrder [MouseEventOrderHead] <> 0) and
  243. (PendingMouseEvents < MouseEventBufSize) then
  244. begin
  245. MouGetNumQueEl (QI, Handle);
  246. if QI.cEvents = 0 then NullOrder else
  247. begin
  248. LowerOrder;
  249. WF := Mou_NoWait;
  250. if (MouReadEventQue (SysEvent, WF, Handle) = 0) then
  251. begin
  252. if PendingMouseHead = @PendingMouseEvent then
  253. P := @PendingMouseEvent [MouseEventBufSize - 1] else
  254. begin
  255. P := PendingMouseHead;
  256. Dec (P);
  257. end;
  258. TranslateEvents (SysEvent, P^);
  259. if P^.Action <> 0 then
  260. begin
  261. if PendingMouseEvents < MouseEventBufSize then
  262. begin
  263. Q := P;
  264. WF := Mou_NoWait;
  265. while (P^.Action = MouseActionMove) and
  266. (PendingMouseEventOrder [MouseEventOrderHead] <> 0) and
  267. (MouReadEventQue (SysEvent, WF, Handle) = 0) and
  268. ((SysEvent.fs <> 0) or (LastMouseEvent.Buttons <> 0)) do
  269. begin
  270. LowerOrder;
  271. TranslateEvents (SysEvent, Event);
  272. if Event.Action <> MouseActionMove then
  273. begin
  274. if Q = @PendingMouseEvent then
  275. Q := @PendingMouseEvent [MouseEventBufSize - 1] else Dec (Q);
  276. if MouseEventOrderHead = 0 then
  277. MouseEventOrderHead := MouseEventBufSize - 1 else
  278. Dec (MouseEventOrderHead);
  279. PendingMouseEventOrder [MouseEventOrderHead] := 0;
  280. Q^ := P^;
  281. Inc (PendingMouseEvents);
  282. if MouseEventOrderHead = 0 then
  283. MouseEventOrderHead := MouseEventBufSize - 1 else
  284. Dec (MouseEventOrderHead);
  285. PendingMouseEventOrder [MouseEventOrderHead] := 0;
  286. end else WF := Mou_NoWait;
  287. P^ := Event;
  288. end;
  289. P := Q;
  290. end;
  291. Inc (PendingMouseEvents);
  292. if MouseEventOrderHead = 0 then
  293. MouseEventOrderHead := MouseEventBufSize - 1 else
  294. Dec (MouseEventOrderHead);
  295. PendingMouseEventOrder [MouseEventOrderHead] := 0;
  296. PendingMouseHead := P;
  297. end;
  298. end else NullOrder;
  299. end;
  300. end;
  301. if PendingMouseEvents <> 0 then
  302. begin
  303. MouseEvent := PendingMouseHead^;
  304. LastMouseEvent := MouseEvent;
  305. PollMouseEvent := true;
  306. end else
  307. begin
  308. PollMouseEvent := false;
  309. MouseEvent := LastMouseEvent;
  310. MouseEvent.Action := 0;
  311. end;
  312. end;
  313. function GetMouseButtons: word;
  314. var
  315. Event: TMouseEvent;
  316. begin
  317. PollMouseEvent (Event);
  318. GetMouseButtons := Event.Buttons;
  319. end;
  320. procedure GetMouseEvent (var MouseEvent: TMouseEvent);
  321. var
  322. Event: TMouEventInfo;
  323. begin
  324. if (PendingMouseEvents = 0) or
  325. (PendingMouseEventOrder [MouseEventOrderHead] <> 0) then
  326. repeat
  327. DosSleep (1);
  328. PollMouseEvent (MouseEvent);
  329. until (PendingMouseEvents <> 0) and
  330. (PendingMouseEventOrder [MouseEventOrderHead] = 0) else
  331. begin
  332. MouseEvent := PendingMouseHead^;
  333. LastMouseEvent := MouseEvent;
  334. end;
  335. Inc (PendingMouseHead);
  336. if longint (PendingMouseHead) = longint (@PendingMouseEvent)
  337. + SizeOf (PendingMouseEvent) then PendingMouseHead := @PendingMouseEvent;
  338. Inc (MouseEventOrderHead);
  339. if MouseEventOrderHead = MouseEventBufSize then MouseEventOrderHead := 0;
  340. Dec (PendingMouseEvents);
  341. end;
  342. procedure PutMouseEvent (const MouseEvent: TMouseEvent);
  343. var
  344. QI: TMouQueInfo;
  345. begin
  346. if PendingMouseEvents < MouseEventBufSize then
  347. begin
  348. PendingMouseTail^ := MouseEvent;
  349. Inc (PendingMouseTail);
  350. if longint (PendingMouseTail) = longint (@PendingMouseEvent) +
  351. SizeOf (PendingMouseEvent) then PendingMouseTail := @PendingMouseEvent;
  352. MouGetNumQueEl (QI, Handle);
  353. PendingMouseEventOrder [MouseEventOrderTail] := QI.cEvents;
  354. Inc (MouseEventOrderTail);
  355. if MouseEventOrderTail = MouseEventBufSize then MouseEventOrderTail := 0;
  356. Inc (PendingMouseEvents);
  357. end;
  358. end;
  359. end.
  360. {
  361. $Log$
  362. Revision 1.1 2001-01-13 11:03:58 peter
  363. * API 2 RTL commit
  364. }