java.awt.event.KeyEvent.java Source code

Java tutorial

Introduction

Here is the source code for java.awt.event.KeyEvent.java

Source

/*
 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package java.awt.event;

import java.awt.Component;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.io.IOException;
import java.io.ObjectInputStream;
import sun.awt.AWTAccessor;

/**
 * An event which indicates that a keystroke occurred in a component.
 * <p>
 * This low-level event is generated by a component object (such as a text
 * field) when a key is pressed, released, or typed.
 * The event is passed to every {@code KeyListener}
 * or {@code KeyAdapter} object which registered to receive such
 * events using the component's {@code addKeyListener} method.
 * ({@code KeyAdapter} objects implement the
 * {@code KeyListener} interface.)  Each such listener object
 * gets this {@code KeyEvent} when the event occurs.
 * <p>
 * <em>"Key typed" events</em> are higher-level and generally do not depend on
 * the platform or keyboard layout.  They are generated when a Unicode character
 * is entered, and are the preferred way to find out about character input.
 * In the simplest case, a key typed event is produced by a single key press
 * (e.g., 'a').  Often, however, characters are produced by series of key
 * presses (e.g., 'shift' + 'a'), and the mapping from key pressed events to
 * key typed events may be many-to-one or many-to-many.  Key releases are not
 * usually necessary to generate a key typed event, but there are some cases
 * where the key typed event is not generated until a key is released (e.g.,
 * entering ASCII sequences via the Alt-Numpad method in Windows).
 * No key typed events are generated for keys that don't generate Unicode
 * characters (e.g., action keys, modifier keys, etc.).
 * <p>
 * The getKeyChar method always returns a valid Unicode character or
 * CHAR_UNDEFINED.  Character input is reported by KEY_TYPED events:
 * KEY_PRESSED and KEY_RELEASED events are not necessarily associated
 * with character input.  Therefore, the result of the getKeyChar method
 * is guaranteed to be meaningful only for KEY_TYPED events.
 * <p>
 * For key pressed and key released events, the getKeyCode method returns
 * the event's keyCode.  For key typed events, the getKeyCode method
 * always returns {@code VK_UNDEFINED}. The {@code getExtendedKeyCode} method
 * may also be used with many international keyboard layouts.
 *
 * <p>
 * <em>"Key pressed" and "key released" events</em> are lower-level and depend
 * on the platform and keyboard layout. They are generated whenever a key is
 * pressed or released, and are the only way to find out about keys that don't
 * generate character input (e.g., action keys, modifier keys, etc.). The key
 * being pressed or released is indicated by the {@code getKeyCode} and {@code getExtendedKeyCode}
 * methods, which return a virtual key code.
 *
 * <p>
 * <em>Virtual key codes</em> are used to report which keyboard key has
 * been pressed, rather than a character generated by the combination
 * of one or more keystrokes (such as "A", which comes from shift and "a").
 *
 * <p>
 * For example, pressing the Shift key will cause a KEY_PRESSED event
 * with a VK_SHIFT keyCode, while pressing the 'a' key will result in
 * a VK_A keyCode.  After the 'a' key is released, a KEY_RELEASED event
 * will be fired with VK_A. Separately, a KEY_TYPED event with a keyChar
 * value of 'A' is generated.
 *
 * <p>
 * Pressing and releasing a key on the keyboard results in the generating
 * the following key events (in order):
 * <PRE>
 *    {@code KEY_PRESSED}
 *    {@code KEY_TYPED} (is only generated if a valid Unicode character could be generated.)
 *    {@code KEY_RELEASED}
 * </PRE>
 *
 * But in some cases (e.g. auto-repeat or input method is activated) the order
 * could be different (and platform dependent).
 *
 * <p>
 * Notes:
 * <ul>
 * <li>Key combinations which do not result in Unicode characters, such as action
 * keys like F1 and the HELP key, do not generate KEY_TYPED events.
 * <li>Not all keyboards or systems are capable of generating all
 * virtual key codes.  No attempt is made in Java to generate these keys
 * artificially.
 * <li>Virtual key codes do not identify a physical key: they depend on the
 * platform and keyboard layout. For example, the key that generates VK_Q
 * when using a U.S. keyboard layout will generate VK_A when using a French
 * keyboard layout.
 * <li>The key that generates {@code VK_Q} when using a U.S. keyboard layout also
 * generates a unique code for Russian or Hebrew layout. There is no a
 * {@code VK_} constant for these and many other codes in various layouts. These codes
 * may be obtained by using {@code getExtendedKeyCode} and are used whenever
 * a {@code VK_} constant is used.
 * <li>Not all characters have a keycode associated with them.  For example,
 * there is no keycode for the question mark because there is no keyboard
 * for which it appears on the primary layer.
 * <li>In order to support the platform-independent handling of action keys,
 * the Java platform uses a few additional virtual key constants for functions
 * that would otherwise have to be recognized by interpreting virtual key codes
 * and modifiers. For example, for Japanese Windows keyboards, VK_ALL_CANDIDATES
 * is returned instead of VK_CONVERT with the ALT modifier.
 * <li>As specified in <a href="../doc-files/FocusSpec.html">Focus Specification</a>
 * key events are dispatched to the focus owner by default.
 * </ul>
 *
 * <p>
 * WARNING: Aside from those keys that are defined by the Java language
 * (VK_ENTER, VK_BACK_SPACE, and VK_TAB), do not rely on the values of the VK_
 * constants.  The platform steward reserves the right to change these values as needed
 * to accommodate a wider range of keyboards in the future.
 * <p>
 * An unspecified behavior will be caused if the {@code id} parameter
 * of any particular {@code KeyEvent} instance is not
 * in the range from {@code KEY_FIRST} to {@code KEY_LAST}.
 *
 * @author Carl Quinn
 * @author Amy Fowler
 * @author Norbert Lindenberg
 *
 * @see KeyAdapter
 * @see KeyListener
 * @see <a href="https://docs.oracle.com/javase/tutorial/uiswing/events/keylistener.html">Tutorial: Writing a Key Listener</a>
 *
 * @since 1.1
 */
public class KeyEvent extends InputEvent {

    /**
     * Stores the state of native event dispatching system
     * - true, if when the event was created event proxying
     *         mechanism was active
     * - false, if it was inactive
     * Used in Component.dispatchEventImpl to correctly dispatch
     * events when proxy is active
     */
    private boolean isProxyActive = false;

    /**
     * The first number in the range of ids used for key events.
     */
    public static final int KEY_FIRST = 400;

    /**
     * The last number in the range of ids used for key events.
     */
    public static final int KEY_LAST = 402;

    /**
     * The "key typed" event.  This event is generated when a character is
     * entered.  In the simplest case, it is produced by a single key press.
     * Often, however, characters are produced by series of key presses, and
     * the mapping from key pressed events to key typed events may be
     * many-to-one or many-to-many.
     */
    public static final int KEY_TYPED = KEY_FIRST;

    /**
     * The "key pressed" event. This event is generated when a key
     * is pushed down.
     */
    public static final int KEY_PRESSED = 1 + KEY_FIRST; //Event.KEY_PRESS

    /**
     * The "key released" event. This event is generated when a key
     * is let up.
     */
    public static final int KEY_RELEASED = 2 + KEY_FIRST; //Event.KEY_RELEASE

    /* Virtual key codes. */

    /** Constant for the ENTER virtual key. */
    public static final int VK_ENTER = '\n';

    /** Constant for the BACK_SPACE virtual key. */
    public static final int VK_BACK_SPACE = '\b';

    /** Constant for the TAB virtual key. */
    public static final int VK_TAB = '\t';

    /** Constant for the CANCEL virtual key. */
    public static final int VK_CANCEL = 0x03;

    /** Constant for the CLEAR virtual key. */
    public static final int VK_CLEAR = 0x0C;

    /** Constant for the SHIFT virtual key. */
    public static final int VK_SHIFT = 0x10;

    /** Constant for the CONTROL virtual key. */
    public static final int VK_CONTROL = 0x11;

    /** Constant for the ALT virtual key. */
    public static final int VK_ALT = 0x12;

    /** Constant for the PAUSE virtual key. */
    public static final int VK_PAUSE = 0x13;

    /** Constant for the CAPS_LOCK virtual key. */
    public static final int VK_CAPS_LOCK = 0x14;

    /** Constant for the ESCAPE virtual key. */
    public static final int VK_ESCAPE = 0x1B;

    /** Constant for the SPACE virtual key. */
    public static final int VK_SPACE = 0x20;

    /** Constant for the PAGE_UP virtual key. */
    public static final int VK_PAGE_UP = 0x21;

    /** Constant for the PAGE_DOWN virtual key. */
    public static final int VK_PAGE_DOWN = 0x22;

    /** Constant for the END virtual key. */
    public static final int VK_END = 0x23;

