/*
* Freeplane - mind map editor
* Copyright (C) 2001, 2002 Slava Pestov
* Copyright (C) 2009 Dimitry Polivaev
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.freeplane.core.resources.components;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Map;
/**
* In conjunction with the <code>KeyEventWorkaround</code>, hides some warts in
* the AWT key event API.
*
*/
class KeyEventTranslator {
static class Key {
final public char input;
final public int key;
final public String modifiers;
public Key(final String modifiers, final int key, final char input) {
this.modifiers = modifiers;
this.key = key;
this.input = input;
}
@Override
public boolean equals(final Object o) {
if (o instanceof Key) {
final Key k = (Key) o;
if ((modifiers.equals(k.modifiers)) && key == k.key && input == k.input) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return key + input;
}
@Override
public String toString() {
return (modifiers == null ? "" : modifiers) + "<" + Integer.toString(key, 16) + ","
+ Integer.toString(input, 16) + ">";
}
}
static int c, a, m, s;
private static Map<Key, Key> transMap = new HashMap<Key, Key>();
static {
KeyEventTranslator.setModifierMapping(InputEvent.CTRL_MASK, InputEvent.ALT_MASK, InputEvent.META_MASK,
InputEvent.SHIFT_MASK);
}
/**
* Returns a string containing symbolic modifier names set in the specified
* event.
*
* @param evt
* The event
* @since jEdit 4.2pre3
*/
public static String getModifierString(final InputEvent evt) {
final StringBuilder buf = new StringBuilder();
if (evt.isControlDown()) {
buf.append(KeyEventTranslator.getSymbolicModifierName(InputEvent.CTRL_MASK));
}
if (evt.isAltDown()) {
buf.append(KeyEventTranslator.getSymbolicModifierName(InputEvent.ALT_MASK));
}
if (evt.isMetaDown()) {
buf.append(KeyEventTranslator.getSymbolicModifierName(InputEvent.META_MASK));
}
if (evt.isShiftDown()) {
buf.append(KeyEventTranslator.getSymbolicModifierName(InputEvent.SHIFT_MASK));
}
return (buf.length() == 0 ? null : buf.toString());
}
/**
* Returns a the symbolic modifier name for the specified Java modifier
* flag.
*
* @param mod
* A modifier constant from <code>InputEvent</code>
* @since jEdit 4.2pre3
*/
public static String getSymbolicModifierName(final int mod) {
if ((mod & KeyEventTranslator.c) != 0) {
return "control";
}
else if ((mod & KeyEventTranslator.a) != 0) {
return "alt";
}
else if ((mod & KeyEventTranslator.m) != 0) {
return "meta";
}
else if ((mod & KeyEventTranslator.s) != 0) {
return "shift";
}
else {
return "";
}
}
public static String modifiersToString(final int mods) {
StringBuilder buf = null;
if ((mods & InputEvent.CTRL_MASK) != 0) {
buf = new StringBuilder();
buf.append(KeyEventTranslator.getSymbolicModifierName(InputEvent.CTRL_MASK));
}
if ((mods & InputEvent.ALT_MASK) != 0) {
if (buf == null) {
buf = new StringBuilder();
}
else {
buf.append(GrabKeyDialog.MODIFIER_SEPARATOR);
}
buf.append(KeyEventTranslator.getSymbolicModifierName(InputEvent.ALT_MASK));
}
if ((mods & InputEvent.META_MASK) != 0) {
if (buf == null) {
buf = new StringBuilder();
}
else {
buf.append(GrabKeyDialog.MODIFIER_SEPARATOR);
}
buf.append(KeyEventTranslator.getSymbolicModifierName(InputEvent.META_MASK));
}
if ((mods & InputEvent.SHIFT_MASK) != 0) {
if (buf == null) {
buf = new StringBuilder();
}
else {
buf.append(GrabKeyDialog.MODIFIER_SEPARATOR);
}
buf.append(KeyEventTranslator.getSymbolicModifierName(InputEvent.SHIFT_MASK));
}
if (buf == null) {
return null;
}
else {
return buf.toString();
}
}
/**
* Changes the mapping between symbolic modifier key names (<code>C</code>,
* <code>A</code>, <code>M</code>, <code>S</code>) and Java modifier flags.
* You can map more than one Java modifier to a symobolic modifier, for
* example :
* <p>
* <code><pre>
* setModifierMapping(
* InputEvent.CTRL_MASK,
* InputEvent.ALT_MASK | InputEvent.META_MASK,
* 0,
* InputEvent.SHIFT_MASK);
* <pre></code>
* </p>
* You cannot map a Java modifer to more than one symbolic modifier.
*
* @param c
* The modifier(s) to map the <code>C</code> modifier to
* @param a
* The modifier(s) to map the <code>A</code> modifier to
* @param m
* The modifier(s) to map the <code>M</code> modifier to
* @param s
* The modifier(s) to map the <code>S</code> modifier to
* @since jEdit 4.2pre3
*/
public static void setModifierMapping(final int c, final int a, final int m, final int s) {
final int duplicateMapping = ((c & a) | (c & m) | (c & s) | (a & m) | (a & s) | (m & s));
if ((duplicateMapping & InputEvent.CTRL_MASK) != 0) {
throw new IllegalArgumentException("CTRL is mapped to more than one modifier");
}
if ((duplicateMapping & InputEvent.ALT_MASK) != 0) {
throw new IllegalArgumentException("ALT is mapped to more than one modifier");
}
if ((duplicateMapping & InputEvent.META_MASK) != 0) {
throw new IllegalArgumentException("META is mapped to more than one modifier");
}
if ((duplicateMapping & InputEvent.SHIFT_MASK) != 0) {
throw new IllegalArgumentException("SHIFT is mapped to more than one modifier");
}
KeyEventTranslator.c = c;
KeyEventTranslator.a = a;
KeyEventTranslator.m = m;
KeyEventTranslator.s = s;
}
/**
* Pass this an event from
* {@link KeyEventWorkaround#processKeyEvent(java.awt.event.KeyEvent)}.
*
* @since jEdit 4.2pre3
*/
public static Key translateKeyEvent(final KeyEvent evt) {
final int modifiers = evt.getModifiers();
Key returnValue = null;
switch (evt.getID()) {
case KeyEvent.KEY_PRESSED:
final int keyCode = evt.getKeyCode();
if ((keyCode >= KeyEvent.VK_0 && keyCode <= KeyEvent.VK_9)
|| (keyCode >= KeyEvent.VK_A && keyCode <= KeyEvent.VK_Z)) {
returnValue = new Key(KeyEventTranslator.modifiersToString(modifiers), '\0', Character
.toUpperCase((char) keyCode));
}
else {
if (keyCode > 0 && keyCode <= KeyEvent.VK_SPACE
|| keyCode == KeyEvent.VK_DELETE) {
evt.consume();
returnValue = new Key(KeyEventTranslator.modifiersToString(modifiers), keyCode,
KeyEvent.CHAR_UNDEFINED);
}
else {
returnValue = new Key(KeyEventTranslator.modifiersToString(modifiers), keyCode, evt
.getKeyChar());
}
}
break;
default:
return null;
}
/*
* I guess translated events do not have the 'evt' field set so
* consuming won't work. I don't think this is a problem as nothing uses
* translation anyway
*/
final Key trans = KeyEventTranslator.transMap.get(returnValue);
if (trans == null) {
return returnValue;
}
else {
return trans;
}
}
public static final boolean ALT_KEY_PRESSED_DISABLED = false;
static int modifiers;
}