mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-21 07:49:38 +02:00
238 lines
7.3 KiB
ObjectPascal
238 lines
7.3 KiB
ObjectPascal
{ 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. |