Function 12 - Set User Subroutine
PSS ID Number: Q19853
Article last modified on 05-14-1993
PSS database name: H_Mouse

1.x 2.x 3.x 4.x 5.x 6.x 7.x 8.x 9.00

MS-DOS


-------------------------------------------------------------------
The information in this article applies to:

 - Microsoft Mouse Driver for MS-DOS, versions 1.x, 2.x, 3.x, 4.x,
   5.x, 6.x, 7.x, 8.x, and 9.0
------------------------------------------------------------------- 

Summary:

The following is a description of Function 12, the Set User Defined
Subroutine Input Mask:

Inputs:

   AX = 12
   CX = call mask
   DX = offset of subroutine
   ES = segment of subroutine

Outputs: none

CALL MASK:

   bit       condition
   ------------------------------------
   0         cursor position changes
   1         Left button pressed
   2         Left button released
   3         Right button pressed
   4         Right button released

   If the bit = 1, the subroutine is called on the specified
   condition. 

The following are registers on entry to subroutine:

   AX = Condition mask (same structure as CALL MASK, save that the
        appropriate bit(s) = 1 ONLY if the condition(s) occurred).
   BX = Button state (same as Function 3:

        bit 0 = 1 --> left button pressed
              = 0 --> left button NOT pressed
        bit 1 = 1 --> right button pressed
              = 0 --> right button NOT pressed

The following example shows the minimum Function 12 subroutine that
allows sharing of a variable with Microsoft C (any model): 

   _DATA segment word public 'DATA'
   _DATA ends
   EXTRN _variable:WORD              ;note that this external variable
   ;is declared OUTSIDE of any segments so that LINK fixes it up. If it
   ;is declared inside _DATA, the SEG operator in _function does NOT WORK,
   ;as the real offset is from the start of DGROUP, NOT _DATA
   DGROUP GROUP _DATA
   _TEXT segment byte public 'CODE'
        assume CS:_TEXT,DS:DGROUP
        public _function
   _function proc far
        and  ax,1eh                ;check call mask for button
                                   ;events - ignore motion
        jz   _exit                 ;no button events, go quit
                                   ;button event happened
        push ds                    ;save DS
        mov  bx,seg _variable      ;get the SEGMENT that _variable
        mov  ds,bx                 ;exists in into DS
        mov  _variable,ax          ;move the button event info into
                                   ;the _variable WORD (this is a
                                   ;C 'int' [signed or unsigned])
        pop  ds                    ;restore DS
   _exit: ret                      ;return to the mouse driver
   _function endp
   _TEXT ends
   end

What Function 12 Subroutines CAN Do
-----------------------------------

Keep the following in mind when dealing with Function 12 subroutines
and how they should function: 

1. They should be defined as FAR PROCEDURES (terminate with a FAR
   RETURN).  

2. They should SAVE and RESTORE (PUSH and POP) any CPU register 
   other than AX, BX, CX, and DX whose contents are modified within the
   subroutine.  

3. They can call any mouse function.

4. Take care not to overflow the STACK (detect that the stack pointer 
   (SP) not go to ZERO (0). Note: The DOS stack is being used by the 
   subroutine.  

5. The segment register values are not those of the parent process
   (the COM or EXE process that the subroutine exists within).

6. The mouse driver protects function 12 from reentrant conditions
   (the subroutine cannot be called again until it terminates).

7. The mouse driver calls function 12 LAST in its own chain of
   internal events (mouse driver internals updated, cursor moved, etc.,
   first).  

8. Function 12 may be called to modify the call mask, or select a
   different subroutine; however, the currently executing subroutine
   should terminate as soon as possible because the mouse driver then
   no longer protects it from reentrancy. 

What Function 12 Subroutines Should NOT Do
------------------------------------------

Do not use Function 12 subroutines to do the following:

1. Make MS-DOS calls or BIOS interrupts; if they do, MS-DOS may
   crash. Because MS-DOS is not reentrant, INTs from Function 12
   subroutines (which are INTs) cause reentrant conditions. A very
   involved interrupt trapping and chaining, etc., process is 
   required to accomplish this safely.  

2. Make calls to other subroutines that may do MS-DOS or BIOS calls.
   (See No. 1 above). Library routines may do this.  

3. Make calls to other subroutines that assume certain values in
   segment registers. (See No. 5 in the above section on what
   Function 12 subroutines should do.) Library routines may do this.

Additional reference words: 7.00 7.04 7.05 8.00 8.10 8.20 9.00

Copyright Microsoft Corporation 1993.