Java tutorial
/* * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.awt.event; import java.awt.Component; import java.awt.GraphicsEnvironment; import java.awt.Point; import java.awt.Toolkit; import java.io.IOException; import java.io.ObjectInputStream; import java.awt.IllegalComponentStateException; import java.awt.MouseInfo; import sun.awt.AWTAccessor; import sun.awt.SunToolkit; /** * 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. * For lightweight components, such as Swing's components, mouse events * are only dispatched to the component if the mouse event type has been * enabled on the component. A mouse event type is enabled by adding the * appropriate mouse-based {@code EventListener} to the component * ({@link MouseListener} or {@link MouseMotionListener}), or by invoking * {@link Component#enableEvents(long)} with the appropriate mask parameter * ({@code AWTEvent.MOUSE_EVENT_MASK} or {@code AWTEvent.MOUSE_MOTION_EVENT_MASK}). * If the mouse event type has not been enabled on the component, the * corresponding mouse events are dispatched to the first ancestor that * has enabled the mouse event type. *<p> * For example, if a {@code MouseListener} has been added to a component, or * {@code enableEvents(AWTEvent.MOUSE_EVENT_MASK)} has been invoked, then all * the events defined by {@code MouseListener} are dispatched to the component. * On the other hand, if a {@code MouseMotionListener} has not been added and * {@code enableEvents} has not been invoked with * {@code AWTEvent.MOUSE_MOTION_EVENT_MASK}, then mouse motion events are not * dispatched to the component. Instead the mouse motion events are * dispatched to the first ancestors that has enabled mouse motion * events. * <P> * This low-level event is generated by a component object for: * <ul> * <li>Mouse Events * <ul> * <li>a mouse button is pressed * <li>a mouse button is released * <li>a mouse button is clicked (pressed and released) * <li>the mouse cursor enters the unobscured part of component's geometry * <li>the mouse cursor exits the unobscured part of component's geometry * </ul> * <li> Mouse Motion Events * <ul> * <li>the mouse is moved * <li>the mouse is dragged * </ul> * </ul> * <P> * A {@code MouseEvent} object is passed to every * {@code MouseListener} * or {@code MouseAdapter} object which is registered to receive * the "interesting" mouse events using the component's * {@code addMouseListener} method. * ({@code MouseAdapter} objects implement the * {@code MouseListener} interface.) Each such listener object * gets a {@code MouseEvent} containing the mouse event. * <P> * A {@code MouseEvent} object is also passed to every * {@code MouseMotionListener} or * {@code MouseMotionAdapter} object which is registered to receive * mouse motion events using the component's * {@code addMouseMotionListener} * method. ({@code MouseMotionAdapter} objects implement the * {@code MouseMotionListener} interface.) Each such listener object * gets a {@code MouseEvent} containing the mouse motion event. * <P> * When a mouse button is clicked, events are generated and sent to the * registered {@code 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} * <P> * For example, if the first mouse button is pressed, events are sent in the * following order: * <pre><b> * id modifiers button</b>{@code * MOUSE_PRESSED: BUTTON1_MASK BUTTON1 * MOUSE_RELEASED: BUTTON1_MASK BUTTON1 * MOUSE_CLICKED: BUTTON1_MASK BUTTON1 * }</pre> * When multiple mouse buttons are pressed, each press, release, and click * results in a separate event. * <P> * For example, if the user presses <b>button 1</b> followed by * <b>button 2</b>, and then releases them in the same order, * the following sequence of events is generated: * <pre><b> * id modifiers button</b>{@code * 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 * }</pre> * If <b>button 2</b> is released first, the * {@code MOUSE_RELEASED}/{@code MOUSE_CLICKED} pair * for {@code BUTTON2_MASK} arrives first, * followed by the pair for {@code BUTTON1_MASK}. * <p> * Some extra mouse buttons are added to extend the standard set of buttons * represented by the following constants:{@code BUTTON1}, {@code BUTTON2}, and {@code BUTTON3}. * Extra buttons have no assigned {@code BUTTONx} * constants as well as their button masks have no assigned {@code BUTTONx_DOWN_MASK} * constants. Nevertheless, ordinal numbers starting from 4 may be * used as button numbers (button ids). Values obtained by the * {@link InputEvent#getMaskForButton(int) getMaskForButton(button)} method may be used * as button masks. * <p> * {@code MOUSE_DRAGGED} events are delivered to the {@code 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 * {@code Component}). Due to platform-dependent Drag&Drop implementations, * {@code 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 * {@code Component} even if the mouse position is outside the bounds of the * {@code GraphicsConfiguration} associated with that * {@code Component}. However, the reported position for mouse drag events * in this case may differ from the actual mouse position: * <ul> * <li>In a multi-screen environment without a virtual device: * <br> * The reported coordinates for mouse drag events are clipped to fit within the * bounds of the {@code GraphicsConfiguration} associated with * the {@code Component}. * <li>In a multi-screen environment with a virtual device: * <br> * The reported coordinates for mouse drag events are clipped to fit within the * bounds of the virtual device associated with the {@code Component}. * </ul> * <p> * An unspecified behavior will be caused if the {@code id} parameter * of any particular {@code MouseEvent} instance is not * in the range from {@code MOUSE_FIRST} to {@code MOUSE_LAST}-1 * ({@code MOUSE_WHEEL} is not acceptable). * * @author Carl Quinn * * @see MouseAdapter * @see MouseListener * @see MouseMotionAdapter * @see MouseMotionListener * @see MouseWheelListener * @see <a href="https://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html">Tutorial: Writing a Mouse Listener</a> * @see <a href="https://docs.oracle.com/javase/tutorial/uiswing/events/mousemotionlistener.html">Tutorial: Writing a Mouse Motion Listener</a> * * @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 {@code MouseEvent} * occurs when a mouse button is pressed and released. */ public static final int MOUSE_CLICKED = MOUSE_FIRST; /** * The "mouse pressed" event. This {@code 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 {@code 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 {@code MouseEvent} * occurs when the mouse position changes. */ public static final int MOUSE_MOVED = 3 + MOUSE_FIRST; //Event.MOUSE_MOVE /** * The "mouse entered" event. This {@code 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 {@code 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 {@code 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 {@code 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; /** * The mouse event's x absolute coordinate. * In a virtual device multi-screen environment in which the * desktop area could span multiple physical screen devices, * this coordinate is relative to the virtual coordinate system. * Otherwise, this coordinate is relative to the coordinate system * associated with the Component's GraphicsConfiguration. * * @serial */ private int xAbs; /** * The mouse event's y absolute coordinate. * In a virtual device multi-screen environment in which the * desktop area could span multiple physical screen devices, * this coordinate is relative to the virtual coordinate system. * Otherwise, this coordinate is relative to the coordinate system * associated with the Component's GraphicsConfiguration. * * @serial */ private int yAbs; /** * Indicates the number of quick consecutive clicks of * a mouse button. * clickCount will be valid for only three mouse events :<BR> * {@code MOUSE_CLICKED}, * {@code MOUSE_PRESSED} and * {@code MOUSE_RELEASED}. * For the above, the {@code clickCount} will be at least 1. * For all other events the count will be 0. * * @serial * @see #getClickCount() */ int clickCount; /** * Indicates whether the event is a result of a touch event. */ private boolean causedByTouchEvent; /** * Indicates which, if any, of the mouse buttons has changed state. * * The valid values are ranged from 0 to the value returned by the * {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} method. * This range already includes constants {@code NOBUTTON}, {@code BUTTON1}, * {@code BUTTON2}, and {@code BUTTON3} * if these buttons are present. So it is allowed to use these constants too. * For example, for a mouse with two buttons this field may contain the following values: * <ul> * <li> 0 ({@code NOBUTTON}) * <li> 1 ({@code BUTTON1}) * <li> 2 ({@code BUTTON2}) * </ul> * If a mouse has 5 buttons, this field may contain the following values: * <ul> * <li> 0 ({@code NOBUTTON}) * <li> 1 ({@code BUTTON1}) * <li> 2 ({@code BUTTON2}) * <li> 3 ({@code BUTTON3}) * <li> 4 * <li> 5 * </ul> * If support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled()} disabled by Java * then the field may not contain the value larger than {@code BUTTON3}. * @serial * @see #getButton() * @see java.awt.Toolkit#areExtraMouseButtonsEnabled() */ int button; /** * A property used to indicate whether a Popup Menu * should appear with a certain gestures. * If {@code popupTrigger} = {@code false}, * no popup menu should appear. If it is {@code 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; /** * A number of buttons available on the mouse at the {@code Toolkit} machinery startup. */ private static int cachedNumberOfButtons; static { /* ensure that the necessary native libraries are loaded */ NativeLibLoader.loadLibraries(); if (!GraphicsEnvironment.isHeadless()) { initIDs(); } final Toolkit tk = Toolkit.getDefaultToolkit(); if (tk instanceof SunToolkit) { cachedNumberOfButtons = ((SunToolkit) tk).getNumberOfButtons(); } else { //It's expected that some toolkits (Headless, //whatever besides SunToolkit) could also operate. cachedNumberOfButtons = 3; } AWTAccessor.setMouseEventAccessor(new AWTAccessor.MouseEventAccessor() { public boolean isCausedByTouchEvent(MouseEvent ev) { return ev.causedByTouchEvent; } public void setCausedByTouchEvent(MouseEvent ev, boolean causedByTouchEvent) { ev.causedByTouchEvent = causedByTouchEvent; } }); } /** * Initialize JNI field and method IDs for fields that may be * accessed from C. */ private static native void initIDs(); /** * Returns the absolute x, y position of the event. * In a virtual device multi-screen environment in which the * desktop area could span multiple physical screen devices, * these coordinates are relative to the virtual coordinate system. * Otherwise, these coordinates are relative to the coordinate system * associated with the Component's GraphicsConfiguration. * * @return a {@code Point} object containing the absolute x * and y coordinates. * * @see java.awt.GraphicsConfiguration * @since 1.6 */ public Point getLocationOnScreen() { return new Point(xAbs, yAbs); } /** * Returns the absolute horizontal x position of the event. * In a virtual device multi-screen environment in which the * desktop area could span multiple physical screen devices, * this coordinate is relative to the virtual coordinate system. * Otherwise, this coordinate is relative to the coordinate system * associated with the Component's GraphicsConfiguration. * * @return x an integer indicating absolute horizontal position. * * @see java.awt.GraphicsConfiguration * @since 1.6 */ public int getXOnScreen() { return xAbs; } /** * Returns the absolute vertical y position of the event. * In a virtual device multi-screen environment in which the * desktop area could span multiple physical screen devices, * this coordinate is relative to the virtual coordinate system. * Otherwise, this coordinate is relative to the coordinate system * associated with the Component's GraphicsConfiguration. * * @return y an integer indicating absolute vertical position. * * @see java.awt.GraphicsConfiguration * @since 1.6 */ public int getYOnScreen() { return yAbs; } /** * Constructs a {@code MouseEvent} object with the * specified source component, * type, time, modifiers, coordinates, click count, popupTrigger flag, * and button number. * <p> * 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. * An invocation of the form * {@code MouseEvent(source, id, when, modifiers, x, y, clickCount, popupTrigger, button)} * behaves in exactly the same way as the invocation * {@link #MouseEvent(Component, int, long, int, int, int, * int, int, int, boolean, int) MouseEvent(source, id, when, modifiers, * x, y, xAbs, yAbs, clickCount, popupTrigger, button)} * where xAbs and yAbs defines as source's location on screen plus * relative coordinates x and y. * xAbs and yAbs are set to zero if the source is not showing. * This method throws an * {@code IllegalArgumentException} if {@code source} * is {@code null}. * * @param source The {@code Component} that originated the event * @param id An integer indicating the type of event. * For information on allowable values, see * the class description for {@link MouseEvent} * @param when A long integer that gives the time the event occurred. * Passing negative or zero value * is not recommended * @param modifiers a modifier mask describing the modifier keys and mouse * buttons (for example, shift, ctrl, alt, and meta) that * are down during the event. * Only extended modifiers are allowed to be used as a * value for this parameter (see the {@link InputEvent#getModifiersEx} * class for the description of extended modifiers). * Passing negative parameter * is not recommended. * Zero value means that no modifiers were passed * @param x The horizontal x coordinate for the mouse location. * It is allowed to pass negative values * @param y The vertical y coordinate for the mouse location. * It is allowed to pass negative values * @param clickCount The number of mouse clicks associated with event. * Passing negative value * is not recommended * @param popupTrigger A boolean that equals {@code true} if this event * is a trigger for a popup menu * @param button An integer that indicates, which of the mouse buttons has * changed its state. * The following rules are applied to this parameter: * <ul> * <li>If support for the extended mouse buttons is * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java * then it is allowed to create {@code MouseEvent} objects only with the standard buttons: * {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2}, and * {@code BUTTON3}. * <li> If support for the extended mouse buttons is * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java * then it is allowed to create {@code MouseEvent} objects with * the standard buttons. * In case the support for extended mouse buttons is * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java, then * in addition to the standard buttons, {@code MouseEvent} objects can be created * using buttons from the range starting from 4 to * {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} * if the mouse has more than three buttons. * </ul> * @throws IllegalArgumentException if {@code button} is less than zero * @throws IllegalArgumentException if {@code source} is null * @throws IllegalArgumentException if {@code button} is greater than BUTTON3 * and the support for extended mouse buttons is * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java * @throws IllegalArgumentException if {@code button} is greater than the * {@link java.awt.MouseInfo#getNumberOfButtons() current number of buttons} * and the support for extended mouse buttons is * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} * by Java * @throws IllegalArgumentException if an invalid {@code button} * value is passed in * @throws IllegalArgumentException if {@code source} is null * @see #getSource() * @see #getID() * @see #getWhen() * @see #getModifiers() * @see #getX() * @see #getY() * @see #getClickCount() * @see #isPopupTrigger() * @see #getButton() * @since 1.4 */ public MouseEvent(Component source, int id, long when, int modifiers, int x, int y, int clickCount, boolean popupTrigger, int button) { this(source, id, when, modifiers, x, y, 0, 0, clickCount, popupTrigger, button); Point eventLocationOnScreen = new Point(0, 0); try { eventLocationOnScreen = source.getLocationOnScreen(); this.xAbs = eventLocationOnScreen.x + x; this.yAbs = eventLocationOnScreen.y + y; } catch (IllegalComponentStateException e) { this.xAbs = 0; this.yAbs = 0; } } /** * Constructs a {@code MouseEvent} object with the * specified source component, * type, modifiers, coordinates, click count, and popupTrigger flag. * An invocation of the form * {@code MouseEvent(source, id, when, modifiers, x, y, clickCount, popupTrigger)} * behaves in exactly the same way as the invocation * {@link #MouseEvent(Component, int, long, int, int, int, * int, int, int, boolean, int) MouseEvent(source, id, when, modifiers, * x, y, xAbs, yAbs, clickCount, popupTrigger, MouseEvent.NOBUTTON)} * where xAbs and yAbs defines as source's location on screen plus * relative coordinates x and y. * xAbs and yAbs are set to zero if the source is not showing. * This method throws an {@code IllegalArgumentException} * if {@code source} is {@code null}. * * @param source The {@code Component} that originated the event * @param id An integer indicating the type of event. * For information on allowable values, see * the class description for {@link MouseEvent} * @param when A long integer that gives the time the event occurred. * Passing negative or zero value * is not recommended * @param modifiers a modifier mask describing the modifier keys and mouse * buttons (for example, shift, ctrl, alt, and meta) that * are down during the event. * Only extended modifiers are allowed to be used as a * value for this parameter (see the {@link InputEvent#getModifiersEx} * class for the description of extended modifiers). * Passing negative parameter * is not recommended. * Zero value means that no modifiers were passed * @param x The horizontal x coordinate for the mouse location. * It is allowed to pass negative values * @param y The vertical y coordinate for the mouse location. * It is allowed to pass negative values * @param clickCount The number of mouse clicks associated with event. * Passing negative value * is not recommended * @param popupTrigger A boolean that equals {@code true} if this event * is a trigger for a popup menu * @throws IllegalArgumentException if {@code source} is null * @see #getSource() * @see #getID() * @see #getWhen() * @see #getModifiers() * @see #getX() * @see #getY() * @see #getClickCount() * @see #isPopupTrigger() */ 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); } /* if the button is an extra button and it is released or clicked then in Xsystem its state is not modified. Exclude this button number from ExtModifiers mask.*/ private transient boolean shouldExcludeButtonFromExtModifiers = false; /** * {@inheritDoc} */ public int getModifiersEx() { int tmpModifiers = modifiers; if (shouldExcludeButtonFromExtModifiers) { tmpModifiers &= ~(InputEvent.getMaskForButton(getButton())); } return tmpModifiers & ~JDK_1_3_MODIFIERS; } /** * Constructs a {@code MouseEvent} object with the * specified source component, * type, time, modifiers, coordinates, absolute coordinates, click count, popupTrigger flag, * and button number. * <p> * 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. * Even if inconsistent values for relative and absolute coordinates are * passed to the constructor, the mouse event instance is still * created and no exception is thrown. * This method throws an * {@code IllegalArgumentException} if {@code source} * is {@code null}. * * @param source The {@code Component} that originated the event * @param id An integer indicating the type of event. * For information on allowable values, see * the class description for {@link MouseEvent} * @param when A long integer that gives the time the event occurred. * Passing negative or zero value * is not recommended * @param modifiers a modifier mask describing the modifier keys and mouse * buttons (for example, shift, ctrl, alt, and meta) that * are down during the event. * Only extended modifiers are allowed to be used as a * value for this parameter (see the {@link InputEvent#getModifiersEx} * class for the description of extended modifiers). * Passing negative parameter * is not recommended. * Zero value means that no modifiers were passed * @param x The horizontal x coordinate for the mouse location. * It is allowed to pass negative values * @param y The vertical y coordinate for the mouse location. * It is allowed to pass negative values * @param xAbs The absolute horizontal x coordinate for the mouse location * It is allowed to pass negative values * @param yAbs The absolute vertical y coordinate for the mouse location * It is allowed to pass negative values * @param clickCount The number of mouse clicks associated with event. * Passing negative value * is not recommended * @param popupTrigger A boolean that equals {@code true} if this event * is a trigger for a popup menu * @param button An integer that indicates, which of the mouse buttons has * changed its state. * The following rules are applied to this parameter: * <ul> * <li>If support for the extended mouse buttons is * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java * then it is allowed to create {@code MouseEvent} objects only with the standard buttons: * {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2}, and * {@code BUTTON3}. * <li> If support for the extended mouse buttons is * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java * then it is allowed to create {@code MouseEvent} objects with * the standard buttons. * In case the support for extended mouse buttons is * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java, then * in addition to the standard buttons, {@code MouseEvent} objects can be created * using buttons from the range starting from 4 to * {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} * if the mouse has more than three buttons. * </ul> * @throws IllegalArgumentException if {@code button} is less than zero * @throws IllegalArgumentException if {@code source} is null * @throws IllegalArgumentException if {@code button} is greater than BUTTON3 * and the support for extended mouse buttons is * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java * @throws IllegalArgumentException if {@code button} is greater than the * {@link java.awt.MouseInfo#getNumberOfButtons() * current number of buttons} and the support * for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} * by Java * @throws IllegalArgumentException if an invalid {@code button} * value is passed in * @throws IllegalArgumentException if {@code source} is null * @see #getSource() * @see #getID() * @see #getWhen() * @see #getModifiers() * @see #getX() * @see #getY() * @see #getXOnScreen() * @see #getYOnScreen() * @see #getClickCount() * @see #isPopupTrigger() * @see #getButton() * @see Toolkit#areExtraMouseButtonsEnabled() * @see java.awt.MouseInfo#getNumberOfButtons() * @see InputEvent#getMaskForButton(int) * @since 1.6 */ @SuppressWarnings("deprecation") public MouseEvent(Component source, int id, long when, int modifiers, int x, int y, int xAbs, int yAbs, int clickCount, boolean popupTrigger, int button) { super(source, id, when, modifiers); this.x = x; this.y = y; this.xAbs = xAbs; this.yAbs = yAbs; this.clickCount = clickCount; this.popupTrigger = popupTrigger; if (button < NOBUTTON) { throw new IllegalArgumentException("Invalid button value :" + button); } if (button > BUTTON3) { if (!Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled()) { throw new IllegalArgumentException("Extra mouse events are disabled " + button); } else { if (button > cachedNumberOfButtons) { throw new IllegalArgumentException("Nonexistent button " + button); } } // XToolkit: extra buttons are not reporting about their state correctly. // Being pressed they report the state=0 both on the press and on the release. // For 1-3 buttons the state value equals zero on press and non-zero on release. // Other modifiers like Shift, ALT etc seem report well with extra buttons. // The problem reveals as follows: one button is pressed and then another button is pressed and released. // So, the getModifiersEx() would not be zero due to a first button and we will skip this modifier. // This may have to be moved into the peer code instead if possible. if (getModifiersEx() != 0) { //There is at least one more button in a pressed state. if (id == MouseEvent.MOUSE_RELEASED || id == MouseEvent.MOUSE_CLICKED) { shouldExcludeButtonFromExtModifiers = true; } } } this.button = button; if ((getModifiers() != 0) && (getModifiersEx() == 0)) { setNewModifiers(); } else if ((getModifiers() == 0) && (getModifiersEx() != 0 || button != NOBUTTON) && (button <= BUTTON3)) { setOldModifiers(); } } /** * 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 {@code 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 {@code x} (horizontal) and {@code 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. * The returned value is ranged * from 0 to the {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} * value. * The returned value includes at least the following constants: * <ul> * <li> {@code NOBUTTON} * <li> {@code BUTTON1} * <li> {@code BUTTON2} * <li> {@code BUTTON3} * </ul> * It is allowed to use those constants to compare with the returned button number in the application. * For example, * <pre> * if (anEvent.getButton() == MouseEvent.BUTTON1) { * </pre> * In particular, for a mouse with one, two, or three buttons this method may return the following values: * <ul> * <li> 0 ({@code NOBUTTON}) * <li> 1 ({@code BUTTON1}) * <li> 2 ({@code BUTTON2}) * <li> 3 ({@code BUTTON3}) * </ul> * Button numbers greater than {@code BUTTON3} have no constant identifier. * So if a mouse with five buttons is * installed, this method may return the following values: * <ul> * <li> 0 ({@code NOBUTTON}) * <li> 1 ({@code BUTTON1}) * <li> 2 ({@code BUTTON2}) * <li> 3 ({@code BUTTON3}) * <li> 4 * <li> 5 * </ul> * <p> * Note: If support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java * then the AWT event subsystem does not produce mouse events for the extended mouse * buttons. So it is not expected that this method returns anything except {@code NOBUTTON}, {@code BUTTON1}, * {@code BUTTON2}, {@code BUTTON3}. * * @return one of the values from 0 to {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} * if support for the extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java. * That range includes {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2}, {@code BUTTON3}; * <br> * {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2} or {@code BUTTON3} * if support for the extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java * @since 1.4 * @see Toolkit#areExtraMouseButtonsEnabled() * @see java.awt.MouseInfo#getNumberOfButtons() * @see #MouseEvent(Component, int, long, int, int, int, int, int, int, boolean, int) * @see InputEvent#getMaskForButton(int) */ public int getButton() { return button; } /** * Returns whether or not this mouse event is the popup menu * trigger event for the platform. * <p><b>Note</b>: Popup menus are triggered differently * on different systems. Therefore, {@code isPopupTrigger} * should be checked in both {@code mousePressed} * and {@code 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 {@code String} instance 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 {@code awt.properties} file. * <p> * Note that the {@code InputEvent.ALT_MASK} and * {@code InputEvent.BUTTON2_MASK} have equal values, * so the "Alt" string is returned for both modifiers. Likewise, * the {@code InputEvent.META_MASK} and * {@code InputEvent.BUTTON3_MASK} have equal values, * so the "Meta" string is returned for both modifiers. * <p> * Note that passing negative parameter is incorrect, * and will cause the returning an unspecified string. * Zero parameter means that no modifiers were passed and will * cause the returning an empty string. * * @param modifiers A modifier mask describing the modifier keys and * mouse buttons that were down during the event * @return string string text description of the combination of modifier * keys and mouse buttons that were down during the event * @see InputEvent#getModifiersExText(int) * @since 1.4 */ @SuppressWarnings("deprecation") public static String getMouseModifiersText(int modifiers) { StringBuilder buf = new StringBuilder(); 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("+"); } int mask; // TODO: add a toolkit field that holds a number of button on the mouse. // As the method getMouseModifiersText() is static and obtain // an integer as a parameter then we may not restrict this with the number // of buttons installed on the mouse. // It's a temporary solution. We need to somehow hold the number of buttons somewhere else. for (int i = 1; i <= cachedNumberOfButtons; i++) { mask = InputEvent.getMaskForButton(i); if ((modifiers & mask) != 0 && buf.indexOf(Toolkit.getProperty("AWT.button" + i, "Button" + i)) == -1) //1,2,3 buttons may already be there; so don't duplicate it. { buf.append(Toolkit.getProperty("AWT.button" + i, "Button" + i)); 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 */ @SuppressWarnings("deprecation") public String paramString() { StringBuilder str = new StringBuilder(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(",absolute(").append(xAbs).append(",").append(yAbs).append(")"); if (id != MOUSE_DRAGGED && id != MOUSE_MOVED) { str.append(",button=").append(getButton()); } if (getModifiers() != 0) { str.append(",modifiers=").append(getMouseModifiersText(modifiers)); } if (getModifiersEx() != 0) { //Using plain "modifiers" here does show an excluded extended buttons in the string event representation. //getModifiersEx() solves the problem. str.append(",extModifiers=").append(getModifiersExText(getModifiersEx())); } str.append(",clickCount=").append(clickCount); return str.toString(); } /** * Sets new modifiers by the old ones. * Also sets button. */ @SuppressWarnings("deprecation") 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. */ @SuppressWarnings("deprecation") 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 */ @SuppressWarnings("deprecation") private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); if (getModifiers() != 0 && getModifiersEx() == 0) { setNewModifiers(); } } }