Path: blob/master/src/java.desktop/share/classes/java/awt/AWTKeyStroke.java
41152 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.awt;2627import java.awt.event.InputEvent;28import java.awt.event.KeyEvent;29import java.io.Serial;30import java.io.Serializable;31import java.lang.reflect.Field;32import java.lang.reflect.Modifier;33import java.util.Collections;34import java.util.HashMap;35import java.util.Map;36import java.util.StringTokenizer;3738import sun.awt.AppContext;39import sun.swing.SwingAccessor;4041/**42* An {@code AWTKeyStroke} represents a key action on the43* keyboard, or equivalent input device. {@code AWTKeyStroke}s44* can correspond to only a press or release of a45* particular key, just as {@code KEY_PRESSED} and46* {@code KEY_RELEASED KeyEvent}s do;47* alternately, they can correspond to typing a specific Java character, just48* as {@code KEY_TYPED KeyEvent}s do.49* In all cases, {@code AWTKeyStroke}s can specify modifiers50* (alt, shift, control, meta, altGraph, or a combination thereof) which must be present51* during the action for an exact match.52* <p>53* {@code AWTKeyStrokes} are immutable, and are intended54* to be unique. Client code should never create an55* {@code AWTKeyStroke} on its own, but should instead use56* a variant of {@code getAWTKeyStroke}. Client use of these factory57* methods allows the {@code AWTKeyStroke} implementation58* to cache and share instances efficiently.59*60* @see #getAWTKeyStroke61*62* @author Arnaud Weber63* @author David Mendenhall64* @since 1.465*/66public class AWTKeyStroke implements Serializable {6768/**69* Use serialVersionUID from JDK 1.4 for interoperability.70*/71@Serial72private static final long serialVersionUID = -6430539691155161871L;7374private static Map<String, Integer> modifierKeywords;75/**76* Associates VK_XXX (as a String) with code (as Integer). This is77* done to avoid the overhead of the reflective call to find the78* constant.79*/80private static VKCollection vks;8182//A key for the collection of AWTKeyStrokes within AppContext.83private static Object APP_CONTEXT_CACHE_KEY = new Object();84//A key withing the cache85private static AWTKeyStroke APP_CONTEXT_KEYSTROKE_KEY = new AWTKeyStroke();8687/**88* The character value for a keyboard key.89*/90private char keyChar = KeyEvent.CHAR_UNDEFINED;9192/**93* The key code for this {@code AWTKeyStroke}.94*/95private int keyCode = KeyEvent.VK_UNDEFINED;9697/**98* The bitwise-ored combination of any modifiers.99*/100private int modifiers;101102/**103* {@code true} if this {@code AWTKeyStroke} corresponds to a key release;104* {@code false} otherwise.105*/106private boolean onKeyRelease;107108static {109/* ensure that the necessary native libraries are loaded */110Toolkit.loadLibraries();111}112113/**114* Constructs an {@code AWTKeyStroke} with default values.115* The default values used are:116*117* <table class="striped">118* <caption>AWTKeyStroke default values</caption>119* <thead>120* <tr>121* <th scope="col">Property122* <th scope="col">Default Value123* </thead>124* <tbody>125* <tr>126* <th scope="row">Key Char127* <td>{@code KeyEvent.CHAR_UNDEFINED}128* <tr>129* <th scope="row">Key Code130* <td>{@code KeyEvent.VK_UNDEFINED}131* <tr>132* <th scope="row">Modifiers133* <td>none134* <tr>135* <th scope="row">On key release?136* <td>{@code false}137* </tbody>138* </table>139*140* {@code AWTKeyStroke}s should not be constructed141* by client code. Use a variant of {@code getAWTKeyStroke}142* instead.143*144* @see #getAWTKeyStroke145*/146protected AWTKeyStroke() {147}148149/**150* Constructs an {@code AWTKeyStroke} with the specified151* values. {@code AWTKeyStroke}s should not be constructed152* by client code. Use a variant of {@code getAWTKeyStroke}153* instead.154*155* @param keyChar the character value for a keyboard key156* @param keyCode the key code for this {@code AWTKeyStroke}157* @param modifiers a bitwise-ored combination of any modifiers158* @param onKeyRelease {@code true} if this159* {@code AWTKeyStroke} corresponds160* to a key release; {@code false} otherwise161* @see #getAWTKeyStroke162*/163protected AWTKeyStroke(char keyChar, int keyCode, int modifiers,164boolean onKeyRelease) {165this.keyChar = keyChar;166this.keyCode = keyCode;167this.modifiers = modifiers;168this.onKeyRelease = onKeyRelease;169}170171/**172* The method has no effect and is only left present to avoid introducing173* a binary incompatibility.174*175* @param subclass the new Class of which the factory methods should create176* instances177* @deprecated178*/179@Deprecated180protected static void registerSubclass(Class<?> subclass) {181}182183private static synchronized AWTKeyStroke getCachedStroke184(char keyChar, int keyCode, int modifiers, boolean onKeyRelease)185{186@SuppressWarnings("unchecked")187Map<AWTKeyStroke, AWTKeyStroke> cache = (Map)AppContext.getAppContext().get(APP_CONTEXT_CACHE_KEY);188AWTKeyStroke cacheKey = (AWTKeyStroke)AppContext.getAppContext().get(APP_CONTEXT_KEYSTROKE_KEY);189190if (cache == null) {191cache = new HashMap<>();192AppContext.getAppContext().put(APP_CONTEXT_CACHE_KEY, cache);193}194195if (cacheKey == null) {196cacheKey = SwingAccessor.getKeyStrokeAccessor().create();197AppContext.getAppContext().put(APP_CONTEXT_KEYSTROKE_KEY, cacheKey);198}199200cacheKey.keyChar = keyChar;201cacheKey.keyCode = keyCode;202cacheKey.modifiers = mapNewModifiers(mapOldModifiers(modifiers));203cacheKey.onKeyRelease = onKeyRelease;204205AWTKeyStroke stroke = cache.get(cacheKey);206if (stroke == null) {207stroke = cacheKey;208cache.put(stroke, stroke);209AppContext.getAppContext().remove(APP_CONTEXT_KEYSTROKE_KEY);210}211return stroke;212}213214/**215* Returns a shared instance of an {@code AWTKeyStroke}216* that represents a {@code KEY_TYPED} event for the217* specified character.218*219* @param keyChar the character value for a keyboard key220* @return an {@code AWTKeyStroke} object for that key221*/222public static AWTKeyStroke getAWTKeyStroke(char keyChar) {223return getCachedStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false);224}225226/**227* Returns a shared instance of an {@code AWTKeyStroke}228* that represents a {@code KEY_TYPED} event for the229* specified Character object and a set of modifiers. Note230* that the first parameter is of type Character rather than231* char. This is to avoid inadvertent clashes with232* calls to {@code getAWTKeyStroke(int keyCode, int modifiers)}.233*234* The modifiers consist of any combination of following:<ul>235* <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK236* <li>java.awt.event.InputEvent.CTRL_DOWN_MASK237* <li>java.awt.event.InputEvent.META_DOWN_MASK238* <li>java.awt.event.InputEvent.ALT_DOWN_MASK239* <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK240* </ul>241* The old modifiers listed below also can be used, but they are242* mapped to _DOWN_ modifiers. <ul>243* <li>java.awt.event.InputEvent.SHIFT_MASK244* <li>java.awt.event.InputEvent.CTRL_MASK245* <li>java.awt.event.InputEvent.META_MASK246* <li>java.awt.event.InputEvent.ALT_MASK247* <li>java.awt.event.InputEvent.ALT_GRAPH_MASK248* </ul>249* also can be used, but they are mapped to _DOWN_ modifiers.250*251* Since these numbers are all different powers of two, any combination of252* them is an integer in which each bit represents a different modifier253* key. Use 0 to specify no modifiers.254*255* @param keyChar the Character object for a keyboard character256* @param modifiers a bitwise-ored combination of any modifiers257* @return an {@code AWTKeyStroke} object for that key258* @throws IllegalArgumentException if {@code keyChar} is259* {@code null}260*261* @see java.awt.event.InputEvent262*/263public static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers)264{265if (keyChar == null) {266throw new IllegalArgumentException("keyChar cannot be null");267}268return getCachedStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED,269modifiers, false);270}271272/**273* Returns a shared instance of an {@code AWTKeyStroke},274* given a numeric key code and a set of modifiers, specifying275* whether the key is activated when it is pressed or released.276* <p>277* The "virtual key" constants defined in278* {@code java.awt.event.KeyEvent} can be279* used to specify the key code. For example:<ul>280* <li>{@code java.awt.event.KeyEvent.VK_ENTER}281* <li>{@code java.awt.event.KeyEvent.VK_TAB}282* <li>{@code java.awt.event.KeyEvent.VK_SPACE}283* </ul>284* Alternatively, the key code may be obtained by calling285* {@code java.awt.event.KeyEvent.getExtendedKeyCodeForChar}.286*287* The modifiers consist of any combination of:<ul>288* <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK289* <li>java.awt.event.InputEvent.CTRL_DOWN_MASK290* <li>java.awt.event.InputEvent.META_DOWN_MASK291* <li>java.awt.event.InputEvent.ALT_DOWN_MASK292* <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK293* </ul>294* The old modifiers <ul>295* <li>java.awt.event.InputEvent.SHIFT_MASK296* <li>java.awt.event.InputEvent.CTRL_MASK297* <li>java.awt.event.InputEvent.META_MASK298* <li>java.awt.event.InputEvent.ALT_MASK299* <li>java.awt.event.InputEvent.ALT_GRAPH_MASK300* </ul>301* also can be used, but they are mapped to _DOWN_ modifiers.302*303* Since these numbers are all different powers of two, any combination of304* them is an integer in which each bit represents a different modifier305* key. Use 0 to specify no modifiers.306*307* @param keyCode an int specifying the numeric code for a keyboard key308* @param modifiers a bitwise-ored combination of any modifiers309* @param onKeyRelease {@code true} if the {@code AWTKeyStroke}310* should represent a key release; {@code false} otherwise311* @return an AWTKeyStroke object for that key312*313* @see java.awt.event.KeyEvent314* @see java.awt.event.InputEvent315*/316public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers,317boolean onKeyRelease) {318return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers,319onKeyRelease);320}321322/**323* Returns a shared instance of an {@code AWTKeyStroke},324* given a numeric key code and a set of modifiers. The returned325* {@code AWTKeyStroke} will correspond to a key press.326* <p>327* The "virtual key" constants defined in328* {@code java.awt.event.KeyEvent} can be329* used to specify the key code. For example:<ul>330* <li>{@code java.awt.event.KeyEvent.VK_ENTER}331* <li>{@code java.awt.event.KeyEvent.VK_TAB}332* <li>{@code java.awt.event.KeyEvent.VK_SPACE}333* </ul>334* The modifiers consist of any combination of:<ul>335* <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK336* <li>java.awt.event.InputEvent.CTRL_DOWN_MASK337* <li>java.awt.event.InputEvent.META_DOWN_MASK338* <li>java.awt.event.InputEvent.ALT_DOWN_MASK339* <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK340* </ul>341* The old modifiers <ul>342* <li>java.awt.event.InputEvent.SHIFT_MASK343* <li>java.awt.event.InputEvent.CTRL_MASK344* <li>java.awt.event.InputEvent.META_MASK345* <li>java.awt.event.InputEvent.ALT_MASK346* <li>java.awt.event.InputEvent.ALT_GRAPH_MASK347* </ul>348* also can be used, but they are mapped to _DOWN_ modifiers.349*350* Since these numbers are all different powers of two, any combination of351* them is an integer in which each bit represents a different modifier352* key. Use 0 to specify no modifiers.353*354* @param keyCode an int specifying the numeric code for a keyboard key355* @param modifiers a bitwise-ored combination of any modifiers356* @return an {@code AWTKeyStroke} object for that key357*358* @see java.awt.event.KeyEvent359* @see java.awt.event.InputEvent360*/361public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) {362return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers,363false);364}365366/**367* Returns an {@code AWTKeyStroke} which represents the368* stroke which generated a given {@code KeyEvent}.369* <p>370* This method obtains the keyChar from a {@code KeyTyped}371* event, and the keyCode from a {@code KeyPressed} or372* {@code KeyReleased} event. The {@code KeyEvent} modifiers are373* obtained for all three types of {@code KeyEvent}.374*375* @param anEvent the {@code KeyEvent} from which to376* obtain the {@code AWTKeyStroke}377* @throws NullPointerException if {@code anEvent} is null378* @return the {@code AWTKeyStroke} that precipitated the event379*/380@SuppressWarnings("deprecation")381public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent) {382int id = anEvent.getID();383switch(id) {384case KeyEvent.KEY_PRESSED:385case KeyEvent.KEY_RELEASED:386return getCachedStroke(KeyEvent.CHAR_UNDEFINED,387anEvent.getKeyCode(),388anEvent.getModifiers(),389(id == KeyEvent.KEY_RELEASED));390case KeyEvent.KEY_TYPED:391return getCachedStroke(anEvent.getKeyChar(),392KeyEvent.VK_UNDEFINED,393anEvent.getModifiers(),394false);395default:396// Invalid ID for this KeyEvent397return null;398}399}400401/**402* Parses a string and returns an {@code AWTKeyStroke}.403* The string must have the following syntax:404* <pre>405* <modifiers>* (<typedID> | <pressedReleasedID>)406*407* modifiers := shift | control | ctrl | meta | alt | altGraph408* typedID := typed <typedKey>409* typedKey := string of length 1 giving Unicode character.410* pressedReleasedID := (pressed | released) key411* key := KeyEvent key code name, i.e. the name following "VK_".412* </pre>413* If typed, pressed or released is not specified, pressed is assumed. Here414* are some examples:415* <pre>416* "INSERT" => getAWTKeyStroke(KeyEvent.VK_INSERT, 0);417* "control DELETE" => getAWTKeyStroke(KeyEvent.VK_DELETE, InputEvent.CTRL_MASK);418* "alt shift X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK);419* "alt shift released X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK, true);420* "typed a" => getAWTKeyStroke('a');421* </pre>422*423* @param s a String formatted as described above424* @return an {@code AWTKeyStroke} object for that String425* @throws IllegalArgumentException if {@code s} is {@code null},426* or is formatted incorrectly427*/428@SuppressWarnings("deprecation")429public static AWTKeyStroke getAWTKeyStroke(String s) {430if (s == null) {431throw new IllegalArgumentException("String cannot be null");432}433434final String errmsg = "String formatted incorrectly";435436StringTokenizer st = new StringTokenizer(s, " ");437438int mask = 0;439boolean released = false;440boolean typed = false;441boolean pressed = false;442443synchronized (AWTKeyStroke.class) {444if (modifierKeywords == null) {445Map<String, Integer> uninitializedMap = new HashMap<>(8, 1.0f);446uninitializedMap.put("shift",447Integer.valueOf(InputEvent.SHIFT_DOWN_MASK448|InputEvent.SHIFT_MASK));449uninitializedMap.put("control",450Integer.valueOf(InputEvent.CTRL_DOWN_MASK451|InputEvent.CTRL_MASK));452uninitializedMap.put("ctrl",453Integer.valueOf(InputEvent.CTRL_DOWN_MASK454|InputEvent.CTRL_MASK));455uninitializedMap.put("meta",456Integer.valueOf(InputEvent.META_DOWN_MASK457|InputEvent.META_MASK));458uninitializedMap.put("alt",459Integer.valueOf(InputEvent.ALT_DOWN_MASK460|InputEvent.ALT_MASK));461uninitializedMap.put("altGraph",462Integer.valueOf(InputEvent.ALT_GRAPH_DOWN_MASK463|InputEvent.ALT_GRAPH_MASK));464uninitializedMap.put("button1",465Integer.valueOf(InputEvent.BUTTON1_DOWN_MASK));466uninitializedMap.put("button2",467Integer.valueOf(InputEvent.BUTTON2_DOWN_MASK));468uninitializedMap.put("button3",469Integer.valueOf(InputEvent.BUTTON3_DOWN_MASK));470modifierKeywords =471Collections.synchronizedMap(uninitializedMap);472}473}474475int count = st.countTokens();476477for (int i = 1; i <= count; i++) {478String token = st.nextToken();479480if (typed) {481if (token.length() != 1 || i != count) {482throw new IllegalArgumentException(errmsg);483}484return getCachedStroke(token.charAt(0), KeyEvent.VK_UNDEFINED,485mask, false);486}487488if (pressed || released || i == count) {489if (i != count) {490throw new IllegalArgumentException(errmsg);491}492493String keyCodeName = "VK_" + token;494int keyCode = getVKValue(keyCodeName);495496return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode,497mask, released);498}499500if (token.equals("released")) {501released = true;502continue;503}504if (token.equals("pressed")) {505pressed = true;506continue;507}508if (token.equals("typed")) {509typed = true;510continue;511}512513Integer tokenMask = modifierKeywords.get(token);514if (tokenMask != null) {515mask |= tokenMask.intValue();516} else {517throw new IllegalArgumentException(errmsg);518}519}520521throw new IllegalArgumentException(errmsg);522}523524private static VKCollection getVKCollection() {525if (vks == null) {526vks = new VKCollection();527}528return vks;529}530/**531* Returns the integer constant for the KeyEvent.VK field named532* {@code key}. This will throw an533* {@code IllegalArgumentException} if {@code key} is534* not a valid constant.535*/536private static int getVKValue(String key) {537VKCollection vkCollect = getVKCollection();538539Integer value = vkCollect.findCode(key);540541if (value == null) {542int keyCode = 0;543final String errmsg = "String formatted incorrectly";544545try {546keyCode = KeyEvent.class.getField(key).getInt(KeyEvent.class);547} catch (NoSuchFieldException nsfe) {548throw new IllegalArgumentException(errmsg);549} catch (IllegalAccessException iae) {550throw new IllegalArgumentException(errmsg);551}552value = Integer.valueOf(keyCode);553vkCollect.put(key, value);554}555return value.intValue();556}557558/**559* Returns the character for this {@code AWTKeyStroke}.560*561* @return a char value562* @see #getAWTKeyStroke(char)563* @see KeyEvent#getKeyChar564*/565public final char getKeyChar() {566return keyChar;567}568569/**570* Returns the numeric key code for this {@code AWTKeyStroke}.571*572* @return an int containing the key code value573* @see #getAWTKeyStroke(int,int)574* @see KeyEvent#getKeyCode575*/576public final int getKeyCode() {577return keyCode;578}579580/**581* Returns the modifier keys for this {@code AWTKeyStroke}.582*583* @return an int containing the modifiers584* @see #getAWTKeyStroke(int,int)585*/586public final int getModifiers() {587return modifiers;588}589590/**591* Returns whether this {@code AWTKeyStroke} represents a key release.592*593* @return {@code true} if this {@code AWTKeyStroke}594* represents a key release; {@code false} otherwise595* @see #getAWTKeyStroke(int,int,boolean)596*/597public final boolean isOnKeyRelease() {598return onKeyRelease;599}600601/**602* Returns the type of {@code KeyEvent} which corresponds to603* this {@code AWTKeyStroke}.604*605* @return {@code KeyEvent.KEY_PRESSED},606* {@code KeyEvent.KEY_TYPED},607* or {@code KeyEvent.KEY_RELEASED}608* @see java.awt.event.KeyEvent609*/610public final int getKeyEventType() {611if (keyCode == KeyEvent.VK_UNDEFINED) {612return KeyEvent.KEY_TYPED;613} else {614return (onKeyRelease)615? KeyEvent.KEY_RELEASED616: KeyEvent.KEY_PRESSED;617}618}619620/**621* Returns a numeric value for this object that is likely to be unique,622* making it a good choice as the index value in a hash table.623*624* @return an int that represents this object625*/626public int hashCode() {627return (((int)keyChar) + 1) * (2 * (keyCode + 1)) * (modifiers + 1) +628(onKeyRelease ? 1 : 2);629}630631/**632* Returns true if this object is identical to the specified object.633*634* @param anObject the Object to compare this object to635* @return true if the objects are identical636*/637public final boolean equals(Object anObject) {638if (anObject instanceof AWTKeyStroke) {639AWTKeyStroke ks = (AWTKeyStroke)anObject;640return (ks.keyChar == keyChar && ks.keyCode == keyCode &&641ks.onKeyRelease == onKeyRelease &&642ks.modifiers == modifiers);643}644return false;645}646647/**648* Returns a string that displays and identifies this object's properties.649* The {@code String} returned by this method can be passed650* as a parameter to {@code getAWTKeyStroke(String)} to produce651* a key stroke equal to this key stroke.652*653* @return a String representation of this object654* @see #getAWTKeyStroke(String)655*/656public String toString() {657if (keyCode == KeyEvent.VK_UNDEFINED) {658return getModifiersText(modifiers) + "typed " + keyChar;659} else {660return getModifiersText(modifiers) +661(onKeyRelease ? "released" : "pressed") + " " +662getVKText(keyCode);663}664}665666static String getModifiersText(int modifiers) {667StringBuilder buf = new StringBuilder();668669if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0 ) {670buf.append("shift ");671}672if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0 ) {673buf.append("ctrl ");674}675if ((modifiers & InputEvent.META_DOWN_MASK) != 0 ) {676buf.append("meta ");677}678if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0 ) {679buf.append("alt ");680}681if ((modifiers & InputEvent.ALT_GRAPH_DOWN_MASK) != 0 ) {682buf.append("altGraph ");683}684if ((modifiers & InputEvent.BUTTON1_DOWN_MASK) != 0 ) {685buf.append("button1 ");686}687if ((modifiers & InputEvent.BUTTON2_DOWN_MASK) != 0 ) {688buf.append("button2 ");689}690if ((modifiers & InputEvent.BUTTON3_DOWN_MASK) != 0 ) {691buf.append("button3 ");692}693694return buf.toString();695}696697static String getVKText(int keyCode) {698VKCollection vkCollect = getVKCollection();699Integer key = Integer.valueOf(keyCode);700String name = vkCollect.findName(key);701if (name != null) {702return name.substring(3);703}704int expected_modifiers =705(Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL);706707Field[] fields = KeyEvent.class.getDeclaredFields();708for (int i = 0; i < fields.length; i++) {709try {710if (fields[i].getModifiers() == expected_modifiers711&& fields[i].getType() == Integer.TYPE712&& fields[i].getName().startsWith("VK_")713&& fields[i].getInt(KeyEvent.class) == keyCode)714{715name = fields[i].getName();716vkCollect.put(name, key);717return name.substring(3);718}719} catch (IllegalAccessException e) {720assert(false);721}722}723return "UNKNOWN";724}725726/**727* Returns a cached instance of {@code AWTKeyStroke} (or a subclass of728* {@code AWTKeyStroke}) which is equal to this instance.729*730* @return a cached instance which is equal to this instance731* @throws java.io.ObjectStreamException if a serialization problem occurs732*/733@Serial734protected Object readResolve() throws java.io.ObjectStreamException {735synchronized (AWTKeyStroke.class) {736737return getCachedStroke(keyChar, keyCode, modifiers, onKeyRelease);738}739}740741@SuppressWarnings("deprecation")742private static int mapOldModifiers(int modifiers) {743if ((modifiers & InputEvent.SHIFT_MASK) != 0) {744modifiers |= InputEvent.SHIFT_DOWN_MASK;745}746if ((modifiers & InputEvent.ALT_MASK) != 0) {747modifiers |= InputEvent.ALT_DOWN_MASK;748}749if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) {750modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;751}752if ((modifiers & InputEvent.CTRL_MASK) != 0) {753modifiers |= InputEvent.CTRL_DOWN_MASK;754}755if ((modifiers & InputEvent.META_MASK) != 0) {756modifiers |= InputEvent.META_DOWN_MASK;757}758759modifiers &= InputEvent.SHIFT_DOWN_MASK760| InputEvent.ALT_DOWN_MASK761| InputEvent.ALT_GRAPH_DOWN_MASK762| InputEvent.CTRL_DOWN_MASK763| InputEvent.META_DOWN_MASK764| InputEvent.BUTTON1_DOWN_MASK765| InputEvent.BUTTON2_DOWN_MASK766| InputEvent.BUTTON3_DOWN_MASK;767768return modifiers;769}770771@SuppressWarnings("deprecation")772private static int mapNewModifiers(int modifiers) {773if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0) {774modifiers |= InputEvent.SHIFT_MASK;775}776if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0) {777modifiers |= InputEvent.ALT_MASK;778}779if ((modifiers & InputEvent.ALT_GRAPH_DOWN_MASK) != 0) {780modifiers |= InputEvent.ALT_GRAPH_MASK;781}782if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0) {783modifiers |= InputEvent.CTRL_MASK;784}785if ((modifiers & InputEvent.META_DOWN_MASK) != 0) {786modifiers |= InputEvent.META_MASK;787}788789return modifiers;790}791792}793794class VKCollection {795Map<Integer, String> code2name;796Map<String, Integer> name2code;797798public VKCollection() {799code2name = new HashMap<>();800name2code = new HashMap<>();801}802803public synchronized void put(String name, Integer code) {804assert((name != null) && (code != null));805assert(findName(code) == null);806assert(findCode(name) == null);807code2name.put(code, name);808name2code.put(name, code);809}810811public synchronized Integer findCode(String name) {812assert(name != null);813return name2code.get(name);814}815816public synchronized String findName(Integer code) {817assert(code != null);818return code2name.get(code);819}820}821822823