    /** Constant for the HOME virtual key. */
    public static final int VK_HOME = 0x24;

    /**
     * Constant for the non-numpad <b>left</b> arrow key.
     * @see #VK_KP_LEFT
     */
    public static final int VK_LEFT = 0x25;

    /**
     * Constant for the non-numpad <b>up</b> arrow key.
     * @see #VK_KP_UP
     */
    public static final int VK_UP = 0x26;

    /**
     * Constant for the non-numpad <b>right</b> arrow key.
     * @see #VK_KP_RIGHT
     */
    public static final int VK_RIGHT = 0x27;

    /**
     * Constant for the non-numpad <b>down</b> arrow key.
     * @see #VK_KP_DOWN
     */
    public static final int VK_DOWN = 0x28;

    /**
     * Constant for the comma key, ","
     */
    public static final int VK_COMMA = 0x2C;

    /**
     * Constant for the minus key, "-"
     * @since 1.2
     */
    public static final int VK_MINUS = 0x2D;

    /**
     * Constant for the period key, "."
     */
    public static final int VK_PERIOD = 0x2E;

    /**
     * Constant for the forward slash key, "/"
     */
    public static final int VK_SLASH = 0x2F;

    /** VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */

    /** Constant for the "0" key. */
    public static final int VK_0 = 0x30;

    /** Constant for the "1" key. */
    public static final int VK_1 = 0x31;

    /** Constant for the "2" key. */
    public static final int VK_2 = 0x32;

    /** Constant for the "3" key. */
    public static final int VK_3 = 0x33;

    /** Constant for the "4" key. */
    public static final int VK_4 = 0x34;

    /** Constant for the "5" key. */
    public static final int VK_5 = 0x35;

    /** Constant for the "6" key. */
    public static final int VK_6 = 0x36;

    /** Constant for the "7" key. */
    public static final int VK_7 = 0x37;

    /** Constant for the "8" key. */
    public static final int VK_8 = 0x38;

    /** Constant for the "9" key. */
    public static final int VK_9 = 0x39;

    /**
     * Constant for the semicolon key, ";"
     */
    public static final int VK_SEMICOLON = 0x3B;

    /**
     * Constant for the equals key, "="
     */
    public static final int VK_EQUALS = 0x3D;

    /** VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */

    /** Constant for the "A" key. */
    public static final int VK_A = 0x41;

    /** Constant for the "B" key. */
    public static final int VK_B = 0x42;

    /** Constant for the "C" key. */
    public static final int VK_C = 0x43;

    /** Constant for the "D" key. */
    public static final int VK_D = 0x44;

    /** Constant for the "E" key. */
    public static final int VK_E = 0x45;

    /** Constant for the "F" key. */
    public static final int VK_F = 0x46;

    /** Constant for the "G" key. */
    public static final int VK_G = 0x47;

    /** Constant for the "H" key. */
    public static final int VK_H = 0x48;

    /** Constant for the "I" key. */
    public static final int VK_I = 0x49;

    /** Constant for the "J" key. */
    public static final int VK_J = 0x4A;

    /** Constant for the "K" key. */
    public static final int VK_K = 0x4B;

    /** Constant for the "L" key. */
    public static final int VK_L = 0x4C;

    /** Constant for the "M" key. */
    public static final int VK_M = 0x4D;

    /** Constant for the "N" key. */
    public static final int VK_N = 0x4E;

    /** Constant for the "O" key. */
    public static final int VK_O = 0x4F;

    /** Constant for the "P" key. */
    public static final int VK_P = 0x50;

    /** Constant for the "Q" key. */
    public static final int VK_Q = 0x51;

    /** Constant for the "R" key. */
    public static final int VK_R = 0x52;

    /** Constant for the "S" key. */
    public static final int VK_S = 0x53;

    /** Constant for the "T" key. */
    public static final int VK_T = 0x54;

    /** Constant for the "U" key. */
    public static final int VK_U = 0x55;

    /** Constant for the "V" key. */
    public static final int VK_V = 0x56;

    /** Constant for the "W" key. */
    public static final int VK_W = 0x57;

    /** Constant for the "X" key. */
    public static final int VK_X = 0x58;

    /** Constant for the "Y" key. */
    public static final int VK_Y = 0x59;

    /** Constant for the "Z" key. */
    public static final int VK_Z = 0x5A;

    /**
     * Constant for the open bracket key, "["
     */
    public static final int VK_OPEN_BRACKET = 0x5B;

    /**
     * Constant for the back slash key, "\"
     */
    public static final int VK_BACK_SLASH = 0x5C;

    /**
     * Constant for the close bracket key, "]"
     */
    public static final int VK_CLOSE_BRACKET = 0x5D;

    /** Constant for the number pad "0" key. */
    public static final int VK_NUMPAD0 = 0x60;

    /** Constant for the number pad "1" key. */
    public static final int VK_NUMPAD1 = 0x61;

    /** Constant for the number pad "2" key. */
    public static final int VK_NUMPAD2 = 0x62;

    /** Constant for the number pad "3" key. */
    public static final int VK_NUMPAD3 = 0x63;

    /** Constant for the number pad "4" key. */
    public static final int VK_NUMPAD4 = 0x64;

    /** Constant for the number pad "5" key. */
    public static final int VK_NUMPAD5 = 0x65;

    /** Constant for the number pad "6" key. */
    public static final int VK_NUMPAD6 = 0x66;

    /** Constant for the number pad "7" key. */
    public static final int VK_NUMPAD7 = 0x67;

    /** Constant for the number pad "8" key. */
    public static final int VK_NUMPAD8 = 0x68;

    /** Constant for the number pad "9" key. */
    public static final int VK_NUMPAD9 = 0x69;

    /** Constant for the number pad multiply key. */
    public static final int VK_MULTIPLY = 0x6A;

    /** Constant for the number pad add key. */
    public static final int VK_ADD = 0x6B;

    /**
     * This constant is obsolete, and is included only for backwards
     * compatibility.
     * @see #VK_SEPARATOR
     */
    public static final int VK_SEPARATER = 0x6C;

    /**
     * Constant for the Numpad Separator key.
     * @since 1.4
     */
    public static final int VK_SEPARATOR = VK_SEPARATER;

    /** Constant for the number pad subtract key. */
    public static final int VK_SUBTRACT = 0x6D;

    /** Constant for the number pad decimal point key. */
    public static final int VK_DECIMAL = 0x6E;

    /** Constant for the number pad divide key. */
    public static final int VK_DIVIDE = 0x6F;

    /** Constant for the delete key. */
    public static final int VK_DELETE = 0x7F; /* ASCII DEL */

    /** Constant for the NUM_LOCK key. */
    public static final int VK_NUM_LOCK = 0x90;

    /** Constant for the SCROLL_LOCK key. */
    public static final int VK_SCROLL_LOCK = 0x91;

    /** Constant for the F1 function key. */
    public static final int VK_F1 = 0x70;

    /** Constant for the F2 function key. */
    public static final int VK_F2 = 0x71;

    /** Constant for the F3 function key. */
    public static final int VK_F3 = 0x72;

    /** Constant for the F4 function key. */
    public static final int VK_F4 = 0x73;

    /** Constant for the F5 function key. */
    public static final int VK_F5 = 0x74;

    /** Constant for the F6 function key. */
    public static final int VK_F6 = 0x75;

    /** Constant for the F7 function key. */
    public static final int VK_F7 = 0x76;

    /** Constant for the F8 function key. */
    public static final int VK_F8 = 0x77;

    /** Constant for the F9 function key. */
    public static final int VK_F9 = 0x78;

    /** Constant for the F10 function key. */
    public static final int VK_F10 = 0x79;

    /** Constant for the F11 function key. */
    public static final int VK_F11 = 0x7A;

    /** Constant for the F12 function key. */
    public static final int VK_F12 = 0x7B;

    /**
     * Constant for the F13 function key.
     * @since 1.2
     */
    /* F13 - F24 are used on IBM 3270 keyboard; use random range for constants. */
    public static final int VK_F13 = 0xF000;

    /**
     * Constant for the F14 function key.
     * @since 1.2
     */
    public static final int VK_F14 = 0xF001;

    /**
     * Constant for the F15 function key.
     * @since 1.2
     */
    public static final int VK_F15 = 0xF002;

    /**
     * Constant for the F16 function key.
     * @since 1.2
     */
    public static final int VK_F16 = 0xF003;

    /**
     * Constant for the F17 function key.
     * @since 1.2
     */
    public static final int VK_F17 = 0xF004;

    /**
     * Constant for the F18 function key.
     * @since 1.2
     */
    public static final int VK_F18 = 0xF005;

    /**
     * Constant for the F19 function key.
     * @since 1.2
     */
    public static final int VK_F19 = 0xF006;

