source: trunk/src/org/expeditee/gio/swing/SwingInputManager.java@ 1130

Last change on this file since 1130 was 1130, checked in by bln4, 6 years ago

org.expeditee.gio.swing.SwingInputManager ->

Potential fix for out of order typing error. To be discussed with David. If no follow up assume Bryce's awesomeness.

File size: 14.5 KB
Line 
1package org.expeditee.gio.swing;
2
3import java.awt.AWTException;
4import java.awt.Color;
5import java.awt.MouseInfo;
6import java.awt.Robot;
7import java.awt.event.ActionEvent;
8import java.awt.event.ActionListener;
9import java.awt.event.ComponentEvent;
10import java.awt.event.ComponentListener;
11import java.awt.event.KeyEvent;
12import java.awt.event.KeyListener;
13import java.awt.event.MouseEvent;
14import java.awt.event.MouseListener;
15import java.awt.event.MouseMotionListener;
16import java.awt.event.MouseWheelEvent;
17import java.awt.event.MouseWheelListener;
18import java.awt.event.WindowEvent;
19import java.awt.event.WindowListener;
20import java.awt.event.WindowStateListener;
21
22import javax.swing.SwingUtilities;
23import javax.swing.Timer;
24
25import org.expeditee.core.Line;
26import org.expeditee.core.Point;
27import org.expeditee.gio.EcosystemManager;
28import org.expeditee.gio.InputManager;
29import org.expeditee.gio.input.InputEvent;
30import org.expeditee.gio.input.InputEvent.InputType;
31import org.expeditee.gio.input.KBMInputEvent;
32import org.expeditee.gui.Popup;
33import org.expeditee.gui.PopupManager;
34import org.expeditee.items.widgets.Widget;
35
36public class SwingInputManager extends InputManager
37implements ComponentListener,
38 WindowListener,
39 WindowStateListener,
40 KeyListener,
41 MouseListener,
42 MouseMotionListener,
43 MouseWheelListener
44{
45 /** Singleton instance. */
46 private static SwingInputManager _instance;
47
48 /** Singleton constructor. */
49 public static SwingInputManager getInstance()
50 {
51 if (_instance == null) {
52 try {
53 SwingUtilities.invokeAndWait(new Runnable() {
54 @Override
55 public void run() {
56 _instance = new SwingInputManager();
57 }
58 });
59 } catch (Exception e) {
60 System.err.println("Error while initialising InputManager. Aborting...");
61 System.exit(1);
62 }
63 }
64
65 return _instance;
66 }
67
68 /** TODO: What functionality does this object provide? */
69 private MouseEventRouter _mouseEventRouter;
70
71 /** For robotically controlling the mouse position. */
72 private Robot _robot;
73
74 private SwingInputManager()
75 {
76 SwingInputManager swingInputManager = this;
77
78 // Sign up to receive input as events
79 SwingGraphicsManager graphicsManager = SwingMiscManager.getIfUsingSwingGraphicsManager();
80 if (graphicsManager != null) {
81 graphicsManager.addWindowListener(swingInputManager);
82 graphicsManager.addWindowStateListener(swingInputManager);
83 graphicsManager.getContentPane().addKeyListener(swingInputManager); // TODO: Why do we need...
84 graphicsManager.addKeyListener(swingInputManager); // TODO: ...both of these? cts16
85 graphicsManager.addComponentListener(swingInputManager);
86
87 // Sign up to receive mouse events, from the SwingGraphicsManager
88 // TODO: Decide if we will keep using MouseEventRouter. cts16
89 _mouseEventRouter = new MouseEventRouter(graphicsManager.getJMenuBar(), graphicsManager.getContentPane());
90 _mouseEventRouter.addExpediteeMouseListener(swingInputManager);
91 _mouseEventRouter.addExpediteeMouseMotionListener(swingInputManager);
92 _mouseEventRouter.addExpediteeMouseWheelListener(swingInputManager);
93
94 // enable the glasspane-for capturing all mouse events
95 graphicsManager.setGlassPane(_mouseEventRouter);
96 graphicsManager.getGlassPane().setVisible(true);
97 graphicsManager.getContentPane().setBackground(Color.WHITE);
98 graphicsManager.getContentPane().setFocusTraversalKeysEnabled(false);
99 }
100
101 // Set up the robot (for controlling the mouse)
102 // TODO: What to do if robot throws exception??? cts16
103 try {
104 _robot = new Robot();
105 } catch (AWTException e) {
106 e.printStackTrace();
107 }
108
109 // Create the timer for firing timeout events
110 Timer.setLogTimers(false);
111 _timer = new Timer(1, new ActionListener() {
112 @Override
113 public void actionPerformed(ActionEvent e) {
114 swingInputManager.triggerTimeoutEvents();
115 }
116 });
117 _timer.setRepeats(false);
118 }
119
120 @Override
121 protected Point getRealCursorPosition()
122 {
123 Point mouseScreenPos = SwingConversions.fromSwingPoint(MouseInfo.getPointerInfo().getLocation());
124 return screenToWindowPosition(mouseScreenPos);
125 }
126
127 @Override
128 public void setCursorPosition(Point position)
129 {
130 //System.err.println("Move to position; Moving to: " + position);
131 Point screenPosition = windowToScreenPosition(position);
132 //System.err.println("Move to position: window adjusted; Moving to: " + screenPosition);
133 _robot.mouseMove(screenPosition.x, screenPosition.y);
134 updateCursorPosition(position.x, position.y);
135 }
136
137 @Override
138 public void windowStateChanged(WindowEvent e)
139 {
140 // Does nothing. cts16
141 }
142
143 @Override
144 public void windowOpened(WindowEvent e)
145 {
146 // Does nothing. cts16
147 }
148
149 @Override
150 public void windowClosing(WindowEvent e)
151 {
152 // Does nothing. cts16
153 }
154
155 @Override
156 public void windowClosed(WindowEvent e)
157 {
158 SwingGraphicsManager g = SwingMiscManager.getIfUsingSwingGraphicsManager();
159
160 if (g == null || !g.isFullscreenTransitionPending()) {
161 distributeWindowEvent(WindowEventType.WINDOW_CLOSED);
162 }
163 }
164
165 @Override
166 public void windowIconified(WindowEvent e)
167 {
168 // Does nothing. cts16
169 }
170
171 @Override
172 public void windowDeiconified(WindowEvent e)
173 {
174 // Does nothing. cts16
175 }
176
177 @Override
178 public void windowActivated(WindowEvent e)
179 {
180 // Does nothing. cts16
181 }
182
183 @Override
184 public void windowDeactivated(WindowEvent e)
185 {
186 // Does nothing. cts16
187 }
188
189 @Override
190 public void componentResized(ComponentEvent e)
191 {
192 SwingGraphicsManager g = SwingMiscManager.getIfUsingSwingGraphicsManager();
193 if (g != null) g.refreshRootSurface();
194
195 distributeWindowEvent(WindowEventType.WINDOW_RESIZED);
196 }
197
198 @Override
199 public void componentMoved(ComponentEvent e)
200 {
201 // Does nothing. cts16
202
203 }
204
205 @Override
206 public void componentShown(ComponentEvent e)
207 {
208 SwingGraphicsManager g = SwingMiscManager.getIfUsingSwingGraphicsManager();
209
210 if (g != null) g.finishFullscreenTransition();
211 }
212
213 @Override
214 public void componentHidden(ComponentEvent e)
215 {
216 // Does nothing. cts16
217 }
218
219 /** Converts a location given in screen-space to window-space. */
220 private Point screenToWindowPosition(Point screenPosition)
221 {
222 Point windowTopLeft = EcosystemManager.getGraphicsManager().getWindowLocation();
223
224 return Point.difference(screenPosition, windowTopLeft);
225 }
226
227 /** Converts a location given in window-space to screen-space. */
228 private Point windowToScreenPosition(Point windowPosition)
229 {
230 Point windowTopLeft = EcosystemManager.getGraphicsManager().getWindowLocation();
231
232 return windowPosition.clone().add(windowTopLeft);
233 }
234
235 @Override
236 public void mouseWheelMoved(MouseWheelEvent e)
237 {
238 // Give widgets first whack at input
239 distributeNativeInput(e);
240 if (e.isConsumed()) return;
241
242 try {
243 // Create an input event
244 Integer rotation = new Integer(e.getWheelRotation());
245 InputEvent event = new KBMInputEvent(KBMInputEvent.EventType.MOUSE_WHEEL_SCROLL, rotation);
246
247 // Translate and perform the input
248 distributeInputEvent(event);
249 } catch (Exception exception) {
250 System.err.println(exception.getMessage());
251 }
252 }
253
254 @Override
255 public void mouseDragged(MouseEvent e)
256 {
257 mouseMoved(e);
258 }
259
260 @Override
261 public void mouseMoved(MouseEvent e)
262 {
263 // Update the cursor position
264 updateCursorPosition(e.getX(), e.getY());
265
266 // Give widgets first whack at input
267 distributeNativeInput(e);
268 if (e.isConsumed()) return;
269
270 try {
271 // Create an input event
272 Point movedFrom = getCursorPosition();
273 Point movedTo = new Point(e.getX(), e.getY());
274 InputEvent event = new KBMInputEvent(KBMInputEvent.EventType.MOUSE_MOVE, new Line(movedFrom, movedTo));
275
276 // Translate and perform the input
277 distributeInputEvent(event);
278 } catch (Exception exception) {
279 System.err.println(exception.getMessage());
280 }
281 }
282
283 @Override
284 public void mouseClicked(MouseEvent e)
285 {
286 // Give widgets first whack at input
287 distributeNativeInput(e);
288 if (e.isConsumed()) return;
289
290 // Do nothing else (handled by mousePressed and mouseReleased)
291 }
292
293 @Override
294 public void mousePressed(MouseEvent e)
295 {
296 mouseAction(e, true);
297 }
298
299 @Override
300 public void mouseReleased(MouseEvent e)
301 {
302 mouseAction(e, false);
303 }
304
305 /** Handles mouse pressed/released events. */
306 private void mouseAction(MouseEvent e, boolean down)
307 {
308 // Give widgets first whack at input
309 distributeNativeInput(e);
310 if (e.isConsumed()) return;
311
312 // Work out which button was pressed
313 KBMInputEvent.MouseButton button;
314 switch (e.getButton()) {
315 case MouseEvent.BUTTON1:
316 button = KBMInputEvent.MouseButton.LEFT;
317 break;
318 case MouseEvent.BUTTON2:
319 button = KBMInputEvent.MouseButton.MIDDLE;
320 break;
321 case MouseEvent.BUTTON3:
322 button = KBMInputEvent.MouseButton.RIGHT;
323 break;
324 default:
325 return;
326 }
327
328 try {
329 // Create an input event
330 KBMInputEvent.EventType type = down ? KBMInputEvent.EventType.MOUSE_BUTTON_DOWN : KBMInputEvent.EventType.MOUSE_BUTTON_UP;
331 InputEvent event = new KBMInputEvent(type, button);
332
333 // Translate and perform the input
334 distributeInputEvent(event);
335 } catch (Exception exception) {
336 System.err.println(exception.getMessage());
337 }
338 }
339
340 /** Prevents forwarding mouse-entered-window events when coming back from a widget. */
341 private boolean _inWindow = false;
342
343 @Override
344 public void mouseEntered(MouseEvent e)
345 {
346 if (!_inWindow) {
347 _inWindow = true;
348 distributeWindowEvent(WindowEventType.MOUSE_ENTERED_WINDOW);
349 }
350 }
351
352 @Override
353 public void mouseExited(MouseEvent e)
354 {
355 _inWindow = false;
356 distributeWindowEvent(WindowEventType.MOUSE_EXITED_WINDOW);
357 }
358
359 @Override
360 public void keyTyped(KeyEvent e)
361 {
362 // Give widgets first whack at input
363 distributeNativeInput(e);
364 if (e.isConsumed()) return;
365
366 try {
367 // Ignore escape character and control characters
368 if (e.getKeyChar() == KeyEvent.VK_ESCAPE || e.isControlDown() || e.isAltDown()) return;
369
370 // Create an input event
371 Character character = new Character(e.getKeyChar());
372 InputEvent event = new KBMInputEvent(KBMInputEvent.EventType.CHAR_TYPED, character);
373
374 // Translate and perform the input
375 distributeInputEvent(event);
376 } catch (Exception exception) {
377 System.err.println(exception.getMessage());
378 }
379 }
380
381 @Override
382 public void keyPressed(KeyEvent e)
383 {
384 keyAction(e, true);
385 }
386
387 @Override
388 public void keyReleased(KeyEvent e)
389 {
390 keyAction(e, false);
391 }
392
393 /** Handles key pressed/released events. */
394 private void keyAction(KeyEvent e, boolean down)
395 {
396 // Give widgets first whack at input
397 distributeNativeInput(e);
398 if (e.isConsumed()) return;
399
400 KBMInputEvent.Key key = SwingConversions.fromSwingVirtualKey(e.getKeyCode());
401 if (key == null) return;
402
403 try {
404 // Create an input event
405 KBMInputEvent.EventType type = down ? KBMInputEvent.EventType.KEY_DOWN : KBMInputEvent.EventType.KEY_UP;
406 InputEvent event = new KBMInputEvent(type, key);
407
408 // Translate and perform the input
409 distributeInputEvent(event);
410 } catch (Exception exception) {
411 System.err.println(exception.getMessage());
412 }
413 }
414
415 @Override
416 protected final boolean isInputTypeSupported(InputType type)
417 {
418 // Only keyboard/mouse input is currently supported
419 if (type == InputEvent.InputType.KBM) return true;
420
421 return false;
422 }
423
424 /** Forwards the given input event to the listener if it is listening for it. */
425 private void forwardNativeInputToListener(Object listener, java.awt.event.InputEvent event)
426 {
427 if (listener == null || event == null) return;
428
429 if (listener instanceof KeyListener && event instanceof KeyEvent) {
430
431 KeyListener keyListener = (KeyListener) listener;
432 KeyEvent ke = (KeyEvent) event;
433
434 switch (event.getID()) {
435 case KeyEvent.KEY_PRESSED:
436 keyListener.keyPressed(ke);
437 return;
438 case KeyEvent.KEY_RELEASED:
439 keyListener.keyReleased(ke);
440 return;
441 case KeyEvent.KEY_TYPED:
442 keyListener.keyTyped(ke);
443 return;
444 }
445
446 } else if (event instanceof MouseEvent) {
447
448 MouseEvent me = (MouseEvent) event;
449
450 if (listener instanceof MouseListener) {
451 MouseListener mouseListener = (MouseListener) listener;
452 switch (event.getID()) {
453 case MouseEvent.MOUSE_CLICKED:
454 mouseListener.mouseClicked(me);
455 return;
456 case MouseEvent.MOUSE_PRESSED:
457 mouseListener.mousePressed(me);
458 return;
459 case MouseEvent.MOUSE_RELEASED:
460 mouseListener.mouseReleased(me);
461 return;
462 case MouseEvent.MOUSE_ENTERED:
463 mouseListener.mouseEntered(me);
464 return;
465 case MouseEvent.MOUSE_EXITED:
466 mouseListener.mouseExited(me);
467 return;
468 }
469 }
470
471 if (listener instanceof MouseMotionListener) {
472 MouseMotionListener motionListener = (MouseMotionListener) listener;
473 switch (event.getID()) {
474 case MouseEvent.MOUSE_MOVED:
475 motionListener.mouseMoved(me);
476 return;
477 case MouseEvent.MOUSE_DRAGGED:
478 motionListener.mouseDragged(me);
479 return;
480 }
481 }
482
483 if (listener instanceof MouseWheelListener && me instanceof MouseWheelEvent) {
484 MouseWheelListener wheelListener = (MouseWheelListener) listener;
485 MouseWheelEvent mwe = (MouseWheelEvent) me;
486 switch (event.getID()) {
487 case MouseEvent.MOUSE_WHEEL:
488 wheelListener.mouseWheelMoved(mwe);
489 return;
490 }
491 }
492 }
493 }
494
495 /** Distributes the native input to all pop-ups and widgets. */
496 private void distributeNativeInput(java.awt.event.InputEvent event)
497 {
498 // Distribute to pop-ups first
499 distributeNativeInputToPopups(event);
500 if (event.isConsumed()) return;
501
502 // Then distribute to widgets
503 distributeNativeInputToWidgets(event);
504 }
505
506 /** Distributes the input event to registered widgets. */
507 private void distributeNativeInputToPopups(java.awt.event.InputEvent event)
508 {
509 if (event == null) return;
510
511 for (Popup popup : PopupManager.getInstance().getPopups()) {
512 forwardNativeInputToListener(popup, event);
513
514 if (event.isConsumed()) return;
515 }
516 }
517
518 /** Distributes the input event to registered widgets. */
519 private void distributeNativeInputToWidgets(java.awt.event.InputEvent event)
520 {
521 if (event == null) return;
522
523 for (Widget iw : _widgets) {
524 java.awt.event.InputEvent e = respecInputEventForWidget(event, iw);
525
526 forwardNativeInputToListener(iw, e);
527
528 if (e != event && e.isConsumed()) event.consume();
529
530 if (event.isConsumed()) return;
531 }
532 }
533
534 /** Modifies the event so that it is relative to the given widget. */
535 private java.awt.event.InputEvent respecInputEventForWidget(java.awt.event.InputEvent event, Widget iw)
536 {
537 // TODO: Complete. cts16
538 return event;
539 }
540
541 /** The timer which fires timeout events for the Swing input manager. */
542 private Timer _timer;
543
544 @Override
545 protected void updateTimer(long nextTimeout)
546 {
547 if (nextTimeout < 0) nextTimeout = 0;
548 _timer.stop();
549 _timer.setInitialDelay((int) nextTimeout);
550 _timer.start();
551
552 }
553}
Note: See TracBrowser for help on using the repository browser.