Skip to content

Mice do it on the Mat

Vector 7:3, page 130

user interfaces system interfaces

Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 130

All you need to know to use a mouse from within APL on a PC with examples using the STSC ⎕INT system function. This will work on any version of APL*PLUS/PC, unlike ⎕MOUSE, which is only available on release-10.

On an IBM (or compatible) PC with an attached mouse, special system software called the mouse driver provides an interface between the application program and the mouse hardware. The mouse driver can be installed (attached to DOS) at the time the system is configured. Alternatively the mouse driver can be installed in the form of a TSR (terminate and stay resident) program at run time. In either case, the driver should be installed before APL is invoked.

On the PC, system functions can be invoked from application software via interrupts. All that needs to be said is the CPU chip can support up to 255 different interrupts, and the standard (Microsoft) mouse driver is controlled and interrogated via interrupt number 51 (33hex). All parameters needed for this exercise can (and must) be passed to and from the mouse driver via the PC’s registers.

So a method of setting the CPU’s registers and then executing interrupt 51 is required to use the mouse. The ⎕INT system function in STSC’s APL can provide all the interfacing needed between APL and the mouse driver.

Using ⎕INT is dead easy. (It took me less than 5 minutes to find out how, without a manual, by trial and error!) It takes two arguments: the right hand argument is the interrupt number (51 for the mouse); the left hand argument is a list of register values. The result ⎕INT returns is a vector of the register values after the interrupt.

The facilities provided by the mouse driver allow you to position the mouse, set boundaries of mouse travel, read the mouse position, count the number of button presses (and releases), and show and hide the mouse. (Many other facilities are also provided, see Appendix 2 for the full list.)

But first you need to initialise the mouse. (Note: initialising the mouse is not the same as installing the mouse driver.) Initialising the mouse determines whether a mouse is attached, it resets the mouse driver (on reset, the mouse cursor is hidden and placed in the centre of the screen), and returns the number of buttons on the mouse. It may be initialised from APL by executing:

0 ⎕INT 51

The first element of the result should contain ¯1 and the second element the number of buttons on the mouse (2 or 3). All other elements will be zero.

The equivalent assembler code would be:

MOV AX,0 ; Put function 0 request in the AX register
INT 33H  ; Call mouse interrupt 51 (33 hex)

If successful, the driver will return -1 in the AX register and the number of buttons on the mouse in the BX register. The other registers should not be affected.

Next, to show the mouse cursor execute the code:

1 ⎕INT 51

And in assembler:

MOV AX,1 ; Put function 1 request in the AX register
INT 33H  ; call interrupt 51 (33 hex)

To hide the mouse cursor (useful when scrolling text or between screens):

2 ⎕INT 51

And in assembler:

MOV AX,2 ; Put function 2 request in the AX register
INT 33H  ; call interrupt 51 (33 hex)

Now to get the current mouse position and button status.

To the mouse, the screen is 640 pixels wide by 200 pixels deep. So all x coordinates are in the range 0-639 and all y coordinates 0-199.

Note
these ranges apply to screen modes 0 to 16. Some newer high resolution modes return the actual screen pixel numbers. For example, VGA mode 18 returns 0-639 and 0-479.
3 ⎕INT 51

The x coordinate will be returned in the 3rd element of the result, the y coordinate in the 4th element. The current button status is returned in the 2nd element.

The meaning of the button status value is as follows:

0 no buttons pressed
1 left button pressed
2 right button pressed
3 left and right buttons pressed
4 centre button pressed
5 left and centre pressed
6 right and centre pressed
7 left, right and centre pressed!

And in assembler:

MOV AX,3 ; Put function 3 request in the AX register
INT 33H  ; call interrupt 51 (33 hex)

BX contains the button status, CX the x coordinate and DX the y coordinate.

If you want to set the mouse position to x:y, set the 3rd element to the x coordinate, and the 4th element to the y coordinate viz:

4 0 x y ⎕INT 51

And in assembler:

MOV AX,4 ; Put function 4 request in the AX register
MOV CX,x ; put x position in the CX register
MOV DX,y ; put y position in the DX register
INT 33H  ; call interrupt 51 (33 hex)

To get the button press information …

5 0 ⎕INT 51     ⍝ Left button
5 1 ⎕INT 51     ⍝ Right button
5 2 ⎕INT 51     ⍝ Centre button

These calls will return four values, the status of the requested button (see above), the count of the number of button presses (reset to zero on each call), the x coordinate at the last button press, and the y coordinate in the 4th element.

So in assembler for the left button only:

MOV AX,5 ; Put function 5 request in the AX register
MOV BX,0 ; left button request 0, right 1, centre 2
INT 33H  ; call interrupt 51 (33 hex)

On return the AX contains the button status, BX the count of the number of presses, CX the x coordinate and DX the y coordinate.

For the button release information use function call 6 e.g. Left button:

6 0 ⎕INT 51

