KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > jedit > gui > KeyEventWorkaround


1 /*
2  * KeyEventWorkaround.java - Works around bugs in Java event handling
3  * :tabSize=8:indentSize=8:noTabs=false:
4  * :folding=explicit:collapseFolds=1:
5  *
6  * Copyright (C) 2000, 2005 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 org.gjt.sp.jedit.Debug;
28 import org.gjt.sp.jedit.OperatingSystem;
29 import org.gjt.sp.jedit.Options;
30 import org.gjt.sp.util.Log;
31 //}}}
32

33 /**
34  * Various hacks to get keyboard event handling to behave in a consistent manner
35  * across Java implementations. This type of stuff should not be necessary, but
36  * Java's keyboard handling is crap, to put it mildly.
37  *
38  * @author Slava Pestov
39  * @version $Id: KeyEventWorkaround.java 8175 2006-12-05 20:36:33Z kpouer $
40  */

41 public class KeyEventWorkaround
42 {
43     //{{{ isBindable() method
44
public static boolean isBindable(int keyCode)
45     {
46         switch(keyCode)
47         {
48         case KeyEvent.VK_ALT:
49         case KeyEvent.VK_ALT_GRAPH:
50         case KeyEvent.VK_CONTROL:
51         case KeyEvent.VK_SHIFT:
52         case KeyEvent.VK_META:
53         case KeyEvent.VK_DEAD_GRAVE:
54         case KeyEvent.VK_DEAD_ACUTE:
55         case KeyEvent.VK_DEAD_CIRCUMFLEX:
56         case KeyEvent.VK_DEAD_TILDE:
57         case KeyEvent.VK_DEAD_MACRON:
58         case KeyEvent.VK_DEAD_BREVE:
59         case KeyEvent.VK_DEAD_ABOVEDOT:
60         case KeyEvent.VK_DEAD_DIAERESIS:
61         case KeyEvent.VK_DEAD_ABOVERING:
62         case KeyEvent.VK_DEAD_DOUBLEACUTE:
63         case KeyEvent.VK_DEAD_CARON:
64         case KeyEvent.VK_DEAD_CEDILLA:
65         case KeyEvent.VK_DEAD_OGONEK:
66         case KeyEvent.VK_DEAD_IOTA:
67         case KeyEvent.VK_DEAD_VOICED_SOUND:
68         case KeyEvent.VK_DEAD_SEMIVOICED_SOUND:
69             return false;
70         default:
71             return true;
72         }
73     } //}}}
74

75     //{{{ isPrintable() method
76
/**
77      * We need to know if a keycode can potentially result in a
78      * keytyped.
79      * @since jEdit 4.3pre2
80      */

81     public static boolean isPrintable(int keyCode)
82     {
83         switch(keyCode)
84         {
85         /* case KeyEvent.VK_ENTER:
86         case KeyEvent.VK_TAB: */

87         case KeyEvent.VK_SPACE:
88         case KeyEvent.VK_COMMA:
89         case KeyEvent.VK_MINUS:
90         case KeyEvent.VK_PERIOD:
91         case KeyEvent.VK_SLASH:
92         case KeyEvent.VK_0:
93         case KeyEvent.VK_1:
94         case KeyEvent.VK_2:
95         case KeyEvent.VK_3:
96         case KeyEvent.VK_4:
97         case KeyEvent.VK_5:
98         case KeyEvent.VK_6:
99         case KeyEvent.VK_7:
100         case KeyEvent.VK_8:
101         case KeyEvent.VK_9:
102         case KeyEvent.VK_SEMICOLON:
103         case KeyEvent.VK_EQUALS :
104         case KeyEvent.VK_A:
105         case KeyEvent.VK_B:
106         case KeyEvent.VK_C:
107         case KeyEvent.VK_D:
108         case KeyEvent.VK_E:
109         case KeyEvent.VK_F:
110         case KeyEvent.VK_G:
111         case KeyEvent.VK_H:
112         case KeyEvent.VK_I:
113         case KeyEvent.VK_J:
114         case KeyEvent.VK_K:
115         case KeyEvent.VK_L:
116         case KeyEvent.VK_M:
117         case KeyEvent.VK_N:
118         case KeyEvent.VK_O:
119         case KeyEvent.VK_P:
120         case KeyEvent.VK_Q:
121         case KeyEvent.VK_R:
122         case KeyEvent.VK_S:
123         case KeyEvent.VK_T:
124         case KeyEvent.VK_U:
125         case KeyEvent.VK_V:
126         case KeyEvent.VK_W:
127         case KeyEvent.VK_X:
128         case KeyEvent.VK_Y:
129         case KeyEvent.VK_Z:
130         case KeyEvent.VK_OPEN_BRACKET :
131         case KeyEvent.VK_BACK_SLASH :
132         case KeyEvent.VK_CLOSE_BRACKET:
133 /* case KeyEvent.VK_NUMPAD0 :
134         case KeyEvent.VK_NUMPAD1 :
135         case KeyEvent.VK_NUMPAD2 :
136         case KeyEvent.VK_NUMPAD3 :
137         case KeyEvent.VK_NUMPAD4 :
138         case KeyEvent.VK_NUMPAD5 :
139         case KeyEvent.VK_NUMPAD6 :
140         case KeyEvent.VK_NUMPAD7 :
141         case KeyEvent.VK_NUMPAD8 :
142         case KeyEvent.VK_NUMPAD9 :
143         case KeyEvent.VK_MULTIPLY:
144         case KeyEvent.VK_ADD :
145         case KeyEvent.VK_SEPARATOR:
146         case KeyEvent.VK_SUBTRACT :
147         case KeyEvent.VK_DECIMAL :
148         case KeyEvent.VK_DIVIDE : */

149         case KeyEvent.VK_BACK_QUOTE:
150         case KeyEvent.VK_QUOTE:
151         case KeyEvent.VK_DEAD_GRAVE:
152         case KeyEvent.VK_DEAD_ACUTE:
153         case KeyEvent.VK_DEAD_CIRCUMFLEX:
154         case KeyEvent.VK_DEAD_TILDE:
155         case KeyEvent.VK_DEAD_MACRON:
156         case KeyEvent.VK_DEAD_BREVE:
157         case KeyEvent.VK_DEAD_ABOVEDOT:
158         case KeyEvent.VK_DEAD_DIAERESIS:
159         case KeyEvent.VK_DEAD_ABOVERING:
160         case KeyEvent.VK_DEAD_DOUBLEACUTE:
161         case KeyEvent.VK_DEAD_CARON:
162         case KeyEvent.VK_DEAD_CEDILLA:
163         case KeyEvent.VK_DEAD_OGONEK:
164         case KeyEvent.VK_DEAD_IOTA:
165         case KeyEvent.VK_DEAD_VOICED_SOUND:
166         case KeyEvent.VK_DEAD_SEMIVOICED_SOUND:
167         case KeyEvent.VK_AMPERSAND:
168         case KeyEvent.VK_ASTERISK:
169         case KeyEvent.VK_QUOTEDBL:
170         case KeyEvent.VK_LESS:
171         case KeyEvent.VK_GREATER:
172         case KeyEvent.VK_BRACELEFT:
173         case KeyEvent.VK_BRACERIGHT:
174         case KeyEvent.VK_AT:
175         case KeyEvent.VK_COLON:
176         case KeyEvent.VK_CIRCUMFLEX:
177         case KeyEvent.VK_DOLLAR:
178         case KeyEvent.VK_EURO_SIGN:
179         case KeyEvent.VK_EXCLAMATION_MARK:
180         case KeyEvent.VK_INVERTED_EXCLAMATION_MARK:
181         case KeyEvent.VK_LEFT_PARENTHESIS:
182         case KeyEvent.VK_NUMBER_SIGN:
183         case KeyEvent.VK_PLUS:
184         case KeyEvent.VK_RIGHT_PARENTHESIS:
185         case KeyEvent.VK_UNDERSCORE:
186             return true;
187         default:
188             return false;
189         }
190     } //}}}
191

192     //{{{ isMacControl() method
193
/**
194      * Apple sucks.
195      */

196     public static boolean isMacControl(KeyEvent evt)
197     {
198         return (OperatingSystem.isMacOS() &&
199             (evt.getModifiers() & InputEvent.CTRL_MASK) != 0
200             && evt.getKeyChar() <= 0x2B);
201     } //}}}
202

203     //{{{ isNumericKeypad() method
204
public static boolean isNumericKeypad(int keyCode)
205     {
206         switch(keyCode)
207         {
208         case KeyEvent.VK_NUMPAD0:
209         case KeyEvent.VK_NUMPAD1:
210         case KeyEvent.VK_NUMPAD2:
211         case KeyEvent.VK_NUMPAD3:
212         case KeyEvent.VK_NUMPAD4:
213         case KeyEvent.VK_NUMPAD5:
214         case KeyEvent.VK_NUMPAD6:
215         case KeyEvent.VK_NUMPAD7:
216         case KeyEvent.VK_NUMPAD8:
217         case KeyEvent.VK_NUMPAD9:
218         case KeyEvent.VK_MULTIPLY:
219         case KeyEvent.VK_ADD:
220         /* case KeyEvent.VK_SEPARATOR: */
221         case KeyEvent.VK_SUBTRACT:
222         case KeyEvent.VK_DECIMAL:
223         case KeyEvent.VK_DIVIDE:
224             return true;
225         default:
226             return false;
227         }
228     } //}}}
229

230     //{{{ processKeyEvent() method
231
public static KeyEvent processKeyEvent(KeyEvent evt)
232     {
233         if (Options.SIMPLIFIED_KEY_HANDLING)
234         {
235         }
236         else
237         {
238             int keyCode = evt.getKeyCode();
239             char ch = evt.getKeyChar();
240     
241             switch(evt.getID())
242             {
243             //{{{ KEY_PRESSED...
244
case KeyEvent.KEY_PRESSED:
245                 lastKeyTime = evt.getWhen();
246                 // get rid of keys we never need to handle
247
switch(keyCode)
248                 {
249                 case '\0':
250                     return null;
251                 case KeyEvent.VK_ALT:
252                     modifiers |= InputEvent.ALT_MASK;
253                     break;
254                 case KeyEvent.VK_ALT_GRAPH:
255                     modifiers |= InputEvent.ALT_GRAPH_MASK;
256                     break;
257                 case KeyEvent.VK_CONTROL:
258                     modifiers |= InputEvent.CTRL_MASK;
259                     break;
260                 case KeyEvent.VK_SHIFT:
261                     modifiers |= InputEvent.SHIFT_MASK;
262                     break;
263                 case KeyEvent.VK_META:
264                     modifiers |= InputEvent.META_MASK;
265                     break;
266                 default:
267                     if(!evt.isMetaDown())
268                     {
269                         if(evt.isControlDown()
270                             && evt.isAltDown())
271                         {
272                             lastKeyTime = 0L;
273                         }
274                         else if(!evt.isControlDown()
275                             && !evt.isAltDown())
276                         {
277                             if(isPrintable(keyCode))
278                             {
279                                 lastKeyTime = 0L;
280                                 return null;
281                             }
282                         }
283                     }
284     
285                     if(Debug.ALT_KEY_PRESSED_DISABLED)
286                     {
287                         /* we don't handle key pressed A+ */
288                         /* they're too troublesome */
289                         if((modifiers & InputEvent.ALT_MASK) != 0)
290                             return null;
291                     }
292     
293                     if(isNumericKeypad(keyCode))
294                         last = LAST_NUMKEYPAD;
295                     else
296                         last = LAST_NOTHING;
297     
298                     break;
299                 }
300                 break;
301             //}}}
302
//{{{ KEY_TYPED...
303
case KeyEvent.KEY_TYPED:
304                 // need to let \b through so that backspace will work
305
// in HistoryTextFields
306
if(!isMacControl(evt)
307                     && (ch < 0x20 || ch == 0x7f || ch == 0xff)
308                     && ch != '\b' && ch != '\t' && ch != '\n')
309                 {
310                     return null;
311                 }
312                 
313                 if(Debug.DUMP_KEY_EVENTS)
314                 {
315                     Log.log(Log.DEBUG,"KEWa","Key event (working around): "
316                         + GrabKeyDialog.toString(evt)+": evt.getWhen()-lastKeyTime="+(evt.getWhen() - lastKeyTime)+",modifiers="+modifiers+",last="+last+".");
317                 }
318     
319                 if(evt.getWhen() - lastKeyTime < 750)
320                 {
321                     if(!Debug.ALTERNATIVE_DISPATCHER)
322                     {
323                         if(((modifiers & InputEvent.CTRL_MASK) != 0
324                             ^ (modifiers & InputEvent.ALT_MASK) != 0)
325                             || (modifiers & InputEvent.META_MASK) != 0)
326                         {
327                             return null;
328                         }
329                     }
330     
331                     // if the last key was a numeric keypad key
332
// and NumLock is off, filter it out
333
if(last == LAST_NUMKEYPAD)
334                     {
335                         last = LAST_NOTHING;
336                         if((ch >= '0' && ch <= '9') || ch == '.'
337                             || ch == '/' || ch == '*'
338                             || ch == '-' || ch == '+')
339                         {
340                             return null;
341                         }
342                     }
343                     // Windows JDK workaround
344
else if(last == LAST_ALT)
345                     {
346                         last = LAST_NOTHING;
347                         switch(ch)
348                         {
349                         case 'B':
350                         case 'M':
351                         case 'X':
352                         case 'c':
353                         case '!':
354                         case ',':
355                         case '?':
356                             return null;
357                         }
358                     }
359                 }
360                 else
361                 {
362                     if((modifiers & InputEvent.SHIFT_MASK) != 0)
363                     {
364                         switch(ch)
365                         {
366                         case '\n':
367                         case '\t':
368                             return null;
369                         }
370                     }
371                     modifiers = 0;
372                 }
373                 break;
374             //}}}
375
//{{{ KEY_RELEASED...
376
case KeyEvent.KEY_RELEASED:
377                 switch(keyCode)
378                 {
379                 case KeyEvent.VK_ALT:
380                     modifiers &= ~InputEvent.ALT_MASK;
381                     lastKeyTime = evt.getWhen();
382                     // we consume this to work around the bug
383
// where A+TAB window switching activates
384
// the menu bar on Windows.
385
evt.consume();
386                     break;
387                 case KeyEvent.VK_ALT_GRAPH:
388                     modifiers &= ~InputEvent.ALT_GRAPH_MASK;
389                     break;
390                 case KeyEvent.VK_CONTROL:
391                     modifiers &= ~InputEvent.CTRL_MASK;
392                     break;
393                 case KeyEvent.VK_SHIFT:
394                     modifiers &= ~InputEvent.SHIFT_MASK;
395                     break;
396                 case KeyEvent.VK_META:
397                     modifiers &= ~InputEvent.META_MASK;
398                     break;
399                 case KeyEvent.VK_LEFT:
400                 case KeyEvent.VK_RIGHT:
401                 case KeyEvent.VK_UP:
402                 case KeyEvent.VK_DOWN:
403                 case KeyEvent.VK_PAGE_UP:
404                 case KeyEvent.VK_PAGE_DOWN:
405                 case KeyEvent.VK_END:
406                 case KeyEvent.VK_HOME:
407                     /* workaround for A+keys producing
408                      * garbage on Windows */

409                     if(modifiers == InputEvent.ALT_MASK)
410                         last = LAST_ALT;
411                     break;
412                 }
413                 break;
414             //}}}
415
}
416         }
417         return evt;
418     } //}}}
419

420     //{{{ numericKeypadKey() method
421
/**
422      * A workaround for non-working NumLock status in some Java versions.
423      * @since jEdit 4.0pre8
424      */

425     public static void numericKeypadKey()
426     {
427         last = LAST_NOTHING;
428     } //}}}
429

430     //{{{ Package-private members
431
static long lastKeyTime;
432     static int modifiers;
433     //}}}
434

435     //{{{ Private members
436
private static int last;
437     private static final int LAST_NOTHING = 0;
438     private static final int LAST_NUMKEYPAD = 1;
439     private static final int LAST_ALT = 2;
440     //}}}
441
}
442
Popular Tags