    /**
     * Constant for the F20 function key.
     * @since 1.2
     */
    public static final int VK_F20 = 0xF007;

    /**
     * Constant for the F21 function key.
     * @since 1.2
     */
    public static final int VK_F21 = 0xF008;

    /**
     * Constant for the F22 function key.
     * @since 1.2
     */
    public static final int VK_F22 = 0xF009;

    /**
     * Constant for the F23 function key.
     * @since 1.2
     */
    public static final int VK_F23 = 0xF00A;

    /**
     * Constant for the F24 function key.
     * @since 1.2
     */
    public static final int VK_F24 = 0xF00B;

    /**  Constant for the PRINTSCREEN key. */
    public static final int VK_PRINTSCREEN = 0x9A;

    /**  Constant for the INSERT key. */
    public static final int VK_INSERT = 0x9B;

    /**  Constant for the HELP key. */
    public static final int VK_HELP = 0x9C;

    /**  Constant for the META key. */
    public static final int VK_META = 0x9D;

    /**  Constant for the BACK_QUOTE  key. */
    public static final int VK_BACK_QUOTE = 0xC0;

    /**  Constant for the QUOTE key. */
    public static final int VK_QUOTE = 0xDE;

    /**
     * Constant for the numeric keypad <b>up</b> arrow key.
     * @see #VK_UP
     * @since 1.2
     */
    public static final int VK_KP_UP = 0xE0;

    /**
     * Constant for the numeric keypad <b>down</b> arrow key.
     * @see #VK_DOWN
     * @since 1.2
     */
    public static final int VK_KP_DOWN = 0xE1;

    /**
     * Constant for the numeric keypad <b>left</b> arrow key.
     * @see #VK_LEFT
     * @since 1.2
     */
    public static final int VK_KP_LEFT = 0xE2;

    /**
     * Constant for the numeric keypad <b>right</b> arrow key.
     * @see #VK_RIGHT
     * @since 1.2
     */
    public static final int VK_KP_RIGHT = 0xE3;

    /* For European keyboards */
    /** @since 1.2 */
    public static final int VK_DEAD_GRAVE = 0x80;
    /** @since 1.2 */
    public static final int VK_DEAD_ACUTE = 0x81;
    /** @since 1.2 */
    public static final int VK_DEAD_CIRCUMFLEX = 0x82;
    /** @since 1.2 */
    public static final int VK_DEAD_TILDE = 0x83;
    /** @since 1.2 */
    public static final int VK_DEAD_MACRON = 0x84;
    /** @since 1.2 */
    public static final int VK_DEAD_BREVE = 0x85;
    /** @since 1.2 */
    public static final int VK_DEAD_ABOVEDOT = 0x86;
    /** @since 1.2 */
    public static final int VK_DEAD_DIAERESIS = 0x87;
    /** @since 1.2 */
    public static final int VK_DEAD_ABOVERING = 0x88;
    /** @since 1.2 */
    public static final int VK_DEAD_DOUBLEACUTE = 0x89;
    /** @since 1.2 */
    public static final int VK_DEAD_CARON = 0x8a;
    /** @since 1.2 */
    public static final int VK_DEAD_CEDILLA = 0x8b;
    /** @since 1.2 */
    public static final int VK_DEAD_OGONEK = 0x8c;
    /** @since 1.2 */
    public static final int VK_DEAD_IOTA = 0x8d;
    /** @since 1.2 */
    public static final int VK_DEAD_VOICED_SOUND = 0x8e;
    /** @since 1.2 */
    public static final int VK_DEAD_SEMIVOICED_SOUND = 0x8f;

    /** @since 1.2 */
    public static final int VK_AMPERSAND = 0x96;
    /** @since 1.2 */
    public static final int VK_ASTERISK = 0x97;
    /** @since 1.2 */
    public static final int VK_QUOTEDBL = 0x98;
    /** @since 1.2 */
    public static final int VK_LESS = 0x99;

    /** @since 1.2 */
    public static final int VK_GREATER = 0xa0;
    /** @since 1.2 */
    public static final int VK_BRACELEFT = 0xa1;
    /** @since 1.2 */
    public static final int VK_BRACERIGHT = 0xa2;

    /**
     * Constant for the "@" key.
     * @since 1.2
     */
    public static final int VK_AT = 0x0200;

    /**
     * Constant for the ":" key.
     * @since 1.2
     */
    public static final int VK_COLON = 0x0201;

    /**
     * Constant for the "^" key.
     * @since 1.2
     */
    public static final int VK_CIRCUMFLEX = 0x0202;

    /**
     * Constant for the "$" key.
     * @since 1.2
     */
    public static final int VK_DOLLAR = 0x0203;

    /**
     * Constant for the Euro currency sign key.
     * @since 1.2
     */
    public static final int VK_EURO_SIGN = 0x0204;

    /**
     * Constant for the "!" key.
     * @since 1.2
     */
    public static final int VK_EXCLAMATION_MARK = 0x0205;

    /**
     * Constant for the inverted exclamation mark key.
     * @since 1.2
     */
    public static final int VK_INVERTED_EXCLAMATION_MARK = 0x0206;

    /**
     * Constant for the "(" key.
     * @since 1.2
     */
    public static final int VK_LEFT_PARENTHESIS = 0x0207;

    /**
     * Constant for the "#" key.
     * @since 1.2
     */
    public static final int VK_NUMBER_SIGN = 0x0208;

    /**
     * Constant for the "+" key.
     * @since 1.2
     */
    public static final int VK_PLUS = 0x0209;

    /**
     * Constant for the ")" key.
     * @since 1.2
     */
    public static final int VK_RIGHT_PARENTHESIS = 0x020A;

    /**
     * Constant for the "_" key.
     * @since 1.2
     */
    public static final int VK_UNDERSCORE = 0x020B;

    /**
     * Constant for the Microsoft Windows "Windows" key.
     * It is used for both the left and right version of the key.
     * @see #getKeyLocation()
     * @since 1.5
     */
    public static final int VK_WINDOWS = 0x020C;

    /**
     * Constant for the Microsoft Windows Context Menu key.
     * @since 1.5
     */
    public static final int VK_CONTEXT_MENU = 0x020D;

    /* for input method support on Asian Keyboards */

    /* not clear what this means - listed in Microsoft Windows API */
    /** Constant for the FINAL key. */
    public static final int VK_FINAL = 0x0018;

    /** Constant for the Convert function key. */
    /* Japanese PC 106 keyboard, Japanese Solaris keyboard: henkan */
    public static final int VK_CONVERT = 0x001C;

    /** Constant for the Don't Convert function key. */
    /* Japanese PC 106 keyboard: muhenkan */
    public static final int VK_NONCONVERT = 0x001D;

    /** Constant for the Accept or Commit function key. */
    /* Japanese Solaris keyboard: kakutei */
    public static final int VK_ACCEPT = 0x001E;

    /* not clear what this means - listed in Microsoft Windows API */
    /** Constant for the MODECHANGE key. */
    public static final int VK_MODECHANGE = 0x001F;

    /* replaced by VK_KANA_LOCK for Microsoft Windows and Solaris;
       might still be used on other platforms */
    /**
     * Constant for the KANA lock key.
     * @see #VK_KANA_LOCK
     **/
    public static final int VK_KANA = 0x0015;

    /* replaced by VK_INPUT_METHOD_ON_OFF for Microsoft Windows and Solaris;
       might still be used for other platforms */
    /**
     * Constant for KANJI.
     * @see #VK_INPUT_METHOD_ON_OFF
     */
    public static final int VK_KANJI = 0x0019;

    /**
     * Constant for the Alphanumeric function key.
     * @since 1.2
     */
    /* Japanese PC 106 keyboard: eisuu */
    public static final int VK_ALPHANUMERIC = 0x00F0;

    /**
     * Constant for the Katakana function key.
     * @since 1.2
     */
    /* Japanese PC 106 keyboard: katakana */
    public static final int VK_KATAKANA = 0x00F1;

    /**
     * Constant for the Hiragana function key.
     * @since 1.2
     */
    /* Japanese PC 106 keyboard: hiragana */
    public static final int VK_HIRAGANA = 0x00F2;

    /**
     * Constant for the Full-Width Characters function key.
     * @since 1.2
     */
    /* Japanese PC 106 keyboard: zenkaku */
    public static final int VK_FULL_WIDTH = 0x00F3;

    /**
     * Constant for the Half-Width Characters function key.
     * @since 1.2
     */
    /* Japanese PC 106 keyboard: hankaku */
    public static final int VK_HALF_WIDTH = 0x00F4;

    /**
     * Constant for the Roman Characters function key.
     * @since 1.2
     */
    /* Japanese PC 106 keyboard: roumaji */
    public static final int VK_ROMAN_CHARACTERS = 0x00F5;

