Copyright (c) Hyperion Entertainment and contributors.

Intuition Mouse

From AmigaOS Documentation Wiki
Jump to navigation Jump to search

Intuition Mouse

The Amiga mouse is a small, hand-held input device connected to the Amiga by a flexible cable. The user can input horizontal and vertical coordinates with the mouse by sliding it around on a smooth surface. This movement causes the repositioning of a pointer on the display; whenever the mouse is moved the pointer moves, and in the same direction.

The mouse also provides two or three input keys, called mouse buttons, that allow the user to input information to the computer. The basic activities the user can perform with the mouse are shown below.

Mouse Activities
Action Explanation
Moving the Mouse Sliding the body of the mouse over a surface, such as a desk top.
Pressing a button Pushing down a mouse button (which is released at some later time).
Clicking a button Quickly pressing and releasing a mouse button.
Double clicking a button Clicking a button twice in a short period of time.
Dragging Pressing a button and moving the mouse while the button is held down. The drag operation is completed by releasing the button.

The action associated with mouse button presses can occur when the button is first pressed, or while the button is held down, or when the button is released. As an example of this, consider the drag gadget of a window. When the select button of the mouse is first pressed an outline representing the window frame is drawn. While the button is held down the outline remains, and it moves with the pointer as the mouse is moved. When the button is released, the outline is erased and the window takes its new position.

Intuition's Use of Mouse Events

When the mouse is moved or its buttons are pressed, the system generates input events that represent the actions. The input events are taken from the input chain by Intuition when the active window requires the events. Note that only input for a specific window will be affected by changes in that window's IDCMP flags.

Most events generated by the user with the mouse are used by Intuition.

As the user moves the mouse, Intuition changes the position of its pointer. The Intuition pointer moves around the entire video display, mimicking the user's movement of the mouse. The user points at an object by positioning the hot spot of the pointer over the object. The hot spot is the active part of the pointer image; the hot spot for Intuition's default pointer is the pixel at the tip of the arrow.

After pointing to an object, the user can perform some action on that object by selecting it with one of the mouse buttons. These can include any of the actions specified above, such as dragging or double clicking.

The left mouse button is generally used for selection, while the right mouse button is most often used for information transfer. The terms selection and information are intentionally left open to some interpretation, as it is impossible to imagine all the possible uses for the mouse buttons.

The selection/information paradigm can be crafted to cover most interaction between the user and an application. When using the mouse, the application should emphasize this model. It will help the user to understand and remember the mouse control of the application.

Applications that handle mouse button events directly, bypassing the menu and gadget systems, should use the same selection/information model used by Intuition.

Select Button

When the user presses the left, or select button, Intuition examines the state of the system and the position of the pointer. This information is used to decide whether or not the user is trying to select some object, operation, or option. For example, the user positions the pointer over a gadget and then presses the left button to select that gadget. Alternatively, the user can position the pointer over a window and press the select button to activate the window. The pointer is said to be over an object when the pointer's hot spot is positioned within the selection region of the object.

A number of other common techniques involving the select button are available. They include:

Drag Select
Multiple objects or an extended area may be selected by dragging the mouse over a range with the select button held down. For instance, multiple icons can be selected in a Workbench window by pressing the select button while the pointer is over the background of the window (not an icon or a system gadget) and then moving the mouse with the select button held down. A selection rectangle will be displayed and all icons within the rectangle will be selected. Similarly, the user may highlight blocks of text in a console window by pressing the select button over the first desired character and dragging the mouse to the last desired character while holding the button down.
Multi-Select or Shift Select
Another way to select multiple objects or an extended area is through the shift select technique. First, select the first member of the group of objects in the normal way. Additional objects can be added to the group by holding down the Shift key while the select button is pressed. This technique works with Workbench icons, where icons may be added one-at-a-time to the list of selected icons; and with text in a console window, where the selected text is extended to include the new position. Note that text need not operate this way, and the application may allow multiple discrete blocks to be selected at any given time.
Cancel Drag Operation
Both drag select and the dragging of individual objects may often be canceled by pressing the right mouse button before completing the drag operation (before releasing the select button). Examples of this include window dragging and sizing, and positioning of Workbench icons.

Menu Button

The right mouse button is used to initiate and control information gathering processes. Intuition uses this button most often for menu operations.

For most active windows, pressing the menu button will display the window's menu bar at the top of the screen. Dragging the mouse with the menu button depressed allows the user to browse through the available menus. Releasing the right mouse button over a menu item will select that item, if it is a valid choice. Additionally, the user can select multiple items by repeatedly pressing the select button while the menu button is held down.

