mouse.pp 14 KB

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