001: ///////////////////////////////////////////////////////////////////////////////
002: //
003: // This program is free software; you can redistribute it and/or modify
004: // it under the terms of the GNU General Public License and GNU Library
005: // General Public License as published by the Free Software Foundation;
006: // either version 2, or (at your option) any later version.
007: //
008: // This program is distributed in the hope that it will be useful,
009: // but WITHOUT ANY WARRANTY; without even the implied warranty of
010: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: // GNU General Public License and GNU Library General Public License
012: // for more details.
013: //
014: // You should have received a copy of the GNU General Public License
015: // and GNU Library General Public License along with this program; if
016: // not, write to the Free Software Foundation, 675 Mass Ave, Cambridge,
017: // MA 02139, USA.
018: //
019: ///////////////////////////////////////////////////////////////////////////////
020:
021: package org.rdesktop.server.rdp.keymapping;
022:
023: import java.io.*;
024: import java.util.*;
025: import java.awt.event.*;
026:
027: import org.rdesktop.server.rdp.RdpOptions;
028:
029: public abstract class KeyCode_FileBased {
030: public static final int DOWN = 1;
031: public static final int UP = 0;
032: public static final int QUIETUP = 2;
033: public static final int QUIETDOWN = 3;
034: public static final int SCANCODE_EXTENDED = 0x80;
035:
036: private int m_mapCode = -1;
037: private boolean m_altQuiet = false;
038: private boolean m_lastEventMatched = false;
039: private KeyEvent m_lastKeyEvent = null;
040: private Hashtable m_keysCurrentlyDown = new Hashtable();
041:
042: public boolean m_capsLockDown = false;
043: public boolean m_useLockingKeyState = true;
044:
045: protected Vector keyMap = new Vector();
046:
047: public KeyCode_FileBased(InputStream fstream)
048: throws KeyMapException {
049: readMapFile(fstream);
050: }
051:
052: public KeyCode_FileBased(String keyMapFile) throws KeyMapException {
053: int lineNum = 0;
054: String line = "";
055: boolean mapCodeSet = false;
056:
057: try {
058: FileInputStream fstream = new FileInputStream(keyMapFile);
059: readMapFile(fstream);
060: } catch (FileNotFoundException e) {
061: throw new KeyMapException("KeyMap file not found: "
062: + keyMapFile);
063: }
064: }
065:
066: private void updateCapsLock(KeyEvent e) {
067: }
068:
069: private int getCodeFromAlphaChar(char keyChar) {
070: if (('a' <= keyChar) && (keyChar <= 'z')) {
071: return KeyEvent.VK_A + keyChar - 'a';
072: }
073:
074: if (('A' <= keyChar) && (keyChar <= 'Z')) {
075: return KeyEvent.VK_A + keyChar - 'A';
076: }
077:
078: return -1;
079: }
080:
081: private void registerKeyEvent(KeyEvent e, MapDef m) {
082: if (e.getID() == KeyEvent.KEY_RELEASED) {
083: m_keysCurrentlyDown.remove(new Integer(e.getKeyCode()));
084: if ((RdpOptions.caps_sends_up_and_down == false)
085: && (e.getKeyCode() == KeyEvent.VK_CAPS_LOCK)) {
086: m_capsLockDown = false;
087: }
088:
089: m_lastEventMatched = false;
090: }
091:
092: if (e.getID() == KeyEvent.KEY_PRESSED) {
093: m_lastKeyEvent = e;
094: if (m != null) {
095: m_lastEventMatched = true;
096: } else {
097: m_lastEventMatched = false;
098: }
099:
100: if ((RdpOptions.caps_sends_up_and_down)
101: && (e.getKeyCode() == KeyEvent.VK_CAPS_LOCK)) {
102: m_capsLockDown = !m_capsLockDown;
103: } else if (e.getKeyCode() == KeyEvent.VK_CAPS_LOCK) {
104: m_capsLockDown = true;
105: }
106: }
107:
108: if ((m_lastKeyEvent != null)
109: && (m != null)
110: && (m_keysCurrentlyDown.containsKey(new Integer(
111: m_lastKeyEvent.getKeyCode())) == false)) {
112: m_keysCurrentlyDown.put(new Integer(m_lastKeyEvent
113: .getKeyCode()), m);
114: m_lastKeyEvent = null;
115: }
116:
117: }
118:
119: public void readMapFile(InputStream fstream) throws KeyMapException {
120: int lineNum = 0;
121:
122: if (fstream == null) {
123: throw new KeyMapException(
124: "Could not find specified keymap file");
125: }
126:
127: boolean mapCodeSet = false;
128:
129: try {
130: BufferedReader in = new BufferedReader(
131: new InputStreamReader(fstream));
132:
133: String line = in.readLine();
134: while (line != null) {
135: char fc = 0x0;
136: if ((line != null) && (line.length() > 0)) {
137: fc = line.charAt(0);
138: }
139:
140: if ((line != null) && (line.length() > 0)
141: && (fc != '#') && (fc != 'c')) {
142: keyMap.add(new MapDef(line));
143: } else if (fc == 'c') {
144: StringTokenizer st = new StringTokenizer(line);
145: String s = st.nextToken();
146:
147: s = st.nextToken();
148: m_mapCode = Integer.decode(s).intValue();
149: mapCodeSet = true;
150: }
151:
152: line = in.readLine();
153: }
154:
155: Vector newMap = new Vector();
156:
157: Iterator iter = keyMap.iterator();
158: while (iter.hasNext()) {
159: MapDef current = (MapDef) iter.next();
160:
161: if (current.isCharacterDef()
162: && !(current.isAltDown()
163: || current.isCtrlDown()
164: || current.isShiftDown() || current
165: .isCapslockOn())) {
166: int code = getCodeFromAlphaChar(current
167: .getKeyChar());
168: if (code > -1) {
169: newMap.add(new MapDef(code, 0, current
170: .getScancode(), true, false, false,
171: false));
172: newMap.add(new MapDef(code, 0, current
173: .getScancode(), false, false, true,
174: false));
175: }
176: }
177: }
178:
179: keyMap.addAll(newMap);
180:
181: in.close();
182: } catch (IOException e) {
183: throw new KeyMapException("File input error: "
184: + e.getMessage());
185: } catch (NumberFormatException nfEx) {
186: throw new KeyMapException("" + nfEx.getMessage()
187: + " is not numeric at line " + lineNum);
188: } catch (NoSuchElementException nseEx) {
189: throw new KeyMapException(
190: "Not enough parameters in definition at line "
191: + lineNum);
192: } catch (KeyMapException kmEx) {
193: throw new KeyMapException("Error parsing keymap file: "
194: + kmEx.getMessage() + " at line " + lineNum);
195: } catch (Exception e) {
196: e.printStackTrace();
197:
198: throw new KeyMapException(e.getClass().getName() + ": "
199: + e.getMessage());
200: }
201:
202: if (mapCodeSet == false) {
203: throw new KeyMapException("No map identifier found in file");
204: }
205: }
206:
207: public int getMapCode() {
208: return m_mapCode;
209: }
210:
211: public String stateChanges(KeyEvent e, MapDef theDef) {
212: String changes = "";
213:
214: final int SHIFT = 0;
215: final int CTRL = 1;
216: final int ALT = 2;
217: final int CAPSLOCK = 3;
218:
219: int BEFORE = 0;
220: int AFTER = 1;
221:
222: boolean[][] state = new boolean[4][2];
223:
224: state[SHIFT][BEFORE] = e.isShiftDown();
225: state[SHIFT][AFTER] = theDef.isShiftDown();
226:
227: state[CTRL][BEFORE] = e.isControlDown() || e.isAltGraphDown();
228: state[CTRL][AFTER] = theDef.isCtrlDown();
229:
230: state[ALT][BEFORE] = e.isAltDown() || e.isAltGraphDown();
231: state[ALT][AFTER] = theDef.isAltDown();
232:
233: updateCapsLock(e);
234:
235: state[CAPSLOCK][BEFORE] = m_capsLockDown;
236: state[CAPSLOCK][AFTER] = theDef.isCapslockOn();
237:
238: if (e.getID() == KeyEvent.KEY_RELEASED) {
239: AFTER = 0;
240: BEFORE = 1;
241: }
242:
243: if ((e == null) || (theDef == null)
244: || (!theDef.isCharacterDef())) {
245: return "";
246: }
247:
248: String up = "" + ((char) UP);
249: String down = "" + ((char) DOWN);
250: String quietup = up;
251: String quietdown = down;
252:
253: quietup = "" + ((char) QUIETUP);
254: quietdown = "" + ((char) QUIETDOWN);
255:
256: if (state[SHIFT][BEFORE] != state[SHIFT][AFTER]) {
257: if (state[SHIFT][BEFORE]) {
258: changes += ((char) 0x2a) + up;
259: } else {
260: changes += ((char) 0x2a) + down;
261: }
262: }
263:
264: if (state[CTRL][BEFORE] != state[CTRL][AFTER]) {
265: if (state[CTRL][BEFORE]) {
266: changes += ((char) 0x1d) + up;
267: } else {
268: changes += ((char) 0x1d) + down;
269: }
270: }
271:
272: if (RdpOptions.altkey_quiet) {
273: if (state[ALT][BEFORE] != state[ALT][AFTER]) {
274: if (state[ALT][BEFORE]) {
275: changes += (char) 0x38 + quietup + ((char) 0x38)
276: + quietdown + ((char) 0x38) + up;
277: } else {
278: if (e.getID() == KeyEvent.KEY_RELEASED) {
279: m_altQuiet = true;
280: changes += ((char) 0x38) + quietdown;
281: } else {
282: m_altQuiet = false;
283: changes += ((char) 0x38) + down;
284: }
285: }
286: } else if (state[ALT][AFTER] && m_altQuiet) {
287: m_altQuiet = false;
288: changes += (char) 0x38 + quietup + ((char) 0x38)
289: + quietdown + ((char) 0x38) + up
290: + ((char) 0x38) + down;
291: }
292: } else {
293: if (state[ALT][BEFORE] != state[ALT][AFTER]) {
294: if (state[ALT][BEFORE]) {
295: changes += ((char) 0x38) + up;
296: } else {
297: changes += ((char) 0x38) + down;
298: }
299: }
300: }
301:
302: if (state[CAPSLOCK][BEFORE] != state[CAPSLOCK][AFTER]) {
303: changes += ((char) 0x3a) + down + ((char) 0x3a) + up;
304: }
305:
306: return changes;
307: }
308:
309: public void writeToFile(String filename) {
310: try {
311: FileOutputStream out = new FileOutputStream(filename);
312: PrintStream printStream = new PrintStream(out);
313:
314: Iterator iter = keyMap.iterator();
315: while (iter.hasNext()) {
316: ((MapDef) iter.next()).writeToStream(printStream);
317: }
318:
319: printStream.close();
320:
321: } catch (Exception e) {
322: System.err.println("Error writing to file: "
323: + e.getMessage());
324: }
325: }
326:
327: public boolean hasScancode(char c) {
328: if (c == KeyEvent.CHAR_UNDEFINED) {
329: return false;
330: }
331:
332: MapDef best = null;
333: Iterator iter = keyMap.iterator();
334: while (iter.hasNext()) {
335: MapDef current = (MapDef) iter.next();
336: if (current.appliesTo(c)) {
337: best = current;
338: }
339: }
340:
341: return (best != null);
342:
343: }
344:
345: public int charToScancode(char c, String[] mod) {
346: MapDef best = null;
347: int smallestDist = -1;
348: Iterator iter = keyMap.iterator();
349:
350: while (iter.hasNext()) {
351: MapDef current = (MapDef) iter.next();
352: if (current.appliesTo(c)) {
353: best = current;
354: }
355: }
356:
357: if (best != null) {
358: if (best.isShiftDown()) {
359: mod[0] = "SHIFT";
360: } else if (best.isCtrlDown() && best.isAltDown()) {
361: mod[0] = "ALTGR";
362: } else {
363: mod[0] = "NONE";
364: }
365:
366: return best.getScancode();
367: } else {
368: return -1;
369: }
370: }
371:
372: public MapDef getDef(KeyEvent e) {
373: if (e.getID() == KeyEvent.KEY_RELEASED) {
374: MapDef def = (MapDef) m_keysCurrentlyDown.get(new Integer(e
375: .getKeyCode()));
376: registerKeyEvent(e, def);
377: return def;
378: }
379:
380: updateCapsLock(e);
381:
382: MapDef best = null;
383: int smallestDist = -1;
384: boolean noScanCode = !hasScancode(e.getKeyChar());
385:
386: Iterator iter = keyMap.iterator();
387: while (iter.hasNext()) {
388: MapDef current = (MapDef) iter.next();
389:
390: boolean applies;
391: if ((e.getID() == KeyEvent.KEY_PRESSED)) {
392: applies = current.appliesToPressed(e);
393: } else if ((m_lastEventMatched == false)
394: && (e.getID() == KeyEvent.KEY_TYPED)) {
395: applies = current.appliesToTyped(e, m_capsLockDown);
396: } else {
397: applies = false;
398: }
399:
400: if (applies == true) {
401: int d = current.modifierDistance(e, m_capsLockDown);
402: if ((smallestDist == -1) || (d < smallestDist)) {
403: smallestDist = d;
404: best = current;
405: }
406: }
407: }
408:
409: registerKeyEvent(e, best);
410:
411: return best;
412: }
413:
414: public int getScancode(KeyEvent e) {
415: String[] mod = { "" };
416:
417: MapDef d = getDef(e);
418: if (d != null) {
419: return d.getScancode();
420: } else {
421: return -1;
422: }
423: }
424:
425: public String getKeyStrokes(KeyEvent e) {
426: String codes = "";
427: MapDef d = getDef(e);
428:
429: if (d == null) {
430: return "";
431: }
432:
433: codes = stateChanges(e, d);
434:
435: String type = "";
436:
437: if (e.getID() == KeyEvent.KEY_RELEASED) {
438: if ((RdpOptions.caps_sends_up_and_down == false)
439: && (e.getKeyCode() == KeyEvent.VK_CAPS_LOCK)) {
440: codes = "" + ((char) 0x3a) + ((char) DOWN)
441: + ((char) 0x3a) + ((char) UP) + codes;
442: } else {
443: type = "" + ((char) UP);
444: codes = ((char) d.getScancode()) + type + codes;
445: }
446: } else {
447: if ((RdpOptions.caps_sends_up_and_down == false)
448: && (e.getKeyCode() == KeyEvent.VK_CAPS_LOCK)) {
449: codes += "" + ((char) 0x3a) + ((char) DOWN)
450: + ((char) 0x3a) + ((char) UP);
451: } else {
452: type = "" + ((char) DOWN);
453: codes += ((char) d.getScancode()) + type;
454: }
455: }
456:
457: return codes;
458: }
459: }
|