Drag selection is also available in menu operations. When the menu system is activated, and the user has the menu button pressed, the select button may be pressed and the mouse dragged over all items to be selected. This only works if the select button is pressed after the menu button, and all items that the pointer travels over will be selected.

Double clicking the right mouse button can bring up a special requester for extended exchange of information. This requester is called the double-menu requester, because a double click of the menu button is required to reveal it, and because this requester acts like a super menu through which a complex exchange of information can take place. Because the requester is used for the transfer of information, it is appropriate that this mechanism is called up by using the right button.

The programmer should consult the Amiga User Interface Style Guide for more information on the standard uses of the mouse and its buttons.

Button activation and mouse movements can be combined to create compound instructions. For example, Intuition combines multiple mouse events when displaying the menu system. While the right button is pressed to reveal the menu items of the active window, the user can move the mouse to position the pointer and display different menu items and sub-items. Additionally, multiple presses of the left button can be used to select more than one option from the menus.

Dragging can have different effects, depending on the object being dragged. Dragging a window by the drag gadget will change the position of the window. Dragging a window by the sizing gadget will change the size of the window. Dragging a range in a Workbench window will select all of the icons in the rectangular range.

Mouse Messages

Mouse events are broadcast to the application via the IDCMP or the console device. See Intuition Input and Output Methods for information on the IDCMP. See the Console Device for more about the console device.

Simple mouse button activity not associated with any Intuition function will be reported to the window as an IntuiMessage with a Class of IDCMP_MOUSEBUTTONS. The IntuiMessage Code field will be set to SELECTDOWN, SELECTUP, MIDDLEDOWN, MIDDLEUP, MENUDOWN or MENUUP to specify changes in the state of the left, middle and right buttons, respectively.

Direct select button events will not be received by the program if the select button is pressed while the pointer is positioned over a gadget or other object which uses the button event. For example, select button activity over a gadget is reported with a Class of IDCMP_GADGETDOWN or IDCMP_GADGETUP. The gadget is said to have consumed the mouse events and produced gadget events.

If the menu system is enabled, menu selections appear with a Class of IDCMP_MENUPICK. To directly receive menu button events, the application must set the flag WFLG_RMBTRAP for the window either when the window is opened or by changing the flag in a single, atomic operation. See Intuition Windows for more information on the flag WFLG_RMBTRAP.

The program receives mouse position changes in the event Class IDCMP_MOUSEMOVE. The MouseX and MouseY position coordinates describe the position of the mouse relative to the upper left corner of the reference window. These coordinates are always in the resolution of the screen being used, and may represent any pixel position on the screen, even though the hardware sprites can be positioned only on the even numbered pixels of a high resolution screen and on the even numbered rows of an interlaced screen. Enabling IDCMP_MOUSEMOVE messages is discussed below in the section on "The Pointer".

To get mouse movement reported as deltas (amount of change from the last position) instead of as absolute positions, set the IDCMP flag IDCMP_DELTAMOVE. When IDCMP_DELTAMOVE is set, the IDCMP_MOUSEMOVE messages received by the program will have delta values rather than absolute values. Note that IDCMP_DELTAMOVE is simply a flag used to modify the behavior of IDCMP_MOUSEMOVE, and that no messages of class IDCMP_DELTAMOVE are ever sent.

Each window has a queue limit for the number of IDCMP_MOUSEMOVE messages waiting on its IDCMP at any given time. If the number of mouse move messages waiting at the IDCMP is equal to the queue limit, then Intuition will discard additional IDCMP_MOUSEMOVE messages until the application replies to one of the queued mouse move messages. The default queue limit for mouse move messages is five.

Be aware that this may cause some data loss, especially when the application is using IDCMP_DELTAMOVE, as the information contained in the discarded messages is not repeated. When using IDCMP_DELTAMOVE, this could cause the application to lose track of the actual pointer position. The application may wish to change the default mouse queue size if it is unable to reply to messages queued at the IDCMP for an extended period. The mouse queue can be set when the window is opened by using the WA_MouseQueue tag, and may later be modified using the SetMouseQueue() call. Note that the actual mouse position is always available to the application through the Window structure MouseX and MouseY.

Mouse Usage Example

The example program below shows the use of IDCMP_MOUSEBUTTONS, IDCMP_MOUSEMOVE and DoubleClick(). DoubleClick() is used to test the interval between two times and determine if the interval is within the user specified time for double clicking as set in the Preferences Input editor.

BOOL DoubleClick( ULONG sSeconds, ULONG sMicros,
                  ULONG cSeconds, ULONG cMicros );

