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/DefaultInputHandler.java


1   /*
2    * DefaultInputHandler.java - Default implementation of an input handler
3    * :tabSize=8:indentSize=8:noTabs=false:
4    * :folding=explicit:collapseFolds=1:
5    *
6    * Copyright (C) 1999, 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 javax.swing.KeyStroke;
27  import java.awt.event.KeyEvent;
28  import java.awt.event.InputEvent;
29  import java.awt.Toolkit;
30  import java.util.Hashtable;
31  import java.util.StringTokenizer;
32  import org.gjt.sp.jedit.*;
33  import org.gjt.sp.util.Log;
34  //}}}
35  
36  /**
37   * The default input handler. It maps sequences of keystrokes into actions
38   * and inserts key typed events into the text area.
39   * @author Slava Pestov
40   * @version $Id: DefaultInputHandler.java,v 1.37 2003/08/28 22:05:24 spestov Exp $
41   */
42  public class DefaultInputHandler extends InputHandler
43  {
44    //{{{ DefaultInputHandler constructor
45    /**
46     * Creates a new input handler with no key bindings defined.
47     * @param view The view
48     */
49    public DefaultInputHandler(View view)
50    {
51      super(view);
52  
53      bindings = currentBindings = new Hashtable();
54    } //}}}
55  
56    //{{{ DefaultInputHandler constructor
57    /**
58     * Creates a new input handler with the same set of key bindings
59     * as the one specified. Note that both input handlers share
60     * a pointer to exactly the same key binding table; so adding
61     * a key binding in one will also add it to the other.
62     * @param copy The input handler to copy key bindings from
63     * @param view The view
64     */
65    public DefaultInputHandler(View view, DefaultInputHandler copy)
66    {
67      super(view);
68  
69      bindings = currentBindings = copy.bindings;
70    } //}}}
71  
72    //{{{ addKeyBinding() method
73    /**
74     * Adds a key binding to this input handler. The key binding is
75     * a list of white space separated key strokes of the form
76     * <i>[modifiers+]key</i> where modifier is C for Control, A for Alt,
77     * or S for Shift, and key is either a character (a-z) or a field
78     * name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
79     * @param keyBinding The key binding
80     * @param action The action
81     * @since jEdit 4.2pre1
82     */
83    public void addKeyBinding(String keyBinding, String action)
84    {
85      _addKeyBinding(keyBinding,(Object)action);
86    } //}}}
87  
88    //{{{ addKeyBinding() method
89    /**
90     * Adds a key binding to this input handler. The key binding is
91     * a list of white space separated key strokes of the form
92     * <i>[modifiers+]key</i> where modifier is C for Control, A for Alt,
93     * or S for Shift, and key is either a character (a-z) or a field
94     * name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
95     * @param keyBinding The key binding
96     * @param action The action
97     */
98    public void addKeyBinding(String keyBinding, EditAction action)
99    {
100     _addKeyBinding(keyBinding,(Object)action);
101   } //}}}
102 
103   //{{{ removeKeyBinding() method
104   /**
105    * Removes a key binding from this input handler. This is not yet
106    * implemented.
107    * @param keyBinding The key binding
108    */
109   public void removeKeyBinding(String keyBinding)
110   {
111     Hashtable current = bindings;
112 
113     StringTokenizer st = new StringTokenizer(keyBinding);
114     while(st.hasMoreTokens())
115     {
116       String keyCodeStr = st.nextToken();
117       KeyEventTranslator.Key keyStroke = KeyEventTranslator.parseKey(keyCodeStr);
118       if(keyStroke == null)
119         return;
120 
121       if(st.hasMoreTokens())
122       {
123         Object o = current.get(keyStroke);
124         if(o instanceof Hashtable)
125           current = ((Hashtable)o);
126         else if(o != null)
127         {
128           // we have binding foo
129           // but user asks to remove foo bar?
130           current.remove(keyStroke);
131           return;
132         }
133         else
134         {
135           // user asks to remove non-existent
136           return;
137         }
138       }
139       else
140         current.remove(keyStroke);
141     }
142   } //}}}
143 
144   //{{{ removeAllKeyBindings() method
145   /**
146    * Removes all key bindings from this input handler.
147    */
148   public void removeAllKeyBindings()
149   {
150     bindings.clear();
151   } //}}}
152 
153   //{{{ getKeyBinding() method
154   /**
155    * Returns either an edit action, or a hashtable if the specified key
156    * is a prefix.
157    * @param keyBinding The key binding
158    * @since jEdit 3.2pre5
159    */
160   public Object getKeyBinding(String keyBinding)
161   {
162     Hashtable current = bindings;
163     StringTokenizer st = new StringTokenizer(keyBinding);
164 
165     while(st.hasMoreTokens())
166     {
167       KeyEventTranslator.Key keyStroke = KeyEventTranslator.parseKey(keyBinding);
168       if(keyStroke == null)
169         return null;
170 
171       if(st.hasMoreTokens())
172       {
173         Object o = current.get(keyStroke);
174         if(o instanceof Hashtable)
175           current = (Hashtable)o;
176         else
177           return o;
178       }
179       else
180       {
181         return current.get(keyStroke);
182       }
183     }
184 
185     return null;
186   } //}}}
187 
188   //{{{ isPrefixActive() method
189   /**
190    * Returns if a prefix key has been pressed.
191    */
192   public boolean isPrefixActive()
193   {
194     return bindings != currentBindings;
195   } //}}}
196 
197   //{{{ handleKey() method
198   /**
199    * Handles the given keystroke.
200    * @param keyStroke The key stroke
201    * @since jEdit 4.2pre5
202    */
203   public boolean handleKey(KeyEventTranslator.Key keyStroke)
204   {
205     char input = '\0';
206     if(keyStroke.modifiers == null
207       || keyStroke.modifiers.equals("S"))
208     {
209       switch(keyStroke.key)
210       {
211       case '\n':
212       case '\t':
213         input = (char)keyStroke.key;
214         break;
215       default:
216         input = keyStroke.input;
217         break;
218       }
219     }
220 
221     if(readNextChar != null)
222     {
223       if(input != '\0')
224       {
225         setCurrentBindings(bindings);
226         invokeReadNextChar(input);
227         repeatCount = 1;
228         return true;
229       }
230       else
231       {
232         readNextChar = null;
233         view.getStatus().setMessage(null);
234       }
235     }
236 
237     Object o = currentBindings.get(keyStroke);
238     if(o == null)
239     {
240       // Don't beep if the user presses some
241       // key we don't know about unless a
242       // prefix is active. Otherwise it will
243       // beep when caps lock is pressed, etc.
244       if(currentBindings != bindings)
245       {
246         Toolkit.getDefaultToolkit().beep();
247         // F10 should be passed on, but C+e F10
248         // shouldn't
249         repeatCount = 1;
250         setCurrentBindings(bindings);
251       }
252 
253       if(input != '\0')
254         userInput(input);
255       else
256       {
257         // this is retarded. excuse me while I drool
258         // and make stupid noises
259         switch(keyStroke.key)
260         {
261         case KeyEvent.VK_NUMPAD0:
262         case KeyEvent.VK_NUMPAD1:
263         case KeyEvent.VK_NUMPAD2:
264         case KeyEvent.VK_NUMPAD3:
265         case KeyEvent.VK_NUMPAD4:
266         case KeyEvent.VK_NUMPAD5:
267         case KeyEvent.VK_NUMPAD6:
268         case KeyEvent.VK_NUMPAD7:
269         case KeyEvent.VK_NUMPAD8:
270         case KeyEvent.VK_NUMPAD9:
271         case KeyEvent.VK_MULTIPLY:
272         case KeyEvent.VK_ADD:
273         /* case KeyEvent.VK_SEPARATOR: */
274         case KeyEvent.VK_SUBTRACT:
275         case KeyEvent.VK_DECIMAL:
276         case KeyEvent.VK_DIVIDE:
277           KeyEventWorkaround.numericKeypadKey();
278           break;
279         }
280       }
281     }
282     else if(o instanceof Hashtable)
283     {
284       setCurrentBindings((Hashtable)o);
285       return true;
286     }
287     else if(o instanceof String)
288     {
289       setCurrentBindings(bindings);
290       invokeAction((String)o);
291       return true;
292     }
293     else if(o instanceof EditAction)
294     {
295       setCurrentBindings(bindings);
296       invokeAction((EditAction)o);
297       return true;
298     }
299 
300     return false;
301   } //}}}
302 
303   //{{{ getSymbolicModifierName() method
304   /**
305    * Returns a the symbolic modifier name for the specified Java modifier
306    * flag.
307    *
308    * @param mod A modifier constant from <code>InputEvent</code>
309    *
310    * @since jEdit 4.1pre3
311    */
312   public static char getSymbolicModifierName(int mod)
313   {
314     return KeyEventTranslator.getSymbolicModifierName(mod);
315   } //}}}
316 
317   //{{{ getModifierString() method
318   /**
319    * Returns a string containing symbolic modifier names set in the
320    * specified event.
321    *
322    * @param evt The event
323    *
324    * @since jEdit 4.1pre3
325    */
326   public static String getModifierString(InputEvent evt)
327   {
328     return KeyEventTranslator.getModifierString(evt);
329   } //}}}
330 
331   //{{{ parseKeyStroke() method
332   /**
333    * @deprecated We don't use Swing KeyStrokes anymore.
334    */
335   public static KeyStroke parseKeyStroke(String keyStroke)
336   {
337     if(keyStroke == null)
338       return null;
339     int modifiers = 0;
340     int index = keyStroke.indexOf('+');
341     if(index != -1)
342     {
343       for(int i = 0; i < index; i++)
344       {
345         switch(Character.toUpperCase(keyStroke
346           .charAt(i)))
347         {
348         case 'A':
349           modifiers |= KeyEventTranslator.a;
350           break;
351         case 'C':
352           modifiers |= KeyEventTranslator.c;
353           break;
354         case 'M':
355           modifiers |= KeyEventTranslator.m;
356           break;
357         case 'S':
358           modifiers |= KeyEventTranslator.s;
359           break;
360         }
361       }
362     }
363     String key = keyStroke.substring(index + 1);
364     if(key.length() == 1)
365     {
366       char ch = key.charAt(0);
367       if(modifiers == 0)
368         return KeyStroke.getKeyStroke(ch);
369       else
370       {
371         return KeyStroke.getKeyStroke(Character.toUpperCase(ch),
372           modifiers);
373       }
374     }
375     else if(key.length() == 0)
376     {
377       Log.log(Log.ERROR,DefaultInputHandler.class,
378         "Invalid key stroke: " + keyStroke);
379       return null;
380     }
381     else
382     {
383       int ch;
384 
385       try
386       {
387         ch = KeyEvent.class.getField("VK_".concat(key))
388           .getInt(null);
389       }
390       catch(Exception e)
391       {
392         Log.log(Log.ERROR,DefaultInputHandler.class,
393           "Invalid key stroke: "
394           + keyStroke);
395         return null;
396       }
397 
398       return KeyStroke.getKeyStroke(ch,modifiers);
399     }
400   } //}}}
401 
402   //{{{ Private members
403 
404   // Stores prefix name in bindings hashtable
405   private static Object PREFIX_STR = "PREFIX_STR";
406 
407   private Hashtable bindings;
408   private Hashtable currentBindings;
409 
410   //{{{ setCurrentBindings() method
411   private void setCurrentBindings(Hashtable bindings)
412   {
413     view.getStatus().setMessage((String)bindings.get(PREFIX_STR));
414     currentBindings = bindings;
415   } //}}}
416 
417   //{{{ _addKeyBinding() method
418   /**
419    * Adds a key binding to this input handler. The key binding is
420    * a list of white space separated key strokes of the form
421    * <i>[modifiers+]key</i> where modifier is C for Control, A for Alt,
422    * or S for Shift, and key is either a character (a-z) or a field
423    * name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
424    * @param keyBinding The key binding
425    * @param action The action
426    */
427   public void _addKeyBinding(String keyBinding, Object action)
428   {
429     Hashtable current = bindings;
430 
431     String prefixStr = null;
432 
433     StringTokenizer st = new StringTokenizer(keyBinding);
434     while(st.hasMoreTokens())
435     {
436       String keyCodeStr = st.nextToken();
437       if(prefixStr == null)
438         prefixStr = keyCodeStr;
439       else
440         prefixStr = prefixStr + " " + keyCodeStr;
441 
442       KeyEventTranslator.Key keyStroke = KeyEventTranslator.parseKey(keyCodeStr);
443       if(keyStroke == null)
444         return;
445 
446       if(st.hasMoreTokens())
447       {
448         Object o = current.get(keyStroke);
449         if(o instanceof Hashtable)
450           current = (Hashtable)o;
451         else
452         {
453           Hashtable hash = new Hashtable();
454           hash.put(PREFIX_STR,prefixStr);
455           o = hash;
456           current.put(keyStroke,o);
457           current = (Hashtable)o;
458         }
459       }
460       else
461         current.put(keyStroke,action);
462     }
463   } //}}}
464 
465   //}}}
466 }