Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/gjt/sp/jedit/gui/KeyEventTranslator.java


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  
23  package org.gjt.sp.jedit.gui;
24  
25  //{{{ Imports
26  import java.awt.event.*;
27  import java.awt.Toolkit;
28  import java.util.*;
29  import org.gjt.sp.jedit.*;
30  import org.gjt.sp.util.Log;
31  //}}}
32  
33  /**
34   * In conjunction with the <code>KeyEventWorkaround</code>, hides some 
35   * warts in the AWT key event API.
36   *
37   * @author Slava Pestov
38   * @version $Id: KeyEventTranslator.java,v 1.20 2003/10/11 02:21:37 spestov Exp $
39   */
40  public class KeyEventTranslator
41  {
42    //{{{ addTranslation() method
43    /**
44     * Adds a keyboard translation.
45     * @param key1 Translate this key
46     * @param key2 Into this key
47     * @since jEdit 4.2pre3
48     */
49    public static void addTranslation(Key key1, Key key2)
50    {
51      transMap.put(key1,key2);
52    } //}}}
53  
54    //{{{ translateKeyEvent() method
55    /**
56     * Pass this an event from {@link
57     * KeyEventWorkaround#processKeyEvent(java.awt.event.KeyEvent)}.
58     * @since jEdit 4.2pre3
59     */
60    public static Key translateKeyEvent(KeyEvent evt)
61    {
62      int modifiers = evt.getModifiers();
63      Key returnValue = null;
64  
65      switch(evt.getID())
66      {
67      case KeyEvent.KEY_PRESSED:
68        int keyCode = evt.getKeyCode();
69        if((keyCode >= KeyEvent.VK_0
70          && keyCode <= KeyEvent.VK_9)
71          || (keyCode >= KeyEvent.VK_A
72          && keyCode <= KeyEvent.VK_Z))
73        {
74          if(Debug.ALTERNATIVE_DISPATCHER)
75            return null;
76          else
77          {
78            returnValue = new Key(
79              modifiersToString(modifiers),
80              '\0',Character.toLowerCase(
81              (char)keyCode));
82          }
83        }
84        else
85        {
86          if(keyCode == KeyEvent.VK_TAB)
87          {
88            evt.consume();
89            returnValue = new Key(
90              modifiersToString(modifiers),
91              keyCode,'\0');
92          }
93          else if(keyCode == KeyEvent.VK_SPACE)
94          {
95            // for SPACE or S+SPACE we pass the
96            // key typed since international
97            // keyboards sometimes produce a
98            // KEY_PRESSED SPACE but not a
99            // KEY_TYPED SPACE, eg if you have to
100           // do a "<space> to insert ".
101           if((modifiers & ~InputEvent.SHIFT_MASK) == 0)
102             returnValue = null;
103           else
104           {
105             returnValue = new Key(
106               modifiersToString(modifiers),
107               0,' ');
108           }
109         }
110         else
111         {
112           returnValue = new Key(
113             modifiersToString(modifiers),
114             keyCode,'\0');
115         }
116       }
117       break;
118     case KeyEvent.KEY_TYPED:
119       char ch = evt.getKeyChar();
120 
121       switch(ch)
122       {
123       case '\n':
124       case '\t':
125       case '\b':
126         return null;
127       case ' ':
128         if((modifiers & ~InputEvent.SHIFT_MASK) != 0)
129           return null;
130       }
131 
132       int ignoreMods;
133       if(Debug.ALT_KEY_PRESSED_DISABLED)
134       {
135         /* on MacOS, A+ can be user input */
136         ignoreMods = (InputEvent.SHIFT_MASK
137           | InputEvent.ALT_GRAPH_MASK
138           | InputEvent.ALT_MASK);
139       }
140       else
141       {
142         /* on MacOS, A+ can be user input */
143         ignoreMods = (InputEvent.SHIFT_MASK
144           | InputEvent.ALT_GRAPH_MASK);
145       }
146 
147       boolean mod;
148       if((modifiers & InputEvent.ALT_GRAPH_MASK) == 0
149         && System.currentTimeMillis()
150         -  KeyEventWorkaround.lastKeyTime < 750
151         && (KeyEventWorkaround.modifiers & ~ignoreMods)
152         != 0)
153       {
154         if(Debug.ALTERNATIVE_DISPATCHER)
155         {
156           returnValue = new Key(
157             modifiersToString(modifiers),
158             0,ch);
159         }
160         else
161           return null;
162       }
163       else
164         returnValue = new Key(null,0,ch);
165       break;
166     default:
167       return null;
168     }
169 
170     /* I guess translated events do not have the 'evt' field set
171     so consuming won't work. I don't think this is a problem as
172     nothing uses translation anyway */
173     Key trans = (Key)transMap.get(returnValue);
174     if(trans == null)
175       return returnValue;
176     else
177       return trans;
178   } //}}}
179 
180   //{{{ parseKey() method
181   /**
182    * Converts a string to a keystroke. The string should be of the
183    * form <i>modifiers</i>+<i>shortcut</i> where <i>modifiers</i>
184    * is any combination of A for Alt, C for Control, S for Shift
185    * or M for Meta, and <i>shortcut</i> is either a single character,
186    * or a keycode name from the <code>KeyEvent</code> class, without
187    * the <code>VK_</code> prefix.
188    * @param keyStroke A string description of the key stroke
189    * @since jEdit 4.2pre3
190    */
191   public static Key parseKey(String keyStroke)
192   {
193     if(keyStroke == null)
194       return null;
195     int index = keyStroke.indexOf('+');
196     int modifiers = 0;
197     if(index != -1)
198     {
199       for(int i = 0; i < index; i++)
200       {
201         switch(Character.toUpperCase(keyStroke
202           .charAt(i)))
203         {
204         case 'A':
205           modifiers |= a;
206           break;
207         case 'C':
208           modifiers |= c;
209           break;
210         case 'M':
211           modifiers |= m;
212           break;
213         case 'S':
214           modifiers |= s;
215           break;
216         }
217       }
218     }
219     String key = keyStroke.substring(index + 1);
220     if(key.length() == 1)
221     {
222       return new Key(modifiersToString(modifiers),0,key.charAt(0));
223     }
224     else if(key.length() == 0)
225     {
226       Log.log(Log.ERROR,DefaultInputHandler.class,
227         "Invalid key stroke: " + keyStroke);
228       return null;
229     }
230     else if(key.equals("SPACE"))
231     {
232       return new Key(modifiersToString(modifiers),0,' ');
233     }
234     else
235     {
236       int ch;
237 
238       try
239       {
240         ch = KeyEvent.class.getField("VK_".concat(key))
241           .getInt(null);
242       }
243       catch(Exception e)
244       {
245         Log.log(Log.ERROR,DefaultInputHandler.class,
246           "Invalid key stroke: "
247           + keyStroke);
248         return null;
249       }
250 
251       return new Key(modifiersToString(modifiers),ch,'\0');
252     }
253   } //}}}
254 
255   //{{{ setModifierMapping() method
256   /**
257    * Changes the mapping between symbolic modifier key names
258    * (<code>C</code>, <code>A</code>, <code>M</code>, <code>S</code>) and
259    * Java modifier flags.
260    *
261    * @param c The modifier to map the <code>C</code> modifier to
262    * @param a The modifier to map the <code>A</code> modifier to
263    * @param m The modifier to map the <code>M</code> modifier to
264    * @param s The modifier to map the <code>S</code> modifier to
265    *
266    * @since jEdit 4.2pre3
267    */
268   public static void setModifierMapping(int c, int a, int m, int s)
269   {
270     KeyEventTranslator.c = c;
271     KeyEventTranslator.a = a;
272     KeyEventTranslator.m = m;
273     KeyEventTranslator.s = s;
274   } //}}}
275 
276   //{{{ getSymbolicModifierName() method
277   /**
278    * Returns a the symbolic modifier name for the specified Java modifier
279    * flag.
280    *
281    * @param mod A modifier constant from <code>InputEvent</code>
282    *
283    * @since jEdit 4.2pre3
284    */
285   public static char getSymbolicModifierName(int mod)
286   {
287     // this relies on the fact that if C is mapped to M, then
288     // M will be mapped to C.
289     if(mod == c)
290       return 'C';
291     else if(mod == a)
292       return 'A';
293     else if(mod == m)
294       return 'M';
295     else if(mod == s)
296       return 'S';
297     else
298       return '\0';
299   } //}}}
300 
301   //{{{ modifiersToString() method
302   public static String modifiersToString(int mods)
303   {
304     StringBuffer buf = null;
305 
306     if((mods & InputEvent.CTRL_MASK) != 0)
307     {
308       if(buf == null)
309         buf = new StringBuffer();
310       buf.append(getSymbolicModifierName(InputEvent.CTRL_MASK));
311     }
312     if((mods & InputEvent.ALT_MASK) != 0)
313     {
314       if(buf == null)
315         buf = new StringBuffer();
316       buf.append(getSymbolicModifierName(InputEvent.ALT_MASK));
317     }
318     if((mods & InputEvent.META_MASK) != 0)
319     {
320       if(buf == null)
321         buf = new StringBuffer();
322       buf.append(getSymbolicModifierName(InputEvent.META_MASK));
323     }
324     if((mods & InputEvent.SHIFT_MASK) != 0)
325     {
326       if(buf == null)
327         buf = new StringBuffer();
328       buf.append(getSymbolicModifierName(InputEvent.SHIFT_MASK));
329     }
330 
331     if(buf == null)
332       return null;
333     else
334       return buf.toString();
335   } //}}}
336 
337   //{{{ getModifierString() method
338   /**
339    * Returns a string containing symbolic modifier names set in the
340    * specified event.
341    *
342    * @param evt The event
343    *
344    * @since jEdit 4.2pre3
345    */
346   public static String getModifierString(InputEvent evt)
347   {
348     StringBuffer buf = new StringBuffer();
349     if(evt.isControlDown())
350       buf.append(getSymbolicModifierName(InputEvent.CTRL_MASK));
351     if(evt.isAltDown())
352       buf.append(getSymbolicModifierName(InputEvent.ALT_MASK));
353     if(evt.isMetaDown())
354       buf.append(getSymbolicModifierName(InputEvent.META_MASK));
355     if(evt.isShiftDown())
356       buf.append(getSymbolicModifierName(InputEvent.SHIFT_MASK));
357     return (buf.length() == 0 ? null : buf.toString());
358   } //}}}
359 
360   static int c, a, m, s;
361 
362   //{{{ Private members
363   private static Map transMap = new HashMap();
364 
365   static
366   {
367     if(OperatingSystem.isMacOS())
368     {
369       setModifierMapping(
370         InputEvent.META_MASK,  /* == C+ */
371         InputEvent.CTRL_MASK,  /* == A+ */
372         /* M+ discarded by key event workaround! */
373         InputEvent.ALT_MASK,   /* == M+ */
374         InputEvent.SHIFT_MASK  /* == S+ */);
375     }
376     else
377     {
378       setModifierMapping(
379         InputEvent.CTRL_MASK,
380         InputEvent.ALT_MASK,
381         InputEvent.META_MASK,
382         InputEvent.SHIFT_MASK);
383     }
384   } //}}}
385 
386   //{{{ Key class
387   public static class Key
388   {
389     public String modifiers;
390     public int key;
391     public char input;
392 
393     public Key(String modifiers, int key, char input)
394     {
395       this.modifiers = modifiers;
396       this.key = key;
397       this.input = input;
398     }
399 
400     public int hashCode()
401     {
402       return key + input;
403     }
404 
405     public boolean equals(Object o)
406     {
407       if(o instanceof Key)
408       {
409         Key k = (Key)o;
410         if(MiscUtilities.objectsEqual(modifiers,
411           k.modifiers) && key == k.key
412           && input == k.input)
413         {
414           return true;
415         }
416       }
417 
418       return false;
419     }
420 
421     public String toString()
422     {
423       return (modifiers == null ? "" : modifiers)
424         + "<"
425         + Integer.toString(key,16)
426         + ","
427         + Integer.toString(input,16)
428         + ">";
429     }
430   } //}}}
431 }