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

Quick Search    Search Deep

Source code: jsource/syntax/DefaultInputHandler.java


1   package jsource.syntax;
2   
3   
4   /**
5    * DefaultInputHandler.java  12/17/02
6    *
7    * This program is free software; you can redistribute it and/or modify
8    * it under the terms of the GNU Library General Public License as published
9    * by the Free Software Foundation; either version 2 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU Library General Public License for more details.
16   */
17  import javax.swing.KeyStroke;
18  import java.awt.event.*;
19  import java.awt.Toolkit;
20  import java.util.Hashtable;
21  import java.util.StringTokenizer;
22  import jsource.util.JSConstants;
23  import jsource.gui.MainFrame;
24  
25  
26  /**
27   * <code>DefaultInputHandler</code> is the default input handler. It maps sequences
28   * of keystrokes into actions and inserts key typed events into the text area.
29   * @author Slava Pestov
30   * <br>Revised for JSource 2003 Panagiotis Plevrakis
31   */
32  public class DefaultInputHandler extends InputHandler {
33  
34      private Hashtable bindings = null;
35      private Hashtable currentBindings = null;
36      private MainFrame mainFrame = null;
37  
38      private DefaultInputHandler(DefaultInputHandler copy) {
39          bindings = currentBindings = copy.bindings;
40      }
41  
42      /**
43       * Creates a new input handler with no key bindings defined.
44       */
45      public DefaultInputHandler(MainFrame mainFrame) {
46          bindings = currentBindings = new Hashtable();
47          this.mainFrame = mainFrame;
48      }
49  
50      /**
51       * Sets up the default key bindings.
52       */
53      public void addDefaultKeyBindings() {
54          addKeyBinding("BACK_SPACE", BACKSPACE);
55          addKeyBinding("C+BACK_SPACE", BACKSPACE_WORD);
56          addKeyBinding("DELETE", DELETE);
57          addKeyBinding("C+DELETE", DELETE_WORD);
58  
59          addKeyBinding("ENTER", INSERT_BREAK);
60          addKeyBinding("TAB", INSERT_TAB);
61  
62          addKeyBinding("INSERT", OVERWRITE);
63          addKeyBinding("C+\\", TOGGLE_RECT);
64  
65          addKeyBinding("HOME", HOME);
66          addKeyBinding("END", END);
67          addKeyBinding("C+A", SELECT_ALL);
68          addKeyBinding("S+HOME", SELECT_HOME);
69          addKeyBinding("S+END", SELECT_END);
70          addKeyBinding("C+HOME", DOCUMENT_HOME);
71          addKeyBinding("C+END", DOCUMENT_END);
72          addKeyBinding("CS+HOME", SELECT_DOC_HOME);
73          addKeyBinding("CS+END", SELECT_DOC_END);
74  
75          addKeyBinding("PAGE_UP", PREV_PAGE);
76          addKeyBinding("PAGE_DOWN", NEXT_PAGE);
77          addKeyBinding("S+PAGE_UP", SELECT_PREV_PAGE);
78          addKeyBinding("S+PAGE_DOWN", SELECT_NEXT_PAGE);
79  
80          addKeyBinding("LEFT", PREV_CHAR);
81          addKeyBinding("S+LEFT", SELECT_PREV_CHAR);
82          addKeyBinding("C+LEFT", PREV_WORD);
83          addKeyBinding("CS+LEFT", SELECT_PREV_WORD);
84          addKeyBinding("RIGHT", NEXT_CHAR);
85          addKeyBinding("S+RIGHT", SELECT_NEXT_CHAR);
86          addKeyBinding("C+RIGHT", NEXT_WORD);
87          addKeyBinding("CS+RIGHT", SELECT_NEXT_WORD);
88          addKeyBinding("UP", PREV_LINE);
89          addKeyBinding("S+UP", SELECT_PREV_LINE);
90          addKeyBinding("DOWN", NEXT_LINE);
91          addKeyBinding("S+DOWN", SELECT_NEXT_LINE);
92  
93          addKeyBinding("C+ENTER", REPEAT);
94  
95          // Clipboard
96          addKeyBinding("C+C", CLIP_COPY);
97          addKeyBinding("C+V", CLIP_PASTE);
98          addKeyBinding("C+X", CLIP_CUT);
99      }
100 
101     /**
102      * Adds a key binding to this input handler. The key binding is
103      * a list of white space separated key strokes of the form
104      * <i>[modifiers+]key</i> where modifier is C for Control, A for Alt,
105      * or S for Shift, and key is either a character (a-z) or a field
106      * name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
107      * @param keyBinding The key binding
108      * @param action The action
109      */
110     public void addKeyBinding(String keyBinding, ActionListener action) {
111         Hashtable current = bindings;
112 
113         StringTokenizer st = new StringTokenizer(keyBinding);
114 
115         while (st.hasMoreTokens()) {
116             KeyStroke keyStroke = parseKeyStroke(st.nextToken());
117 
118             if (keyStroke == null)
119                 return;
120 
121             if (st.hasMoreTokens()) {
122                 Object o = current.get(keyStroke);
123 
124                 if (o instanceof Hashtable)
125                     current = (Hashtable) o;
126                 else {
127                     o = new Hashtable();
128                     current.put(keyStroke, o);
129                     current = (Hashtable) o;
130                 }
131             } else
132                 current.put(keyStroke, action);
133         }
134     }
135 
136     /**
137      * Removes a key binding from this input handler. This is not yet implemented.
138      * @param keyBinding The key binding
139      */
140     public void removeKeyBinding(String keyBinding) {
141         throw new InternalError("Not yet implemented");
142     }
143 
144     /**
145      * Removes all key bindings from this input handler.
146      */
147     public void removeAllKeyBindings() {
148         bindings.clear();
149     }
150 
151     /**
152      * Returns a copy of this input handler that shares the same
153      * key bindings. Setting key bindings in the copy will also
154      * set them in the original.
155      */
156     public InputHandler copy() {
157         return new DefaultInputHandler(this);
158     }
159 
160     /**
161      * Handle a key pressed event. This will look up the binding for
162      * the key stroke and execute it.
163      */
164     public void keyPressed(KeyEvent evt) {
165         int keyCode = evt.getKeyCode();
166         int modifiers = evt.getModifiers();
167 
168         if (keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_SHIFT
169                 || keyCode == KeyEvent.VK_ALT || keyCode == KeyEvent.VK_META)
170             return;
171 
172         if ((modifiers & ~KeyEvent.SHIFT_MASK) != 0 || evt.isActionKey()
173                 || keyCode == KeyEvent.VK_BACK_SPACE
174                 || keyCode == KeyEvent.VK_DELETE || keyCode == KeyEvent.VK_ENTER
175                 || keyCode == KeyEvent.VK_TAB || keyCode == KeyEvent.VK_ESCAPE) {
176             if (grabAction != null) {
177                 handleGrabAction(evt);
178                 return;
179             }
180 
181             KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode,
182                     modifiers);
183             Object o = currentBindings.get(keyStroke);
184 
185             if (o == null) {
186                 // Don't beep if the user presses some
187                 // key we don't know about unless a
188                 // prefix is active. Otherwise it will
189                 // beep when caps lock is pressed, etc.
190                 if (currentBindings != bindings) {
191                     JSConstants.TOOLKIT.beep();
192                     // F10 should be passed on, but C+e F10 shouldn't
193                     repeatCount = 0;
194                     repeat = false;
195                     evt.consume();
196                 }
197                 currentBindings = bindings;
198                 return;
199             } else if (o instanceof ActionListener) {
200                 currentBindings = bindings;
201 
202                 executeAction(((ActionListener) o),
203                         evt.getSource(), null);
204 
205                 evt.consume();
206                 return;
207             } else if (o instanceof Hashtable) {
208                 currentBindings = (Hashtable) o;
209                 evt.consume();
210                 return;
211             }
212         }
213     }
214 
215     /**
216      * Handle a key released event. Used only to stop the <code>Timer</code> that
217      * handles <code>Refresher</code> in the <code>MainFrame</code>.
218      */
219     public void keyReleased(KeyEvent evt) {
220     mainFrame.refreshTimer.stop();
221   }
222 
223     /**
224      * Handle a key typed event. This inserts the key into the text area.
225      */
226     public void keyTyped(KeyEvent evt) {
227     if (mainFrame.currFile != null) {
228       mainFrame.currFile.setFileModified(true);
229       mainFrame.refreshTimer.start();
230     }
231         int modifiers = evt.getModifiers();
232         char c = evt.getKeyChar();
233 
234         if (c != KeyEvent.CHAR_UNDEFINED && (modifiers & KeyEvent.ALT_MASK) == 0) {
235             if (c >= 0x20 && c != 0x7f) {
236                 KeyStroke keyStroke = KeyStroke.getKeyStroke(
237                         Character.toUpperCase(c));
238                 Object o = currentBindings.get(keyStroke);
239 
240                 if (o instanceof Hashtable) {
241                     currentBindings = (Hashtable) o;
242                     return;
243                 } else if (o instanceof ActionListener) {
244                     currentBindings = bindings;
245                     executeAction((ActionListener) o,
246                             evt.getSource(),
247                             String.valueOf(c));
248                     return;
249                 }
250 
251                 currentBindings = bindings;
252 
253                 if (grabAction != null) {
254                     handleGrabAction(evt);
255                     return;
256                 }
257 
258                 // 0-9 adds another 'digit' to the repeat number
259                 if (repeat && Character.isDigit(c)) {
260                     repeatCount *= 10;
261                     repeatCount += (c - '0');
262                     return;
263                 }
264 
265                 executeAction(INSERT_CHAR, evt.getSource(),
266                         String.valueOf(evt.getKeyChar()));
267 
268                 repeatCount = 0;
269                 repeat = false;
270             }
271         }
272     }
273 
274     /**
275      * Converts a string to a keystroke. The string should be of the
276      * form <i>modifiers</i>+<i>shortcut</i> where <i>modifiers</i>
277      * is any combination of A for Alt, C for Control, S for Shift
278      * or M for Meta, and <i>shortcut</i> is either a single character,
279      * or a keycode name from the <code>KeyEvent</code> class, without
280      * the <code>VK_</code> prefix.
281      * @param keyStroke A string description of the key stroke
282      */
283     public static KeyStroke parseKeyStroke(String keyStroke) {
284         if (keyStroke == null)
285             return null;
286         int modifiers = 0;
287         int index = keyStroke.indexOf('+');
288 
289         if (index != -1) {
290             for (int i = 0; i < index; i++) {
291                 switch (Character.toUpperCase(keyStroke.charAt(i))) {
292                 case 'A':
293                     modifiers |= InputEvent.ALT_MASK;
294                     break;
295 
296                 case 'C':
297                     modifiers |= InputEvent.CTRL_MASK;
298                     break;
299 
300                 case 'M':
301                     modifiers |= InputEvent.META_MASK;
302                     break;
303 
304                 case 'S':
305                     modifiers |= InputEvent.SHIFT_MASK;
306                     break;
307                 }
308             }
309         }
310         String key = keyStroke.substring(index + 1);
311 
312         if (key.length() == 1) {
313             char ch = Character.toUpperCase(key.charAt(0));
314 
315             if (modifiers == 0)
316                 return KeyStroke.getKeyStroke(ch);
317             else
318                 return KeyStroke.getKeyStroke(ch, modifiers);
319         } else if (key.length() == 0) {
320             System.err.println("Invalid key stroke: " + keyStroke);
321             return null;
322         } else {
323             int ch;
324 
325             try {
326                 ch = KeyEvent.class.getField("VK_".concat(key)).getInt(null);
327             } catch (Exception e) {
328                 System.err.println("Invalid key stroke: " + keyStroke);
329                 return null;
330             }
331 
332             return KeyStroke.getKeyStroke(ch, modifiers);
333         }
334     }
335 }