# Mouse Interactions

Introduction

Mouse objects are obtained from the mouse attribute of a display object such as scene. For example, to obtain mouse input from the default window created by Visual, refer to scene.mouse. For basic examples of mouse handling, see Click example and Drag example.

A mouse object has a group of attributes corresponding to the current state of the mouse. It also has functions getevent() and getclick(), which return an object with similar attributes corresponding to the state of the mouse when the user last did something with the mouse buttons. If the user has not already done something with the mouse buttons, getevent() and getclick() will stop program execution until this happens.

Different kinds of mouse

The mouse routines can handle a three-button mouse, with "left", "right", and "middle" buttons. For systems with a two-button mouse, the "middle" button consists of the left and right buttons pressed together. For systems with a one button mouse, the right button is invoked by holding down the SHIFT key, and the middle button is invoked by holding down the CTRL key.

Current state of mouse

pos The current 3D position of the mouse cursor; scene.mouse.pos. Visual always chooses a point in the plane parallel to the screen and passing through display.center. (See Projecting mouse information onto a given plane for other options.)

button = None (no buttons pressed), 'left', 'right', 'middle', or 'wheel' (scroll wheel pressed on some Windows mouses). Example: scene.mouse.button == 'left' is true if the left button is currently down.

pick The nearest object in the scene which falls under the cursor, or None. At present only spheres, boxes, cylinders, and convex can be picked. The picked object is scene.mouse.pick.

pickpos The 3D point on the surface of the picked object which falls under the cursor, or None; scene.mouse.pickpos.

camera The read-only current position of the camera as positioned by the user, scene.mouse.camera. For example, mag(scene.mouse.camera-scene.center) is the distance from the center of the scene to the current position of the camera. If you want to set the camera position and direction by program, use scene.forward and scene.center, described in Controlling Windows.

ray A unit vector pointing from camera in the direction of the mouse cursor. The points under the mouse cursor are exactly { camera + t*ray for t>0}.

The camera and ray attributes together define all of the 3D points under the mouse cursor.

project() Projects position onto a plane. See Projecting mouse position onto a given plane.

alt = 1 if the ALT key is down, otherwise 0

ctrl = 1 if the CTRL key is down, otherwise 0 (for a one-button mouse, meaningful only if mouse buttons up)

shift = 1 if the SHIFT key is down, otherwise 0 (for a one-button mouse, meaningful only if mouse buttons up)

Note that programs that depend on modifying a mouse event with CTRL or SHIFT will not work properly with a one-button mouse (e.g. most Macintosh systems), since CTRL invokes "middle" button, and SHIFT invokes "right" button.

Getting events

There are four kinds of mouse events: press, click, drag, and drop:

A press event occurs when a mouse button is depressed.

A click event occurs when all mouse buttons are released with no or very slight movement of the mouse.
Note that a click event happens when the mouse button is released. See Click example.

A drag event occurs when the mouse is moved slightly after a press event, with mouse buttons still down.
This can be used to signal the beginning of dragging an object. See Drag example.

A drop event occurs when the mouse buttons are released after a drag event.

Between a drag event (start of dragging) and a drop event (end of dragging), there are no mouse events but you can examine the continuously updated position of the mouse indicated by scene.mouse.pos. Here is how to tell that an event has happened, and to get information about that event:

events The number of events (press, click, drag, or drop) which have been queued; e.g. scene.mouse.events.
scene.mouse.events = 0 may be used to discard all input. No value other than zero can be assigned.

getevent() Obtains the earliest mouse event and removes it from the input queue. If no events are waiting in the queue (that is, if scene.mouse.events is zero), getevent() waits until the user enters a mouse event (press, click, drag, or drop). getevent() returns an object with attributes similar to a mouse object: pos, button, pick, pickpos, camera, ray, project(), alt, ctrl, and shift. These attributes correspond to the state of the mouse when the event took place. For example, after executing mm = scene.mouse.getevent() you can look at the various properties of this event, such as mm.pos, mm.pick, mm.drag (see below), etc.

If you are interested in every type of event (press, click, drag, and drop), you must use events and getevent(). If you are only interested in left click events (left button down and up without significant mouse movement), you can use clicked and getclick():

clicked The number of left clicks which have been queued; e.g. scene.mouse.clicked.
This does not include a count of nonclick events (press, drag, or drop).

getclick() Obtains the earliest mouse left click event (pressing the left button and releasing it in nearly the same position) and removes it from the input queue, discarding any earlier press, drag, or drop events. If no clicks are waiting in the queue (that is, if scene.mouse.clicked is zero), getclick() waits until the user clicks. Otherwise getclick() is just like getevent().

It is a useful debugging technique to insert scene.mouse.getclick() into your program at a point where you would like to stop temporarily to examine the scene. Then just click to proceed.

Additional information obtained with getevent() or getclick()

In addition to the information available with scene.mouse, getevent() and getclick() furnish this additional information:

press = 'left' or 'right' or 'middle' for a press event, or None

click = 'left' or 'right' or 'middle' for a click event, or None; in this case pos and other attributes correspond to the state of the mouse at the time of the original press event, so as not to lose initial position information. See Click example.

drag = 'left' or 'right' or 'middle' for a drag event, or None; in this case pos and other attributes correspond to the state of the mouse at the time of the original press event, so as not to lose initial position information. See Drag example.

drop = 'left' or 'right' or 'middle' for a drop event, or None

release = 'left' or 'right' or 'middle' following click and drop events, indicating which button was released, or None

Normally, dragging with right or middle button represents spin or zoom, and is handled automatically by Visual, so you can check for left-button drag or drop events simply by checking whether drag or drop is true (in Python, a nonempty string such as 'left' is true, None is false). Unless you disable user zoom (scene.userzoom = 0), click, drag, and drop with the middle button are invisible to your program. Unless you disable user spin (scene.userspin = 0), click, drag, and drop with the right button are invisible to your program.

Projecting mouse position onto a given plane

Here is a way to get the mouse position relative to a particular plane in space:

## temp = scene.mouse.project(normal=(0,1,0), point=(0,3,0))

if temp: # temp is None if no intersection with plane

ball.pos = temp

This projects the mouse cursor onto a plane that is perpendicular to the specified normal. If point is not specified, the plane passes through the origin. It returns a 3D position, or None if the projection of the mouse misses the plane.

In the example shown above, the user of your program will be able to use the mouse to place balls in a plane parallel to the xy plane, a height of 3 above the xy plane, no matter how the user has rotated the point of view.

You can instead specify a perpendicular distance d from the origin to the plane that is perpendicular to the specified normal. The example above is equivalent to

## temp = scene.mouse.project(normal=(0,1,0), d=3)