2 * Sixth 3D engine. Copyright ©2012-2016, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 3 of the GNU Lesser General Public License
6 * or later as published by the Free Software Foundation.
10 package eu.svjatoslav.sixth.e3d.gui.humaninput;
12 import eu.svjatoslav.sixth.e3d.geometry.Point2D;
13 import eu.svjatoslav.sixth.e3d.gui.Avatar;
14 import eu.svjatoslav.sixth.e3d.gui.View;
15 import eu.svjatoslav.sixth.e3d.gui.ViewContext;
16 import eu.svjatoslav.sixth.e3d.gui.ViewUpdateListener;
19 import java.awt.event.*;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.List;
25 public class UserInputTracker
26 implements MouseMotionListener, KeyListener, MouseListener, MouseWheelListener, ViewUpdateListener {
30 * Key is keyboard key code.
31 * Value is system milliseconds when key was pressed.
33 * So by reading the map one can determine currently pressed keys as well as duration.
36 private final Map<Integer, Long> pressedKeysToPressedTimeMap = new HashMap<>();
37 private final List<MouseClick> detectedMouseClicks = new ArrayList<>();
38 private final List<KeyEvent> detectedKeyEvents = new ArrayList<>();
39 public int wheelMovedDirection = 0;
40 Point2D mouseDraggedDirection = new Point2D();
41 Point2D oldMouseCoordinatesWhenDragging;
42 ViewContext viewContext;
43 Point2D currentMouseLocation;
45 private boolean mouseWithinWindow = false;
47 public UserInputTracker(final ViewContext viewContext) {
48 this.viewContext = viewContext;
55 public boolean beforeViewUpdate(final ViewContext viewContext, final int millisecondsSinceLastFrame) {
57 boolean viewUpdateNeeded = handleDetectedMouseClicks(viewContext.getView());
59 viewUpdateNeeded |= handleDetectedKeyEvents();
61 viewContext.getKeyboardFocusTracker().getCurrentFocusOwner().beforeViewUpdate(viewContext,
62 millisecondsSinceLastFrame);
63 viewUpdateNeeded |= trackMouse();
65 return viewUpdateNeeded;
68 public void bind(final JPanel panel) {
69 panel.addMouseMotionListener(this);
71 panel.addKeyListener(this);
73 panel.addMouseListener(this);
75 panel.addMouseWheelListener(this);
78 public boolean handleDetectedKeyEvents() {
79 boolean keyEventsHandled = false;
81 final UserInputHandler currentFocusOwner = viewContext.getKeyboardFocusTracker().getCurrentFocusOwner();
83 synchronized (detectedKeyEvents) {
84 if (currentFocusOwner == null) {
85 detectedKeyEvents.clear();
89 while (!detectedKeyEvents.isEmpty()) {
90 final KeyEvent keyEvent = detectedKeyEvents.remove(0);
92 switch (keyEvent.getID()) {
93 case KeyEvent.KEY_PRESSED:
94 currentFocusOwner.keyPressed(keyEvent, viewContext);
95 keyEventsHandled = true;
98 case KeyEvent.KEY_RELEASED:
99 currentFocusOwner.keyReleased(keyEvent, viewContext);
100 keyEventsHandled = true;
106 return keyEventsHandled;
110 * Returns <code>true</code> if mouse events are detected and view needs to
113 public synchronized boolean handleDetectedMouseClicks(final View view) {
114 if (detectedMouseClicks.isEmpty()) {
116 if (currentMouseLocation != null)
117 view.getRenderingContext().mouseClick = new MouseClick(currentMouseLocation, 0);
126 view.getRenderingContext().mouseClick = detectedMouseClicks.remove(0);
131 public boolean isKeyPressed(final int keyCode) {
132 return pressedKeysToPressedTimeMap.containsKey(keyCode);
136 public void keyPressed(final KeyEvent evt) {
137 synchronized (detectedKeyEvents) {
138 pressedKeysToPressedTimeMap.put(evt.getKeyCode(), System.currentTimeMillis());
139 detectedKeyEvents.add(evt);
140 viewContext.getView().repaintDuringNextViewUpdate();
145 public void keyReleased(final KeyEvent evt) {
146 synchronized (detectedKeyEvents) {
147 pressedKeysToPressedTimeMap.remove(evt.getKeyCode());
148 detectedKeyEvents.add(evt);
149 viewContext.getView().repaintDuringNextViewUpdate();
154 public void keyTyped(final KeyEvent e) {
158 public void mouseClicked(final MouseEvent e) {
159 synchronized (detectedMouseClicks) {
160 detectedMouseClicks.add(new MouseClick(e.getX(), e.getY(), e.getButton()));
165 public void mouseDragged(final java.awt.event.MouseEvent evt) {
166 final Point2D mouseLocation = new Point2D(evt.getX(), evt.getY());
168 if (oldMouseCoordinatesWhenDragging == null) {
169 oldMouseCoordinatesWhenDragging = mouseLocation;
173 mouseDraggedDirection.add(mouseLocation.clone().subtract(oldMouseCoordinatesWhenDragging));
175 oldMouseCoordinatesWhenDragging = mouseLocation;
179 public void mouseEntered(final MouseEvent e) {
180 mouseWithinWindow = true;
184 public synchronized void mouseExited(final MouseEvent e) {
185 mouseWithinWindow = false;
186 currentMouseLocation = null;
190 public synchronized void mouseMoved(final MouseEvent e) {
191 currentMouseLocation = new Point2D(e.getX(), e.getY());
196 public void mousePressed(final MouseEvent e) {
200 public void mouseReleased(final java.awt.event.MouseEvent evt) {
201 oldMouseCoordinatesWhenDragging = null;
205 public void mouseWheelMoved(final java.awt.event.MouseWheelEvent evt) {
206 wheelMovedDirection += evt.getWheelRotation();
210 * Interpret mouse movement
212 public boolean trackMouse() {
213 final Avatar avatar = viewContext.getAvatar();
215 // track mouse dragging
217 // TODO: need to detect whether user moved mouse or touch screen
220 avatar.setAngleXZ(avatar.getAngleXZ() - ((float) mouseDraggedDirection.x / 50));
221 avatar.setAngleYZ(avatar.getAngleYZ() - ((float) mouseDraggedDirection.y / 50));
224 // avatar.setAngleXZ(avatar.getAngleXZ() + ((float)
225 // mouseDraggedDirection.x / 50));
226 // avatar.setAngleYZ(avatar.getAngleYZ() + ((float)
227 // mouseDraggedDirection.y / 50));
229 // track mouse wheel movements
230 final double actualAcceleration = 50 * avatar.avatarAcceleration * (1 + (avatar.getMovementSpeed() / 10));
232 avatar.getMovementDirection().y += (wheelMovedDirection * actualAcceleration);
233 avatar.enforceSpeedLimit();
235 // check if view shall be repainted
236 boolean repaintNeeded;
237 repaintNeeded = (mouseDraggedDirection.x != 0) || (mouseDraggedDirection.y != 0) || (wheelMovedDirection != 0);
239 // reset movement counters
240 wheelMovedDirection = 0;
241 mouseDraggedDirection.zero();
243 return repaintNeeded;