mouse.pp 12 KB

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