/* * @(#)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 MouseListeners. * 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           
 *    MOUSE_PRESSED:  BUTTON1_MASK BUTTON1
 *    MOUSE_RELEASED: BUTTON1_MASK BUTTON1
 *    MOUSE_CLICKED:  BUTTON1_MASK BUTTON1
 * 
* When multiple mouse buttons are pressed, each press, release, and click * results in a separate event. *

* 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           
 *    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
 * 
* If button 2 is released first, the * 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: *

* * @author Carl Quinn * 1.49, 12/19/03 * * @see MouseAdapter * @see MouseListener * @see MouseMotionAdapter * @see MouseMotionListener * @see MouseWheelListener * @see Tutorial: Writing a Mouse Listener * @see Tutorial: Writing a Mouse Motion Listener * @see Reference: The Java Class Libraries (update file) * * @since 1.1 */ public class MouseEvent extends InputEvent { /** * The first number in the range of ids used for mouse events. */ public static final int MOUSE_FIRST = 500; /** * The last number in the range of ids used for mouse events. */ public static final int MOUSE_LAST = 507; /** * The "mouse clicked" event. This 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(); } } }