    /**
     * Constant for the All Candidates function key.
     * @since 1.2
     */
    /* Japanese PC 106 keyboard - VK_CONVERT + ALT: zenkouho */
    public static final int VK_ALL_CANDIDATES = 0x0100;

    /**
     * Constant for the Previous Candidate function key.
     * @since 1.2
     */
    /* Japanese PC 106 keyboard - VK_CONVERT + SHIFT: maekouho */
    public static final int VK_PREVIOUS_CANDIDATE = 0x0101;

    /**
     * Constant for the Code Input function key.
     * @since 1.2
     */
    /* Japanese PC 106 keyboard - VK_ALPHANUMERIC + ALT: kanji bangou */
    public static final int VK_CODE_INPUT = 0x0102;

    /**
     * Constant for the Japanese-Katakana function key.
     * This key switches to a Japanese input method and selects its Katakana input mode.
     * @since 1.2
     */
    /* Japanese Macintosh keyboard - VK_JAPANESE_HIRAGANA + SHIFT */
    public static final int VK_JAPANESE_KATAKANA = 0x0103;

    /**
     * Constant for the Japanese-Hiragana function key.
     * This key switches to a Japanese input method and selects its Hiragana input mode.
     * @since 1.2
     */
    /* Japanese Macintosh keyboard */
    public static final int VK_JAPANESE_HIRAGANA = 0x0104;

    /**
     * Constant for the Japanese-Roman function key.
     * This key switches to a Japanese input method and selects its Roman-Direct input mode.
     * @since 1.2
     */
    /* Japanese Macintosh keyboard */
    public static final int VK_JAPANESE_ROMAN = 0x0105;

    /**
     * Constant for the locking Kana function key.
     * This key locks the keyboard into a Kana layout.
     * @since 1.3
     */
    /* Japanese PC 106 keyboard with special Windows driver - eisuu + Control; Japanese Solaris keyboard: kana */
    public static final int VK_KANA_LOCK = 0x0106;

    /**
     * Constant for the input method on/off key.
     * @since 1.3
     */
    /* Japanese PC 106 keyboard: kanji. Japanese Solaris keyboard: nihongo */
    public static final int VK_INPUT_METHOD_ON_OFF = 0x0107;

    /* for Sun keyboards */
    /** @since 1.2 */
    public static final int VK_CUT = 0xFFD1;
    /** @since 1.2 */
    public static final int VK_COPY = 0xFFCD;
    /** @since 1.2 */
    public static final int VK_PASTE = 0xFFCF;
    /** @since 1.2 */
    public static final int VK_UNDO = 0xFFCB;
    /** @since 1.2 */
    public static final int VK_AGAIN = 0xFFC9;
    /** @since 1.2 */
    public static final int VK_FIND = 0xFFD0;
    /** @since 1.2 */
    public static final int VK_PROPS = 0xFFCA;
    /** @since 1.2 */
    public static final int VK_STOP = 0xFFC8;

    /**
     * Constant for the Compose function key.
     * @since 1.2
     */
    public static final int VK_COMPOSE = 0xFF20;

    /**
     * Constant for the AltGraph function key.
     * @since 1.2
     */
    public static final int VK_ALT_GRAPH = 0xFF7E;

    /**
     * Constant for the Begin key.
     * @since 1.5
     */
    public static final int VK_BEGIN = 0xFF58;

    /**
     * This value is used to indicate that the keyCode is unknown.
     * KEY_TYPED events do not have a keyCode value; this value
     * is used instead.
     */
    public static final int VK_UNDEFINED = 0x0;

    /**
     * KEY_PRESSED and KEY_RELEASED events which do not map to a
     * valid Unicode character use this for the keyChar value.
     */
    public static final char CHAR_UNDEFINED = 0xFFFF;

    /**
     * A constant indicating that the keyLocation is indeterminate
     * or not relevant.
     * {@code KEY_TYPED} events do not have a keyLocation; this value
     * is used instead.
     * @since 1.4
     */
    public static final int KEY_LOCATION_UNKNOWN = 0;

    /**
     * A constant indicating that the key pressed or released
     * is not distinguished as the left or right version of a key,
     * and did not originate on the numeric keypad (or did not
     * originate with a virtual key corresponding to the numeric
     * keypad).
     * @since 1.4
     */
    public static final int KEY_LOCATION_STANDARD = 1;

    /**
     * A constant indicating that the key pressed or released is in
     * the left key location (there is more than one possible location
     * for this key).  Example: the left shift key.
     * @since 1.4
     */
    public static final int KEY_LOCATION_LEFT = 2;

    /**
     * A constant indicating that the key pressed or released is in
     * the right key location (there is more than one possible location
     * for this key).  Example: the right shift key.
     * @since 1.4
     */
    public static final int KEY_LOCATION_RIGHT = 3;

    /**
     * A constant indicating that the key event originated on the
     * numeric keypad or with a virtual key corresponding to the
     * numeric keypad.
     * @since 1.4
     */
    public static final int KEY_LOCATION_NUMPAD = 4;

    /**
     * The unique value assigned to each of the keys on the
     * keyboard.  There is a common set of key codes that
     * can be fired by most keyboards.
     * The symbolic name for a key code should be used rather
     * than the code value itself.
     *
     * @serial
     * @see #getKeyCode()
     * @see #setKeyCode(int)
     */
    int keyCode;

    /**
     * {@code keyChar} is a valid unicode character
     * that is fired by a key or a key combination on
     * a keyboard.
     *
     * @serial
     * @see #getKeyChar()
     * @see #setKeyChar(char)
     */
    char keyChar;

    /**
     * The location of the key on the keyboard.
     *
     * Some keys occur more than once on a keyboard, e.g. the left and
     * right shift keys.  Additionally, some keys occur on the numeric
     * keypad.  This variable is used to distinguish such keys.
     *
     * The only legal values are {@code KEY_LOCATION_UNKNOWN},
     * {@code KEY_LOCATION_STANDARD}, {@code KEY_LOCATION_LEFT},
     * {@code KEY_LOCATION_RIGHT}, and {@code KEY_LOCATION_NUMPAD}.
     *
     * @serial
     * @see #getKeyLocation()
     */
    int keyLocation;

    //set from native code.
    private transient long rawCode = 0;
    private transient long primaryLevelUnicode = 0;
    private transient long scancode = 0; // for MS Windows only
    private transient long extendedKeyCode = 0;

    /*
     * JDK 1.1 serialVersionUID
     */
    private static final long serialVersionUID = -2352130953028126954L;

    static {
        /* ensure that the necessary native libraries are loaded */
        NativeLibLoader.loadLibraries();
        if (!GraphicsEnvironment.isHeadless()) {
            initIDs();
        }

        AWTAccessor.setKeyEventAccessor(new AWTAccessor.KeyEventAccessor() {
            public void setRawCode(KeyEvent ev, long rawCode) {
                ev.rawCode = rawCode;
            }

            public void setPrimaryLevelUnicode(KeyEvent ev, long primaryLevelUnicode) {
                ev.primaryLevelUnicode = primaryLevelUnicode;
            }

            public void setExtendedKeyCode(KeyEvent ev, long extendedKeyCode) {
                ev.extendedKeyCode = extendedKeyCode;
            }

            public Component getOriginalSource(KeyEvent ev) {
                return ev.originalSource;
            }

            @Override
            public boolean isProxyActive(KeyEvent ev) {
                return ev.isProxyActive;
            }
        });
    }

    /**
     * Initialize JNI field and method IDs for fields that may be
     * accessed from C.
     */
    private static native void initIDs();

    /**
     * The original event source.
     *
     * Event source can be changed during processing, but in some cases
     * we need to be able to obtain original source.
     *
     * @since 1.8
     */
    private Component originalSource;

    private KeyEvent(Component source, int id, long when, int modifiers, int keyCode, char keyChar, int keyLocation,
            boolean isProxyActive) {
        this(source, id, when, modifiers, keyCode, keyChar, keyLocation);
        this.isProxyActive = isProxyActive;
    }

