/* * @(#)MouseEvent.java 1.49 03/12/19 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.awt.event; import java.awt.Component; import java.awt.Event; import java.awt.GraphicsEnvironment; import java.awt.Point; import java.awt.Toolkit; import java.io.IOException; import java.io.ObjectInputStream; /** * An event which indicates that a mouse action occurred in a component. * A mouse action is considered to occur in a particular component if and only * if the mouse cursor is over the unobscured part of the component's bounds * when the action happens. * Component bounds can be obscurred by the visible component's children or by a * menu or by a top-level window. * This event is used both for mouse events (click, enter, exit) and mouse * motion events (moves and drags). *
* This low-level event is generated by a component object for: *
* A MouseEvent
object is passed to every
* MouseListener
* or MouseAdapter
object which is registered to receive
* the "interesting" mouse events using the component's
* addMouseListener
method.
* (MouseAdapter
objects implement the
* MouseListener
interface.) Each such listener object
* gets a MouseEvent
containing the mouse event.
*
* A MouseEvent
object is also passed to every
* MouseMotionListener
or
* MouseMotionAdapter
object which is registered to receive
* mouse motion events using the component's
* addMouseMotionListener
* method. (MouseMotionAdapter
objects implement the
* MouseMotionListener
interface.) Each such listener object
* gets a MouseEvent
containing the mouse motion event.
*
* When a mouse button is clicked, events are generated and sent to the
* registered MouseListener
s.
* The state of modal keys can be retrieved using {@link InputEvent#getModifiers}
* and {@link InputEvent#getModifiersEx}.
* The button mask returned by {@link InputEvent#getModifiers} reflects
* only the button that changed state, not the current state of all buttons.
* (Note: Due to overlap in the values of ALT_MASK/BUTTON2_MASK and
* META_MASK/BUTTON3_MASK, this is not always true for mouse events involving
* modifier keys).
* To get the state of all buttons and modifier keys, use
* {@link InputEvent#getModifiersEx}.
* The button which has changed state is returned by {@link MouseEvent#getButton}
*
* For example, if the first mouse button is pressed, events are sent in the * following order: *
* id modifiers button ** When multiple mouse buttons are pressed, each press, release, and click * results in a separate event. *MOUSE_PRESSED
:BUTTON1_MASK
BUTTON1
*MOUSE_RELEASED
:BUTTON1_MASK
BUTTON1
*MOUSE_CLICKED
:BUTTON1_MASK
BUTTON1
*
* For example, if the user presses button 1 followed by * button 2, and then releases them in the same order, * the following sequence of events is generated: *
* id modifiers button ** If button 2 is released first, the *MOUSE_PRESSED
:BUTTON1_MASK
BUTTON1
*MOUSE_PRESSED
:BUTTON2_MASK
BUTTON2
*MOUSE_RELEASED
:BUTTON1_MASK
BUTTON1
*MOUSE_CLICKED
:BUTTON1_MASK
BUTTON1
*MOUSE_RELEASED
:BUTTON2_MASK
BUTTON2
*MOUSE_CLICKED
:BUTTON2_MASK
BUTTON2
*
MOUSE_RELEASED
/MOUSE_CLICKED
pair
* for BUTTON2_MASK
arrives first,
* followed by the pair for BUTTON1_MASK
.
*
*
* MOUSE_DRAGGED
events are delivered to the Component
* in which the mouse button was pressed until the mouse button is released
* (regardless of whether the mouse position is within the bounds of the
* Component
). Due to platform-dependent Drag&Drop implementations,
* MOUSE_DRAGGED
events may not be delivered during a native
* Drag&Drop operation.
*
* In a multi-screen environment mouse drag events are delivered to the
* Component
even if the mouse position is outside the bounds of the
* GraphicsConfiguration
associated with that
* Component
. However, the reported position for mouse drag events
* in this case may differ from the actual mouse position:
*
GraphicsConfiguration
associated with
* the Component
.
* Component
.
* MouseEvent
* occurs when a mouse button is pressed and released.
*/
public static final int MOUSE_CLICKED = MOUSE_FIRST;
/**
* The "mouse pressed" event. This MouseEvent
* occurs when a mouse button is pushed down.
*/
public static final int MOUSE_PRESSED = 1 + MOUSE_FIRST; //Event.MOUSE_DOWN
/**
* The "mouse released" event. This MouseEvent
* occurs when a mouse button is let up.
*/
public static final int MOUSE_RELEASED = 2 + MOUSE_FIRST; //Event.MOUSE_UP
/**
* The "mouse moved" event. This MouseEvent
* occurs when the mouse position changes.
*/
public static final int MOUSE_MOVED = 3 + MOUSE_FIRST; //Event.MOUSE_MOVE
/**
* The "mouse entered" event. This MouseEvent
* occurs when the mouse cursor enters the unobscured part of component's
* geometry.
*/
public static final int MOUSE_ENTERED = 4 + MOUSE_FIRST; //Event.MOUSE_ENTER
/**
* The "mouse exited" event. This MouseEvent
* occurs when the mouse cursor exits the unobscured part of component's
* geometry.
*/
public static final int MOUSE_EXITED = 5 + MOUSE_FIRST; //Event.MOUSE_EXIT
/**
* The "mouse dragged" event. This MouseEvent
* occurs when the mouse position changes while a mouse button is pressed.
*/
public static final int MOUSE_DRAGGED = 6 + MOUSE_FIRST; //Event.MOUSE_DRAG
/**
* The "mouse wheel" event. This is the only MouseWheelEvent
.
* It occurs when a mouse equipped with a wheel has its wheel rotated.
* @since 1.4
*/
public static final int MOUSE_WHEEL = 7 + MOUSE_FIRST;
/**
* Indicates no mouse buttons; used by {@link #getButton}.
* @since 1.4
*/
public static final int NOBUTTON = 0;
/**
* Indicates mouse button #1; used by {@link #getButton}.
* @since 1.4
*/
public static final int BUTTON1 = 1;
/**
* Indicates mouse button #2; used by {@link #getButton}.
* @since 1.4
*/
public static final int BUTTON2 = 2;
/**
* Indicates mouse button #3; used by {@link #getButton}.
* @since 1.4
*/
public static final int BUTTON3 = 3;
/**
* The mouse event's x coordinate.
* The x value is relative to the component that fired the event.
*
* @serial
* @see #getX()
*/
int x;
/**
* The mouse event's y coordinate.
* The y value is relative to the component that fired the event.
*
* @serial
* @see #getY()
*/
int y;
/**
* Indicates the number of quick consecutive clicks of
* a mouse button.
* clickCount will be valid for only three mouse events :MOUSE_CLICKED
,
* MOUSE_PRESSED
and
* MOUSE_RELEASED
.
* For the above, the clickCount
will be at least 1.
* For all other events the count will be 0.
*
* @serial
* @see #getClickCount().
*/
int clickCount;
/**
* Indicates which, if any, of the mouse buttons has changed state.
*
* The only legal values are the following constants:
* NOBUTTON
,
* BUTTON1
,
* BUTTON2
or
* BUTTON3
.
* @serial
* @see #getButton().
*/
int button;
/**
* A property used to indicate whether a Popup Menu
* should appear with a certain gestures.
* If popupTrigger
= false
,
* no popup menu should appear. If it is true
* then a popup menu should appear.
*
* @serial
* @see java.awt.PopupMenu
* @see #isPopupTrigger()
*/
boolean popupTrigger = false;
/*
* JDK 1.1 serialVersionUID
*/
private static final long serialVersionUID = -991214153494842848L;
static {
/* ensure that the necessary native libraries are loaded */
NativeLibLoader.loadLibraries();
if (!GraphicsEnvironment.isHeadless()) {
initIDs();
}
}
/**
* Initialize JNI field and method IDs for fields that may be
accessed from C.
*/
private static native void initIDs();
/**
* Constructs a MouseEvent
object with the
* specified source component,
* type, modifiers, coordinates, and click count.
*
* Note that passing in an invalid id
results in
* unspecified behavior. Creating an invalid event (such
* as by using more than one of the old _MASKs, or modifier/button
* values which don't match) results in unspecified behavior.
* This method throws an
* IllegalArgumentException
if source
* is null
.
*
* @param source the Component
that originated the event
* @param id the integer that identifies the event
* @param when a long int that gives the time the event occurred
* @param modifiers the modifier keys down during event (e.g. shift, ctrl,
* alt, meta)
* Either extended _DOWN_MASK or old _MASK modifiers
* should be used, but both models should not be mixed
* in one event. Use of the extended modifiers is
* preferred.
* @param x the horizontal x coordinate for the mouse location
* @param y the vertical y coordinate for the mouse location
* @param clickCount the number of mouse clicks associated with event
* @param popupTrigger a boolean, true if this event is a trigger for a
* popup menu
* @param button which of the mouse buttons has changed state.
* NOBUTTON
,
* BUTTON1
,
* BUTTON2
or
* BUTTON3
.
* @throws IllegalArgumentException if an invalid button
* value is passed in
* @throws IllegalArgumentException if source
is null
* @since 1.4
*/
public MouseEvent(Component source, int id, long when, int modifiers,
int x, int y, int clickCount, boolean popupTrigger,
int button)
{
super(source, id, when, modifiers);
this.x = x;
this.y = y;
this.clickCount = clickCount;
this.popupTrigger = popupTrigger;
if (button < NOBUTTON || button >BUTTON3) {
throw new IllegalArgumentException("Invalid button value");
}
this.button = button;
if ((getModifiers() != 0) && (getModifiersEx() == 0)) {
setNewModifiers();
} else if ((getModifiers() == 0) &&
(getModifiersEx() != 0 ||
button != NOBUTTON))
{
setOldModifiers();
}
}
/**
* Constructs a MouseEvent
object with the
* specified source component,
* type, modifiers, coordinates, and click count.
*
Note that passing in an invalid id
results in
* unspecified behavior. This method throws an
* IllegalArgumentException
if source
* is null
.
*
* @param source the Component
that originated the event
* @param id the integer that identifies the event
* @param when a long int that gives the time the event occurred
* @param modifiers the modifier keys down during event (e.g. shift, ctrl,
* alt, meta)
* Either extended _DOWN_MASK or old _MASK modifiers
* should be used, but both models should not be mixed
* in one event. Use of the extended modifiers is
* preferred.
* @param x the horizontal x coordinate for the mouse location
* @param y the vertical y coordinate for the mouse location
* @param clickCount the number of mouse clicks associated with event
* @param popupTrigger a boolean, true if this event is a trigger for a
* popup menu
* @throws IllegalArgumentException if source
is null
*/
public MouseEvent(Component source, int id, long when, int modifiers,
int x, int y, int clickCount, boolean popupTrigger) {
this(source, id, when, modifiers, x, y, clickCount, popupTrigger, NOBUTTON);
}
/**
* Returns the horizontal x position of the event relative to the
* source component.
*
* @return x an integer indicating horizontal position relative to
* the component
*/
public int getX() {
return x;
}
/**
* Returns the vertical y position of the event relative to the
* source component.
*
* @return y an integer indicating vertical position relative to
* the component
*/
public int getY() {
return y;
}
/**
* Returns the x,y position of the event relative to the source component.
*
* @return a Point
object containing the x and y coordinates
* relative to the source component
*
*/
public Point getPoint() {
int x;
int y;
synchronized (this) {
x = this.x;
y = this.y;
}
return new Point(x, y);
}
/**
* Translates the event's coordinates to a new position
* by adding specified x
(horizontal) and y
* (vertical) offsets.
*
* @param x the horizontal x value to add to the current x
* coordinate position
* @param y the vertical y value to add to the current y
coordinate position
*/
public synchronized void translatePoint(int x, int y) {
this.x += x;
this.y += y;
}
/**
* Returns the number of mouse clicks associated with this event.
*
* @return integer value for the number of clicks
*/
public int getClickCount() {
return clickCount;
}
/**
* Returns which, if any, of the mouse buttons has changed state.
*
* @return one of the following constants:
* NOBUTTON
,
* BUTTON1
,
* BUTTON2
or
* BUTTON3
.
* @since 1.4
*/
public int getButton() {
return button;
}
/**
* Returns whether or not this mouse event is the popup menu
* trigger event for the platform.
*
Note: Popup menus are triggered differently
* on different systems. Therefore, isPopupTrigger
* should be checked in both mousePressed
* and mouseReleased
* for proper cross-platform functionality.
*
* @return boolean, true if this event is the popup menu trigger
* for this platform
*/
public boolean isPopupTrigger() {
return popupTrigger;
}
/**
* Returns a String
describing the modifier keys and
* mouse buttons that were down during the event, such as "Shift",
* or "Ctrl+Shift". These strings can be localized by changing
* the awt.properties
file.
*
* Note that InputEvent.ALT_MASK
and
* InputEvent.BUTTON2_MASK
have the same value,
* so the string "Alt" is returned for both modifiers. Likewise,
* InputEvent.META_MASK
and
* InputEvent.BUTTON3_MASK
have the same value,
* so the string "Meta" is returned for both modifiers.
*
* @param modifiers a modifier mask describing the modifier keys and
* mouse buttons that were down during the event
* @return string a text description of the combination of modifier
* keys and mouse buttons that were down during the event
* @see InputEvent#getModifiersExText(int)
* @since 1.4
*/
public static String getMouseModifiersText(int modifiers) {
StringBuffer buf = new StringBuffer();
if ((modifiers & InputEvent.ALT_MASK) != 0) {
buf.append(Toolkit.getProperty("AWT.alt", "Alt"));
buf.append("+");
}
if ((modifiers & InputEvent.META_MASK) != 0) {
buf.append(Toolkit.getProperty("AWT.meta", "Meta"));
buf.append("+");
}
if ((modifiers & InputEvent.CTRL_MASK) != 0) {
buf.append(Toolkit.getProperty("AWT.control", "Ctrl"));
buf.append("+");
}
if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
buf.append(Toolkit.getProperty("AWT.shift", "Shift"));
buf.append("+");
}
if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) {
buf.append(Toolkit.getProperty("AWT.altGraph", "Alt Graph"));
buf.append("+");
}
if ((modifiers & InputEvent.BUTTON1_MASK) != 0) {
buf.append(Toolkit.getProperty("AWT.button1", "Button1"));
buf.append("+");
}
if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
buf.append(Toolkit.getProperty("AWT.button2", "Button2"));
buf.append("+");
}
if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
buf.append(Toolkit.getProperty("AWT.button3", "Button3"));
buf.append("+");
}
if (buf.length() > 0) {
buf.setLength(buf.length()-1); // remove trailing '+'
}
return buf.toString();
}
/**
* Returns a parameter string identifying this event.
* This method is useful for event-logging and for debugging.
*
* @return a string identifying the event and its attributes
*/
public String paramString() {
StringBuffer str = new StringBuffer(80);
switch(id) {
case MOUSE_PRESSED:
str.append("MOUSE_PRESSED");
break;
case MOUSE_RELEASED:
str.append("MOUSE_RELEASED");
break;
case MOUSE_CLICKED:
str.append("MOUSE_CLICKED");
break;
case MOUSE_ENTERED:
str.append("MOUSE_ENTERED");
break;
case MOUSE_EXITED:
str.append("MOUSE_EXITED");
break;
case MOUSE_MOVED:
str.append("MOUSE_MOVED");
break;
case MOUSE_DRAGGED:
str.append("MOUSE_DRAGGED");
break;
case MOUSE_WHEEL:
str.append("MOUSE_WHEEL");
break;
default:
str.append("unknown type");
}
// (x,y) coordinates
str.append(",(").append(x).append(",").append(y).append(")");
str.append(",button=").append(getButton());
if (getModifiers() != 0) {
str.append(",modifiers=").append(getMouseModifiersText(modifiers));
}
if (getModifiersEx() != 0) {
str.append(",extModifiers=").append(getModifiersExText(modifiers));
}
str.append(",clickCount=").append(clickCount);
return str.toString();
}
/**
* Sets new modifiers by the old ones.
* Also sets button.
*/
private void setNewModifiers() {
if ((modifiers & BUTTON1_MASK) != 0) {
modifiers |= BUTTON1_DOWN_MASK;
}
if ((modifiers & BUTTON2_MASK) != 0) {
modifiers |= BUTTON2_DOWN_MASK;
}
if ((modifiers & BUTTON3_MASK) != 0) {
modifiers |= BUTTON3_DOWN_MASK;
}
if (id == MOUSE_PRESSED
|| id == MOUSE_RELEASED
|| id == MOUSE_CLICKED)
{
if ((modifiers & BUTTON1_MASK) != 0) {
button = BUTTON1;
modifiers &= ~BUTTON2_MASK & ~BUTTON3_MASK;
if (id != MOUSE_PRESSED) {
modifiers &= ~BUTTON1_DOWN_MASK;
}
} else if ((modifiers & BUTTON2_MASK) != 0) {
button = BUTTON2;
modifiers &= ~BUTTON1_MASK & ~BUTTON3_MASK;
if (id != MOUSE_PRESSED) {
modifiers &= ~BUTTON2_DOWN_MASK;
}
} else if ((modifiers & BUTTON3_MASK) != 0) {
button = BUTTON3;
modifiers &= ~BUTTON1_MASK & ~BUTTON2_MASK;
if (id != MOUSE_PRESSED) {
modifiers &= ~BUTTON3_DOWN_MASK;
}
}
}
if ((modifiers & InputEvent.ALT_MASK) != 0) {
modifiers |= InputEvent.ALT_DOWN_MASK;
}
if ((modifiers & InputEvent.META_MASK) != 0) {
modifiers |= InputEvent.META_DOWN_MASK;
}
if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
modifiers |= InputEvent.SHIFT_DOWN_MASK;
}
if ((modifiers & InputEvent.CTRL_MASK) != 0) {
modifiers |= InputEvent.CTRL_DOWN_MASK;
}
if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) {
modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;
}
}
/**
* Sets old modifiers by the new ones.
*/
private void setOldModifiers() {
if (id == MOUSE_PRESSED
|| id == MOUSE_RELEASED
|| id == MOUSE_CLICKED)
{
switch(button) {
case BUTTON1:
modifiers |= BUTTON1_MASK;
break;
case BUTTON2:
modifiers |= BUTTON2_MASK;
break;
case BUTTON3:
modifiers |= BUTTON3_MASK;
break;
}
} else {
if ((modifiers & BUTTON1_DOWN_MASK) != 0) {
modifiers |= BUTTON1_MASK;
}
if ((modifiers & BUTTON2_DOWN_MASK) != 0) {
modifiers |= BUTTON2_MASK;
}
if ((modifiers & BUTTON3_DOWN_MASK) != 0) {
modifiers |= BUTTON3_MASK;
}
}
if ((modifiers & ALT_DOWN_MASK) != 0) {
modifiers |= ALT_MASK;
}
if ((modifiers & META_DOWN_MASK) != 0) {
modifiers |= META_MASK;
}
if ((modifiers & SHIFT_DOWN_MASK) != 0) {
modifiers |= SHIFT_MASK;
}
if ((modifiers & CTRL_DOWN_MASK) != 0) {
modifiers |= CTRL_MASK;
}
if ((modifiers & ALT_GRAPH_DOWN_MASK) != 0) {
modifiers |= ALT_GRAPH_MASK;
}
}
/**
* Sets new modifiers by the old ones.
* @serial
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
if (getModifiers() != 0 && getModifiersEx() == 0) {
setNewModifiers();
}
}
}