123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- { This program tries to give an example how to install a callback
- procedure with the help of the GO32 unit.
- It installs a callback which is supplied by any Microsoft compatible
- mouse driver; at a specified mouse action this routine is called.
- This callback must provide the services explained in the docs. The
- main callback has to be in assembly, because it isn't possible to do
- these services with pascal alone. But is written as general as
- possible to provide maximum re-usability for other applications and
- hence it simply calls a normal pascal user procedure in addition to
- some initialization and callback service code, so you don't need to
- hassle around with it too much.
- Notes to this user procedure :
- *) it should not last too long to execute it
- *) ALL data and code touched in this proc MUST be locked BEFORE it is
- called the first time
- Used software interrupt calls (rough descriptions, only what's used):
- Int 33h 0000h - Microsoft Mouse driver : Reset mouse
- Input : AX = 0000h
- Return : AX = FFFFh if successful
- BX = number of buttons (if FFFFh then mouse has 2 buttons)
- Int 33h 0001h - Microsoft Mouse driver : Show mouse cursor
- Input : AX = 0001h
- Return : Mouse cursor shown on screen
- Int 33h 0002h - Microsoft mouse driver : Hide mouse cursor
- Input : AX = 0002h
- Return : Hides mouse cursor again
- Int 33h 000Ch - Microsoft mouse driver : Install user callback
- Input : AX = 000Ch
- CX = bit mask which tells the mouse driver at which actions
- the callback should be called, i.e. if button pressed, mouse
- moved etc.
- (In this example it's set to 7Fh so that the callback is
- called on every action)
- ES:EDX = pointer to callback procedure to call
- Note : The registers structure supplied to the callback contains
- valid mouse data when the handler is called.
- BX = button state information
- CX = mouse X coordinates
- DX = mouse Y coordinates
- For more detailed information consult any mouse reference or
- interrupt list.
- }
- {$ASMMODE ATT}
- {$MODE FPC}
- uses
- crt,
- go32;
- const
- { the mouse interrupt number }
- mouseint = $33;
- var
- { supplied register structure to the callback }
- mouse_regs : trealregs; external name '___v2prt0_rmcb_regs';
- { real mode 48 bit pointer to the callback }
- mouse_seginfo : tseginfo;
- var
- { number of mouse buttons }
- mouse_numbuttons : longint;
- { bit mask for the action which triggered the callback }
- mouse_action : word;
- { current mouse x and y coordinates }
- mouse_x, mouse_y : Word;
- { button state }
- mouse_b : Word;
- { is an additional user procedure installed }
- userproc_installed : Longbool;
- { length of additional user procedure }
- userproc_length : Longint;
- { pointer to user proc }
- userproc_proc : pointer;
- { callback control handler, calls a user procedure if installed }
- { callback control handler, calls a user procedure if installed }
- procedure callback_handler; assembler;
- asm
- pushw %ds
- pushl %eax
- movw %es, %ax
- movw %ax, %ds
- { give control to user procedure if installed }
- cmpl $1, USERPROC_INSTALLED
- jne .LNoCallback
- pushal
- movw DOSmemSELECTOR, %ax
- movw %ax, %fs { set fs for FPC }
- call *USERPROC_PROC
- popal
- .LNoCallback:
- popl %eax
- popw %ds
- pushl %eax
- movl (%esi), %eax
- movl %eax, %es: 42(%edi) { adjust stack }
- addw $4, %es:46(%edi)
- popl %eax
- iret
- end;
- { This dummy is used to obtain the length of the callback control
- function. It has to be right after the callback_handler() function.
- }
- procedure mouse_dummy; begin end;
- { This is the supplied user procedure. In this case we simply
- transform the virtual 640x200 mouse coordinate system to a 80x25
- text mode coordinate system }
- procedure textuserproc;
- begin
- { the mouse_regs record contains the real mode registers now }
- mouse_b := mouse_regs.bx;
- mouse_x := (mouse_regs.cx shr 3) + 1;
- mouse_y := (mouse_regs.dx shr 3) + 1;
- end;
- { Description : Installs the mouse callback control handler and
- handles all necessary mouse related initialization.
- Input : userproc - pointer to a user procedure, nil if none
- userproclen - length of user procedure
- }
- procedure install_mouse(userproc : pointer; userproclen : longint);
- var r : trealregs;
- begin
- { mouse driver reset }
- r.eax := $0; realintr(mouseint, r);
- if (r.eax <> $FFFF) then begin
- Writeln('No Microsoft compatible mouse found');
- Writeln('A Microsoft compatible mouse driver is necessary ',
- 'to run this example');
- halt;
- end;
- { obtain number of mouse buttons }
- if (r.bx = $ffff) then mouse_numbuttons := 2
- else mouse_numbuttons := r.bx;
- Writeln(mouse_numbuttons, ' button Microsoft compatible mouse ',
- ' found.');
- { check for additional user procedure, and install it if
- available }
- if (userproc <> nil) then begin
- userproc_proc := userproc;
- userproc_installed := true;
- userproc_length := userproclen;
- { lock code for user procedure }
- lock_code(userproc_proc, userproc_length);
- end else begin
- { clear variables }
- userproc_proc := nil;
- userproc_length := 0;
- userproc_installed := false;
- end;
- { lock code & data which is touched in the callback handler }
- lock_data(mouse_x, sizeof(mouse_x));
- lock_data(mouse_y, sizeof(mouse_y));
- lock_data(mouse_b, sizeof(mouse_b));
- lock_data(mouse_action, sizeof(mouse_action));
- lock_data(userproc_installed, sizeof(userproc_installed));
- lock_data(userproc_proc, sizeof(userproc_proc));
- lock_data(mouse_regs, sizeof(mouse_regs));
- lock_data(mouse_seginfo, sizeof(mouse_seginfo));
- lock_code(@callback_handler,
- longint(@mouse_dummy)-longint(@callback_handler));
- { allocate callback (supply registers structure) }
- get_rm_callback(@callback_handler, mouse_regs, mouse_seginfo);
- { install callback }
- r.eax := $0c; r.ecx := $7f;
- r.edx := longint(mouse_seginfo.offset);
- r.es := mouse_seginfo.segment;
- realintr(mouseint, r);
- { show mouse cursor }
- r.eax := $01;
- realintr(mouseint, r);
- end;
- procedure remove_mouse;
- var
- r : trealregs;
- begin
- { hide mouse cursor }
- r.eax := $02; realintr(mouseint, r);
- { remove callback handler }
- r.eax := $0c; r.ecx := 0; r.edx := 0; r.es := 0;
- realintr(mouseint, r);
- { free callback }
- free_rm_callback(mouse_seginfo);
- { check if additional userproc is installed, and clean up if
- needed }
- if (userproc_installed) then begin
- unlock_code(userproc_proc, userproc_length);
- userproc_proc := nil;
- userproc_length := 0;
- userproc_installed := false;
- end;
- { unlock used code & data }
- unlock_data(mouse_x, sizeof(mouse_x));
- unlock_data(mouse_y, sizeof(mouse_y));
- unlock_data(mouse_b, sizeof(mouse_b));
- unlock_data(mouse_action, sizeof(mouse_action));
- unlock_data(userproc_proc, sizeof(userproc_proc));
- unlock_data(userproc_installed, sizeof(userproc_installed));
- unlock_data(mouse_regs, sizeof(mouse_regs));
- unlock_data(mouse_seginfo, sizeof(mouse_seginfo));
- unlock_code(@callback_handler,
- longint(@mouse_dummy)-longint(@callback_handler));
- fillchar(mouse_seginfo, sizeof(mouse_seginfo), 0);
- end;
- begin
- install_mouse(@textuserproc, 400);
- Writeln('Press any key to exit...');
- while (not keypressed) do begin
- { write mouse state info }
- gotoxy(1, wherey);
- write('MouseX : ', mouse_x:2, ' MouseY : ', mouse_y:2,
- ' Buttons : ', mouse_b:2);
- end;
- remove_mouse;
- end.
|