Mice do it on the Mat
Vector 7:3, page 130
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:
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:
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:
And in assembler:
To hide the mouse cursor (useful when scrolling text or between screens):
And in assembler:
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.
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:
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:
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 …
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:
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"?):
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