/*
* Copyright (c) 2011, 2014, 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 javafx.scene.input;
import com.sun.javafx.tk.Toolkit;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
// PENDING_DOC_REVIEW
Represents a combination of keys which are used in keyboard shortcuts. A key combination consists of a main key and a set of modifier keys. The main key can be specified by its key code - KeyCodeCombination
or key character - KeyCharacterCombination
. A modifier key is shift
, control
, alt
, meta
or shortcut
and can be defined as DOWN
, UP
or ANY
. The shortcut
modifier is used to represent the modifier key which is used commonly in keyboard shortcuts on the host platform. This is for example control
on Windows and meta
(command key) on Mac. By using shortcut
key modifier developers can create platform independent shortcuts. So the "Shortcut+C" key combination is handled internally as "Ctrl+C" on Windows and "Meta+C" on Mac.
Since: JavaFX 2.0
/**
* Represents a combination of keys which are used in keyboard shortcuts.
* A key combination consists of a main key and a set of modifier keys. The main
* key can be specified by its key code - {@code KeyCodeCombination} or key
* character - {@code KeyCharacterCombination}. A modifier key is {@code shift},
* {@code control}, {@code alt}, {@code meta} or {@code shortcut} and can be
* defined as {@code DOWN}, {@code UP} or {@code ANY}.
* <p>
* The {@code shortcut} modifier is used to represent the modifier key which is
* used commonly in keyboard shortcuts on the host platform. This is for
* example {@code control} on Windows and {@code meta} (command key) on Mac.
* By using {@code shortcut} key modifier developers can create platform
* independent shortcuts. So the "Shortcut+C" key combination is handled
* internally as "Ctrl+C" on Windows and "Meta+C" on Mac.
* @since JavaFX 2.0
*/
public abstract class KeyCombination {
Modifier which specifies that the shift
key must be down. /** Modifier which specifies that the {@code shift} key must be down. */
public static final Modifier SHIFT_DOWN =
new Modifier(KeyCode.SHIFT, ModifierValue.DOWN);
Modifier which specifies that the shift
key can be either up or down. /**
* Modifier which specifies that the {@code shift} key can be either up or
* down.
*/
public static final Modifier SHIFT_ANY =
new Modifier(KeyCode.SHIFT, ModifierValue.ANY);
Modifier which specifies that the control
key must be down. /** Modifier which specifies that the {@code control} key must be down. */
public static final Modifier CONTROL_DOWN =
new Modifier(KeyCode.CONTROL, ModifierValue.DOWN);
Modifier which specifies that the control
key can be either up or down. /**
* Modifier which specifies that the {@code control} key can be either up or
* down.
*/
public static final Modifier CONTROL_ANY =
new Modifier(KeyCode.CONTROL, ModifierValue.ANY);
Modifier which specifies that the alt
key must be down. /** Modifier which specifies that the {@code alt} key must be down. */
public static final Modifier ALT_DOWN =
new Modifier(KeyCode.ALT, ModifierValue.DOWN);
Modifier which specifies that the alt
key can be either up or down. /**
* Modifier which specifies that the {@code alt} key can be either up or
* down.
*/
public static final Modifier ALT_ANY =
new Modifier(KeyCode.ALT, ModifierValue.ANY);
Modifier which specifies that the meta
key must be down. /** Modifier which specifies that the {@code meta} key must be down. */
public static final Modifier META_DOWN =
new Modifier(KeyCode.META, ModifierValue.DOWN);
Modifier which specifies that the meta
key can be either up or down. /**
* Modifier which specifies that the {@code meta} key can be either up or
* down.
*/
public static final Modifier META_ANY =
new Modifier(KeyCode.META, ModifierValue.ANY);
Modifier which specifies that the shortcut
key must be down. /** Modifier which specifies that the {@code shortcut} key must be down. */
public static final Modifier SHORTCUT_DOWN =
new Modifier(KeyCode.SHORTCUT, ModifierValue.DOWN);
Modifier which specifies that the shortcut
key can be either up or down. /**
* Modifier which specifies that the {@code shortcut} key can be either up
* or down.
*/
public static final Modifier SHORTCUT_ANY =
new Modifier(KeyCode.SHORTCUT, ModifierValue.ANY);
private static final Modifier[] POSSIBLE_MODIFIERS = {
SHIFT_DOWN, SHIFT_ANY,
CONTROL_DOWN, CONTROL_ANY,
ALT_DOWN, ALT_ANY,
META_DOWN, META_ANY,
SHORTCUT_DOWN, SHORTCUT_ANY
};
A KeyCombination that will match with no events.
/**
* A KeyCombination that will match with no events.
*/
public static final KeyCombination NO_MATCH = new KeyCombination() {
@Override
public boolean match(KeyEvent e) {
return false;
}
};
The state of the shift
key in this key combination. /** The state of the {@code shift} key in this key combination. */
private final ModifierValue shift;
The state of the shift
key in this key combination. Returns: The state of the shift
key in this key combination
/**
* The state of the {@code shift} key in this key combination.
* @return The state of the {@code shift} key in this key combination
*/
public final ModifierValue getShift() {
return shift;
}
The state of the control
key in this key combination. /** The state of the {@code control} key in this key combination. */
private final ModifierValue control;
The state of the control
key in this key combination. Returns: The state of the control
key in this key combination
/**
* The state of the {@code control} key in this key combination.
* @return The state of the {@code control} key in this key combination
*/
public final ModifierValue getControl() {
return control;
}
The state of the alt
key in this key combination. /** The state of the {@code alt} key in this key combination. */
private final ModifierValue alt;
The state of the alt
key in this key combination. Returns: The state of the alt
key in this key combination.
/**
* The state of the {@code alt} key in this key combination.
* @return The state of the {@code alt} key in this key combination.
*/
public final ModifierValue getAlt() {
return alt;
}
The state of the meta
key in this key combination. /** The state of the {@code meta} key in this key combination. */
private final ModifierValue meta;
The state of the meta
key in this key combination. Returns: The state of the meta
key in this key combination
/**
* The state of the {@code meta} key in this key combination.
* @return The state of the {@code meta} key in this key combination
*/
public final ModifierValue getMeta() {
return meta;
}
The state of the shortcut
key in this key combination. /** The state of the {@code shortcut} key in this key combination. */
private final ModifierValue shortcut;
The state of the shortcut
key in this key combination. Returns: The state of the shortcut
key in this key combination
/**
* The state of the {@code shortcut} key in this key combination.
* @return The state of the {@code shortcut} key in this key combination
*/
public final ModifierValue getShortcut() {
return shortcut;
}
Constructs a KeyCombination
with an explicit specification of all modifier keys. Each modifier key can be set to DOWN
, UP
or ANY
. Params: - shift – the value of the
shift
modifier key - control – the value of the
control
modifier key - alt – the value of the
alt
modifier key - meta – the value of the
meta
modifier key - shortcut – the value of the
shortcut
modifier key
/**
* Constructs a {@code KeyCombination} with an explicit specification
* of all modifier keys. Each modifier key can be set to {@code DOWN},
* {@code UP} or {@code ANY}.
*
* @param shift the value of the {@code shift} modifier key
* @param control the value of the {@code control} modifier key
* @param alt the value of the {@code alt} modifier key
* @param meta the value of the {@code meta} modifier key
* @param shortcut the value of the {@code shortcut} modifier key
*/
protected KeyCombination(final ModifierValue shift,
final ModifierValue control,
final ModifierValue alt,
final ModifierValue meta,
final ModifierValue shortcut) {
if ((shift == null)
|| (control == null)
|| (alt == null)
|| (meta == null)
|| (shortcut == null)) {
throw new NullPointerException("Modifier value must not be null!");
}
this.shift = shift;
this.control = control;
this.alt = alt;
this.meta = meta;
this.shortcut = shortcut;
}
Constructs a KeyCombination
with the specified list of modifiers. All modifier keys which are not explicitly listed are set to the default UP
value. All possible modifiers which change the default modifier value are defined as constants in the KeyCombination
class.
Params: - modifiers – the list of modifier keys and their corresponding values
/**
* Constructs a {@code KeyCombination} with the specified list of modifiers.
* All modifier keys which are not explicitly listed are set to the
* default {@code UP} value.
* <p>
* All possible modifiers which change the default modifier value are
* defined as constants in the {@code KeyCombination} class.
*
* @param modifiers the list of modifier keys and their corresponding values
*/
protected KeyCombination(final Modifier... modifiers) {
this(getModifierValue(modifiers, KeyCode.SHIFT),
getModifierValue(modifiers, KeyCode.CONTROL),
getModifierValue(modifiers, KeyCode.ALT),
getModifierValue(modifiers, KeyCode.META),
getModifierValue(modifiers, KeyCode.SHORTCUT));
}
Tests whether this key combination matches the combination in the given KeyEvent
. The implementation of this method in the KeyCombination
class does only a partial test with the modifier keys. This method is overridden in subclasses to include the main key in the test.
Params: - event – the key event
Returns: true
if the key combinations match, false
otherwise
/**
* Tests whether this key combination matches the combination in the given
* {@code KeyEvent}.
* <p>
* The implementation of this method in the {@code KeyCombination} class
* does only a partial test with the modifier keys. This method is
* overridden in subclasses to include the main key in the test.
*
* @param event the key event
* @return {@code true} if the key combinations match, {@code false}
* otherwise
*/
public boolean match(final KeyEvent event) {
final KeyCode shortcutKey =
Toolkit.getToolkit().getPlatformShortcutKey();
return test(KeyCode.SHIFT, shift, shortcutKey, shortcut,
event.isShiftDown())
&& test(KeyCode.CONTROL, control, shortcutKey, shortcut,
event.isControlDown())
&& test(KeyCode.ALT, alt, shortcutKey, shortcut,
event.isAltDown())
&& test(KeyCode.META, meta, shortcutKey, shortcut,
event.isMetaDown());
}
Returns a string representation of this KeyCombination
.
The string representation consists of sections separated by plus
characters. Each section specifies either a modifier key or the main key.
A modifier key section contains the KeyCode
name of a modifier key. It can be prefixed with the Ignored
keyword. A non-prefixed modifier key implies its DOWN
value while the prefixed version implies the ANY
(ignored) value. If some modifier key is not specified in the string at all, it means it has the default UP
value.
The format of the main key section of the key combination string depends on the KeyCombination
subclass. It is either the key code name for KeyCodeCombination
or the single quoted key character for KeyCharacterCombination
.
Examples of KeyCombination
string representations:
"Ctrl+Alt+Q"
"Ignore Shift+Ctrl+A"
"Alt+'w'"
Returns: the string representation of this KeyCombination
/**
* Returns a string representation of this {@code KeyCombination}.
* <p>
* The string representation consists of sections separated by plus
* characters. Each section specifies either a modifier key or the main key.
* <p>
* A modifier key section contains the {@code KeyCode} name of a modifier
* key. It can be prefixed with the {@code Ignored} keyword. A non-prefixed
* modifier key implies its {@code DOWN} value while the prefixed version
* implies the {@code ANY} (ignored) value. If some modifier key is not
* specified in the string at all, it means it has the default {@code UP}
* value.
* <p>
* The format of the main key section of the key combination string depends
* on the {@code KeyCombination} subclass. It is either the key code name
* for {@code KeyCodeCombination} or the single quoted key character for
* {@code KeyCharacterCombination}.
* <p>
* Examples of {@code KeyCombination} string representations:
<PRE>
"Ctrl+Alt+Q"
"Ignore Shift+Ctrl+A"
"Alt+'w'"
</PRE>
* @return the string representation of this {@code KeyCombination}
*/
public String getName() {
StringBuilder sb = new StringBuilder();
addModifiersIntoString(sb);
return sb.toString();
}
Returns a string representation of this KeyCombination
that is suitable for display in a user interface (for example, beside a menu item). Returns: A string representation of this KeyCombination
, suitable for display in a user interface. Since: JavaFX 8u20
/**
* Returns a string representation of this {@code KeyCombination} that is
* suitable for display in a user interface (for example, beside a menu item).
*
* @return A string representation of this {@code KeyCombination}, suitable
* for display in a user interface.
* @since JavaFX 8u20
*/
public String getDisplayText() {
StringBuilder stringBuilder = new StringBuilder();
if (com.sun.javafx.PlatformUtil.isMac()) {
// Macs have a different convention for keyboard accelerators -
// no pluses to separate modifiers, and special symbols for
// each modifier (in a particular order), etc
if (getControl() == KeyCombination.ModifierValue.DOWN) {
stringBuilder.append("\u2303");
}
if (getAlt() == KeyCombination.ModifierValue.DOWN) {
stringBuilder.append("\u2325");
}
if (getShift() == KeyCombination.ModifierValue.DOWN) {
stringBuilder.append("\u21e7");
}
if (getMeta() == KeyCombination.ModifierValue.DOWN || getShortcut() == KeyCombination.ModifierValue.DOWN) {
stringBuilder.append("\u2318");
}
// TODO refer to RT-14486 for remaining glyphs
}
else {
if (getControl() == KeyCombination.ModifierValue.DOWN || getShortcut() == KeyCombination.ModifierValue.DOWN ) {
stringBuilder.append("Ctrl+");
}
if (getAlt() == KeyCombination.ModifierValue.DOWN) {
stringBuilder.append("Alt+");
}
if (getShift() == KeyCombination.ModifierValue.DOWN) {
stringBuilder.append("Shift+");
}
if (getMeta() == KeyCombination.ModifierValue.DOWN) {
stringBuilder.append("Meta+");
}
}
return stringBuilder.toString();
}
Tests whether this KeyCombination
equals to the specified object. Params: - obj – the object to compare to
Returns: true
if the objects are equal, false
otherwise
/**
* Tests whether this {@code KeyCombination} equals to the specified object.
*
* @param obj the object to compare to
* @return {@code true} if the objects are equal, {@code false} otherwise
*/
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof KeyCombination)) {
return false;
}
final KeyCombination other = (KeyCombination) obj;
return (shift == other.shift)
&& (control == other.control)
&& (alt == other.alt)
&& (meta == other.meta)
&& (shortcut == other.shortcut);
}
Returns a hash code value for this KeyCombination
. Returns: the hash code value
/**
* Returns a hash code value for this {@code KeyCombination}.
*
* @return the hash code value
*/
@Override
public int hashCode() {
int hash = 7;
hash = 23 * hash + shift.hashCode();
hash = 23 * hash + control.hashCode();
hash = 23 * hash + alt.hashCode();
hash = 23 * hash + meta.hashCode();
hash = 23 * hash + shortcut.hashCode();
return hash;
}
Returns a string representation of this object. Implementation returns the result of the getName()
call. Returns: the string representation of this KeyCombination
/**
* Returns a string representation of this object. Implementation returns
* the result of the {@code getName()} call.
*
* @return the string representation of this {@code KeyCombination}
*/
@Override
public String toString() {
return getName();
}
Constructs a new KeyCombination
from the specified string. The string should be in the same format as produced by the getName
method. If the main key section string is quoted in single quotes the method creates a new KeyCharacterCombination
for the unquoted substring. Otherwise it finds the key code which name corresponds to the main key section string and creates a KeyCodeCombination
for it. If this can't be done, it falls back to the KeyCharacterCombination
.
Params: - value – the string which represents the requested key combination
Returns: the constructed KeyCombination
Since: JavaFX 2.1
/**
* Constructs a new {@code KeyCombination} from the specified string. The
* string should be in the same format as produced by the {@code getName}
* method.
* <p>
* If the main key section string is quoted in single quotes the method
* creates a new {@code KeyCharacterCombination} for the unquoted substring.
* Otherwise it finds the key code which name corresponds to the main key
* section string and creates a {@code KeyCodeCombination} for it. If this
* can't be done, it falls back to the {@code KeyCharacterCombination}.
*
* @param value the string which represents the requested key combination
* @return the constructed {@code KeyCombination}
* @since JavaFX 2.1
*/
public static KeyCombination valueOf(String value) {
final List<Modifier> modifiers = new ArrayList<Modifier>(4);
final String[] tokens = splitName(value);
KeyCode keyCode = null;
String keyCharacter = null;
for (String token : tokens) {
if ((token.length() > 2)
&& (token.charAt(0) == '\'')
&& (token.charAt(token.length() - 1) == '\'')) {
if ((keyCode != null) || (keyCharacter != null)) {
throw new IllegalArgumentException(
"Cannot parse key binding " + value);
}
keyCharacter = token.substring(1, token.length() - 1)
.replace("\\'", "'");
continue;
}
final String normalizedToken = normalizeToken(token);
final Modifier modifier = getModifier(normalizedToken);
if (modifier != null) {
modifiers.add(modifier);
continue;
}
if ((keyCode != null) || (keyCharacter != null)) {
throw new IllegalArgumentException(
"Cannot parse key binding " + value);
}
keyCode = KeyCode.getKeyCode(normalizedToken);
if (keyCode == null) {
keyCharacter = token;
}
}
if ((keyCode == null) && (keyCharacter == null)) {
throw new IllegalArgumentException(
"Cannot parse key binding " + value);
}
final Modifier[] modifierArray =
modifiers.toArray(new Modifier[modifiers.size()]);
return (keyCode != null)
? new KeyCodeCombination(keyCode, modifierArray)
: new KeyCharacterCombination(keyCharacter, modifierArray);
}
Constructs a new KeyCombination
from the specified string. This method simply delegates to valueOf(String)
. Params: - name – the string which represents the requested key combination
See Also: Returns: the constructed KeyCombination
/**
* Constructs a new {@code KeyCombination} from the specified string. This
* method simply delegates to {@link #valueOf(String)}.
*
* @param name the string which represents the requested key combination
* @return the constructed {@code KeyCombination}
*
* @see #valueOf(String)
*/
public static KeyCombination keyCombination(String name) {
return valueOf(name);
}
This class represents a pair of modifier key and its value.
Since: JavaFX 2.0
/**
* This class represents a pair of modifier key and its value.
* @since JavaFX 2.0
*/
public static final class Modifier {
private final KeyCode key;
private final ModifierValue value;
private Modifier(final KeyCode key,
final ModifierValue value) {
this.key = key;
this.value = value;
}
Gets the modifier key of this Modifier
. Returns: the modifier key
/**
* Gets the modifier key of this {@code Modifier}.
*
* @return the modifier key
*/
public KeyCode getKey() {
return key;
}
Gets the modifier value of this Modifier
. Returns: the modifier value
/**
* Gets the modifier value of this {@code Modifier}.
*
* @return the modifier value
*/
public ModifierValue getValue() {
return value;
}
Returns a string representation of the modifier.
Returns: a string representation of the modifier
/**
* Returns a string representation of the modifier.
* @return a string representation of the modifier
*/
@Override
public String toString() {
return ((value == ModifierValue.ANY) ? "Ignore " : "")
+ key.getName();
}
}
ModifierValue
specifies state of modifier keys. Since: JavaFX 2.0
/**
* {@code ModifierValue} specifies state of modifier keys.
* @since JavaFX 2.0
*/
public static enum ModifierValue {
Constant which indicates that the modifier key must be down. /** Constant which indicates that the modifier key must be down. */
DOWN,
Constant which indicates that the modifier key must be up. /** Constant which indicates that the modifier key must be up. */
UP,
Constant which indicates that the modifier key can be either up or
down.
/**
* Constant which indicates that the modifier key can be either up or
* down.
*/
ANY
}
private void addModifiersIntoString(final StringBuilder sb) {
addModifierIntoString(sb, KeyCode.SHIFT, shift);
addModifierIntoString(sb, KeyCode.CONTROL, control);
addModifierIntoString(sb, KeyCode.ALT, alt);
addModifierIntoString(sb, KeyCode.META, meta);
addModifierIntoString(sb, KeyCode.SHORTCUT, shortcut);
}
private static void addModifierIntoString(
final StringBuilder sb,
final KeyCode modifierKey,
final ModifierValue modifierValue) {
if (modifierValue == ModifierValue.UP) {
return;
}
if (sb.length() > 0) {
sb.append("+");
}
if (modifierValue == ModifierValue.ANY) {
sb.append("Ignore ");
}
sb.append(modifierKey.getName());
}
private static boolean test(final KeyCode testedModifierKey,
final ModifierValue testedModifierValue,
final KeyCode shortcutModifierKey,
final ModifierValue shortcutModifierValue,
final boolean isKeyDown) {
final ModifierValue finalModifierValue =
(testedModifierKey == shortcutModifierKey)
? resolveModifierValue(testedModifierValue,
shortcutModifierValue)
: testedModifierValue;
return test(finalModifierValue, isKeyDown);
}
private static boolean test(final ModifierValue modifierValue,
final boolean isDown) {
switch (modifierValue) {
case DOWN:
return isDown;
case UP:
return !isDown;
case ANY:
default:
return true;
}
}
private static ModifierValue resolveModifierValue(
final ModifierValue firstValue,
final ModifierValue secondValue) {
if ((firstValue == ModifierValue.DOWN)
|| (secondValue == ModifierValue.DOWN)) {
return ModifierValue.DOWN;
}
if ((firstValue == ModifierValue.ANY)
|| (secondValue == ModifierValue.ANY)) {
return ModifierValue.ANY;
}
return ModifierValue.UP;
}
static Modifier getModifier(final String name) {
for (final Modifier modifier: POSSIBLE_MODIFIERS) {
if (modifier.toString().equals(name)) {
return modifier;
}
}
return null;
}
private static ModifierValue getModifierValue(
final Modifier[] modifiers,
final KeyCode modifierKey) {
ModifierValue modifierValue = ModifierValue.UP;
for (final Modifier modifier: modifiers) {
if (modifier == null) {
throw new NullPointerException("Modifier must not be null!");
}
if (modifier.getKey() == modifierKey) {
if (modifierValue != ModifierValue.UP) {
throw new IllegalArgumentException(
(modifier.getValue() != modifierValue)
? "Conflicting modifiers specified!"
: "Duplicate modifiers specified!");
}
modifierValue = modifier.getValue();
}
}
return modifierValue;
}
private static String normalizeToken(final String token) {
final String[] words = token.split("\\s+");
final StringBuilder sb = new StringBuilder();
for (final String word: words) {
if (sb.length() > 0) {
sb.append(' ');
}
sb.append(word.substring(0, 1).toUpperCase(Locale.ROOT));
sb.append(word.substring(1).toLowerCase(Locale.ROOT));
}
return sb.toString();
}
private static String[] splitName(String name) {
List<String> tokens = new ArrayList<String>();
char[] chars = name.trim().toCharArray();
final int STATE_BASIC = 0; // general text
final int STATE_WHITESPACE = 1; // spaces found
final int STATE_SEPARATOR = 2; // plus found
final int STATE_QUOTED = 3; // quoted text
int state = STATE_BASIC;
int tokenStart = 0;
int tokenEnd = -1;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
switch(state) {
case STATE_BASIC:
switch(c) {
case ' ':
case '\t':
case '\n':
case '\f':
case '\r':
case '\u000B':
tokenEnd = i;
state = STATE_WHITESPACE;
break;
case '+':
tokenEnd = i;
state = STATE_SEPARATOR;
break;
case '\'':
if (i == 0 || chars[i - 1] != '\\') {
state = STATE_QUOTED;
}
break;
default:
break;
}
break;
case STATE_WHITESPACE:
switch(c) {
case ' ':
case '\t':
case '\n':
case '\f':
case '\r':
case '\u000B':
break;
case '+':
state = STATE_SEPARATOR;
break;
case '\'':
state = STATE_QUOTED;
tokenEnd = -1;
break;
default:
state = STATE_BASIC;
tokenEnd = -1;
break;
}
break;
case STATE_SEPARATOR:
switch(c) {
case ' ':
case '\t':
case '\n':
case '\f':
case '\r':
case '\u000B':
break;
case '+':
throw new IllegalArgumentException(
"Cannot parse key binding " + name);
default:
if (tokenEnd <= tokenStart) {
throw new IllegalArgumentException(
"Cannot parse key binding " + name);
}
tokens.add(new String(chars,
tokenStart, tokenEnd - tokenStart));
tokenStart = i;
tokenEnd = -1;
state = (c == '\'' ? STATE_QUOTED : STATE_BASIC);
break;
}
break;
case STATE_QUOTED:
if (c == '\'' && chars[i - 1] != '\\') {
state = STATE_BASIC;
}
break;
}
}
switch(state) {
case STATE_BASIC:
case STATE_WHITESPACE:
tokens.add(new String(chars,
tokenStart, chars.length - tokenStart));
break;
case STATE_SEPARATOR:
case STATE_QUOTED:
throw new IllegalArgumentException(
"Cannot parse key binding " + name);
}
return tokens.toArray(new String[tokens.size()]);
}
}