callback.pas 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. { This program tries to give an example how to install a callback
  2. procedure with the help of the GO32 unit.
  3. It installs a callback which is supplied by any Microsoft compatible
  4. mouse driver; at a specified mouse action this routine is called.
  5. This callback must provide the services explained in the docs. The
  6. main callback has to be in assembly, because it isn't possible to do
  7. these services with pascal alone. But is written as general as
  8. possible to provide maximum re-usability for other applications and
  9. hence it simply calls a normal pascal user procedure in addition to
  10. some initialization and callback service code, so you don't need to
  11. hassle around with it too much.
  12. Notes to this user procedure :
  13. *) it should not last too long to execute it
  14. *) ALL data and code touched in this proc MUST be locked BEFORE it is
  15. called the first time
  16. Used software interrupt calls (rough descriptions, only what's used):
  17. Int 33h 0000h - Microsoft Mouse driver : Reset mouse
  18. Input : AX = 0000h
  19. Return : AX = FFFFh if successful
  20. BX = number of buttons (if FFFFh then mouse has 2 buttons)
  21. Int 33h 0001h - Microsoft Mouse driver : Show mouse cursor
  22. Input : AX = 0001h
  23. Return : Mouse cursor shown on screen
  24. Int 33h 0002h - Microsoft mouse driver : Hide mouse cursor
  25. Input : AX = 0002h
  26. Return : Hides mouse cursor again
  27. Int 33h 000Ch - Microsoft mouse driver : Install user callback
  28. Input : AX = 000Ch
  29. CX = bit mask which tells the mouse driver at which actions
  30. the callback should be called, i.e. if button pressed, mouse
  31. moved etc.
  32. (In this example it's set to 7Fh so that the callback is
  33. called on every action)
  34. ES:EDX = pointer to callback procedure to call
  35. Note : The registers structure supplied to the callback contains
  36. valid mouse data when the handler is called.
  37. BX = button state information
  38. CX = mouse X coordinates
  39. DX = mouse Y coordinates
  40. For more detailed information consult any mouse reference or
  41. interrupt list.
  42. }
  43. {$ASMMODE ATT}
  44. {$MODE FPC}
  45. uses
  46. crt,
  47. go32;
  48. const
  49. { the mouse interrupt number }
  50. mouseint = $33;
  51. var
  52. { supplied register structure to the callback }
  53. mouse_regs : trealregs; external name '___v2prt0_rmcb_regs';
  54. { real mode 48 bit pointer to the callback }
  55. mouse_seginfo : tseginfo;
  56. var
  57. { number of mouse buttons }
  58. mouse_numbuttons : longint;
  59. { bit mask for the action which triggered the callback }
  60. mouse_action : word;
  61. { current mouse x and y coordinates }
  62. mouse_x, mouse_y : Word;
  63. { button state }
  64. mouse_b : Word;
  65. { is an additional user procedure installed }
  66. userproc_installed : Longbool;
  67. { length of additional user procedure }
  68. userproc_length : Longint;
  69. { pointer to user proc }
  70. userproc_proc : pointer;
  71. { callback control handler, calls a user procedure if installed }
  72. { callback control handler, calls a user procedure if installed }
  73. procedure callback_handler; assembler;
  74. asm
  75. pushw %ds
  76. pushl %eax
  77. movw %es, %ax
  78. movw %ax, %ds
  79. { give control to user procedure if installed }
  80. cmpl $1, USERPROC_INSTALLED
  81. jne .LNoCallback
  82. pushal
  83. movw DOSmemSELECTOR, %ax
  84. movw %ax, %fs { set fs for FPC }
  85. call *USERPROC_PROC
  86. popal
  87. .LNoCallback:
  88. popl %eax
  89. popw %ds
  90. pushl %eax
  91. movl (%esi), %eax
  92. movl %eax, %es: 42(%edi) { adjust stack }
  93. addw $4, %es:46(%edi)
  94. popl %eax
  95. iret
  96. end;
  97. { This dummy is used to obtain the length of the callback control
  98. function. It has to be right after the callback_handler() function.
  99. }
  100. procedure mouse_dummy; begin end;
  101. { This is the supplied user procedure. In this case we simply
  102. transform the virtual 640x200 mouse coordinate system to a 80x25
  103. text mode coordinate system }
  104. procedure textuserproc;
  105. begin
  106. { the mouse_regs record contains the real mode registers now }
  107. mouse_b := mouse_regs.bx;
  108. mouse_x := (mouse_regs.cx shr 3) + 1;
  109. mouse_y := (mouse_regs.dx shr 3) + 1;
  110. end;
  111. { Description : Installs the mouse callback control handler and
  112. handles all necessary mouse related initialization.
  113. Input : userproc - pointer to a user procedure, nil if none
  114. userproclen - length of user procedure
  115. }
  116. procedure install_mouse(userproc : pointer; userproclen : longint);
  117. var r : trealregs;
  118. begin
  119. { mouse driver reset }
  120. r.eax := $0; realintr(mouseint, r);
  121. if (r.eax <> $FFFF) then begin
  122. Writeln('No Microsoft compatible mouse found');
  123. Writeln('A Microsoft compatible mouse driver is necessary ',
  124. 'to run this example');
  125. halt;
  126. end;
  127. { obtain number of mouse buttons }
  128. if (r.bx = $ffff) then mouse_numbuttons := 2
  129. else mouse_numbuttons := r.bx;
  130. Writeln(mouse_numbuttons, ' button Microsoft compatible mouse ',
  131. ' found.');
  132. { check for additional user procedure, and install it if
  133. available }
  134. if (userproc <> nil) then begin
  135. userproc_proc := userproc;
  136. userproc_installed := true;
  137. userproc_length := userproclen;
  138. { lock code for user procedure }
  139. lock_code(userproc_proc, userproc_length);
  140. end else begin
  141. { clear variables }
  142. userproc_proc := nil;
  143. userproc_length := 0;
  144. userproc_installed := false;
  145. end;
  146. { lock code & data which is touched in the callback handler }
  147. lock_data(mouse_x, sizeof(mouse_x));
  148. lock_data(mouse_y, sizeof(mouse_y));
  149. lock_data(mouse_b, sizeof(mouse_b));
  150. lock_data(mouse_action, sizeof(mouse_action));
  151. lock_data(userproc_installed, sizeof(userproc_installed));
  152. lock_data(userproc_proc, sizeof(userproc_proc));
  153. lock_data(mouse_regs, sizeof(mouse_regs));
  154. lock_data(mouse_seginfo, sizeof(mouse_seginfo));
  155. lock_code(@callback_handler,
  156. longint(@mouse_dummy)-longint(@callback_handler));
  157. { allocate callback (supply registers structure) }
  158. get_rm_callback(@callback_handler, mouse_regs, mouse_seginfo);
  159. { install callback }
  160. r.eax := $0c; r.ecx := $7f;
  161. r.edx := longint(mouse_seginfo.offset);
  162. r.es := mouse_seginfo.segment;
  163. realintr(mouseint, r);
  164. { show mouse cursor }
  165. r.eax := $01;
  166. realintr(mouseint, r);
  167. end;
  168. procedure remove_mouse;
  169. var
  170. r : trealregs;
  171. begin
  172. { hide mouse cursor }
  173. r.eax := $02; realintr(mouseint, r);
  174. { remove callback handler }
  175. r.eax := $0c; r.ecx := 0; r.edx := 0; r.es := 0;
  176. realintr(mouseint, r);
  177. { free callback }
  178. free_rm_callback(mouse_seginfo);
  179. { check if additional userproc is installed, and clean up if
  180. needed }
  181. if (userproc_installed) then begin
  182. unlock_code(userproc_proc, userproc_length);
  183. userproc_proc := nil;
  184. userproc_length := 0;
  185. userproc_installed := false;
  186. end;
  187. { unlock used code & data }
  188. unlock_data(mouse_x, sizeof(mouse_x));
  189. unlock_data(mouse_y, sizeof(mouse_y));
  190. unlock_data(mouse_b, sizeof(mouse_b));
  191. unlock_data(mouse_action, sizeof(mouse_action));
  192. unlock_data(userproc_proc, sizeof(userproc_proc));
  193. unlock_data(userproc_installed, sizeof(userproc_installed));
  194. unlock_data(mouse_regs, sizeof(mouse_regs));
  195. unlock_data(mouse_seginfo, sizeof(mouse_seginfo));
  196. unlock_code(@callback_handler,
  197. longint(@mouse_dummy)-longint(@callback_handler));
  198. fillchar(mouse_seginfo, sizeof(mouse_seginfo), 0);
  199. end;
  200. begin
  201. install_mouse(@textuserproc, 400);
  202. Writeln('Press any key to exit...');
  203. while (not keypressed) do begin
  204. { write mouse state info }
  205. gotoxy(1, wherey);
  206. write('MouseX : ', mouse_x:2, ' MouseY : ', mouse_y:2,
  207. ' Buttons : ', mouse_b:2);
  208. end;
  209. remove_mouse;
  210. end.