Source code: org/gjt/sp/jedit/gui/KeyEventWorkaround.java
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, 2001, 2002 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.*;
28 import org.gjt.sp.jedit.OperatingSystem;
29 //}}}
30
31 /**
32 * This class contains various hacks to get keyboard event handling to behave in
33 * a consistent manner across Java implementations, many of which are
34 * hopelessly broken in this regard.
35 *
36 * @author Slava Pestov
37 * @version $Id: KeyEventWorkaround.java,v 1.3 2002/10/25 17:29:57 gfx Exp $
38 */
39 public class KeyEventWorkaround
40 {
41 //{{{ processKeyEvent() method
42 public static KeyEvent processKeyEvent(KeyEvent evt)
43 {
44 int keyCode = evt.getKeyCode();
45 char ch = evt.getKeyChar();
46
47 switch(evt.getID())
48 {
49 //{{{ KEY_PRESSED...
50 case KeyEvent.KEY_PRESSED:
51 // get rid of keys we never need to handle
52 switch(keyCode)
53 {
54 case KeyEvent.VK_ALT:
55 case KeyEvent.VK_ALT_GRAPH:
56 case KeyEvent.VK_CONTROL:
57 case KeyEvent.VK_SHIFT:
58 case KeyEvent.VK_META:
59 case KeyEvent.VK_DEAD_GRAVE:
60 case KeyEvent.VK_DEAD_ACUTE:
61 case KeyEvent.VK_DEAD_CIRCUMFLEX:
62 case KeyEvent.VK_DEAD_TILDE:
63 case KeyEvent.VK_DEAD_MACRON:
64 case KeyEvent.VK_DEAD_BREVE:
65 case KeyEvent.VK_DEAD_ABOVEDOT:
66 case KeyEvent.VK_DEAD_DIAERESIS:
67 case KeyEvent.VK_DEAD_ABOVERING:
68 case KeyEvent.VK_DEAD_DOUBLEACUTE:
69 case KeyEvent.VK_DEAD_CARON:
70 case KeyEvent.VK_DEAD_CEDILLA:
71 case KeyEvent.VK_DEAD_OGONEK:
72 case KeyEvent.VK_DEAD_IOTA:
73 case KeyEvent.VK_DEAD_VOICED_SOUND:
74 case KeyEvent.VK_DEAD_SEMIVOICED_SOUND:
75 case '\0':
76 return null;
77 default:
78
79 if(!OperatingSystem.isMacOS())
80 handleBrokenKeys(evt,keyCode);
81 else
82 last = LAST_NOTHING;
83 break;
84 }
85
86 return evt;
87 //}}}
88 //{{{ KEY_TYPED...
89 case KeyEvent.KEY_TYPED:
90 // need to let \b through so that backspace will work
91 // in HistoryTextFields
92 if((ch < 0x20 || ch == 0x7f || ch == 0xff) && ch != '\b')
93 return null;
94
95 // "Alt" is the option key on MacOS, and it can generate
96 // user input
97 if(OperatingSystem.isMacOS())
98 {
99 if(evt.isControlDown() || evt.isMetaDown())
100 return null;
101 }
102 else
103 {
104 if((evt.isControlDown() ^ evt.isAltDown())
105 || evt.isMetaDown())
106 return null;
107 }
108
109 // On JDK 1.4 with Windows, some Alt-key sequences send
110 // bullshit in a KEY_TYPED afterwards. We filter it out
111 // here
112 if(last == LAST_MOD)
113 {
114 switch(ch)
115 {
116 case 'B':
117 case 'M':
118 case 'X':
119 case 'c':
120 case '!':
121 case ',':
122 case '?':
123 last = LAST_NOTHING;
124 return null;
125 }
126 }
127
128 // if the last key was a broken key, filter
129 // out all except 'a'-'z' that occur 750 ms after.
130 else if(last == LAST_BROKEN && System.currentTimeMillis()
131 - lastKeyTime < 750 && !Character.isLetter(ch))
132 {
133 last = LAST_NOTHING;
134 return null;
135 }
136 // otherwise, if it was ALT, filter out everything.
137 else if(last == LAST_ALT && System.currentTimeMillis()
138 - lastKeyTime < 750)
139 {
140 last = LAST_NOTHING;
141 return null;
142 }
143
144 return evt;
145 //}}}
146 //{{{ KEY_RELEASED...
147 case KeyEvent.KEY_RELEASED:
148 if(keyCode == KeyEvent.VK_ALT)
149 {
150 // bad workaround... on Windows JDK 1.4, some
151 // Alt-sequences generate random crap afterwards
152 if(OperatingSystem.isWindows()
153 && OperatingSystem.hasJava14())
154 last = LAST_MOD;
155 }
156 return evt;
157 //}}}
158 default:
159 return evt;
160 }
161 } //}}}
162
163 //{{{ numericKeypadKey() method
164 /**
165 * A workaround for non-working NumLock status in some Java versions.
166 * @since jEdit 4.0pre8
167 */
168 public static void numericKeypadKey()
169 {
170 last = LAST_NOTHING;
171 } //}}}
172
173 //{{{ Private members
174
175 //{{{ Static variables
176 private static long lastKeyTime;
177
178 private static int last;
179 private static final int LAST_NOTHING = 0;
180 private static final int LAST_ALT = 1;
181 private static final int LAST_BROKEN = 2;
182 private static final int LAST_NUMKEYPAD = 3;
183 private static final int LAST_MOD = 4;
184 //}}}
185
186 //{{{ handleBrokenKeys() method
187 private static void handleBrokenKeys(KeyEvent evt, int keyCode)
188 {
189 if(evt.isAltDown() && evt.isControlDown()
190 && !evt.isMetaDown())
191 {
192 last = LAST_NOTHING;
193 return;
194 }
195 else if(!(evt.isAltDown() || evt.isControlDown() || evt.isMetaDown()))
196 {
197 last = LAST_NOTHING;
198 return;
199 }
200
201 if(evt.isAltDown())
202 last = LAST_ALT;
203
204 switch(keyCode)
205 {
206 case KeyEvent.VK_LEFT: case KeyEvent.VK_RIGHT:
207 case KeyEvent.VK_UP: case KeyEvent.VK_DOWN:
208 case KeyEvent.VK_DELETE: case KeyEvent.VK_BACK_SPACE:
209 case KeyEvent.VK_TAB: case KeyEvent.VK_ENTER:
210 last = LAST_NOTHING;
211 break;
212 default:
213 if(keyCode < KeyEvent.VK_A || keyCode > KeyEvent.VK_Z)
214 last = LAST_BROKEN;
215 else
216 last = LAST_NOTHING;
217 break;
218 }
219
220 lastKeyTime = System.currentTimeMillis();
221 } //}}}
222
223 //}}}
224 }