1 /*
   2  * Copyright (c) 2010, 2014, 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.EventTarget;
  31 import javafx.event.EventType;
  32 
  33 import com.sun.javafx.robot.impl.FXRobotHelper;
  34 import com.sun.javafx.robot.impl.FXRobotHelper.FXRobotInputAccessor;
  35 import com.sun.javafx.scene.input.KeyCodeMap;
  36 import javafx.event.Event;
  37 import javafx.scene.input.ScrollEvent.HorizontalTextScrollUnits;
  38 import javafx.scene.input.ScrollEvent.VerticalTextScrollUnits;
  39 
  40 /**
  41  * An event which indicates that a keystroke occurred in a {@link javafx.scene.Node}.
  42  * <p>
  43  * This event is generated when a key is pressed, released, or typed.
  44  * Depending on the type of the event it is passed
  45  * to {@link javafx.scene.Node#onKeyPressedProperty onKeyPressed}, {@link javafx.scene.Node#onKeyTypedProperty onKeyTyped}
  46  * or {@link javafx.scene.Node#onKeyReleasedProperty onKeyReleased} function.
  47  *
  48  * <p>
  49  * <em>"Key typed" events</em> are higher-level and generally do not depend on
  50  * the platform or keyboard layout.  They are generated when a Unicode character
  51  * is entered, and are the preferred way to find out about character input.
  52  * In the simplest case, a key typed event is produced by a single key press
  53  * (e.g., 'a').  Often, however, characters are produced by series of key
  54  * presses (e.g., SHIFT + 'a'), and the mapping from key pressed events to
  55  * key typed events may be many-to-one or many-to-many.  Key releases are not
  56  * usually necessary to generate a key typed event, but there are some cases
  57  * where the key typed event is not generated until a key is released (e.g.,
  58  * entering ASCII sequences via the Alt-Numpad method in Windows).
  59  * No key typed events are generated for keys that don't generate Unicode
  60  * characters (e.g., action keys, modifier keys, etc.).
  61  *
  62  * <p>
  63  * The {@code character} variable always contains a valid Unicode character(s)
  64  * or CHAR_UNDEFINED. Character input is reported by key typed events;
  65  * key pressed and key released events are not necessarily associated
  66  * with character input. Therefore, the {@code character} variable
  67  * is guaranteed to be meaningful only for key typed events.
  68  *
  69  * <p>
  70  * For key pressed and key released events, the {@code code} variable contains
  71  * the event's key code.  For key typed events, the {@code code} variable
  72  * always contains {@code KeyCode.UNDEFINED}.
  73  *
  74  * <p>
  75  * <em>"Key pressed" and "key released" events</em> are lower-level and depend
  76  * on the platform and keyboard layout. They are generated whenever a key is
  77  * pressed or released, and are the only way to find out about keys that don't
  78  * generate character input (e.g., action keys, modifier keys, etc.). The key
  79  * being pressed or released is indicated by the code variable, which contains
  80  * a virtual key code.
  81  *
  82  * <p>
  83  * For triggering context menus see the {@link ContextMenuEvent}.
  84  * @since JavaFX 2.0
  85  */
  86 public final class KeyEvent extends InputEvent {
  87 
  88     private static final long serialVersionUID = 20121107L;
  89 
  90     /**
  91      * Common supertype for all key event types.
  92      */
  93     public static final EventType<KeyEvent> ANY =
  94             new EventType<KeyEvent>(InputEvent.ANY, "KEY");
  95 
  96     /**
  97      * This event occurs when a key has been pressed.
  98      */
  99     public static final EventType<KeyEvent> KEY_PRESSED =
 100             new EventType<KeyEvent>(KeyEvent.ANY, "KEY_PRESSED");
 101 
 102     /**
 103      * This event occurs when a key has been released.
 104      */
 105     public static final EventType<KeyEvent> KEY_RELEASED =
 106             new EventType<KeyEvent>(KeyEvent.ANY, "KEY_RELEASED");
 107 
 108     /**
 109      * This event occurs when a character-generating key was typed
 110      * (pressed and released).  The event contains the {@code character}
 111      * field containing the typed string, the {@code code} and {@code text}
 112      * fields are not used.
 113      */
 114     public static final EventType<KeyEvent> KEY_TYPED =
 115             new EventType<KeyEvent>(KeyEvent.ANY, "KEY_TYPED");
 116 
 117     static {
 118         FXRobotInputAccessor a = new FXRobotInputAccessor() {
 119             @Override public int getCodeForKeyCode(KeyCode keyCode) {
 120                 return keyCode.code;
 121             }
 122             @Override public KeyCode getKeyCodeForCode(int code) {
 123                 return KeyCodeMap.valueOf(code);
 124             }
 125             @Override public KeyEvent createKeyEvent(
 126                 EventType<? extends KeyEvent> eventType,
 127                 KeyCode code, String character, String text,
 128                 boolean shiftDown, boolean controlDown,
 129                 boolean altDown, boolean metaDown)
 130             {
 131                 return new KeyEvent((EventType<KeyEvent>)eventType, character, text, code,
 132                         shiftDown, controlDown, altDown, metaDown);
 133             }
 134             @Override public MouseEvent createMouseEvent(
 135                 EventType<? extends MouseEvent> eventType,
 136                 int x, int y, int screenX, int screenY,
 137                 MouseButton button, int clickCount, boolean shiftDown,
 138                 boolean controlDown, boolean altDown, boolean metaDown,
 139                 boolean popupTrigger, boolean primaryButtonDown,
 140                 boolean middleButtonDown, boolean secondaryButtonDown)
 141             {
 142                 return new MouseEvent(eventType, x, y,
 143                                            screenX, screenY,
 144                                            button, clickCount,
 145                                            shiftDown,
 146                                            controlDown,
 147                                            altDown,
 148                                            metaDown,
 149                                            primaryButtonDown,
 150                                            middleButtonDown,
 151                                            secondaryButtonDown,
 152                                            false,
 153                                            popupTrigger,
 154                                            false,
 155                                            null
 156                                            );
 157             }
 158 
 159             @Override
 160             public ScrollEvent createScrollEvent(
 161                     EventType<? extends ScrollEvent> eventType,
 162                     int scrollX, int scrollY,
 163                     HorizontalTextScrollUnits xTextUnits, int xText,
 164                     VerticalTextScrollUnits yTextUnits, int yText,
 165                     int x, int y, int screenX, int screenY,
 166                     boolean shiftDown, boolean controlDown,
 167                     boolean altDown, boolean metaDown) {
 168                 return new ScrollEvent(ScrollEvent.SCROLL,
 169                         x, y, screenX, screenY,
 170                         shiftDown, controlDown, altDown, metaDown, false, false,
 171                         scrollX, scrollY, 0, 0,
 172                         xTextUnits, xText, yTextUnits, yText,
 173                         0, null);
 174             }
 175         };
 176         FXRobotHelper.setInputAccessor(a);
 177     }
 178 
 179     /**
 180      * Constructs new KeyEvent event with null source and target and KeyCode object directly specified.
 181      * @param source the source of the event. Can be null.
 182      * @param target the target of the event. Can be null.
 183      * @param eventType The type of the event.
 184      * @param character The character or sequence of characters associated with the event
 185      * @param text A String describing the key code
 186      * @param code The integer key code
 187      * @param shiftDown true if shift modifier was pressed.
 188      * @param controlDown true if control modifier was pressed.
 189      * @param altDown true if alt modifier was pressed.
 190      * @param metaDown true if meta modifier was pressed.
 191      * @since JavaFX 8.0
 192      */
 193     public KeyEvent(@NamedArg("source") Object source, @NamedArg("target") EventTarget target, @NamedArg("eventType") EventType<KeyEvent> eventType, @NamedArg("character") String character,
 194             @NamedArg("text") String text, @NamedArg("code") KeyCode code, @NamedArg("shiftDown") boolean shiftDown, @NamedArg("controlDown") boolean controlDown,
 195             @NamedArg("altDown") boolean altDown, @NamedArg("metaDown") boolean metaDown) {
 196         super(source, target, eventType);
 197         boolean isKeyTyped = eventType == KEY_TYPED;
 198 
 199         this.character = isKeyTyped ? character : KeyEvent.CHAR_UNDEFINED;
 200         this.text = isKeyTyped ? "" : text;
 201         this.code = isKeyTyped ? KeyCode.UNDEFINED : code;
 202         this.shiftDown = shiftDown;
 203         this.controlDown = controlDown;
 204         this.altDown = altDown;
 205         this.metaDown = metaDown;
 206     }
 207 
 208     /**
 209      * Constructs new KeyEvent event with null source and target and KeyCode object directly specified.
 210      * @param eventType The type of the event.
 211      * @param character The character or sequence of characters associated with the event
 212      * @param text A String describing the key code
 213      * @param code The integer key code
 214      * @param shiftDown true if shift modifier was pressed.
 215      * @param controlDown true if control modifier was pressed.
 216      * @param altDown true if alt modifier was pressed.
 217      * @param metaDown true if meta modifier was pressed.
 218      * @since JavaFX 8.0
 219      */
 220     public KeyEvent(@NamedArg("eventType") EventType<KeyEvent> eventType, @NamedArg("character") String character,
 221             @NamedArg("text") String text, @NamedArg("code") KeyCode code, @NamedArg("shiftDown") boolean shiftDown, @NamedArg("controlDown") boolean controlDown,
 222             @NamedArg("altDown") boolean altDown, @NamedArg("metaDown") boolean metaDown) {
 223         super(eventType);
 224         boolean isKeyTyped = eventType == KEY_TYPED;
 225 
 226         this.character = isKeyTyped ? character : KeyEvent.CHAR_UNDEFINED;
 227         this.text = isKeyTyped ? "" : text;
 228         this.code = isKeyTyped ? KeyCode.UNDEFINED : code;
 229         this.shiftDown = shiftDown;
 230         this.controlDown = controlDown;
 231         this.altDown = altDown;
 232         this.metaDown = metaDown;
 233     }
 234 
 235     /**
 236      * KEY_PRESSED and KEY_RELEASED events which do not map to a valid Unicode
 237      * character use this for the keyChar value.
 238      */
 239     public static final String CHAR_UNDEFINED = KeyCode.UNDEFINED.ch;
 240 
 241     /**
 242      * The Unicode character or sequence of characters associated with the key
 243      * typed event. Contains multiple elements if the key produced a single
 244      * Unicode character from outside of the Basic Multilingual Plane which
 245      * needs to be encoded by the corresponding surrogate pair in Java or if
 246      * the key produced multiple Unicode characters itself.
 247      * <p/>
 248      * For example, {@code character} will have the value "A" for a key typed
 249      * event generated by pressing SHIFT + 'a'.
 250      * For key pressed and key released events, {@code character} is always
 251      * {@code CHAR_UNDEFINED}.
 252      */
 253     private final String character;
 254 
 255     /**
 256      * The Unicode character or sequence of characters associated with the key
 257      * typed event. Contains multiple elements if the key produced a single
 258      * Unicode character from outside of the Basic Multilingual Plane which
 259      * needs to be encoded by the corresponding surrogate pair in Java or if
 260      * the key produced multiple Unicode characters itself.
 261      * <p/>
 262      * For example, {@code character} will have the value "A" for a key typed
 263      * event generated by pressing SHIFT + 'a'.
 264      * For key pressed and key released events, {@code character} is always
 265      * {@code CHAR_UNDEFINED}.
 266      *
 267      * @return The Unicode character(s) associated with the key typed event
 268      */
 269     public final String getCharacter() {
 270         return character;
 271     }
 272 
 273     /**
 274      * A String describing the key code, such as "HOME", "F1" or "A",
 275      * for key pressed and key released events.
 276      * For key typed events, {@code text} is always the empty string.
 277      */
 278     private final String text;
 279 
 280     /**
 281      * A String describing the key code, such as "HOME", "F1" or "A",
 282      * for key pressed and key released events.
 283      * For key typed events, {@code text} is always the empty string.
 284      *
 285      * @return A String describing the key code
 286      */
 287     public final String getText() {
 288         return text;
 289     }
 290 
 291     /**
 292      * The integer key code associated with the key in this key
 293      * pressed or key released event.
 294      * For key typed events, {@code code} is always {@code KeyCode.UNDEFINED}.
 295      */
 296     private final KeyCode code;
 297 
 298     /**
 299      * The key code associated with the key in this key pressed or key released
 300      * event. For key typed events, {@code code} is always {@code KeyCode.UNDEFINED}.
 301      *
 302      * @return The key code associated with the key in this event,
 303      * {@code KeyCode.UNDEFINED} for key typed event
 304      */
 305     public final KeyCode getCode() {
 306         return code;
 307     }
 308 
 309     /**
 310      * Returns whether or not the Shift modifier is down on this event.
 311      */
 312     private final boolean shiftDown;
 313 
 314     /**
 315      * Returns whether or not the Shift modifier is down on this event.
 316      * @return whether or not the Shift modifier is down on this event.
 317      */
 318     public final boolean isShiftDown() {
 319         return shiftDown;
 320     }
 321 
 322     /**
 323      * Returns whether or not the Control modifier is down on this event.
 324      */
 325     private final boolean controlDown;
 326 
 327     /**
 328      * Returns whether or not the Control modifier is down on this event.
 329      * @return whether or not the Control modifier is down on this event.
 330      */
 331     public final boolean isControlDown() {
 332         return controlDown;
 333     }
 334 
 335     /**
 336      * Returns whether or not the Alt modifier is down on this event.
 337      */
 338     private final boolean altDown;
 339 
 340     /**
 341      * Returns whether or not the Alt modifier is down on this event.
 342      * @return whether or not the Alt modifier is down on this event.
 343      */
 344     public final boolean isAltDown() {
 345         return altDown;
 346     }
 347 
 348     /**
 349      * Returns whether or not the Meta modifier is down on this event.
 350      */
 351     private final boolean metaDown;
 352 
 353     /**
 354      * Returns whether or not the Meta modifier is down on this event.
 355      * @return whether or not the Meta modifier is down on this event.
 356      */
 357     public final boolean isMetaDown() {
 358         return metaDown;
 359     }
 360 
 361 
 362     /**
 363      * Returns whether or not the host platform common shortcut modifier is
 364      * down on this event. This common shortcut modifier is a modifier key which
 365      * is used commonly in shortcuts on the host platform. It is for example
 366      * {@code control} on Windows and {@code meta} (command key) on Mac.
 367      *
 368      * @return {@code true} if the shortcut modifier is down, {@code false}
 369      *      otherwise
 370      */
 371     public final boolean isShortcutDown() {
 372         switch (Toolkit.getToolkit().getPlatformShortcutKey()) {
 373             case SHIFT:
 374                 return shiftDown;
 375 
 376             case CONTROL:
 377                 return controlDown;
 378 
 379             case ALT:
 380                 return altDown;
 381 
 382             case META:
 383                 return metaDown;
 384 
 385             default:
 386                 return false;
 387         }
 388     }
 389 
 390     /**
 391      * Returns a string representation of this {@code KeyEvent} object.
 392      * @return a string representation of this {@code KeyEvent} object.
 393      */
 394     @Override public String toString() {
 395         final StringBuilder sb = new StringBuilder("KeyEvent [");
 396 
 397         sb.append("source = ").append(getSource());
 398         sb.append(", target = ").append(getTarget());
 399         sb.append(", eventType = ").append(getEventType());
 400         sb.append(", consumed = ").append(isConsumed());
 401 
 402         sb.append(", character = ").append(getCharacter());
 403         sb.append(", text = ").append(getText());
 404         sb.append(", code = ").append(getCode());
 405 
 406         if (isShiftDown()) {
 407             sb.append(", shiftDown");
 408         }
 409         if (isControlDown()) {
 410             sb.append(", controlDown");
 411         }
 412         if (isAltDown()) {
 413             sb.append(", altDown");
 414         }
 415         if (isMetaDown()) {
 416             sb.append(", metaDown");
 417         }
 418         if (isShortcutDown()) {
 419             sb.append(", shortcutDown");
 420         }
 421 
 422         return sb.append("]").toString();
 423     }
 424 
 425     @Override
 426     public KeyEvent copyFor(Object newSource, EventTarget newTarget) {
 427         return (KeyEvent) super.copyFor(newSource, newTarget);
 428     }
 429 
 430     /**
 431      * Creates a copy of the given event with the given fields substituted.
 432      * @param source the new source of the copied event
 433      * @param target the new target of the copied event
 434      * @param type the new event type.
 435      * @return the event copy with the fields substituted
 436      * @since JavaFX 8.0
 437      */
 438     public KeyEvent copyFor(Object source, EventTarget target, EventType<KeyEvent> type) {
 439         KeyEvent e = copyFor(source, target);
 440         e.eventType = type;
 441         return e;
 442     }
 443 
 444     @Override
 445     public EventType<KeyEvent> getEventType() {
 446         return (EventType<KeyEvent>) super.getEventType();
 447     }
 448 
 449 
 450 
 451 }