    /**
     * Constructs a {@code KeyEvent} object.
     * <p>This method throws an
     * {@code IllegalArgumentException} if {@code source}
     * is {@code null}.
     *
     * @param source    The {@code Component} that originated the event
     * @param id              An integer indicating the type of event.
     *                  For information on allowable values, see
     *                  the class description for {@link KeyEvent}
     * @param when      A long integer that specifies the time the event
     *                  occurred.
     *                     Passing negative or zero value
     *                     is not recommended
     * @param modifiers The modifier keys down during event (shift, ctrl,
     *                  alt, meta).
     *                     Passing negative value
     *                     is not recommended.
     *                     Zero value means that no modifiers were passed.
     *                  Use either an extended _DOWN_MASK or old _MASK modifiers,
     *                  however do not mix models in the one event.
     *                  The extended modifiers are preferred for using
     * @param keyCode   The integer code for an actual key, or VK_UNDEFINED
     *                  (for a key-typed event)
     * @param keyChar   The Unicode character generated by this event, or
     *                  CHAR_UNDEFINED (for key-pressed and key-released
     *                  events which do not map to a valid Unicode character)
     * @param keyLocation  Identifies the key location.  The only legal
     *        values are {@code KEY_LOCATION_UNKNOWN},
     *        {@code KEY_LOCATION_STANDARD}, {@code KEY_LOCATION_LEFT},
     *        {@code KEY_LOCATION_RIGHT}, and {@code KEY_LOCATION_NUMPAD}.
     * @throws IllegalArgumentException
     *     if {@code id} is {@code KEY_TYPED} and
     *       {@code keyChar} is {@code CHAR_UNDEFINED};
     *     or if {@code id} is {@code KEY_TYPED} and
     *       {@code keyCode} is not {@code VK_UNDEFINED};
     *     or if {@code id} is {@code KEY_TYPED} and
     *       {@code keyLocation} is not {@code KEY_LOCATION_UNKNOWN};
     *     or if {@code keyLocation} is not one of the legal
     *       values enumerated above.
     * @throws IllegalArgumentException if {@code source} is null
     * @see #getSource()
     * @see #getID()
     * @see #getWhen()
     * @see #getModifiers()
     * @see #getKeyCode()
     * @see #getKeyChar()
     * @see #getKeyLocation()
     * @since 1.4
     */
    @SuppressWarnings("deprecation")
    public KeyEvent(Component source, int id, long when, int modifiers, int keyCode, char keyChar,
            int keyLocation) {
        super(source, id, when, modifiers);
        if (id == KEY_TYPED) {
            if (keyChar == CHAR_UNDEFINED) {
                throw new IllegalArgumentException("invalid keyChar");
            }
            if (keyCode != VK_UNDEFINED) {
                throw new IllegalArgumentException("invalid keyCode");
            }
            if (keyLocation != KEY_LOCATION_UNKNOWN) {
                throw new IllegalArgumentException("invalid keyLocation");
            }
        }

        this.keyCode = keyCode;
        this.keyChar = keyChar;

        if ((keyLocation < KEY_LOCATION_UNKNOWN) || (keyLocation > KEY_LOCATION_NUMPAD)) {
            throw new IllegalArgumentException("invalid keyLocation");
        }
        this.keyLocation = keyLocation;
        if ((getModifiers() != 0) && (getModifiersEx() == 0)) {
            setNewModifiers();
        } else if ((getModifiers() == 0) && (getModifiersEx() != 0)) {
            setOldModifiers();
        }
        originalSource = source;
    }

    /**
     * Constructs a {@code KeyEvent} object.
     * <p> This method throws an
     * {@code IllegalArgumentException} if {@code source}
     * is {@code null}.
     *
     * @param source    The {@code Component} that originated the event
     * @param id              An integer indicating the type of event.
     *                  For information on allowable values, see
     *                  the class description for {@link KeyEvent}
     * @param when      A long integer that specifies the time the event
     *                  occurred.
     *                     Passing negative or zero value
     *                     is not recommended
     * @param modifiers The modifier keys down during event (shift, ctrl,
     *                  alt, meta).
     *                     Passing negative value
     *                     is not recommended.
     *                     Zero value means that no modifiers were passed.
     *                  Use either an extended _DOWN_MASK or old _MASK modifiers,
     *                  however do not mix models in the one event.
     *                  The extended modifiers are preferred for using
     * @param keyCode   The integer code for an actual key, or VK_UNDEFINED
     *                  (for a key-typed event)
     * @param keyChar   The Unicode character generated by this event, or
     *                  CHAR_UNDEFINED (for key-pressed and key-released
     *                  events which do not map to a valid Unicode character)
     * @throws IllegalArgumentException  if {@code id} is
     *     {@code KEY_TYPED} and {@code keyChar} is
     *     {@code CHAR_UNDEFINED}; or if {@code id} is
     *     {@code KEY_TYPED} and {@code keyCode} is not
     *     {@code VK_UNDEFINED}
     * @throws IllegalArgumentException if {@code source} is null
     * @see #getSource()
     * @see #getID()
     * @see #getWhen()
     * @see #getModifiers()
     * @see #getKeyCode()
     * @see #getKeyChar()
     */
    public KeyEvent(Component source, int id, long when, int modifiers, int keyCode, char keyChar) {
        this(source, id, when, modifiers, keyCode, keyChar, KEY_LOCATION_UNKNOWN);
    }

    /**
     * @deprecated as of JDK1.1; use {@link #KeyEvent(Component, int, long, int, int, char)} instead
     * @param source    The {@code Component} that originated the event
     * @param id              An integer indicating the type of event.
     *                  For information on allowable values, see
     *                  the class description for {@link KeyEvent}
     * @param when      A long integer that specifies the time the event
     *                  occurred.
     *                     Passing negative or zero value
     *                     is not recommended
     * @param modifiers The modifier keys down during event (shift, ctrl,
     *                  alt, meta).
     *                     Passing negative value
     *                     is not recommended.
     *                     Zero value means that no modifiers were passed.
     *                  Use either an extended _DOWN_MASK or old _MASK modifiers,
     *                  however do not mix models in the one event.
     *                  The extended modifiers are preferred for using
     * @param keyCode   The integer code for an actual key, or VK_UNDEFINED
     *                  (for a key-typed event)
     */
    @Deprecated
    public KeyEvent(Component source, int id, long when, int modifiers, int keyCode) {
        this(source, id, when, modifiers, keyCode, (char) keyCode);
    }

    /**
     * Returns the integer keyCode associated with the key in this event.
     *
     * @return the integer code for an actual key on the keyboard.
     *         (For {@code KEY_TYPED} events, the keyCode is
     *         {@code VK_UNDEFINED}.)
     */
    public int getKeyCode() {
        return keyCode;
    }

    /**
     * Set the keyCode value to indicate a physical key.
     *
     * @param keyCode an integer corresponding to an actual key on the keyboard.
     */
    public void setKeyCode(int keyCode) {
        this.keyCode = keyCode;
    }

    /**
     * Returns the character associated with the key in this event.
     * For example, the {@code KEY_TYPED} event for shift + "a"
     * returns the value for "A".
     * <p>
     * {@code KEY_PRESSED} and {@code KEY_RELEASED} events
     * are not intended for reporting of character input.  Therefore,
     * the values returned by this method are guaranteed to be
     * meaningful only for {@code KEY_TYPED} events.
     *
     * @return the Unicode character defined for this key event.
     *         If no valid Unicode character exists for this key event,
     *         {@code CHAR_UNDEFINED} is returned.
     */
    public char getKeyChar() {
        return keyChar;
    }

    /**
     * Set the keyChar value to indicate a logical character.
     *
     * @param keyChar a char corresponding to the combination of keystrokes
     *                that make up this event.
     */
    public void setKeyChar(char keyChar) {
        this.keyChar = keyChar;
    }

    /**
     * Set the modifiers to indicate additional keys that were held down
     * (e.g. shift, ctrl, alt, meta) defined as part of InputEvent.
     * <p>
     * NOTE:  use of this method is not recommended, because many AWT
     * implementations do not recognize modifier changes.  This is
     * especially true for {@code KEY_TYPED} events where the shift
     * modifier is changed.
     *
     * @param modifiers an integer combination of the modifier constants.
     * @see InputEvent
     * @deprecated as of JDK1.1.4
     */
    @Deprecated
    public void setModifiers(int modifiers) {
        this.modifiers = modifiers;
        if ((getModifiers() != 0) && (getModifiersEx() == 0)) {
            setNewModifiers();
        } else if ((getModifiers() == 0) && (getModifiersEx() != 0)) {
            setOldModifiers();
        }
    }

    /**
     * Returns the location of the key that originated this key event.
     *
     * Some keys occur more than once on a keyboard, e.g. the left and
     * right shift keys.  Additionally, some keys occur on the numeric
     * keypad.  This provides a way of distinguishing such keys.
     *
     * @return the location of the key that was pressed or released.
     *         Always returns {@code KEY_LOCATION_UNKNOWN} for
     *         {@code KEY_TYPED} events.
     * @since 1.4
     */
    public int getKeyLocation() {
        return keyLocation;
    }

