mouse.inc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. {
  2. System dependent mouse implementation for go32v2
  3. $Id$
  4. }
  5. uses
  6. video,go32;
  7. var
  8. RealSeg : Word; { Real mode segment }
  9. RealOfs : Word; { Real mode offset }
  10. CurrentMask : word;
  11. MouseCallback : Pointer; { Mouse call back ptr }
  12. {$ifdef DEBUG}
  13. EntryEDI,EntryESI : longint;
  14. EntryDS,EntryES : word;
  15. {$endif DEBUG}
  16. { Real mode registers in text segment below $ffff limit
  17. for Windows NT
  18. NOTE this might cause problem if someone want to
  19. protect text section against writing (would be possible
  20. with CWSDPMI under raw dos, not implemented yet !) }
  21. ActionRegs : TRealRegs;external name '___v2prt0_rmcb_regs';
  22. v2prt0_ds_alias : word;external name '___v2prt0_ds_alias';
  23. const
  24. MousePresent : boolean = false;
  25. {$ifdef DEBUG}
  26. MouseError : longint = 0;
  27. CallCounter : longint = 0;
  28. {$endif DEBUG}
  29. drawmousecursor : boolean = false;
  30. mouseisvisible : boolean = false;
  31. { position where the mouse was drawn the last time }
  32. oldmousex : longint = -1;
  33. oldmousey : longint = -1;
  34. mouselock : boolean = false;
  35. { if the cursor is drawn by this the unit, we must be careful }
  36. { when drawing while the interrupt handler is called }
  37. procedure lockmouse;assembler;
  38. asm
  39. .Ltrylockagain:
  40. movb $1,%al
  41. xchgb mouselock,%al
  42. orb %al,%al
  43. jne .Ltrylockagain
  44. end;
  45. procedure unlockmouse;
  46. begin
  47. mouselock:=false;
  48. end;
  49. {$ASMMODE ATT}
  50. procedure MouseInt;assembler;
  51. asm
  52. movb %bl,mousebuttons
  53. movw %cx,mousewherex
  54. movw %dx,mousewherey
  55. shrw $3,%cx
  56. shrw $3,%dx
  57. { should we draw the mouse cursor? }
  58. cmpb $0,drawmousecursor
  59. je .Lmouse_nocursor
  60. cmpb $0,mouseisvisible
  61. je .Lmouse_nocursor
  62. pushw %fs
  63. pushl %eax
  64. pushl %edi
  65. { check lock }
  66. movb $1,%al
  67. xchgb mouselock,%al
  68. orb %al,%al
  69. { don't update the cursor yet, because hide/showcursor is called }
  70. jne .Ldont_draw
  71. { load start of video buffer }
  72. movzwl videoseg,%edi
  73. shll $4,%edi
  74. movw dosmemselector,%fs
  75. { calculate address of old mouse cursor }
  76. movl oldmousey,%eax
  77. imulw screenwidth,%ax
  78. addl oldmousex,%eax
  79. leal 1(%edi,%eax,2),%eax
  80. { remove old cursor }
  81. xorb $0x7f,%fs:(%eax)
  82. { store position of old cursor }
  83. movzwl %cx,%ecx
  84. movl %ecx,oldmousex
  85. movzwl %dx,%edx
  86. movl %edx,oldmousey
  87. { calculate address of new cursor }
  88. movl %edx,%eax
  89. imulw screenwidth,%ax
  90. addl %ecx,%eax
  91. leal 1(%edi,%eax,2),%eax
  92. { draw new cursor }
  93. xorb $0x7f,%fs:(%eax)
  94. { unlock mouse }
  95. movb $0,mouselock
  96. .Ldont_draw:
  97. popl %edi
  98. popl %eax
  99. popw %fs
  100. .Lmouse_nocursor:
  101. cmpb MouseEventBufSize,PendingMouseEvents
  102. je .Lmouse_exit
  103. movl PendingMouseTail,%edi
  104. movw %bx,(%edi)
  105. movw %cx,2(%edi)
  106. movw %dx,4(%edi)
  107. movw $0,6(%edi)
  108. addl $8,%edi
  109. leal PendingMouseEvent,%eax
  110. addl MouseEventBufSize*8,%eax
  111. cmpl %eax,%edi
  112. jne .Lmouse_nowrap
  113. leal PendingMouseEvent,%edi
  114. .Lmouse_nowrap:
  115. movl %edi,PendingMouseTail
  116. incb PendingMouseEvents
  117. .Lmouse_exit:
  118. end;
  119. PROCEDURE Mouse_Trap; ASSEMBLER;
  120. ASM
  121. PUSH %ES; { Save ES register }
  122. PUSH %DS; { Save DS register }
  123. PUSHL %EDI; { Save register }
  124. PUSHL %ESI; { Save register }
  125. { ; caution : ds is not the selector for our data !! }
  126. {$ifdef DEBUG}
  127. MOVL %EDI,%ES:EntryEDI
  128. MOVL %ESI,%ES:EntryESI
  129. MOVW %DS,%AX
  130. MOVW %AX,%ES:EntryDS
  131. MOVW %ES,%AX
  132. MOVW %AX,%ES:EntryES
  133. {$endif DEBUG}
  134. { movw %cs:v2prt0_ds_alias,%ax v2prt0 is not locked !!
  135. movw %ax,%ds
  136. movw %ax,%es }
  137. PUSH %ES; { Push data seg }
  138. POP %DS; { Load data seg }
  139. {$ifdef DEBUG}
  140. incl callcounter
  141. CMPL $ACTIONREGS,%edi
  142. JE .L_ActionRegsOK
  143. INCL MouseError
  144. JMP .L_NoCallBack
  145. .L_ActionRegsOK:
  146. {$endif DEBUG}
  147. MOVL MOUSECALLBACK, %EAX; { Fetch callback addr }
  148. CMPL $0, %EAX; { Check for nil ptr }
  149. JZ .L_NoCallBack; { Ignore if nil }
  150. MOVL %EDI,%EAX; { %EAX = @actionregs }
  151. MOVL (%EAX), %EDI; { EDI from actionregs }
  152. MOVL 4(%EAX), %ESI; { ESI from actionregs }
  153. MOVL 16(%EAX), %EBX; { EBX from actionregs }
  154. MOVL 20(%EAX), %EDX; { EDX from actionregs }
  155. MOVL 24(%EAX), %ECX; { ECX from actionregs }
  156. MOVL 28(%EAX), %EAX; { EAX from actionregs }
  157. CALL *MOUSECALLBACK; { Call callback proc }
  158. .L_NoCallBack:
  159. POPL %ESI; { Recover register }
  160. POPL %EDI; { Recover register }
  161. POP %DS; { Restore DS register }
  162. POP %ES; { Restore ES register }
  163. { This works for WinNT
  164. movzwl %si,%eax
  165. but CWSDPMI need this }
  166. movl %esi,%eax
  167. MOVL %ds:(%Eax), %EAX;
  168. MOVL %EAX, %ES:42(%EDI); { Set as return addr }
  169. ADDW $4, %ES:46(%EDI); { adjust stack }
  170. IRET; { Interrupt return }
  171. END;
  172. Function Allocate_mouse_bridge : boolean;
  173. var
  174. error : word;
  175. begin
  176. ASM
  177. LEAL ACTIONREGS, %EDI; { Addr of actionregs }
  178. LEAL MOUSE_TRAP, %ESI; { Procedure address }
  179. PUSH %DS; { Save DS segment }
  180. PUSH %ES; { Save ES segment }
  181. MOVW v2prt0_ds_alias,%ES; { ES now has dataseg alias that is never invalid }
  182. PUSH %CS;
  183. POP %DS; { DS now has codeseg }
  184. MOVW $0x303, %AX; { Function id }
  185. INT $0x31; { Call DPMI bridge }
  186. JNC .L_call_ok; { Branch if ok }
  187. POP %ES; { Restore ES segment }
  188. POP %DS; { Restore DS segment }
  189. MOVW $0,REALSEG;
  190. MOVW $0,REALOFS;
  191. JMP .L_exit
  192. .L_call_ok:
  193. POP %ES; { Restore ES segment }
  194. POP %DS; { Restore DS segment }
  195. MOVW %CX,REALSEG; { Transfer real seg }
  196. MOVW %DX,REALOFS; { Transfer real ofs }
  197. MOVW $0, %AX; { Force error to zero }
  198. .L_exit:
  199. MOVW %AX, ERROR; { Return error state }
  200. END;
  201. Allocate_mouse_bridge:=error=0;
  202. end;
  203. Procedure Release_mouse_bridge;
  204. begin
  205. ASM
  206. MOVW $0x304, %AX; { Set function id }
  207. MOVW REALSEG, %CX; { Bridged real seg }
  208. MOVW REALOFS, %DX; { Bridged real ofs }
  209. INT $0x31; { Release bridge }
  210. MOVW $0,REALSEG;
  211. MOVW $0,REALOFS;
  212. END;
  213. end;
  214. PROCEDURE Mouse_Action (Mask : Word; P : Pointer);
  215. VAR
  216. Error : Word;
  217. Rg : TRealRegs;
  218. BEGIN
  219. Error := 0; { Preset no error }
  220. If (P <> MouseCallBack) or (Mask<>CurrentMask) Then { Check func different }
  221. Begin
  222. { Remove old calback }
  223. If (CurrentMask <> 0) Then
  224. Begin
  225. Rg.AX := 12; { Function id }
  226. Rg.CX := 0; { Zero mask register }
  227. Rg.ES := 0; { Zero proc seg }
  228. Rg.DX := 0; { Zero proc ofs }
  229. RealIntr($33, Rg); { Stop INT 33 callback }
  230. End;
  231. if RealSeg=0 then
  232. error:=1;
  233. { test addresses for Windows NT }
  234. if (longint(@actionregs)>$ffff) {or
  235. (longint(@mouse_trap)>$ffff)} then
  236. begin
  237. error:=1;
  238. end
  239. else If (P = Nil) Then
  240. Begin
  241. Mask := 0; { Zero mask register }
  242. End;
  243. If (Error = 0) Then
  244. Begin
  245. MouseCallback := P; { Set call back addr }
  246. if Mask<>0 then
  247. begin
  248. Rg.AX := 12; { Set function id }
  249. Rg.CX := Mask; { Set mask register }
  250. If Mask<>0 then
  251. begin
  252. Rg.ES := RealSeg; { Real mode segment }
  253. Rg.DX := RealOfs; { Real mode offset }
  254. end
  255. else
  256. begin
  257. Rg.ES:=0;
  258. Rg.DX:=0;
  259. end;
  260. RealIntr($33, Rg); { Set interrupt 33 }
  261. end;
  262. CurrentMask:=Mask;
  263. End;
  264. End;
  265. If (Error <> 0) Then
  266. Begin
  267. Writeln('GO32V2 mouse handler set failed !!');
  268. ReadLn; { Wait for user to see }
  269. End;
  270. END;
  271. { We need to remove the mouse callback before exiting !! PM }
  272. const StoredExit : Pointer = Nil;
  273. FirstMouseInitDone : boolean = false;
  274. procedure MouseSafeExit;
  275. begin
  276. ExitProc:=StoredExit;
  277. if MouseCallBack<>Nil then
  278. Mouse_Action(0, Nil);
  279. if not FirstMouseInitDone then
  280. exit;
  281. FirstMouseInitDone:=false;
  282. Unlock_Code(Pointer(@Mouse_Trap), 400); { Release trap code }
  283. Unlock_Code(Pointer(@MouseInt), 400); { Lock MouseInt code }
  284. Unlock_Data(ActionRegs, SizeOf(TRealRegs)); { Release registers }
  285. UnLock_Data(MouseCallBack,SizeOf(Pointer));
  286. { unlock Mouse Queue and related stuff ! }
  287. Unlock_Data(PendingMouseEvent,
  288. MouseEventBufSize*Sizeof(TMouseEvent));
  289. Unlock_Data(PendingMouseTail,SizeOf(longint));
  290. Unlock_Data(PendingMouseEvents,sizeof(byte));
  291. Unlock_Data(MouseButtons,SizeOf(byte));
  292. Unlock_Data(MouseWhereX,SizeOf(word));
  293. Unlock_Data(MouseWhereY,SizeOf(word));
  294. Unlock_Data(drawmousecursor,SizeOf(boolean));
  295. Unlock_Data(mouseisvisible,SizeOf(boolean));
  296. Unlock_Data(mouselock,SizeOf(boolean));
  297. Unlock_Data(videoseg,SizeOf(word));
  298. Unlock_Data(dosmemselector,SizeOf(word));
  299. Unlock_Data(screenwidth,SizeOf(word));
  300. Unlock_Data(OldMouseX,SizeOf(longint));
  301. Unlock_Data(OldMouseY,SizeOf(longint));
  302. {$ifdef DEBUG}
  303. Unlock_Data(EntryEDI, SizeOf(longint));
  304. Unlock_Data(EntryESI, SizeOf(longint));
  305. Unlock_Data(EntryDS, SizeOf(word));
  306. Unlock_Data(EntryES, SizeOf(word));
  307. Unlock_Data(MouseError, SizeOf(longint));
  308. Unlock_Data(callcounter, SizeOf(longint));
  309. {$endif DEBUG}
  310. Release_mouse_bridge;
  311. end;
  312. procedure InitMouse;
  313. begin
  314. if not MousePresent then
  315. begin
  316. if DetectMouse=0 then
  317. begin
  318. Writeln('No mouse driver found ');
  319. exit;
  320. end
  321. else
  322. MousePresent:=true;
  323. end;
  324. PendingMouseHead:=@PendingMouseEvent;
  325. PendingMouseTail:=@PendingMouseEvent;
  326. PendingMouseEvents:=0;
  327. FillChar(LastMouseEvent,sizeof(TMouseEvent),0);
  328. { don't do this twice !! PM }
  329. If not FirstMouseInitDone then
  330. begin
  331. StoredExit:=ExitProc;
  332. ExitProc:=@MouseSafeExit;
  333. Lock_Code(Pointer(@Mouse_Trap), 400); { Lock trap code }
  334. Lock_Code(Pointer(@MouseInt), 400); { Lock MouseInt code }
  335. Lock_Data(ActionRegs, SizeOf(TRealRegs)); { Lock registers }
  336. Lock_Data(MouseCallBack, SizeOf(pointer));
  337. { lock Mouse Queue and related stuff ! }
  338. Lock_Data(PendingMouseEvent,
  339. MouseEventBufSize*Sizeof(TMouseEvent));
  340. Lock_Data(PendingMouseTail,SizeOf(longint));
  341. Lock_Data(PendingMouseEvents,sizeof(byte));
  342. Lock_Data(MouseButtons,SizeOf(byte));
  343. Lock_Data(MouseWhereX,SizeOf(word));
  344. Lock_Data(MouseWhereY,SizeOf(word));
  345. Lock_Data(drawmousecursor,SizeOf(boolean));
  346. Lock_Data(mouseisvisible,SizeOf(boolean));
  347. Lock_Data(mouselock,SizeOf(boolean));
  348. Lock_Data(videoseg,SizeOf(word));
  349. Lock_Data(dosmemselector,SizeOf(word));
  350. Lock_Data(screenwidth,SizeOf(word));
  351. Lock_Data(OldMouseX,SizeOf(longint));
  352. Lock_Data(OldMouseY,SizeOf(longint));
  353. {$ifdef DEBUG}
  354. Lock_Data(EntryEDI, SizeOf(longint));
  355. Lock_Data(EntryESI, SizeOf(longint));
  356. Lock_Data(EntryDS, SizeOf(word));
  357. Lock_Data(EntryES, SizeOf(word));
  358. Lock_Data(MouseError, SizeOf(longint));
  359. Lock_Data(callcounter, SizeOf(longint));
  360. {$endif DEBUG}
  361. Allocate_mouse_bridge;
  362. FirstMouseInitDone:=true;
  363. end;
  364. If MouseCallBack=Nil then
  365. Mouse_Action($ffff, @MouseInt); { Set masks/interrupt }
  366. drawmousecursor:=false;
  367. mouseisvisible:=false;
  368. if (screenwidth>80) or (screenheight>50) then
  369. DoCustomMouse(true);
  370. ShowMouse;
  371. end;
  372. procedure DoneMouse;
  373. begin
  374. HideMouse;
  375. If (MouseCallBack <> Nil) Then
  376. Mouse_Action(0, Nil); { Clear mask/interrupt }
  377. end;
  378. function DetectMouse:byte;assembler;
  379. asm
  380. movl $0x200,%eax
  381. movl $0x33,%ebx
  382. int $0x31
  383. movw %cx,%ax
  384. orw %ax,%dx
  385. jz .Lno_mouse
  386. xorl %eax,%eax
  387. pushl %ebp
  388. int $0x33
  389. popl %ebp
  390. orw %ax,%ax
  391. jz .Lno_mouse
  392. movl %ebx,%eax
  393. .Lno_mouse:
  394. end;
  395. procedure ShowMouse;
  396. begin
  397. if drawmousecursor then
  398. begin
  399. lockmouse;
  400. if not(mouseisvisible) then
  401. begin
  402. oldmousex:=getmousex-1;
  403. oldmousey:=getmousey-1;
  404. mem[videoseg:(((screenwidth*oldmousey)+oldmousex)*2)+1]:=
  405. mem[videoseg:(((screenwidth*oldmousey)+oldmousex)*2)+1] xor $7f;
  406. mouseisvisible:=true;
  407. end;
  408. unlockmouse;
  409. end
  410. else
  411. asm
  412. cmpb $1,MousePresent
  413. jne .LShowMouseExit
  414. movl $1,%eax
  415. pushl %ebp
  416. int $0x33
  417. popl %ebp
  418. .LShowMouseExit:
  419. end;
  420. end;
  421. procedure HideMouse;
  422. begin
  423. if drawmousecursor then
  424. begin
  425. lockmouse;
  426. if mouseisvisible then
  427. begin
  428. mouseisvisible:=false;
  429. mem[videoseg:(((screenwidth*oldmousey)+oldmousex)*2)+1]:=
  430. mem[videoseg:(((screenwidth*oldmousey)+oldmousex)*2)+1] xor $7f;
  431. oldmousex:=-1;
  432. oldmousey:=-1;
  433. end;
  434. unlockmouse;
  435. end
  436. else
  437. asm
  438. cmpb $1,MousePresent
  439. jne .LHideMouseExit
  440. movl $2,%eax
  441. pushl %ebp
  442. int $0x33
  443. popl %ebp
  444. .LHideMouseExit:
  445. end;
  446. end;
  447. function GetMouseX:word;assembler;
  448. asm
  449. cmpb $1,MousePresent
  450. jne .LGetMouseXError
  451. movl $3,%eax
  452. pushl %ebp
  453. int $0x33
  454. popl %ebp
  455. movzwl %cx,%eax
  456. shrl $3,%eax
  457. incl %eax
  458. ret
  459. .LGetMouseXError:
  460. xorl %eax,%eax
  461. end;
  462. function GetMouseY:word;assembler;
  463. asm
  464. cmpb $1,MousePresent
  465. jne .LGetMouseYError
  466. movl $3,%eax
  467. pushl %ebp
  468. int $0x33
  469. popl %ebp
  470. movzwl %dx,%eax
  471. shrl $3,%eax
  472. incl %eax
  473. ret
  474. .LGetMouseYError:
  475. xorl %eax,%eax
  476. end;
  477. function GetMouseButtons:word;assembler;
  478. asm
  479. cmpb $1,MousePresent
  480. jne .LGetMouseButtonsError
  481. movl $3,%eax
  482. pushl %ebp
  483. int $0x33
  484. popl %ebp
  485. movw %bx,%ax
  486. ret
  487. .LGetMouseButtonsError:
  488. xorl %eax,%eax
  489. end;
  490. procedure SetMouseXY(x,y:word);assembler;
  491. asm
  492. cmpb $1,MousePresent
  493. jne .LSetMouseXYExit
  494. movw x,%cx
  495. movw y,%dx
  496. movl $4,%eax
  497. pushl %ebp
  498. int $0x33
  499. popl %ebp
  500. .LSetMouseXYExit:
  501. end;
  502. Procedure SetMouseXRange (Min,Max:Longint);
  503. begin
  504. If Not(MousePresent) Then Exit;
  505. asm
  506. movl $7,%eax
  507. movl min,%ecx
  508. movl max,%edx
  509. pushl %ebp
  510. int $0x33
  511. popl %ebp
  512. end;
  513. end;
  514. Procedure SetMouseYRange (min,max:Longint);
  515. begin
  516. If Not(MousePresent) Then Exit;
  517. asm
  518. movl $8,%eax
  519. movl min,%ecx
  520. movl max,%edx
  521. pushl %ebp
  522. int $0x33
  523. popl %ebp
  524. end;
  525. end;
  526. procedure DoCustomMouse(b : boolean);
  527. begin
  528. HideMouse;
  529. lockmouse;
  530. oldmousex:=-1;
  531. oldmousey:=-1;
  532. SetMouseXRange(0,(screenwidth-1)*8);
  533. SetMouseYRange(0,(screenheight-1)*8);
  534. if b then
  535. begin
  536. mouseisvisible:=false;
  537. drawmousecursor:=true;
  538. end
  539. else
  540. drawmousecursor:=false;
  541. unlockmouse;
  542. end;
  543. const
  544. LastCallcounter : longint = 0;
  545. procedure GetMouseEvent(var MouseEvent: TMouseEvent);
  546. begin
  547. if not MousePresent then
  548. begin
  549. Fillchar(MouseEvent,SizeOf(TMouseEvent),#0);
  550. end;
  551. {$ifdef DEBUG}
  552. if mouseError>0 then
  553. Writeln('Errors in mouse Handler ',MouseError);
  554. {$ifdef EXTMOUSEDEBUG}
  555. if callcounter>LastCallcounter then
  556. Writeln('Number of calls in mouse Handler ',Callcounter);
  557. {$endif EXTMOUSEDEBUG}
  558. LastCallcounter:=Callcounter;
  559. {$endif DEBUG}
  560. repeat until PendingMouseEvents>0;
  561. MouseEvent:=PendingMouseHead^;
  562. inc(PendingMouseHead);
  563. if longint(PendingMouseHead)=longint(@PendingMouseEvent)+sizeof(PendingMouseEvent) then
  564. PendingMouseHead:=@PendingMouseEvent;
  565. dec(PendingMouseEvents);
  566. if (LastMouseEvent.x<>MouseEvent.x) or (LastMouseEvent.y<>MouseEvent.y) then
  567. MouseEvent.Action:=MouseActionMove;
  568. if (LastMouseEvent.Buttons<>MouseEvent.Buttons) then
  569. begin
  570. if (LastMouseEvent.Buttons=0) then
  571. MouseEvent.Action:=MouseActionDown
  572. else
  573. MouseEvent.Action:=MouseActionUp;
  574. end;
  575. LastMouseEvent:=MouseEvent;
  576. end;
  577. function PollMouseEvent(var MouseEvent: TMouseEvent):boolean;
  578. begin
  579. if PendingMouseEvents>0 then
  580. begin
  581. MouseEvent:=PendingMouseHead^;
  582. PollMouseEvent:=true;
  583. end
  584. else
  585. PollMouseEvent:=false;
  586. end;
  587. {
  588. $Log$
  589. Revision 1.2 2000-07-13 11:32:24 michael
  590. + removed logs
  591. }