To set the mouse movement limits use functions 7 (x coordinate) and 8 (y coordinate). This function is useful to "trap" the mouse within a window on the screen by "boxing" it in. (Hence the expression "window-box" or is it a "box-window"?):

7 0 xmin xmax ⎕INT 51
8 0 ymin ymax ⎕INT 51

And in assembler:

MOV AX,7    ; Put function 7(8) request in the AX register
MOV CX,xmin ; set x(y) limit minimum
MOV DX,xmax ; set x(y) limit maximum
INT 33H     ; call interrupt 51

Lastly, did you know that the international unit of mouse movement is called a "Mickey", one mickey being about 1⁄200 inch!

This should be all you need to know to build a simple mouse trap!

Appendix 1: Function Listings

    ∇ MS∆INIT CU;RC
[1]  ⍝ Initialize mouse ... sets global ⍙mouse←1 if OK ... else 0
[2]  ⍝ CU is the cursor type ... 0=mouse block; 1=hardware cursor
[3]   RC←0 ⎕INT 51 ⋄ ⍙mouse←0≠1↑RC ⋄ →⍙mouse↓0
[4]   →CU↓0 ⋄ RC← 10 1 ⎕INT 51
    ∇

    ∇ MS∆SHOW;R
[1]  ⍝ Show mouse cursor
[2]   →⍙mouse↓0 ⋄ R←1 ⎕INT 51
    ∇

    ∇ MS∆HIDE;R
[1]  ⍝ Hide mouse cursor
[2]   →⍙mouse↓0 ⋄ R←2 ⎕INT 51
    ∇

    ∇ R←MS∆QCU;RC;XY
[1]  ⍝ Query row/col for cursor
[2]   R← 0 0 ⋄ →⍙mouse↓0
[3]   RC←3 ⎕INT 51
[4]   XY←RC[3 4]
[5]   R←⌽⌊0.125×XY
    ∇

    ∇ MS∆CU POS;XY;RC
[1]  ⍝ Place mouse at row,col
[2]   →⍙mouse↓0
[3]   XY←8×⌽2↑,POS
[4]   RC←(4,0,XY)⎕INT 51
    ∇

    ∇ R←MS∆Q BTN;RC;XY;CT
[1]  ⍝ Query number of presses and row/col for button <btn>
[2]  ⍝ BTN←0 ... left; BTN←1 ... right; BTN←2 ... both together
[3]   R←3⍴0 ⋄ →⍙mouse↓0
[4]   RC←(5,BTN)⎕INT 51
[5]   CT←RC[2] ⋄ XY←RC[3 4]
[6]   R←CT,⌽⌊0.125×XY
    ∇

    ∇ R←MS∆QR BTN;RC;XY;CT
[1]  ⍝ Query number of releases and cursor row/col for <btn>
[2]  ⍝ BTN←0 ... left; BTN←1 ... right; BTN←2 ... both together
[3]   R←3⍴0 ⋄ →⍙mouse↓0
[4]   RC←(6,BTN)⎕INT 51
[5]   CT←RC[2] ⋄ XY←RC[3 4]
[6]   R←CT,⌽⌊0.125×XY
    ∇

    ∇ MS∆WIN POS;XY;RC;SIZE
[1]  ⍝ Set Mouse Window .... as per ⎕WIN i.e. offset,size
[2]   →⍙mouse↓0
[3]   POS←4↑,POS
[4]   XY←8×⌽2↑POS ⋄ SIZE←8×⌽2↓POS
[5]   RC←(7,0,XY[1],XY[1]+SIZE[1])⎕INT 51
[6]   RC←(8,0,XY[2],XY[2]+SIZE[2])⎕INT 51
    ∇

Appendix 2

Summary of all known (to me) mouse interrupts (in HEX):

00 Initialize mouse
01 Show mouse cursor
02 Hide mouse cursor
03 Get mouse position
04 Set mouse position
05 Get "button press" information
06 Get "button release" information
07 Set mouse X limits
08 Set mouse Y limits
09 Set graphics cursor shape
0A Set text cursor type
0B Read motion counters
0C Set user defined event handler
0D Start light pen emulation
0E Stop light pen emulation
0F Set mickey-to-pixel ratio
10 Conditional cursor off (a "mouse hole" on the screen)
13 Set double speed threshold
No, I don’t know what happened to 11 and 12
14 Swap user event handlers
15 Get "save state" storage size
16 Save mouse driver state
17 Restore mouse driver state
18 Set alternate mouse user handler
19 Get user alternate interrupt vector
1A Set mouse sensitivity
1B Get mouse sensitivity
1C Set interrupt rate
1D Set CRT page number
1E Get CRT page number
1F Disable mouse driver (the mind boggles!)
20 Enable mouse driver
21 Software reset
22 Set message language
23 Get message language
24 Interrogate mouse ("We have ways to make you squeak")
2A Life, the universe and everything.

Reference

DOS Programmer’s Reference, 2nd edition. Terry Dettmann. QUE. ISBN 0-88022-458-4