    /**
     * Returns a String describing the keyCode, such as "HOME", "F1" or "A".
     * These strings can be localized by changing the awt.properties file.
     *
     * @param keyCode the key whose description is to be returned
     * @return a string containing a text description for a physical key,
     *         identified by its keyCode
     */
    public static String getKeyText(int keyCode) {
        if (keyCode >= VK_0 && keyCode <= VK_9 || keyCode >= VK_A && keyCode <= VK_Z) {
            return String.valueOf((char) keyCode);
        }

        switch (keyCode) {
        case VK_ENTER:
            return Toolkit.getProperty("AWT.enter", "Enter");
        case VK_BACK_SPACE:
            return Toolkit.getProperty("AWT.backSpace", "Backspace");
        case VK_TAB:
            return Toolkit.getProperty("AWT.tab", "Tab");
        case VK_CANCEL:
            return Toolkit.getProperty("AWT.cancel", "Cancel");
        case VK_CLEAR:
            return Toolkit.getProperty("AWT.clear", "Clear");
        case VK_COMPOSE:
            return Toolkit.getProperty("AWT.compose", "Compose");
        case VK_PAUSE:
            return Toolkit.getProperty("AWT.pause", "Pause");
        case VK_CAPS_LOCK:
            return Toolkit.getProperty("AWT.capsLock", "Caps Lock");
        case VK_ESCAPE:
            return Toolkit.getProperty("AWT.escape", "Escape");
        case VK_SPACE:
            return Toolkit.getProperty("AWT.space", "Space");
        case VK_PAGE_UP:
            return Toolkit.getProperty("AWT.pgup", "Page Up");
        case VK_PAGE_DOWN:
            return Toolkit.getProperty("AWT.pgdn", "Page Down");
        case VK_END:
            return Toolkit.getProperty("AWT.end", "End");
        case VK_HOME:
            return Toolkit.getProperty("AWT.home", "Home");
        case VK_LEFT:
            return Toolkit.getProperty("AWT.left", "Left");
        case VK_UP:
            return Toolkit.getProperty("AWT.up", "Up");
        case VK_RIGHT:
            return Toolkit.getProperty("AWT.right", "Right");
        case VK_DOWN:
            return Toolkit.getProperty("AWT.down", "Down");
        case VK_BEGIN:
            return Toolkit.getProperty("AWT.begin", "Begin");

        // modifiers
        case VK_SHIFT:
            return Toolkit.getProperty("AWT.shift", "Shift");
        case VK_CONTROL:
            return Toolkit.getProperty("AWT.control", "Control");
        case VK_ALT:
            return Toolkit.getProperty("AWT.alt", "Alt");
        case VK_META:
            return Toolkit.getProperty("AWT.meta", "Meta");
        case VK_ALT_GRAPH:
            return Toolkit.getProperty("AWT.altGraph", "Alt Graph");

        // punctuation
        case VK_COMMA:
            return Toolkit.getProperty("AWT.comma", "Comma");
        case VK_PERIOD:
            return Toolkit.getProperty("AWT.period", "Period");
        case VK_SLASH:
            return Toolkit.getProperty("AWT.slash", "Slash");
        case VK_SEMICOLON:
            return Toolkit.getProperty("AWT.semicolon", "Semicolon");
        case VK_EQUALS:
            return Toolkit.getProperty("AWT.equals", "Equals");
        case VK_OPEN_BRACKET:
            return Toolkit.getProperty("AWT.openBracket", "Open Bracket");
        case VK_BACK_SLASH:
            return Toolkit.getProperty("AWT.backSlash", "Back Slash");
        case VK_CLOSE_BRACKET:
            return Toolkit.getProperty("AWT.closeBracket", "Close Bracket");

        // numpad numeric keys handled below
        case VK_MULTIPLY:
            return Toolkit.getProperty("AWT.multiply", "NumPad *");
        case VK_ADD:
            return Toolkit.getProperty("AWT.add", "NumPad +");
        case VK_SEPARATOR:
            return Toolkit.getProperty("AWT.separator", "NumPad ,");
        case VK_SUBTRACT:
            return Toolkit.getProperty("AWT.subtract", "NumPad -");
        case VK_DECIMAL:
            return Toolkit.getProperty("AWT.decimal", "NumPad .");
        case VK_DIVIDE:
            return Toolkit.getProperty("AWT.divide", "NumPad /");
        case VK_DELETE:
            return Toolkit.getProperty("AWT.delete", "Delete");
        case VK_NUM_LOCK:
            return Toolkit.getProperty("AWT.numLock", "Num Lock");
        case VK_SCROLL_LOCK:
            return Toolkit.getProperty("AWT.scrollLock", "Scroll Lock");

        case VK_WINDOWS:
            return Toolkit.getProperty("AWT.windows", "Windows");
        case VK_CONTEXT_MENU:
            return Toolkit.getProperty("AWT.context", "Context Menu");

        case VK_F1:
            return Toolkit.getProperty("AWT.f1", "F1");
        case VK_F2:
            return Toolkit.getProperty("AWT.f2", "F2");
        case VK_F3:
            return Toolkit.getProperty("AWT.f3", "F3");
        case VK_F4:
            return Toolkit.getProperty("AWT.f4", "F4");
        case VK_F5:
            return Toolkit.getProperty("AWT.f5", "F5");
        case VK_F6:
            return Toolkit.getProperty("AWT.f6", "F6");
        case VK_F7:
            return Toolkit.getProperty("AWT.f7", "F7");
        case VK_F8:
            return Toolkit.getProperty("AWT.f8", "F8");
        case VK_F9:
            return Toolkit.getProperty("AWT.f9", "F9");
        case VK_F10:
            return Toolkit.getProperty("AWT.f10", "F10");
        case VK_F11:
            return Toolkit.getProperty("AWT.f11", "F11");
        case VK_F12:
            return Toolkit.getProperty("AWT.f12", "F12");
        case VK_F13:
            return Toolkit.getProperty("AWT.f13", "F13");
        case VK_F14:
            return Toolkit.getProperty("AWT.f14", "F14");
        case VK_F15:
            return Toolkit.getProperty("AWT.f15", "F15");
        case VK_F16:
            return Toolkit.getProperty("AWT.f16", "F16");
        case VK_F17:
            return Toolkit.getProperty("AWT.f17", "F17");
        case VK_F18:
            return Toolkit.getProperty("AWT.f18", "F18");
        case VK_F19:
            return Toolkit.getProperty("AWT.f19", "F19");
        case VK_F20:
            return Toolkit.getProperty("AWT.f20", "F20");
        case VK_F21:
            return Toolkit.getProperty("AWT.f21", "F21");
        case VK_F22:
            return Toolkit.getProperty("AWT.f22", "F22");
        case VK_F23:
            return Toolkit.getProperty("AWT.f23", "F23");
        case VK_F24:
            return Toolkit.getProperty("AWT.f24", "F24");

        case VK_PRINTSCREEN:
            return Toolkit.getProperty("AWT.printScreen", "Print Screen");
        case VK_INSERT:
            return Toolkit.getProperty("AWT.insert", "Insert");
        case VK_HELP:
            return Toolkit.getProperty("AWT.help", "Help");
        case VK_BACK_QUOTE:
            return Toolkit.getProperty("AWT.backQuote", "Back Quote");
        case VK_QUOTE:
            return Toolkit.getProperty("AWT.quote", "Quote");

        case VK_KP_UP:
            return Toolkit.getProperty("AWT.up", "Up");
        case VK_KP_DOWN:
            return Toolkit.getProperty("AWT.down", "Down");
        case VK_KP_LEFT:
            return Toolkit.getProperty("AWT.left", "Left");
        case VK_KP_RIGHT:
            return Toolkit.getProperty("AWT.right", "Right");

        case VK_DEAD_GRAVE:
            return Toolkit.getProperty("AWT.deadGrave", "Dead Grave");
        case VK_DEAD_ACUTE:
            return Toolkit.getProperty("AWT.deadAcute", "Dead Acute");
        case VK_DEAD_CIRCUMFLEX:
            return Toolkit.getProperty("AWT.deadCircumflex", "Dead Circumflex");
        case VK_DEAD_TILDE:
            return Toolkit.getProperty("AWT.deadTilde", "Dead Tilde");
        case VK_DEAD_MACRON:
            return Toolkit.getProperty("AWT.deadMacron", "Dead Macron");
        case VK_DEAD_BREVE:
            return Toolkit.getProperty("AWT.deadBreve", "Dead Breve");
        case VK_DEAD_ABOVEDOT:
            return Toolkit.getProperty("AWT.deadAboveDot", "Dead Above Dot");
        case VK_DEAD_DIAERESIS:
            return Toolkit.getProperty("AWT.deadDiaeresis", "Dead Diaeresis");
        case VK_DEAD_ABOVERING:
            return Toolkit.getProperty("AWT.deadAboveRing", "Dead Above Ring");
        case VK_DEAD_DOUBLEACUTE:
            return Toolkit.getProperty("AWT.deadDoubleAcute", "Dead Double Acute");
        case VK_DEAD_CARON:
            return Toolkit.getProperty("AWT.deadCaron", "Dead Caron");
        case VK_DEAD_CEDILLA:
            return Toolkit.getProperty("AWT.deadCedilla", "Dead Cedilla");
        case VK_DEAD_OGONEK:
            return Toolkit.getProperty("AWT.deadOgonek", "Dead Ogonek");
        case VK_DEAD_IOTA:
            return Toolkit.getProperty("AWT.deadIota", "Dead Iota");
        case VK_DEAD_VOICED_SOUND:
            return Toolkit.getProperty("AWT.deadVoicedSound", "Dead Voiced Sound");
        case VK_DEAD_SEMIVOICED_SOUND:
            return Toolkit.getProperty("AWT.deadSemivoicedSound", "Dead Semivoiced Sound");

        case VK_AMPERSAND:
            return Toolkit.getProperty("AWT.ampersand", "Ampersand");
        case VK_ASTERISK:
            return Toolkit.getProperty("AWT.asterisk", "Asterisk");
        case VK_QUOTEDBL:
            return Toolkit.getProperty("AWT.quoteDbl", "Double Quote");
        case VK_LESS:
            return Toolkit.getProperty("AWT.Less", "Less");
        case VK_GREATER:
            return Toolkit.getProperty("AWT.greater", "Greater");
        case VK_BRACELEFT:
            return Toolkit.getProperty("AWT.braceLeft", "Left Brace");
        case VK_BRACERIGHT:
            return Toolkit.getProperty("AWT.braceRight", "Right Brace");
        case VK_AT:
            return Toolkit.getProperty("AWT.at", "At");
        case VK_COLON:
            return Toolkit.getProperty("AWT.colon", "Colon");
        case VK_CIRCUMFLEX:
            return Toolkit.getProperty("AWT.circumflex", "Circumflex");
        case VK_DOLLAR:
            return Toolkit.getProperty("AWT.dollar", "Dollar");
        case VK_EURO_SIGN:
            return Toolkit.getProperty("AWT.euro", "Euro");
        case VK_EXCLAMATION_MARK:
            return Toolkit.getProperty("AWT.exclamationMark", "Exclamation Mark");
        case VK_INVERTED_EXCLAMATION_MARK:
            return Toolkit.getProperty("AWT.invertedExclamationMark", "Inverted Exclamation Mark");
        case VK_LEFT_PARENTHESIS:
            return Toolkit.getProperty("AWT.leftParenthesis", "Left Parenthesis");
        case VK_NUMBER_SIGN:
            return Toolkit.getProperty("AWT.numberSign", "Number Sign");
        case VK_MINUS:
            return Toolkit.getProperty("AWT.minus", "Minus");
        case VK_PLUS:
            return Toolkit.getProperty("AWT.plus", "Plus");
        case VK_RIGHT_PARENTHESIS:
            return Toolkit.getProperty("AWT.rightParenthesis", "Right Parenthesis");
        case VK_UNDERSCORE:
            return Toolkit.getProperty("AWT.underscore", "Underscore");

        case VK_FINAL:
            return Toolkit.getProperty("AWT.final", "Final");
        case VK_CONVERT:
            return Toolkit.getProperty("AWT.convert", "Convert");
        case VK_NONCONVERT:
            return Toolkit.getProperty("AWT.noconvert", "No Convert");
        case VK_ACCEPT:
            return Toolkit.getProperty("AWT.accept", "Accept");
        case VK_MODECHANGE:
            return Toolkit.getProperty("AWT.modechange", "Mode Change");
        case VK_KANA:
            return Toolkit.getProperty("AWT.kana", "Kana");
        case VK_KANJI:
            return Toolkit.getProperty("AWT.kanji", "Kanji");
        case VK_ALPHANUMERIC:
            return Toolkit.getProperty("AWT.alphanumeric", "Alphanumeric");
        case VK_KATAKANA:
            return Toolkit.getProperty("AWT.katakana", "Katakana");
        case VK_HIRAGANA:
            return Toolkit.getProperty("AWT.hiragana", "Hiragana");
        case VK_FULL_WIDTH:
            return Toolkit.getProperty("AWT.fullWidth", "Full-Width");
        case VK_HALF_WIDTH:
            return Toolkit.getProperty("AWT.halfWidth", "Half-Width");
        case VK_ROMAN_CHARACTERS:
            return Toolkit.getProperty("AWT.romanCharacters", "Roman Characters");
        case VK_ALL_CANDIDATES:
            return Toolkit.getProperty("AWT.allCandidates", "All Candidates");
        case VK_PREVIOUS_CANDIDATE:
            return Toolkit.getProperty("AWT.previousCandidate", "Previous Candidate");
        case VK_CODE_INPUT:
            return Toolkit.getProperty("AWT.codeInput", "Code Input");
        case VK_JAPANESE_KATAKANA:
            return Toolkit.getProperty("AWT.japaneseKatakana", "Japanese Katakana");
        case VK_JAPANESE_HIRAGANA:
            return Toolkit.getProperty("AWT.japaneseHiragana", "Japanese Hiragana");
        case VK_JAPANESE_ROMAN:
            return Toolkit.getProperty("AWT.japaneseRoman", "Japanese Roman");
        case VK_KANA_LOCK:
            return Toolkit.getProperty("AWT.kanaLock", "Kana Lock");
        case VK_INPUT_METHOD_ON_OFF:
            return Toolkit.getProperty("AWT.inputMethodOnOff", "Input Method On/Off");

        case VK_AGAIN:
            return Toolkit.getProperty("AWT.again", "Again");
        case VK_UNDO:
            return Toolkit.getProperty("AWT.undo", "Undo");
        case VK_COPY:
            return Toolkit.getProperty("AWT.copy", "Copy");
        case VK_PASTE:
            return Toolkit.getProperty("AWT.paste", "Paste");
        case VK_CUT:
            return Toolkit.getProperty("AWT.cut", "Cut");
        case VK_FIND:
            return Toolkit.getProperty("AWT.find", "Find");
        case VK_PROPS:
            return Toolkit.getProperty("AWT.props", "Props");
        case VK_STOP:
            return Toolkit.getProperty("AWT.stop", "Stop");
        }

        if (keyCode >= VK_NUMPAD0 && keyCode <= VK_NUMPAD9) {
            String numpad = Toolkit.getProperty("AWT.numpad", "NumPad");
            char c = (char) (keyCode - VK_NUMPAD0 + '0');
            return numpad + "-" + c;
        }

        if ((keyCode & 0x01000000) != 0) {
            return String.valueOf((char) (keyCode ^ 0x01000000));
        }
        String unknown = Toolkit.getProperty("AWT.unknown", "Unknown");
        return unknown + " keyCode: 0x" + Integer.toString(keyCode, 16);
    }

