/jEdit/tags/jedit-4-2-pre3/org/gjt/sp/jedit/gui/KeyEventTranslator.java

# · Java · 364 lines · 245 code · 28 blank · 91 comment · 57 complexity · bbe79b045f4cfd974a9e2ef7a29431db MD5 · raw file

  1. /*
  2. * KeyEventTranslator.java - Hides some warts of AWT event API
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2003 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit.gui;
  23. //{{{ Imports
  24. import java.awt.event.*;
  25. import java.awt.Toolkit;
  26. import java.util.*;
  27. import org.gjt.sp.jedit.*;
  28. import org.gjt.sp.util.Log;
  29. //}}}
  30. /**
  31. * In conjunction with the <code>KeyEventWorkaround</code>, hides some
  32. * warts in the AWT key event API.
  33. *
  34. * @author Slava Pestov
  35. * @version $Id: KeyEventTranslator.java 4819 2003-07-03 21:06:33Z spestov $
  36. */
  37. public class KeyEventTranslator
  38. {
  39. //{{{ addTranslation() method
  40. /**
  41. * Adds a keyboard translation.
  42. * @param key1 Translate this key
  43. * @param key2 Into this key
  44. * @since jEdit 4.2pre3
  45. */
  46. public static void addTranslation(Key key1, Key key2)
  47. {
  48. transMap.put(key1,key2);
  49. } //}}}
  50. //{{{ translateKeyEvent() method
  51. /**
  52. * Pass this an event from {@link
  53. * KeyEventWorkaround#processKeyEvent(java.awt.event.KeyEvent)}.
  54. * @since jEdit 4.2pre3
  55. */
  56. public static Key translateKeyEvent(KeyEvent evt)
  57. {
  58. int modifiers = evt.getModifiers();
  59. Key returnValue = null;
  60. switch(evt.getID())
  61. {
  62. case KeyEvent.KEY_PRESSED:
  63. int keyCode = evt.getKeyCode();
  64. if((keyCode >= KeyEvent.VK_0
  65. && keyCode <= KeyEvent.VK_9)
  66. || (keyCode >= KeyEvent.VK_A
  67. && keyCode <= KeyEvent.VK_Z))
  68. {
  69. if(Debug.ALTERNATIVE_DISPATCHER)
  70. return null;
  71. else
  72. {
  73. returnValue = new Key(
  74. getModifierString(evt),
  75. '\0',Character.toLowerCase(
  76. (char)keyCode));
  77. }
  78. }
  79. else
  80. {
  81. if(keyCode == KeyEvent.VK_TAB)
  82. evt.consume();
  83. returnValue = new Key(getModifierString(evt),keyCode,'\0');
  84. }
  85. break;
  86. case KeyEvent.KEY_TYPED:
  87. char ch = evt.getKeyChar();
  88. switch(ch)
  89. {
  90. case '\n':
  91. case '\t':
  92. case '\b':
  93. case ' ':
  94. return null;
  95. }
  96. boolean mod = (System.currentTimeMillis() -
  97. KeyEventWorkaround.lastKeyTime < 750
  98. && (KeyEventWorkaround.modifiers
  99. & ~(InputEvent.SHIFT_MASK | InputEvent.ALT_GRAPH_MASK)) != 0);
  100. if(mod)
  101. {
  102. if(Debug.ALTERNATIVE_DISPATCHER)
  103. {
  104. returnValue = new Key(
  105. modifiersToString(modifiers),
  106. 0,ch);
  107. }
  108. else
  109. return null;
  110. }
  111. else
  112. returnValue = new Key(null,0,ch);
  113. break;
  114. default:
  115. return null;
  116. }
  117. Key trans = (Key)transMap.get(returnValue);
  118. if(trans == null)
  119. return returnValue;
  120. else
  121. return trans;
  122. } //}}}
  123. //{{{ parseKey() method
  124. /**
  125. * Converts a string to a keystroke. The string should be of the
  126. * form <i>modifiers</i>+<i>shortcut</i> where <i>modifiers</i>
  127. * is any combination of A for Alt, C for Control, S for Shift
  128. * or M for Meta, and <i>shortcut</i> is either a single character,
  129. * or a keycode name from the <code>KeyEvent</code> class, without
  130. * the <code>VK_</code> prefix.
  131. * @param keyStroke A string description of the key stroke
  132. * @since jEdit 4.2pre3
  133. */
  134. public static Key parseKey(String keyStroke)
  135. {
  136. if(keyStroke == null)
  137. return null;
  138. int index = keyStroke.indexOf('+');
  139. int modifiers = 0;
  140. if(index != -1)
  141. {
  142. for(int i = 0; i < index; i++)
  143. {
  144. switch(Character.toUpperCase(keyStroke
  145. .charAt(i)))
  146. {
  147. case 'A':
  148. modifiers |= a;
  149. break;
  150. case 'C':
  151. modifiers |= c;
  152. break;
  153. case 'M':
  154. modifiers |= m;
  155. break;
  156. case 'S':
  157. modifiers |= s;
  158. break;
  159. }
  160. }
  161. }
  162. String key = keyStroke.substring(index + 1);
  163. if(key.length() == 1)
  164. {
  165. return new Key(modifiersToString(modifiers),0,key.charAt(0));
  166. }
  167. else if(key.length() == 0)
  168. {
  169. Log.log(Log.ERROR,DefaultInputHandler.class,
  170. "Invalid key stroke: " + keyStroke);
  171. return null;
  172. }
  173. else
  174. {
  175. int ch;
  176. try
  177. {
  178. ch = KeyEvent.class.getField("VK_".concat(key))
  179. .getInt(null);
  180. }
  181. catch(Exception e)
  182. {
  183. Log.log(Log.ERROR,DefaultInputHandler.class,
  184. "Invalid key stroke: "
  185. + keyStroke);
  186. return null;
  187. }
  188. return new Key(modifiersToString(modifiers),ch,'\0');
  189. }
  190. } //}}}
  191. //{{{ setModifierMapping() method
  192. /**
  193. * Changes the mapping between symbolic modifier key names
  194. * (<code>C</code>, <code>A</code>, <code>M</code>, <code>S</code>) and
  195. * Java modifier flags.
  196. *
  197. * @param c The modifier to map the <code>C</code> modifier to
  198. * @param a The modifier to map the <code>A</code> modifier to
  199. * @param m The modifier to map the <code>M</code> modifier to
  200. * @param s The modifier to map the <code>S</code> modifier to
  201. *
  202. * @since jEdit 4.2pre3
  203. */
  204. public static void setModifierMapping(int c, int a, int m, int s)
  205. {
  206. KeyEventTranslator.c = c;
  207. KeyEventTranslator.a = a;
  208. KeyEventTranslator.m = m;
  209. KeyEventTranslator.s = s;
  210. } //}}}
  211. //{{{ getSymbolicModifierName() method
  212. /**
  213. * Returns a the symbolic modifier name for the specified Java modifier
  214. * flag.
  215. *
  216. * @param mod A modifier constant from <code>InputEvent</code>
  217. *
  218. * @since jEdit 4.2pre3
  219. */
  220. public static char getSymbolicModifierName(int mod)
  221. {
  222. // this relies on the fact that if C is mapped to M, then
  223. // M will be mapped to C.
  224. if(mod == c)
  225. return 'C';
  226. else if(mod == a)
  227. return 'A';
  228. else if(mod == m)
  229. return 'M';
  230. else if(mod == s)
  231. return 'S';
  232. else
  233. return '\0';
  234. } //}}}
  235. //{{{ modifiersToString() method
  236. public static String modifiersToString(int mods)
  237. {
  238. if(mods == 0)
  239. return null;
  240. StringBuffer buf = new StringBuffer();
  241. if((mods & InputEvent.CTRL_MASK) != 0)
  242. buf.append(getSymbolicModifierName(InputEvent.CTRL_MASK));
  243. if((mods & InputEvent.ALT_MASK) != 0)
  244. buf.append(getSymbolicModifierName(InputEvent.ALT_MASK));
  245. if((mods & InputEvent.META_MASK) != 0)
  246. buf.append(getSymbolicModifierName(InputEvent.META_MASK));
  247. if((mods & InputEvent.SHIFT_MASK) != 0)
  248. buf.append(getSymbolicModifierName(InputEvent.SHIFT_MASK));
  249. return buf.toString();
  250. } //}}}
  251. //{{{ getModifierString() method
  252. /**
  253. * Returns a string containing symbolic modifier names set in the
  254. * specified event.
  255. *
  256. * @param evt The event
  257. *
  258. * @since jEdit 4.2pre3
  259. */
  260. public static String getModifierString(InputEvent evt)
  261. {
  262. StringBuffer buf = new StringBuffer();
  263. if(evt.isControlDown())
  264. buf.append(getSymbolicModifierName(InputEvent.CTRL_MASK));
  265. if(evt.isAltDown())
  266. buf.append(getSymbolicModifierName(InputEvent.ALT_MASK));
  267. if(evt.isMetaDown())
  268. buf.append(getSymbolicModifierName(InputEvent.META_MASK));
  269. if(evt.isShiftDown())
  270. buf.append(getSymbolicModifierName(InputEvent.SHIFT_MASK));
  271. return (buf.length() == 0 ? null : buf.toString());
  272. } //}}}
  273. static int c, a, m, s;
  274. //{{{ Private members
  275. private static Map transMap = new HashMap();
  276. static
  277. {
  278. if(OperatingSystem.isMacOS())
  279. {
  280. setModifierMapping(
  281. InputEvent.META_MASK, /* == C+ */
  282. InputEvent.CTRL_MASK, /* == A+ */
  283. /* M+ discarded by key event workaround! */
  284. InputEvent.ALT_MASK, /* == M+ */
  285. InputEvent.SHIFT_MASK /* == S+ */);
  286. }
  287. else
  288. {
  289. setModifierMapping(
  290. InputEvent.CTRL_MASK,
  291. InputEvent.ALT_MASK,
  292. InputEvent.META_MASK,
  293. InputEvent.SHIFT_MASK);
  294. }
  295. } //}}}
  296. //{{{ Key class
  297. public static class Key
  298. {
  299. public String modifiers;
  300. public int key;
  301. public char input;
  302. public Key(String modifiers, int key, char input)
  303. {
  304. this.modifiers = modifiers;
  305. this.key = key;
  306. this.input = input;
  307. }
  308. public int hashCode()
  309. {
  310. return key + input;
  311. }
  312. public boolean equals(Object o)
  313. {
  314. if(o instanceof Key)
  315. {
  316. Key k = (Key)o;
  317. if(MiscUtilities.objectsEqual(modifiers,
  318. k.modifiers) && key == k.key
  319. && input == k.input)
  320. {
  321. return true;
  322. }
  323. }
  324. return false;
  325. }
  326. public String toString()
  327. {
  328. return (modifiers == null ? "" : modifiers)
  329. + "<"
  330. + Integer.toString(key,16)
  331. + ","
  332. + Integer.toString(input,16)
  333. + ">";
  334. }
  335. } //}}}
  336. }