The sSeconds and sMicros arguments specify a timestamp value describing the start of the double click time interval to be tested. The cSeconds and cMicros arguments specify a timestamp value describing the end of the double click time interval to be tested.

DoubleClick() returns TRUE if the time interval was short enough to qualify as a double-click. A FALSE return indicates that the time interval between presses took too long. The button presses should be treated as separate events in that case.

/*
** mousetest.c - Read position and button events from the mouse.
*/
#include <exec/types.h>
#include <intuition/intuition.h>
#include <graphics/gfxbase.h>
#include <devices/inputevent.h>
 
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/utility.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
 
#define BUFSIZE 16
 
/* something to use to track the time between messages
** to test for double-clicks.
*/
typedef struct myTimeVal
    {
    ULONG LeftSeconds;
    ULONG LeftMicros;
    ULONG RightSeconds;
    ULONG RightMicros;
    } MYTIMEVAL;
 
 
/* our function prototypes */
VOID doButtons(struct IntuiMessage *msg, MYTIMEVAL *tv);
VOID process_window(struct Window *win);
 
struct IntuitionIFace *IIntuition;
struct GfxBase       *GfxBase;  /* we need GfxBase->DefaultFont */
struct GraphicsIFace *IGraphics;
 
/*
** main() -- set-up everything.
*/
int main(int argc, char **argv)
{
struct Window *win;
struct Screen *scr;
struct DrawInfo *dr_info;
ULONG width;
 
struct Library *IntuitionBase = IExec->OpenLibrary("intuition.library", 50);
IIntuition = (struct IntuitionIFace*)IExec->GetInterface(IntuitionBase, "main", 1, NULL);
 
GfxBase = (struct GfxBase *)IExec->OpenLibrary("graphics.library", 50);
IGraphics = (struct GraphicsIFace*)IExec->GetInterface((struct Library*)GfxBase, "main", 1, NULL);
 
if (IIntuition != NULL && IGraphics != NULL)
    {
        /* Lock the default public screen in order to read its DrawInfo data */
        if (scr = IIntuition->LockPubScreen(NULL))
            {
            if (dr_info = IIntuition->GetScreenDrawInfo(scr))
                {
                /* use wider of space needed for output (18 chars and spaces)
                 * or titlebar text plus room for titlebar gads (approx 18 each)
                 */
                width = max((GfxBase->DefaultFont->tf_XSize * 18),
                            (18 * 2) + IGraphics->TextLength(&scr->RastPort,"MouseTest",9));
 
                if (win = IIntuition->OpenWindowTags(NULL,
                            WA_Top,    20,
                            WA_Left,   100,
                            WA_InnerWidth,  width,
                            WA_Height, (2 * GfxBase->DefaultFont->tf_YSize) +
                                       scr->WBorTop + scr->Font->ta_YSize + 1 +
                                       scr->WBorBottom,
                            WA_Flags, WFLG_DEPTHGADGET | WFLG_CLOSEGADGET |
                                      WFLG_ACTIVATE    | WFLG_REPORTMOUSE |
                                      WFLG_RMBTRAP     | WFLG_DRAGBAR,
                            WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_RAWKEY |
                                      IDCMP_MOUSEMOVE   | IDCMP_MOUSEBUTTONS,
                            WA_Title, "MouseTest",
                            WA_PubScreen, scr,
                            TAG_END))
                    {
                    IDOS->Printf("Monitors the Mouse:\n");
                    IDOS->Printf("    Move Mouse, Click and DoubleClick in Window\n");
 
                    SetAPen(win->RPort,dr_info->dri_Pens[TEXTPEN]);
                    SetBPen(win->RPort,dr_info->dri_Pens[BACKGROUNDPEN]);
                    SetDrMd(win->RPort,JAM2);
 
                    process_window(win);
 
                    IIntuition->CloseWindow(win);
                    }
                IIntuition->FreeScreenDrawInfo(scr, dr_info);
                }
            IIntuition->UnlockPubScreen(NULL,scr);
            }
    }
 
IExec->DropInterface((struct Interface*)IGraphics);
IExec->CloseLibrary((struct Library *)GfxBase);
 
IExec->DropInterface((struct Interface*)IIntuition);
IExec->CloseLibrary(IntuitionBase);
 
return 0;
}
 
 
/*
** process_window() - simple message loop for processing IntuiMessages
*/
VOID process_window(struct Window *win)
{
BOOL done;
struct IntuiMessage *msg;
MYTIMEVAL tv;
UBYTE prt_buff[14];
LONG xText, yText;  /* places to position text in window. */
 
done = FALSE;
tv.LeftSeconds = 0; /* initial values for testing double-click */
tv.LeftMicros  = 0;
tv.RightSeconds = 0;
tv.RightMicros  = 0;
xText = win->BorderLeft + (win->IFont->tf_XSize * 2);
yText = win->BorderTop + 3 + win->IFont->tf_Baseline;
 
while (!done)
    {
    IExec->Wait((1L<<win->UserPort->mp_SigBit));
 
    while ((!done) &&
           (msg = (struct IntuiMessage *)IExec->GetMsg(win->UserPort)))
        {
        switch (msg->Class)
            {
            case IDCMP_CLOSEWINDOW:
                done = TRUE;
                break;
            /* NOTE NOTE NOTE:  If the mouse queue backs up a lot, Intuition
            ** will start dropping MOUSEMOVE messages off the end until the
            ** queue is serviced.  This may cause the program to lose some
            ** of the MOUSEMOVE events at the end of the stream.
            **
            ** Look in the window structure if you need the true position
            ** of the mouse pointer at any given time.  Look in the
            ** MOUSEBUTTONS message if you need position when it clicked.
            ** An alternate to this processing would be to set a flag that
            ** a mousemove event arrived, then print the position of the
            ** mouse outside of the "while (GetMsg())" loop.  This allows
            ** a single processing call for many mouse events, which speeds
            ** up processing A LOT!  Something like:
            **
            ** while (GetMsg())
            **    {
            **    if (class == IDCMP_MOUSEMOVE)
            **        mouse_flag = TRUE;
            **    ReplyMsg();   NOTE: copy out all needed fields first !
            **    }
            ** if (mouse_flag)
            **    {
            **    process_mouse_event();
            **    mouse_flag = FALSE;
            **    }
            **
            ** You can also use IDCMP_INTUITICKS for slower paced messages
            ** (all messages have mouse coordinates.)
            */
            case IDCMP_MOUSEMOVE:
                /* Show the current position of the mouse relative to the
                ** upper left hand corner of our window
                */
                IGraphics->Move(win->RPort,xText,yText);
                IUtility->SNPrintf(prt_buff, sizeof(prt_buff), "X%5ld Y%5ld", msg->MouseX, msg->MouseY);
                IGraphics->Text(win->RPort,prt_buff,13);
                break;
            case IDCMP_MOUSEBUTTONS:
                doButtons(msg,&tv);
                break;
            }
        IExec->ReplyMsg((struct Message *)msg);
        }
    }
}
 