    /**
     * Returns a {@code String} describing the modifier key(s),
     * such as "Shift", or "Ctrl+Shift".  These strings can be
     * localized by changing the {@code awt.properties} file.
     * <p>
     * Note that {@code InputEvent.ALT_MASK} and
     * {@code InputEvent.BUTTON2_MASK} have the same value,
     * so the string "Alt" is returned for both modifiers.  Likewise,
     * {@code InputEvent.META_MASK} and
     * {@code InputEvent.BUTTON3_MASK} have the same value,
     * so the string "Meta" is returned for both modifiers.
     *
     * @param modifiers the modifier mask to be processed
     * @return string a text description of the combination of modifier
     *                keys that were held down during the event
     * @see InputEvent#getModifiersExText(int)
     * @deprecated It is recommended that extended modifier keys and
     *             {@link InputEvent#getModifiersExText(int)} be used instead
     */
    @Deprecated(since = "9")
    public static String getKeyModifiersText(int modifiers) {
        StringBuilder buf = new StringBuilder();
        if ((modifiers & InputEvent.META_MASK) != 0) {
            buf.append(Toolkit.getProperty("AWT.meta", "Meta"));
            buf.append("+");
        }
        if ((modifiers & InputEvent.CTRL_MASK) != 0) {
            buf.append(Toolkit.getProperty("AWT.control", "Ctrl"));
            buf.append("+");
        }
        if ((modifiers & InputEvent.ALT_MASK) != 0) {
            buf.append(Toolkit.getProperty("AWT.alt", "Alt"));
            buf.append("+");
        }
        if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
            buf.append(Toolkit.getProperty("AWT.shift", "Shift"));
            buf.append("+");
        }
        if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) {
            buf.append(Toolkit.getProperty("AWT.altGraph", "Alt Graph"));
            buf.append("+");
        }
        if ((modifiers & InputEvent.BUTTON1_MASK) != 0) {
            buf.append(Toolkit.getProperty("AWT.button1", "Button1"));
            buf.append("+");
        }
        if (buf.length() > 0) {
            buf.setLength(buf.length() - 1); // remove trailing '+'
        }
        return buf.toString();
    }

    /**
     * Returns whether the key in this event is an "action" key.
     * Typically an action key does not fire a unicode character and is
     * not a modifier key.
     *
     * @return {@code true} if the key is an "action" key,
     *         {@code false} otherwise
     */
    public boolean isActionKey() {
        switch (keyCode) {
        case VK_HOME:
        case VK_END:
        case VK_PAGE_UP:
        case VK_PAGE_DOWN:
        case VK_UP:
        case VK_DOWN:
        case VK_LEFT:
        case VK_RIGHT:
        case VK_BEGIN:

        case VK_KP_LEFT:
        case VK_KP_UP:
        case VK_KP_RIGHT:
        case VK_KP_DOWN:

        case VK_F1:
        case VK_F2:
        case VK_F3:
        case VK_F4:
        case VK_F5:
        case VK_F6:
        case VK_F7:
        case VK_F8:
        case VK_F9:
        case VK_F10:
        case VK_F11:
        case VK_F12:
        case VK_F13:
        case VK_F14:
        case VK_F15:
        case VK_F16:
        case VK_F17:
        case VK_F18:
        case VK_F19:
        case VK_F20:
        case VK_F21:
        case VK_F22:
        case VK_F23:
        case VK_F24:
        case VK_PRINTSCREEN:
        case VK_SCROLL_LOCK:
        case VK_CAPS_LOCK:
        case VK_NUM_LOCK:
        case VK_PAUSE:
        case VK_INSERT:

        case VK_FINAL:
        case VK_CONVERT:
        case VK_NONCONVERT:
        case VK_ACCEPT:
        case VK_MODECHANGE:
        case VK_KANA:
        case VK_KANJI:
        case VK_ALPHANUMERIC:
        case VK_KATAKANA:
        case VK_HIRAGANA:
        case VK_FULL_WIDTH:
        case VK_HALF_WIDTH:
        case VK_ROMAN_CHARACTERS:
        case VK_ALL_CANDIDATES:
        case VK_PREVIOUS_CANDIDATE:
        case VK_CODE_INPUT:
        case VK_JAPANESE_KATAKANA:
        case VK_JAPANESE_HIRAGANA:
        case VK_JAPANESE_ROMAN:
        case VK_KANA_LOCK:
        case VK_INPUT_METHOD_ON_OFF:

        case VK_AGAIN:
        case VK_UNDO:
        case VK_COPY:
        case VK_PASTE:
        case VK_CUT:
        case VK_FIND:
        case VK_PROPS:
        case VK_STOP:

        case VK_HELP:
        case VK_WINDOWS:
        case VK_CONTEXT_MENU:
            return true;
        }
        return false;
    }

    /**
     * Returns a parameter string identifying this event.
     * This method is useful for event logging and for debugging.
     *
     * @return a string identifying the event and its attributes
     */
    @SuppressWarnings("deprecation")
    public String paramString() {
        StringBuilder str = new StringBuilder(100);

        switch (id) {
        case KEY_PRESSED:
            str.append("KEY_PRESSED");
            break;
        case KEY_RELEASED:
            str.append("KEY_RELEASED");
            break;
        case KEY_TYPED:
            str.append("KEY_TYPED");
            break;
        default:
            str.append("unknown type");
            break;
        }

        str.append(",keyCode=").append(keyCode);
        str.append(",keyText=").append(getKeyText(keyCode));

        /* Some keychars don't print well, e.g. escape, backspace,
         * tab, return, delete, cancel.  Get keyText for the keyCode
         * instead of the keyChar.
         */
        str.append(",keyChar=");
        switch (keyChar) {
        case '\b':
            str.append(getKeyText(VK_BACK_SPACE));
            break;
        case '\t':
            str.append(getKeyText(VK_TAB));
            break;
        case '\n':
            str.append(getKeyText(VK_ENTER));
            break;
        case '\u0018':
            str.append(getKeyText(VK_CANCEL));
            break;
        case '\u001b':
            str.append(getKeyText(VK_ESCAPE));
            break;
        case '\u007f':
            str.append(getKeyText(VK_DELETE));
            break;
        case CHAR_UNDEFINED:
            str.append(Toolkit.getProperty("AWT.undefined", "Undefined"));
            str.append(" keyChar");
            break;
        default:
            str.append("'").append(keyChar).append("'");
            break;
        }

        if (getModifiers() != 0) {
            str.append(",modifiers=").append(getKeyModifiersText(modifiers));
        }
        if (getModifiersEx() != 0) {
            str.append(",extModifiers=").append(getModifiersExText(modifiers));
        }

        str.append(",keyLocation=");
        switch (keyLocation) {
        case KEY_LOCATION_UNKNOWN:
            str.append("KEY_LOCATION_UNKNOWN");
            break;
        case KEY_LOCATION_STANDARD:
            str.append("KEY_LOCATION_STANDARD");
            break;
        case KEY_LOCATION_LEFT:
            str.append("KEY_LOCATION_LEFT");
            break;
        case KEY_LOCATION_RIGHT:
            str.append("KEY_LOCATION_RIGHT");
            break;
        case KEY_LOCATION_NUMPAD:
            str.append("KEY_LOCATION_NUMPAD");
            break;
        default:
            str.append("KEY_LOCATION_UNKNOWN");
            break;
        }
        str.append(",rawCode=").append(rawCode);
        str.append(",primaryLevelUnicode=").append(primaryLevelUnicode);
        str.append(",scancode=").append(scancode);
        str.append(",extendedKeyCode=0x").append(Long.toHexString(extendedKeyCode));

        return str.toString();
    }

    /**
     * Returns an extended key code for the event.
     * The extended key code is a unique id assigned to  a key on the keyboard
     * just like {@code keyCode}. However, unlike {@code keyCode}, this value depends on the
     * current keyboard layout. For instance, pressing the left topmost letter key
     * in a common English layout produces the same value as {@code keyCode}, {@code VK_Q}.
     * Pressing the same key in a regular Russian layout gives another code, unique for the
     * letter "Cyrillic I short".
     *
     * @return an extended key code for the event
     * @since 1.7
     */
    public int getExtendedKeyCode() {
        return (int) extendedKeyCode;
    }

    /**
     * Returns an extended key code for a unicode character.
     *
     * @param c the unicode character to be processed
     * @return for a unicode character with a corresponding {@code VK_} constant -- this
     *   {@code VK_} constant; for a character appearing on the primary
     *   level of a known keyboard layout -- a unique integer.
     *   If a character does not appear on the primary level of a known keyboard,
     *   {@code VK_UNDEFINED} is returned.
     *
     * @since 1.7
     */
    public static int getExtendedKeyCodeForChar(int c) {
        // Return a keycode (if any) associated with a character.
        return sun.awt.ExtendedKeyCodes.getExtendedKeyCodeForChar(c);
    }

    /**
     * Sets new modifiers by the old ones. The key modifiers
     * override overlapping mouse modifiers.
     */
    @SuppressWarnings("deprecation")
    private void setNewModifiers() {
        if ((modifiers & SHIFT_MASK) != 0) {
            modifiers |= SHIFT_DOWN_MASK;
        }
        if ((modifiers & ALT_MASK) != 0) {
            modifiers |= ALT_DOWN_MASK;
        }
        if ((modifiers & CTRL_MASK) != 0) {
            modifiers |= CTRL_DOWN_MASK;
        }
        if ((modifiers & META_MASK) != 0) {
            modifiers |= META_DOWN_MASK;
        }
        if ((modifiers & ALT_GRAPH_MASK) != 0) {
            modifiers |= ALT_GRAPH_DOWN_MASK;
        }
        if ((modifiers & BUTTON1_MASK) != 0) {
            modifiers |= BUTTON1_DOWN_MASK;
        }
    }

    /**
     * Sets old modifiers by the new ones.
     */
    @SuppressWarnings("deprecation")
    private void setOldModifiers() {
        if ((modifiers & SHIFT_DOWN_MASK) != 0) {
            modifiers |= SHIFT_MASK;
        }
        if ((modifiers & ALT_DOWN_MASK) != 0) {
            modifiers |= ALT_MASK;
        }
        if ((modifiers & CTRL_DOWN_MASK) != 0) {
            modifiers |= CTRL_MASK;
        }
        if ((modifiers & META_DOWN_MASK) != 0) {
            modifiers |= META_MASK;
        }
        if ((modifiers & ALT_GRAPH_DOWN_MASK) != 0) {
            modifiers |= ALT_GRAPH_MASK;
        }
        if ((modifiers & BUTTON1_DOWN_MASK) != 0) {
            modifiers |= BUTTON1_MASK;
        }
    }

    /**
     * Sets new modifiers by the old ones. The key modifiers
     * override overlapping mouse modifiers.
     * @serial
     */
    @SuppressWarnings("deprecation")
    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        if (getModifiers() != 0 && getModifiersEx() == 0) {
            setNewModifiers();
        }
    }
}