1 /* 2 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.awt.event; 27 28 import java.awt.Component; 29 import java.awt.GraphicsEnvironment; 30 import java.awt.Point; 31 import java.awt.Toolkit; 32 import java.io.IOException; 33 import java.io.ObjectInputStream; 34 import java.awt.IllegalComponentStateException; 35 import java.awt.MouseInfo; 36 import sun.awt.SunToolkit; 37 38 /** 39 * An event which indicates that a mouse action occurred in a component. 40 * A mouse action is considered to occur in a particular component if and only 41 * if the mouse cursor is over the unobscured part of the component's bounds 42 * when the action happens. 43 * For lightweight components, such as Swing's components, mouse events 44 * are only dispatched to the component if the mouse event type has been 45 * enabled on the component. A mouse event type is enabled by adding the 46 * appropriate mouse-based {@code EventListener} to the component 47 * ({@link MouseListener} or {@link MouseMotionListener}), or by invoking 48 * {@link Component#enableEvents(long)} with the appropriate mask parameter 49 * ({@code AWTEvent.MOUSE_EVENT_MASK} or {@code AWTEvent.MOUSE_MOTION_EVENT_MASK}). 50 * If the mouse event type has not been enabled on the component, the 51 * corresponding mouse events are dispatched to the first ancestor that 52 * has enabled the mouse event type. 53 *<p> 54 * For example, if a {@code MouseListener} has been added to a component, or 55 * {@code enableEvents(AWTEvent.MOUSE_EVENT_MASK)} has been invoked, then all 56 * the events defined by {@code MouseListener} are dispatched to the component. 57 * On the other hand, if a {@code MouseMotionListener} has not been added and 58 * {@code enableEvents} has not been invoked with 59 * {@code AWTEvent.MOUSE_MOTION_EVENT_MASK}, then mouse motion events are not 60 * dispatched to the component. Instead the mouse motion events are 61 * dispatched to the first ancestors that has enabled mouse motion 62 * events. 63 * <P> 64 * This low-level event is generated by a component object for: 65 * <ul> 66 * <li>Mouse Events 67 * <ul> 68 * <li>a mouse button is pressed 69 * <li>a mouse button is released 70 * <li>a mouse button is clicked (pressed and released) 71 * <li>the mouse cursor enters the unobscured part of component's geometry 72 * <li>the mouse cursor exits the unobscured part of component's geometry 73 * </ul> 74 * <li> Mouse Motion Events 75 * <ul> 76 * <li>the mouse is moved 77 * <li>the mouse is dragged 78 * </ul> 79 * </ul> 80 * <P> 81 * A {@code MouseEvent} object is passed to every 82 * {@code MouseListener} 83 * or {@code MouseAdapter} object which is registered to receive 84 * the "interesting" mouse events using the component's 85 * {@code addMouseListener} method. 86 * ({@code MouseAdapter} objects implement the 87 * {@code MouseListener} interface.) Each such listener object 88 * gets a {@code MouseEvent} containing the mouse event. 89 * <P> 90 * A {@code MouseEvent} object is also passed to every 91 * {@code MouseMotionListener} or 92 * {@code MouseMotionAdapter} object which is registered to receive 93 * mouse motion events using the component's 94 * {@code addMouseMotionListener} 95 * method. ({@code MouseMotionAdapter} objects implement the 96 * {@code MouseMotionListener} interface.) Each such listener object 97 * gets a {@code MouseEvent} containing the mouse motion event. 98 * <P> 99 * When a mouse button is clicked, events are generated and sent to the 100 * registered {@code MouseListener}s. 101 * The state of modal keys can be retrieved using {@link InputEvent#getModifiers} 102 * and {@link InputEvent#getModifiersEx}. 103 * The button mask returned by {@link InputEvent#getModifiers} reflects 104 * only the button that changed state, not the current state of all buttons. 105 * (Note: Due to overlap in the values of ALT_MASK/BUTTON2_MASK and 106 * META_MASK/BUTTON3_MASK, this is not always true for mouse events involving 107 * modifier keys). 108 * To get the state of all buttons and modifier keys, use 109 * {@link InputEvent#getModifiersEx}. 110 * The button which has changed state is returned by {@link MouseEvent#getButton} 111 * <P> 112 * For example, if the first mouse button is pressed, events are sent in the 113 * following order: 114 * <pre><b> 115 * id modifiers button</b>{@code 116 * MOUSE_PRESSED: BUTTON1_MASK BUTTON1 117 * MOUSE_RELEASED: BUTTON1_MASK BUTTON1 118 * MOUSE_CLICKED: BUTTON1_MASK BUTTON1 119 * }</pre> 120 * When multiple mouse buttons are pressed, each press, release, and click 121 * results in a separate event. 122 * <P> 123 * For example, if the user presses <b>button 1</b> followed by 124 * <b>button 2</b>, and then releases them in the same order, 125 * the following sequence of events is generated: 126 * <pre><b> 127 * id modifiers button</b>{@code 128 * MOUSE_PRESSED: BUTTON1_MASK BUTTON1 129 * MOUSE_PRESSED: BUTTON2_MASK BUTTON2 130 * MOUSE_RELEASED: BUTTON1_MASK BUTTON1 131 * MOUSE_CLICKED: BUTTON1_MASK BUTTON1 132 * MOUSE_RELEASED: BUTTON2_MASK BUTTON2 133 * MOUSE_CLICKED: BUTTON2_MASK BUTTON2 134 * }</pre> 135 * If <b>button 2</b> is released first, the 136 * {@code MOUSE_RELEASED}/{@code MOUSE_CLICKED} pair 137 * for {@code BUTTON2_MASK} arrives first, 138 * followed by the pair for {@code BUTTON1_MASK}. 139 * <p> 140 * Some extra mouse buttons are added to extend the standard set of buttons 141 * represented by the following constants:{@code BUTTON1}, {@code BUTTON2}, and {@code BUTTON3}. 142 * Extra buttons have no assigned {@code BUTTONx} 143 * constants as well as their button masks have no assigned {@code BUTTONx_DOWN_MASK} 144 * constants. Nevertheless, ordinal numbers starting from 4 may be 145 * used as button numbers (button ids). Values obtained by the 146 * {@link InputEvent#getMaskForButton(int) getMaskForButton(button)} method may be used 147 * as button masks. 148 * <p> 149 * {@code MOUSE_DRAGGED} events are delivered to the {@code Component} 150 * in which the mouse button was pressed until the mouse button is released 151 * (regardless of whether the mouse position is within the bounds of the 152 * {@code Component}). Due to platform-dependent Drag&Drop implementations, 153 * {@code MOUSE_DRAGGED} events may not be delivered during a native 154 * Drag&Drop operation. 155 * 156 * In a multi-screen environment mouse drag events are delivered to the 157 * {@code Component} even if the mouse position is outside the bounds of the 158 * {@code GraphicsConfiguration} associated with that 159 * {@code Component}. However, the reported position for mouse drag events 160 * in this case may differ from the actual mouse position: 161 * <ul> 162 * <li>In a multi-screen environment without a virtual device: 163 * <br> 164 * The reported coordinates for mouse drag events are clipped to fit within the 165 * bounds of the {@code GraphicsConfiguration} associated with 166 * the {@code Component}. 167 * <li>In a multi-screen environment with a virtual device: 168 * <br> 169 * The reported coordinates for mouse drag events are clipped to fit within the 170 * bounds of the virtual device associated with the {@code Component}. 171 * </ul> 172 * <p> 173 * An unspecified behavior will be caused if the {@code id} parameter 174 * of any particular {@code MouseEvent} instance is not 175 * in the range from {@code MOUSE_FIRST} to {@code MOUSE_LAST}-1 176 * ({@code MOUSE_WHEEL} is not acceptable). 177 * 178 * @author Carl Quinn 179 * 180 * @see MouseAdapter 181 * @see MouseListener 182 * @see MouseMotionAdapter 183 * @see MouseMotionListener 184 * @see MouseWheelListener 185 * @see <a href="http://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html">Tutorial: Writing a Mouse Listener</a> 186 * @see <a href="http://docs.oracle.com/javase/tutorial/uiswing/events/mousemotionlistener.html">Tutorial: Writing a Mouse Motion Listener</a> 187 * 188 * @since 1.1 189 */ 190 public class MouseEvent extends InputEvent { 191 192 /** 193 * The first number in the range of ids used for mouse events. 194 */ 195 public static final int MOUSE_FIRST = 500; 196 197 /** 198 * The last number in the range of ids used for mouse events. 199 */ 200 public static final int MOUSE_LAST = 507; 201 202 /** 203 * The "mouse clicked" event. This {@code MouseEvent} 204 * occurs when a mouse button is pressed and released. 205 */ 206 public static final int MOUSE_CLICKED = MOUSE_FIRST; 207 208 /** 209 * The "mouse pressed" event. This {@code MouseEvent} 210 * occurs when a mouse button is pushed down. 211 */ 212 public static final int MOUSE_PRESSED = 1 + MOUSE_FIRST; //Event.MOUSE_DOWN 213 214 /** 215 * The "mouse released" event. This {@code MouseEvent} 216 * occurs when a mouse button is let up. 217 */ 218 public static final int MOUSE_RELEASED = 2 + MOUSE_FIRST; //Event.MOUSE_UP 219 220 /** 221 * The "mouse moved" event. This {@code MouseEvent} 222 * occurs when the mouse position changes. 223 */ 224 public static final int MOUSE_MOVED = 3 + MOUSE_FIRST; //Event.MOUSE_MOVE 225 226 /** 227 * The "mouse entered" event. This {@code MouseEvent} 228 * occurs when the mouse cursor enters the unobscured part of component's 229 * geometry. 230 */ 231 public static final int MOUSE_ENTERED = 4 + MOUSE_FIRST; //Event.MOUSE_ENTER 232 233 /** 234 * The "mouse exited" event. This {@code MouseEvent} 235 * occurs when the mouse cursor exits the unobscured part of component's 236 * geometry. 237 */ 238 public static final int MOUSE_EXITED = 5 + MOUSE_FIRST; //Event.MOUSE_EXIT 239 240 /** 241 * The "mouse dragged" event. This {@code MouseEvent} 242 * occurs when the mouse position changes while a mouse button is pressed. 243 */ 244 public static final int MOUSE_DRAGGED = 6 + MOUSE_FIRST; //Event.MOUSE_DRAG 245 246 /** 247 * The "mouse wheel" event. This is the only {@code MouseWheelEvent}. 248 * It occurs when a mouse equipped with a wheel has its wheel rotated. 249 * @since 1.4 250 */ 251 public static final int MOUSE_WHEEL = 7 + MOUSE_FIRST; 252 253 /** 254 * Indicates no mouse buttons; used by {@link #getButton}. 255 * @since 1.4 256 */ 257 public static final int NOBUTTON = 0; 258 259 /** 260 * Indicates mouse button #1; used by {@link #getButton}. 261 * @since 1.4 262 */ 263 public static final int BUTTON1 = 1; 264 265 /** 266 * Indicates mouse button #2; used by {@link #getButton}. 267 * @since 1.4 268 */ 269 public static final int BUTTON2 = 2; 270 271 /** 272 * Indicates mouse button #3; used by {@link #getButton}. 273 * @since 1.4 274 */ 275 public static final int BUTTON3 = 3; 276 277 /** 278 * The mouse event's x coordinate. 279 * The x value is relative to the component that fired the event. 280 * 281 * @serial 282 * @see #getX() 283 */ 284 int x; 285 286 /** 287 * The mouse event's y coordinate. 288 * The y value is relative to the component that fired the event. 289 * 290 * @serial 291 * @see #getY() 292 */ 293 int y; 294 295 /** 296 * The mouse event's x absolute coordinate. 297 * In a virtual device multi-screen environment in which the 298 * desktop area could span multiple physical screen devices, 299 * this coordinate is relative to the virtual coordinate system. 300 * Otherwise, this coordinate is relative to the coordinate system 301 * associated with the Component's GraphicsConfiguration. 302 * 303 * @serial 304 */ 305 private int xAbs; 306 307 /** 308 * The mouse event's y absolute coordinate. 309 * In a virtual device multi-screen environment in which the 310 * desktop area could span multiple physical screen devices, 311 * this coordinate is relative to the virtual coordinate system. 312 * Otherwise, this coordinate is relative to the coordinate system 313 * associated with the Component's GraphicsConfiguration. 314 * 315 * @serial 316 */ 317 private int yAbs; 318 319 /** 320 * Indicates the number of quick consecutive clicks of 321 * a mouse button. 322 * clickCount will be valid for only three mouse events :<BR> 323 * {@code MOUSE_CLICKED}, 324 * {@code MOUSE_PRESSED} and 325 * {@code MOUSE_RELEASED}. 326 * For the above, the {@code clickCount} will be at least 1. 327 * For all other events the count will be 0. 328 * 329 * @serial 330 * @see #getClickCount() 331 */ 332 int clickCount; 333 334 /** 335 * Indicates which, if any, of the mouse buttons has changed state. 336 * 337 * The valid values are ranged from 0 to the value returned by the 338 * {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} method. 339 * This range already includes constants {@code NOBUTTON}, {@code BUTTON1}, 340 * {@code BUTTON2}, and {@code BUTTON3} 341 * if these buttons are present. So it is allowed to use these constants too. 342 * For example, for a mouse with two buttons this field may contain the following values: 343 * <ul> 344 * <li> 0 ({@code NOBUTTON}) 345 * <li> 1 ({@code BUTTON1}) 346 * <li> 2 ({@code BUTTON2}) 347 * </ul> 348 * If a mouse has 5 buttons, this field may contain the following values: 349 * <ul> 350 * <li> 0 ({@code NOBUTTON}) 351 * <li> 1 ({@code BUTTON1}) 352 * <li> 2 ({@code BUTTON2}) 353 * <li> 3 ({@code BUTTON3}) 354 * <li> 4 355 * <li> 5 356 * </ul> 357 * If support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled()} disabled by Java 358 * then the field may not contain the value larger than {@code BUTTON3}. 359 * @serial 360 * @see #getButton() 361 * @see java.awt.Toolkit#areExtraMouseButtonsEnabled() 362 */ 363 int button; 364 365 /** 366 * A property used to indicate whether a Popup Menu 367 * should appear with a certain gestures. 368 * If {@code popupTrigger} = {@code false}, 369 * no popup menu should appear. If it is {@code true} 370 * then a popup menu should appear. 371 * 372 * @serial 373 * @see java.awt.PopupMenu 374 * @see #isPopupTrigger() 375 */ 376 boolean popupTrigger = false; 377 378 /* 379 * JDK 1.1 serialVersionUID 380 */ 381 private static final long serialVersionUID = -991214153494842848L; 382 383 /** 384 * A number of buttons available on the mouse at the {@code Toolkit} machinery startup. 385 */ 386 private static int cachedNumberOfButtons; 387 388 static { 389 /* ensure that the necessary native libraries are loaded */ 390 NativeLibLoader.loadLibraries(); 391 if (!GraphicsEnvironment.isHeadless()) { 392 initIDs(); 393 } 394 final Toolkit tk = Toolkit.getDefaultToolkit(); 395 if (tk instanceof SunToolkit) { 396 cachedNumberOfButtons = ((SunToolkit)tk).getNumberOfButtons(); 397 } else { 398 //It's expected that some toolkits (Headless, 399 //whatever besides SunToolkit) could also operate. 400 cachedNumberOfButtons = 3; 401 } 402 } 403 404 /** 405 * Initialize JNI field and method IDs for fields that may be 406 * accessed from C. 407 */ 408 private static native void initIDs(); 409 410 /** 411 * Returns the absolute x, y position of the event. 412 * In a virtual device multi-screen environment in which the 413 * desktop area could span multiple physical screen devices, 414 * these coordinates are relative to the virtual coordinate system. 415 * Otherwise, these coordinates are relative to the coordinate system 416 * associated with the Component's GraphicsConfiguration. 417 * 418 * @return a {@code Point} object containing the absolute x 419 * and y coordinates. 420 * 421 * @see java.awt.GraphicsConfiguration 422 * @since 1.6 423 */ 424 public Point getLocationOnScreen(){ 425 return new Point(xAbs, yAbs); 426 } 427 428 /** 429 * Returns the absolute horizontal x position of the event. 430 * In a virtual device multi-screen environment in which the 431 * desktop area could span multiple physical screen devices, 432 * this coordinate is relative to the virtual coordinate system. 433 * Otherwise, this coordinate is relative to the coordinate system 434 * associated with the Component's GraphicsConfiguration. 435 * 436 * @return x an integer indicating absolute horizontal position. 437 * 438 * @see java.awt.GraphicsConfiguration 439 * @since 1.6 440 */ 441 public int getXOnScreen() { 442 return xAbs; 443 } 444 445 /** 446 * Returns the absolute vertical y position of the event. 447 * In a virtual device multi-screen environment in which the 448 * desktop area could span multiple physical screen devices, 449 * this coordinate is relative to the virtual coordinate system. 450 * Otherwise, this coordinate is relative to the coordinate system 451 * associated with the Component's GraphicsConfiguration. 452 * 453 * @return y an integer indicating absolute vertical position. 454 * 455 * @see java.awt.GraphicsConfiguration 456 * @since 1.6 457 */ 458 public int getYOnScreen() { 459 return yAbs; 460 } 461 462 /** 463 * Constructs a {@code MouseEvent} object with the 464 * specified source component, 465 * type, time, modifiers, coordinates, click count, popupTrigger flag, 466 * and button number. 467 * <p> 468 * Creating an invalid event (such 469 * as by using more than one of the old _MASKs, or modifier/button 470 * values which don't match) results in unspecified behavior. 471 * An invocation of the form 472 * {@code MouseEvent(source, id, when, modifiers, x, y, clickCount, popupTrigger, button)} 473 * behaves in exactly the same way as the invocation 474 * {@link #MouseEvent(Component, int, long, int, int, int, 475 * int, int, int, boolean, int) MouseEvent(source, id, when, modifiers, 476 * x, y, xAbs, yAbs, clickCount, popupTrigger, button)} 477 * where xAbs and yAbs defines as source's location on screen plus 478 * relative coordinates x and y. 479 * xAbs and yAbs are set to zero if the source is not showing. 480 * This method throws an 481 * {@code IllegalArgumentException} if {@code source} 482 * is {@code null}. 483 * 484 * @param source The {@code Component} that originated the event 485 * @param id An integer indicating the type of event. 486 * For information on allowable values, see 487 * the class description for {@link MouseEvent} 488 * @param when A long integer that gives the time the event occurred. 489 * Passing negative or zero value 490 * is not recommended 491 * @param modifiers a modifier mask describing the modifier keys and mouse 492 * buttons (for example, shift, ctrl, alt, and meta) that 493 * are down during the event. 494 * Only extended modifiers are allowed to be used as a 495 * value for this parameter (see the {@link InputEvent#getModifiersEx} 496 * class for the description of extended modifiers). 497 * Passing negative parameter 498 * is not recommended. 499 * Zero value means that no modifiers were passed 500 * @param x The horizontal x coordinate for the mouse location. 501 * It is allowed to pass negative values 502 * @param y The vertical y coordinate for the mouse location. 503 * It is allowed to pass negative values 504 * @param clickCount The number of mouse clicks associated with event. 505 * Passing negative value 506 * is not recommended 507 * @param popupTrigger A boolean that equals {@code true} if this event 508 * is a trigger for a popup menu 509 * @param button An integer that indicates, which of the mouse buttons has 510 * changed its state. 511 * The following rules are applied to this parameter: 512 * <ul> 513 * <li>If support for the extended mouse buttons is 514 * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java 515 * then it is allowed to create {@code MouseEvent} objects only with the standard buttons: 516 * {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2}, and 517 * {@code BUTTON3}. 518 * <li> If support for the extended mouse buttons is 519 * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java 520 * then it is allowed to create {@code MouseEvent} objects with 521 * the standard buttons. 522 * In case the support for extended mouse buttons is 523 * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java, then 524 * in addition to the standard buttons, {@code MouseEvent} objects can be created 525 * using buttons from the range starting from 4 to 526 * {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} 527 * if the mouse has more than three buttons. 528 * </ul> 529 * @throws IllegalArgumentException if {@code button} is less than zero 530 * @throws IllegalArgumentException if {@code source} is null 531 * @throws IllegalArgumentException if {@code button} is greater than BUTTON3 532 * and the support for extended mouse buttons is 533 * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java 534 * @throws IllegalArgumentException if {@code button} is greater than the 535 * {@link java.awt.MouseInfo#getNumberOfButtons() current number of buttons} 536 * and the support for extended mouse buttons is 537 * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} 538 * by Java 539 * @throws IllegalArgumentException if an invalid {@code button} 540 * value is passed in 541 * @throws IllegalArgumentException if {@code source} is null 542 * @see #getSource() 543 * @see #getID() 544 * @see #getWhen() 545 * @see #getModifiers() 546 * @see #getX() 547 * @see #getY() 548 * @see #getClickCount() 549 * @see #isPopupTrigger() 550 * @see #getButton() 551 * @since 1.4 552 */ 553 public MouseEvent(Component source, int id, long when, int modifiers, 554 int x, int y, int clickCount, boolean popupTrigger, 555 int button) 556 { 557 this(source, id, when, modifiers, x, y, 0, 0, clickCount, popupTrigger, button); 558 Point eventLocationOnScreen = new Point(0, 0); 559 try { 560 eventLocationOnScreen = source.getLocationOnScreen(); 561 this.xAbs = eventLocationOnScreen.x + x; 562 this.yAbs = eventLocationOnScreen.y + y; 563 } catch (IllegalComponentStateException e){ 564 this.xAbs = 0; 565 this.yAbs = 0; 566 } 567 } 568 569 /** 570 * Constructs a {@code MouseEvent} object with the 571 * specified source component, 572 * type, modifiers, coordinates, click count, and popupTrigger flag. 573 * An invocation of the form 574 * {@code MouseEvent(source, id, when, modifiers, x, y, clickCount, popupTrigger)} 575 * behaves in exactly the same way as the invocation 576 * {@link #MouseEvent(Component, int, long, int, int, int, 577 * int, int, int, boolean, int) MouseEvent(source, id, when, modifiers, 578 * x, y, xAbs, yAbs, clickCount, popupTrigger, MouseEvent.NOBUTTON)} 579 * where xAbs and yAbs defines as source's location on screen plus 580 * relative coordinates x and y. 581 * xAbs and yAbs are set to zero if the source is not showing. 582 * This method throws an {@code IllegalArgumentException} 583 * if {@code source} is {@code null}. 584 * 585 * @param source The {@code Component} that originated the event 586 * @param id An integer indicating the type of event. 587 * For information on allowable values, see 588 * the class description for {@link MouseEvent} 589 * @param when A long integer that gives the time the event occurred. 590 * Passing negative or zero value 591 * is not recommended 592 * @param modifiers a modifier mask describing the modifier keys and mouse 593 * buttons (for example, shift, ctrl, alt, and meta) that 594 * are down during the event. 595 * Only extended modifiers are allowed to be used as a 596 * value for this parameter (see the {@link InputEvent#getModifiersEx} 597 * class for the description of extended modifiers). 598 * Passing negative parameter 599 * is not recommended. 600 * Zero value means that no modifiers were passed 601 * @param x The horizontal x coordinate for the mouse location. 602 * It is allowed to pass negative values 603 * @param y The vertical y coordinate for the mouse location. 604 * It is allowed to pass negative values 605 * @param clickCount The number of mouse clicks associated with event. 606 * Passing negative value 607 * is not recommended 608 * @param popupTrigger A boolean that equals {@code true} if this event 609 * is a trigger for a popup menu 610 * @throws IllegalArgumentException if {@code source} is null 611 * @see #getSource() 612 * @see #getID() 613 * @see #getWhen() 614 * @see #getModifiers() 615 * @see #getX() 616 * @see #getY() 617 * @see #getClickCount() 618 * @see #isPopupTrigger() 619 */ 620 public MouseEvent(Component source, int id, long when, int modifiers, 621 int x, int y, int clickCount, boolean popupTrigger) { 622 this(source, id, when, modifiers, x, y, clickCount, popupTrigger, NOBUTTON); 623 } 624 625 626 /* if the button is an extra button and it is released or clicked then in Xsystem its state 627 is not modified. Exclude this button number from ExtModifiers mask.*/ 628 private transient boolean shouldExcludeButtonFromExtModifiers = false; 629 630 /** 631 * {@inheritDoc} 632 */ 633 public int getModifiersEx() { 634 int tmpModifiers = modifiers; 635 if (shouldExcludeButtonFromExtModifiers) { 636 tmpModifiers &= ~(InputEvent.getMaskForButton(getButton())); 637 } 638 return tmpModifiers & ~JDK_1_3_MODIFIERS; 639 } 640 641 /** 642 * Constructs a {@code MouseEvent} object with the 643 * specified source component, 644 * type, time, modifiers, coordinates, absolute coordinates, click count, popupTrigger flag, 645 * and button number. 646 * <p> 647 * Creating an invalid event (such 648 * as by using more than one of the old _MASKs, or modifier/button 649 * values which don't match) results in unspecified behavior. 650 * Even if inconsistent values for relative and absolute coordinates are 651 * passed to the constructor, the mouse event instance is still 652 * created and no exception is thrown. 653 * This method throws an 654 * {@code IllegalArgumentException} if {@code source} 655 * is {@code null}. 656 * 657 * @param source The {@code Component} that originated the event 658 * @param id An integer indicating the type of event. 659 * For information on allowable values, see 660 * the class description for {@link MouseEvent} 661 * @param when A long integer that gives the time the event occurred. 662 * Passing negative or zero value 663 * is not recommended 664 * @param modifiers a modifier mask describing the modifier keys and mouse 665 * buttons (for example, shift, ctrl, alt, and meta) that 666 * are down during the event. 667 * Only extended modifiers are allowed to be used as a 668 * value for this parameter (see the {@link InputEvent#getModifiersEx} 669 * class for the description of extended modifiers). 670 * Passing negative parameter 671 * is not recommended. 672 * Zero value means that no modifiers were passed 673 * @param x The horizontal x coordinate for the mouse location. 674 * It is allowed to pass negative values 675 * @param y The vertical y coordinate for the mouse location. 676 * It is allowed to pass negative values 677 * @param xAbs The absolute horizontal x coordinate for the mouse location 678 * It is allowed to pass negative values 679 * @param yAbs The absolute vertical y coordinate for the mouse location 680 * It is allowed to pass negative values 681 * @param clickCount The number of mouse clicks associated with event. 682 * Passing negative value 683 * is not recommended 684 * @param popupTrigger A boolean that equals {@code true} if this event 685 * is a trigger for a popup menu 686 * @param button An integer that indicates, which of the mouse buttons has 687 * changed its state. 688 * The following rules are applied to this parameter: 689 * <ul> 690 * <li>If support for the extended mouse buttons is 691 * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java 692 * then it is allowed to create {@code MouseEvent} objects only with the standard buttons: 693 * {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2}, and 694 * {@code BUTTON3}. 695 * <li> If support for the extended mouse buttons is 696 * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java 697 * then it is allowed to create {@code MouseEvent} objects with 698 * the standard buttons. 699 * In case the support for extended mouse buttons is 700 * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java, then 701 * in addition to the standard buttons, {@code MouseEvent} objects can be created 702 * using buttons from the range starting from 4 to 703 * {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} 704 * if the mouse has more than three buttons. 705 * </ul> 706 * @throws IllegalArgumentException if {@code button} is less than zero 707 * @throws IllegalArgumentException if {@code source} is null 708 * @throws IllegalArgumentException if {@code button} is greater than BUTTON3 709 * and the support for extended mouse buttons is 710 * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java 711 * @throws IllegalArgumentException if {@code button} is greater than the 712 * {@link java.awt.MouseInfo#getNumberOfButtons() 713 * current number of buttons} and the support 714 * for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} 715 * by Java 716 * @throws IllegalArgumentException if an invalid {@code button} 717 * value is passed in 718 * @throws IllegalArgumentException if {@code source} is null 719 * @see #getSource() 720 * @see #getID() 721 * @see #getWhen() 722 * @see #getModifiers() 723 * @see #getX() 724 * @see #getY() 725 * @see #getXOnScreen() 726 * @see #getYOnScreen() 727 * @see #getClickCount() 728 * @see #isPopupTrigger() 729 * @see #getButton() 730 * @see #button 731 * @see Toolkit#areExtraMouseButtonsEnabled() 732 * @see java.awt.MouseInfo#getNumberOfButtons() 733 * @see InputEvent#getMaskForButton(int) 734 * @since 1.6 735 */ 736 @SuppressWarnings("deprecation") 737 public MouseEvent(Component source, int id, long when, int modifiers, 738 int x, int y, int xAbs, int yAbs, 739 int clickCount, boolean popupTrigger, int button) 740 { 741 super(source, id, when, modifiers); 742 this.x = x; 743 this.y = y; 744 this.xAbs = xAbs; 745 this.yAbs = yAbs; 746 this.clickCount = clickCount; 747 this.popupTrigger = popupTrigger; 748 if (button < NOBUTTON){ 749 throw new IllegalArgumentException("Invalid button value :" + button); 750 } 751 if (button > BUTTON3) { 752 if (!Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled()){ 753 throw new IllegalArgumentException("Extra mouse events are disabled " + button); 754 } else { 755 if (button > cachedNumberOfButtons) { 756 throw new IllegalArgumentException("Nonexistent button " + button); 757 } 758 } 759 // XToolkit: extra buttons are not reporting about their state correctly. 760 // Being pressed they report the state=0 both on the press and on the release. 761 // For 1-3 buttons the state value equals zero on press and non-zero on release. 762 // Other modifiers like Shift, ALT etc seem report well with extra buttons. 763 // The problem reveals as follows: one button is pressed and then another button is pressed and released. 764 // So, the getModifiersEx() would not be zero due to a first button and we will skip this modifier. 765 // This may have to be moved into the peer code instead if possible. 766 767 if (getModifiersEx() != 0) { //There is at least one more button in a pressed state. 768 if (id == MouseEvent.MOUSE_RELEASED || id == MouseEvent.MOUSE_CLICKED){ 769 shouldExcludeButtonFromExtModifiers = true; 770 } 771 } 772 } 773 774 this.button = button; 775 776 if ((getModifiers() != 0) && (getModifiersEx() == 0)) { 777 setNewModifiers(); 778 } else if ((getModifiers() == 0) && 779 (getModifiersEx() != 0 || button != NOBUTTON) && 780 (button <= BUTTON3)) 781 { 782 setOldModifiers(); 783 } 784 } 785 786 /** 787 * Returns the horizontal x position of the event relative to the 788 * source component. 789 * 790 * @return x an integer indicating horizontal position relative to 791 * the component 792 */ 793 public int getX() { 794 return x; 795 } 796 797 /** 798 * Returns the vertical y position of the event relative to the 799 * source component. 800 * 801 * @return y an integer indicating vertical position relative to 802 * the component 803 */ 804 public int getY() { 805 return y; 806 } 807 808 /** 809 * Returns the x,y position of the event relative to the source component. 810 * 811 * @return a {@code Point} object containing the x and y coordinates 812 * relative to the source component 813 * 814 */ 815 public Point getPoint() { 816 int x; 817 int y; 818 synchronized (this) { 819 x = this.x; 820 y = this.y; 821 } 822 return new Point(x, y); 823 } 824 825 /** 826 * Translates the event's coordinates to a new position 827 * by adding specified {@code x} (horizontal) and {@code y} 828 * (vertical) offsets. 829 * 830 * @param x the horizontal x value to add to the current x 831 * coordinate position 832 * @param y the vertical y value to add to the current y 833 coordinate position 834 */ 835 public synchronized void translatePoint(int x, int y) { 836 this.x += x; 837 this.y += y; 838 } 839 840 /** 841 * Returns the number of mouse clicks associated with this event. 842 * 843 * @return integer value for the number of clicks 844 */ 845 public int getClickCount() { 846 return clickCount; 847 } 848 849 /** 850 * Returns which, if any, of the mouse buttons has changed state. 851 * The returned value is ranged 852 * from 0 to the {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} 853 * value. 854 * The returned value includes at least the following constants: 855 * <ul> 856 * <li> {@code NOBUTTON} 857 * <li> {@code BUTTON1} 858 * <li> {@code BUTTON2} 859 * <li> {@code BUTTON3} 860 * </ul> 861 * It is allowed to use those constants to compare with the returned button number in the application. 862 * For example, 863 * <pre> 864 * if (anEvent.getButton() == MouseEvent.BUTTON1) { 865 * </pre> 866 * In particular, for a mouse with one, two, or three buttons this method may return the following values: 867 * <ul> 868 * <li> 0 ({@code NOBUTTON}) 869 * <li> 1 ({@code BUTTON1}) 870 * <li> 2 ({@code BUTTON2}) 871 * <li> 3 ({@code BUTTON3}) 872 * </ul> 873 * Button numbers greater than {@code BUTTON3} have no constant identifier. 874 * So if a mouse with five buttons is 875 * installed, this method may return the following values: 876 * <ul> 877 * <li> 0 ({@code NOBUTTON}) 878 * <li> 1 ({@code BUTTON1}) 879 * <li> 2 ({@code BUTTON2}) 880 * <li> 3 ({@code BUTTON3}) 881 * <li> 4 882 * <li> 5 883 * </ul> 884 * <p> 885 * Note: If support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java 886 * then the AWT event subsystem does not produce mouse events for the extended mouse 887 * buttons. So it is not expected that this method returns anything except {@code NOBUTTON}, {@code BUTTON1}, 888 * {@code BUTTON2}, {@code BUTTON3}. 889 * 890 * @return one of the values from 0 to {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} 891 * if support for the extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java. 892 * That range includes {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2}, {@code BUTTON3}; 893 * <br> 894 * {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2} or {@code BUTTON3} 895 * if support for the extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java 896 * @since 1.4 897 * @see Toolkit#areExtraMouseButtonsEnabled() 898 * @see java.awt.MouseInfo#getNumberOfButtons() 899 * @see #MouseEvent(Component, int, long, int, int, int, int, int, int, boolean, int) 900 * @see InputEvent#getMaskForButton(int) 901 */ 902 public int getButton() { 903 return button; 904 } 905 906 /** 907 * Returns whether or not this mouse event is the popup menu 908 * trigger event for the platform. 909 * <p><b>Note</b>: Popup menus are triggered differently 910 * on different systems. Therefore, {@code isPopupTrigger} 911 * should be checked in both {@code mousePressed} 912 * and {@code mouseReleased} 913 * for proper cross-platform functionality. 914 * 915 * @return boolean, true if this event is the popup menu trigger 916 * for this platform 917 */ 918 public boolean isPopupTrigger() { 919 return popupTrigger; 920 } 921 922 /** 923 * Returns a {@code String} instance describing the modifier keys and 924 * mouse buttons that were down during the event, such as "Shift", 925 * or "Ctrl+Shift". These strings can be localized by changing 926 * the {@code awt.properties} file. 927 * <p> 928 * Note that the {@code InputEvent.ALT_MASK} and 929 * {@code InputEvent.BUTTON2_MASK} have equal values, 930 * so the "Alt" string is returned for both modifiers. Likewise, 931 * the {@code InputEvent.META_MASK} and 932 * {@code InputEvent.BUTTON3_MASK} have equal values, 933 * so the "Meta" string is returned for both modifiers. 934 * <p> 935 * Note that passing negative parameter is incorrect, 936 * and will cause the returning an unspecified string. 937 * Zero parameter means that no modifiers were passed and will 938 * cause the returning an empty string. 939 * 940 * @param modifiers A modifier mask describing the modifier keys and 941 * mouse buttons that were down during the event 942 * @return string string text description of the combination of modifier 943 * keys and mouse buttons that were down during the event 944 * @see InputEvent#getModifiersExText(int) 945 * @since 1.4 946 */ 947 @SuppressWarnings("deprecation") 948 public static String getMouseModifiersText(int modifiers) { 949 StringBuilder buf = new StringBuilder(); 950 if ((modifiers & InputEvent.ALT_MASK) != 0) { 951 buf.append(Toolkit.getProperty("AWT.alt", "Alt")); 952 buf.append("+"); 953 } 954 if ((modifiers & InputEvent.META_MASK) != 0) { 955 buf.append(Toolkit.getProperty("AWT.meta", "Meta")); 956 buf.append("+"); 957 } 958 if ((modifiers & InputEvent.CTRL_MASK) != 0) { 959 buf.append(Toolkit.getProperty("AWT.control", "Ctrl")); 960 buf.append("+"); 961 } 962 if ((modifiers & InputEvent.SHIFT_MASK) != 0) { 963 buf.append(Toolkit.getProperty("AWT.shift", "Shift")); 964 buf.append("+"); 965 } 966 if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) { 967 buf.append(Toolkit.getProperty("AWT.altGraph", "Alt Graph")); 968 buf.append("+"); 969 } 970 if ((modifiers & InputEvent.BUTTON1_MASK) != 0) { 971 buf.append(Toolkit.getProperty("AWT.button1", "Button1")); 972 buf.append("+"); 973 } 974 if ((modifiers & InputEvent.BUTTON2_MASK) != 0) { 975 buf.append(Toolkit.getProperty("AWT.button2", "Button2")); 976 buf.append("+"); 977 } 978 if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { 979 buf.append(Toolkit.getProperty("AWT.button3", "Button3")); 980 buf.append("+"); 981 } 982 983 int mask; 984 985 // TODO: add a toolkit field that holds a number of button on the mouse. 986 // As the method getMouseModifiersText() is static and obtain 987 // an integer as a parameter then we may not restrict this with the number 988 // of buttons installed on the mouse. 989 // It's a temporary solution. We need to somehow hold the number of buttons somewhere else. 990 for (int i = 1; i <= cachedNumberOfButtons; i++){ 991 mask = InputEvent.getMaskForButton(i); 992 if ((modifiers & mask) != 0 && 993 buf.indexOf(Toolkit.getProperty("AWT.button"+i, "Button"+i)) == -1) //1,2,3 buttons may already be there; so don't duplicate it. 994 { 995 buf.append(Toolkit.getProperty("AWT.button"+i, "Button"+i)); 996 buf.append("+"); 997 } 998 } 999 1000 if (buf.length() > 0) { 1001 buf.setLength(buf.length()-1); // remove trailing '+' 1002 } 1003 return buf.toString(); 1004 } 1005 1006 /** 1007 * Returns a parameter string identifying this event. 1008 * This method is useful for event-logging and for debugging. 1009 * 1010 * @return a string identifying the event and its attributes 1011 */ 1012 @SuppressWarnings("deprecation") 1013 public String paramString() { 1014 StringBuilder str = new StringBuilder(80); 1015 1016 switch(id) { 1017 case MOUSE_PRESSED: 1018 str.append("MOUSE_PRESSED"); 1019 break; 1020 case MOUSE_RELEASED: 1021 str.append("MOUSE_RELEASED"); 1022 break; 1023 case MOUSE_CLICKED: 1024 str.append("MOUSE_CLICKED"); 1025 break; 1026 case MOUSE_ENTERED: 1027 str.append("MOUSE_ENTERED"); 1028 break; 1029 case MOUSE_EXITED: 1030 str.append("MOUSE_EXITED"); 1031 break; 1032 case MOUSE_MOVED: 1033 str.append("MOUSE_MOVED"); 1034 break; 1035 case MOUSE_DRAGGED: 1036 str.append("MOUSE_DRAGGED"); 1037 break; 1038 case MOUSE_WHEEL: 1039 str.append("MOUSE_WHEEL"); 1040 break; 1041 default: 1042 str.append("unknown type"); 1043 } 1044 1045 // (x,y) coordinates 1046 str.append(",(").append(x).append(",").append(y).append(")"); 1047 str.append(",absolute(").append(xAbs).append(",").append(yAbs).append(")"); 1048 1049 if (id != MOUSE_DRAGGED && id != MOUSE_MOVED){ 1050 str.append(",button=").append(getButton()); 1051 } 1052 1053 if (getModifiers() != 0) { 1054 str.append(",modifiers=").append(getMouseModifiersText(modifiers)); 1055 } 1056 1057 if (getModifiersEx() != 0) { 1058 //Using plain "modifiers" here does show an excluded extended buttons in the string event representation. 1059 //getModifiersEx() solves the problem. 1060 str.append(",extModifiers=").append(getModifiersExText(getModifiersEx())); 1061 } 1062 1063 str.append(",clickCount=").append(clickCount); 1064 1065 return str.toString(); 1066 } 1067 1068 /** 1069 * Sets new modifiers by the old ones. 1070 * Also sets button. 1071 */ 1072 @SuppressWarnings("deprecation") 1073 private void setNewModifiers() { 1074 if ((modifiers & BUTTON1_MASK) != 0) { 1075 modifiers |= BUTTON1_DOWN_MASK; 1076 } 1077 if ((modifiers & BUTTON2_MASK) != 0) { 1078 modifiers |= BUTTON2_DOWN_MASK; 1079 } 1080 if ((modifiers & BUTTON3_MASK) != 0) { 1081 modifiers |= BUTTON3_DOWN_MASK; 1082 } 1083 if (id == MOUSE_PRESSED 1084 || id == MOUSE_RELEASED 1085 || id == MOUSE_CLICKED) 1086 { 1087 if ((modifiers & BUTTON1_MASK) != 0) { 1088 button = BUTTON1; 1089 modifiers &= ~BUTTON2_MASK & ~BUTTON3_MASK; 1090 if (id != MOUSE_PRESSED) { 1091 modifiers &= ~BUTTON1_DOWN_MASK; 1092 } 1093 } else if ((modifiers & BUTTON2_MASK) != 0) { 1094 button = BUTTON2; 1095 modifiers &= ~BUTTON1_MASK & ~BUTTON3_MASK; 1096 if (id != MOUSE_PRESSED) { 1097 modifiers &= ~BUTTON2_DOWN_MASK; 1098 } 1099 } else if ((modifiers & BUTTON3_MASK) != 0) { 1100 button = BUTTON3; 1101 modifiers &= ~BUTTON1_MASK & ~BUTTON2_MASK; 1102 if (id != MOUSE_PRESSED) { 1103 modifiers &= ~BUTTON3_DOWN_MASK; 1104 } 1105 } 1106 } 1107 if ((modifiers & InputEvent.ALT_MASK) != 0) { 1108 modifiers |= InputEvent.ALT_DOWN_MASK; 1109 } 1110 if ((modifiers & InputEvent.META_MASK) != 0) { 1111 modifiers |= InputEvent.META_DOWN_MASK; 1112 } 1113 if ((modifiers & InputEvent.SHIFT_MASK) != 0) { 1114 modifiers |= InputEvent.SHIFT_DOWN_MASK; 1115 } 1116 if ((modifiers & InputEvent.CTRL_MASK) != 0) { 1117 modifiers |= InputEvent.CTRL_DOWN_MASK; 1118 } 1119 if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) { 1120 modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK; 1121 } 1122 } 1123 1124 /** 1125 * Sets old modifiers by the new ones. 1126 */ 1127 @SuppressWarnings("deprecation") 1128 private void setOldModifiers() { 1129 if (id == MOUSE_PRESSED 1130 || id == MOUSE_RELEASED 1131 || id == MOUSE_CLICKED) 1132 { 1133 switch(button) { 1134 case BUTTON1: 1135 modifiers |= BUTTON1_MASK; 1136 break; 1137 case BUTTON2: 1138 modifiers |= BUTTON2_MASK; 1139 break; 1140 case BUTTON3: 1141 modifiers |= BUTTON3_MASK; 1142 break; 1143 } 1144 } else { 1145 if ((modifiers & BUTTON1_DOWN_MASK) != 0) { 1146 modifiers |= BUTTON1_MASK; 1147 } 1148 if ((modifiers & BUTTON2_DOWN_MASK) != 0) { 1149 modifiers |= BUTTON2_MASK; 1150 } 1151 if ((modifiers & BUTTON3_DOWN_MASK) != 0) { 1152 modifiers |= BUTTON3_MASK; 1153 } 1154 } 1155 if ((modifiers & ALT_DOWN_MASK) != 0) { 1156 modifiers |= ALT_MASK; 1157 } 1158 if ((modifiers & META_DOWN_MASK) != 0) { 1159 modifiers |= META_MASK; 1160 } 1161 if ((modifiers & SHIFT_DOWN_MASK) != 0) { 1162 modifiers |= SHIFT_MASK; 1163 } 1164 if ((modifiers & CTRL_DOWN_MASK) != 0) { 1165 modifiers |= CTRL_MASK; 1166 } 1167 if ((modifiers & ALT_GRAPH_DOWN_MASK) != 0) { 1168 modifiers |= ALT_GRAPH_MASK; 1169 } 1170 } 1171 1172 /** 1173 * Sets new modifiers by the old ones. 1174 * @serial 1175 */ 1176 @SuppressWarnings("deprecation") 1177 private void readObject(ObjectInputStream s) 1178 throws IOException, ClassNotFoundException { 1179 s.defaultReadObject(); 1180 if (getModifiers() != 0 && getModifiersEx() == 0) { 1181 setNewModifiers(); 1182 } 1183 } 1184 }