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 then zero 530 * @throws IllegalArgumentException if {@code source} is null 531 * @throws IllegalArgumentException if {@code button} is greater then BUTTON3 and the support for extended mouse buttons is 532 * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java 533 * @throws IllegalArgumentException if {@code button} is greater then the 534 * {@link java.awt.MouseInfo#getNumberOfButtons() current number of buttons} and the support 535 * for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} 536 * by Java 537 * @throws IllegalArgumentException if an invalid {@code button} 538 * value is passed in 539 * @throws IllegalArgumentException if {@code source} is null 540 * @see #getSource() 541 * @see #getID() 542 * @see #getWhen() 543 * @see #getModifiers() 544 * @see #getX() 545 * @see #getY() 546 * @see #getClickCount() 547 * @see #isPopupTrigger() 548 * @see #getButton() 549 * @since 1.4 550 */ 551 public MouseEvent(Component source, int id, long when, int modifiers, 552 int x, int y, int clickCount, boolean popupTrigger, 553 int button) 554 { 555 this(source, id, when, modifiers, x, y, 0, 0, clickCount, popupTrigger, button); 556 Point eventLocationOnScreen = new Point(0, 0); 557 try { 558 eventLocationOnScreen = source.getLocationOnScreen(); 559 this.xAbs = eventLocationOnScreen.x + x; 560 this.yAbs = eventLocationOnScreen.y + y; 561 } catch (IllegalComponentStateException e){ 562 this.xAbs = 0; 563 this.yAbs = 0; 564 } 565 } 566 567 /** 568 * Constructs a {@code MouseEvent} object with the 569 * specified source component, 570 * type, modifiers, coordinates, click count, and popupTrigger flag. 571 * An invocation of the form 572 * {@code MouseEvent(source, id, when, modifiers, x, y, clickCount, popupTrigger)} 573 * behaves in exactly the same way as the invocation 574 * {@link #MouseEvent(Component, int, long, int, int, int, 575 * int, int, int, boolean, int) MouseEvent(source, id, when, modifiers, 576 * x, y, xAbs, yAbs, clickCount, popupTrigger, MouseEvent.NOBUTTON)} 577 * where xAbs and yAbs defines as source's location on screen plus 578 * relative coordinates x and y. 579 * xAbs and yAbs are set to zero if the source is not showing. 580 * This method throws an {@code IllegalArgumentException} 581 * if {@code source} is {@code null}. 582 * 583 * @param source The {@code Component} that originated the event 584 * @param id An integer indicating the type of event. 585 * For information on allowable values, see 586 * the class description for {@link MouseEvent} 587 * @param when A long integer that gives the time the event occurred. 588 * Passing negative or zero value 589 * is not recommended 590 * @param modifiers a modifier mask describing the modifier keys and mouse 591 * buttons (for example, shift, ctrl, alt, and meta) that 592 * are down during the event. 593 * Only extended modifiers are allowed to be used as a 594 * value for this parameter (see the {@link InputEvent#getModifiersEx} 595 * class for the description of extended modifiers). 596 * Passing negative parameter 597 * is not recommended. 598 * Zero value means that no modifiers were passed 599 * @param x The horizontal x coordinate for the mouse location. 600 * It is allowed to pass negative values 601 * @param y The vertical y coordinate for the mouse location. 602 * It is allowed to pass negative values 603 * @param clickCount The number of mouse clicks associated with event. 604 * Passing negative value 605 * is not recommended 606 * @param popupTrigger A boolean that equals {@code true} if this event 607 * is a trigger for a popup menu 608 * @throws IllegalArgumentException if {@code source} is null 609 * @see #getSource() 610 * @see #getID() 611 * @see #getWhen() 612 * @see #getModifiers() 613 * @see #getX() 614 * @see #getY() 615 * @see #getClickCount() 616 * @see #isPopupTrigger() 617 */ 618 public MouseEvent(Component source, int id, long when, int modifiers, 619 int x, int y, int clickCount, boolean popupTrigger) { 620 this(source, id, when, modifiers, x, y, clickCount, popupTrigger, NOBUTTON); 621 } 622 623 624 /* if the button is an extra button and it is released or clicked then in Xsystem its state 625 is not modified. Exclude this button number from ExtModifiers mask.*/ 626 private transient boolean shouldExcludeButtonFromExtModifiers = false; 627 628 /** 629 * {@inheritDoc} 630 */ 631 public int getModifiersEx() { 632 int tmpModifiers = modifiers; 633 if (shouldExcludeButtonFromExtModifiers) { 634 tmpModifiers &= ~(InputEvent.getMaskForButton(getButton())); 635 } 636 return tmpModifiers & ~JDK_1_3_MODIFIERS; 637 } 638 639 /** 640 * Constructs a {@code MouseEvent} object with the 641 * specified source component, 642 * type, time, modifiers, coordinates, absolute coordinates, click count, popupTrigger flag, 643 * and button number. 644 * <p> 645 * Creating an invalid event (such 646 * as by using more than one of the old _MASKs, or modifier/button 647 * values which don't match) results in unspecified behavior. 648 * Even if inconsistent values for relative and absolute coordinates are 649 * passed to the constructor, the mouse event instance is still 650 * created and no exception is thrown. 651 * This method throws an 652 * {@code IllegalArgumentException} if {@code source} 653 * is {@code null}. 654 * 655 * @param source The {@code Component} that originated the event 656 * @param id An integer indicating the type of event. 657 * For information on allowable values, see 658 * the class description for {@link MouseEvent} 659 * @param when A long integer that gives the time the event occurred. 660 * Passing negative or zero value 661 * is not recommended 662 * @param modifiers a modifier mask describing the modifier keys and mouse 663 * buttons (for example, shift, ctrl, alt, and meta) that 664 * are down during the event. 665 * Only extended modifiers are allowed to be used as a 666 * value for this parameter (see the {@link InputEvent#getModifiersEx} 667 * class for the description of extended modifiers). 668 * Passing negative parameter 669 * is not recommended. 670 * Zero value means that no modifiers were passed 671 * @param x The horizontal x coordinate for the mouse location. 672 * It is allowed to pass negative values 673 * @param y The vertical y coordinate for the mouse location. 674 * It is allowed to pass negative values 675 * @param xAbs The absolute horizontal x coordinate for the mouse location 676 * It is allowed to pass negative values 677 * @param yAbs The absolute vertical y coordinate for the mouse location 678 * It is allowed to pass negative values 679 * @param clickCount The number of mouse clicks associated with event. 680 * Passing negative value 681 * is not recommended 682 * @param popupTrigger A boolean that equals {@code true} if this event 683 * is a trigger for a popup menu 684 * @param button An integer that indicates, which of the mouse buttons has 685 * changed its state. 686 * The following rules are applied to this parameter: 687 * <ul> 688 * <li>If support for the extended mouse buttons is 689 * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java 690 * then it is allowed to create {@code MouseEvent} objects only with the standard buttons: 691 * {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2}, and 692 * {@code BUTTON3}. 693 * <li> If support for the extended mouse buttons is 694 * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java 695 * then it is allowed to create {@code MouseEvent} objects with 696 * the standard buttons. 697 * In case the support for extended mouse buttons is 698 * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java, then 699 * in addition to the standard buttons, {@code MouseEvent} objects can be created 700 * using buttons from the range starting from 4 to 701 * {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} 702 * if the mouse has more than three buttons. 703 * </ul> 704 * @throws IllegalArgumentException if {@code button} is less then zero 705 * @throws IllegalArgumentException if {@code source} is null 706 * @throws IllegalArgumentException if {@code button} is greater then BUTTON3 and the support for extended mouse buttons is 707 * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java 708 * @throws IllegalArgumentException if {@code button} is greater then the 709 * {@link java.awt.MouseInfo#getNumberOfButtons() current number of buttons} and the support 710 * for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} 711 * by Java 712 * @throws IllegalArgumentException if an invalid {@code button} 713 * value is passed in 714 * @throws IllegalArgumentException if {@code source} is null 715 * @see #getSource() 716 * @see #getID() 717 * @see #getWhen() 718 * @see #getModifiers() 719 * @see #getX() 720 * @see #getY() 721 * @see #getXOnScreen() 722 * @see #getYOnScreen() 723 * @see #getClickCount() 724 * @see #isPopupTrigger() 725 * @see #getButton() 726 * @see #button 727 * @see Toolkit#areExtraMouseButtonsEnabled() 728 * @see java.awt.MouseInfo#getNumberOfButtons() 729 * @see InputEvent#getMaskForButton(int) 730 * @since 1.6 731 */ 732 public MouseEvent(Component source, int id, long when, int modifiers, 733 int x, int y, int xAbs, int yAbs, 734 int clickCount, boolean popupTrigger, int button) 735 { 736 super(source, id, when, modifiers); 737 this.x = x; 738 this.y = y; 739 this.xAbs = xAbs; 740 this.yAbs = yAbs; 741 this.clickCount = clickCount; 742 this.popupTrigger = popupTrigger; 743 if (button < NOBUTTON){ 744 throw new IllegalArgumentException("Invalid button value :" + button); 745 } 746 if (button > BUTTON3) { 747 if (!Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled()){ 748 throw new IllegalArgumentException("Extra mouse events are disabled " + button); 749 } else { 750 if (button > cachedNumberOfButtons) { 751 throw new IllegalArgumentException("Nonexistent button " + button); 752 } 753 } 754 // XToolkit: extra buttons are not reporting about their state correctly. 755 // Being pressed they report the state=0 both on the press and on the release. 756 // For 1-3 buttons the state value equals zero on press and non-zero on release. 757 // Other modifiers like Shift, ALT etc seem report well with extra buttons. 758 // The problem reveals as follows: one button is pressed and then another button is pressed and released. 759 // So, the getModifiersEx() would not be zero due to a first button and we will skip this modifier. 760 // This may have to be moved into the peer code instead if possible. 761 762 if (getModifiersEx() != 0) { //There is at least one more button in a pressed state. 763 if (id == MouseEvent.MOUSE_RELEASED || id == MouseEvent.MOUSE_CLICKED){ 764 shouldExcludeButtonFromExtModifiers = true; 765 } 766 } 767 } 768 769 this.button = button; 770 771 if ((getModifiers() != 0) && (getModifiersEx() == 0)) { 772 setNewModifiers(); 773 } else if ((getModifiers() == 0) && 774 (getModifiersEx() != 0 || button != NOBUTTON) && 775 (button <= BUTTON3)) 776 { 777 setOldModifiers(); 778 } 779 } 780 781 /** 782 * Returns the horizontal x position of the event relative to the 783 * source component. 784 * 785 * @return x an integer indicating horizontal position relative to 786 * the component 787 */ 788 public int getX() { 789 return x; 790 } 791 792 /** 793 * Returns the vertical y position of the event relative to the 794 * source component. 795 * 796 * @return y an integer indicating vertical position relative to 797 * the component 798 */ 799 public int getY() { 800 return y; 801 } 802 803 /** 804 * Returns the x,y position of the event relative to the source component. 805 * 806 * @return a {@code Point} object containing the x and y coordinates 807 * relative to the source component 808 * 809 */ 810 public Point getPoint() { 811 int x; 812 int y; 813 synchronized (this) { 814 x = this.x; 815 y = this.y; 816 } 817 return new Point(x, y); 818 } 819 820 /** 821 * Translates the event's coordinates to a new position 822 * by adding specified {@code x} (horizontal) and {@code y} 823 * (vertical) offsets. 824 * 825 * @param x the horizontal x value to add to the current x 826 * coordinate position 827 * @param y the vertical y value to add to the current y 828 coordinate position 829 */ 830 public synchronized void translatePoint(int x, int y) { 831 this.x += x; 832 this.y += y; 833 } 834 835 /** 836 * Returns the number of mouse clicks associated with this event. 837 * 838 * @return integer value for the number of clicks 839 */ 840 public int getClickCount() { 841 return clickCount; 842 } 843 844 /** 845 * Returns which, if any, of the mouse buttons has changed state. 846 * The returned value is ranged 847 * from 0 to the {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} 848 * value. 849 * The returned value includes at least the following constants: 850 * <ul> 851 * <li> {@code NOBUTTON} 852 * <li> {@code BUTTON1} 853 * <li> {@code BUTTON2} 854 * <li> {@code BUTTON3} 855 * </ul> 856 * It is allowed to use those constants to compare with the returned button number in the application. 857 * For example, 858 * <pre> 859 * if (anEvent.getButton() == MouseEvent.BUTTON1) { 860 * </pre> 861 * In particular, for a mouse with one, two, or three buttons this method may return the following values: 862 * <ul> 863 * <li> 0 ({@code NOBUTTON}) 864 * <li> 1 ({@code BUTTON1}) 865 * <li> 2 ({@code BUTTON2}) 866 * <li> 3 ({@code BUTTON3}) 867 * </ul> 868 * Button numbers greater then {@code BUTTON3} have no constant identifier. So if a mouse with five buttons is 869 * installed, this method may return the following values: 870 * <ul> 871 * <li> 0 ({@code NOBUTTON}) 872 * <li> 1 ({@code BUTTON1}) 873 * <li> 2 ({@code BUTTON2}) 874 * <li> 3 ({@code BUTTON3}) 875 * <li> 4 876 * <li> 5 877 * </ul> 878 * <p> 879 * Note: If support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java 880 * then the AWT event subsystem does not produce mouse events for the extended mouse 881 * buttons. So it is not expected that this method returns anything except {@code NOBUTTON}, {@code BUTTON1}, 882 * {@code BUTTON2}, {@code BUTTON3}. 883 * 884 * @return one of the values from 0 to {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()} 885 * if support for the extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java. 886 * That range includes {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2}, {@code BUTTON3}; 887 * <br> 888 * {@code NOBUTTON}, {@code BUTTON1}, {@code BUTTON2} or {@code BUTTON3} 889 * if support for the extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java 890 * @since 1.4 891 * @see Toolkit#areExtraMouseButtonsEnabled() 892 * @see java.awt.MouseInfo#getNumberOfButtons() 893 * @see #MouseEvent(Component, int, long, int, int, int, int, int, int, boolean, int) 894 * @see InputEvent#getMaskForButton(int) 895 */ 896 public int getButton() { 897 return button; 898 } 899 900 /** 901 * Returns whether or not this mouse event is the popup menu 902 * trigger event for the platform. 903 * <p><b>Note</b>: Popup menus are triggered differently 904 * on different systems. Therefore, {@code isPopupTrigger} 905 * should be checked in both {@code mousePressed} 906 * and {@code mouseReleased} 907 * for proper cross-platform functionality. 908 * 909 * @return boolean, true if this event is the popup menu trigger 910 * for this platform 911 */ 912 public boolean isPopupTrigger() { 913 return popupTrigger; 914 } 915 916 /** 917 * Returns a {@code String} instance describing the modifier keys and 918 * mouse buttons that were down during the event, such as "Shift", 919 * or "Ctrl+Shift". These strings can be localized by changing 920 * the {@code awt.properties} file. 921 * <p> 922 * Note that the {@code InputEvent.ALT_MASK} and 923 * {@code InputEvent.BUTTON2_MASK} have equal values, 924 * so the "Alt" string is returned for both modifiers. Likewise, 925 * the {@code InputEvent.META_MASK} and 926 * {@code InputEvent.BUTTON3_MASK} have equal values, 927 * so the "Meta" string is returned for both modifiers. 928 * <p> 929 * Note that passing negative parameter is incorrect, 930 * and will cause the returning an unspecified string. 931 * Zero parameter means that no modifiers were passed and will 932 * cause the returning an empty string. 933 * 934 * @param modifiers A modifier mask describing the modifier keys and 935 * mouse buttons that were down during the event 936 * @return string string text description of the combination of modifier 937 * keys and mouse buttons that were down during the event 938 * @see InputEvent#getModifiersExText(int) 939 * @since 1.4 940 */ 941 public static String getMouseModifiersText(int modifiers) { 942 StringBuilder buf = new StringBuilder(); 943 if ((modifiers & InputEvent.ALT_MASK) != 0) { 944 buf.append(Toolkit.getProperty("AWT.alt", "Alt")); 945 buf.append("+"); 946 } 947 if ((modifiers & InputEvent.META_MASK) != 0) { 948 buf.append(Toolkit.getProperty("AWT.meta", "Meta")); 949 buf.append("+"); 950 } 951 if ((modifiers & InputEvent.CTRL_MASK) != 0) { 952 buf.append(Toolkit.getProperty("AWT.control", "Ctrl")); 953 buf.append("+"); 954 } 955 if ((modifiers & InputEvent.SHIFT_MASK) != 0) { 956 buf.append(Toolkit.getProperty("AWT.shift", "Shift")); 957 buf.append("+"); 958 } 959 if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) { 960 buf.append(Toolkit.getProperty("AWT.altGraph", "Alt Graph")); 961 buf.append("+"); 962 } 963 if ((modifiers & InputEvent.BUTTON1_MASK) != 0) { 964 buf.append(Toolkit.getProperty("AWT.button1", "Button1")); 965 buf.append("+"); 966 } 967 if ((modifiers & InputEvent.BUTTON2_MASK) != 0) { 968 buf.append(Toolkit.getProperty("AWT.button2", "Button2")); 969 buf.append("+"); 970 } 971 if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { 972 buf.append(Toolkit.getProperty("AWT.button3", "Button3")); 973 buf.append("+"); 974 } 975 976 int mask; 977 978 // TODO: add a toolkit field that holds a number of button on the mouse. 979 // As the method getMouseModifiersText() is static and obtain 980 // an integer as a parameter then we may not restrict this with the number 981 // of buttons installed on the mouse. 982 // It's a temporary solution. We need to somehow hold the number of buttons somewhere else. 983 for (int i = 1; i <= cachedNumberOfButtons; i++){ 984 mask = InputEvent.getMaskForButton(i); 985 if ((modifiers & mask) != 0 && 986 buf.indexOf(Toolkit.getProperty("AWT.button"+i, "Button"+i)) == -1) //1,2,3 buttons may already be there; so don't duplicate it. 987 { 988 buf.append(Toolkit.getProperty("AWT.button"+i, "Button"+i)); 989 buf.append("+"); 990 } 991 } 992 993 if (buf.length() > 0) { 994 buf.setLength(buf.length()-1); // remove trailing '+' 995 } 996 return buf.toString(); 997 } 998 999 /** 1000 * Returns a parameter string identifying this event. 1001 * This method is useful for event-logging and for debugging. 1002 * 1003 * @return a string identifying the event and its attributes 1004 */ 1005 public String paramString() { 1006 StringBuilder str = new StringBuilder(80); 1007 1008 switch(id) { 1009 case MOUSE_PRESSED: 1010 str.append("MOUSE_PRESSED"); 1011 break; 1012 case MOUSE_RELEASED: 1013 str.append("MOUSE_RELEASED"); 1014 break; 1015 case MOUSE_CLICKED: 1016 str.append("MOUSE_CLICKED"); 1017 break; 1018 case MOUSE_ENTERED: 1019 str.append("MOUSE_ENTERED"); 1020 break; 1021 case MOUSE_EXITED: 1022 str.append("MOUSE_EXITED"); 1023 break; 1024 case MOUSE_MOVED: 1025 str.append("MOUSE_MOVED"); 1026 break; 1027 case MOUSE_DRAGGED: 1028 str.append("MOUSE_DRAGGED"); 1029 break; 1030 case MOUSE_WHEEL: 1031 str.append("MOUSE_WHEEL"); 1032 break; 1033 default: 1034 str.append("unknown type"); 1035 } 1036 1037 // (x,y) coordinates 1038 str.append(",(").append(x).append(",").append(y).append(")"); 1039 str.append(",absolute(").append(xAbs).append(",").append(yAbs).append(")"); 1040 1041 if (id != MOUSE_DRAGGED && id != MOUSE_MOVED){ 1042 str.append(",button=").append(getButton()); 1043 } 1044 1045 if (getModifiers() != 0) { 1046 str.append(",modifiers=").append(getMouseModifiersText(modifiers)); 1047 } 1048 1049 if (getModifiersEx() != 0) { 1050 //Using plain "modifiers" here does show an excluded extended buttons in the string event representation. 1051 //getModifiersEx() solves the problem. 1052 str.append(",extModifiers=").append(getModifiersExText(getModifiersEx())); 1053 } 1054 1055 str.append(",clickCount=").append(clickCount); 1056 1057 return str.toString(); 1058 } 1059 1060 /** 1061 * Sets new modifiers by the old ones. 1062 * Also sets button. 1063 */ 1064 private void setNewModifiers() { 1065 if ((modifiers & BUTTON1_MASK) != 0) { 1066 modifiers |= BUTTON1_DOWN_MASK; 1067 } 1068 if ((modifiers & BUTTON2_MASK) != 0) { 1069 modifiers |= BUTTON2_DOWN_MASK; 1070 } 1071 if ((modifiers & BUTTON3_MASK) != 0) { 1072 modifiers |= BUTTON3_DOWN_MASK; 1073 } 1074 if (id == MOUSE_PRESSED 1075 || id == MOUSE_RELEASED 1076 || id == MOUSE_CLICKED) 1077 { 1078 if ((modifiers & BUTTON1_MASK) != 0) { 1079 button = BUTTON1; 1080 modifiers &= ~BUTTON2_MASK & ~BUTTON3_MASK; 1081 if (id != MOUSE_PRESSED) { 1082 modifiers &= ~BUTTON1_DOWN_MASK; 1083 } 1084 } else if ((modifiers & BUTTON2_MASK) != 0) { 1085 button = BUTTON2; 1086 modifiers &= ~BUTTON1_MASK & ~BUTTON3_MASK; 1087 if (id != MOUSE_PRESSED) { 1088 modifiers &= ~BUTTON2_DOWN_MASK; 1089 } 1090 } else if ((modifiers & BUTTON3_MASK) != 0) { 1091 button = BUTTON3; 1092 modifiers &= ~BUTTON1_MASK & ~BUTTON2_MASK; 1093 if (id != MOUSE_PRESSED) { 1094 modifiers &= ~BUTTON3_DOWN_MASK; 1095 } 1096 } 1097 } 1098 if ((modifiers & InputEvent.ALT_MASK) != 0) { 1099 modifiers |= InputEvent.ALT_DOWN_MASK; 1100 } 1101 if ((modifiers & InputEvent.META_MASK) != 0) { 1102 modifiers |= InputEvent.META_DOWN_MASK; 1103 } 1104 if ((modifiers & InputEvent.SHIFT_MASK) != 0) { 1105 modifiers |= InputEvent.SHIFT_DOWN_MASK; 1106 } 1107 if ((modifiers & InputEvent.CTRL_MASK) != 0) { 1108 modifiers |= InputEvent.CTRL_DOWN_MASK; 1109 } 1110 if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) { 1111 modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK; 1112 } 1113 } 1114 1115 /** 1116 * Sets old modifiers by the new ones. 1117 */ 1118 private void setOldModifiers() { 1119 if (id == MOUSE_PRESSED 1120 || id == MOUSE_RELEASED 1121 || id == MOUSE_CLICKED) 1122 { 1123 switch(button) { 1124 case BUTTON1: 1125 modifiers |= BUTTON1_MASK; 1126 break; 1127 case BUTTON2: 1128 modifiers |= BUTTON2_MASK; 1129 break; 1130 case BUTTON3: 1131 modifiers |= BUTTON3_MASK; 1132 break; 1133 } 1134 } else { 1135 if ((modifiers & BUTTON1_DOWN_MASK) != 0) { 1136 modifiers |= BUTTON1_MASK; 1137 } 1138 if ((modifiers & BUTTON2_DOWN_MASK) != 0) { 1139 modifiers |= BUTTON2_MASK; 1140 } 1141 if ((modifiers & BUTTON3_DOWN_MASK) != 0) { 1142 modifiers |= BUTTON3_MASK; 1143 } 1144 } 1145 if ((modifiers & ALT_DOWN_MASK) != 0) { 1146 modifiers |= ALT_MASK; 1147 } 1148 if ((modifiers & META_DOWN_MASK) != 0) { 1149 modifiers |= META_MASK; 1150 } 1151 if ((modifiers & SHIFT_DOWN_MASK) != 0) { 1152 modifiers |= SHIFT_MASK; 1153 } 1154 if ((modifiers & CTRL_DOWN_MASK) != 0) { 1155 modifiers |= CTRL_MASK; 1156 } 1157 if ((modifiers & ALT_GRAPH_DOWN_MASK) != 0) { 1158 modifiers |= ALT_GRAPH_MASK; 1159 } 1160 } 1161 1162 /** 1163 * Sets new modifiers by the old ones. 1164 * @serial 1165 */ 1166 private void readObject(ObjectInputStream s) 1167 throws IOException, ClassNotFoundException { 1168 s.defaultReadObject(); 1169 if (getModifiers() != 0 && getModifiersEx() == 0) { 1170 setNewModifiers(); 1171 } 1172 } 1173 }