Application Development |
This chapter shows how to evaluate and process mouse events, mouse data, and contextual information. Topics include:
Trapping Mouse Events |
You can intercept single and double mouse clicks on an application-wide basis through Panther's key change hook function. You can also intercept double clicking on an individual widget through its Double Click property. Both techniques are discussed in the sections that follow.
With Panther's key change hook function, you can intercept single and double mouse clicks throughout the program. Panther's key file (smkeys.h
) defines these two events through the logical keys MOUS
for single mouse clicks, and MDBL
for double clicks. A key change function that tests for these logical keys can use Panther library functions to examine the state of the mouse cursor and mouse buttons, and perform special processing accordingly.
For example, the following code shows in skeletal format a key change function that tests for a single click mouse event outside a field, and then determines which button, if any, is down. It also conditionally tests for different combinations of mouse events with keyboard modifiers, such as Shift+click versus Ctrl+click. Most of the processing relies on sm_ms_inquire to test the mouse's state. For detailed information on using this function, refer to page 47-4. For more information on key change functions, refer to page 44-36.
int keychg ( int which_key )
{
int ms_btn;
switch ( which_key )
{
case MOUS:
/*is mouse click outside field? */
if ( sm_ms_inquire( MOUSE_FIELD ) < 0
{
ms_btn = ( sm_ms_inquire( MOUSE_BUTTONS ) & 0x49;
/*is any button down?*/
if ( ms_btn > 0 )
{
/*test which button is down*/
switch ( mouse_button )
{
...
}
/*is any keyboard modifier also down */
if ( sm_ms_inquire( MOUSE_SHIFT ))
{
ms_kbd = sm_ms_inquire( MOUSE_SHIFT );
switch ( ms_kbd ) /*which key is down? */
{
...
}
...
}
Several widget types have the double_click
property, which lets you specify an action that is triggered by double clicking on a widget. double_click
gets a control string as its value. This control string can specify to call a function, invoke an operating system command, or open another screen.
The following widget types have the double_click
property:
Getting Mouse Data |
Panther provides library functions and application properties that get information about the mouse's current state:
The library function sm_ms_inquire lets you test the last mouse click's line and column location on a Panther screen or on the physical display. Several runtime properties also offer access to the field and screen on which the last mouse click occurred.
To determine the line and column location of the last mouse click, supply The previous example also uses sm_ms_inquire and sm_prop_get_str to test whether a mouse click occurred inside a field and the field's identity:
When supplied an argument of You can also use these runtime properties to get the name of the field and occurrence in which a mouse click occurred:
Determining Mouse Click Location
Identifying Mouse Coordinates
sm_ms_inquire
with arguments of MOUSE_LINE
and MOUSE_COLM
, respectively. To get the mouse click's line and column within a Panther screen, supply MOUSE_FORM_LINE
and MOUSE_FORM_COLM
. For example, the following routine gets the mouse click coordinates on a map that is displayed on a static label:
void get_mouse_coords( void )
{
int longitude, latitude;
/* make sure the user clicked somewhere on the map */
if ( sm_ms_inquire( MOUSE_FIELD ) > 0 &&
sm_prop_get_str
( PR_APPLICATION, PR_MOUSE_FIELD_NAME ) == "mapLbl" )
{
longitude = sm_ms_inquire( MOUSE_FORM_COLM );
latitude = sm_ms_inquire( MOUSE_FORM_LINE );
return get_map_location( longitude, latitude );
}
}
Mouse and Widgets
if ( sm_ms_inquire( MOUSE_FIELD ) > 0 &&
sm_prop_get_str
( PR_APPLICATION, PR_MOUSE_FIELD_NAME ) == "mapLbl" )
MOUSE_FIELD
, sm_ms_inquire
returns either the field number in which the mouse click occurred, or -1 if the mouse click occurred outside the field.
mouse_field
and mouse_field_name
respectively get the number and name of the field in which the last mouse click occurred.
mouse_field_occ
gets the number of the occurrence in which the last mouse click occurred.
All mouse properties are application-level properties, accessible through the You can get the state of each mouse button—up, down, just pressed, or just released—by supplying sm_ms_inquire an argument of Each bit within a three-bit segment can be set as follows, from lowest- to highest-order bit:
@app()
modifier. For example, this all-purpose code obtains the data in the last clicked-on occurrence of any field:
vars data
data = @widget(@app()->mouse_field_name)[@app()->mouse_field_occ]
Mouse and Screen
mouse_form_name
is an application runtime property that gets the name of the screen on which a mouse click occurred. Like other mouse properties, it is accessible through the @app()
modifier as in this example:
vars mouse_screen
mouse_screen = @app()->mouse_form_name
Determining Mouse Button State
MOUSE_BUTTONS
. If successful, the function returns an integer bit mask. The function puts the requested data in three segments of three bits each, where each segment represents one of three mouse buttons—left, middle, and right. The three lowest-order bits contain left button data; if the mouse has only one button, only these bit settings are significant. The middle three bits contain right button data. The three highest-order bits contain data for the middle button, if any.
For example, the bit settings returned for a just-initiated point and click operation—left button is down and just pressed—can be represented as follows:
A click and drag operation that is in progress—right button is down—can be represented like this:
Only four combinations of bit settings are meaningful to Panther and recognized as representing valid button states:
For example, the following routine tests whether any mouse buttons are down: it bitwise By supplying sm_ms_inquire with an argument of AND's
sm_ms_inquire's
return value with 0x49, thereby masking off all but the first, fourth, and seventh-order bits:
/*find out whether any button is down */
int is_any_button_down( void )
{
return sm_ms_inquire ( MOUSE_BUTTONS ) & 0x49;
}
Identifying Keyboard Modifiers
MOUSE_SHIFT
, you can find out whether a mouse click occurred with one or more of these keys pressed down: Shift, Ctrl, and Alt. The function returns an integer bit mask whose three lowest-order bits are set to indicate which of the three keys, if any, were pressed. These bits are set as follows, from lowest- to highest-order bit:
For example, a return value of 2 (0 1 0) indicates that the Ctrl key is down, while a return value of 5 (1 0 1) indicates that the Alt and Shift keys are both down. The second of these returns can be represented as follows:
In the following example, the return value of sm_mus_time reports the number of milliseconds that elapsed since an unspecified time. You can compare this value to the value reported on previous or subsequent mouse clicks—for example, to determine whether two successive mouse clicks should be interpreted as a double mouse click.
Notes:
Ordinarily, you can use the key change function to intercept double mouse click events. For more information, refer to page 47-1.
sm_ms_inquire
(MOUSE_FIELD
) is bitwise AND's with 0x06 in order to mask off the lowest-order bit (Shift). This lets the program determine whether Alt or Ctrl, or both, were pressed down during the last mouse click:
if ( sm_ms_inquire( MOUSE_SHIFT ))
{
/*test for Alt and Ctrl keys only */
ms_kbd = sm_ms_inquire( MOUSE_SHIFT ) & 0x06;
switch ( ms_kbd )
{
case 0x02: /*Ctrl key is down */
...
break;
case 0x04: /*Alt key is down*/
...
break;
case 0x06: /*Alt+Ctrl keys are down */
...
break;
}
Reporting Elapsed Time between Mouse Clicks
Changing the Mouse Pointer State |
sm_delay_cursor sets the mouse pointer to be either the default cursor or the delay cursor, or gets the mouse pointer's current state, according to the supplied argument. It can also specify to change the cursor's state automatically, depending on whether the application is awaiting input or not.
For GUI platforms, you can set a screen's default cursor through its Pointer property. In Windows and Motif, the default cursor is an arrow. The delay cursor in Windows is an hourglass; in Motif, the delay cursor is usually a wristwatch icon. You can change Motif's default cursor through the pointerShape
resource.
Because character-mode Panther does not change the mouse pointer shape, sm_delay_cursor
resets the background status line message to the value of SM_WAIT
or SM_READY
. Note that you can turn background status messages on and off through sm_setstatus. sm_delay_cursor
takes a single integer argument, one of these constants:
SM_AUTO_BUSY_CURSOR
SM_BUSY_CURSOR
SM_DEFAULT_CURSOR
SM_SAME_CURSOR
SM_TEMP_BUSY_CURSOR