D]4 P]01J:mouse.tutor/Clips/Mouse.title ]]P01 00 ]]P01 01 ]]P01 02 ]]P01 03 BUILDING A BETTER MOUSETRAP ]]P01 04 Using the Mouse ]]P01 05 In AmigaBASIC ]]P01 06 By Tom Beale ]]P01 07 Note: For HiSoft BASIC users, the commands, functions and concepts for dealing with the mouse in HiSoft BASIC are identical to AmigaBASIC. With the exception of the keyboard, the mouse is probably the most important input device for today's computers, allowing the user to visually select and directly manipulate objects on the screen. Not surprisingly, AmigaBASIC has the built-in functions necessary to incorporate the mouse into BASIC programs. This tutorial is an introduction to how these functions are used, how to use the values returned by them, and how different programming techniques can change the way the mouse "handles". 4]THE BASICS OF THE MOUSE() FUNCTION The basis of all mouse activity in BASIC centers on the MOUSE() function. Assuming that "return" is a variable, and "n" represents a number from 0-6, the MOUSE() function uses the following syntax: return = MOUSE(n) Depending on the number used for n, MOUSE() will return different values: MOUSE(0) - This returns the status of the select button. Calling this function also updates MOUSE(1)-MOUSE(6) A zero indicates that the select button has not been pressed since the last call to mouse(0) A nonzero value indicates how many times the select button has been clicked since the last MOUSE(0) call. Positive numbers indicate that the select button has been released. Negative numbers indicate that the button is still down. MOUSE(1) - This returns the current X position of the pointer (at the time MOUSE(0) is called). MOUSE(2) - This returns the current Y position of the pointer (at the time MOUSE(0) is called). MOUSE(3) - X Position of mouse when select button was last pressed (Before the last MOUSE(0)) MOUSE(4) - Y Position of mouse when select button was last pressed (Before the last MOUSE(0)) MOUSE(5) - X Position of mouse when select button was released. If the button is still down, this will be the current X position at the time MOUSE(0) is called. MOUSE(6) - Y Position of mouse when select button was released. If the button is still down, this will be the current Y position at the time MOUSE(0) is called. 4] P R A C T I C A L M O U S E T R A P P I N G 1 0 1 Usually, you will have, somewhere in your program, a subroutine that deals with the mouse. This usually includes a bunch of IF statements, or SELECT/CASE statements that call still other subroutines or subprograms, depending on what it is your program does. With event trapping on, your program will jump to this subroutine automatically each time the select button is pressed. With event trapping off, you will have to check the value returned by MOUSE(0) to determine if the mouse has been pressed and call the correct subroutine if it has. Both approaches have advantages and disadvantages and are more a matter of personal style than correct or incorrect. 4]USING EVENT TRAPPING FOR THE MOUSE AmigaBASIC provides automatic event trapping with the MOUSE command. When this is on, your program drops what it is doing and automatically jumps to a predetermined subroutine whenever the left mouse button is pressed. There are two steps: 1. Tell AmigaBASIC what you want it to do if the mouse button is pressed by using the following command: ON MOUSE GOSUB YourMouseSubroutine 2. Turn Mouse trapping on: MOUSE ON In addition, mouse trapping can be turned off at any time through the statement: MOUSE OFF Last, mouse trapping can be suspended by using the command: MOUSE STOP The difference between MOUSE OFF and MOUSE STOP is that mouse events will be saved and acted upon when mouse trapping is restarted using the MOUSE ON command. To understand why you might want to do this, consider that when mouse trapping is on, your program literally drops what it is doing and reacts to the mouse. If it is in the middle of redrawing the screen, writing a file, etc., it will stop and deal with the mouse event. When it returns, some variables or values may have changed (text color, counter values, etc.), which can have somewhat unpredictable results. It is best to suspend mouse trapping at the beginning of critical subroutines or subprograms and resume it again just before or after returning. 4]WITHOUT EVENT TRAPPING If you are not using the event trap, then you will probably have a routine in your main loop that checks the status of the mouse. This can be done with the following line: IF MOUSE(0) THEN GOSUB YourMouseSubroutine This routine requires no set-up and assumes you are interested only in whether the mouse button has been clicked. If it has not, MOUSE(0) will return 0, and nothing will happen. If it has, MOUSE(0) will return something other than 0, and off the program goes to deal with whatever the user is doing with the mouse (covered a bit later). If you will need the value returned by MOUSE(0), put it in a variable first, then check that. For example: m% = MOUSE(0) IF m% THEN GOSUB YourMouseSubroutine This stores the condition of the mouse in m%, which can be checked later. Note that MOUSE(0) is reset each time it is called. 4]USING THE MOUSE FUNCTIONS For most practical applications, MOUSE(0), MOUSE(1), and MOUSE(2) are all we will need to be concerned with, so we will concentrate on those for now. 4]MOUSE(0) MOUSE(0) performs two distinct functions: 1. Calling it will return select button status and the number of mouse events since the last call to MOUSE(0), 2. Calling it will update MOUSE(1) thru MOUSE(6). If MOUSE(0) is not called, the values returned by the other MOUSE() calls will not change. According to the manual, MOUSE(0) will return a value from -2 to 2, but in actuality (at least in HiSoft Basic) the value can range from -6 to 6. The number indicates the number of mouse-clicks since the last MOUSE(0) call, and the negative sign signifies that the button is still held down (perhaps the mouse is being dragged). While these values may give the impression that double-clicks are easy to obtain, that is not the case. 4]MOUSE(1) and MOUSE(2) Consider the following program: Start: A = MOUSE(0) ' Get Mouse Status and Update MOUSE() X = MOUSE(1) ' Put Pointer Horizontal Location into X Y = MOUSE(2) ' Put Pointer Vertical Location into Y LOCATE 1,1 ' Cursor to Upper Left Corner of Screen PRINT A;" ",X;" ",Y;" " ' Print Mouse Info GOTO Start This program simply prints the mouse coordinates to the screen, but it shows how easily X and Y coordinates can be assigned to variables and used within a program. The SLEEP command is optional, but . . . 4]WHAT ABOUT DOUBLE-CLICKS? At first glance, the MOUSE(0) function seems an easy way to tell if there has been a double-click or not. Unfortunately, this is not the case, and the values returned by MOUSE(0) can be confusing at best. An alternative solution is to use the TIMER function to check the intervals between mouse-clicks, something like the following example: ON MOUSE GOSUB GetMouse MOUSE ON Start: SLEEP GOTO Start GetMouse: ' ------------- Mouse Handler last = a ' put last time into variable last a = TIMER ' get time of this call LOCATE 1,1 PRINT last,a ' Print times IF a - last <.5 THEN ' Less than a half-second between clicks? PRINT "Double Click" ' if yes, ELSE PRINT "Single Click" ' if no END IF RETURN The real-life application of this would vary wildly, depending on a program's needs and function. It might be necessary to stall the subroutine for a half-second or so when it is first entered just to see if there will be another click. 4]MAKING THE MOUSE MORE RESPONSIVE 4] Speeding the Mouse For many mouse operations, such as dragging, creating or resizing something, it becomes important that the operation be done quickly. Unlike menu selections, mouse operations may require hundreds of calls in rapid succession, each time updating variables and redrawing a portion of the screen as something is moved or changed. If this is the case, it is sometimes best to trap the mouse in a subroutine which performs only the necessary functions to deal with the mouse and returns when the select button is released. The code might look something like this: YourSub: ... Setup WHILE MOUSE(0) x% = MOUSE(1) y% = MOUSE(2) ... ... ... WEND ... Update changed data for main program RETURN In the setup portion of the code, any possible calculations are made before the loop actually starts are made. These would include such things as putting the length of a string into a variable so the LEN() function would not have to be called within the loop. The WHILE loop contains only the commands absolutely necessary to give the user the visual feedback for the operation. The update portion of the code takes the final mouse values and applies them to the data sets, updates displays or whatever applies to your program. 4]Slowing the Mouse Another problem with getting mouse input is that the input comes in streams rather than single mouse messages. Your program's main loop may check for the mouse, jump to a routine that selects/deselects something, then return. Problem is, when it returns from the subroutine, if the user's finger is still on the button, the subroutine gets called again. A simple routine can be used to halt the program until the user releases the mouse: WHILE MOUSE(0):WEND This is useful for a selection routine where you only need one click, no matter how long the user holds the button down. This acts as a garbage collector to prevent remnants of one mouse operation from recalling your mouse handler before the user can let go of the button. Conversely, to hold the program until the mouse button is pressed: WHILE NOT MOUSE(0):SLEEP:WEND The SLEEP command is optional but prevents the small loop from bogging down the system when other programs are running in the background. 4]MOUSE(3)-MOUSE(6) The remaining functions are useful for routines that need the starting and ending points of when the mouse button was pressed and released, perhaps to draw a line or reposition an object. These functions might be well suited for programs with many critical routines that cannot be interrupted. 4]ABOUT MOUSETRAP The program included with this article, MouseTrap, is a demonstration of the MOUSE() function. When it is double-clicked, a window opens to show all values currently returned by the MOUSE() function. Beneath the display there are four buttons that allow the program flow to be changed. This allows you to experiment with some of the concepts. The options are: MOUSE OFF/ON This turns mouse event checking on or off. MOUSE (0) called from main loop or when key is pressed. When this button is down, the program will in effect not call MOUSE(0) unless a key is pressed. If event trapping is on (first button), then the mouse will be dealt with when clicked. Otherwise, the program will not see the mouse. To get out of this, click the mouse over the first or second button then press any key. MOUSE(1)-MOUSE(6) continue to be called even when MOUSE(0) is not. The values returned by them remain unchanged until the next call to MOUSE(0). LOOP/SLEEP When pressed, the main loop will stop and wait for input before calling MOUSE(0). This is recommended for "multitasking friendly" applications since a program running a tight loop will slow other programs that may be running at the same time. It is interesting to note, however, that if MOUSE(0) is continuously called, you can monitor the current mouse position even if another application's window is active. TRAP THE MOUSE/DO NOT TRAP MOUSE MouseTrap's main loop calls the subroutine that updates the MOUSE() values every time it loops. When this button is out, this routine simply gets the MOUSE() values, prints them and returns to the main loop. With mouse trapping on, however, the subroutine retains control until the mouse button is released. This becomes apparent when SLEEP is on, which allows the program to stop and wait for messages in a multitasking- friendly manner, yet being responsive to the mouse when the select button is down 4]PARTING SHOT The mouse and the way it works play a large part in the character of the Amiga. In AmigaBASIC it is as easy to deal with the mouse as it is to deal with the keyboard, making it possible to create very professional interfaces with nothing more than a stock Amiga and a little imagination.