/* MapDef.java * Component: ProperJavaRDP * * Revision: $Revision: 1.4 $ * Author: $Author: telliott $ * Date: $Date: 2005/09/27 14:15:39 $ * * Copyright (c) 2005 Propero Limited * * Purpose: Encapsulates an individual key mapping * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * * (See gpl.txt for details of the GNU General Public License.) * */ package org.jopenray.rdp.keymapping; import java.awt.event.KeyEvent; import java.io.PrintStream; import java.util.NoSuchElementException; import java.util.StringTokenizer; import org.jopenray.rdp.Constants; import org.jopenray.rdp.Options; public class MapDef { // Flag masks for use in generating an integer modifiers value (for text // definition output) private final int FLAG_SHIFT = 0x01; // flag mask for a shift modifier private final int FLAG_CTRL = 0x02; // flag mask for a control modifier private final int FLAG_ALT = 0x04; // flag mask for an alt modifier private final int FLAG_CAPSLOCK = 0x08; // flag mask for a capslock modifier private int scancode; private boolean ctrlDown; private boolean shiftDown; private boolean altDown; private boolean capslockDown; private char keyChar; private int keyCode; private boolean characterDef; private int keyLocation; /** * Constructor for a character-defined mapping definition * * @param keyChar * @param keyLocation * @param scancode * @param ctrlDown * @param shiftDown * @param altDown * @param capslockDown */ public MapDef(char keyChar, int keyLocation, int scancode, boolean ctrlDown, boolean shiftDown, boolean altDown, boolean capslockDown) { this.keyChar = keyChar; this.characterDef = true; this.keyLocation = keyLocation; this.scancode = scancode; this.ctrlDown = ctrlDown; this.altDown = altDown; this.shiftDown = shiftDown; this.capslockDown = capslockDown; } /** * Constructor for a keycode-defined mapping definition * * @param keyChar * @param keyLocation * @param scancode * @param ctrlDown * @param shiftDown * @param altDown * @param capslockDown */ public MapDef(int keyCode, int keyLocation, int scancode, boolean ctrlDown, boolean shiftDown, boolean altDown, boolean capslockDown) { this.keyCode = keyCode; this.characterDef = false; this.keyLocation = keyLocation; this.scancode = scancode; this.ctrlDown = ctrlDown; this.altDown = altDown; this.shiftDown = shiftDown; this.capslockDown = capslockDown; } public int getKeyCode() { return keyCode; } public char getKeyChar() { return keyChar; } /** * Return the scancode associated with this mapping * * @return */ public int getScancode() { return scancode; } /** * Return true if this mapping is defined by a character, false otherwise * * @return */ public boolean isCharacterDef() { return characterDef; } /** * Return true if the keystroke defined in this mapping requires that the * Control key be down * * @return */ public boolean isCtrlDown() { return ctrlDown; } /** * Return true if the keystroke defined in this mapping requires that the * Alt key be down * * @return */ public boolean isAltDown() { return altDown; } /** * Return true if the keystroke defined in this mapping requires that the * Shift key be down * * @return */ public boolean isShiftDown() { return shiftDown; } /** * Return true if the keystroke defined in this mapping requires that Caps * Lock is on * * @return */ public boolean isCapslockOn() { return capslockDown; } /** * Return the number of modifiers that would need to be changed to send the * specified character/key using this particular mapping. * * @param e * Key event which was received by Java * @param capslock * Is the Caps Lock key down? * @return The number of modifier changes to make */ public int modifierDistance(KeyEvent e, boolean capslock) { // boolean capslock = e.getComponent().getToolkit().getLockingKeyState( // KeyEvent.VK_CAPS_LOCK); if (!characterDef) return 0; int dist = 0; if (ctrlDown != e.isControlDown()) dist += 1; if (altDown != e.isAltDown()) dist += 1; if (shiftDown != e.isShiftDown()) dist += 1; if (capslockDown != capslock) dist += 1; return dist; } public boolean appliesTo(char c) { return ((characterDef) && (this.keyChar == c) && !(capslockDown)); } /** * * Return true if this map definition applies to the supplied key event * * @param e * KeyEvent to check definition against * @return */ protected boolean appliesToTyped(KeyEvent e) { return ((characterDef) && (this.keyChar == e.getKeyChar())); } protected boolean appliesToTyped(KeyEvent e, boolean capslock) { if (Constants.OS == Constants.MAC) { // Remap the hash key to � if (Options.remap_hash && (e.getKeyChar() == '#')) { return ((characterDef) && (this.keyChar == '#')); } // Handle unreported shifted capitals (with capslock) on a Mac if (capslock && Character.isLetter(e.getKeyChar()) && Character.isUpperCase(e.getKeyChar()) && e.isShiftDown()) { char c = Character.toLowerCase(e.getKeyChar()); return ((characterDef) && (this.keyChar == c)); } } return ((characterDef) && (this.keyChar == e.getKeyChar())); } /** * * Return true if this map definition applies to the supplied key event * * @param e * KeyEvent to check definition against * @return */ protected boolean appliesToPressed(KeyEvent e) { // only match special characters if the modifiers are consistent if (!characterDef) { if (!((ctrlDown && e.isControlDown()) || !ctrlDown)) return false; if (!((altDown && e.isAltDown()) || !altDown)) return false; } return ((!characterDef) && (this.keyCode == e.getKeyCode())); } /** * Constructor for a mapping definition based on a given string * representation (as would be output to a stream by the writeToStream * method). * * @param definition * One-line definition string * @throws KeyMapException * Any parsing errors which may occur */ public MapDef(String definition) throws KeyMapException { StringTokenizer st = new StringTokenizer(definition); try { // determine whether the definition is character-oriented characterDef = ((Integer.parseInt(st.nextToken()) == 1) ? true : false); // read in the character or keycode if (characterDef) keyChar = (char) Integer.parseInt(st.nextToken()); else keyCode = Integer.parseInt(st.nextToken()); // read in the key location keyLocation = Integer.parseInt(st.nextToken()); // read in the scancode (from a HEX string) scancode = Integer.decode(st.nextToken()).intValue(); // read in the modifiers and interpret int modifiers = Integer.parseInt(st.nextToken()); shiftDown = ((modifiers & this.FLAG_SHIFT) != 0); ctrlDown = ((modifiers & this.FLAG_CTRL) != 0); altDown = ((modifiers & this.FLAG_ALT) != 0); capslockDown = ((modifiers & this.FLAG_CAPSLOCK) != 0); } catch (NumberFormatException nfEx) { throw new KeyMapException("" + nfEx.getMessage() + " is not numeric"); } catch (NoSuchElementException nseEx) { throw new KeyMapException("Not enough parameters in definition"); } } /** * Output this mapping definition to a stream, formatted as a single line * (characterDef character/keycode location scancode modifiers * [description]) * * @param p * Stream to write to */ public void writeToStream(PrintStream p) { // create definition string with first character 1 if the // mapping is character-defined, 0 otherwise String definition = "" + (characterDef ? 1 : 0); // add character or keycode definition += "\t"; if (characterDef) definition += (int) keyChar; else definition += keyCode; // add key location definition += "\t" + keyLocation; definition += "\t0x" + Integer.toHexString(scancode); // build and add modifiers as a set of flags in an integer value int modifiers = 0; modifiers |= (shiftDown ? FLAG_SHIFT : 0); modifiers |= (ctrlDown ? FLAG_CTRL : 0); modifiers |= (altDown ? FLAG_ALT : 0); modifiers |= (capslockDown ? FLAG_CAPSLOCK : 0); definition += "\t" + modifiers; // add additional information if available (and necessary) if (!characterDef) definition += "\t" + KeyEvent.getKeyText(this.keyCode); // output the definition to the specified stream p.println(definition); } public void dump() { System.out.println("KeyCode:" + this.keyCode + " keyChar:" + this.keyChar + " scan:" + this.scancode); } }