mouse.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  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. Of course, we use the
  120. Pascal libgpm translation, doing it here allows us to keep the Pascal
  121. one compatible with the external C one.
  122. }
  123. function detect_xterm_mouse:word;
  124. const mouse_terminals:array[0..6] of string[7]=('cons','eterm','gnome',
  125. 'konsole','rxvt','screen',
  126. 'xterm');
  127. xterm=6;
  128. mouse_1003_capable=[xterm]; {xterm only for now}
  129. var term,colorterm:string;
  130. i,t:shortint;
  131. begin
  132. detect_xterm_mouse:=0;
  133. t:=-1;
  134. term:=fpgetenv('TERM');
  135. for i:=low(mouse_terminals) to high(mouse_terminals) do
  136. if copy(term,1,length(mouse_terminals[i]))=mouse_terminals[i] then
  137. begin
  138. t:=i;
  139. break;
  140. end;
  141. if t=xterm then
  142. begin
  143. {Rxvt sets TERM=xterm and COLORTERM=rxvt. Gnome does something similar.}
  144. term:=fpgetenv('COLORTERM');
  145. for i:=low(mouse_terminals) to high(mouse_terminals) do
  146. if copy(term,1,length(mouse_terminals[i]))=mouse_terminals[i] then
  147. begin
  148. t:=i;
  149. break;
  150. end;
  151. end;
  152. if t>0 then
  153. begin
  154. detect_xterm_mouse:=1000;
  155. {Can the terminal report all mouse events?}
  156. if t in mouse_1003_capable then
  157. detect_xterm_mouse:=1003;
  158. end;
  159. end;
  160. procedure SysInitMouse;
  161. {$ifndef NOGPM}
  162. var connect:TGPMConnect;
  163. e:Tgpm_event;
  164. {$endif ndef NOGPM}
  165. begin
  166. { if gpm_fs<>-1 then
  167. runerror(240);}
  168. {Test wether to use X-terminals.}
  169. case detect_xterm_mouse of
  170. 1000:
  171. begin
  172. {Use the xterm mouse, report button events only.}
  173. gpm_fs:=-1000;
  174. {write(#27'[?1001s');} { save old hilit tracking }
  175. write(#27'[?1000h'); { enable mouse tracking }
  176. end;
  177. 1003:
  178. begin
  179. {Use the xterm mouse, report all mouse events.}
  180. gpm_fs:=-1003;
  181. write(#27'[?1003h'); { enable mouse tracking }
  182. end;
  183. end;
  184. {$ifndef NOGPM}
  185. {Use the gpm mouse?}
  186. if (gpm_fs=-1) and (vcs_device<>-1) then
  187. begin
  188. { open gpm }
  189. connect.EventMask:=GPM_MOVE or GPM_DRAG or GPM_DOWN or GPM_UP;
  190. connect.DefaultMask:=0;
  191. connect.MinMod:=0;
  192. connect.MaxMod:=0;
  193. gpm_fs:=gpm_open(connect,0);
  194. { initialize SysLastMouseEvent }
  195. if gpm_fs<>-1 then
  196. begin
  197. Gpm_GetSnapshot(e);
  198. GPMEvent2MouseEvent(e,SysLastMouseEvent);
  199. end;
  200. end;
  201. {$endif NOGPM}
  202. end;
  203. procedure SysDoneMouse;
  204. begin
  205. case gpm_fs of
  206. -1:
  207. HideMouse;
  208. -1000:
  209. begin
  210. {xterm mouse}
  211. write(#27'[?1000l'); { disable mouse tracking }
  212. {write(#27'[?1001r');} { Restore old hilit tracking }
  213. end;
  214. -1003:
  215. write(#27'[?1003l'); { disable mouse tracking }
  216. {$ifndef NOGPM}
  217. else
  218. gpm_close;
  219. {$endif}
  220. end;
  221. gpm_fs:=-1;
  222. end;
  223. function SysDetectMouse:byte;
  224. {$ifndef NOGPM}
  225. var
  226. connect : TGPMConnect;
  227. fds : tFDSet;
  228. e : Tgpm_event;
  229. {$endif ndef NOGPM}
  230. begin
  231. if detect_xterm_mouse<>0 then
  232. SysDetectMouse:=2
  233. {$ifndef NOGPM}
  234. else
  235. begin
  236. if gpm_fs=-1 then
  237. begin
  238. connect.EventMask:=GPM_MOVE or GPM_DRAG or GPM_DOWN or GPM_UP;
  239. connect.DefaultMask:=0;
  240. connect.MinMod:=0;
  241. connect.MaxMod:=0;
  242. gpm_fs:=gpm_open(connect,0);
  243. end;
  244. if gpm_fs>=0 then
  245. begin
  246. fpFD_ZERO(fds);
  247. fpFD_SET(gpm_fs,fds);
  248. while fpSelect(gpm_fs+1,@fds,nil,nil,1)>0 do
  249. begin
  250. fillchar(e,sizeof(e),#0);
  251. Gpm_GetEvent(e);
  252. end;
  253. end;
  254. if gpm_fs<>-1 then
  255. SysDetectMouse:=Gpm_GetSnapshot(nil)
  256. else
  257. SysDetectMouse:=0;
  258. end
  259. {$endif NOGPM};
  260. end;
  261. procedure SysGetMouseEvent(var MouseEvent: TMouseEvent);
  262. {$ifndef NOGPM}
  263. var
  264. e : Tgpm_event;
  265. {$endif ndef NOGPM}
  266. begin
  267. fillchar(MouseEvent,SizeOf(TMouseEvent),#0);
  268. if gpm_fs<0 then
  269. exit;
  270. {$ifndef NOGPM}
  271. Gpm_GetEvent(e);
  272. GPMEvent2MouseEvent(e,MouseEvent);
  273. SysLastMouseEvent:=MouseEvent;
  274. { update mouse cursor }
  275. if PrintMouseCur then
  276. PlaceMouseCur(MouseEvent.y*ScreenWidth+MouseEvent.x);
  277. {$endif ndef NOGPM}
  278. end;
  279. function SysPollMouseEvent(var MouseEvent: TMouseEvent):boolean;
  280. {$ifndef NOGPM}
  281. var
  282. e : Tgpm_event;
  283. fds : tFDSet;
  284. {$endif ndef NOGPM}
  285. begin
  286. fillchar(MouseEvent,SizeOf(TMouseEvent),#0);
  287. {$ifndef NOGPM}
  288. if gpm_fs<0 then
  289. exit(false);
  290. if gpm_fs>0 then
  291. begin
  292. fpFD_ZERO(fds);
  293. fpFD_SET(gpm_fs,fds);
  294. end;
  295. if (fpSelect(gpm_fs+1,@fds,nil,nil,1)>0) then
  296. begin
  297. FillChar(e,SizeOf(e),#0);
  298. { Gpm_snapshot does not work here PM }
  299. Gpm_GetEvent(e);
  300. GPMEvent2MouseEvent(e,MouseEvent);
  301. SysLastMouseEvent:=MouseEvent;
  302. if (MouseEvent.Action<>0) then
  303. begin
  304. { As we now use Gpm_GetEvent, we need to put in
  305. in the MouseEvent queue PM }
  306. PutMouseEvent(MouseEvent);
  307. SysPollMouseEvent:=true;
  308. { update mouse cursor is also required here
  309. as next call will read MouseEvent from queue }
  310. if PrintMouseCur then
  311. PlaceMouseCur(MouseEvent.y*ScreenWidth+MouseEvent.x);
  312. end
  313. else
  314. SysPollMouseEvent:=false;
  315. end
  316. else
  317. {$endif NOGPM}
  318. SysPollMouseEvent:=false;
  319. end;
  320. function SysGetMouseX:word;
  321. {$ifndef NOGPM}
  322. var
  323. me : TMouseEvent;
  324. {$endif ndef NOGPM}
  325. begin
  326. if gpm_fs<0 then
  327. exit(0);
  328. {$ifndef NOGPM}
  329. if PollMouseEvent(ME) then
  330. begin
  331. { Remove mouse event, we are only interrested in
  332. the X,Y so all other events can be thrown away }
  333. GetMouseEvent(ME);
  334. SysGetMouseX:=ME.X
  335. end
  336. else
  337. begin
  338. SysGetMouseX:=SysLastMouseEvent.x;
  339. end;
  340. {$endif ndef NOGPM}
  341. end;
  342. function SysGetMouseY:word;
  343. {$ifndef NOGPM}
  344. var
  345. me : TMouseEvent;
  346. {$endif ndef NOGPM}
  347. begin
  348. if gpm_fs<0 then
  349. exit(0);
  350. {$ifndef NOGPM}
  351. if PollMouseEvent(ME) then
  352. begin
  353. { Remove mouse event, we are only interrested in
  354. the X,Y so all other events can be thrown away }
  355. GetMouseEvent(ME);
  356. SysGetMouseY:=ME.Y
  357. end
  358. else
  359. begin
  360. SysGetMouseY:=SysLastMouseEvent.y;
  361. end;
  362. {$endif ndef NOGPM}
  363. end;
  364. procedure SysShowMouse;
  365. var
  366. x,y : word;
  367. begin
  368. PrintMouseCur:=true;
  369. { Wait with showing the cursor until the mouse has moved. Else the
  370. cursor updates will be to quickly }
  371. if WaitMouseMove then
  372. exit;
  373. if (MouseCurOfs>=0) or (gpm_fs=-1) then
  374. PlaceMouseCur(MouseCurOfs)
  375. else
  376. begin
  377. x:=SysGetMouseX;
  378. y:=SysGetMouseY;
  379. if (x<=ScreenWidth) and (y<=ScreenHeight) then
  380. PlaceMouseCur(Y*ScreenWidth+X)
  381. else
  382. PlaceMouseCur(MouseCurOfs);
  383. end;
  384. end;
  385. procedure SysHideMouse;
  386. begin
  387. if (MouseCurOfs>=0) then
  388. PlaceMouseCur(-1);
  389. WaitMouseMove:=true;
  390. PrintMouseCur:=false;
  391. end;
  392. function SysGetMouseButtons:word;
  393. {$ifndef NOGPM}
  394. var
  395. me : TMouseEvent;
  396. {$endif ndef NOGPM}
  397. begin
  398. if gpm_fs<0 then
  399. exit(0);
  400. {$ifndef NOGPM}
  401. if PollMouseEvent(ME) then
  402. begin
  403. { Remove mouse event, we are only interrested in
  404. the buttons so all other events can be thrown away }
  405. GetMouseEvent(ME);
  406. SysGetMouseButtons:=ME.Buttons;
  407. end
  408. else
  409. begin
  410. SysGetMouseButtons:=SysLastMouseEvent.buttons;
  411. end;
  412. {$endif ndef NOGPM}
  413. end;
  414. Const
  415. SysMouseDriver : TMouseDriver = (
  416. UseDefaultQueue : true;
  417. InitDriver : @SysInitMouse;
  418. DoneDriver : @SysDoneMouse;
  419. DetectMouse : @SysDetectMouse;
  420. ShowMouse : @SysShowMouse;
  421. HideMouse : @SysHideMouse;
  422. GetMouseX : @SysGetMouseX;
  423. GetMouseY : @SysGetMouseY;
  424. GetMouseButtons : @SysGetMouseButtons;
  425. SetMouseXY : Nil;
  426. GetMouseEvent : @SysGetMouseEvent;
  427. PollMouseEvent : @SysPollMouseEvent;
  428. PutMouseEvent : Nil;
  429. );
  430. {$else ifndef NOMOUSE}
  431. Const
  432. SysMouseDriver : TMouseDriver = (
  433. UseDefaultQueue : true;
  434. InitDriver : Nil;
  435. DoneDriver : Nil;
  436. DetectMouse : Nil;
  437. ShowMouse : Nil;
  438. HideMouse : Nil;
  439. GetMouseX : Nil;
  440. GetMouseY : Nil;
  441. GetMouseButtons : Nil;
  442. SetMouseXY : Nil;
  443. GetMouseEvent : Nil;
  444. PollMouseEvent : Nil;
  445. PutMouseEvent : Nil;
  446. );
  447. {$endif}
  448. Begin
  449. SetMouseDriver(SysMouseDriver);
  450. end.