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

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