mouse.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  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. {$ifdef NOMOUSE}
  15. {$DEFINE NOGPM}
  16. {$ENDIF}
  17. {$i mouseh.inc}
  18. implementation
  19. uses
  20. BaseUnix,Video
  21. {$ifndef NOGPM}
  22. ,gpm,linuxvcs
  23. {$endif ndef NOGPM}
  24. ;
  25. {$i mouse.inc}
  26. {$ifndef NOMOUSE}
  27. const
  28. WaitMouseMove : boolean = false;
  29. PrintMouseCur : boolean = false;
  30. mousecurofs : longint = -1;
  31. var
  32. mousecurcell : TVideoCell;
  33. SysLastMouseEvent : TMouseEvent;
  34. const
  35. gpm_fs : longint = -1;
  36. {$ifndef NOGPM}
  37. procedure GPMEvent2MouseEvent(const e:Tgpm_event;var mouseevent:tmouseevent);
  38. var
  39. PrevButtons : byte;
  40. begin
  41. PrevButtons:=SysLastMouseEvent.Buttons;
  42. if e.x>0 then
  43. mouseevent.x:=e.x-1
  44. else
  45. MouseEvent.x:=0;
  46. if e.y>0 then
  47. MouseEvent.y:=e.y-1
  48. else
  49. MouseEvent.y:=0;
  50. MouseEvent.buttons:=0;
  51. if e.buttons and Gpm_b_left<>0 then
  52. inc(MouseEvent.buttons,1);
  53. if e.buttons and Gpm_b_right<>0 then
  54. inc(MouseEvent.buttons,2);
  55. if e.buttons and Gpm_b_middle<>0 then
  56. inc(MouseEvent.buttons,4);
  57. case (e.EventType and $f) of
  58. GPM_MOVE,
  59. GPM_DRAG :
  60. begin
  61. MouseEvent.Action:=MouseActionMove;
  62. WaitMouseMove:=false;
  63. end;
  64. GPM_DOWN :
  65. begin
  66. MouseEvent.Action:=MouseActionDown;
  67. WaitMouseMove:=false;
  68. end;
  69. GPM_UP :
  70. begin
  71. { gpm apparently sends the button that is left up
  72. while mouse unit expects the button state after
  73. the button was released PM }
  74. if MouseEvent.Buttons<>0 then
  75. begin
  76. MouseEvent.Buttons:=MouseEvent.Buttons xor PrevButtons;
  77. MouseEvent.Action:=MouseActionUp;
  78. end
  79. { this does probably never happen...
  80. but its just a security PM }
  81. else
  82. MouseEvent.Action:=MouseActionMove;
  83. WaitMouseMove:=false;
  84. end;
  85. else
  86. MouseEvent.Action:=MouseActionMove;
  87. end;
  88. end;
  89. {$ENDIF}
  90. procedure PlaceMouseCur(ofs:longint);
  91. var
  92. upd : boolean;
  93. begin
  94. if (VideoBuf=nil) or (MouseCurOfs=Ofs) then
  95. exit;
  96. upd:=false;
  97. if (MouseCurOfs<>-1) and (VideoBuf^[MouseCurOfs]=MouseCurCell) then
  98. begin
  99. VideoBuf^[MouseCurOfs]:=MouseCurCell xor $7f00;
  100. upd:=true;
  101. end;
  102. MouseCurOfs:=ofs;
  103. if (MouseCurOfs<>-1) then
  104. begin
  105. MouseCurCell:=VideoBuf^[MouseCurOfs] xor $7f00;
  106. VideoBuf^[MouseCurOfs]:=MouseCurCell;
  107. upd:=true;
  108. end;
  109. if upd then
  110. Updatescreen(false);
  111. end;
  112. {Note: libgpm will initialize an xterm mouse if TERM=xterm.
  113. However, this check sucks, because xterm is not the only terminal
  114. with mouse. To make it worse, it assumes gpm should be used on
  115. anything not xterm, while in reality only the Linux console has gpm.
  116. Some distributions use a patched libgpm to work around this, but
  117. to avoid this mess, we detect the xterm mouse ourselves (we need to
  118. be able to do this anyway for the NOGPM case), and don't do any libgpm
  119. call at all if an xterm mouse is detected.}
  120. function detect_xterm_mouse:word;
  121. const mouse_terminals:array[0..6] of string[7]=('cons','eterm','gnome',
  122. 'konsole','rxvt','screen',
  123. 'xterm');
  124. xterm=6;
  125. mouse_1003_capable=[xterm]; {xterm only for now}
  126. var term,colorterm:string;
  127. i,t:shortint;
  128. begin
  129. detect_xterm_mouse:=0;
  130. t:=-1;
  131. term:=fpgetenv('TERM');
  132. for i:=low(mouse_terminals) to high(mouse_terminals) do
  133. if copy(term,1,length(mouse_terminals[i]))=mouse_terminals[i] then
  134. begin
  135. t:=i;
  136. break;
  137. end;
  138. if t=xterm then
  139. begin
  140. {Rxvt sets TERM=xterm and COLORTERM=rxvt. Gnome does something similar.}
  141. term:=fpgetenv('COLORTERM');
  142. for i:=low(mouse_terminals) to high(mouse_terminals) do
  143. if copy(term,1,length(mouse_terminals[i]))=mouse_terminals[i] then
  144. begin
  145. t:=i;
  146. break;
  147. end;
  148. end;
  149. if t>0 then
  150. begin
  151. detect_xterm_mouse:=1000;
  152. {Can the terminal report all mouse events?}
  153. if t in mouse_1003_capable then
  154. detect_xterm_mouse:=1003;
  155. end;
  156. end;
  157. procedure SysInitMouse;
  158. {$ifndef NOGPM}
  159. var connect:TGPMConnect;
  160. e:Tgpm_event;
  161. {$endif ndef NOGPM}
  162. begin
  163. { if gpm_fs<>-1 then
  164. runerror(240);}
  165. {Test wether to use X-terminals.}
  166. case detect_xterm_mouse of
  167. 1000:
  168. begin
  169. {Use the xterm mouse, report button events only.}
  170. gpm_fs:=-1000;
  171. {write(#27'[?1001s');} { save old hilit tracking }
  172. write(#27'[?1000h'); { enable mouse tracking }
  173. end;
  174. 1003:
  175. begin
  176. {Use the xterm mouse, report all mouse events.}
  177. gpm_fs:=-1003;
  178. write(#27'[?1003h'); { enable mouse tracking }
  179. end;
  180. end;
  181. {$ifndef NOGPM}
  182. {Use the gpm mouse?}
  183. if (gpm_fs=-1) and (vcs_device<>-1) then
  184. begin
  185. { open gpm }
  186. connect.EventMask:=GPM_MOVE or GPM_DRAG or GPM_DOWN or GPM_UP;
  187. connect.DefaultMask:=0;
  188. connect.MinMod:=0;
  189. connect.MaxMod:=0;
  190. gpm_fs:=gpm_open(connect,0);
  191. { initialize SysLastMouseEvent }
  192. if gpm_fs<>-1 then
  193. begin
  194. Gpm_GetSnapshot(e);
  195. GPMEvent2MouseEvent(e,SysLastMouseEvent);
  196. end;
  197. end;
  198. {$endif NOGPM}
  199. end;
  200. procedure SysDoneMouse;
  201. begin
  202. case gpm_fs of
  203. -1:
  204. HideMouse;
  205. -1000:
  206. begin
  207. {xterm mouse}
  208. write(#27'[?1000l'); { disable mouse tracking }
  209. {write(#27'[?1001r');} { Restore old hilit tracking }
  210. end;
  211. -1003:
  212. write(#27'[?1003l'); { disable mouse tracking }
  213. {$ifndef NOGPM}
  214. else
  215. gpm_close;
  216. {$endif};
  217. end;
  218. gpm_fs:=-1;
  219. end;
  220. function SysDetectMouse:byte;
  221. {$ifndef NOGPM}
  222. var
  223. connect : TGPMConnect;
  224. fds : tFDSet;
  225. e : Tgpm_event;
  226. {$endif ndef NOGPM}
  227. begin
  228. if detect_xterm_mouse<>0 then
  229. SysDetectMouse:=2
  230. {$ifndef NOGPM}
  231. else
  232. begin
  233. if gpm_fs=-1 then
  234. begin
  235. connect.EventMask:=GPM_MOVE or GPM_DRAG or GPM_DOWN or GPM_UP;
  236. connect.DefaultMask:=0;
  237. connect.MinMod:=0;
  238. connect.MaxMod:=0;
  239. gpm_fs:=gpm_open(connect,0);
  240. end;
  241. if gpm_fs>=0 then
  242. begin
  243. fpFD_ZERO(fds);
  244. fpFD_SET(gpm_fs,fds);
  245. while fpSelect(gpm_fs+1,@fds,nil,nil,1)>0 do
  246. begin
  247. fillchar(e,sizeof(e),#0);
  248. Gpm_GetEvent(e);
  249. end;
  250. end;
  251. if gpm_fs<>-1 then
  252. SysDetectMouse:=Gpm_GetSnapshot(nil)
  253. else
  254. SysDetectMouse:=0;
  255. end
  256. {$endif NOGPM};
  257. end;
  258. procedure SysGetMouseEvent(var MouseEvent: TMouseEvent);
  259. {$ifndef NOGPM}
  260. var
  261. e : Tgpm_event;
  262. {$endif ndef NOGPM}
  263. begin
  264. fillchar(MouseEvent,SizeOf(TMouseEvent),#0);
  265. if gpm_fs<0 then
  266. exit;
  267. {$ifndef NOGPM}
  268. Gpm_GetEvent(e);
  269. GPMEvent2MouseEvent(e,MouseEvent);
  270. SysLastMouseEvent:=MouseEvent;
  271. { update mouse cursor }
  272. if PrintMouseCur then
  273. PlaceMouseCur(MouseEvent.y*ScreenWidth+MouseEvent.x);
  274. {$endif ndef NOGPM}
  275. end;
  276. function SysPollMouseEvent(var MouseEvent: TMouseEvent):boolean;
  277. {$ifndef NOGPM}
  278. var
  279. e : Tgpm_event;
  280. fds : tFDSet;
  281. {$endif ndef NOGPM}
  282. begin
  283. fillchar(MouseEvent,SizeOf(TMouseEvent),#0);
  284. {$ifndef NOGPM}
  285. if gpm_fs<0 then
  286. exit(false);
  287. if gpm_fs>0 then
  288. begin
  289. fpFD_ZERO(fds);
  290. fpFD_SET(gpm_fs,fds);
  291. end;
  292. if (fpSelect(gpm_fs+1,@fds,nil,nil,1)>0) then
  293. begin
  294. FillChar(e,SizeOf(e),#0);
  295. { Gpm_snapshot does not work here PM }
  296. Gpm_GetEvent(e);
  297. GPMEvent2MouseEvent(e,MouseEvent);
  298. SysLastMouseEvent:=MouseEvent;
  299. if (MouseEvent.Action<>0) then
  300. begin
  301. { As we now use Gpm_GetEvent, we need to put in
  302. in the MouseEvent queue PM }
  303. PutMouseEvent(MouseEvent);
  304. SysPollMouseEvent:=true;
  305. { update mouse cursor is also required here
  306. as next call will read MouseEvent from queue }
  307. if PrintMouseCur then
  308. PlaceMouseCur(MouseEvent.y*ScreenWidth+MouseEvent.x);
  309. end
  310. else
  311. SysPollMouseEvent:=false;
  312. end
  313. else
  314. {$endif NOGPM}
  315. SysPollMouseEvent:=false;
  316. end;
  317. function SysGetMouseX:word;
  318. {$ifndef NOGPM}
  319. var
  320. me : TMouseEvent;
  321. {$endif ndef NOGPM}
  322. begin
  323. if gpm_fs<0 then
  324. exit(0);
  325. {$ifndef NOGPM}
  326. if PollMouseEvent(ME) then
  327. begin
  328. { Remove mouse event, we are only interrested in
  329. the X,Y so all other events can be thrown away }
  330. GetMouseEvent(ME);
  331. SysGetMouseX:=ME.X
  332. end
  333. else
  334. begin
  335. SysGetMouseX:=SysLastMouseEvent.x;
  336. end;
  337. {$endif ndef NOGPM}
  338. end;
  339. function SysGetMouseY:word;
  340. {$ifndef NOGPM}
  341. var
  342. me : TMouseEvent;
  343. {$endif ndef NOGPM}
  344. begin
  345. if gpm_fs<0 then
  346. exit(0);
  347. {$ifndef NOGPM}
  348. if PollMouseEvent(ME) then
  349. begin
  350. { Remove mouse event, we are only interrested in
  351. the X,Y so all other events can be thrown away }
  352. GetMouseEvent(ME);
  353. SysGetMouseY:=ME.Y
  354. end
  355. else
  356. begin
  357. SysGetMouseY:=SysLastMouseEvent.y;
  358. end;
  359. {$endif ndef NOGPM}
  360. end;
  361. procedure SysShowMouse;
  362. var
  363. x,y : word;
  364. begin
  365. PrintMouseCur:=true;
  366. { Wait with showing the cursor until the mouse has moved. Else the
  367. cursor updates will be to quickly }
  368. if WaitMouseMove then
  369. exit;
  370. if (MouseCurOfs>=0) or (gpm_fs=-1) then
  371. PlaceMouseCur(MouseCurOfs)
  372. else
  373. begin
  374. x:=SysGetMouseX;
  375. y:=SysGetMouseY;
  376. if (x<=ScreenWidth) and (y<=ScreenHeight) then
  377. PlaceMouseCur(Y*ScreenWidth+X)
  378. else
  379. PlaceMouseCur(MouseCurOfs);
  380. end;
  381. end;
  382. procedure SysHideMouse;
  383. begin
  384. if (MouseCurOfs>=0) then
  385. PlaceMouseCur(-1);
  386. WaitMouseMove:=true;
  387. PrintMouseCur:=false;
  388. end;
  389. function SysGetMouseButtons:word;
  390. {$ifndef NOGPM}
  391. var
  392. me : TMouseEvent;
  393. {$endif ndef NOGPM}
  394. begin
  395. if gpm_fs<0 then
  396. exit(0);
  397. {$ifndef NOGPM}
  398. if PollMouseEvent(ME) then
  399. begin
  400. { Remove mouse event, we are only interrested in
  401. the buttons so all other events can be thrown away }
  402. GetMouseEvent(ME);
  403. SysGetMouseButtons:=ME.Buttons;
  404. end
  405. else
  406. begin
  407. SysGetMouseButtons:=SysLastMouseEvent.buttons;
  408. end;
  409. {$endif ndef NOGPM}
  410. end;
  411. Const
  412. SysMouseDriver : TMouseDriver = (
  413. UseDefaultQueue : true;
  414. InitDriver : @SysInitMouse;
  415. DoneDriver : @SysDoneMouse;
  416. DetectMouse : @SysDetectMouse;
  417. ShowMouse : @SysShowMouse;
  418. HideMouse : @SysHideMouse;
  419. GetMouseX : @SysGetMouseX;
  420. GetMouseY : @SysGetMouseY;
  421. GetMouseButtons : @SysGetMouseButtons;
  422. SetMouseXY : Nil;
  423. GetMouseEvent : @SysGetMouseEvent;
  424. PollMouseEvent : @SysPollMouseEvent;
  425. PutMouseEvent : Nil;
  426. );
  427. {$else ifndef NOMOUSE}
  428. Const
  429. SysMouseDriver : TMouseDriver = (
  430. UseDefaultQueue : true;
  431. InitDriver : Nil;
  432. DoneDriver : Nil;
  433. DetectMouse : Nil;
  434. ShowMouse : Nil;
  435. HideMouse : Nil;
  436. GetMouseX : Nil;
  437. GetMouseY : Nil;
  438. GetMouseButtons : Nil;
  439. SetMouseXY : Nil;
  440. GetMouseEvent : Nil;
  441. PollMouseEvent : Nil;
  442. PutMouseEvent : Nil;
  443. );
  444. {$endif}
  445. Begin
  446. SetMouseDriver(SysMouseDriver);
  447. end.