/*
** Show what mouse buttons where pushed
*/
VOID doButtons(struct IntuiMessage *msg, MYTIMEVAL *tv)
{
/* Yes, qualifiers can apply to the mouse also.  That is how
** we get the shift select on the Workbench.  This shows how
** to see if a specific bit is set within the qualifier
*/
if (msg->Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
    printf("Shift ");
 
switch (msg->Code)
    {
    case SELECTDOWN:
        IDOS->Printf("Left Button Down at X%ld Y%ld", msg->MouseX, msg->MouseY);
        if(IIntuition->DoubleClick(tv->LeftSeconds, tv->LeftMicros, msg->Seconds, msg->Micros))
            IDOS->Printf(" DoubleClick!");
        else
            {
            tv->LeftSeconds = msg->Seconds;
            tv->LeftMicros  = msg->Micros;
            tv->RightSeconds = 0;
            tv->RightMicros  = 0;
            }
        break;
    case SELECTUP:
        IDOS->Printf("Left Button Up   at X%ld Y%ld", msg->MouseX, msg->MouseY);
        break;
    case MENUDOWN:
        IDOS->Printf("Right Button down at X%ld Y%ld", msg->MouseX, msg->MouseY);
        if(IIntuition->DoubleClick(tv->RightSeconds, tv->RightMicros, msg->Seconds, msg->Micros))
            IDOS->Printf(" DoubleClick!");
        else
            {
            tv->LeftSeconds = 0;
            tv->LeftMicros  = 0;
            tv->RightSeconds = msg->Seconds;
            tv->RightMicros  = msg->Micros;
            }
        break;
    case MENUUP:
        IDOS->Printf("Right Button Up   at X%ld Y%ld", msg->MouseX, msg->MouseY);
        break;
    }
IDOS->Printf("\n");
}

Function Reference

The following are brief descriptions of the Intuition functions that relate to the use of the mouse under Intuition. See the SDK for details on each function call.

Function Description
DoubleClick() Test two time values for double click status.
SetMouseQueue() Change the mouse queue for an open window.
ReportMouse() A function C programmers should not use.