Introducing the Mouse


Mouse Presence & Characteristics

In windows, a mouse is usually present and mice usually have two buttons. The presence of a mouse may be determined within a program via the following call.

bool present = (bool)get_system_metrics(system_metric::mouse_present);

The number of buttons present on a mouse may be ascertained via the following statement.

int buttons = get_system_metrics(system_metric::number_mouse_buttons);

In the early days, programs were written to run without a mouse. That is, a keyboard interface that emulated the mouse was present. These days, most programs assume the presence of a two-button mouse.

The two buttons of a mouse may be swapped (for left-handed operators) using the system control panel. Usually, the button that is under the index finger is considered to be the left button (even if it is physically on the right hand side of the mouse). The system metric system_metric::swap_button may be used to ascertain the interpretation placed on the physical buttons - however, this is normally unnecessary programmatically. When three buttons are present on the mouse, the buttons are referred to as the left, middle and right buttons.

The Mouse and the Cursor

A mouse is related to the cursor on the screen. moving the mouse results in the cursor being moved. There are a number of cursors available, with the cursor of the window class usually being cursor_identity::arrow. The hotspot of a mouse is a single pixel within the cursor image. For the arrow cursor, this is the tip of the arrow image. The hotspot of the cursor cursor_identity::cross is the center of the cross hairs pattern. The cursor cursor_identity::wait is an hour glass, and it is generally used to indicate that input is unable to be accepted whilst a task is currently in progress.

The blockout program sets a cursor using the following statement.

set_cursor(load_cursor(0,cursor_identity::cross));

Mouse Messages

A mouse can be used in a number of ways, giving rise to different window messages. A mouse may be

These actions give rise to the following messages.

message::mouse_move
message::left_button_double_click
message::left_button_down
message::left_button_up
message::middle_button_double_click
message::middle_button_down
message::middle_button_up
message::right_button_double_click
message::right_button_down
message::right_button_up

While keyboard input messages (e.g. message::character, message::key_down and message::key_up) are directed only to the window with the input focus, mouse messages are directed to the window under the cursor or to the window that has captured the mouse (capturing the mouse will be discussed shortly). This is the case even if the window does not have the input focus or is not the active window.

Windows defines 21 messages relating to the mouse; however, 11 of these messages relate to the non-client portions of a window. windows applications usually ignore the non-client mouse messages.

When a mouse is moved over the client portion of a window, the operating system generates mouse move messages. A message is not generated for every pixel over which the mouse passes; rather, the number of mouse messages that are received depends upon the mouse hardware and upon the speed with which the application can process the messages. The "connect" program presented later in the chapter gives a feel for how many mouse movements are actually registered by the window.

When the left button of a mouse is clicked upon the client area of an inactive window, the operating system changes the active window to the window that is being selected and then passes it the message message::left_button_down. An application may safely assume that it is the active window upon receiving this message. Despite this, an application may receive the message message::left_button_up without first having received the corresponding button down message. This may happen when a mouse button is depressed when over one window, then dragged and released over another window. Similarly, an application may receive a button down message with no button up message for the same reason. There are two circumstances where this cannot happen:

When the mouse is captured, the operating system continues to direct input to the window even when the mouse leaves the window. In the second case, system modality implies that no input can be directed to other applications until the system modal object is dismissed.

Connecting the Dots

To demonstrate the generation of mouse movement messages, a simple example will be presented. This program does the following.

  1. Upon receiving the message message::left_button_down, the program clears the window.

  2. Upon receiving the message message::mouse_move, the window stores the point in its array of points (held in the client class) and draws a black dot.

  3. Upon receiving the message message::left_button_up, the program connects each dot to every other dot in the registered array.

The output of the program is shown below.

An array of 1000 points is declared within the client data structure, as shown below.

struct window_data
{
    ipoint point_array[maximum_points];
    int count;
};

This array is used to store successive mouse positions. The variable count is incremented to step through this array. The code for mouse move processing is shown below.

    case message::mouse_move:
    {
        window_data* data = (window_data*)get_window_pointer(window_handle, 0);
        if ((int)parameter1 & mouse_state::left_button && data->count < maximum_points)
        {
            data->point_array[data->count](0) = low_part(parameter2);
            data->point_array[data->count++](1) = high_part(parameter2);

            handle device_context = get_device_context(window_handle);
            set_pixel(device_context, low_part(parameter2), high_part(parameter2), 0);
            release_device_context(window_handle, device_context);
        }
    }
    break;

If the flags parameter indicates that the left button is down, the program adds the position to its array of points (with a maximum of maximum_points==1000) and then uses the function set_pixel to draw a single pixel at that point.

When the left button is released, the client area is invalidated, causing a paint message to be generated. Upon receipt of a paint message, the following code is executed.

   case message::paint:
    {
     paint paint_struct;
     handle device_context = begin_paint(window_handle,&paint_struct);

     set_cursor(load_cursor(0,(const character*)cursor_identity::wait));

     for (int i=0; i<Count-1; i++)
      for (int j=i+1; j<Count; j++)
       {
        move_to(device_context,point_array[i](0),point_array[i](1));
        draw_line_to(device_context,point_array[j](0),point_array[j](1));
       }

     set_cursor(load_cursor(0,(const character*)cursor_identity::arrow));

     end_paint(window_handle,&paint_struct);
    }
    break;

The double for loop joins each point in the diagram to every other point, yielding the patterns. The patterns are most obvious when the mouse is moved rapidly in an arc and then released. If the mouse is moved outside the window (with the left button depressed) then back inside the client area, the drawing is continued, but no mouse move messages are generated when the mouse lies outside the client. If the left button is released whilst outside the client, the program gets confused and does not join the dots. This is a case for capturing the mouse. To continue the program in the case when the mouse was released outside the window, the left button must once again be pressed to start again.

The maximum number of points that is stored is 1000. The number of lines that are drawn is (N*(N-1))/2, where N is the number of points utilized. When all 1000 points are utilized, almost 1/2 a million lines are drawn. This is why the cursor is set to an hour glass when painting - because it may take a while.

Mouse Double Clicks

A double-click of the mouse is defined to be two clicks of the mouse in quick succession within a predefined area. The system metrics system_metric::double_click_width and system_metric::double_click_height define the area in which the two clicks must lie. A window only receives double click messages if it is registered with the class style class_style::double_clicks. If the class style does not include class_style::double_clicks, two clicks in rapid succession result in the four messages:

  1. message::left_button_down,
  2. message::left_button_up,
  3. message::left_button_down and
  4. message::left_button_up

being delivered to the window. If class_style::double_clicks is applied to a window, the messages that are delivered are:

  1. message::left_button_down,
  2. message::left_button_up,
  3. message::left_button_double_click and
  4. message::left_button_up;

where, the double click replaces the second left button down message. Given that a double click of the mouse gives rise to a left button down message followed by a left button double click message, it is simpler if the application does one thing for a single click and does that plus more for a double click. If an application does something completely different for single and double clicks, coding may get messy.