1 /* 2 * Copyright (c) 2010, 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 javafx.scene.input; 27 28 import com.sun.javafx.tk.Toolkit; 29 import javafx.beans.NamedArg; 30 import javafx.event.Event; 31 import javafx.event.EventTarget; 32 import javafx.event.EventType; 33 import javafx.geometry.Point3D; 34 import javafx.scene.Node; 35 36 import com.sun.javafx.scene.input.InputEventUtils; 37 import java.io.IOException; 38 39 // PENDING_DOC_REVIEW 40 /** 41 * When mouse event occurs, the top-most node under cursor is picked and 42 * the event is delivered to it through capturing and bubbling phases 43 * described at {@link javafx.event.EventDispatcher EventDispatcher}. 44 * <p> 45 * The mouse (pointer's) location is available relative to several 46 * coordinate systems: x,y - relative to the origin of the 47 * MouseEvent's node, sceneX,sceneY - relative to to the 48 * origin of the {@code Scene} that contains the node, 49 * screenX,screenY - relative to origin of the screen that 50 * contains the mouse pointer. 51 * 52 * <h4>Dragging gestures</h4> 53 * <p> 54 * There are three types of dragging gestures. They are all initiated by 55 * a mouse press event and terminated as a result of a mouse released 56 * event, the source node decides which gesture will take place. 57 * <p> 58 * The simple press-drag-release gesture is default. It's best used to allow 59 * changing size of a shape, dragging it around and so on. Whole 60 * press-drag-release gesture is delivered to one node. When mouse 61 * button is pressed, the top-most node is picked and all subsequent 62 * mouse events are delivered to the same node until the button is released. 63 * If a mouse clicked event is generated from these events, it is still 64 * delivered to the same node. 65 * <p> 66 * During simple press-drag-release gesture, the other nodes are not involved 67 * and don't get any events. If these nodes need to be involved in the gesture, 68 * full press-drag-release gesture has to be activated. This gesture is 69 * best used for connecting nodes by "wires", dragging nodes to other nodes etc. 70 * This gesture type is more closely described at 71 * {@link javafx.scene.input.MouseDragEvent MouseDragEvent} which contains 72 * the events delivered to the gesture targets. 73 * <p> 74 * The third gesture type is platform-supported drag-and-drop gesture. It serves 75 * best to transfer data and works also between (not necessarily FX) 76 * applications. This gesture type is more closely described 77 * at {@link javafx.scene.input.DragEvent DragEvent}. 78 * <p> 79 * In a short summary, simple press-drag-release gesture is activated 80 * automatically when a mouse button is pressed and delivers all 81 * {@code MouseEvent}s to the gesture source. When you start dragging, 82 * eventually the {@code DRAG_DETECTED} event arrives. In its handler 83 * you can either start full press-drag-release gesture by calling 84 * {@code startFullDrag} method on a node or scene - the {@code MouseDragEvent}s 85 * start to be delivered to gesture targets, or you can start drag and drop 86 * gesture by calling {@code startDragAndDrop} method on a node or scene - 87 * the system switches into the drag and drop mode and {@code DragEvent}s start 88 * to be delivered instead of {@code MouseEvent}s. If you don't call any of 89 * those methods, the simple press-drag-release gesture continues. 90 * <p> 91 * Note that dragging a finger over touch screen produces mouse dragging events, 92 * but also scroll gesture events. If it means a conflict in an application 93 * (the physical dragging action is handled by two different handlers), the 94 * {@code isSynthesized()} method may be used to detect the problem and make the 95 * dragging handlers behave accordingly. 96 * 97 * <h4>Mouse enter/exit handling</h4> 98 * <p> 99 * When mouse enters a node, the node gets {@code MOUSE_ENTERED} event, when 100 * it leaves, it gets {@code MOUSE_EXITED} event. These events are delivered 101 * only to the entered/exited node and seemingly don't go through the 102 * capturing/bubbling phases. This is the most common use-case. 103 * <p> 104 * When the capturing or bubbling is desired, there are 105 * {@code MOUSE_ENTERED_TARGET}/{@code MOUSE_EXITED_TARGET} events. These events 106 * go through capturing/bubbling phases normally. This means that parent may 107 * receive the {@code MOUSE_ENTERED_TARGET} event when mouse entered 108 * either the parent itself or some of its children. To distinguish between 109 * these two cases event target can be tested on equality with the node. 110 * <p> 111 * These two types are closely connected: 112 * {@code MOUSE_ENTERED}/{@code MOUSE_EXITED} are subtypes 113 * of {@code MOUSE_ENTERED_TARGET}/{@code MOUSE_EXITED_TARGET}. 114 * During capturing phase, 115 * {@code MOUSE_ENTERED_TARGET} is delivered to the 116 * parents. When the event is delivered to the event target (the node that 117 * has actually been entered), its type is switched to 118 * {@code MOUSE_ENTERED}. Then the type is switched back to 119 * {@code MOUSE_ENTERED_TARGET} for the bubbling phase. 120 * It's still one event just switching types, so if it's filtered or consumed, 121 * it affects both event variants. Thanks to the subtype-relationship, a 122 * {@code MOUSE_ENTERED_TARGET} event handler will receive the 123 * {@code MOUSE_ENTERED} event on target. 124 * 125 * <h4>Notes</h4> 126 * <ul> 127 * <li>For triggering context menus see the {@link ContextMenuEvent}.</li> 128 * </ul> 129 * @since JavaFX 2.0 130 */ 131 public class MouseEvent extends InputEvent { 132 133 private static final long serialVersionUID = 20121107L; 134 135 /** 136 * Common supertype for all mouse event types. 137 */ 138 public static final EventType<MouseEvent> ANY = 139 new EventType<MouseEvent>(InputEvent.ANY, "MOUSE"); 140 141 /** 142 * This event occurs when mouse button is pressed. This activates a 143 * press-drag-release gesture, so all subsequent mouse events until 144 * the button is released are delivered to the same node. 145 */ 146 public static final EventType<MouseEvent> MOUSE_PRESSED = 147 new EventType<MouseEvent>(MouseEvent.ANY, "MOUSE_PRESSED"); 148 149 /** 150 * This event occurs when mouse button is released. It is delivered 151 * to the same node where the button has been pressed which activated 152 * a press-drag-release gesture. 153 */ 154 public static final EventType<MouseEvent> MOUSE_RELEASED = 155 new EventType<MouseEvent>(MouseEvent.ANY, "MOUSE_RELEASED"); 156 157 /** 158 * This event occurs when mouse button has been clicked (pressed and 159 * released on the same node). This event provides a button-like behavior 160 * to any node. Note that even long drags can generate click event (it 161 * is delivered to the top-most node on which the mouse was both 162 * pressed and released). 163 */ 164 public static final EventType<MouseEvent> MOUSE_CLICKED = 165 new EventType<MouseEvent>(MouseEvent.ANY, "MOUSE_CLICKED"); 166 167 /** 168 * This event occurs when mouse enters a node. It's the bubbling variant, 169 * which is delivered also to all parents of the entered node (unless it 170 * was consumed). When notifications about mouse entering some of node's 171 * children are not desired, {@code MOUSE_ENTERED} event handler should 172 * be used. 173 * 174 * @see MouseEvent MouseEvent for more information about mouse entered/exited handling 175 */ 176 public static final EventType<MouseEvent> MOUSE_ENTERED_TARGET = 177 new EventType<MouseEvent>(MouseEvent.ANY, "MOUSE_ENTERED_TARGET"); 178 179 /** 180 * This event occurs when mouse enters a node. This event type is delivered 181 * only to the entered node, if parents want to filter it or get the 182 * bubbling event, they need to use {@code MOUSE_ENTERED_TARGET}. 183 * 184 * @see MouseEvent MouseEvent for more information about mouse entered/exited handling 185 */ 186 public static final EventType<MouseEvent> MOUSE_ENTERED = 187 new EventType<MouseEvent>(MouseEvent.MOUSE_ENTERED_TARGET, "MOUSE_ENTERED"); 188 189 /** 190 * This event occurs when mouse exits a node. It's the bubbling variant, 191 * which is delivered also to all parents of the exited node (unless it 192 * was consumed). When notifications about mouse exiting some of node's 193 * children are not desired, {@code MOUSE_EXITED} event handler should 194 * be used. 195 * 196 * @see MouseEvent MouseEvent for more information about mouse entered/exited handling 197 */ 198 public static final EventType<MouseEvent> MOUSE_EXITED_TARGET = 199 new EventType<MouseEvent>(MouseEvent.ANY, "MOUSE_EXITED_TARGET"); 200 201 /** 202 * This event occurs when mouse exits a node. This event type is delivered 203 * only to the exited node, if parents want to filter it or get the 204 * bubbling event, they need to use {@code MOUSE_EXITED_TARGET}. 205 * 206 * @see MouseEvent MouseEvent for more information about mouse entered/exited handling 207 */ 208 public static final EventType<MouseEvent> MOUSE_EXITED = 209 new EventType<MouseEvent>(MouseEvent.MOUSE_EXITED_TARGET, "MOUSE_EXITED"); 210 211 /** 212 * This event occurs when mouse moves within a node and no buttons 213 * are pressed. If any mouse button is pressed, MOUSE_DRAGGED event 214 * occurs instead. 215 */ 216 public static final EventType<MouseEvent> MOUSE_MOVED = 217 new EventType<MouseEvent>(MouseEvent.ANY, "MOUSE_MOVED"); 218 219 /** 220 * This event occurs when mouse moves with a pressed button. 221 * It is delivered to the same node where the button has been pressed 222 * which activated a press-drag-release gesture. It is delivered 223 * regardless of the mouse being within bounds of the node. 224 */ 225 public static final EventType<MouseEvent> MOUSE_DRAGGED = 226 new EventType<MouseEvent>(MouseEvent.ANY, "MOUSE_DRAGGED"); 227 228 /** 229 * This event is delivered to a node that is identified as a source of a 230 * dragging gesture. Handler of this event is the only place where 231 * full press-drag-release gesture or a drag and drop gesture can be 232 * started (by calling {@link javafx.scene.Node#startFullDrag startFullDrag()} 233 * of {@link javafx.scene.Node#startDragAndDrop startDragAndDrop()} method). 234 * If none of them is called, simple press-drag-release gesture will continue. 235 * <p> 236 * Note that his event is generated based on dragging the mouse over a 237 * platform-specific distance threshold. You can modify this behavior 238 * by calling {@code setDragDetect} method on any MOUSE_PRESSED or 239 * MOUSE_DRAGGED event. 240 * 241 * @see MouseEvent MouseEvent for more details about simple press-drag-release gestures 242 * @see MouseDragEvent MouseDragEvent for more details about full press-drag-release gestures 243 * @see DragEvent DragEvent for more details about drag and drop gestures 244 */ 245 public static final EventType<MouseEvent> DRAG_DETECTED = 246 new EventType<MouseEvent>(MouseEvent.ANY, "DRAG_DETECTED"); 247 248 /** 249 * Fills the given event by this event's coordinates recomputed to the given 250 * source object 251 * @param newEvent Event whose coordinates are to be filled 252 * @param newSource Source object to compute coordinates for 253 */ 254 void recomputeCoordinatesToSource(MouseEvent oldEvent, Object newSource) { 255 256 final Point3D newCoordinates = InputEventUtils.recomputeCoordinates( 257 pickResult, newSource); 258 259 x = newCoordinates.getX(); 260 y = newCoordinates.getY(); 261 z = newCoordinates.getZ(); 262 } 263 264 @Override 265 public EventType<? extends MouseEvent> getEventType() { 266 return (EventType<? extends MouseEvent>) super.getEventType(); 267 } 268 269 /** 270 * Copies this event for a different source and target. 271 * In most cases you don't need to use this method, it's called 272 * automatically when you fire the event. 273 * @param newSource New event source 274 * @param newTarget New event target 275 * @return copy of this event for a different source and target 276 */ 277 @Override 278 public MouseEvent copyFor(Object newSource, EventTarget newTarget) { 279 MouseEvent e = (MouseEvent) super.copyFor(newSource, newTarget); 280 e.recomputeCoordinatesToSource(this, newSource); 281 return e; 282 } 283 284 /** 285 * Creates a copy of the given event with the given fields substituted. 286 * @param newSource the new source of the copied event 287 * @param newTarget the new target of the copied event 288 * @param eventType the new eventType 289 * @return the event copy with the fields substituted 290 * @since JavaFX 8.0 291 */ 292 public MouseEvent copyFor(Object newSource, EventTarget newTarget, EventType<? extends MouseEvent> eventType) { 293 MouseEvent e = copyFor(newSource, newTarget); 294 e.eventType = eventType; 295 return e; 296 } 297 298 /** 299 * Constructs new MouseEvent event with null source and target. 300 * @param eventType The type of the event. 301 * @param x The x with respect to the scene. 302 * @param y The y with respect to the scene. 303 * @param screenX The x coordinate relative to screen. 304 * @param screenY The y coordinate relative to screen. 305 * @param button the mouse button used 306 * @param clickCount number of click counts 307 * @param shiftDown true if shift modifier was pressed. 308 * @param controlDown true if control modifier was pressed. 309 * @param altDown true if alt modifier was pressed. 310 * @param metaDown true if meta modifier was pressed. 311 * @param primaryButtonDown true if primary button was pressed. 312 * @param middleButtonDown true if middle button was pressed. 313 * @param secondaryButtonDown true if secondary button was pressed. 314 * @param synthesized if this event was synthesized 315 * @param popupTrigger whether this event denotes a popup trigger for current platform 316 * @param stillSincePress see {@link #isStillSincePress() } 317 * @param pickResult pick result. Can be null, in this case a 2D pick result 318 * without any further values is constructed 319 * based on the scene coordinates 320 * @since JavaFX 8.0 321 */ 322 public MouseEvent( 323 @NamedArg("eventType") EventType<? extends MouseEvent> eventType, 324 @NamedArg("x") double x, @NamedArg("y") double y, 325 @NamedArg("screenX") double screenX, @NamedArg("screenY") double screenY, 326 @NamedArg("button") MouseButton button, 327 @NamedArg("clickCount") int clickCount, 328 @NamedArg("shiftDown") boolean shiftDown, 329 @NamedArg("controlDown") boolean controlDown, 330 @NamedArg("altDown") boolean altDown, 331 @NamedArg("metaDown") boolean metaDown, 332 @NamedArg("primaryButtonDown") boolean primaryButtonDown, 333 @NamedArg("middleButtonDown") boolean middleButtonDown, 334 @NamedArg("secondaryButtonDown") boolean secondaryButtonDown, 335 @NamedArg("synthesized") boolean synthesized, 336 @NamedArg("popupTrigger") boolean popupTrigger, 337 @NamedArg("stillSincePress") boolean stillSincePress, 338 @NamedArg("pickResult") PickResult pickResult) { 339 this(null, null, eventType, x, y, screenX, screenY, button, clickCount, 340 shiftDown, controlDown, altDown, metaDown, 341 primaryButtonDown, middleButtonDown, secondaryButtonDown, 342 synthesized, popupTrigger, stillSincePress, pickResult); 343 } 344 345 /** 346 * Constructs new MouseEvent event. 347 * @param source the source of the event. Can be null. 348 * @param target the target of the event. Can be null. 349 * @param eventType The type of the event. 350 * @param x The x with respect to the source. Should be in scene coordinates if source == null or source is not a Node. 351 * @param y The y with respect to the source. Should be in scene coordinates if source == null or source is not a Node. 352 * @param screenX The x coordinate relative to screen. 353 * @param screenY The y coordinate relative to screen. 354 * @param button the mouse button used 355 * @param clickCount number of click counts 356 * @param shiftDown true if shift modifier was pressed. 357 * @param controlDown true if control modifier was pressed. 358 * @param altDown true if alt modifier was pressed. 359 * @param metaDown true if meta modifier was pressed. 360 * @param primaryButtonDown true if primary button was pressed. 361 * @param middleButtonDown true if middle button was pressed. 362 * @param secondaryButtonDown true if secondary button was pressed. 363 * @param synthesized if this event was synthesized 364 * @param popupTrigger whether this event denotes a popup trigger for current platform 365 * @param stillSincePress see {@link #isStillSincePress() } 366 * @param pickResult pick result. Can be null, in this case a 2D pick result 367 * without any further values is constructed 368 * based on the scene coordinates and target 369 * @since JavaFX 8.0 370 */ 371 public MouseEvent(@NamedArg("source") Object source, @NamedArg("target") EventTarget target, 372 @NamedArg("eventType") EventType<? extends MouseEvent> eventType, 373 @NamedArg("x") double x, @NamedArg("y") double y, 374 @NamedArg("screenX") double screenX, @NamedArg("screenY") double screenY, 375 @NamedArg("button") MouseButton button, 376 @NamedArg("clickCount") int clickCount, 377 @NamedArg("shiftDown") boolean shiftDown, 378 @NamedArg("controlDown") boolean controlDown, 379 @NamedArg("altDown") boolean altDown, 380 @NamedArg("metaDown") boolean metaDown, 381 @NamedArg("primaryButtonDown") boolean primaryButtonDown, 382 @NamedArg("middleButtonDown") boolean middleButtonDown, 383 @NamedArg("secondaryButtonDown") boolean secondaryButtonDown, 384 @NamedArg("synthesized") boolean synthesized, 385 @NamedArg("popupTrigger") boolean popupTrigger, 386 @NamedArg("stillSincePress") boolean stillSincePress, 387 @NamedArg("pickResult") PickResult pickResult) { 388 super(source, target, eventType); 389 this.x = x; 390 this.y = y; 391 this.screenX = screenX; 392 this.screenY = screenY; 393 this.sceneX = x; 394 this.sceneY = y; 395 this.button = button; 396 this.clickCount = clickCount; 397 this.shiftDown = shiftDown; 398 this.controlDown = controlDown; 399 this.altDown = altDown; 400 this.metaDown = metaDown; 401 this.primaryButtonDown = primaryButtonDown; 402 this.middleButtonDown = middleButtonDown; 403 this.secondaryButtonDown = secondaryButtonDown; 404 this.synthesized = synthesized; 405 this.stillSincePress = stillSincePress; 406 this.popupTrigger = popupTrigger; 407 this.pickResult = pickResult; 408 this.pickResult = pickResult != null ? pickResult : new PickResult(target, x, y); 409 final Point3D p = InputEventUtils.recomputeCoordinates(this.pickResult, null); 410 this.x = p.getX(); 411 this.y = p.getY(); 412 this.z = p.getZ(); 413 } 414 415 /** 416 * Creates a copy of this mouse event of MouseDragEvent type 417 * @param e the mouse event to copy 418 * @param source the new source of the copied event 419 * @param target the new target of the copied event 420 * @param type the new MouseDragEvent type 421 * @param gestureSource the new source of the gesture 422 * @param pickResult pick result. Can be null, in this case a 2D pick result 423 * without any further values is constructed 424 * based on the scene coordinates 425 * @return new MouseDragEvent that was created from MouseEvent 426 * @since JavaFX 8.0 427 */ 428 public static MouseDragEvent copyForMouseDragEvent( 429 MouseEvent e, 430 Object source, EventTarget target, 431 EventType<MouseDragEvent> type, 432 Object gestureSource, PickResult pickResult) { 433 MouseDragEvent ev = new MouseDragEvent(source, target, 434 type, e.sceneX, e.sceneY, e.screenX, e.screenY, 435 e.button, e.clickCount, e.shiftDown, e.controlDown, 436 e.altDown, e.metaDown, e.primaryButtonDown, e.middleButtonDown, 437 e.secondaryButtonDown, e.synthesized, e.popupTrigger, 438 pickResult, gestureSource); 439 ev.recomputeCoordinatesToSource(e, source); 440 return ev; 441 } 442 private final Flags flags = new Flags(); 443 444 /** 445 * Determines whether this event will be followed by {@code DRAG_DETECTED} 446 * event. It has effect only with {@code MOUSE_PRESSED} and 447 * {@code MOUSE_DRAGGED} events. 448 * 449 * @return true if the {@code DRAG_DETECTED} event will follow 450 */ 451 public boolean isDragDetect() { 452 return flags.dragDetect; 453 } 454 455 /** 456 * Augments drag detection behavior. The value says whether this event 457 * will be followed by {@code DRAG_DETECTED} event. It has effect only 458 * with {@code MOUSE_PRESSED} and {@code MOUSE_DRAGGED} events. 459 * 460 * @param dragDetect Whether {@code DRAG_DETECTED} event will follow 461 */ 462 public void setDragDetect(boolean dragDetect) { 463 flags.dragDetect = dragDetect; 464 } 465 466 /** 467 * Horizontal x position of the event relative to the 468 * origin of the MouseEvent's node. 469 */ 470 private transient double x; 471 472 /** 473 * Horizontal position of the event relative to the 474 * origin of the MouseEvent's source. 475 * 476 * @return horizontal position of the event relative to the 477 * origin of the MouseEvent's source. 478 */ 479 public final double getX() { 480 return x; 481 } 482 483 /** 484 * Vertical y position of the event relative to the 485 * origin of the MouseEvent's node. 486 */ 487 private transient double y; 488 489 /** 490 * Vertical position of the event relative to the 491 * origin of the MouseEvent's source. 492 * 493 * @return vertical position of the event relative to the 494 * origin of the MouseEvent's source. 495 */ 496 public final double getY() { 497 return y; 498 } 499 500 /** 501 * Depth z position of the event relative to the 502 * origin of the MouseEvent's node. 503 */ 504 private transient double z; 505 506 /** 507 * Depth position of the event relative to the 508 * origin of the MouseEvent's source. 509 * 510 * @return depth position of the event relative to the 511 * origin of the MouseEvent's source. 512 * @since JavaFX 8.0 513 */ 514 public final double getZ() { 515 return z; 516 } 517 518 /** 519 * Absolute horizontal x position of the event. 520 */ 521 private final double screenX; 522 523 /** 524 * Returns absolute horizontal position of the event. 525 * @return absolute horizontal position of the event 526 */ 527 public final double getScreenX() { 528 return screenX; 529 } 530 531 /** 532 * Absolute vertical y position of the event. 533 */ 534 private final double screenY; 535 536 /** 537 * Returns absolute vertical position of the event. 538 * @return absolute vertical position of the event 539 */ 540 public final double getScreenY() { 541 return screenY; 542 } 543 544 /** 545 * Horizontal x position of the event relative to the 546 * origin of the {@code Scene} that contains the MouseEvent's node. 547 * If the node is not in a {@code Scene}, then the value is relative to 548 * the boundsInParent of the root-most parent of the MouseEvent's node. 549 */ 550 private final double sceneX; 551 552 /** 553 * Returns horizontal position of the event relative to the 554 * origin of the {@code Scene} that contains the MouseEvent's source. 555 * If the node is not in a {@code Scene}, then the value is relative to 556 * the boundsInParent of the root-most parent of the MouseEvent's node. 557 * Note that in 3D scene, this represents the flat coordinates after 558 * applying the projection transformations. 559 * 560 * @return horizontal position of the event relative to the 561 * origin of the {@code Scene} that contains the MouseEvent's source 562 */ 563 public final double getSceneX() { 564 return sceneX; 565 } 566 567 /** 568 * Vertical y position of the event relative to the 569 * origin of the {@code Scene} that contains the MouseEvent's node. 570 * If the node is not in a {@code Scene}, then the value is relative to 571 * the boundsInParent of the root-most parent of the MouseEvent's node. 572 */ 573 private final double sceneY; 574 575 /** 576 * Returns vertical position of the event relative to the 577 * origin of the {@code Scene} that contains the MouseEvent's source. 578 * If the node is not in a {@code Scene}, then the value is relative to 579 * the boundsInParent of the root-most parent of the MouseEvent's node. 580 * Note that in 3D scene, this represents the flat coordinates after 581 * applying the projection transformations. 582 * 583 * @return vertical position of the event relative to the 584 * origin of the {@code Scene} that contains the MouseEvent's source 585 */ 586 public final double getSceneY() { 587 return sceneY; 588 } 589 590 /** 591 * Which, if any, of the mouse buttons is responsible for this event. 592 */ 593 private final MouseButton button; 594 595 /** 596 * Which, if any, of the mouse buttons is responsible for this event. 597 * 598 * @return mouse button whose state change caused this event 599 */ 600 public final MouseButton getButton() { 601 return button; 602 } 603 604 /** 605 * Number of mouse clicks associated with this event. 606 * All MOUSE_MOVED events have the clickCount value equal to 0. The 607 * value is increased with MOUSE_PRESSED event and stays like 608 * that for all subsequent events till MOUSE_RELEASED, including the 609 * afterwards generated MOUSE_CLICKED event. The value is increased 610 * to numbers higher than one if all the events between two subsequent 611 * presses happen on a small region and in a small time (according 612 * to native operating system configuration). 613 */ 614 private final int clickCount; 615 616 /** 617 * Returns number of mouse clicks associated with this event. 618 * All MOUSE_MOVED events have the clickCount value equal to 0. The 619 * value is increased with MOUSE_PRESSED event and stays like 620 * that for all subsequent events till MOUSE_RELEASED, including the 621 * afterwards generated MOUSE_CLICKED event. The value is increased 622 * to numbers higher than one if all the events between two subsequent 623 * presses happen on a small region and in a small time (according 624 * to native operating system configuration). 625 * 626 * @return number of mouse clicks associated with this event 627 */ 628 public final int getClickCount() { 629 return clickCount; 630 } 631 632 /** 633 * Whether the mouse cursor left the hysteresis region since the previous 634 * press. 635 */ 636 private final boolean stillSincePress; 637 638 /** 639 * Indicates whether the mouse cursor stayed in the system-provided 640 * hysteresis area since last pressed event that occurred before this event. 641 * <p> 642 * Click event is generated for a node if mouse was both pressed and 643 * released over the node, regardless of mouse movements between the press 644 * and release. If a node wants to react differently on a simple click and 645 * on a mouse drag, it should use a system-supplied short distance 646 * threshold to decide between click and drag (users often perform 647 * inadvertent tiny movements during a click). It can be easily achieved 648 * by ignoring all drags with this method returning {@code true} and 649 * ignoring all clicks with this method returning {@code false}. 650 * 651 * @return true if there were no significant mouse movements (out of 652 * system hysteresis area) since the last pressed event that occurred 653 * before this event. 654 */ 655 public final boolean isStillSincePress() { 656 return stillSincePress; 657 } 658 659 /** 660 * Whether or not the Shift modifier is down on this event. 661 */ 662 private final boolean shiftDown; 663 664 /** 665 * Whether or not the Shift modifier is down on this event. 666 * @return true if the Shift modifier is down on this event 667 */ 668 public final boolean isShiftDown() { 669 return shiftDown; 670 } 671 672 /** 673 * Whether or not the Control modifier is down on this event. 674 */ 675 private final boolean controlDown; 676 677 /** 678 * Whether or not the Control modifier is down on this event. 679 * @return true if the Control modifier is down on this event 680 */ 681 public final boolean isControlDown() { 682 return controlDown; 683 } 684 685 /** 686 * Whether or not the Alt modifier is down on this event. 687 */ 688 private final boolean altDown; 689 690 /** 691 * Whether or not the Alt modifier is down on this event. 692 * @return true if the Alt modifier is down on this event 693 */ 694 public final boolean isAltDown() { 695 return altDown; 696 } 697 698 /** 699 * Whether or not the Meta modifier is down on this event. 700 */ 701 private final boolean metaDown; 702 703 /** 704 * Whether or not the Meta modifier is down on this event. 705 * @return true if the Meta modifier is down on this event 706 */ 707 public final boolean isMetaDown() { 708 return metaDown; 709 } 710 711 private final boolean synthesized; 712 713 /** 714 * Indicates whether this event is synthesized from using a touch screen 715 * instead of usual mouse event source devices like mouse or track pad. 716 * When a finger is dragged over a touch screen, both scrolling gesture 717 * and mouse dragging are produced. If it causes a conflict in an 718 * application, this flag can be used to tell apart the usual mouse dragging 719 * from the touch screen dragging already handled as scroll events. 720 * @return true if this event is synthesized from using a touch screen 721 * @since JavaFX 2.2 722 */ 723 public boolean isSynthesized() { 724 return synthesized; 725 } 726 727 /** 728 * Returns whether or not the host platform common shortcut modifier is 729 * down on this event. This common shortcut modifier is a modifier key which 730 * is used commonly in shortcuts on the host platform. It is for example 731 * {@code control} on Windows and {@code meta} (command key) on Mac. 732 * 733 * @return {@code true} if the shortcut modifier is down, {@code false} 734 * otherwise 735 */ 736 public final boolean isShortcutDown() { 737 switch (Toolkit.getToolkit().getPlatformShortcutKey()) { 738 case SHIFT: 739 return shiftDown; 740 741 case CONTROL: 742 return controlDown; 743 744 case ALT: 745 return altDown; 746 747 case META: 748 return metaDown; 749 750 default: 751 return false; 752 } 753 } 754 755 /** 756 * Whether or not this mouse event is the popup menu 757 * trigger event for the platform. 758 * <p><b>Note</b>: Popup menus are triggered differently 759 * on different systems. Therefore, {@code popupTrigger} 760 * should be checked in both {@code onMousePressed} 761 * and {@code mouseReleased} for proper cross-platform functionality. 762 */ 763 private final boolean popupTrigger; 764 765 /** 766 * Returns {@code true} if this mouse event is the popup menu 767 * trigger event for the platform. 768 * <p><b>Note</b>: Popup menus are triggered differently 769 * on different systems. Therefore, {@code popupTrigger} 770 * should be checked in both {@code onMousePressed} 771 * and {@code mouseReleased} for proper cross-platform functionality. 772 * 773 * @return {@code true} if this mouse event is the popup menu 774 * trigger event for the platform 775 * @since JavaFX 8.0 776 */ 777 public final boolean isPopupTrigger() { 778 return popupTrigger; 779 } 780 781 /** 782 * {@code true} if primary button (button 1, usually the left) is currently 783 * pressed. Note that this is different from the {@link #getButton() button} 784 * variable in that the {@code button} variable indicates which button press was 785 * responsible for this event while this variable indicates whether the 786 * primary button is depressed. 787 */ 788 private final boolean primaryButtonDown; 789 790 /** 791 * Returns {@code true} if primary button (button 1, usually the left) 792 * is currently pressed. Note that this is different from the 793 * {@code getButton()} method that indicates which button press was 794 * responsible for this event while this method indicates whether the 795 * primary button is depressed. 796 * 797 * @return {@code true} if primary button (button 1, usually the left) 798 * is currently pressed 799 */ 800 public final boolean isPrimaryButtonDown() { 801 return primaryButtonDown; 802 } 803 804 /** 805 * {@code true} if secondary button (button 3, usually the right) is currently 806 * pressed. Note that this is different from the {@link #getButton() button} 807 * variable in that the {@code button} variable indicates which button press was 808 * responsible for this event while this variable indicates whether the 809 * primary button is depressed. 810 */ 811 private final boolean secondaryButtonDown; 812 813 /** 814 * Returns {@code true} if secondary button (button 1, usually the right) 815 * is currently pressed. Note that this is different from the 816 * {@code getButton()} method that indicates which button press was 817 * responsible for this event while this method indicates whether the 818 * secondary button is depressed. 819 * 820 * @return {@code true} if secondary button (button 3, usually the right) 821 * is currently pressed 822 */ 823 public final boolean isSecondaryButtonDown() { 824 return secondaryButtonDown; 825 } 826 827 /** 828 * {@code true} if middle button (button 2) is currently pressed. 829 * Note that this is different from the {@link #getButton() button} variable in 830 * that the {@code button} variable indicates which button press was 831 * responsible for this event while this variable indicates whether the 832 * middle button is depressed. 833 */ 834 private final boolean middleButtonDown; 835 836 /** 837 * Returns {@code true} if middle button (button 2) 838 * is currently pressed. Note that this is different from the 839 * {@code getButton()} method that indicates which button press was 840 * responsible for this event while this method indicates whether the 841 * middle button is depressed. 842 * 843 * @return {@code true} if middle button (button 2) is currently pressed 844 */ 845 public final boolean isMiddleButtonDown() { 846 return middleButtonDown; 847 } 848 849 /** 850 * Returns a string representation of this {@code MouseEvent} object. 851 * @return a string representation of this {@code MouseEvent} object. 852 */ 853 @Override public String toString() { 854 final StringBuilder sb = new StringBuilder("MouseEvent ["); 855 856 sb.append("source = ").append(getSource()); 857 sb.append(", target = ").append(getTarget()); 858 sb.append(", eventType = ").append(getEventType()); 859 sb.append(", consumed = ").append(isConsumed()); 860 861 sb.append(", x = ").append(getX()).append(", y = ").append(getY()) 862 .append(", z = ").append(getZ()); 863 864 if (getButton() != null) { 865 sb.append(", button = ").append(getButton()); 866 } 867 if (getClickCount() > 1) { 868 sb.append(", clickCount = ").append(getClickCount()); 869 } 870 if (isPrimaryButtonDown()) { 871 sb.append(", primaryButtonDown"); 872 } 873 if (isMiddleButtonDown()) { 874 sb.append(", middleButtonDown"); 875 } 876 if (isSecondaryButtonDown()) { 877 sb.append(", secondaryButtonDown"); 878 } 879 if (isShiftDown()) { 880 sb.append(", shiftDown"); 881 } 882 if (isControlDown()) { 883 sb.append(", controlDown"); 884 } 885 if (isAltDown()) { 886 sb.append(", altDown"); 887 } 888 if (isMetaDown()) { 889 sb.append(", metaDown"); 890 } 891 if (isShortcutDown()) { 892 sb.append(", shortcutDown"); 893 } 894 if (isSynthesized()) { 895 sb.append(", synthesized"); 896 } 897 sb.append(", pickResult = ").append(getPickResult()); 898 899 return sb.append("]").toString(); 900 } 901 902 /** 903 * Information about the pick if the picked {@code Node} is a 904 * {@code Shape3D} node and its pickOnBounds is false. 905 */ 906 private PickResult pickResult; 907 908 /** 909 * Returns information about the pick. 910 * 911 * @return new PickResult object that contains information about the pick 912 * @since JavaFX 8.0 913 */ 914 public final PickResult getPickResult() { 915 return pickResult; 916 } 917 918 /** 919 * These properties need to live in a separate object shared among all the 920 * copied events to make sure that the values are propagated to the 921 * original event. 922 */ 923 private static class Flags implements Cloneable { 924 /** 925 * Whether dragDetected event is going to be sent after this event. 926 * Applies only to MOUSE_PRESSED and MOUSE_MOVED event types. 927 */ 928 boolean dragDetect = true; 929 930 @Override 931 public Flags clone() { 932 try { 933 return (Flags) super.clone(); 934 } catch (CloneNotSupportedException e) { 935 /* won't happen */ 936 return null; 937 } 938 } 939 } 940 941 private void readObject(java.io.ObjectInputStream in) 942 throws IOException, ClassNotFoundException { 943 in.defaultReadObject(); 944 x = sceneX; 945 y = sceneY; 946 } 947 }