2 JPC-RR: A x86 PC Hardware Emulator
5 Copyright (C) 2007-2009 Isis Innovation Limited
6 Copyright (C) 2009-2010 H. Ilari Liusvaara
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 2 as published by
10 the Free Software Foundation.
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 General Public License for more details.
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 Based on JPC x86 PC Hardware emulator,
22 A project from the Physics Dept, The University of Oxford
24 Details about original JPC can be found at:
26 www-jpc.physics.ox.ac.uk
30 package org
.jpc
.plugins
;
32 import org
.jpc
.emulator
.peripheral
.Keyboard
;
33 import org
.jpc
.emulator
.KeyboardStatusListener
;
34 import org
.jpc
.pluginsbase
.Plugins
;
35 import org
.jpc
.pluginsbase
.Plugin
;
36 import org
.jpc
.pluginsaux
.ConstantTableLayout
;
37 import static org
.jpc
.Misc
.errorDialog
;
38 import static org
.jpc
.Misc
.moveWindow
;
42 import java
.awt
.event
.*;
45 public class VirtualKeyboard
implements ActionListener
, Plugin
, KeyboardStatusListener
47 private JFrame window
;
49 private HashMap
<String
, Integer
> commandToKey
;
50 private HashMap
<String
, JToggleButton
> commandToButton
;
51 private JToggleButton capsLock
;
52 private JToggleButton numLock
;
53 private JToggleButton scrollLock
;
54 private org
.jpc
.emulator
.peripheral
.Keyboard keyboard
;
56 private boolean[] cachedState
;
57 private Plugins pluginManager
;
58 private int nativeWidth
, nativeHeight
;
60 public void addKey(String name
, int scanCode
, int x
, int y
, int w
, int h
)
62 String cmdName
= name
+ "-" + (keyNo
++);
63 JToggleButton button
= new JToggleButton(name
, false);
64 commandToKey
.put(cmdName
, new Integer(scanCode
));
65 commandToButton
.put(cmdName
, button
);
66 ConstantTableLayout
.Placement c
= new ConstantTableLayout
.Placement(x
, y
, w
, h
);
68 button
.setActionCommand(cmdName
);
69 button
.addActionListener(this);
72 public JToggleButton
addSpecial(String name
, String text
, int x
, int y
, int w
, int h
)
74 ConstantTableLayout
.Placement c
= new ConstantTableLayout
.Placement(x
, y
, w
, h
);
75 JToggleButton button
= new JToggleButton(text
, false);
77 button
.setEnabled(false);
78 button
.setVisible(false);
82 public void eci_virtualkeyboard_setwinpos(Integer x
, Integer y
)
84 moveWindow(window
, x
.intValue(), y
.intValue(), nativeWidth
, nativeHeight
);
88 public VirtualKeyboard(Plugins _pluginManager
)
90 pluginManager
= _pluginManager
;
93 commandToKey
= new HashMap
<String
, Integer
>();
94 commandToButton
= new HashMap
<String
, JToggleButton
>();
95 window
= new JFrame("Virtual Keyboard");
96 ConstantTableLayout layout
= new ConstantTableLayout();
97 cachedState
= new boolean[256];
98 panel
= new JPanel(layout
);
100 addKey("Esc", 1, 0, 0, 3, 2); //Hack: W should be 2, but we use 3 to make keyboard narrower.
101 addKey("F1", 59, 4, 0, 2, 2);
102 addKey("F2", 60, 6, 0, 2, 2);
103 addKey("F3", 61, 8, 0, 2, 2);
104 addKey("F4", 62, 10, 0, 2, 2);
105 addKey("F5", 63, 13, 0, 2, 2);
106 addKey("F6", 64, 15, 0, 2, 2);
107 addKey("F7", 65, 17, 0, 2, 2);
108 addKey("F8", 66, 19, 0, 2, 2);
109 addKey("F9", 67, 22, 0, 2, 2);
110 addKey("FA", 68, 24, 0, 2, 2);
111 addKey("FB", 87, 26, 0, 2, 2);
112 addKey("FC", 88, 28, 0, 2, 2);
113 addKey("PS", 128 + 55, 31, 0, 2, 2);
114 addKey("SL", 70, 33, 0, 2, 2);
115 addKey("PA", 255, 35, 0, 2, 2);
117 numLock
= addSpecial("NumLock", "N", 38, 0, 2, 2);
118 capsLock
= addSpecial("CapsLock", "C", 40, 0, 2, 2);
119 scrollLock
= addSpecial("ScrollLock", "S", 42, 0, 2, 2);
121 addKey("1", 2, 2, 4, 2, 2);
122 addKey("2", 3, 4, 4, 2, 2);
123 addKey("3", 4, 6, 4, 2, 2);
124 addKey("4", 5, 8, 4, 2, 2);
125 addKey("5", 6, 10, 4, 2, 2);
126 addKey("6", 7, 12, 4, 2, 2);
127 addKey("7", 8, 14, 4, 2, 2);
128 addKey("8", 9, 16, 4, 2, 2);
129 addKey("9", 10, 18, 4, 2, 2);
130 addKey("0", 11, 20, 4, 2, 2);
131 addKey("-", 12, 22, 4, 2, 2);
132 addKey("=", 13, 24, 4, 2, 2);
133 addKey("BS", 14, 26, 4, 4, 2);
134 addKey("I", 128 + 82, 31, 4, 2, 2);
135 addKey("H", 128 + 71, 33, 4, 2, 2);
136 addKey("PU", 128 + 73, 35, 4, 2, 2);
137 addKey("NL", 69, 38, 4, 2, 2);
138 addKey("/", 128 + 53, 40, 4, 2, 2);
139 addKey("*", 55, 42, 4, 2, 2);
140 addKey("-", 74, 44, 4, 2, 2);
142 addKey("Tab", 15, 0, 6, 3, 2);
143 addKey("Q", 16, 3, 6, 2, 2);
144 addKey("W", 17, 5, 6, 2, 2);
145 addKey("E", 18, 7, 6, 2, 2);
146 addKey("R", 19, 9, 6, 2, 2);
147 addKey("T", 20, 11, 6, 2, 2);
148 addKey("Y", 21, 13, 6, 2, 2);
149 addKey("U", 22, 15, 6, 2, 2);
150 addKey("I", 23, 17, 6, 2, 2);
151 addKey("O", 24, 19, 6, 2, 2);
152 addKey("P", 25, 21, 6, 2, 2);
153 addKey("[", 26, 23, 6, 2, 2);
154 addKey("]", 27, 25, 6, 2, 2);
155 addKey("EN", 28, 28, 6, 2, 4);
156 addKey("D", 128 + 83, 31, 6, 2, 2);
157 addKey("E", 128 + 79, 33, 6, 2, 2);
158 addKey("PD", 128 + 81, 35, 6, 2, 2);
159 addKey("7", 71, 38, 6, 2, 2);
160 addKey("8", 72, 40, 6, 2, 2);
161 addKey("9", 73, 42, 6, 2, 2);
162 addKey("+", 78, 44, 6, 2, 4);
164 addKey("CL", 58, 0, 8, 4, 2);
165 addKey("A", 30, 4, 8, 2, 2);
166 addKey("S", 31, 6, 8, 2, 2);
167 addKey("D", 32, 8, 8, 2, 2);
168 addKey("F", 33, 10, 8, 2, 2);
169 addKey("G", 34, 12, 8, 2, 2);
170 addKey("H", 35, 14, 8, 2, 2);
171 addKey("J", 36, 16, 8, 2, 2);
172 addKey("K", 37, 18, 8, 2, 2);
173 addKey("L", 38, 20, 8, 2, 2);
174 addKey(";", 39, 22, 8, 2, 2);
175 addKey("'", 40, 24, 8, 2, 2);
176 addKey("`", 41, 26, 8, 2, 2);
177 addKey("4", 75, 38, 8, 2, 2);
178 addKey("5", 76, 40, 8, 2, 2);
179 addKey("6", 77, 42, 8, 2, 2);
181 addKey("SH", 42, 0, 10, 3, 2);
182 addKey("\\", 43, 3, 10, 2, 2);
183 addKey("Z", 44, 5, 10, 2, 2);
184 addKey("X", 45, 7, 10, 2, 2);
185 addKey("C", 46, 9, 10, 2, 2);
186 addKey("V", 47, 11, 10, 2, 2);
187 addKey("B", 48, 13, 10, 2, 2);
188 addKey("N", 49, 15, 10, 2, 2);
189 addKey("M", 50, 17, 10, 2, 2);
190 addKey(",", 51, 19, 10, 2, 2);
191 addKey(".", 52, 21, 10, 2, 2);
192 addKey("/", 53, 23, 10, 2, 2);
193 addKey("SH", 54, 25, 10, 5, 2);
194 addKey("^", 128 + 72, 33, 10, 2, 2);
195 addKey("1", 79, 38, 10, 2, 2);
196 addKey("2", 80, 40, 10, 2, 2);
197 addKey("3", 81, 42, 10, 2, 2);
198 addKey("EN", 128 + 28, 44, 10, 2, 4);
200 addKey("CT", 29, 0, 12, 3, 2);
201 addKey("AL", 56, 5, 12, 3, 2);
202 addKey("SP", 57, 8, 12, 14, 2);
203 addKey("AL", 128 + 56, 22, 12, 3, 2);
204 addKey("CT", 128 + 29, 27, 12, 3, 2);
205 addKey("<", 128 + 75, 31, 12, 2, 2);
206 addKey("v", 128 + 80, 33, 12, 2, 2 );
207 addKey(">", 128 + 77, 35, 12, 2, 2 );
208 addKey("0", 82, 38, 12, 4, 2);
209 addKey(".", 83, 42, 12, 2, 2);
212 window
.setDefaultCloseOperation(JFrame
.DO_NOTHING_ON_CLOSE
);
213 Dimension d
= window
.getSize();
214 nativeWidth
= d
.width
;
215 nativeHeight
= d
.height
;
216 window
.setVisible(true);
219 //-1 if unknonw, bit 2 is capslock, bit 1 is numlock, bit 0 is scrollock.
220 private void updateLEDs(int status
)
223 numLock
.setVisible(false);
224 numLock
.setSelected(false);
225 capsLock
.setVisible(false);
226 capsLock
.setSelected(false);
227 scrollLock
.setVisible(false);
228 scrollLock
.setSelected(false);
230 numLock
.setVisible(true);
231 capsLock
.setVisible(true);
232 scrollLock
.setVisible(true);
233 numLock
.setSelected((status
& 2) != 0);
234 capsLock
.setSelected((status
& 4) != 0);
235 scrollLock
.setSelected((status
& 1) != 0);
239 public void resetButtons()
241 for(Map
.Entry
<String
, Integer
> entry
: commandToKey
.entrySet()) {
242 int scan
= entry
.getValue().intValue();
243 JToggleButton button
= commandToButton
.get(entry
.getKey());
244 if(keyboard
.getKeyStatus((byte)scan
) != cachedState
[scan
]) {
245 cachedState
[scan
] = keyboard
.getKeyStatus((byte)scan
);
246 button
.setSelected(cachedState
[scan
]);
249 updateLEDs(keyboard
.getLEDStatus());
252 private void keyStatusChangeEventThread(int scancode
, boolean pressed
)
254 /* THIS IS JUST PLAIN BROKEN.
255 for(Map.Entry<String, Integer> entry : commandToKey.entrySet()) {
256 int scan = entry.getValue().intValue();
259 JToggleButton button = commandToButton.get(entry.getKey());
260 if(pressed != cachedState[scan]) {
261 cachedState[scan] = pressed;
262 button.setSelected(pressed);
268 public void keyExecStatusChange(int scancode
, boolean pressed
)
270 //These aren't currently shown.
273 public void keyStatusChange(int scancode
, boolean pressed
)
275 if(!SwingUtilities
.isEventDispatchThread())
277 final int _scancode
= scancode
;
278 final boolean _pressed
= pressed
;
279 SwingUtilities
.invokeLater(new Thread() { public void run() { VirtualKeyboard
.this.keyStatusChangeEventThread(_scancode
, _pressed
); }});
280 } catch(Exception e
) {
283 keyStatusChangeEventThread(scancode
, pressed
);
286 public void keyStatusReload()
288 if(!SwingUtilities
.isEventDispatchThread())
290 SwingUtilities
.invokeLater(new Thread() { public void run() { VirtualKeyboard
.this.resetButtons(); }});
291 } catch(Exception e
) {
297 public void ledStatusChange(int newstatus
)
299 if(!SwingUtilities
.isEventDispatchThread())
301 final int _newstatus
= newstatus
;
302 SwingUtilities
.invokeLater(new Thread() { public void run() { VirtualKeyboard
.this.updateLEDs(_newstatus
); }});
303 } catch(Exception e
) {
306 updateLEDs(newstatus
);
309 public void mouseButtonsChange(int newstatus
)
314 public void mouseExecButtonsChange(int newstatus
)
321 //This runs entierely in UI thread.
324 public boolean systemShutdown()
326 //OK to proceed with JVM shutdown.
330 public void pcStarting()
335 public void pcStopping()
337 if(pluginManager
.isShuttingDown())
338 return; //Too much of deadlock risk.
340 if(!SwingUtilities
.isEventDispatchThread())
342 SwingUtilities
.invokeAndWait(new Thread() { public void run() { VirtualKeyboard
.this.resetButtons(); }});
343 } catch(Exception e
) {
349 public void reconnect(org
.jpc
.emulator
.PC pc
)
352 keyboard
.removeStatusListener(this);
354 Keyboard keys
= (Keyboard
)pc
.getComponent(Keyboard
.class);
356 keyboard
.addStatusListener(this);
360 Iterator
<Map
.Entry
<String
, Integer
> > itt
= commandToKey
.entrySet().iterator();
361 while (itt
.hasNext())
363 Map
.Entry
<String
, Integer
> entry
= itt
.next();
364 String n
= entry
.getKey();
365 Integer s
= entry
.getValue();
366 cachedState
[s
.intValue()] = false;
367 commandToButton
.get(n
).setSelected(false);
373 public void actionPerformed(ActionEvent evt
)
378 String command
= evt
.getActionCommand();
379 JToggleButton button
= commandToButton
.get(command
);
380 int scan
= commandToKey
.get(command
).intValue();
381 if(button
.isSelected())
382 System
.err
.println("Informational: Keydown on key " + scan
+ ".");
384 System
.err
.println("Informational: Keyup on key " + scan
+ ".");
386 keyboard
.sendEdge(scan
);
387 if(scan
!= 255 && (evt
.getModifiers() & ActionEvent
.SHIFT_MASK
) != 0)
388 keyboard
.sendEdge(scan
);
389 } catch(Exception e
) {
390 System
.err
.println("Error: Sending command failed: " + e
);
391 errorDialog(e
, "Failed to send keyboard key edge", null, "Dismiss");
393 if(scan
!= 255 && (evt
.getModifiers() & ActionEvent
.SHIFT_MASK
) == 0)
394 cachedState
[scan
] = !cachedState
[scan
];
395 button
.setSelected(cachedState
[scan
]);